From 5627b6871e1794db471ed69c57006f2f15b926b7 Mon Sep 17 00:00:00 2001 From: Changpeng Liu Date: Thu, 28 Jul 2016 13:58:47 +0800 Subject: [PATCH] nvmf: add identify namespace list support to NVMf target We reported virtualized NVMe devices through NVMe over Fabric specification, with 1.2.1 NVMe version. For direct mode, the NVMe device maybe has lower version, such as 1.0, the identify namespace list can not support in those devices, so we need to add helper function here to simulate such commands from initiator. Change-Id: I226f4f34bf61017f538d2dd80332f1d054a501f1 Signed-off-by: Changpeng Liu --- lib/nvmf/request.c | 58 ++++++++++++++++++++++++++---- test/lib/nvmf/request/request_ut.c | 25 +++++++++++++ 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/lib/nvmf/request.c b/lib/nvmf/request.c index 42ec3cefe..319272669 100644 --- a/lib/nvmf/request.c +++ b/lib/nvmf/request.c @@ -142,6 +142,39 @@ nvmf_complete_cmd(void *ctx, const struct spdk_nvme_cpl *cmp) spdk_nvmf_request_complete(req); } +static int +nvmf_admin_identify_nslist(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvmf_request *req) +{ + struct spdk_nvme_ns *ns; + struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; + uint32_t req_ns_id = cmd->nsid; + uint32_t i, num_ns, count = 0; + struct spdk_nvme_ns_list *ns_list; + + if (req_ns_id >= 0xfffffffeUL) { + return -1; + } + memset(req->data, 0, req->length); + + num_ns = spdk_nvme_ctrlr_get_num_ns(ctrlr); + ns_list = (struct spdk_nvme_ns_list *)req->data; + for (i = 1; i <= num_ns; i++) { + ns = spdk_nvme_ctrlr_get_ns(ctrlr, i); + if (!spdk_nvme_ns_is_active(ns)) { + continue; + } + if (i <= req_ns_id) { + continue; + } + + ns_list->ns_list[count++] = i; + if (count == sizeof(*ns_list) / sizeof(uint32_t)) { + break; + } + } + return 0; +} + static spdk_nvmf_request_exec_status nvmf_process_admin_cmd(struct spdk_nvmf_request *req) { @@ -150,6 +183,7 @@ nvmf_process_admin_cmd(struct spdk_nvmf_request *req) struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; struct spdk_nvmf_subsystem *subsystem = session->subsys; uint32_t nr_io_queues = 0; + union spdk_nvme_vs_register vs; int rc = 0; uint8_t feature; @@ -160,18 +194,30 @@ nvmf_process_admin_cmd(struct spdk_nvmf_request *req) switch (cmd->opc) { case SPDK_NVME_OPC_IDENTIFY: - if ((cmd->cdw10 & 0xFF) == SPDK_NVME_IDENTIFY_CTRLR) { - if (req->data == NULL || req->length < sizeof(struct spdk_nvme_ctrlr_data)) { - SPDK_ERRLOG("identify command with no buffer\n"); - response->status.sc = SPDK_NVME_SC_INVALID_FIELD; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } + if (req->data == NULL || req->length < 4096) { + SPDK_ERRLOG("identify command with invalid buffer\n"); + response->status.sc = SPDK_NVME_SC_INVALID_FIELD; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + if ((cmd->cdw10 & 0xFF) == SPDK_NVME_IDENTIFY_CTRLR) { SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Controller\n"); /* pull from virtual controller context */ memcpy(req->data, &session->vcdata, sizeof(struct spdk_nvme_ctrlr_data)); return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } else if ((cmd->cdw10 & 0xFF) == SPDK_NVME_IDENTIFY_ACTIVE_NS_LIST) { + vs = spdk_nvme_ctrlr_get_regs_vs(subsystem->ctrlr.direct.ctrlr); + if (vs.raw < SPDK_NVME_VERSION(1, 1, 0)) { + /* fill in identify ns list with virtual controller information */ + rc = nvmf_admin_identify_nslist(subsystem->ctrlr.direct.ctrlr, req); + if (rc < 0) { + SPDK_ERRLOG("Invalid Namespace or Format\n"); + response->status.sc = SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT; + } + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } } + goto passthrough; case SPDK_NVME_OPC_GET_FEATURES: diff --git a/test/lib/nvmf/request/request_ut.c b/test/lib/nvmf/request/request_ut.c index 3edac6148..53600bf1c 100644 --- a/test/lib/nvmf/request/request_ut.c +++ b/test/lib/nvmf/request/request_ut.c @@ -85,6 +85,31 @@ spdk_nvme_ctrlr_cmd_io_raw(struct spdk_nvme_ctrlr *ctrlr, return -1; } +uint32_t +spdk_nvme_ctrlr_get_num_ns(struct spdk_nvme_ctrlr *ctrlr) +{ + return 0; +} + +union spdk_nvme_vs_register spdk_nvme_ctrlr_get_regs_vs(struct spdk_nvme_ctrlr *ctrlr) +{ + union spdk_nvme_vs_register vs; + + vs.raw = 0; + return vs; +} + +bool +spdk_nvme_ns_is_active(struct spdk_nvme_ns *ns) +{ + return false; +} + +struct spdk_nvme_ns *spdk_nvme_ctrlr_get_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t ns_id) +{ + return NULL; +} + void nvmf_disconnect(struct nvmf_session *session, struct spdk_nvmf_conn *conn) {