From fc75d2a2824a6b4a833f76c173cad08ca32eaa2a Mon Sep 17 00:00:00 2001 From: Cunyin Chang Date: Mon, 1 Aug 2016 14:02:59 +0800 Subject: [PATCH] nvmf: Add nvmf controller operation structure. Change-Id: I3f8c0cea7fbbf443b13ed336a786d0e14927131e Signed-off-by: Cunyin Chang --- lib/nvmf/Makefile | 3 +- lib/nvmf/conf.c | 47 ++--- lib/nvmf/direct.c | 255 +++++++++++++++++++++++++ lib/nvmf/request.c | 200 +------------------ lib/nvmf/request.h | 6 + lib/nvmf/session.c | 13 +- lib/nvmf/subsystem.c | 15 +- lib/nvmf/subsystem.h | 52 +++-- test/lib/nvmf/subsystem/subsystem_ut.c | 3 + 9 files changed, 342 insertions(+), 252 deletions(-) create mode 100644 lib/nvmf/direct.c diff --git a/lib/nvmf/Makefile b/lib/nvmf/Makefile index 895379e46..4eb8a4bcd 100644 --- a/lib/nvmf/Makefile +++ b/lib/nvmf/Makefile @@ -37,7 +37,8 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk CFLAGS += $(DPDK_INC) LIBNAME = nvmf C_SRCS = subsystem.c conf.c nvmf.c \ - request.c session.c transport.c + request.c session.c transport.c \ + direct.c C_SRCS-$(CONFIG_RDMA) += rdma.c diff --git a/lib/nvmf/conf.c b/lib/nvmf/conf.c index 4523d314e..a06ae3589 100644 --- a/lib/nvmf/conf.c +++ b/lib/nvmf/conf.c @@ -356,9 +356,8 @@ spdk_nvmf_allocate_lcore(uint64_t mask, uint32_t lcore) static int spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) { - const char *nqn, *mode, *bdf; + const char *nqn, *mode; struct spdk_nvmf_subsystem *subsystem; - struct spdk_nvmf_probe_ctx ctx = { 0 }; int i, ret; uint64_t mask; uint32_t lcore; @@ -449,31 +448,35 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) spdk_nvmf_subsystem_add_host(subsystem, host_nqn); } - /* Parse NVMe section */ - bdf = spdk_conf_section_get_val(sp, "NVMe"); - if (bdf == NULL) { - SPDK_ERRLOG("Subsystem %d: missing NVMe directive\n", sp->num); - nvmf_delete_subsystem(subsystem); - return -1; - } + if (subsystem->mode == NVMF_SUBSYSTEM_MODE_DIRECT) { + const char *bdf; + struct spdk_nvmf_probe_ctx ctx = { 0 }; - ctx.subsystem = subsystem; - ctx.found = false; - if (strcmp(bdf, "*") == 0) { - ctx.any = true; - } else { - ret = sscanf(bdf, "%x:%x:%x.%x", &ctx.domain, &ctx.bus, &ctx.device, &ctx.function); - if (ret != 4) { - SPDK_ERRLOG("Invalid format for NVMe BDF: %s\n", bdf); + /* Parse NVMe section */ + bdf = spdk_conf_section_get_val(sp, "NVMe"); + if (bdf == NULL) { + SPDK_ERRLOG("Subsystem %d: missing NVMe directive\n", sp->num); + nvmf_delete_subsystem(subsystem); return -1; } - ctx.any = false; - } - if (spdk_nvme_probe(&ctx, probe_cb, attach_cb, NULL)) { - SPDK_ERRLOG("One or more controllers failed in spdk_nvme_probe()\n"); - } + ctx.subsystem = subsystem; + ctx.found = false; + if (strcmp(bdf, "*") == 0) { + ctx.any = true; + } else { + ret = sscanf(bdf, "%x:%x:%x.%x", &ctx.domain, &ctx.bus, &ctx.device, &ctx.function); + if (ret != 4) { + SPDK_ERRLOG("Invalid format for NVMe BDF: %s\n", bdf); + return -1; + } + ctx.any = false; + } + if (spdk_nvme_probe(&ctx, probe_cb, attach_cb, NULL)) { + SPDK_ERRLOG("One or more controllers failed in spdk_nvme_probe()\n"); + } + } return 0; } diff --git a/lib/nvmf/direct.c b/lib/nvmf/direct.c new file mode 100644 index 000000000..46e5f67eb --- /dev/null +++ b/lib/nvmf/direct.c @@ -0,0 +1,255 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "subsystem.h" +#include "session.h" +#include "request.h" +#include "spdk/log.h" +#include "spdk/nvme.h" +#include "spdk/nvmf_spec.h" +#include "spdk/trace.h" + +static void +nvmf_direct_ctrlr_get_data(struct nvmf_session *session) +{ + const struct spdk_nvme_ctrlr_data *cdata; + + cdata = spdk_nvme_ctrlr_get_data(session->subsys->ctrlr.dev.direct.ctrlr); + memcpy(&session->vcdata, cdata, sizeof(struct spdk_nvme_ctrlr_data)); +} + +static void +nvmf_direct_ctrlr_poll_for_completions(struct nvmf_session *session) +{ + spdk_nvme_ctrlr_process_admin_completions(session->subsys->ctrlr.dev.direct.ctrlr); + spdk_nvme_qpair_process_completions(session->subsys->ctrlr.dev.direct.io_qpair, 0); +} + +static void +nvmf_direct_ctrlr_complete_cmd(void *ctx, const struct spdk_nvme_cpl *cmp) +{ + struct spdk_nvmf_request *req = ctx; + struct spdk_nvme_cpl *response; + + spdk_trace_record(TRACE_NVMF_LIB_COMPLETE, 0, 0, (uint64_t)req, 0); + + response = &req->rsp->nvme_cpl; + memcpy(response, cmp, sizeof(*cmp)); + + spdk_nvmf_request_complete(req); +} + +static int +nvmf_direct_ctrlr_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 int +nvmf_direct_ctrlr_process_admin_cmd(struct spdk_nvmf_request *req) +{ + struct nvmf_session *session = req->conn->sess; + struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; + 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; + + /* pre-set response details for this command */ + response->status.sc = SPDK_NVME_SC_SUCCESS; + /* Extra 1 connection for Admin queue */ + nr_io_queues = session->max_connections_allowed - 1; + + switch (cmd->opc) { + case SPDK_NVME_OPC_IDENTIFY: + 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.dev.direct.ctrlr); + if (vs.raw < SPDK_NVME_VERSION(1, 1, 0)) { + /* fill in identify ns list with virtual controller information */ + rc = nvmf_direct_ctrlr_admin_identify_nslist(subsystem->ctrlr.dev.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: + feature = cmd->cdw10 & 0xff; /* mask out the FID value */ + switch (feature) { + case SPDK_NVME_FEAT_NUMBER_OF_QUEUES: + SPDK_TRACELOG(SPDK_TRACE_NVMF, "Get Features - Number of Queues\n"); + /* Number of IO queues has a zero based value */ + response->cdw0 = ((nr_io_queues - 1) << 16) | + (nr_io_queues - 1); + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + default: + goto passthrough; + } + break; + case SPDK_NVME_OPC_SET_FEATURES: + feature = cmd->cdw10 & 0xff; /* mask out the FID value */ + switch (feature) { + case SPDK_NVME_FEAT_NUMBER_OF_QUEUES: + SPDK_TRACELOG(SPDK_TRACE_NVMF, "Set Features - Number of Queues, cdw11 0x%x\n", cmd->cdw11); + + /* verify that the contoller is ready to process commands */ + if (session->num_connections > 1) { + SPDK_TRACELOG(SPDK_TRACE_NVMF, "Queue pairs already active!\n"); + response->status.sc = SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR; + } else { + /* Number of IO queues has a zero based value */ + response->cdw0 = ((nr_io_queues - 1) << 16) | + (nr_io_queues - 1); + } + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + default: + goto passthrough; + } + break; + case SPDK_NVME_OPC_ASYNC_EVENT_REQUEST: + SPDK_TRACELOG(SPDK_TRACE_NVMF, "Async Event Request\n"); + /* TODO: Just release the request as consumed. AER events will never + * be triggered. */ + return SPDK_NVMF_REQUEST_EXEC_STATUS_RELEASE; + case SPDK_NVME_OPC_KEEP_ALIVE: + SPDK_TRACELOG(SPDK_TRACE_NVMF, "Keep Alive\n"); + /* + To handle keep alive just clear or reset the + session based keep alive duration counter. + When added, a separate timer based process + will monitor if the time since last recorded + keep alive has exceeded the max duration and + take appropriate action. + */ + //session->keep_alive_timestamp = ; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + + case SPDK_NVME_OPC_CREATE_IO_SQ: + case SPDK_NVME_OPC_CREATE_IO_CQ: + case SPDK_NVME_OPC_DELETE_IO_SQ: + case SPDK_NVME_OPC_DELETE_IO_CQ: + SPDK_ERRLOG("Admin opc 0x%02X not allowed in NVMf\n", cmd->opc); + response->status.sc = SPDK_NVME_SC_INVALID_OPCODE; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + + default: +passthrough: + SPDK_TRACELOG(SPDK_TRACE_NVMF, "admin_cmd passthrough: opc 0x%02x\n", cmd->opc); + rc = spdk_nvme_ctrlr_cmd_admin_raw(subsystem->ctrlr.dev.direct.ctrlr, + cmd, + req->data, req->length, + nvmf_direct_ctrlr_complete_cmd, + req); + if (rc) { + SPDK_ERRLOG("Error submitting admin opc 0x%02x\n", cmd->opc); + response->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS; + } + +} + +static int +nvmf_direct_ctrlr_process_io_cmd(struct spdk_nvmf_request *req) +{ + struct spdk_nvmf_subsystem *subsystem = req->conn->sess->subsys; + int rc; + + rc = spdk_nvme_ctrlr_cmd_io_raw(subsystem->ctrlr.dev.direct.ctrlr, + subsystem->ctrlr.dev.direct.io_qpair, + &req->cmd->nvme_cmd, + req->data, req->length, + nvmf_direct_ctrlr_complete_cmd, + req); + + if (rc) { + SPDK_ERRLOG("Failed to submit request %p\n", req); + req->rsp->nvme_cpl.status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + + return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS; +} + +const struct spdk_nvmf_ctrlr_ops spdk_nvmf_direct_ctrlr_ops = { + .ctrlr_get_data = nvmf_direct_ctrlr_get_data, + .process_admin_cmd = nvmf_direct_ctrlr_process_admin_cmd, + .process_io_cmd = nvmf_direct_ctrlr_process_io_cmd, + .poll_for_completions = nvmf_direct_ctrlr_poll_for_completions, +}; diff --git a/lib/nvmf/request.c b/lib/nvmf/request.c index 319272669..19aa3cbab 100644 --- a/lib/nvmf/request.c +++ b/lib/nvmf/request.c @@ -44,12 +44,6 @@ #include "spdk/nvmf_spec.h" #include "spdk/trace.h" -typedef enum _spdk_nvmf_request_exec_status { - SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE, - SPDK_NVMF_REQUEST_EXEC_STATUS_RELEASE, - SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS, -} spdk_nvmf_request_exec_status; - int spdk_nvmf_request_complete(struct spdk_nvmf_request *req) { @@ -128,196 +122,6 @@ nvmf_process_discovery_cmd(struct spdk_nvmf_request *req) return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } -static void -nvmf_complete_cmd(void *ctx, const struct spdk_nvme_cpl *cmp) -{ - struct spdk_nvmf_request *req = ctx; - struct spdk_nvme_cpl *response; - - spdk_trace_record(TRACE_NVMF_LIB_COMPLETE, 0, 0, (uint64_t)req, 0); - - response = &req->rsp->nvme_cpl; - memcpy(response, cmp, sizeof(*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) -{ - struct nvmf_session *session = req->conn->sess; - struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; - 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; - - /* pre-set response details for this command */ - response->status.sc = SPDK_NVME_SC_SUCCESS; - /* Extra 1 connection for Admin queue */ - nr_io_queues = session->max_connections_allowed - 1; - - switch (cmd->opc) { - case SPDK_NVME_OPC_IDENTIFY: - 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: - feature = cmd->cdw10 & 0xff; /* mask out the FID value */ - switch (feature) { - case SPDK_NVME_FEAT_NUMBER_OF_QUEUES: - SPDK_TRACELOG(SPDK_TRACE_NVMF, "Get Features - Number of Queues\n"); - /* Number of IO queues has a zero based value */ - response->cdw0 = ((nr_io_queues - 1) << 16) | - (nr_io_queues - 1); - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - default: - goto passthrough; - } - break; - case SPDK_NVME_OPC_SET_FEATURES: - feature = cmd->cdw10 & 0xff; /* mask out the FID value */ - switch (feature) { - case SPDK_NVME_FEAT_NUMBER_OF_QUEUES: - SPDK_TRACELOG(SPDK_TRACE_NVMF, "Set Features - Number of Queues, cdw11 0x%x\n", cmd->cdw11); - - /* verify that the contoller is ready to process commands */ - if (session->num_connections > 1) { - SPDK_TRACELOG(SPDK_TRACE_NVMF, "Queue pairs already active!\n"); - response->status.sc = SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR; - } else { - /* Number of IO queues has a zero based value */ - response->cdw0 = ((nr_io_queues - 1) << 16) | - (nr_io_queues - 1); - } - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - default: - goto passthrough; - } - break; - case SPDK_NVME_OPC_ASYNC_EVENT_REQUEST: - SPDK_TRACELOG(SPDK_TRACE_NVMF, "Async Event Request\n"); - /* TODO: Just release the request as consumed. AER events will never - * be triggered. */ - return SPDK_NVMF_REQUEST_EXEC_STATUS_RELEASE; - case SPDK_NVME_OPC_KEEP_ALIVE: - SPDK_TRACELOG(SPDK_TRACE_NVMF, "Keep Alive\n"); - /* - To handle keep alive just clear or reset the - session based keep alive duration counter. - When added, a separate timer based process - will monitor if the time since last recorded - keep alive has exceeded the max duration and - take appropriate action. - */ - //session->keep_alive_timestamp = ; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - - case SPDK_NVME_OPC_CREATE_IO_SQ: - case SPDK_NVME_OPC_CREATE_IO_CQ: - case SPDK_NVME_OPC_DELETE_IO_SQ: - case SPDK_NVME_OPC_DELETE_IO_CQ: - SPDK_ERRLOG("Admin opc 0x%02X not allowed in NVMf\n", cmd->opc); - response->status.sc = SPDK_NVME_SC_INVALID_OPCODE; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - - default: -passthrough: - SPDK_TRACELOG(SPDK_TRACE_NVMF, "admin_cmd passthrough: opc 0x%02x\n", cmd->opc); - rc = spdk_nvme_ctrlr_cmd_admin_raw(subsystem->ctrlr.direct.ctrlr, - cmd, - req->data, req->length, - nvmf_complete_cmd, - req); - if (rc) { - SPDK_ERRLOG("Error submitting admin opc 0x%02x\n", cmd->opc); - response->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } - return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS; - } - -} - -static spdk_nvmf_request_exec_status -nvmf_process_io_cmd(struct spdk_nvmf_request *req) -{ - struct spdk_nvmf_subsystem *subsystem = req->conn->sess->subsys; - int rc; - - rc = spdk_nvme_ctrlr_cmd_io_raw(subsystem->ctrlr.direct.ctrlr, subsystem->ctrlr.direct.io_qpair, - &req->cmd->nvme_cmd, - req->data, req->length, - nvmf_complete_cmd, - req); - - if (rc) { - SPDK_ERRLOG("Failed to submit request %p\n", req); - req->rsp->nvme_cpl.status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; - return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; - } - - return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS; -} - static spdk_nvmf_request_exec_status nvmf_process_property_get(struct spdk_nvmf_request *req) { @@ -516,10 +320,10 @@ spdk_nvmf_request_exec(struct spdk_nvmf_request *req) if (subsystem->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) { status = nvmf_process_discovery_cmd(req); } else { - status = nvmf_process_admin_cmd(req); + status = session->subsys->ctrlr.ops->process_admin_cmd(req); } } else { - status = nvmf_process_io_cmd(req); + status = session->subsys->ctrlr.ops->process_io_cmd(req); } switch (status) { diff --git a/lib/nvmf/request.h b/lib/nvmf/request.h index 67be049c5..d596390f7 100644 --- a/lib/nvmf/request.h +++ b/lib/nvmf/request.h @@ -37,6 +37,12 @@ #include "spdk/nvmf_spec.h" #include "spdk/queue.h" +typedef enum _spdk_nvmf_request_exec_status { + SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE, + SPDK_NVMF_REQUEST_EXEC_STATUS_RELEASE, + SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS, +} spdk_nvmf_request_exec_status; + union nvmf_h2c_msg { struct spdk_nvmf_capsule_cmd nvmf_cmd; struct spdk_nvme_cmd nvme_cmd; diff --git a/lib/nvmf/session.c b/lib/nvmf/session.c index b8b8a9099..f5dd29c6a 100644 --- a/lib/nvmf/session.c +++ b/lib/nvmf/session.c @@ -83,19 +83,10 @@ nvmf_init_discovery_session_properties(struct nvmf_session *session) static void nvmf_init_nvme_session_properties(struct nvmf_session *session) { - const struct spdk_nvme_ctrlr_data *cdata; - assert((g_nvmf_tgt.max_io_size % 4096) == 0); - /* - Here we are going to initialize the features, properties, and - identify controller details for the virtual controller associated - with a specific subsystem session. - */ - - /* Init the virtual controller details using actual HW details */ - cdata = spdk_nvme_ctrlr_get_data(session->subsys->ctrlr.direct.ctrlr); - memcpy(&session->vcdata, cdata, sizeof(struct spdk_nvme_ctrlr_data)); + /* Init the controller details */ + session->subsys->ctrlr.ops->ctrlr_get_data(session); session->vcdata.aerl = 0; session->vcdata.cntlid = 0; diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 046546bf7..74c2a2a2b 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -85,8 +85,7 @@ spdk_nvmf_subsystem_poller(void *arg) /* For NVMe subsystems, check the backing physical device for completions. */ if (subsystem->subtype == SPDK_NVMF_SUBTYPE_NVME) { - spdk_nvme_ctrlr_process_admin_completions(subsystem->ctrlr.direct.ctrlr); - spdk_nvme_qpair_process_completions(subsystem->ctrlr.direct.io_qpair, 0); + session->subsys->ctrlr.ops->poll_for_completions(session); } /* For each connection in the session, check for RDMA completions */ @@ -153,8 +152,8 @@ nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem) spdk_nvmf_session_destruct(subsystem->session); } - if (subsystem->ctrlr.direct.ctrlr) { - spdk_nvme_detach(subsystem->ctrlr.direct.ctrlr); + if (subsystem->ctrlr.dev.direct.ctrlr) { + spdk_nvme_detach(subsystem->ctrlr.dev.direct.ctrlr); } TAILQ_REMOVE(&g_subsystems, subsystem, entries); @@ -221,14 +220,14 @@ int nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvme_ctrlr *ctrlr) { - subsystem->ctrlr.direct.ctrlr = ctrlr; + subsystem->ctrlr.dev.direct.ctrlr = ctrlr; /* Assume that all I/O will be handled on one thread for now */ - subsystem->ctrlr.direct.io_qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, 0); - if (subsystem->ctrlr.direct.io_qpair == NULL) { + subsystem->ctrlr.dev.direct.io_qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, 0); + if (subsystem->ctrlr.dev.direct.io_qpair == NULL) { SPDK_ERRLOG("spdk_nvme_ctrlr_alloc_io_qpair() failed\n"); return -1; } - + subsystem->ctrlr.ops = &spdk_nvmf_direct_ctrlr_ops; return 0; } diff --git a/lib/nvmf/subsystem.h b/lib/nvmf/subsystem.h index b2a77a138..121d303e3 100644 --- a/lib/nvmf/subsystem.h +++ b/lib/nvmf/subsystem.h @@ -43,6 +43,8 @@ struct spdk_nvmf_conn; struct spdk_nvmf_subsystem; +struct spdk_nvmf_request; +struct nvmf_session; #define MAX_NQN_SIZE 255 #define MAX_VIRTUAL_NAMESPACE 16 @@ -69,19 +71,44 @@ struct spdk_nvmf_ns { struct spdk_bdev *bdev; }; +struct spdk_nvmf_ctrlr_ops { + /** + * Get NVMe identify controller data. + */ + void (*ctrlr_get_data)(struct nvmf_session *session); -union spdk_nvmf_controller { - struct { - struct nvmf_session *session; - struct spdk_nvme_ctrlr *ctrlr; - struct spdk_nvme_qpair *io_qpair; - } direct; + /** + * Process admin command. + */ + int (*process_admin_cmd)(struct spdk_nvmf_request *req); - struct { - struct nvmf_session *session; - struct spdk_nvmf_ns *ns_list[MAX_VIRTUAL_NAMESPACE]; - uint16_t ns_count; - } virtual; + /** + * Process IO command. + */ + int (*process_io_cmd)(struct spdk_nvmf_request *req); + + /** + * Poll for completions. + */ + void (*poll_for_completions)(struct nvmf_session *session); +}; + +struct spdk_nvmf_controller { + union { + struct { + struct nvmf_session *session; + struct spdk_nvme_ctrlr *ctrlr; + struct spdk_nvme_qpair *io_qpair; + } direct; + + struct { + struct nvmf_session *session; + struct spdk_nvmf_ns *ns_list[MAX_VIRTUAL_NAMESPACE]; + uint16_t ns_count; + } virtual; + } dev; + + const struct spdk_nvmf_ctrlr_ops *ops; }; @@ -96,7 +123,7 @@ struct spdk_nvmf_subsystem { enum spdk_nvmf_subsystem_mode mode; enum spdk_nvmf_subtype subtype; struct nvmf_session *session; - union spdk_nvmf_controller ctrlr; + struct spdk_nvmf_controller ctrlr; struct spdk_poller poller; @@ -139,4 +166,5 @@ spdk_shutdown_nvmf_subsystems(void); void spdk_format_discovery_log(struct spdk_nvmf_discovery_log_page *disc_log, uint32_t length); +extern const struct spdk_nvmf_ctrlr_ops spdk_nvmf_direct_ctrlr_ops; #endif /* SPDK_NVMF_SUBSYSTEM_H */ diff --git a/test/lib/nvmf/subsystem/subsystem_ut.c b/test/lib/nvmf/subsystem/subsystem_ut.c index 9e18d869f..b9dc6f2b4 100644 --- a/test/lib/nvmf/subsystem/subsystem_ut.c +++ b/test/lib/nvmf/subsystem/subsystem_ut.c @@ -37,6 +37,9 @@ #include #include "spdk_cunit.h" +#include "subsystem.h" + +const struct spdk_nvmf_ctrlr_ops spdk_nvmf_direct_ctrlr_ops; #include "subsystem.c"