From 2d34864a61be7c0d2ea425414460fcb4d32593f8 Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Fri, 16 Jun 2017 10:06:09 -0700 Subject: [PATCH] nvmf: stub out Abort command support Add handling of the Abort command in virtual subsystems. This doesn't actually abort any requests - the spdk_nvmf_request_abort() implementation just fails all abort requests - but at least this gives us a place to hook up actual abort handling later. Change-Id: Iafaa393c6f9e7f404af91747cbd81c64ab4810bb Signed-off-by: Daniel Verkamp Reviewed-on: https://review.gerrithub.io/365905 Tested-by: SPDK Automated Test System Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- lib/nvmf/request.c | 7 +++++ lib/nvmf/request.h | 2 ++ lib/nvmf/session.c | 21 +++++++++++++ lib/nvmf/session.h | 5 +++ lib/nvmf/virtual.c | 49 ++++++++++++++++++++++++++++++ test/lib/nvmf/virtual/virtual_ut.c | 19 ++++++++++++ 6 files changed, 103 insertions(+) diff --git a/lib/nvmf/request.c b/lib/nvmf/request.c index bd5c9ca6f..fe6f939ca 100644 --- a/lib/nvmf/request.c +++ b/lib/nvmf/request.c @@ -311,3 +311,10 @@ spdk_nvmf_request_exec(struct spdk_nvmf_request *req) return 0; } + +int +spdk_nvmf_request_abort(struct spdk_nvmf_request *req) +{ + /* TODO: implement abort, at least for commands that are still queued in software */ + return -1; +} diff --git a/lib/nvmf/request.h b/lib/nvmf/request.h index 44fc00400..e1a77e616 100644 --- a/lib/nvmf/request.h +++ b/lib/nvmf/request.h @@ -73,4 +73,6 @@ spdk_nvmf_request_exec(struct spdk_nvmf_request *req); int spdk_nvmf_request_complete(struct spdk_nvmf_request *req); +int spdk_nvmf_request_abort(struct spdk_nvmf_request *req); + #endif diff --git a/lib/nvmf/session.c b/lib/nvmf/session.c index 096d24c15..2c70fb6c9 100644 --- a/lib/nvmf/session.c +++ b/lib/nvmf/session.c @@ -273,6 +273,7 @@ spdk_nvmf_session_connect(struct spdk_nvmf_conn *conn, return; } conn->sq_head_max = cmd->sqsize; + conn->qid = cmd->qid; if (cmd->qid == 0) { conn->type = CONN_TYPE_AQ; @@ -405,6 +406,26 @@ spdk_nvmf_session_disconnect(struct spdk_nvmf_conn *conn) } } +struct spdk_nvmf_conn * +spdk_nvmf_session_get_conn(struct spdk_nvmf_session *session, uint16_t qid) +{ + struct spdk_nvmf_conn *conn; + + TAILQ_FOREACH(conn, &session->connections, link) { + if (conn->qid == qid) { + return conn; + } + } + return NULL; +} + +struct spdk_nvmf_request * +spdk_nvmf_conn_get_request(struct spdk_nvmf_conn *conn, uint16_t cid) +{ + /* TODO: track list of outstanding requests in conn? */ + return NULL; +} + static uint64_t nvmf_prop_get_cap(struct spdk_nvmf_session *session) { diff --git a/lib/nvmf/session.h b/lib/nvmf/session.h index 40a2b01ca..40a7f83e3 100644 --- a/lib/nvmf/session.h +++ b/lib/nvmf/session.h @@ -55,6 +55,7 @@ struct spdk_nvmf_conn { struct spdk_nvmf_session *sess; enum conn_type type; + uint16_t qid; uint16_t sq_head; uint16_t sq_head_max; @@ -102,6 +103,10 @@ void spdk_nvmf_session_connect(struct spdk_nvmf_conn *conn, struct spdk_nvmf_fabric_connect_data *data, struct spdk_nvmf_fabric_connect_rsp *rsp); +struct spdk_nvmf_conn *spdk_nvmf_session_get_conn(struct spdk_nvmf_session *session, uint16_t qid); + +struct spdk_nvmf_request *spdk_nvmf_conn_get_request(struct spdk_nvmf_conn *conn, uint16_t cid); + void spdk_nvmf_property_get(struct spdk_nvmf_session *session, struct spdk_nvmf_fabric_prop_get_cmd *cmd, diff --git a/lib/nvmf/virtual.c b/lib/nvmf/virtual.c index ead1d3011..4f4009c14 100644 --- a/lib/nvmf/virtual.c +++ b/lib/nvmf/virtual.c @@ -286,6 +286,53 @@ nvmf_virtual_ctrlr_identify(struct spdk_nvmf_request *req) } } +static int +nvmf_virtual_ctrlr_abort(struct spdk_nvmf_request *req) +{ + struct spdk_nvmf_session *session = req->conn->sess; + struct spdk_nvme_cpl *rsp = &req->rsp->nvme_cpl; + struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; + uint32_t cdw10 = cmd->cdw10; + uint16_t cid = cdw10 >> 16; + uint16_t sqid = cdw10 & 0xFFFFu; + struct spdk_nvmf_conn *conn; + struct spdk_nvmf_request *req_to_abort; + + SPDK_TRACELOG(SPDK_TRACE_NVMF, "abort sqid=%u cid=%u\n", sqid, cid); + + rsp->cdw0 = 1; /* Command not aborted */ + + conn = spdk_nvmf_session_get_conn(session, sqid); + if (conn == NULL) { + SPDK_TRACELOG(SPDK_TRACE_NVMF, "sqid %u not found\n", sqid); + rsp->status.sct = SPDK_NVME_SCT_GENERIC; + rsp->status.sc = SPDK_NVME_SC_INVALID_FIELD; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + + /* + * NOTE: This relies on the assumption that all connections for a session will be handled + * on the same thread. If this assumption becomes untrue, this will need to pass a message + * to the thread handling conn, and the abort will need to be asynchronous. + */ + req_to_abort = spdk_nvmf_conn_get_request(conn, cid); + if (req_to_abort == NULL) { + SPDK_TRACELOG(SPDK_TRACE_NVMF, "cid %u not found\n", cid); + rsp->status.sct = SPDK_NVME_SCT_GENERIC; + rsp->status.sc = SPDK_NVME_SC_INVALID_FIELD; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; + } + + if (spdk_nvmf_request_abort(req_to_abort) == 0) { + SPDK_TRACELOG(SPDK_TRACE_NVMF, "abort session=%p req=%p sqid=%u cid=%u successful\n", + session, req_to_abort, sqid, cid); + rsp->cdw0 = 0; /* Command successfully aborted */ + } + rsp->status.sct = SPDK_NVME_SCT_GENERIC; + rsp->status.sc = SPDK_NVME_SC_SUCCESS; + return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; +} + static int nvmf_virtual_ctrlr_get_features(struct spdk_nvmf_request *req) { @@ -351,6 +398,8 @@ nvmf_virtual_ctrlr_process_admin_cmd(struct spdk_nvmf_request *req) return nvmf_virtual_ctrlr_get_log_page(req); case SPDK_NVME_OPC_IDENTIFY: return nvmf_virtual_ctrlr_identify(req); + case SPDK_NVME_OPC_ABORT: + return nvmf_virtual_ctrlr_abort(req); case SPDK_NVME_OPC_GET_FEATURES: return nvmf_virtual_ctrlr_get_features(req); case SPDK_NVME_OPC_SET_FEATURES: diff --git a/test/lib/nvmf/virtual/virtual_ut.c b/test/lib/nvmf/virtual/virtual_ut.c index a81b91a66..8d59ec6b6 100644 --- a/test/lib/nvmf/virtual/virtual_ut.c +++ b/test/lib/nvmf/virtual/virtual_ut.c @@ -39,6 +39,19 @@ SPDK_LOG_REGISTER_TRACE_FLAG("nvmf", SPDK_TRACE_NVMF) + +struct spdk_nvmf_conn * +spdk_nvmf_session_get_conn(struct spdk_nvmf_session *session, uint16_t qid) +{ + return NULL; +} + +struct spdk_nvmf_request * +spdk_nvmf_conn_get_request(struct spdk_nvmf_conn *conn, uint16_t cid) +{ + return NULL; +} + int spdk_nvmf_session_get_features_number_of_queues(struct spdk_nvmf_request *req) { @@ -97,6 +110,12 @@ spdk_nvmf_request_complete(struct spdk_nvmf_request *req) return -1; } +int +spdk_nvmf_request_abort(struct spdk_nvmf_request *req) +{ + return -1; +} + const char * spdk_bdev_get_name(const struct spdk_bdev *bdev) {