From 332e846fe6718fbd581c645dc66b3c388a283a84 Mon Sep 17 00:00:00 2001 From: Monica Kenguva Date: Wed, 17 Jun 2020 01:23:52 +0000 Subject: [PATCH] lib/nvmf: implement ANA log page SPDK NVMe-oF controller creates a ANA group for each namespace, ANA group ID matches namespace ID, and default ANA state of ANA group is optimized, and the MNAN field is set equal to the NN field. If a ANA log page contains multiple ANA group descriptors, it has one or more descriptors will not be 8 bytes aligned. Hence we create one descriptor and copy it to the ANA log page at a time. Change count will be supported later. Signed-off-by: Monica Kenguva Signed-off-by: Shuhei Matsumoto Change-Id: I56ba6aa78983480caa3dfbf22aefc9aeabfd5405 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/2920 Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins Reviewed-by: Ben Walker Reviewed-by: Paul Luse Reviewed-by: Jim Harris --- lib/nvmf/ctrlr.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/lib/nvmf/ctrlr.c b/lib/nvmf/ctrlr.c index c11f3ee82..0c20f32d9 100644 --- a/lib/nvmf/ctrlr.c +++ b/lib/nvmf/ctrlr.c @@ -1560,6 +1560,79 @@ nvmf_get_firmware_slot_log_page(void *buffer, uint64_t offset, uint32_t length) } } +static void +nvmf_get_ana_log_page(struct spdk_nvmf_ctrlr *ctrlr, void *data, + uint64_t offset, uint32_t length) +{ + char *buf = data; + struct spdk_nvme_ana_page ana_hdr; + const size_t ana_desc_size = sizeof(struct spdk_nvme_ana_group_descriptor) + + sizeof(uint32_t); + char _ana_desc[ana_desc_size]; + struct spdk_nvme_ana_group_descriptor *ana_desc; + size_t copy_len; + uint32_t num_ns = 0; + struct spdk_nvmf_ns *ns; + + if (length == 0) { + return; + } + + if (offset >= sizeof(ana_hdr)) { + offset -= sizeof(ana_hdr); + } else { + for (ns = spdk_nvmf_subsystem_get_first_ns(ctrlr->subsys); ns != NULL; + ns = spdk_nvmf_subsystem_get_next_ns(ctrlr->subsys, ns)) { + num_ns++; + } + + memset(&ana_hdr, 0, sizeof(ana_hdr)); + + ana_hdr.num_ana_group_desc = num_ns; + /* TODO: Support Change Count. */ + ana_hdr.change_count = 0; + + copy_len = spdk_min(sizeof(ana_hdr) - offset, length); + memcpy(buf, (const char *)&ana_hdr + offset, copy_len); + length -= copy_len; + buf += copy_len; + offset = 0; + } + + if (length == 0) { + return; + } + + ana_desc = (void *)_ana_desc; + + for (ns = spdk_nvmf_subsystem_get_first_ns(ctrlr->subsys); ns != NULL; + ns = spdk_nvmf_subsystem_get_next_ns(ctrlr->subsys, ns)) { + if (offset >= ana_desc_size) { + offset -= ana_desc_size; + continue; + } + + memset(ana_desc, 0, ana_desc_size); + + ana_desc->ana_group_id = ns->nsid; + ana_desc->num_of_nsid = 1; + ana_desc->ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE; + ana_desc->nsid[0] = ns->nsid; + /* TODO: Support Change Count. */ + ana_desc->change_count = 0; + + copy_len = spdk_min(ana_desc_size - offset, length); + memcpy(buf, (const char *)ana_desc + offset, copy_len); + length -= copy_len; + buf += copy_len; + offset = 0; + + if (length == 0) { + return; + } + } +} + void nvmf_ctrlr_ns_changed(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid) { @@ -1761,6 +1834,9 @@ nvmf_ctrlr_get_log_page(struct spdk_nvmf_request *req) case SPDK_NVME_LOG_FIRMWARE_SLOT: nvmf_get_firmware_slot_log_page(req->data, offset, len); return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + case SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS: + nvmf_get_ana_log_page(ctrlr, req->data, offset, len); + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; case SPDK_NVME_LOG_COMMAND_EFFECTS_LOG: nvmf_get_cmds_and_effects_log_page(req->data, offset, len); return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; @@ -1821,6 +1897,9 @@ spdk_nvmf_ctrlr_identify_ns(struct spdk_nvmf_ctrlr *ctrlr, nsdata->noiob = max_num_blocks; } + /* ANA group ID matches NSID. */ + nsdata->anagrpid = ns->nsid; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } @@ -1870,6 +1949,7 @@ spdk_nvmf_ctrlr_identify_ctrlr(struct spdk_nvmf_ctrlr *ctrlr, struct spdk_nvme_c cdata->sgls = ctrlr->cdata.sgls; cdata->fuses.compare_and_write = 1; cdata->acwu = 1; + cdata->mnan = subsystem->max_nsid; spdk_strcpy_pad(cdata->subnqn, subsystem->subnqn, sizeof(cdata->subnqn), '\0'); SPDK_DEBUGLOG(SPDK_LOG_NVMF, "ctrlr data: maxcmd 0x%x\n", cdata->maxcmd); @@ -1886,6 +1966,8 @@ spdk_nvmf_ctrlr_identify_ctrlr(struct spdk_nvmf_ctrlr *ctrlr, struct spdk_nvme_c cdata->rab = 6; cdata->cmic.multi_port = 1; cdata->cmic.multi_host = 1; + /* Asymmetric Namespace Access Reporting is supported. */ + cdata->cmic.ana_reporting = 1; cdata->oaes.ns_attribute_notices = 1; cdata->ctratt.host_id_exhid_supported = 1; /* TODO: Concurrent execution of multiple abort commands. */ @@ -1909,6 +1991,11 @@ spdk_nvmf_ctrlr_identify_ctrlr(struct spdk_nvmf_ctrlr *ctrlr, struct spdk_nvme_c cdata->oncs.dsm = nvmf_ctrlr_dsm_supported(ctrlr); cdata->oncs.write_zeroes = nvmf_ctrlr_write_zeroes_supported(ctrlr); cdata->oncs.reservations = 1; + cdata->anacap.ana_optimized_state = 1; + /* ANAGRPID does not change while namespace is attached to controller */ + cdata->anacap.no_change_anagrpid = 1; + cdata->anagrpmax = subsystem->max_nsid; + cdata->nanagrpid = subsystem->max_nsid; nvmf_ctrlr_populate_oacs(ctrlr, cdata);