diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index 46600277f..4e18712ee 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -987,6 +987,43 @@ struct spdk_nvme_qpair *spdk_nvme_ctrlr_alloc_io_qpair(struct spdk_nvme_ctrlr *c */ int spdk_nvme_ctrlr_free_io_qpair(struct spdk_nvme_qpair *qpair); +/** + * Send the given NVM I/O command, I/O buffers, lists and all to the NVMe controller. + * + * This is a low level interface for submitting I/O commands directly. + * + * This function allows a caller to submit an I/O request that is + * COMPLETELY pre-defined, right down to the "physical" memory buffers. + * It is intended for testing hardware, specifying exact buffer location, + * alignment, and offset. It also allows for specific choice of PRP + * and SGLs. + * + * The driver sets the CID. EVERYTHING else is assumed set by the caller. + * Needless to say, this is potentially extremely dangerous for both the host + * (accidental/malicionus storage usage/corruption), and the device. + * Thus its intent is for very specific hardware testing and environment + * reproduction. + * + * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair(). + * The user must ensure that only one thread submits I/O on a given qpair at any + * given time. + * + * This function can only be used on PCIe controllers and qpairs. + * + * \param ctrlr Opaque handle to NVMe controller. + * \param qpair I/O qpair to submit command. + * \param cmd NVM I/O command to submit. + * \param cb_fn Callback function invoked when the I/O command completes. + * \param cb_arg Argument passed to callback function. + * + * \return 0 on success, negated errno on failure. + */ + +int spdk_nvme_ctrlr_io_cmd_raw_no_payload_build(struct spdk_nvme_ctrlr *ctrlr, + struct spdk_nvme_qpair *qpair, + struct spdk_nvme_cmd *cmd, + spdk_nvme_cmd_cb cb_fn, void *cb_arg); + /** * Send the given NVM I/O command to the NVMe controller. * diff --git a/lib/nvme/nvme_ctrlr_cmd.c b/lib/nvme/nvme_ctrlr_cmd.c index 45cb05412..7abebcf66 100644 --- a/lib/nvme/nvme_ctrlr_cmd.c +++ b/lib/nvme/nvme_ctrlr_cmd.c @@ -33,6 +33,31 @@ #include "nvme_internal.h" +int +spdk_nvme_ctrlr_io_cmd_raw_no_payload_build(struct spdk_nvme_ctrlr *ctrlr, + struct spdk_nvme_qpair *qpair, + struct spdk_nvme_cmd *cmd, + spdk_nvme_cmd_cb cb_fn, void *cb_arg) +{ + struct nvme_request *req; + struct nvme_payload payload; + + if (ctrlr->trid.trtype != SPDK_NVME_TRANSPORT_PCIE) { + return -EINVAL; + } + + memset(&payload, 0, sizeof(payload)); + req = nvme_allocate_request(qpair, &payload, 0, cb_fn, cb_arg); + + if (req == NULL) { + return -ENOMEM; + } + + memcpy(&req->cmd, cmd, sizeof(req->cmd)); + + return nvme_qpair_submit_request(qpair, req); +} + int spdk_nvme_ctrlr_cmd_io_raw(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair, diff --git a/lib/nvme/nvme_pcie.c b/lib/nvme/nvme_pcie.c index 0d2f9eee3..e29b49eca 100644 --- a/lib/nvme/nvme_pcie.c +++ b/lib/nvme/nvme_pcie.c @@ -2032,7 +2032,7 @@ nvme_pcie_qpair_submit_request(struct spdk_nvme_qpair *qpair, struct nvme_reques } if (req->payload_size == 0) { - /* Null payload - leave PRP fields zeroed */ + /* Null payload - leave PRP fields untouched */ rc = 0; } else if (nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG) { rc = nvme_pcie_qpair_build_contig_request(qpair, req, tr);