From a529ff946fa86f9d08ea2e4b08588c81ca524f0e Mon Sep 17 00:00:00 2001 From: Jim Harris Date: Thu, 2 May 2019 15:51:19 -0700 Subject: [PATCH] test/bdevio: add test for NVMe passthrough read/write This uses the bdev nvme passthrough API to do a write followed by a read, checking for final data integrity. It helps verify the passthrough API is working correctly. Signed-off-by: Jim Harris Change-Id: I25fe685b0bdcb88c7537c165cc60f8df31823b24 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/452931 Tested-by: SPDK CI Jenkins Reviewed-by: Changpeng Liu Reviewed-by: Ben Walker --- test/bdev/bdevio/bdevio.c | 91 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/test/bdev/bdevio/bdevio.c b/test/bdev/bdevio/bdevio.c index 9e7b7ed47..ffd692f0e 100644 --- a/test/bdev/bdevio/bdevio.c +++ b/test/bdev/bdevio/bdevio.c @@ -830,6 +830,95 @@ blockdev_test_reset(void) } } +struct bdevio_passthrough_request { + struct spdk_nvme_cmd cmd; + void *buf; + uint32_t len; + struct io_target *target; + int sct; + int sc; +}; + +static void +nvme_pt_test_complete(struct spdk_bdev_io *bdev_io, bool success, void *arg) +{ + struct bdevio_passthrough_request *pt_req = arg; + + spdk_bdev_io_get_nvme_status(bdev_io, &pt_req->sct, &pt_req->sc); + spdk_bdev_free_io(bdev_io); + wake_ut_thread(); +} + +static void +__blockdev_nvme_passthru(void *arg1, void *arg2) +{ + struct bdevio_passthrough_request *pt_req = arg1; + struct io_target *target = pt_req->target; + int rc; + + rc = spdk_bdev_nvme_io_passthru(target->bdev_desc, target->ch, + &pt_req->cmd, pt_req->buf, pt_req->len, + nvme_pt_test_complete, pt_req); + if (rc) { + wake_ut_thread(); + } +} + +static void +blockdev_nvme_passthru_rw(struct io_target *target) +{ + struct bdevio_passthrough_request pt_req; + void *write_buf, *read_buf; + + if (!spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_NVME_IO)) { + return; + } + + memset(&pt_req, 0, sizeof(pt_req)); + pt_req.target = target; + pt_req.cmd.opc = SPDK_NVME_OPC_WRITE; + pt_req.cmd.nsid = 1; + *(uint64_t *)&pt_req.cmd.cdw10 = 4; + pt_req.cmd.cdw12 = 0; + + pt_req.len = spdk_bdev_get_block_size(target->bdev); + write_buf = spdk_dma_malloc(pt_req.len, 0, NULL); + memset(write_buf, 0xA5, pt_req.len); + pt_req.buf = write_buf; + + pt_req.sct = SPDK_NVME_SCT_VENDOR_SPECIFIC; + pt_req.sc = SPDK_NVME_SC_INVALID_FIELD; + execute_spdk_function(__blockdev_nvme_passthru, &pt_req, NULL); + CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC); + CU_ASSERT(pt_req.sc == SPDK_NVME_SC_SUCCESS); + + pt_req.cmd.opc = SPDK_NVME_OPC_READ; + read_buf = spdk_dma_zmalloc(pt_req.len, 0, NULL); + pt_req.buf = read_buf; + + pt_req.sct = SPDK_NVME_SCT_VENDOR_SPECIFIC; + pt_req.sc = SPDK_NVME_SC_INVALID_FIELD; + execute_spdk_function(__blockdev_nvme_passthru, &pt_req, NULL); + CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC); + CU_ASSERT(pt_req.sc == SPDK_NVME_SC_SUCCESS); + + CU_ASSERT(!memcmp(read_buf, write_buf, pt_req.len)); + spdk_dma_free(read_buf); + spdk_dma_free(write_buf); +} + +static void +blockdev_test_nvme_passthru_rw(void) +{ + struct io_target *target; + + target = g_io_targets; + while (target != NULL) { + blockdev_nvme_passthru_rw(target); + target = target->next; + } +} + static void __stop_init_thread(void *arg1, void *arg2) { @@ -896,6 +985,8 @@ __run_ut_thread(void *arg1, void *arg2) blockdev_writev_readv_size_gt_128k) == NULL || CU_add_test(suite, "blockdev writev readv size > 128k in two iovs", blockdev_writev_readv_size_gt_128k_two_iov) == NULL + || CU_add_test(suite, "blockdev nvme passthru rw", + blockdev_test_nvme_passthru_rw) == NULL || CU_add_test(suite, "blockdev reset", blockdev_test_reset) == NULL ) {