From eda407a6f08c9373b6d8590a29c8324ccbb7fa6e Mon Sep 17 00:00:00 2001 From: Ziv Hirsch Date: Tue, 9 Aug 2022 13:14:05 +0300 Subject: [PATCH] nvme: add support for verify command Signed-off-by: Ziv Hirsch Change-Id: Ic9859d5078d9568bb28eefcf8fb70a7fc222ee15 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13928 Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Shuhei Matsumoto --- CHANGELOG.md | 2 ++ include/spdk/nvme.h | 26 ++++++++++++++ include/spdk/nvme_spec.h | 1 + lib/nvme/nvme_ns_cmd.c | 34 +++++++++++++++++++ lib/nvme/spdk_nvme.map | 1 + .../lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c | 26 ++++++++++++++ 6 files changed, 90 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b414f8fa1..3d4fa0179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,8 @@ an engine. Added SPDK_NVME_TRANSPORT_CUSTOM_FABRICS to enum spdk_nvme_transport_type to support custom fabric transport. SPDK_NVME_TRANSPORT_CUSTOM was intended to be non-fabric custom transport. +Added a new function `spdk_nvme_ns_cmd_verify` to submit a Verify Command to a Namespace. + ## v22.05 ### sock diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index b9cd38fe5..836a10ae5 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -3123,6 +3123,32 @@ int spdk_nvme_ns_cmd_write_zeroes(struct spdk_nvme_ns *ns, struct spdk_nvme_qpai spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags); +/** + * Submit a verify I/O to the specified NVMe namespace. + * + * 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. + * + * \param ns NVMe namespace to submit the verify I/O. + * \param qpair I/O queue pair to submit the request. + * \param lba Starting LBA to verify the data. + * \param lba_count Length (in sectors) for the verify operation. + * \param cb_fn Callback function to invoke when the I/O is completed. + * \param cb_arg Argument to pass to the callback function. + * \param io_flags Set flags, defined by the SPDK_NVME_IO_FLAGS_* entries in + * spdk/nvme_spec.h, for this I/O. + * + * \return 0 if successfully submitted, negated errnos on the following error conditions: + * -EINVAL: The request is malformed. + * -ENOMEM: The request cannot be allocated. + * -ENXIO: The qpair is failed at the transport level. + */ +int spdk_nvme_ns_cmd_verify(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, + uint64_t lba, uint32_t lba_count, + spdk_nvme_cmd_cb cb_fn, void *cb_arg, + uint32_t io_flags); + /** * Submit a write uncorrectable I/O to the specified NVMe namespace. * diff --git a/include/spdk/nvme_spec.h b/include/spdk/nvme_spec.h index 557f30ed9..2026bfb6e 100644 --- a/include/spdk/nvme_spec.h +++ b/include/spdk/nvme_spec.h @@ -1540,6 +1540,7 @@ enum spdk_nvme_nvm_opcode { SPDK_NVME_OPC_WRITE_ZEROES = 0x08, SPDK_NVME_OPC_DATASET_MANAGEMENT = 0x09, + SPDK_NVME_OPC_VERIFY = 0x0c, SPDK_NVME_OPC_RESERVATION_REGISTER = 0x0d, SPDK_NVME_OPC_RESERVATION_REPORT = 0x0e, diff --git a/lib/nvme/nvme_ns_cmd.c b/lib/nvme/nvme_ns_cmd.c index 25dbd87ba..6337e220d 100644 --- a/lib/nvme/nvme_ns_cmd.c +++ b/lib/nvme/nvme_ns_cmd.c @@ -1087,6 +1087,40 @@ spdk_nvme_ns_cmd_write_zeroes(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *q return nvme_qpair_submit_request(qpair, req); } +int +spdk_nvme_ns_cmd_verify(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, + uint64_t lba, uint32_t lba_count, + spdk_nvme_cmd_cb cb_fn, void *cb_arg, + uint32_t io_flags) +{ + struct nvme_request *req; + struct spdk_nvme_cmd *cmd; + + if (!_is_io_flags_valid(io_flags)) { + return -EINVAL; + } + + if (lba_count == 0 || lba_count > UINT16_MAX + 1) { + return -EINVAL; + } + + req = nvme_allocate_request_null(qpair, cb_fn, cb_arg); + if (req == NULL) { + return -ENOMEM; + } + + cmd = &req->cmd; + cmd->opc = SPDK_NVME_OPC_VERIFY; + cmd->nsid = ns->id; + + *(uint64_t *)&cmd->cdw10 = lba; + cmd->cdw12 = lba_count - 1; + cmd->fuse = (io_flags & SPDK_NVME_IO_FLAGS_FUSE_MASK); + cmd->cdw12 |= (io_flags & SPDK_NVME_IO_FLAGS_CDW12_MASK); + + return nvme_qpair_submit_request(qpair, req); +} + int spdk_nvme_ns_cmd_write_uncorrectable(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, uint64_t lba, uint32_t lba_count, diff --git a/lib/nvme/spdk_nvme.map b/lib/nvme/spdk_nvme.map index f4522aa31..b69a2967b 100644 --- a/lib/nvme/spdk_nvme.map +++ b/lib/nvme/spdk_nvme.map @@ -167,6 +167,7 @@ spdk_nvme_ns_cmd_compare_with_md; spdk_nvme_ns_cmd_writev_ext; spdk_nvme_ns_cmd_readv_ext; + spdk_nvme_ns_cmd_verify; spdk_nvme_qpair_get_optimal_poll_group; spdk_nvme_qpair_process_completions; diff --git a/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c b/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c index 7fc3e096e..67587233d 100644 --- a/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c +++ b/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c @@ -2204,6 +2204,31 @@ test_spdk_nvme_ns_cmd_readv_ext(void) cleanup_after_test(&qpair); } +static void +test_nvme_ns_cmd_verify(void) +{ + struct spdk_nvme_ns ns; + struct spdk_nvme_ctrlr ctrlr; + struct spdk_nvme_qpair qpair; + uint64_t cmd_lba; + uint32_t cmd_lba_count; + int rc; + + prepare_for_test(&ns, &ctrlr, &qpair, 512, 0, 128 * 1024, 0, false); + + rc = spdk_nvme_ns_cmd_verify(&ns, &qpair, 0, 2, NULL, NULL, 0); + CU_ASSERT(rc == 0); + SPDK_CU_ASSERT_FATAL(g_request != NULL); + CU_ASSERT(g_request->cmd.opc == SPDK_NVME_OPC_VERIFY); + CU_ASSERT(g_request->cmd.nsid == ns.id); + nvme_cmd_interpret_rw(&g_request->cmd, &cmd_lba, &cmd_lba_count); + CU_ASSERT_EQUAL(cmd_lba, 0); + CU_ASSERT_EQUAL(cmd_lba_count, 2); + + nvme_free_request(g_request); + cleanup_after_test(&qpair); +} + int main(int argc, char **argv) { @@ -2244,6 +2269,7 @@ main(int argc, char **argv) CU_ADD_TEST(suite, test_spdk_nvme_ns_cmd_readv_with_md); CU_ADD_TEST(suite, test_spdk_nvme_ns_cmd_writev_ext); CU_ADD_TEST(suite, test_spdk_nvme_ns_cmd_readv_ext); + CU_ADD_TEST(suite, test_nvme_ns_cmd_verify); g_spdk_nvme_driver = &_g_nvme_driver;