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:
Niklas Cassel 2020-09-17 15:27:31 +00:00 committed by Tomasz Zawadzki
parent 64563ada5d
commit c4d1b7d57a
5 changed files with 273 additions and 3 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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,