diff options
| author | Alexander Motin <mav@FreeBSD.org> | 2018-05-25 03:34:33 +0000 |
|---|---|---|
| committer | Alexander Motin <mav@FreeBSD.org> | 2018-05-25 03:34:33 +0000 |
| commit | f439e3a4ff12c411345fd653e9ca4d75b36ada5d (patch) | |
| tree | c2689ce10c0d1405fbbd8cd865595e311eddcaa4 | |
| parent | ea089f8c71775bc0e37c00883bcf3244f0683c7b (diff) | |
Notes
| -rw-r--r-- | sys/cam/cam_xpt.c | 2 | ||||
| -rw-r--r-- | sys/cam/cam_xpt_internal.h | 4 | ||||
| -rw-r--r-- | sys/cam/nvme/nvme_xpt.c | 193 | ||||
| -rw-r--r-- | sys/dev/nvme/nvme.c | 18 | ||||
| -rw-r--r-- | sys/dev/nvme/nvme.h | 17 | ||||
| -rw-r--r-- | sys/dev/nvme/nvme_ctrlr.c | 34 | ||||
| -rw-r--r-- | sys/dev/nvme/nvme_ctrlr_cmd.c | 2 | ||||
| -rw-r--r-- | sys/dev/nvme/nvme_private.h | 7 | ||||
| -rw-r--r-- | sys/dev/nvme/nvme_sim.c | 139 |
9 files changed, 271 insertions, 145 deletions
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 98c1b70ebb5a..f58ce0b6a764 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -5011,6 +5011,8 @@ xpt_release_device(struct cam_ed *device) free(device->physpath, M_CAMXPT); free(device->rcap_buf, M_CAMXPT); free(device->serial_num, M_CAMXPT); + free(device->nvme_data, M_CAMXPT); + free(device->nvme_cdata, M_CAMXPT); taskqueue_enqueue(xsoftc.xpt_taskq, &device->device_destroy_task); } diff --git a/sys/cam/cam_xpt_internal.h b/sys/cam/cam_xpt_internal.h index b620838fbaed..d0485ee28287 100644 --- a/sys/cam/cam_xpt_internal.h +++ b/sys/cam/cam_xpt_internal.h @@ -155,8 +155,8 @@ struct cam_ed { STAILQ_ENTRY(cam_ed) highpowerq_entry; struct mtx device_mtx; struct task device_destroy_task; - const struct nvme_controller_data *nvme_cdata; - const struct nvme_namespace_data *nvme_data; + struct nvme_controller_data *nvme_cdata; + struct nvme_namespace_data *nvme_data; }; /* diff --git a/sys/cam/nvme/nvme_xpt.c b/sys/cam/nvme/nvme_xpt.c index 643db5183b94..5e84b39bf8a7 100644 --- a/sys/cam/nvme/nvme_xpt.c +++ b/sys/cam/nvme/nvme_xpt.c @@ -84,17 +84,17 @@ static struct periph_driver nvme_probe_driver = PERIPHDRIVER_DECLARE(nvme_probe, nvme_probe_driver); typedef enum { - NVME_PROBE_IDENTIFY, + NVME_PROBE_IDENTIFY_CD, + NVME_PROBE_IDENTIFY_NS, NVME_PROBE_DONE, - NVME_PROBE_INVALID, - NVME_PROBE_RESET + NVME_PROBE_INVALID } nvme_probe_action; static char *nvme_probe_action_text[] = { - "NVME_PROBE_IDENTIFY", + "NVME_PROBE_IDENTIFY_CD", + "NVME_PROBE_IDENTIFY_NS", "NVME_PROBE_DONE", - "NVME_PROBE_INVALID", - "NVME_PROBE_RESET", + "NVME_PROBE_INVALID" }; #define NVME_PROBE_SET_ACTION(softc, newaction) \ @@ -113,6 +113,10 @@ typedef enum { typedef struct { TAILQ_HEAD(, ccb_hdr) request_ccbs; + union { + struct nvme_controller_data cd; + struct nvme_namespace_data ns; + }; nvme_probe_action action; nvme_probe_flags flags; int restart; @@ -137,6 +141,7 @@ static cam_status nvme_probe_register(struct cam_periph *periph, void *arg); static void nvme_probe_schedule(struct cam_periph *nvme_probe_periph); static void nvme_probe_start(struct cam_periph *periph, union ccb *start_ccb); +static void nvme_probe_done(struct cam_periph *periph, union ccb *done_ccb); static void nvme_probe_cleanup(struct cam_periph *periph); //static void nvme_find_quirk(struct cam_ed *device); static void nvme_scan_lun(struct cam_periph *periph, @@ -240,7 +245,7 @@ nvme_probe_schedule(struct cam_periph *periph) softc = (nvme_probe_softc *)periph->softc; ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); - NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY); + NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY_CD); if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) softc->flags |= NVME_PROBE_NO_ANNOUNCE; @@ -254,10 +259,8 @@ static void nvme_probe_start(struct cam_periph *periph, union ccb *start_ccb) { struct ccb_nvmeio *nvmeio; - struct ccb_scsiio *csio; nvme_probe_softc *softc; struct cam_path *path; - const struct nvme_namespace_data *nvme_data; lun_id_t lun; CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("nvme_probe_start\n")); @@ -265,57 +268,163 @@ nvme_probe_start(struct cam_periph *periph, union ccb *start_ccb) softc = (nvme_probe_softc *)periph->softc; path = start_ccb->ccb_h.path; nvmeio = &start_ccb->nvmeio; - csio = &start_ccb->csio; - nvme_data = periph->path->device->nvme_data; + lun = xpt_path_lun_id(periph->path); if (softc->restart) { softc->restart = 0; - if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) - NVME_PROBE_SET_ACTION(softc, NVME_PROBE_RESET); - else - NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY); + NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY_CD); } - /* - * Other transports have to ask their SIM to do a lot of action. - * NVMe doesn't, so don't do the dance. Just do things - * directly. - */ switch (softc->action) { - case NVME_PROBE_RESET: - /* FALLTHROUGH */ - case NVME_PROBE_IDENTIFY: - nvme_device_transport(path); + case NVME_PROBE_IDENTIFY_CD: + cam_fill_nvmeadmin(nvmeio, + 0, /* retries */ + nvme_probe_done, /* cbfcnp */ + CAM_DIR_IN, /* flags */ + (uint8_t *)&softc->cd, /* data_ptr */ + sizeof(softc->cd), /* dxfer_len */ + 30 * 1000); /* timeout 30s */ + nvme_ns_cmd(nvmeio, NVME_OPC_IDENTIFY, 0, + 1, 0, 0, 0, 0, 0); + break; + case NVME_PROBE_IDENTIFY_NS: + cam_fill_nvmeadmin(nvmeio, + 0, /* retries */ + nvme_probe_done, /* cbfcnp */ + CAM_DIR_IN, /* flags */ + (uint8_t *)&softc->ns, /* data_ptr */ + sizeof(softc->ns), /* dxfer_len */ + 30 * 1000); /* timeout 30s */ + nvme_ns_cmd(nvmeio, NVME_OPC_IDENTIFY, lun, + 0, 0, 0, 0, 0, 0); + break; + default: + panic("nvme_probe_start: invalid action state 0x%x\n", softc->action); + } + start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; + xpt_action(start_ccb); +} + +static void +nvme_probe_done(struct cam_periph *periph, union ccb *done_ccb) +{ + struct nvme_namespace_data *nvme_data; + struct nvme_controller_data *nvme_cdata; + nvme_probe_softc *softc; + struct cam_path *path; + cam_status status; + u_int32_t priority; + int found = 1; + + CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("nvme_probe_done\n")); + + softc = (nvme_probe_softc *)periph->softc; + path = done_ccb->ccb_h.path; + priority = done_ccb->ccb_h.pinfo.priority; + + if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if (cam_periph_error(done_ccb, + 0, softc->restart ? (SF_NO_RECOVERY | SF_NO_RETRY) : 0 + ) == ERESTART) { +out: + /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ + cam_release_devq(path, 0, 0, 0, FALSE); + return; + } + if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { + /* Don't wedge the queue */ + xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); + } + status = done_ccb->ccb_h.status & CAM_STATUS_MASK; + /* - * Test for lun == CAM_LUN_WILDCARD is lame, but - * appears to be necessary here. XXX + * If we get to this point, we got an error status back + * from the inquiry and the error status doesn't require + * automatically retrying the command. Therefore, the + * inquiry failed. If we had inquiry information before + * for this device, but this latest inquiry command failed, + * the device has probably gone away. If this device isn't + * already marked unconfigured, notify the peripheral + * drivers that this device is no more. */ - lun = xpt_path_lun_id(periph->path); - if (lun == CAM_LUN_WILDCARD || - periph->path->device->flags & CAM_DEV_UNCONFIGURED) { +device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) + xpt_async(AC_LOST_DEVICE, path, NULL); + NVME_PROBE_SET_ACTION(softc, NVME_PROBE_INVALID); + found = 0; + goto done; + } + if (softc->restart) + goto done; + switch (softc->action) { + case NVME_PROBE_IDENTIFY_CD: + nvme_controller_data_swapbytes(&softc->cd); + + nvme_cdata = path->device->nvme_cdata; + if (nvme_cdata == NULL) { + nvme_cdata = malloc(sizeof(*nvme_cdata), M_CAMXPT, + M_NOWAIT); + if (nvme_cdata == NULL) { + xpt_print(path, "Can't allocate memory"); + goto device_fail; + } + } + bcopy(&softc->cd, nvme_cdata, sizeof(*nvme_cdata)); + path->device->nvme_cdata = nvme_cdata; + +// nvme_find_quirk(path->device); + nvme_device_transport(path); + NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY_NS); + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + goto out; + case NVME_PROBE_IDENTIFY_NS: + nvme_namespace_data_swapbytes(&softc->ns); + + /* Check that the namespace exists. */ + if (softc->ns.nsze == 0) + goto device_fail; + + nvme_data = path->device->nvme_data; + if (nvme_data == NULL) { + nvme_data = malloc(sizeof(*nvme_data), M_CAMXPT, + M_NOWAIT); + if (nvme_data == NULL) { + xpt_print(path, "Can't allocate memory"); + goto device_fail; + } + } + bcopy(&softc->ns, nvme_data, sizeof(*nvme_data)); + path->device->nvme_data = nvme_data; + + if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { path->device->flags &= ~CAM_DEV_UNCONFIGURED; xpt_acquire_device(path->device); - start_ccb->ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action(start_ccb); - xpt_async(AC_FOUND_DEVICE, path, start_ccb); + done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action(done_ccb); + xpt_async(AC_FOUND_DEVICE, path, done_ccb); } NVME_PROBE_SET_ACTION(softc, NVME_PROBE_DONE); break; default: - panic("nvme_probe_start: invalid action state 0x%x\n", softc->action); + panic("nvme_probe_done: invalid action state 0x%x\n", softc->action); } - /* - * Probing is now done. We need to complete any lingering items - * in the queue, though there shouldn't be any. - */ - xpt_release_ccb(start_ccb); +done: + if (softc->restart) { + softc->restart = 0; + xpt_release_ccb(done_ccb); + nvme_probe_schedule(periph); + goto out; + } + xpt_release_ccb(done_ccb); CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n")); - while ((start_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) { + while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) { TAILQ_REMOVE(&softc->request_ccbs, - &start_ccb->ccb_h, periph_links.tqe); - start_ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(start_ccb); + &done_ccb->ccb_h, periph_links.tqe); + done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR; + xpt_done(done_ccb); } + /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ + cam_release_devq(path, 0, 0, 0, FALSE); cam_periph_invalidate(periph); cam_periph_release_locked(periph); } diff --git a/sys/dev/nvme/nvme.c b/sys/dev/nvme/nvme.c index 4013601ec5f0..8c5ee9edd637 100644 --- a/sys/dev/nvme/nvme.c +++ b/sys/dev/nvme/nvme.c @@ -439,6 +439,24 @@ nvme_notify_fail_consumers(struct nvme_controller *ctrlr) } } +void +nvme_notify_ns(struct nvme_controller *ctrlr, int nsid) +{ + struct nvme_consumer *cons; + struct nvme_namespace *ns = &ctrlr->ns[nsid - 1]; + uint32_t i; + + if (!ctrlr->is_initialized) + return; + + for (i = 0; i < NVME_MAX_CONSUMERS; i++) { + cons = &nvme_consumer[i]; + if (cons->id != INVALID_CONSUMER_ID && cons->ns_fn != NULL) + ns->cons_cookie[cons->id] = + (*cons->ns_fn)(ns, ctrlr->cons_cookie[cons->id]); + } +} + struct nvme_consumer * nvme_register_consumer(nvme_cons_ns_fn_t ns_fn, nvme_cons_ctrlr_fn_t ctrlr_fn, nvme_cons_async_fn_t async_fn, diff --git a/sys/dev/nvme/nvme.h b/sys/dev/nvme/nvme.h index b51b4a973abf..169f22d1e5f1 100644 --- a/sys/dev/nvme/nvme.h +++ b/sys/dev/nvme/nvme.h @@ -115,7 +115,7 @@ #define NVME_CMD_FUSE_SHIFT (8) #define NVME_CMD_FUSE_MASK (0x3) -#define NVME_CMD_SET_OPC(opc) (htole16(((opc) & NVME_CMD_OPC_MASK) << NVME_CMD_OPC_SHIFT)) +#define NVME_CMD_SET_OPC(opc) (htole16(((uint16_t)(opc) & NVME_CMD_OPC_MASK) << NVME_CMD_OPC_SHIFT)) #define NVME_STATUS_P_SHIFT (0) #define NVME_STATUS_P_MASK (0x1) @@ -1091,6 +1091,12 @@ struct nvme_firmware_page { _Static_assert(sizeof(struct nvme_firmware_page) == 512, "bad size for nvme_firmware_page"); +struct nvme_ns_list { + uint32_t ns[1024]; +} __packed __aligned(4); + +_Static_assert(sizeof(struct nvme_ns_list) == 4096, "bad size for nvme_ns_list"); + struct intel_log_temp_stats { uint64_t current; @@ -1470,6 +1476,15 @@ void nvme_firmware_page_swapbytes(struct nvme_firmware_page *s) } static inline +void nvme_ns_list_swapbytes(struct nvme_ns_list *s) +{ + int i; + + for (i = 0; i < 1024; i++) + s->ns[i] = le32toh(s->ns[i]); +} + +static inline void intel_log_temp_stats_swapbytes(struct intel_log_temp_stats *s) { diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c index 4c9614c9409e..259b5a98117c 100644 --- a/sys/dev/nvme/nvme_ctrlr.c +++ b/sys/dev/nvme/nvme_ctrlr.c @@ -564,6 +564,7 @@ is_log_page_id_valid(uint8_t page_id) case NVME_LOG_ERROR: case NVME_LOG_HEALTH_INFORMATION: case NVME_LOG_FIRMWARE_SLOT: + case NVME_LOG_CHANGED_NAMESPACE: return (TRUE); } @@ -587,6 +588,9 @@ nvme_ctrlr_get_log_page_size(struct nvme_controller *ctrlr, uint8_t page_id) case NVME_LOG_FIRMWARE_SLOT: log_page_size = sizeof(struct nvme_firmware_page); break; + case NVME_LOG_CHANGED_NAMESPACE: + log_page_size = sizeof(struct nvme_ns_list); + break; default: log_page_size = 0; break; @@ -625,6 +629,7 @@ nvme_ctrlr_async_event_log_page_cb(void *arg, const struct nvme_completion *cpl) { struct nvme_async_event_request *aer = arg; struct nvme_health_information_page *health_info; + struct nvme_ns_list *nsl; struct nvme_error_information_entry *err; int i; @@ -652,6 +657,10 @@ nvme_ctrlr_async_event_log_page_cb(void *arg, const struct nvme_completion *cpl) nvme_firmware_page_swapbytes( (struct nvme_firmware_page *)aer->log_page_buffer); break; + case NVME_LOG_CHANGED_NAMESPACE: + nvme_ns_list_swapbytes( + (struct nvme_ns_list *)aer->log_page_buffer); + break; case INTEL_LOG_TEMP_STATS: intel_log_temp_stats_swapbytes( (struct intel_log_temp_stats *)aer->log_page_buffer); @@ -676,6 +685,14 @@ nvme_ctrlr_async_event_log_page_cb(void *arg, const struct nvme_completion *cpl) ~health_info->critical_warning; nvme_ctrlr_cmd_set_async_event_config(aer->ctrlr, aer->ctrlr->async_event_config, NULL, NULL); + } else if (aer->log_page_id == NVME_LOG_CHANGED_NAMESPACE && + !nvme_use_nvd) { + nsl = (struct nvme_ns_list *)aer->log_page_buffer; + for (i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) { + if (nsl->ns[i] > NVME_MAX_NAMESPACES) + break; + nvme_notify_ns(aer->ctrlr, nsl->ns[i]); + } } @@ -712,7 +729,8 @@ nvme_ctrlr_async_event_cb(void *arg, const struct nvme_completion *cpl) /* Associated log page is in bits 23:16 of completion entry dw0. */ aer->log_page_id = (cpl->cdw0 & 0xFF0000) >> 16; - nvme_printf(aer->ctrlr, "async event occurred (log page id=0x%x)\n", + nvme_printf(aer->ctrlr, "async event occurred (type 0x%x, info 0x%02x," + " page 0x%02x)\n", (cpl->cdw0 & 0x03), (cpl->cdw0 & 0xFF00) >> 8, aer->log_page_id); if (is_log_page_id_valid(aer->log_page_id)) { @@ -762,8 +780,12 @@ nvme_ctrlr_configure_aer(struct nvme_controller *ctrlr) struct nvme_async_event_request *aer; uint32_t i; - ctrlr->async_event_config = 0xFF; - ctrlr->async_event_config &= ~NVME_CRIT_WARN_ST_RESERVED_MASK; + ctrlr->async_event_config = NVME_CRIT_WARN_ST_AVAILABLE_SPARE | + NVME_CRIT_WARN_ST_DEVICE_RELIABILITY | + NVME_CRIT_WARN_ST_READ_ONLY | + NVME_CRIT_WARN_ST_VOLATILE_MEMORY_BACKUP; + if (ctrlr->cdata.ver >= NVME_REV(1, 2)) + ctrlr->async_event_config |= 0x300; status.done = 0; nvme_ctrlr_cmd_get_feature(ctrlr, NVME_FEAT_TEMPERATURE_THRESHOLD, @@ -774,8 +796,8 @@ nvme_ctrlr_configure_aer(struct nvme_controller *ctrlr) (status.cpl.cdw0 & 0xFFFF) == 0xFFFF || (status.cpl.cdw0 & 0xFFFF) == 0x0000) { nvme_printf(ctrlr, "temperature threshold not supported\n"); - ctrlr->async_event_config &= ~NVME_CRIT_WARN_ST_TEMPERATURE; - } + } else + ctrlr->async_event_config |= NVME_CRIT_WARN_ST_TEMPERATURE; nvme_ctrlr_cmd_set_async_event_config(ctrlr, ctrlr->async_event_config, NULL, NULL); @@ -1285,6 +1307,8 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev) if (ctrlr->resource == NULL) goto nores; + nvme_notify_fail_consumers(ctrlr); + for (i = 0; i < NVME_MAX_NAMESPACES; i++) nvme_ns_destruct(&ctrlr->ns[i]); diff --git a/sys/dev/nvme/nvme_ctrlr_cmd.c b/sys/dev/nvme/nvme_ctrlr_cmd.c index de0685a3b8cb..68a761c70589 100644 --- a/sys/dev/nvme/nvme_ctrlr_cmd.c +++ b/sys/dev/nvme/nvme_ctrlr_cmd.c @@ -214,7 +214,7 @@ nvme_ctrlr_cmd_set_num_queues(struct nvme_controller *ctrlr, void nvme_ctrlr_cmd_set_async_event_config(struct nvme_controller *ctrlr, - uint8_t state, nvme_cb_fn_t cb_fn, void *cb_arg) + uint32_t state, nvme_cb_fn_t cb_fn, void *cb_arg) { uint32_t cdw11; diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h index 5bc7b26c1af6..e246136e6701 100644 --- a/sys/dev/nvme/nvme_private.h +++ b/sys/dev/nvme/nvme_private.h @@ -312,8 +312,8 @@ struct nvme_controller { struct cdev *cdev; - /** bit mask of critical warning types currently enabled for async events */ - uint8_t async_event_config; + /** bit mask of event types currently enabled for async events */ + uint32_t async_event_config; uint32_t num_aers; struct nvme_async_event_request aer[NVME_MAX_ASYNC_EVENTS]; @@ -399,7 +399,7 @@ void nvme_ctrlr_cmd_set_num_queues(struct nvme_controller *ctrlr, uint32_t num_queues, nvme_cb_fn_t cb_fn, void *cb_arg); void nvme_ctrlr_cmd_set_async_event_config(struct nvme_controller *ctrlr, - uint8_t state, + uint32_t state, nvme_cb_fn_t cb_fn, void *cb_arg); void nvme_ctrlr_cmd_abort(struct nvme_controller *ctrlr, uint16_t cid, uint16_t sqid, nvme_cb_fn_t cb_fn, void *cb_arg); @@ -544,6 +544,7 @@ void nvme_notify_async_consumers(struct nvme_controller *ctrlr, uint32_t log_page_size); void nvme_notify_fail_consumers(struct nvme_controller *ctrlr); void nvme_notify_new_controller(struct nvme_controller *ctrlr); +void nvme_notify_ns(struct nvme_controller *ctrlr, int nsid); void nvme_ctrlr_intx_handler(void *arg); void nvme_ctrlr_poll(struct nvme_controller *ctrlr); diff --git a/sys/dev/nvme/nvme_sim.c b/sys/dev/nvme/nvme_sim.c index 63da6a8eaa00..cdd046a5bf88 100644 --- a/sys/dev/nvme/nvme_sim.c +++ b/sys/dev/nvme/nvme_sim.c @@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$"); #include <cam/cam_ccb.h> #include <cam/cam_sim.h> #include <cam/cam_xpt_sim.h> -#include <cam/cam_xpt_internal.h> // Yes, this is wrong. #include <cam/cam_debug.h> #include <dev/pci/pcivar.h> @@ -54,13 +53,11 @@ static void nvme_sim_action(struct cam_sim *sim, union ccb *ccb); static void nvme_sim_poll(struct cam_sim *sim); #define sim2softc(sim) ((struct nvme_sim_softc *)cam_sim_softc(sim)) -#define sim2ns(sim) (sim2softc(sim)->s_ns) #define sim2ctrlr(sim) (sim2softc(sim)->s_ctrlr) struct nvme_sim_softc { struct nvme_controller *s_ctrlr; - struct nvme_namespace *s_ns; struct cam_sim *s_sim; struct cam_path *s_path; }; @@ -146,18 +143,11 @@ static void nvme_sim_action(struct cam_sim *sim, union ccb *ccb) { struct nvme_controller *ctrlr; - struct nvme_namespace *ns; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("nvme_sim_action: func= %#x\n", ccb->ccb_h.func_code)); - /* - * XXX when we support multiple namespaces in the base driver we'll need - * to revisit how all this gets stored and saved in the periph driver's - * reserved areas. Right now we store all three in the softc of the sim. - */ - ns = sim2ns(sim); ctrlr = sim2ctrlr(sim); mtx_assert(&ctrlr->lock, MA_OWNED); @@ -193,11 +183,11 @@ nvme_sim_action(struct cam_sim *sim, union ccb *ccb) cpi->version_num = 1; cpi->hba_inquiry = 0; cpi->target_sprt = 0; - cpi->hba_misc = PIM_UNMAPPED /* | PIM_NOSCAN */; + cpi->hba_misc = PIM_UNMAPPED | PIM_NOSCAN; cpi->hba_eng_cnt = 0; cpi->max_target = 0; cpi->max_lun = ctrlr->cdata.nn; - cpi->maxio = nvme_ns_get_max_io_xfer_size(ns); + cpi->maxio = ctrlr->max_xfer_size; cpi->initiator_id = 0; cpi->bus_id = cam_sim_bus(sim); cpi->base_transfer_speed = nvme_link_kBps(ctrlr); @@ -209,7 +199,7 @@ nvme_sim_action(struct cam_sim *sim, union ccb *ccb) cpi->transport_version = nvme_mmio_read_4(ctrlr, vs); cpi->protocol = PROTO_NVME; cpi->protocol_version = nvme_mmio_read_4(ctrlr, vs); - cpi->xport_specific.nvme.nsid = ns->id; + cpi->xport_specific.nvme.nsid = xpt_path_lun_id(ccb->ccb_h.path); cpi->xport_specific.nvme.domain = pci_get_domain(dev); cpi->xport_specific.nvme.bus = pci_get_bus(dev); cpi->xport_specific.nvme.slot = pci_get_slot(dev); @@ -285,122 +275,89 @@ nvme_sim_poll(struct cam_sim *sim) static void * nvme_sim_new_controller(struct nvme_controller *ctrlr) { + struct nvme_sim_softc *sc; struct cam_devq *devq; int max_trans; - int unit; - struct nvme_sim_softc *sc = NULL; max_trans = ctrlr->max_hw_pend_io; - unit = device_get_unit(ctrlr->dev); devq = cam_simq_alloc(max_trans); if (devq == NULL) - return NULL; + return (NULL); sc = malloc(sizeof(*sc), M_NVME, M_ZERO | M_WAITOK); - sc->s_ctrlr = ctrlr; sc->s_sim = cam_sim_alloc(nvme_sim_action, nvme_sim_poll, - "nvme", sc, unit, &ctrlr->lock, max_trans, max_trans, devq); + "nvme", sc, device_get_unit(ctrlr->dev), + &ctrlr->lock, max_trans, max_trans, devq); if (sc->s_sim == NULL) { printf("Failed to allocate a sim\n"); cam_simq_free(devq); - free(sc, M_NVME); - return NULL; + goto err1; + } + if (xpt_bus_register(sc->s_sim, ctrlr->dev, 0) != CAM_SUCCESS) { + printf("Failed to create a bus\n"); + goto err2; + } + if (xpt_create_path(&sc->s_path, /*periph*/NULL, cam_sim_path(sc->s_sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + printf("Failed to create a path\n"); + goto err3; } - return sc; + return (sc); + +err3: + xpt_bus_deregister(cam_sim_path(sc->s_sim)); +err2: + cam_sim_free(sc->s_sim, /*free_devq*/TRUE); +err1: + free(sc, M_NVME); + return (NULL); } -static void -nvme_sim_rescan_target(struct nvme_controller *ctrlr, struct cam_path *path) +static void * +nvme_sim_new_ns(struct nvme_namespace *ns, void *sc_arg) { + struct nvme_sim_softc *sc = sc_arg; + struct nvme_controller *ctrlr = sc->s_ctrlr; union ccb *ccb; + mtx_lock(&ctrlr->lock); + ccb = xpt_alloc_ccb_nowait(); if (ccb == NULL) { printf("unable to alloc CCB for rescan\n"); - return; + return (NULL); } - if (xpt_clone_path(&ccb->ccb_h.path, path) != CAM_REQ_CMP) { - printf("unable to copy path for rescan\n"); + if (xpt_create_path(&ccb->ccb_h.path, /*periph*/NULL, + cam_sim_path(sc->s_sim), 0, ns->id) != CAM_REQ_CMP) { + printf("unable to create path for rescan\n"); xpt_free_ccb(ccb); - return; + return (NULL); } xpt_rescan(ccb); -} - -static void * -nvme_sim_new_ns(struct nvme_namespace *ns, void *sc_arg) -{ - struct nvme_sim_softc *sc = sc_arg; - struct nvme_controller *ctrlr = sc->s_ctrlr; - int i; - - sc->s_ns = ns; - - /* - * XXX this is creating one bus per ns, but it should be one - * XXX target per controller, and one LUN per namespace. - * XXX Current drives only support one NS, so there's time - * XXX to fix it later when new drives arrive. - * - * XXX I'm pretty sure the xpt_bus_register() call below is - * XXX like super lame and it really belongs in the sim_new_ctrlr - * XXX callback. Then the create_path below would be pretty close - * XXX to being right. Except we should be per-ns not per-ctrlr - * XXX data. - */ - - mtx_lock(&ctrlr->lock); -/* Create bus */ - - /* - * XXX do I need to lock ctrlr->lock ? - * XXX do I need to lock the path? - * ata and scsi seem to in their code, but their discovery is - * somewhat more asynchronous. We're only every called one at a - * time, and nothing is in parallel. - */ - - i = 0; - if (xpt_bus_register(sc->s_sim, ctrlr->dev, 0) != CAM_SUCCESS) - goto error; - i++; - if (xpt_create_path(&sc->s_path, /*periph*/NULL, cam_sim_path(sc->s_sim), - 1, ns->id) != CAM_REQ_CMP) - goto error; - i++; - - sc->s_path->device->nvme_data = nvme_ns_get_data(ns); - sc->s_path->device->nvme_cdata = nvme_ctrlr_get_data(ns->ctrlr); - -/* Scan bus */ - nvme_sim_rescan_target(ctrlr, sc->s_path); mtx_unlock(&ctrlr->lock); - return ns; - -error: - switch (i) { - case 2: - xpt_free_path(sc->s_path); - case 1: - xpt_bus_deregister(cam_sim_path(sc->s_sim)); - case 0: - cam_sim_free(sc->s_sim, /*free_devq*/TRUE); - } - mtx_unlock(&ctrlr->lock); - return NULL; + return (ns); } static void nvme_sim_controller_fail(void *ctrlr_arg) { - /* XXX cleanup XXX */ + struct nvme_sim_softc *sc = ctrlr_arg; + struct nvme_controller *ctrlr = sc->s_ctrlr; + + mtx_lock(&ctrlr->lock); + xpt_async(AC_LOST_DEVICE, sc->s_path, NULL); + xpt_free_path(sc->s_path); + xpt_bus_deregister(cam_sim_path(sc->s_sim)); + cam_sim_free(sc->s_sim, /*free_devq*/TRUE); + mtx_unlock(&ctrlr->lock); + free(sc, M_NVME); } struct nvme_consumer *consumer_cookie; |
