From 38d59d8b5acff6aa167019995ce3d9acab775811 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 10 Nov 2020 13:10:24 +0000 Subject: [PATCH] nvme: add function to check if controller supports zone append Zone append is an optional command in the Zoned Namespace Command Set. Add a convenience function to check if the controller supports the zone append command. The ratified NVMe TP 4056 added a CSI field (in cdw14) to the Get Log Page command. However, since there already exist two public functions to get a log page (spdk_nvme_ctrlr_cmd_get_log_page() and spdk_nvme_ctrlr_cmd_get_log_page_ext()), avoid creating a third one for now, since nvme_ctrlr_get_zns_cmd_and_effects_log() itself can leverage one of the existing public functions. Signed-off-by: Niklas Cassel Change-Id: I99516dbac8db6714488b4d6cabe64c27f46d6153 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/5078 Community-CI: Broadcom CI Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Shuhei Matsumoto Reviewed-by: Paul Luse --- include/spdk/nvme.h | 1 + lib/nvme/nvme_ctrlr.c | 72 ++++++++++++++++++- lib/nvme/nvme_internal.h | 13 ++++ .../lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c | 10 +++ 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index 0eb949ef2..24ab0a79e 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -425,6 +425,7 @@ enum spdk_nvme_ctrlr_flags { SPDK_NVME_CTRLR_WRR_SUPPORTED = 1 << 2, /**< Weighted Round Robin is supported */ SPDK_NVME_CTRLR_COMPARE_AND_WRITE_SUPPORTED = 1 << 3, /**< Compare and write fused operations supported */ SPDK_NVME_CTRLR_SGL_REQUIRES_DWORD_ALIGNMENT = 1 << 4, /**< Dword alignment is required for SGL */ + SPDK_NVME_CTRLR_ZONE_APPEND_SUPPORTED = 1 << 5, /**< Zone Append is supported (within Zoned Namespaces) */ }; /** diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index 536ffbe3f..7deeec193 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -1160,6 +1160,10 @@ nvme_ctrlr_state_string(enum nvme_ctrlr_state state) 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_GET_ZNS_CMD_EFFECTS_LOG: + return "get zns cmd and effects log page"; + case NVME_CTRLR_STATE_WAIT_FOR_GET_ZNS_CMD_EFFECTS_LOG: + return "wait for get zns cmd and effects log page"; case NVME_CTRLR_STATE_SET_NUM_QUEUES: return "set number of queues"; case NVME_CTRLR_STATE_WAIT_FOR_SET_NUM_QUEUES: @@ -1592,6 +1596,64 @@ nvme_ctrlr_identify(struct spdk_nvme_ctrlr *ctrlr) return 0; } +static void +nvme_ctrlr_get_zns_cmd_and_effects_log_done(void *arg, const struct spdk_nvme_cpl *cpl) +{ + struct spdk_nvme_cmds_and_effect_log_page *log_page; + struct spdk_nvme_ctrlr *ctrlr = arg; + + if (spdk_nvme_cpl_is_error(cpl)) { + SPDK_ERRLOG("nvme_ctrlr_get_zns_cmd_and_effects_log failed!\n"); + spdk_free(ctrlr->tmp_ptr); + ctrlr->tmp_ptr = NULL; + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ERROR, NVME_TIMEOUT_INFINITE); + return; + } + + log_page = ctrlr->tmp_ptr; + + if (log_page->io_cmds_supported[SPDK_NVME_OPC_ZONE_APPEND].csupp) { + ctrlr->flags |= SPDK_NVME_CTRLR_ZONE_APPEND_SUPPORTED; + } + spdk_free(ctrlr->tmp_ptr); + ctrlr->tmp_ptr = NULL; + + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_SET_NUM_QUEUES, ctrlr->opts.admin_timeout_ms); +} + +static int +nvme_ctrlr_get_zns_cmd_and_effects_log(struct spdk_nvme_ctrlr *ctrlr) +{ + int rc; + + assert(!ctrlr->tmp_ptr); + ctrlr->tmp_ptr = spdk_zmalloc(sizeof(struct spdk_nvme_cmds_and_effect_log_page), 64, NULL, + SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_SHARE | SPDK_MALLOC_DMA); + if (!ctrlr->tmp_ptr) { + rc = -ENOMEM; + goto error; + } + + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_WAIT_FOR_GET_ZNS_CMD_EFFECTS_LOG, + ctrlr->opts.admin_timeout_ms); + + rc = spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_COMMAND_EFFECTS_LOG, + 0, ctrlr->tmp_ptr, sizeof(struct spdk_nvme_cmds_and_effect_log_page), + 0, 0, 0, SPDK_NVME_CSI_ZNS << 24, + nvme_ctrlr_get_zns_cmd_and_effects_log_done, ctrlr); + if (rc != 0) { + goto error; + } + + return 0; + +error: + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ERROR, NVME_TIMEOUT_INFINITE); + spdk_free(ctrlr->tmp_ptr); + ctrlr->tmp_ptr = NULL; + return rc; +} + static void nvme_ctrlr_identify_zns_specific_done(void *arg, const struct spdk_nvme_cpl *cpl) { @@ -1600,9 +1662,12 @@ nvme_ctrlr_identify_zns_specific_done(void *arg, const struct spdk_nvme_cpl *cpl 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); + return; } - nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_SET_NUM_QUEUES, + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_GET_ZNS_CMD_EFFECTS_LOG, ctrlr->opts.admin_timeout_ms); } @@ -3053,6 +3118,10 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr) rc = nvme_ctrlr_identify_iocs_specific(ctrlr); break; + case NVME_CTRLR_STATE_GET_ZNS_CMD_EFFECTS_LOG: + rc = nvme_ctrlr_get_zns_cmd_and_effects_log(ctrlr); + break; + case NVME_CTRLR_STATE_SET_NUM_QUEUES: nvme_ctrlr_update_nvmf_ioccsz(ctrlr); rc = nvme_ctrlr_set_num_queues(ctrlr); @@ -3118,6 +3187,7 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr) case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY: case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_IOCS_SPECIFIC: + case NVME_CTRLR_STATE_WAIT_FOR_GET_ZNS_CMD_EFFECTS_LOG: case NVME_CTRLR_STATE_WAIT_FOR_SET_NUM_QUEUES: case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_ACTIVE_NS: case NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_NS: diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index 30419781e..eca1c05fb 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -548,6 +548,16 @@ enum nvme_ctrlr_state { */ NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_IOCS_SPECIFIC, + /** + * Get Commands Supported and Effects log page for the Zoned Namespace Command Set. + */ + NVME_CTRLR_STATE_GET_ZNS_CMD_EFFECTS_LOG, + + /** + * Waiting for the Get Log Page command to be completed. + */ + NVME_CTRLR_STATE_WAIT_FOR_GET_ZNS_CMD_EFFECTS_LOG, + /** * Set Number of Queues of the controller. */ @@ -835,6 +845,9 @@ struct spdk_nvme_ctrlr { struct spdk_nvme_ana_page *ana_log_page; uint32_t ana_log_page_size; + + /* scratchpad pointer that can be used to send data between two NVME_CTRLR_STATEs */ + void *tmp_ptr; }; struct spdk_nvme_probe_ctx { 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 a0409e7a4..aa1f2e90f 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 @@ -257,6 +257,16 @@ spdk_nvme_ctrlr_cmd_get_log_page(struct spdk_nvme_ctrlr *ctrlr, uint8_t log_page return 0; } +int +spdk_nvme_ctrlr_cmd_get_log_page_ext(struct spdk_nvme_ctrlr *ctrlr, uint8_t log_page, + uint32_t nsid, void *payload, uint32_t payload_size, + uint64_t offset, uint32_t cdw10, uint32_t cdw11, + uint32_t cdw14, spdk_nvme_cmd_cb cb_fn, void *cb_arg) +{ + fake_cpl_sc(cb_fn, cb_arg); + return 0; +} + int nvme_qpair_submit_request(struct spdk_nvme_qpair *qpair, struct nvme_request *req) {