diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index efd346095..40b0c0a12 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -46,6 +46,7 @@ static int nvme_ctrlr_construct_and_submit_aer(struct spdk_nvme_ctrlr *ctrlr, struct nvme_async_event_request *aer); static void nvme_ctrlr_identify_active_ns_async(struct nvme_active_ns_ctx *ctx); static int nvme_ctrlr_identify_ns_async(struct spdk_nvme_ns *ns); +static int nvme_ctrlr_identify_ns_iocs_specific_async(struct spdk_nvme_ns *ns); static int nvme_ctrlr_identify_id_desc_async(struct spdk_nvme_ns *ns); static int @@ -1138,6 +1139,10 @@ nvme_ctrlr_state_string(enum nvme_ctrlr_state state) return "identify namespace id descriptors"; case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_ID_DESCS: return "wait for identify namespace id descriptors"; + case NVME_CTRLR_STATE_IDENTIFY_NS_IOCS_SPECIFIC: + return "identify ns iocs specific"; + case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_NS_IOCS_SPECIFIC: + return "wait for identify ns iocs specific"; case NVME_CTRLR_STATE_CONFIGURE_AER: return "configure AER"; case NVME_CTRLR_STATE_WAIT_FOR_CONFIGURE_AER: @@ -1888,6 +1893,114 @@ nvme_ctrlr_identify_namespaces(struct spdk_nvme_ctrlr *ctrlr) return rc; } +static int +nvme_ctrlr_identify_namespaces_iocs_specific_next(struct spdk_nvme_ctrlr *ctrlr, uint32_t prev_nsid) +{ + uint32_t nsid; + struct spdk_nvme_ns *ns; + int rc; + + if (!prev_nsid) { + nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr); + } else { + /* move on to the next active NS */ + nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, prev_nsid); + } + + ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid); + if (ns == NULL) { + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_CONFIGURE_AER, + ctrlr->opts.admin_timeout_ms); + return 0; + } + + /* loop until we find a ns which has (supported) iocs specific data */ + while (!nvme_ns_has_supported_iocs_specific_data(ns)) { + nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, ns->id); + ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid); + if (ns == NULL) { + /* no namespace with (supported) iocs specific data found */ + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_CONFIGURE_AER, + ctrlr->opts.admin_timeout_ms); + return 0; + } + } + + rc = nvme_ctrlr_identify_ns_iocs_specific_async(ns); + if (rc) { + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ERROR, NVME_TIMEOUT_INFINITE); + } + + return rc; +} + +static void +nvme_ctrlr_identify_ns_zns_specific_async_done(void *arg, const struct spdk_nvme_cpl *cpl) +{ + struct spdk_nvme_ns *ns = (struct spdk_nvme_ns *)arg; + struct spdk_nvme_ctrlr *ctrlr = ns->ctrlr; + + if (spdk_nvme_cpl_is_error(cpl)) { + nvme_ns_free_zns_specific_data(ns); + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ERROR, NVME_TIMEOUT_INFINITE); + return; + } + + nvme_ctrlr_identify_namespaces_iocs_specific_next(ctrlr, ns->id); +} + +static int +nvme_ctrlr_identify_ns_iocs_specific_async(struct spdk_nvme_ns *ns) +{ + struct spdk_nvme_ctrlr *ctrlr = ns->ctrlr; + struct spdk_nvme_zns_ns_data **nsdata_zns; + int rc; + + switch (ns->csi) { + case SPDK_NVME_CSI_ZNS: + break; + default: + /* + * This switch must handle all cases for which + * nvme_ns_has_supported_iocs_specific_data() returns true, + * other cases should never happen. + */ + assert(0); + } + + assert(ctrlr->nsdata_zns); + nsdata_zns = &ctrlr->nsdata_zns[ns->id - 1]; + assert(!*nsdata_zns); + *nsdata_zns = spdk_zmalloc(sizeof(**nsdata_zns), 64, NULL, SPDK_ENV_SOCKET_ID_ANY, + SPDK_MALLOC_SHARE | SPDK_MALLOC_DMA); + if (!*nsdata_zns) { + return -ENOMEM; + } + + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_NS_IOCS_SPECIFIC, + ctrlr->opts.admin_timeout_ms); + rc = nvme_ctrlr_cmd_identify(ns->ctrlr, SPDK_NVME_IDENTIFY_NS_IOCS, 0, ns->id, ns->csi, + *nsdata_zns, sizeof(**nsdata_zns), + nvme_ctrlr_identify_ns_zns_specific_async_done, ns); + if (rc) { + nvme_ns_free_zns_specific_data(ns); + } + + return rc; +} + +static int +nvme_ctrlr_identify_namespaces_iocs_specific(struct spdk_nvme_ctrlr *ctrlr) +{ + if (!nvme_ctrlr_multi_iocs_enabled(ctrlr)) { + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_CONFIGURE_AER, + ctrlr->opts.admin_timeout_ms); + return 0; + } + + return nvme_ctrlr_identify_namespaces_iocs_specific_next(ctrlr, 0); +} + static void nvme_ctrlr_identify_id_desc_async_done(void *arg, const struct spdk_nvme_cpl *cpl) { @@ -1908,7 +2021,7 @@ nvme_ctrlr_identify_id_desc_async_done(void *arg, const struct spdk_nvme_cpl *cp nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, ns->id); ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid); if (ns == NULL) { - nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_CONFIGURE_AER, + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_IDENTIFY_NS_IOCS_SPECIFIC, ctrlr->opts.admin_timeout_ms); return; } @@ -2221,6 +2334,9 @@ nvme_ctrlr_destruct_namespaces(struct spdk_nvme_ctrlr *ctrlr) ctrlr->nsdata = NULL; } + spdk_free(ctrlr->nsdata_zns); + ctrlr->nsdata_zns = NULL; + spdk_free(ctrlr->active_ns_list); ctrlr->active_ns_list = NULL; } @@ -2262,7 +2378,7 @@ static int nvme_ctrlr_construct_namespaces(struct spdk_nvme_ctrlr *ctrlr) { int rc = 0; - uint32_t nn = ctrlr->cdata.nn; + uint32_t i, nn = ctrlr->cdata.nn; /* ctrlr->num_ns may be 0 (startup) or a different number of namespaces (reset), * so check if we need to reallocate. @@ -2290,7 +2406,22 @@ nvme_ctrlr_construct_namespaces(struct spdk_nvme_ctrlr *ctrlr) goto fail; } + ctrlr->nsdata_zns = spdk_zmalloc(nn * sizeof(struct spdk_nvme_zns_ns_data *), 64, + NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_SHARE); + if (ctrlr->nsdata_zns == NULL) { + rc = -ENOMEM; + goto fail; + } + ctrlr->num_ns = nn; + } else { + /* + * The controller could have been reset with the same number of namespaces. + * If so, we still need to free the iocs specific data, to get a clean slate. + */ + for (i = 0; i < ctrlr->num_ns; i++) { + nvme_ns_free_iocs_specific_data(&ctrlr->ns[i]); + } } return 0; @@ -2926,6 +3057,14 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr) spdk_nvme_qpair_process_completions(ctrlr->adminq, 0); break; + case NVME_CTRLR_STATE_IDENTIFY_NS_IOCS_SPECIFIC: + rc = nvme_ctrlr_identify_namespaces_iocs_specific(ctrlr); + break; + + case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_NS_IOCS_SPECIFIC: + spdk_nvme_qpair_process_completions(ctrlr->adminq, 0); + break; + case NVME_CTRLR_STATE_CONFIGURE_AER: rc = nvme_ctrlr_configure_aer(ctrlr); break; diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index 3612113e3..9fe27bd77 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -585,6 +585,16 @@ enum nvme_ctrlr_state { */ NVME_CTRLR_STATE_IDENTIFY_ID_DESCS, + /** + * Get Identify I/O Command Set Specific Namespace data structure for each NS. + */ + NVME_CTRLR_STATE_IDENTIFY_NS_IOCS_SPECIFIC, + + /** + * Waiting for the Identify I/O Command Set Specific Namespace commands to be completed. + */ + NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_NS_IOCS_SPECIFIC, + /** * Waiting for the Identify Namespace Identification * Descriptors to be completed. @@ -788,6 +798,11 @@ struct spdk_nvme_ctrlr { */ struct spdk_nvme_ns_data *nsdata; + /** + * Array of pointers to Zoned Namespace Command Set Specific Identify Namespace data. + */ + struct spdk_nvme_zns_ns_data **nsdata_zns; + struct spdk_bit_array *free_io_qids; TAILQ_HEAD(, spdk_nvme_qpair) active_io_qpairs; @@ -977,6 +992,9 @@ void nvme_qpair_resubmit_requests(struct spdk_nvme_qpair *qpair, uint32_t num_re int nvme_ctrlr_identify_active_ns(struct spdk_nvme_ctrlr *ctrlr); void nvme_ns_set_identify_data(struct spdk_nvme_ns *ns); void nvme_ns_set_id_desc_list_data(struct spdk_nvme_ns *ns); +void nvme_ns_free_zns_specific_data(struct spdk_nvme_ns *ns); +void nvme_ns_free_iocs_specific_data(struct spdk_nvme_ns *ns); +bool nvme_ns_has_supported_iocs_specific_data(struct spdk_nvme_ns *ns); int nvme_ns_construct(struct spdk_nvme_ns *ns, uint32_t id, struct spdk_nvme_ctrlr *ctrlr); void nvme_ns_destruct(struct spdk_nvme_ns *ns); diff --git a/lib/nvme/nvme_ns.c b/lib/nvme/nvme_ns.c index 19008bcff..f2c6293f4 100644 --- a/lib/nvme/nvme_ns.c +++ b/lib/nvme/nvme_ns.c @@ -149,6 +149,64 @@ nvme_ctrlr_identify_ns(struct spdk_nvme_ns *ns) return 0; } +static int +nvme_ctrlr_identify_ns_iocs_specific(struct spdk_nvme_ns *ns) +{ + struct nvme_completion_poll_status *status; + struct spdk_nvme_ctrlr *ctrlr = ns->ctrlr; + struct spdk_nvme_zns_ns_data **nsdata_zns; + int rc; + + switch (ns->csi) { + case SPDK_NVME_CSI_ZNS: + break; + default: + /* + * This switch must handle all cases for which + * nvme_ns_has_supported_iocs_specific_data() returns true, + * other cases should never happen. + */ + assert(0); + } + + assert(ctrlr->nsdata_zns); + nsdata_zns = &ctrlr->nsdata_zns[ns->id - 1]; + assert(!*nsdata_zns); + *nsdata_zns = spdk_zmalloc(sizeof(**nsdata_zns), 64, NULL, SPDK_ENV_SOCKET_ID_ANY, + SPDK_MALLOC_SHARE | SPDK_MALLOC_DMA); + if (!*nsdata_zns) { + return -ENOMEM; + } + + status = calloc(1, sizeof(*status)); + if (!status) { + SPDK_ERRLOG("Failed to allocate status tracker\n"); + nvme_ns_free_zns_specific_data(ns); + return -ENOMEM; + } + + rc = nvme_ctrlr_cmd_identify(ctrlr, SPDK_NVME_IDENTIFY_NS_IOCS, 0, ns->id, ns->csi, + *nsdata_zns, sizeof(**nsdata_zns), + nvme_completion_poll_cb, status); + if (rc != 0) { + nvme_ns_free_zns_specific_data(ns); + free(status); + return rc; + } + + if (nvme_wait_for_completion_robust_lock(ctrlr->adminq, status, &ctrlr->ctrlr_lock)) { + SPDK_ERRLOG("Failed to retrieve Identify IOCS Specific Namespace Data Structure\n"); + nvme_ns_free_zns_specific_data(ns); + if (!status->timed_out) { + free(status); + } + return -ENXIO; + } + free(status); + + return 0; +} + static int nvme_ctrlr_identify_id_desc(struct spdk_nvme_ns *ns) { @@ -397,6 +455,43 @@ spdk_nvme_ns_get_csi(const struct spdk_nvme_ns *ns) { return ns->csi; } +void +nvme_ns_free_zns_specific_data(struct spdk_nvme_ns *ns) +{ + if (!ns->id) { + return; + } + + if (ns->ctrlr->nsdata_zns) { + spdk_free(ns->ctrlr->nsdata_zns[ns->id - 1]); + ns->ctrlr->nsdata_zns[ns->id - 1] = NULL; + } +} + +void +nvme_ns_free_iocs_specific_data(struct spdk_nvme_ns *ns) +{ + nvme_ns_free_zns_specific_data(ns); +} + +bool +nvme_ns_has_supported_iocs_specific_data(struct spdk_nvme_ns *ns) +{ + switch (ns->csi) { + case SPDK_NVME_CSI_NVM: + /* + * NVM Command Set Specific Identify Namespace data structure + * is currently all-zeroes, reserved for future use. + */ + return false; + case SPDK_NVME_CSI_ZNS: + return true; + default: + SPDK_WARNLOG("Unsupported CSI: %u for NSID: %u\n", ns->csi, ns->id); + return false; + } +} + uint32_t spdk_nvme_ns_get_ana_group_id(const struct spdk_nvme_ns *ns) { @@ -428,7 +523,20 @@ int nvme_ns_construct(struct spdk_nvme_ns *ns, uint32_t id, return 0; } - return nvme_ctrlr_identify_id_desc(ns); + rc = nvme_ctrlr_identify_id_desc(ns); + if (rc != 0) { + return rc; + } + + if (nvme_ctrlr_multi_iocs_enabled(ctrlr) && + nvme_ns_has_supported_iocs_specific_data(ns)) { + rc = nvme_ctrlr_identify_ns_iocs_specific(ns); + if (rc != 0) { + return rc; + } + } + + return 0; } void nvme_ns_destruct(struct spdk_nvme_ns *ns) @@ -442,6 +550,7 @@ void nvme_ns_destruct(struct spdk_nvme_ns *ns) nsdata = _nvme_ns_get_data(ns); memset(nsdata, 0, sizeof(*nsdata)); memset(ns->id_desc_list, 0, sizeof(ns->id_desc_list)); + nvme_ns_free_iocs_specific_data(ns); ns->sector_size = 0; ns->extended_lba_size = 0; ns->md_size = 0; diff --git a/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c b/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c index cae21000d..b9e840fb3 100644 --- a/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c +++ b/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c @@ -68,6 +68,9 @@ DEFINE_STUB(nvme_ctrlr_cmd_set_host_id, int, spdk_nvme_cmd_cb cb_fn, void *cb_arg), 0); DEFINE_STUB_V(nvme_ns_set_identify_data, (struct spdk_nvme_ns *ns)); DEFINE_STUB_V(nvme_ns_set_id_desc_list_data, (struct spdk_nvme_ns *ns)); +DEFINE_STUB_V(nvme_ns_free_zns_specific_data, (struct spdk_nvme_ns *ns)); +DEFINE_STUB_V(nvme_ns_free_iocs_specific_data, (struct spdk_nvme_ns *ns)); +DEFINE_STUB(nvme_ns_has_supported_iocs_specific_data, bool, (struct spdk_nvme_ns *ns), false); DEFINE_STUB_V(nvme_qpair_abort_reqs, (struct spdk_nvme_qpair *qpair, uint32_t dnr)); DEFINE_STUB(spdk_nvme_poll_group_remove, int, (struct spdk_nvme_poll_group *group, struct spdk_nvme_qpair *qpair), 0); diff --git a/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c b/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c index fa408bb64..542032b18 100644 --- a/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c +++ b/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c @@ -45,6 +45,7 @@ DEFINE_STUB(nvme_wait_for_completion_robust_lock, int, (struct spdk_nvme_qpair *qpair, struct nvme_completion_poll_status *status, pthread_mutex_t *robust_mutex), 0); +DEFINE_STUB(nvme_ctrlr_multi_iocs_enabled, bool, (struct spdk_nvme_ctrlr *ctrlr), true); int nvme_ctrlr_cmd_identify(struct spdk_nvme_ctrlr *ctrlr, uint8_t cns, uint16_t cntid, uint32_t nsid,