1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2021 Intel Corporation. All rights reserved. 31b28efb5SChangpeng Liu */ 41b28efb5SChangpeng Liu 51b28efb5SChangpeng Liu #include "spdk/stdinc.h" 6ae431e31SKonrad Sztyber #include "spdk_internal/cunit.h" 71b28efb5SChangpeng Liu #include "common/lib/test_env.c" 81b28efb5SChangpeng Liu #include "nvmf/vfio_user.c" 91b28efb5SChangpeng Liu #include "nvmf/transport.c" 101b28efb5SChangpeng Liu 111b28efb5SChangpeng Liu DEFINE_STUB(spdk_nvmf_ctrlr_get_regs, const struct spdk_nvmf_registers *, 121b28efb5SChangpeng Liu (struct spdk_nvmf_ctrlr *ctrlr), NULL); 131b28efb5SChangpeng Liu DEFINE_STUB(spdk_mem_register, int, (void *vaddr, size_t len), 0); 141b28efb5SChangpeng Liu DEFINE_STUB(spdk_mem_unregister, int, (void *vaddr, size_t len), 0); 151b28efb5SChangpeng Liu DEFINE_STUB_V(spdk_nvmf_request_exec, (struct spdk_nvmf_request *req)); 161b28efb5SChangpeng Liu DEFINE_STUB(spdk_nvmf_request_complete, int, (struct spdk_nvmf_request *req), 0); 171b28efb5SChangpeng Liu DEFINE_STUB_V(spdk_nvmf_tgt_new_qpair, (struct spdk_nvmf_tgt *tgt, struct spdk_nvmf_qpair *qpair)); 181b28efb5SChangpeng Liu DEFINE_STUB(nvmf_ctrlr_abort_request, int, (struct spdk_nvmf_request *req), 0); 19608b54a2SKonrad Sztyber DEFINE_STUB(spdk_nvmf_qpair_disconnect, int, (struct spdk_nvmf_qpair *qpair), 0); 201b28efb5SChangpeng Liu DEFINE_STUB(spdk_nvmf_subsystem_get_nqn, const char *, 211b28efb5SChangpeng Liu (const struct spdk_nvmf_subsystem *subsystem), NULL); 22*b09de013SShuhei Matsumoto DEFINE_STUB(spdk_bdev_desc_get_block_size, uint32_t, (struct spdk_bdev_desc *desc), 512); 23b3cd421fSChangpeng Liu DEFINE_STUB(spdk_nvmf_subsystem_pause, int, (struct spdk_nvmf_subsystem *subsystem, 24b3cd421fSChangpeng Liu uint32_t nsid, spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg), 0); 25b3cd421fSChangpeng Liu DEFINE_STUB(spdk_nvmf_subsystem_resume, int, (struct spdk_nvmf_subsystem *subsystem, 26b3cd421fSChangpeng Liu spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg), 0); 27414ff9bcSSzulik, Maciej DEFINE_STUB_V(spdk_nvmf_ctrlr_abort_aer, (struct spdk_nvmf_ctrlr *ctrlr)); 28414ff9bcSSzulik, Maciej DEFINE_STUB(spdk_nvmf_ctrlr_async_event_error_event, int, (struct spdk_nvmf_ctrlr *ctrlr, 29414ff9bcSSzulik, Maciej enum spdk_nvme_async_event_info_error info), 0); 30723adbafSChangpeng Liu DEFINE_STUB(spdk_nvme_transport_id_adrfam_str, const char *, (enum spdk_nvmf_adrfam adrfam), NULL); 31723adbafSChangpeng Liu DEFINE_STUB(spdk_nvmf_qpair_get_listen_trid, int, (struct spdk_nvmf_qpair *qpair, 32723adbafSChangpeng Liu struct spdk_nvme_transport_id *trid), 0); 33723adbafSChangpeng Liu DEFINE_STUB(spdk_nvme_transport_id_compare, int, (const struct spdk_nvme_transport_id *trid1, 34723adbafSChangpeng Liu const struct spdk_nvme_transport_id *trid2), 0); 35b3cd421fSChangpeng Liu DEFINE_STUB(nvmf_subsystem_get_ctrlr, struct spdk_nvmf_ctrlr *, 36b3cd421fSChangpeng Liu (struct spdk_nvmf_subsystem *subsystem, uint16_t cntlid), NULL); 37a576bcccSChangpeng Liu DEFINE_STUB_V(nvmf_ctrlr_set_fatal_status, (struct spdk_nvmf_ctrlr *ctrlr)); 38982c25feSChangpeng Liu DEFINE_STUB(spdk_nvmf_ctrlr_save_migr_data, int, (struct spdk_nvmf_ctrlr *ctrlr, 39982c25feSChangpeng Liu struct spdk_nvmf_ctrlr_migr_data *data), 0); 40982c25feSChangpeng Liu DEFINE_STUB(spdk_nvmf_ctrlr_restore_migr_data, int, (struct spdk_nvmf_ctrlr *ctrlr, 41982c25feSChangpeng Liu const struct spdk_nvmf_ctrlr_migr_data *data), 0); 421ac56070SKonrad Sztyber DEFINE_STUB(spdk_mempool_lookup, struct spdk_mempool *, (const char *name), NULL); 43a1a770d0SMichael Haeuptle DEFINE_STUB(nvmf_subsystem_gen_cntlid, uint16_t, (struct spdk_nvmf_subsystem *subsystem), 1) 441b28efb5SChangpeng Liu 451b28efb5SChangpeng Liu static void * 46ea14933aSJohn Levon gpa_to_vva(void *prv, uint64_t addr, uint64_t len, uint32_t flags) 471b28efb5SChangpeng Liu { 481b28efb5SChangpeng Liu return (void *)(uintptr_t)addr; 491b28efb5SChangpeng Liu } 501b28efb5SChangpeng Liu 511b28efb5SChangpeng Liu static void 521b28efb5SChangpeng Liu test_nvme_cmd_map_prps(void) 531b28efb5SChangpeng Liu { 541b28efb5SChangpeng Liu struct spdk_nvme_cmd cmd = {}; 551b28efb5SChangpeng Liu struct iovec iovs[33]; 561b28efb5SChangpeng Liu uint64_t phy_addr, *prp; 571b28efb5SChangpeng Liu uint32_t len; 581b28efb5SChangpeng Liu void *buf, *prps; 591b28efb5SChangpeng Liu int i, ret; 601b28efb5SChangpeng Liu size_t mps = 4096; 611b28efb5SChangpeng Liu 621b28efb5SChangpeng Liu buf = spdk_zmalloc(132 * 1024, 4096, &phy_addr, 0, 0); 631b28efb5SChangpeng Liu CU_ASSERT(buf != NULL); 641b28efb5SChangpeng Liu prps = spdk_zmalloc(4096, 4096, &phy_addr, 0, 0); 651b28efb5SChangpeng Liu CU_ASSERT(prps != NULL); 661b28efb5SChangpeng Liu 671b28efb5SChangpeng Liu /* test case 1: 4KiB with PRP1 only */ 681b28efb5SChangpeng Liu cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf; 691b28efb5SChangpeng Liu len = 4096; 701b28efb5SChangpeng Liu ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 711b28efb5SChangpeng Liu CU_ASSERT(ret == 1); 721b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1); 731b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_len == len); 741b28efb5SChangpeng Liu 751b28efb5SChangpeng Liu /* test case 2: 4KiB with PRP1 and PRP2, 1KiB in first iov, and 3KiB in second iov */ 761b28efb5SChangpeng Liu cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3; 771b28efb5SChangpeng Liu cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)buf + 4096; 781b28efb5SChangpeng Liu len = 4096; 791b28efb5SChangpeng Liu ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 1, len, mps, gpa_to_vva); 801b28efb5SChangpeng Liu CU_ASSERT(ret == -ERANGE); 811b28efb5SChangpeng Liu ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 821b28efb5SChangpeng Liu CU_ASSERT(ret == 2); 831b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1); 841b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_len == 1024); 851b28efb5SChangpeng Liu CU_ASSERT(iovs[1].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp2); 861b28efb5SChangpeng Liu CU_ASSERT(iovs[1].iov_len == 1024 * 3); 871b28efb5SChangpeng Liu 881b28efb5SChangpeng Liu /* test case 3: 128KiB with PRP list, 1KiB in first iov, 3KiB in last iov */ 891b28efb5SChangpeng Liu cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3; 901b28efb5SChangpeng Liu cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)prps; 911b28efb5SChangpeng Liu len = 128 * 1024; 921b28efb5SChangpeng Liu prp = prps; 931b28efb5SChangpeng Liu for (i = 1; i < 33; i++) { 941b28efb5SChangpeng Liu *prp = (uint64_t)(uintptr_t)buf + i * 4096; 951b28efb5SChangpeng Liu prp++; 961b28efb5SChangpeng Liu } 971b28efb5SChangpeng Liu ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 981b28efb5SChangpeng Liu CU_ASSERT(ret == 33); 991b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1); 1001b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_len == 1024); 1011b28efb5SChangpeng Liu for (i = 1; i < 32; i++) { 1021b28efb5SChangpeng Liu CU_ASSERT(iovs[i].iov_base == (void *)((uintptr_t)buf + i * 4096)); 1031b28efb5SChangpeng Liu CU_ASSERT(iovs[i].iov_len == 4096); 1041b28efb5SChangpeng Liu } 1051b28efb5SChangpeng Liu CU_ASSERT(iovs[32].iov_base == (void *)((uintptr_t)buf + 32 * 4096)); 1061b28efb5SChangpeng Liu CU_ASSERT(iovs[32].iov_len == 1024 * 3); 1071b28efb5SChangpeng Liu 1081b28efb5SChangpeng Liu /* test case 4: 256KiB with PRP list, not enough iovs */ 1091b28efb5SChangpeng Liu cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3; 1101b28efb5SChangpeng Liu cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)prps; 1111b28efb5SChangpeng Liu len = 256 * 1024; 1121b28efb5SChangpeng Liu ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 1131b28efb5SChangpeng Liu CU_ASSERT(ret == -ERANGE); 1141b28efb5SChangpeng Liu 1151b28efb5SChangpeng Liu spdk_free(buf); 1161b28efb5SChangpeng Liu spdk_free(prps); 1171b28efb5SChangpeng Liu } 1181b28efb5SChangpeng Liu 1191b28efb5SChangpeng Liu static void 1201b28efb5SChangpeng Liu test_nvme_cmd_map_sgls(void) 1211b28efb5SChangpeng Liu { 1221b28efb5SChangpeng Liu struct spdk_nvme_cmd cmd = {}; 1231b28efb5SChangpeng Liu struct iovec iovs[33]; 1241b28efb5SChangpeng Liu uint64_t phy_addr; 1251b28efb5SChangpeng Liu uint32_t len; 1261b28efb5SChangpeng Liu void *buf, *sgls; 1271b28efb5SChangpeng Liu struct spdk_nvme_sgl_descriptor *sgl; 1281b28efb5SChangpeng Liu int i, ret; 1291b28efb5SChangpeng Liu size_t mps = 4096; 1301b28efb5SChangpeng Liu 1311b28efb5SChangpeng Liu buf = spdk_zmalloc(132 * 1024, 4096, &phy_addr, 0, 0); 1321b28efb5SChangpeng Liu CU_ASSERT(buf != NULL); 1331b28efb5SChangpeng Liu sgls = spdk_zmalloc(4096, 4096, &phy_addr, 0, 0); 1341b28efb5SChangpeng Liu CU_ASSERT(sgls != NULL); 1351b28efb5SChangpeng Liu 1361b28efb5SChangpeng Liu /* test case 1: 8KiB with 1 data block */ 1371b28efb5SChangpeng Liu len = 8192; 1381b28efb5SChangpeng Liu cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 1391b28efb5SChangpeng Liu cmd.dptr.sgl1.unkeyed.length = len; 1401b28efb5SChangpeng Liu cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)buf; 1411b28efb5SChangpeng Liu 1421b28efb5SChangpeng Liu ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 1431b28efb5SChangpeng Liu CU_ASSERT(ret == 1); 1441b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_base == buf); 1451b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_len == 8192); 1461b28efb5SChangpeng Liu 1471b28efb5SChangpeng Liu /* test case 2: 8KiB with 2 data blocks and 1 last segment */ 1481b28efb5SChangpeng Liu sgl = (struct spdk_nvme_sgl_descriptor *)sgls; 1491b28efb5SChangpeng Liu sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 1501b28efb5SChangpeng Liu sgl[0].unkeyed.length = 2048; 1511b28efb5SChangpeng Liu sgl[0].address = (uint64_t)(uintptr_t)buf; 1521b28efb5SChangpeng Liu sgl[1].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 1531b28efb5SChangpeng Liu sgl[1].unkeyed.length = len - 2048; 1541b28efb5SChangpeng Liu sgl[1].address = (uint64_t)(uintptr_t)buf + 16 * 1024; 1551b28efb5SChangpeng Liu 1561b28efb5SChangpeng Liu cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT; 1571b28efb5SChangpeng Liu cmd.dptr.sgl1.unkeyed.length = 2 * sizeof(*sgl); 1581b28efb5SChangpeng Liu cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)sgls; 1591b28efb5SChangpeng Liu 1601b28efb5SChangpeng Liu ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 1611b28efb5SChangpeng Liu CU_ASSERT(ret == 2); 1621b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)buf); 1631b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_len == 2048); 1641b28efb5SChangpeng Liu CU_ASSERT(iovs[1].iov_base == (void *)((uintptr_t)buf + 16 * 1024)); 1651b28efb5SChangpeng Liu CU_ASSERT(iovs[1].iov_len == len - 2048); 1661b28efb5SChangpeng Liu 1671b28efb5SChangpeng Liu /* test case 3: 8KiB with 1 segment, 1 last segment and 3 data blocks */ 1681b28efb5SChangpeng Liu sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 1691b28efb5SChangpeng Liu sgl[0].unkeyed.length = 2048; 1701b28efb5SChangpeng Liu sgl[0].address = (uint64_t)(uintptr_t)buf; 1711b28efb5SChangpeng Liu sgl[1].unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT; 1721b28efb5SChangpeng Liu sgl[1].unkeyed.length = 2 * sizeof(*sgl); 1731b28efb5SChangpeng Liu sgl[1].address = (uint64_t)(uintptr_t)&sgl[9]; 1741b28efb5SChangpeng Liu 1751b28efb5SChangpeng Liu sgl[9].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 1761b28efb5SChangpeng Liu sgl[9].unkeyed.length = 4096; 1771b28efb5SChangpeng Liu sgl[9].address = (uint64_t)(uintptr_t)buf + 4 * 1024; 1781b28efb5SChangpeng Liu sgl[10].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 1791b28efb5SChangpeng Liu sgl[10].unkeyed.length = 2048; 1801b28efb5SChangpeng Liu sgl[10].address = (uint64_t)(uintptr_t)buf + 16 * 1024; 1811b28efb5SChangpeng Liu 1821b28efb5SChangpeng Liu cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_SEGMENT; 1831b28efb5SChangpeng Liu cmd.dptr.sgl1.unkeyed.length = 2 * sizeof(*sgl); 1841b28efb5SChangpeng Liu cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)&sgl[0]; 1851b28efb5SChangpeng Liu 1861b28efb5SChangpeng Liu ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 1871b28efb5SChangpeng Liu CU_ASSERT(ret == 3); 1881b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)buf); 1891b28efb5SChangpeng Liu CU_ASSERT(iovs[0].iov_len == 2048); 1901b28efb5SChangpeng Liu CU_ASSERT(iovs[1].iov_base == (void *)((uintptr_t)buf + 4 * 1024)); 1911b28efb5SChangpeng Liu CU_ASSERT(iovs[1].iov_len == 4096); 1921b28efb5SChangpeng Liu CU_ASSERT(iovs[2].iov_base == (void *)((uintptr_t)buf + 16 * 1024)); 1931b28efb5SChangpeng Liu CU_ASSERT(iovs[2].iov_len == 2048); 1941b28efb5SChangpeng Liu 1951b28efb5SChangpeng Liu /* test case 4: not enough iovs */ 1961b28efb5SChangpeng Liu len = 12 * 1024; 1971b28efb5SChangpeng Liu for (i = 0; i < 6; i++) { 1981b28efb5SChangpeng Liu sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 1991b28efb5SChangpeng Liu sgl[0].unkeyed.length = 2048; 2001b28efb5SChangpeng Liu sgl[0].address = (uint64_t)(uintptr_t)buf + i * 4096; 2011b28efb5SChangpeng Liu } 2021b28efb5SChangpeng Liu 2031b28efb5SChangpeng Liu cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT; 2041b28efb5SChangpeng Liu cmd.dptr.sgl1.unkeyed.length = 6 * sizeof(*sgl); 2051b28efb5SChangpeng Liu cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)sgls; 2061b28efb5SChangpeng Liu 2071b28efb5SChangpeng Liu ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 4, len, mps, gpa_to_vva); 2081b28efb5SChangpeng Liu CU_ASSERT(ret == -ERANGE); 2091b28efb5SChangpeng Liu 2101b28efb5SChangpeng Liu spdk_free(buf); 2111b28efb5SChangpeng Liu spdk_free(sgls); 2121b28efb5SChangpeng Liu } 2131b28efb5SChangpeng Liu 214a43f891eSMao Jiang static void 215a43f891eSMao Jiang ut_transport_destroy_done_cb(void *cb_arg) 216a43f891eSMao Jiang { 217a43f891eSMao Jiang int *done = cb_arg; 218a43f891eSMao Jiang *done = 1; 219a43f891eSMao Jiang } 220a43f891eSMao Jiang 221a43f891eSMao Jiang static void 222a43f891eSMao Jiang test_nvmf_vfio_user_create_destroy(void) 223a43f891eSMao Jiang { 224a43f891eSMao Jiang struct spdk_nvmf_transport *transport = NULL; 225a43f891eSMao Jiang struct nvmf_vfio_user_transport *vu_transport = NULL; 226a43f891eSMao Jiang struct nvmf_vfio_user_endpoint *endpoint = NULL; 227a43f891eSMao Jiang struct spdk_nvmf_transport_opts opts = {}; 228a43f891eSMao Jiang int rc; 229a43f891eSMao Jiang int done; 230a43f891eSMao Jiang 231a43f891eSMao Jiang /* Initialize transport_specific NULL to avoid decoding json */ 232a43f891eSMao Jiang opts.transport_specific = NULL; 233a43f891eSMao Jiang 234a43f891eSMao Jiang transport = nvmf_vfio_user_create(&opts); 235a43f891eSMao Jiang CU_ASSERT(transport != NULL); 236a43f891eSMao Jiang 237a43f891eSMao Jiang vu_transport = SPDK_CONTAINEROF(transport, struct nvmf_vfio_user_transport, 238a43f891eSMao Jiang transport); 239a43f891eSMao Jiang /* Allocate a endpoint for destroy */ 240a43f891eSMao Jiang endpoint = calloc(1, sizeof(*endpoint)); 241a43f891eSMao Jiang pthread_mutex_init(&endpoint->lock, NULL); 242a43f891eSMao Jiang TAILQ_INSERT_TAIL(&vu_transport->endpoints, endpoint, link); 243a43f891eSMao Jiang done = 0; 244a43f891eSMao Jiang 245a43f891eSMao Jiang rc = nvmf_vfio_user_destroy(transport, ut_transport_destroy_done_cb, &done); 246a43f891eSMao Jiang CU_ASSERT(rc == 0); 247a43f891eSMao Jiang CU_ASSERT(done == 1); 248a43f891eSMao Jiang } 249a43f891eSMao Jiang 2508dd1cd21SBen Walker int 2518dd1cd21SBen Walker main(int argc, char **argv) 2521b28efb5SChangpeng Liu { 2531b28efb5SChangpeng Liu CU_pSuite suite = NULL; 2541b28efb5SChangpeng Liu unsigned int num_failures; 2551b28efb5SChangpeng Liu 2561b28efb5SChangpeng Liu CU_initialize_registry(); 2571b28efb5SChangpeng Liu 2581b28efb5SChangpeng Liu suite = CU_add_suite("vfio_user", NULL, NULL); 2591b28efb5SChangpeng Liu 2601b28efb5SChangpeng Liu CU_ADD_TEST(suite, test_nvme_cmd_map_prps); 2611b28efb5SChangpeng Liu CU_ADD_TEST(suite, test_nvme_cmd_map_sgls); 262a43f891eSMao Jiang CU_ADD_TEST(suite, test_nvmf_vfio_user_create_destroy); 2631b28efb5SChangpeng Liu 264ea941caeSKonrad Sztyber num_failures = spdk_ut_run_tests(argc, argv, NULL); 2651b28efb5SChangpeng Liu CU_cleanup_registry(); 2661b28efb5SChangpeng Liu return num_failures; 2671b28efb5SChangpeng Liu } 268