nvme: add new state to get Identify IOCS Specific Namespace data structs
Add a new state in the SPDK NVMe state machine in order to fetch I/O Command Set Specific Namespace data structures. Right now there is only support for the Zoned Namespace Command Set Specific Identify Namespace data structure. The NVM Command Set Specific Identify Namespace data structure is all zeroes right now, reserved for future use. The Key Value Command Set Identify Namespace data structure is not all zeroes, however, adding support for Key Value is outside the scope of this patch. The new NVME_CTRLR_STATE_IDENTIFY_NS_IOCS_SPECIFIC state is added after the NVME_CTRLR_STATE_IDENTIFY_ID_DESCS state. This is because we need to have fetched the identifiers in the desc list in order to know which command set a namespace belongs to. A slightly nicer design might have been to refactor the NVMe state machine to first fetch the id desc list, then the identify namespace struct, and finally the identify IOCS specific namespace struct. However, since this would have required a lot of changes, it didn't really seem justified. Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com> Change-Id: I62cbc533c2c3eec1ccf0ba9b1c414d5a70919cff Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4368 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
parent
64563ada5d
commit
c4d1b7d57a
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user