Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102844847
D33032.id99354.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D33032.id99354.diff
View Options
Index: sys/cam/nvme/nvme_da.c
===================================================================
--- sys/cam/nvme/nvme_da.c
+++ sys/cam/nvme/nvme_da.c
@@ -640,17 +640,51 @@
cam_periph_lock(periph);
}
+static void
+ndasetgeom(struct nda_softc *softc, struct cam_periph *periph)
+{
+ struct disk *disk = softc->disk;
+ struct ccb_pathinq cpi;
+ const struct nvme_namespace_data *nsd;
+ const struct nvme_controller_data *cd;
+ uint8_t flbas_fmt, lbads, vwc_present;
+
+ nsd = nvme_get_identify_ns(periph);
+ cd = nvme_get_identify_cntrl(periph);
+
+ flbas_fmt = (nsd->flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) &
+ NVME_NS_DATA_FLBAS_FORMAT_MASK;
+ lbads = (nsd->lbaf[flbas_fmt] >> NVME_NS_DATA_LBAF_LBADS_SHIFT) &
+ NVME_NS_DATA_LBAF_LBADS_MASK;
+ disk->d_sectorsize = 1 << lbads;
+ disk->d_mediasize = (off_t)(disk->d_sectorsize * nsd->nsze);
+ disk->d_delmaxsize = disk->d_mediasize;
+ disk->d_flags = DISKFLAG_DIRECT_COMPLETION;
+ if (nvme_ctrlr_has_dataset_mgmt(cd))
+ disk->d_flags |= DISKFLAG_CANDELETE;
+ vwc_present = (cd->vwc >> NVME_CTRLR_DATA_VWC_PRESENT_SHIFT) &
+ NVME_CTRLR_DATA_VWC_PRESENT_MASK;
+ if (vwc_present)
+ disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
+ if ((cpi.hba_misc & PIM_UNMAPPED) != 0) {
+ disk->d_flags |= DISKFLAG_UNMAPPED_BIO;
+ softc->unmappedio = 1;
+ }
+}
+
static void
ndaasync(void *callback_arg, u_int32_t code,
struct cam_path *path, void *arg)
{
struct cam_periph *periph;
+ struct nda_softc *softc;
+ struct ccb_getdev *cgd;
+ int error;
periph = (struct cam_periph *)callback_arg;
switch (code) {
case AC_FOUND_DEVICE:
{
- struct ccb_getdev *cgd;
cam_status status;
cgd = (struct ccb_getdev *)arg;
@@ -677,14 +711,27 @@
"due to status 0x%x\n", status);
break;
}
+ case AC_GETDEV_CHANGED:
+ {
+ softc = (struct nda_softc *)periph->softc;
+
+ /*
+ * Update our information based on the new Identify data.
+ */
+ ndasetgeom(softc, periph);
+ error = disk_resize(softc->disk, M_NOWAIT);
+ if (error != 0) {
+ xpt_print(periph->path, "disk_resize(9) failed, error = %d\n", error);
+ break;
+ }
+ break;
+ }
case AC_ADVINFO_CHANGED:
{
uintptr_t buftype;
buftype = (uintptr_t)arg;
if (buftype == CDAI_TYPE_PHYS_PATH) {
- struct nda_softc *softc;
-
softc = periph->softc;
disk_attr_changed(softc->disk, "GEOM::physpath",
M_NOWAIT);
@@ -843,7 +890,6 @@
const struct nvme_namespace_data *nsd;
const struct nvme_controller_data *cd;
char announce_buf[80];
- uint8_t flbas_fmt, lbads, vwc_present;
u_int maxio;
int quirks;
@@ -908,24 +954,8 @@
else if (maxio > maxphys)
maxio = maxphys; /* for safety */
disk->d_maxsize = maxio;
- flbas_fmt = (nsd->flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) &
- NVME_NS_DATA_FLBAS_FORMAT_MASK;
- lbads = (nsd->lbaf[flbas_fmt] >> NVME_NS_DATA_LBAF_LBADS_SHIFT) &
- NVME_NS_DATA_LBAF_LBADS_MASK;
- disk->d_sectorsize = 1 << lbads;
- disk->d_mediasize = (off_t)(disk->d_sectorsize * nsd->nsze);
- disk->d_delmaxsize = disk->d_mediasize;
- disk->d_flags = DISKFLAG_DIRECT_COMPLETION;
- if (nvme_ctrlr_has_dataset_mgmt(cd))
- disk->d_flags |= DISKFLAG_CANDELETE;
- vwc_present = (cd->vwc >> NVME_CTRLR_DATA_VWC_PRESENT_SHIFT) &
- NVME_CTRLR_DATA_VWC_PRESENT_MASK;
- if (vwc_present)
- disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
- if ((cpi.hba_misc & PIM_UNMAPPED) != 0) {
- disk->d_flags |= DISKFLAG_UNMAPPED_BIO;
- softc->unmappedio = 1;
- }
+
+ ndasetgeom(softc, periph);
/*
* d_ident and d_descr are both far bigger than the length of either
* the serial or model number strings.
@@ -991,7 +1021,7 @@
* Register for device going away and info about the drive
* changing (though with NVMe, it can't)
*/
- xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
+ xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED | AC_GETDEV_CHANGED,
ndaasync, periph, periph->path);
softc->state = NDA_STATE_NORMAL;
Index: sys/cam/nvme/nvme_xpt.c
===================================================================
--- sys/cam/nvme/nvme_xpt.c
+++ sys/cam/nvme/nvme_xpt.c
@@ -460,6 +460,8 @@
done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
xpt_action(done_ccb);
xpt_async(AC_FOUND_DEVICE, path, done_ccb);
+ } else {
+ xpt_async(AC_GETDEV_CHANGED, path, NULL);
}
NVME_PROBE_SET_ACTION(softc, NVME_PROBE_DONE);
break;
Index: sys/dev/nvd/nvd.c
===================================================================
--- sys/dev/nvd/nvd.c
+++ sys/dev/nvd/nvd.c
@@ -62,6 +62,7 @@
static void nvd_done(void *arg, const struct nvme_completion *cpl);
static void nvd_gone(struct nvd_disk *ndisk);
+static void *nvd_ns_change(struct nvme_namespace *ns, void *ctrlr);
static void *nvd_new_disk(struct nvme_namespace *ns, void *ctrlr);
static void *nvd_new_controller(struct nvme_controller *ctrlr);
@@ -156,7 +157,7 @@
TAILQ_INIT(&ctrlr_head);
TAILQ_INIT(&disk_head);
- consumer_handle = nvme_register_consumer(nvd_new_disk,
+ consumer_handle = nvme_register_consumer(nvd_ns_change,
nvd_new_controller, NULL, nvd_controller_fail);
return (consumer_handle != NULL ? 0 : -1);
@@ -413,6 +414,49 @@
return (nvd_ctrlr);
}
+static void
+nvd_resize(struct nvd_disk *ndisk)
+{
+ struct disk *disk = ndisk->disk;
+ struct nvme_namespace *ns = ndisk->ns;
+
+ disk->d_sectorsize = nvme_ns_get_sector_size(ns);
+ disk->d_mediasize = (off_t)nvme_ns_get_size(ns);
+ disk->d_maxsize = nvme_ns_get_max_io_xfer_size(ns);
+ disk->d_delmaxsize = (off_t)nvme_ns_get_size(ns);
+ if (disk->d_delmaxsize > nvd_delete_max)
+ disk->d_delmaxsize = nvd_delete_max;
+
+ disk_resize(disk, M_NOWAIT);
+
+ printf(NVD_STR"%u: NVMe namespace resized\n", ndisk->unit);
+ printf(NVD_STR"%u: %juMB (%ju %u byte sectors)\n", disk->d_unit,
+ (uintmax_t)disk->d_mediasize / (1024*1024),
+ (uintmax_t)disk->d_mediasize / disk->d_sectorsize,
+ disk->d_sectorsize);
+}
+
+static void *
+nvd_ns_change(struct nvme_namespace *ns, void *ctrlr_arg)
+{
+ struct nvd_disk *ndisk;
+ struct nvd_controller *ctrlr = ctrlr_arg;
+
+ if (ns->flags & NVME_NS_FLAG_CHANGED) {
+ mtx_lock(&nvd_lock);
+ TAILQ_FOREACH(ndisk, &ctrlr->disk_head, ctrlr_tailq) {
+ if (ndisk->ns->id == ns->id) {
+ nvd_resize(ndisk);
+ }
+ }
+ mtx_unlock(&nvd_lock);
+ return (ctrlr_arg);
+ }
+
+ nvd_new_disk(ns, ctrlr_arg);
+ return (ctrlr_arg);
+}
+
static void *
nvd_new_disk(struct nvme_namespace *ns, void *ctrlr_arg)
{
Index: sys/dev/nvme/nvme_ctrlr.c
===================================================================
--- sys/dev/nvme/nvme_ctrlr.c
+++ sys/dev/nvme/nvme_ctrlr.c
@@ -260,6 +260,36 @@
mtx_unlock(&ctrlr->lock);
}
+static void
+nvme_ctrlr_post_update_ns_request(struct nvme_controller *ctrlr,
+ struct nvme_namespace *req)
+{
+
+ mtx_lock(&ctrlr->lock);
+ STAILQ_INSERT_TAIL(&ctrlr->update_ns_req, req, stailq);
+ mtx_unlock(&ctrlr->lock);
+ if (!ctrlr->is_dying)
+ taskqueue_enqueue(ctrlr->taskqueue, &ctrlr->update_ns_task);
+}
+
+static void
+nvme_ctrlr_update_ns_req_task(void *arg, int pending)
+{
+ struct nvme_controller *ctrlr = arg;
+ struct nvme_namespace *req;
+
+ mtx_lock(&ctrlr->lock);
+ while ((req = STAILQ_FIRST(&ctrlr->update_ns_req)) != NULL) {
+ STAILQ_REMOVE_HEAD(&ctrlr->update_ns_req, stailq);
+ mtx_unlock(&ctrlr->lock);
+ nvme_ns_construct(req, req->id, ctrlr, NVME_REASON_FLAGGED);
+ nvme_notify_ns(ctrlr, req->id);
+ req->flags &= ~NVME_NS_FLAG_CHANGED;
+ mtx_lock(&ctrlr->lock);
+ }
+ mtx_unlock(&ctrlr->lock);
+}
+
/*
* Wait for RDY to change.
*
@@ -586,7 +616,7 @@
for (i = 0; i < min(ctrlr->cdata.nn, NVME_MAX_NAMESPACES); i++) {
ns = &ctrlr->ns[i];
- nvme_ns_construct(ns, i+1, ctrlr);
+ nvme_ns_construct(ns, i+1, ctrlr, NVME_REASON_RESET);
}
return (0);
@@ -750,13 +780,13 @@
~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) {
+ } else if (aer->log_page_id == NVME_LOG_CHANGED_NAMESPACE) {
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]);
+ nvme_ctrlr_post_update_ns_request(aer->ctrlr,
+ &aer->ctrlr->ns[nsl->ns[i]-1]);
}
}
@@ -1467,14 +1497,16 @@
*/
ctrlr->taskqueue = taskqueue_create("nvme_taskq", M_WAITOK,
taskqueue_thread_enqueue, &ctrlr->taskqueue);
- taskqueue_start_threads(&ctrlr->taskqueue, 2, PI_DISK, "nvme taskq");
+ taskqueue_start_threads(&ctrlr->taskqueue, 3, PI_DISK, "nvme taskq");
ctrlr->is_resetting = 0;
ctrlr->is_initialized = 0;
ctrlr->notification_sent = 0;
TASK_INIT(&ctrlr->reset_task, 0, nvme_ctrlr_reset_task, ctrlr);
TASK_INIT(&ctrlr->fail_req_task, 0, nvme_ctrlr_fail_req_task, ctrlr);
+ TASK_INIT(&ctrlr->update_ns_task, 0, nvme_ctrlr_update_ns_req_task, ctrlr);
STAILQ_INIT(&ctrlr->fail_req);
+ STAILQ_INIT(&ctrlr->update_ns_req);
ctrlr->is_failed = false;
make_dev_args_init(&md_args);
Index: sys/dev/nvme/nvme_ns.c
===================================================================
--- sys/dev/nvme/nvme_ns.c
+++ sys/dev/nvme/nvme_ns.c
@@ -510,7 +510,7 @@
int
nvme_ns_construct(struct nvme_namespace *ns, uint32_t id,
- struct nvme_controller *ctrlr)
+ struct nvme_controller *ctrlr, enum nvme_ctor_reason why)
{
struct make_dev_args md_args;
struct nvme_completion_poll_status status;
@@ -549,10 +549,13 @@
* If the size of is zero, chances are this isn't a valid
* namespace (eg one that's not been configured yet). The
* standard says the entire id will be zeros, so this is a
- * cheap way to test for that.
+ * cheap way to test for that. If we previously added this
+ * device, then it's now gone.
*/
- if (ns->data.nsze == 0)
- return (ENXIO);
+ if (ns->data.nsze == 0) {
+ ns->flags |= NVME_NS_FLAG_GONE;
+ return ((ns->flags & NVME_NS_FLAG_ADDED) ? 0 : ENXIO);
+ }
flbas_fmt = (ns->data.flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) &
NVME_NS_DATA_FLBAS_FORMAT_MASK;
@@ -597,10 +600,14 @@
/*
* cdev may have already been created, if we are reconstructing the
- * namespace after a controller-level reset.
+ * namespace after a controller-level reset. If not, then flag this
+ * ns as changed for notification.
*/
- if (ns->cdev != NULL)
+ if (ns->cdev != NULL) {
+ if (why != NVME_REASON_RESET)
+ ns->flags |= NVME_NS_FLAG_CHANGED;
return (0);
+ }
/*
* Namespace IDs start at 1, so we need to subtract 1 to create a
@@ -619,6 +626,7 @@
return (ENXIO);
ns->cdev->si_flags |= SI_UNMAPPED;
+ ns->flags |= NVME_NS_FLAG_ADDED;
return (0);
}
Index: sys/dev/nvme/nvme_private.h
===================================================================
--- sys/dev/nvme/nvme_private.h
+++ sys/dev/nvme/nvme_private.h
@@ -222,10 +222,14 @@
struct nvme_namespace_data data;
uint32_t id;
uint32_t flags;
+#define NVME_NS_FLAG_ADDED 0x1
+#define NVME_NS_FLAG_CHANGED 0x2
+#define NVME_NS_FLAG_GONE 0x4
struct cdev *cdev;
void *cons_cookie[NVME_MAX_CONSUMERS];
uint32_t boundary;
struct mtx lock;
+ STAILQ_ENTRY(nvme_namespace) stailq;
};
/*
@@ -267,6 +271,7 @@
struct task reset_task;
struct task fail_req_task;
+ struct task update_ns_task;
struct taskqueue *taskqueue;
/* For shared legacy interrupt. */
@@ -317,6 +322,7 @@
bool is_failed;
bool is_dying;
STAILQ_HEAD(, nvme_request) fail_req;
+ STAILQ_HEAD(, nvme_namespace) update_ns_req;
/* Host Memory Buffer */
int hmb_nchunks;
@@ -333,6 +339,11 @@
uint64_t hmb_desc_paddr;
};
+enum nvme_ctor_reason {
+ NVME_REASON_RESET, /* Controller was reset, rebuilding */
+ NVME_REASON_FLAGGED, /* NS was flagged as changed somehow */
+};
+
#define nvme_mmio_offsetof(reg) \
offsetof(struct nvme_registers, reg)
@@ -442,7 +453,7 @@
void nvme_io_qpair_destroy(struct nvme_qpair *qpair);
int nvme_ns_construct(struct nvme_namespace *ns, uint32_t id,
- struct nvme_controller *ctrlr);
+ struct nvme_controller *ctrlr, enum nvme_ctor_reason why);
void nvme_ns_destruct(struct nvme_namespace *ns);
void nvme_sysctl_initialize_ctrlr(struct nvme_controller *ctrlr);
Index: sys/dev/nvme/nvme_sim.c
===================================================================
--- sys/dev/nvme/nvme_sim.c
+++ sys/dev/nvme/nvme_sim.c
@@ -326,25 +326,37 @@
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_FLAG_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.
+ *
+ * At the end of the scan, the path is freed, I think...
*/
- 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);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 18, 10:10 PM (5 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14705539
Default Alt Text
D33032.id99354.diff (13 KB)
Attached To
Mode
D33032: nvme: nvd/nda call disk_resize() when namespace changed async event happened
Attached
Detach File
Event Timeline
Log In to Comment