Index: sys/cam/nvme/nvme_da.c =================================================================== --- sys/cam/nvme/nvme_da.c +++ sys/cam/nvme/nvme_da.c @@ -642,17 +642,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; @@ -679,15 +713,42 @@ "due to status 0x%x\n", status); break; } + case AC_GETDEV_CHANGED: + { + struct disk *disk; + char announce_buf[80]; + + softc = (struct nda_softc *)periph->softc; + cgd = (struct ccb_getdev *)arg; + disk = softc->disk; + + /* + * Update our information based on the new Identify data. + */ + ndasetgeom(softc, periph); + error = disk_resize(disk, M_NOWAIT); + if (error != 0) { + xpt_print(periph->path, "disk_resize(9) failed, error = %d\n", error); + break; + } + + snprintf(announce_buf, sizeof(announce_buf), + "%juMB (%ju %u byte sectors)", + (uintmax_t)((uintmax_t)disk->d_mediasize / (1024*1024)), + (uintmax_t)disk->d_mediasize / disk->d_sectorsize, + disk->d_sectorsize); + xpt_announce_periph(periph, announce_buf); + + cam_periph_async(periph, code, path, arg); + 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; + softc = (struct nda_softc *)periph->softc; disk_attr_changed(softc->disk, "GEOM::physpath", M_NOWAIT); } @@ -845,7 +906,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; @@ -892,6 +952,7 @@ softc->quirks = quirks; cam_iosched_set_sort_queue(softc->cam_iosched, 0); softc->disk = disk = disk_alloc(); + ndasetgeom(softc, periph); disk->d_rotation_rate = DISK_RR_NON_ROTATING; disk->d_open = ndaopen; disk->d_close = ndaclose; @@ -910,24 +971,6 @@ 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; - } /* * d_ident and d_descr are both far bigger than the length of either * the serial or model number strings. @@ -993,7 +1036,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/dev/nvd/nvd.c =================================================================== --- sys/dev/nvd/nvd.c +++ sys/dev/nvd/nvd.c @@ -65,6 +65,9 @@ static void *nvd_new_disk(struct nvme_namespace *ns, void *ctrlr); static void *nvd_new_controller(struct nvme_controller *ctrlr); +static void nvd_controller_async(void *ctrlr_arg, + const struct nvme_completion *async_cpl, + uint32_t log_page_id, void *log_page_buffer, uint32_t log_page_size); static void nvd_controller_fail(void *ctrlr); static int nvd_load(void); @@ -157,7 +160,7 @@ TAILQ_INIT(&disk_head); consumer_handle = nvme_register_consumer(nvd_new_disk, - nvd_new_controller, NULL, nvd_controller_fail); + nvd_new_controller, nvd_controller_async, nvd_controller_fail); return (consumer_handle != NULL ? 0 : -1); } @@ -264,6 +267,28 @@ mtx_unlock(&ndisk->bioqlock); } +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_gonecb(struct disk *dp) { @@ -502,6 +527,18 @@ return (ndisk); } +static void +nvd_controller_async(void *ctrlr_arg, const struct nvme_completion *async_cpl, + uint32_t log_page_id, void *log_page_buffer, uint32_t log_page_size) +{ + struct nvd_controller *ctrlr = ctrlr_arg; + struct nvd_disk *ndisk; + + mtx_lock(&nvd_lock); + TAILQ_FOREACH(ndisk, &ctrlr->disk_head, ctrlr_tailq) + nvd_resize(ndisk); + mtx_unlock(&nvd_lock); +} static void nvd_controller_fail(void *ctrlr_arg) Index: sys/dev/nvme/nvme.c =================================================================== --- sys/dev/nvme/nvme.c +++ sys/dev/nvme/nvme.c @@ -278,30 +278,6 @@ } } -void -nvme_notify_ns(struct nvme_controller *ctrlr, int nsid) -{ - struct nvme_consumer *cons; - struct nvme_namespace *ns; - void *ctrlr_cookie; - uint32_t i; - - KASSERT(nsid <= NVME_MAX_NAMESPACES, - ("%s: Namespace notification to nsid %d exceeds range\n", - device_get_nameunit(ctrlr->dev), nsid)); - - if (!ctrlr->is_initialized) - return; - - ns = &ctrlr->ns[nsid - 1]; - for (i = 0; i < NVME_MAX_CONSUMERS; i++) { - cons = &nvme_consumer[i]; - if (cons->id != INVALID_CONSUMER_ID && cons->ns_fn != NULL && - (ctrlr_cookie = ctrlr->cons_cookie[i]) != NULL) - ns->cons_cookie[i] = (*cons->ns_fn)(ns, ctrlr_cookie); - } -} - 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, Index: sys/dev/nvme/nvme_ctrlr.c =================================================================== --- sys/dev/nvme/nvme_ctrlr.c +++ sys/dev/nvme/nvme_ctrlr.c @@ -682,7 +682,6 @@ { 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; @@ -750,14 +749,6 @@ ~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]); - } } /* Index: sys/dev/nvme/nvme_private.h =================================================================== --- sys/dev/nvme/nvme_private.h +++ sys/dev/nvme/nvme_private.h @@ -569,7 +569,6 @@ 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_shared_handler(void *arg); void nvme_ctrlr_poll(struct nvme_controller *ctrlr); Index: sys/dev/nvme/nvme_sim.c =================================================================== --- sys/dev/nvme/nvme_sim.c +++ sys/dev/nvme/nvme_sim.c @@ -323,7 +323,7 @@ } static void * -nvme_sim_ns_change(struct nvme_namespace *ns, void *sc_arg) +nvme_sim_new_ns(struct nvme_namespace *ns, void *sc_arg) { struct nvme_sim_softc *sc = sc_arg; union ccb *ccb; @@ -350,6 +350,21 @@ return (sc_arg); } +static void +nvme_sim_controller_async(void *ctrlr_arg, const struct nvme_completion *async_cpl, + uint32_t log_page_id, void *log_page_buffer, uint32_t log_page_size) +{ + struct nvme_sim_softc *sc = ctrlr_arg; + + switch (log_page_id) { + case NVME_LOG_CHANGED_NAMESPACE: + xpt_async(AC_GETDEV_CHANGED, sc->s_path, NULL); + break; + default: + break; + } +} + static void nvme_sim_controller_fail(void *ctrlr_arg) { @@ -370,8 +385,8 @@ if (nvme_use_nvd) return; - consumer_cookie = nvme_register_consumer(nvme_sim_ns_change, - nvme_sim_new_controller, NULL, nvme_sim_controller_fail); + consumer_cookie = nvme_register_consumer(nvme_sim_new_ns, + nvme_sim_new_controller, nvme_sim_controller_async, nvme_sim_controller_fail); } SYSINIT(nvme_sim_register, SI_SUB_DRIVERS, SI_ORDER_ANY,