nvme: add new state to get Identify IOCS Specific Controller data structs

Add a new state in the SPDK NVMe state machine in order to fetch
I/O Command Set Specific Controller data structures.

Right now there is only support for the Zoned Namespace Command Set
Specific Identify Controller data structure.

The NVM Command Set Specific Identify Controller data structure is
all zeroes right now, reserved for future use.
The Key Value Command Set Identify Controller data structure is also
all zeroes right now, reserved for future use.

The new NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC state is added
after the NVME_CTRLR_STATE_IDENTIFY state. That way, if support for
the Zoned Namespace Command Set is enabled during probing, we will
fetch the Zoned Namespace Command Set Specific Identify Controller data
structure, regardless if any Zoned Namespaces are attached or not, and
no additional steps will be needed once a Zoned Namespace is attached.

Since we only have one command set to fetch, avoid creating
NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC substates, although that will
probably be needed when support for another command set is added.

Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
Change-Id: I95535b09b03b7ef2ee9a11eebdbd28aad66d65ba
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4367
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>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
This commit is contained in:
Niklas Cassel 2020-09-17 15:22:56 +00:00 committed by Tomasz Zawadzki
parent a7ddda8166
commit 64563ada5d
3 changed files with 134 additions and 1 deletions

View File

@ -90,6 +90,13 @@ nvme_ctrlr_get_cmbsz(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_cmbsz_regist
&cmbsz->raw);
}
bool
nvme_ctrlr_multi_iocs_enabled(struct spdk_nvme_ctrlr *ctrlr)
{
return ctrlr->cap.bits.css & SPDK_NVME_CAP_CSS_IOCS &&
ctrlr->opts.command_set == SPDK_NVME_CC_CSS_IOCS;
}
/* When the field in spdk_nvme_ctrlr_opts are changed and you change this function, please
* also update the nvme_ctrl_opts_init function in nvme_ctrlr.c
*/
@ -1109,6 +1116,10 @@ nvme_ctrlr_state_string(enum nvme_ctrlr_state state)
return "identify controller";
case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY:
return "wait for identify controller";
case NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC:
return "identify controller iocs specific";
case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_IOCS_SPECIFIC:
return "wait for identify controller iocs specific";
case NVME_CTRLR_STATE_SET_NUM_QUEUES:
return "set number of queues";
case NVME_CTRLR_STATE_WAIT_FOR_SET_NUM_QUEUES:
@ -1190,6 +1201,19 @@ inf:
ctrlr->state_timeout_tsc = NVME_TIMEOUT_INFINITE;
}
static void
nvme_ctrlr_free_zns_specific_data(struct spdk_nvme_ctrlr *ctrlr)
{
spdk_free(ctrlr->cdata_zns);
ctrlr->cdata_zns = NULL;
}
static void
nvme_ctrlr_free_iocs_specific_data(struct spdk_nvme_ctrlr *ctrlr)
{
nvme_ctrlr_free_zns_specific_data(ctrlr);
}
static void
nvme_ctrlr_free_doorbell_buffer(struct spdk_nvme_ctrlr *ctrlr)
{
@ -1346,6 +1370,9 @@ spdk_nvme_ctrlr_reset(struct spdk_nvme_ctrlr *ctrlr)
/* Doorbell buffer config is invalid during reset */
nvme_ctrlr_free_doorbell_buffer(ctrlr);
/* I/O Command Set Specific Identify Controller data is invalidated during reset */
nvme_ctrlr_free_iocs_specific_data(ctrlr);
/* Set the state back to INIT to cause a full hardware reset. */
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_INIT, NVME_TIMEOUT_INFINITE);
@ -1494,7 +1521,7 @@ nvme_ctrlr_identify_done(void *arg, const struct spdk_nvme_cpl *cpl)
ctrlr->flags |= SPDK_NVME_CTRLR_COMPARE_AND_WRITE_SUPPORTED;
}
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_SET_NUM_QUEUES,
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC,
ctrlr->opts.admin_timeout_ms);
}
@ -1517,6 +1544,75 @@ nvme_ctrlr_identify(struct spdk_nvme_ctrlr *ctrlr)
return 0;
}
static void
nvme_ctrlr_identify_zns_specific_done(void *arg, const struct spdk_nvme_cpl *cpl)
{
struct spdk_nvme_ctrlr *ctrlr = (struct spdk_nvme_ctrlr *)arg;
if (spdk_nvme_cpl_is_error(cpl)) {
/* no need to print an error, the controller simply does not support ZNS */
nvme_ctrlr_free_zns_specific_data(ctrlr);
}
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_SET_NUM_QUEUES,
ctrlr->opts.admin_timeout_ms);
}
/**
* This function will try to fetch the I/O Command Specific Controller data structure for
* each I/O Command Set supported by SPDK.
*
* If an I/O Command Set is not supported by the controller, "Invalid Field in Command"
* will be returned. Since we are fetching in a exploratively way, getting an error back
* from the controller should not be treated as fatal.
*
* I/O Command Sets not supported by SPDK will be skipped (e.g. Key Value Command Set).
*
* I/O Command Sets without a IOCS specific data structure (i.e. a zero-filled IOCS specific
* data structure) will be skipped (e.g. NVM Command Set, Key Value Command Set).
*/
static int
nvme_ctrlr_identify_iocs_specific(struct spdk_nvme_ctrlr *ctrlr)
{
int rc;
if (!nvme_ctrlr_multi_iocs_enabled(ctrlr)) {
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_SET_NUM_QUEUES,
ctrlr->opts.admin_timeout_ms);
return 0;
}
/*
* Since SPDK currently only needs to fetch a single Command Set, keep the code here,
* instead of creating multiple NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC substates,
* which would require additional functions and complexity for no good reason.
*/
assert(!ctrlr->cdata_zns);
ctrlr->cdata_zns = spdk_zmalloc(sizeof(*ctrlr->cdata_zns), 64, NULL, SPDK_ENV_SOCKET_ID_ANY,
SPDK_MALLOC_SHARE | SPDK_MALLOC_DMA);
if (!ctrlr->cdata_zns) {
rc = -ENOMEM;
goto error;
}
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_IOCS_SPECIFIC,
ctrlr->opts.admin_timeout_ms);
rc = nvme_ctrlr_cmd_identify(ctrlr, SPDK_NVME_IDENTIFY_CTRLR_IOCS, 0, 0, SPDK_NVME_CSI_ZNS,
ctrlr->cdata_zns, sizeof(*ctrlr->cdata_zns),
nvme_ctrlr_identify_zns_specific_done, ctrlr);
if (rc != 0) {
goto error;
}
return 0;
error:
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ERROR, NVME_TIMEOUT_INFINITE);
nvme_ctrlr_free_zns_specific_data(ctrlr);
return rc;
}
enum nvme_active_ns_state {
NVME_ACTIVE_NS_STATE_IDLE,
NVME_ACTIVE_NS_STATE_PROCESSING,
@ -2783,6 +2879,14 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr)
spdk_nvme_qpair_process_completions(ctrlr->adminq, 0);
break;
case NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC:
rc = nvme_ctrlr_identify_iocs_specific(ctrlr);
break;
case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_IOCS_SPECIFIC:
spdk_nvme_qpair_process_completions(ctrlr->adminq, 0);
break;
case NVME_CTRLR_STATE_SET_NUM_QUEUES:
nvme_ctrlr_update_nvmf_ioccsz(ctrlr);
rc = nvme_ctrlr_set_num_queues(ctrlr);
@ -3005,6 +3109,7 @@ nvme_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
}
nvme_ctrlr_free_doorbell_buffer(ctrlr);
nvme_ctrlr_free_iocs_specific_data(ctrlr);
if (ctrlr->opts.no_shn_notification) {
SPDK_INFOLOG(SPDK_LOG_NVME, "Disable SSD: %s without shutdown notification\n",

View File

@ -535,6 +535,16 @@ enum nvme_ctrlr_state {
*/
NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY,
/**
* Get Identify I/O Command Set Specific Controller data structure.
*/
NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC,
/**
* Waiting for Identify I/O Command Set Specific Controller command to be completed.
*/
NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_IOCS_SPECIFIC,
/**
* Set Number of Queues of the controller.
*/
@ -761,6 +771,11 @@ struct spdk_nvme_ctrlr {
*/
struct spdk_nvme_ctrlr_data cdata;
/**
* Zoned Namespace Command Set Specific Identify Controller data.
*/
struct spdk_nvme_zns_ctrlr_data *cdata_zns;
/**
* Keep track of active namespaces
*/
@ -943,6 +958,7 @@ int nvme_ctrlr_submit_admin_request(struct spdk_nvme_ctrlr *ctrlr,
int nvme_ctrlr_get_cap(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_cap_register *cap);
int nvme_ctrlr_get_vs(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_vs_register *vs);
int nvme_ctrlr_get_cmbsz(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_cmbsz_register *cmbsz);
bool nvme_ctrlr_multi_iocs_enabled(struct spdk_nvme_ctrlr *ctrlr);
void nvme_ctrlr_init_cap(struct spdk_nvme_ctrlr *ctrlr, const union spdk_nvme_cap_register *cap,
const union spdk_nvme_vs_register *vs);
void nvme_ctrlr_disconnect_qpair(struct spdk_nvme_qpair *qpair);

View File

@ -1986,6 +1986,8 @@ test_nvme_ctrlr_init_set_nvmf_ioccsz(void)
ctrlr.state = NVME_CTRLR_STATE_IDENTIFY;
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_SET_NUM_QUEUES);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_CONSTRUCT_NS);
@ -2000,6 +2002,8 @@ test_nvme_ctrlr_init_set_nvmf_ioccsz(void)
ctrlr.state = NVME_CTRLR_STATE_IDENTIFY;
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_SET_NUM_QUEUES);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_CONSTRUCT_NS);
@ -2016,6 +2020,8 @@ test_nvme_ctrlr_init_set_nvmf_ioccsz(void)
ctrlr.state = NVME_CTRLR_STATE_IDENTIFY;
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_SET_NUM_QUEUES);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_CONSTRUCT_NS);
@ -2032,6 +2038,8 @@ test_nvme_ctrlr_init_set_nvmf_ioccsz(void)
ctrlr.state = NVME_CTRLR_STATE_IDENTIFY;
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_SET_NUM_QUEUES);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_CONSTRUCT_NS);
@ -2048,6 +2056,8 @@ test_nvme_ctrlr_init_set_nvmf_ioccsz(void)
ctrlr.state = NVME_CTRLR_STATE_IDENTIFY;
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_SET_NUM_QUEUES);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0);
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_CONSTRUCT_NS);
@ -2064,6 +2074,8 @@ test_nvme_ctrlr_init_set_num_queues(void)
DECLARE_AND_CONSTRUCT_CTRLR();
ctrlr.state = NVME_CTRLR_STATE_IDENTIFY;
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0); /* -> SET_IDENTIFY_IOCS_SPECIFIC */
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_IDENTIFY_IOCS_SPECIFIC);
CU_ASSERT(nvme_ctrlr_process_init(&ctrlr) == 0); /* -> SET_NUM_QUEUES */
CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_SET_NUM_QUEUES);