aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/nvme
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/nvme')
-rw-r--r--sys/dev/nvme/nvme.h27
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c35
-rw-r--r--sys/dev/nvme/nvme_ns.c11
-rw-r--r--sys/dev/nvme/nvme_private.h1
-rw-r--r--sys/dev/nvme/nvme_sim.c28
5 files changed, 64 insertions, 38 deletions
diff --git a/sys/dev/nvme/nvme.h b/sys/dev/nvme/nvme.h
index f4ea08f129c0..c8eba3df9c2a 100644
--- a/sys/dev/nvme/nvme.h
+++ b/sys/dev/nvme/nvme.h
@@ -1910,6 +1910,8 @@ void nvme_sc_sbuf(const struct nvme_completion *cpl, struct sbuf *sbuf);
void nvme_strvis(uint8_t *dst, const uint8_t *src, int dstlen, int srclen);
#ifdef _KERNEL
+#include <sys/systm.h>
+#include <sys/disk.h>
struct bio;
struct thread;
@@ -1928,8 +1930,11 @@ typedef void (*nvme_cons_async_fn_t)(void *, const struct nvme_completion *,
typedef void (*nvme_cons_fail_fn_t)(void *);
enum nvme_namespace_flags {
- NVME_NS_DEALLOCATE_SUPPORTED = 0x1,
- NVME_NS_FLUSH_SUPPORTED = 0x2,
+ NVME_NS_DEALLOCATE_SUPPORTED = 0x01,
+ NVME_NS_FLUSH_SUPPORTED = 0x02,
+ NVME_NS_ADDED = 0x04,
+ NVME_NS_CHANGED = 0x08,
+ NVME_NS_GONE = 0x10,
};
int nvme_ctrlr_passthrough_cmd(struct nvme_controller *ctrlr,
@@ -1995,6 +2000,24 @@ nvme_ctrlr_has_dataset_mgmt(const struct nvme_controller_data *cd)
return (NVMEV(NVME_CTRLR_DATA_ONCS_DSM, cd->oncs) != 0);
}
+/*
+ * Copy the NVME device's serial number to the provided buffer, which must be
+ * at least DISK_IDENT_SIZE bytes large.
+ */
+static inline void
+nvme_cdata_get_disk_ident(const struct nvme_controller_data *cdata, uint8_t *sn)
+{
+ _Static_assert(NVME_SERIAL_NUMBER_LENGTH < DISK_IDENT_SIZE,
+ "NVME serial number too big for disk ident");
+
+ memmove(sn, cdata->sn, NVME_SERIAL_NUMBER_LENGTH);
+ sn[NVME_SERIAL_NUMBER_LENGTH] = '\0';
+ for (int i = 0; sn[i] != '\0'; i++) {
+ if (sn[i] < 0x20 || sn[i] >= 0x80)
+ sn[i] = ' ';
+ }
+}
+
/* Namespace helper functions */
uint32_t nvme_ns_get_max_io_xfer_size(struct nvme_namespace *ns);
uint32_t nvme_ns_get_sector_size(struct nvme_namespace *ns);
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index e607667decf5..41542d24c107 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -33,7 +33,6 @@
#include <sys/buf.h>
#include <sys/bus.h>
#include <sys/conf.h>
-#include <sys/disk.h>
#include <sys/ioccom.h>
#include <sys/proc.h>
#include <sys/smp.h>
@@ -1154,7 +1153,7 @@ nvme_ctrlr_aer_task(void *arg, int pending)
mtx_sleep(aer, &aer->mtx, PRIBIO, "nvme_pt", 0);
mtx_unlock(&aer->mtx);
- if (aer->log_page_size != (uint32_t)-1) {
+ if (aer->log_page_size == (uint32_t)-1) {
/*
* If the log page fetch for some reason completed with an
* error, don't pass log page data to the consumers. In
@@ -1217,10 +1216,20 @@ nvme_ctrlr_aer_task(void *arg, int pending)
} else if (aer->log_page_id == NVME_LOG_CHANGED_NAMESPACE) {
struct nvme_ns_list *nsl =
(struct nvme_ns_list *)aer->log_page_buffer;
+ struct nvme_controller *ctrlr = aer->ctrlr;
+
for (int i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) {
+ struct nvme_namespace *ns;
+ uint32_t id = nsl->ns[i];
+
if (nsl->ns[i] > NVME_MAX_NAMESPACES)
break;
- nvme_notify_ns(aer->ctrlr, nsl->ns[i]);
+
+ ns = &ctrlr->ns[id - 1];
+ ns->flags |= NVME_NS_CHANGED;
+ nvme_ns_construct(ns, id, ctrlr);
+ nvme_notify_ns(ctrlr, id);
+ ns->flags &= ~NVME_NS_CHANGED;
}
}
@@ -1255,24 +1264,6 @@ nvme_ctrlr_poll(struct nvme_controller *ctrlr)
}
/*
- * Copy the NVME device's serial number to the provided buffer, which must be
- * at least DISK_IDENT_SIZE bytes large.
- */
-void
-nvme_ctrlr_get_ident(const struct nvme_controller *ctrlr, uint8_t *sn)
-{
- _Static_assert(NVME_SERIAL_NUMBER_LENGTH < DISK_IDENT_SIZE,
- "NVME serial number too big for disk ident");
-
- memmove(sn, ctrlr->cdata.sn, NVME_SERIAL_NUMBER_LENGTH);
- sn[NVME_SERIAL_NUMBER_LENGTH] = '\0';
- for (int i = 0; sn[i] != '\0'; i++) {
- if (sn[i] < 0x20 || sn[i] >= 0x80)
- sn[i] = ' ';
- }
-}
-
-/*
* Poll the single-vector interrupt case: num_io_queues will be 1 and
* there's only a single vector. While we're polling, we mask further
* interrupts in the controller.
@@ -1516,7 +1507,7 @@ nvme_ctrlr_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
break;
case DIOCGIDENT: {
uint8_t *sn = arg;
- nvme_ctrlr_get_ident(ctrlr, sn);
+ nvme_cdata_get_disk_ident(&ctrlr->cdata, sn);
break;
}
/* Linux Compatible (see nvme_linux.h) */
diff --git a/sys/dev/nvme/nvme_ns.c b/sys/dev/nvme/nvme_ns.c
index 17684cc14ba2..4ebcc03c4f04 100644
--- a/sys/dev/nvme/nvme_ns.c
+++ b/sys/dev/nvme/nvme_ns.c
@@ -78,7 +78,7 @@ nvme_ns_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
break;
case NVME_PASSTHROUGH_CMD:
pt = (struct nvme_pt_command *)arg;
- return (nvme_ctrlr_passthrough_cmd(ctrlr, pt, ns->id,
+ return (nvme_ctrlr_passthrough_cmd(ctrlr, pt, ns->id,
1 /* is_user_buffer */, 0 /* is_admin_cmd */));
case NVME_GET_NSID:
{
@@ -90,7 +90,7 @@ nvme_ns_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
}
case DIOCGIDENT: {
uint8_t *sn = arg;
- nvme_ctrlr_get_ident(ctrlr, sn);
+ nvme_cdata_get_disk_ident(&ctrlr->cdata, sn);
break;
}
case DIOCGMEDIASIZE:
@@ -558,8 +558,10 @@ nvme_ns_construct(struct nvme_namespace *ns, uint32_t id,
* standard says the entire id will be zeros, so this is a
* cheap way to test for that.
*/
- if (ns->data.nsze == 0)
- return (ENXIO);
+ if (ns->data.nsze == 0) {
+ ns->flags |= NVME_NS_GONE;
+ return ((ns->flags & NVME_NS_ADDED) ? 0 : ENXIO);
+ }
flbas_fmt = NVMEV(NVME_NS_DATA_FLBAS_FORMAT, ns->data.flbas);
@@ -623,6 +625,7 @@ nvme_ns_construct(struct nvme_namespace *ns, uint32_t id,
ns->cdev->si_drv2 = make_dev_alias(ns->cdev, "%sns%d",
device_get_nameunit(ctrlr->dev), ns->id);
ns->cdev->si_flags |= SI_UNMAPPED;
+ ns->flags |= NVME_NS_ADDED;
return (0);
}
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
index dd45e1acd0aa..a425a6a5ad62 100644
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -565,7 +565,6 @@ void nvme_notify_new_controller(struct nvme_controller *ctrlr);
void nvme_notify_ns(struct nvme_controller *ctrlr, int nsid);
void nvme_ctrlr_shared_handler(void *arg);
-void nvme_ctrlr_get_ident(const struct nvme_controller *ctrlr, uint8_t *sn);
void nvme_ctrlr_poll(struct nvme_controller *ctrlr);
int nvme_ctrlr_suspend(struct nvme_controller *ctrlr);
diff --git a/sys/dev/nvme/nvme_sim.c b/sys/dev/nvme/nvme_sim.c
index 7693aa6d54d3..e015fbe4d072 100644
--- a/sys/dev/nvme/nvme_sim.c
+++ b/sys/dev/nvme/nvme_sim.c
@@ -352,25 +352,35 @@ static void *
nvme_sim_ns_change(struct nvme_namespace *ns, void *sc_arg)
{
struct nvme_sim_softc *sc = sc_arg;
+ struct cam_path *tmppath;
union ccb *ccb;
+ if (xpt_create_path(&tmppath, /*periph*/NULL,
+ cam_sim_path(sc->s_sim), 0, ns->id) != CAM_REQ_CMP) {
+ printf("unable to create path for rescan\n");
+ return (NULL);
+ }
+ /*
+ * If it's gone, then signal that and leave.
+ */
+ if (ns->flags & NVME_NS_GONE) {
+ xpt_async(AC_LOST_DEVICE, tmppath, NULL);
+ xpt_free_path(tmppath);
+ return (sc_arg);
+ }
+
ccb = xpt_alloc_ccb_nowait();
if (ccb == NULL) {
printf("unable to alloc CCB for rescan\n");
return (NULL);
}
+ ccb->ccb_h.path = tmppath;
/*
- * We map the NVMe namespace idea onto the CAM unit LUN. For
- * each new namespace, we create a new CAM path for it. We then
- * rescan the path to get it to enumerate.
+ * We map the NVMe namespace idea onto the CAM unit LUN. For each new
+ * namespace, scan or rescan the path to enumerate it. tmppath freed at
+ * end of scan.
*/
- 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 (NULL);
- }
xpt_rescan(ccb);
return (sc_arg);