From 174a5fe140ab630796dd899fabdf551d6e38e29c Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 7 Sep 2020 11:59:35 +0000 Subject: [PATCH] nvme: add initial namespace types support Add support for getting the Command Set Identifier for a given namespace. The SPDK_NVME_CAP_CSS_IOCS feature can be implemented on top of an old NVMe specification. If the feature is set, retrieve the NS ID Descriptor List regardless of the NVMe specification version. The quirk is still respected. Signed-off-by: Niklas Cassel Change-Id: I7b257115ecb0d813ba75201c0f48960c7070dcc9 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4085 Community-CI: Broadcom CI Reviewed-by: Paul Luse Reviewed-by: Jim Harris Reviewed-by: Changpeng Liu Reviewed-by: Shuhei Matsumoto Tested-by: SPDK CI Jenkins --- include/spdk/nvme.h | 9 +++++ include/spdk/nvme_spec.h | 17 +++++++++ lib/nvme/Makefile | 2 +- lib/nvme/nvme_ctrlr.c | 3 +- lib/nvme/nvme_ns.c | 26 +++++++++++++- lib/nvme/spdk_nvme.map | 1 + test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c | 44 +++++++++++++++++++++++ 7 files changed, 99 insertions(+), 3 deletions(-) diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index f23b43a2b..749f87cb2 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -2274,6 +2274,15 @@ uint32_t spdk_nvme_ns_get_optimal_io_boundary(struct spdk_nvme_ns *ns); */ const struct spdk_uuid *spdk_nvme_ns_get_uuid(const struct spdk_nvme_ns *ns); +/** + * Get the Command Set Identifier for the given namespace. + * + * \param ns Namespace to query. + * + * \return the namespace Command Set Identifier. + */ +enum spdk_nvme_csi spdk_nvme_ns_get_csi(const struct spdk_nvme_ns *ns); + /** * \brief Namespace command support flags. */ diff --git a/include/spdk/nvme_spec.h b/include/spdk/nvme_spec.h index ddcf0a91c..91166e3ba 100644 --- a/include/spdk/nvme_spec.h +++ b/include/spdk/nvme_spec.h @@ -980,6 +980,14 @@ SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_cmd_cdw10) == 4, "Incorrect size"); union spdk_nvme_cmd_cdw11 { uint32_t raw; + struct { + /* NVM Set Identifier */ + uint32_t nvmsetid : 16; + uint32_t reserved : 8; + /* Command Set Identifier */ + uint32_t csi : 8; + } identify; + struct { /* Physically Contiguous */ uint32_t pc : 1; @@ -2852,6 +2860,9 @@ enum spdk_nvme_nidt { /** Namespace UUID */ SPDK_NVME_NIDT_UUID = 0x03, + + /** Namespace Command Set Identifier */ + SPDK_NVME_NIDT_CSI = 0x04, }; struct spdk_nvme_ns_id_desc { @@ -2875,6 +2886,12 @@ struct spdk_nvme_ctrlr_list { }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_ctrlr_list) == 4096, "Incorrect size"); +enum spdk_nvme_csi { + SPDK_NVME_CSI_NVM = 0x0, + SPDK_NVME_CSI_KV = 0x1, + SPDK_NVME_CSI_ZNS = 0x2, +}; + enum spdk_nvme_secure_erase_setting { SPDK_NVME_FMT_NVM_SES_NO_SECURE_ERASE = 0x0, SPDK_NVME_FMT_NVM_SES_USER_DATA_ERASE = 0x1, diff --git a/lib/nvme/Makefile b/lib/nvme/Makefile index 1c02965f5..9fe86c090 100644 --- a/lib/nvme/Makefile +++ b/lib/nvme/Makefile @@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk SO_VER := 4 -SO_MINOR := 0 +SO_MINOR := 1 C_SRCS = nvme_ctrlr_cmd.c nvme_ctrlr.c nvme_fabric.c nvme_ns_cmd.c nvme_ns.c nvme_pcie.c nvme_qpair.c nvme.c nvme_quirks.c nvme_transport.c nvme_uevent.c nvme_ctrlr_ocssd_cmd.c \ nvme_ns_ocssd_cmd.c nvme_tcp.c nvme_opal.c nvme_io_msg.c nvme_poll_group.c diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index 25b220e43..14c159421 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -1731,7 +1731,8 @@ nvme_ctrlr_identify_id_desc_namespaces(struct spdk_nvme_ctrlr *ctrlr) struct spdk_nvme_ns *ns; int rc; - if (ctrlr->vs.raw < SPDK_NVME_VERSION(1, 3, 0) || + if ((ctrlr->vs.raw < SPDK_NVME_VERSION(1, 3, 0) && + !(ctrlr->cap.bits.css & SPDK_NVME_CAP_CSS_IOCS)) || (ctrlr->quirks & NVME_QUIRK_IDENTIFY_CNS)) { SPDK_DEBUGLOG(SPDK_LOG_NVME, "Version < 1.3; not attempting to retrieve NS ID Descriptor List\n"); nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_CONFIGURE_AER, diff --git a/lib/nvme/nvme_ns.c b/lib/nvme/nvme_ns.c index 113869362..09ae81c4c 100644 --- a/lib/nvme/nvme_ns.c +++ b/lib/nvme/nvme_ns.c @@ -157,7 +157,8 @@ nvme_ctrlr_identify_id_desc(struct spdk_nvme_ns *ns) memset(ns->id_desc_list, 0, sizeof(ns->id_desc_list)); - if (ns->ctrlr->vs.raw < SPDK_NVME_VERSION(1, 3, 0) || + if ((ns->ctrlr->vs.raw < SPDK_NVME_VERSION(1, 3, 0) && + !(ns->ctrlr->cap.bits.css & SPDK_NVME_CAP_CSS_IOCS)) || (ns->ctrlr->quirks & NVME_QUIRK_IDENTIFY_CNS)) { SPDK_DEBUGLOG(SPDK_LOG_NVME, "Version < 1.3; not attempting to retrieve NS ID Descriptor List\n"); return 0; @@ -360,6 +361,29 @@ spdk_nvme_ns_get_uuid(const struct spdk_nvme_ns *ns) return uuid; } +enum spdk_nvme_csi +spdk_nvme_ns_get_csi(const struct spdk_nvme_ns *ns) { + const uint8_t *csi; + size_t csi_size; + + csi = nvme_ns_find_id_desc(ns, SPDK_NVME_NIDT_CSI, &csi_size); + if (csi && csi_size != sizeof(*csi)) + { + SPDK_WARNLOG("Invalid NIDT_CSI descriptor length reported: %zu (expected: %zu)\n", + csi_size, sizeof(*csi)); + return SPDK_NVME_CSI_NVM; + } + if (!csi) + { + if (ns->ctrlr->cap.bits.css & SPDK_NVME_CAP_CSS_IOCS) { + SPDK_WARNLOG("CSI not reported for NSID: %" PRIu32 "\n", ns->id); + } + return SPDK_NVME_CSI_NVM; + } + + return *csi; +} + int nvme_ns_construct(struct spdk_nvme_ns *ns, uint32_t id, struct spdk_nvme_ctrlr *ctrlr) { diff --git a/lib/nvme/spdk_nvme.map b/lib/nvme/spdk_nvme.map index 63a04eeca..870410070 100644 --- a/lib/nvme/spdk_nvme.map +++ b/lib/nvme/spdk_nvme.map @@ -107,6 +107,7 @@ spdk_nvme_ns_get_dealloc_logical_block_read_value; spdk_nvme_ns_get_optimal_io_boundary; spdk_nvme_ns_get_uuid; + spdk_nvme_ns_get_csi; spdk_nvme_ns_get_flags; spdk_nvme_ns_cmd_write; 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 ef3604ed4..a7f98ad15 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 @@ -135,6 +135,49 @@ test_nvme_ns_uuid(void) CU_ASSERT(memcmp(uuid, &expected_uuid, sizeof(*uuid)) == 0); } +static void +test_nvme_ns_csi(void) +{ + struct spdk_nvme_ctrlr ctrlr = {}; + struct spdk_nvme_ns ns = { .ctrlr = &ctrlr }; + enum spdk_nvme_csi csi; + + /* Empty list - SPDK_NVME_CSI_NVM should be returned */ + memset(ns.id_desc_list, 0, sizeof(ns.id_desc_list)); + csi = spdk_nvme_ns_get_csi(&ns); + CU_ASSERT(csi == SPDK_NVME_CSI_NVM); + + /* NVM CSI - SPDK_NVME_CSI_NVM should be returned */ + memset(ns.id_desc_list, 0, sizeof(ns.id_desc_list)); + ns.id_desc_list[0] = 0x4; /* NIDT == CSI */ + ns.id_desc_list[1] = 0x1; /* NIDL */ + ns.id_desc_list[4] = 0x0; /* SPDK_NVME_CSI_NVM */ + csi = spdk_nvme_ns_get_csi(&ns); + CU_ASSERT(csi == SPDK_NVME_CSI_NVM); + + /* NGUID followed by ZNS CSI - SPDK_NVME_CSI_ZNS should be returned */ + memset(ns.id_desc_list, 0, sizeof(ns.id_desc_list)); + ns.id_desc_list[0] = 0x02; /* NIDT == NGUID */ + ns.id_desc_list[1] = 0x10; /* NIDL */ + memset(&ns.id_desc_list[4], 0xCC, 0x10); + ns.id_desc_list[20] = 0x4; /* NIDT == CSI */ + ns.id_desc_list[21] = 0x1; /* NIDL */ + ns.id_desc_list[24] = 0x2; /* SPDK_NVME_CSI_ZNS */ + csi = spdk_nvme_ns_get_csi(&ns); + CU_ASSERT(csi == SPDK_NVME_CSI_ZNS); + + /* KV CSI followed by NGUID - SPDK_NVME_CSI_KV should be returned */ + memset(ns.id_desc_list, 0, sizeof(ns.id_desc_list)); + ns.id_desc_list[0] = 0x4; /* NIDT == CSI */ + ns.id_desc_list[1] = 0x1; /* NIDL */ + ns.id_desc_list[4] = 0x1; /* SPDK_NVME_CSI_KV */ + ns.id_desc_list[5] = 0x02; /* NIDT == NGUID */ + ns.id_desc_list[6] = 0x10; /* NIDL */ + memset(&ns.id_desc_list[9], 0xCC, 0x10); + csi = spdk_nvme_ns_get_csi(&ns); + CU_ASSERT(csi == SPDK_NVME_CSI_KV); +} + int main(int argc, char **argv) { CU_pSuite suite = NULL; @@ -147,6 +190,7 @@ int main(int argc, char **argv) CU_ADD_TEST(suite, test_nvme_ns_construct); CU_ADD_TEST(suite, test_nvme_ns_uuid); + CU_ADD_TEST(suite, test_nvme_ns_csi); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests();