svn commit: r334200 - in head/sys: cam cam/nvme dev/nvme

Alexander Motin mav at FreeBSD.org
Fri May 25 03:34:36 UTC 2018


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;


More information about the svn-src-all mailing list