aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2018-05-25 03:34:33 +0000
committerAlexander Motin <mav@FreeBSD.org>2018-05-25 03:34:33 +0000
commitf439e3a4ff12c411345fd653e9ca4d75b36ada5d (patch)
treec2689ce10c0d1405fbbd8cd865595e311eddcaa4
parentea089f8c71775bc0e37c00883bcf3244f0683c7b (diff)
Notes
-rw-r--r--sys/cam/cam_xpt.c2
-rw-r--r--sys/cam/cam_xpt_internal.h4
-rw-r--r--sys/cam/nvme/nvme_xpt.c193
-rw-r--r--sys/dev/nvme/nvme.c18
-rw-r--r--sys/dev/nvme/nvme.h17
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c34
-rw-r--r--sys/dev/nvme/nvme_ctrlr_cmd.c2
-rw-r--r--sys/dev/nvme/nvme_private.h7
-rw-r--r--sys/dev/nvme/nvme_sim.c139
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;