Date: Fri, 25 May 2018 03:34:33 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r334200 - in head/sys: cam cam/nvme dev/nvme Message-ID: <201805250334.w4P3YXet006531@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mav Date: Fri May 25 03:34:33 2018 New Revision: 334200 URL: https://svnweb.freebsd.org/changeset/base/334200 Log: Refactor NVMe CAM integration. - Remove layering violation, when NVMe SIM code accessed CAM internal device structures to set pointers on controller and namespace data. Instead make NVMe XPT probe fetch the data directly from hardware. - Cleanup NVMe SIM code, fixing support for multiple namespaces per controller (reporting them as LUNs) and adding controller detach support and run-time namespace change notifications. - Add initial support for namespace change async events. So far only in CAM mode, but it allows run-time namespace arrival and departure. - Add missing nvme_notify_fail_consumers() call on controller detach. Together with previous changes this allows NVMe device detach/unplug. Non-CAM mode still requires a lot of love to stay on par, but at least CAM mode code should not stay in the way so much, becoming much more self-sufficient. Reviewed by: imp MFC after: 1 month Sponsored by: iXsystems, Inc. Modified: head/sys/cam/cam_xpt.c head/sys/cam/cam_xpt_internal.h head/sys/cam/nvme/nvme_xpt.c head/sys/dev/nvme/nvme.c head/sys/dev/nvme/nvme.h head/sys/dev/nvme/nvme_ctrlr.c head/sys/dev/nvme/nvme_ctrlr_cmd.c head/sys/dev/nvme/nvme_private.h head/sys/dev/nvme/nvme_sim.c Modified: head/sys/cam/cam_xpt.c ============================================================================== --- head/sys/cam/cam_xpt.c Fri May 25 02:07:05 2018 (r334199) +++ head/sys/cam/cam_xpt.c Fri May 25 03:34:33 2018 (r334200) @@ -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); } Modified: head/sys/cam/cam_xpt_internal.h ============================================================================== --- head/sys/cam/cam_xpt_internal.h Fri May 25 02:07:05 2018 (r334199) +++ head/sys/cam/cam_xpt_internal.h Fri May 25 03:34:33 2018 (r334200) @@ -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; }; /* Modified: head/sys/cam/nvme/nvme_xpt.c ============================================================================== --- head/sys/cam/nvme/nvme_xpt.c Fri May 25 02:07:05 2018 (r334199) +++ head/sys/cam/nvme/nvme_xpt.c Fri May 25 03:34:33 2018 (r334200) @@ -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_perip 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 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); } Modified: head/sys/dev/nvme/nvme.c ============================================================================== --- head/sys/dev/nvme/nvme.c Fri May 25 02:07:05 2018 (r334199) +++ head/sys/dev/nvme/nvme.c Fri May 25 03:34:33 2018 (r334200) @@ -439,6 +439,24 @@ nvme_notify_fail_consumers(struct nvme_controller *ctr } } +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, Modified: head/sys/dev/nvme/nvme.h ============================================================================== --- head/sys/dev/nvme/nvme.h Fri May 25 02:07:05 2018 (r334199) +++ head/sys/dev/nvme/nvme.h Fri May 25 03:34:33 2018 (r334200) @@ -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; @@ -1467,6 +1473,15 @@ void nvme_firmware_page_swapbytes(struct nvme_firmware for (i = 0; i < 7; i++) s->revision[i] = le64toh(s->revision[i]); +} + +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 Modified: head/sys/dev/nvme/nvme_ctrlr.c ============================================================================== --- head/sys/dev/nvme/nvme_ctrlr.c Fri May 25 02:07:05 2018 (r334199) +++ head/sys/dev/nvme/nvme_ctrlr.c Fri May 25 03:34:33 2018 (r334200) @@ -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 *c 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 st { 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 st 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 st ~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 /* 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); @@ -1284,6 +1306,8 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, 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]); Modified: head/sys/dev/nvme/nvme_ctrlr_cmd.c ============================================================================== --- head/sys/dev/nvme/nvme_ctrlr_cmd.c Fri May 25 02:07:05 2018 (r334199) +++ head/sys/dev/nvme/nvme_ctrlr_cmd.c Fri May 25 03:34:33 2018 (r334200) @@ -214,7 +214,7 @@ nvme_ctrlr_cmd_set_num_queues(struct nvme_controller * 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; Modified: head/sys/dev/nvme/nvme_private.h ============================================================================== --- head/sys/dev/nvme/nvme_private.h Fri May 25 02:07:05 2018 (r334199) +++ head/sys/dev/nvme/nvme_private.h Fri May 25 03:34:33 2018 (r334200) @@ -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_control 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_controlle 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); Modified: head/sys/dev/nvme/nvme_sim.c ============================================================================== --- head/sys/dev/nvme/nvme_sim.c Fri May 25 02:07:05 2018 (r334199) +++ head/sys/dev/nvme/nvme_sim.c Fri May 25 03:34:33 2018 (r334200) @@ -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 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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201805250334.w4P3YXet006531>