1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. All rights reserved. 3 */ 4 5 #include "spdk/stdinc.h" 6 #include "spdk_cunit.h" 7 #include "common/lib/test_env.c" 8 #include "nvmf/vfio_user.c" 9 #include "nvmf/transport.c" 10 11 DEFINE_STUB(spdk_nvmf_ctrlr_get_regs, const struct spdk_nvmf_registers *, 12 (struct spdk_nvmf_ctrlr *ctrlr), NULL); 13 DEFINE_STUB(spdk_mem_register, int, (void *vaddr, size_t len), 0); 14 DEFINE_STUB(spdk_mem_unregister, int, (void *vaddr, size_t len), 0); 15 DEFINE_STUB_V(spdk_nvmf_request_exec, (struct spdk_nvmf_request *req)); 16 DEFINE_STUB_V(spdk_nvmf_request_exec_fabrics, (struct spdk_nvmf_request *req)); 17 DEFINE_STUB(spdk_nvmf_request_complete, int, (struct spdk_nvmf_request *req), 0); 18 DEFINE_STUB_V(spdk_nvmf_tgt_new_qpair, (struct spdk_nvmf_tgt *tgt, struct spdk_nvmf_qpair *qpair)); 19 DEFINE_STUB(nvmf_ctrlr_abort_request, int, (struct spdk_nvmf_request *req), 0); 20 DEFINE_STUB(spdk_nvmf_qpair_disconnect, int, (struct spdk_nvmf_qpair *qpair, 21 nvmf_qpair_disconnect_cb cb_fn, void *ctx), 0); 22 DEFINE_STUB(spdk_nvmf_subsystem_get_nqn, const char *, 23 (const struct spdk_nvmf_subsystem *subsystem), NULL); 24 DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, (const struct spdk_bdev *bdev), 512); 25 DEFINE_STUB(spdk_nvmf_subsystem_pause, int, (struct spdk_nvmf_subsystem *subsystem, 26 uint32_t nsid, spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg), 0); 27 DEFINE_STUB(spdk_nvmf_subsystem_resume, int, (struct spdk_nvmf_subsystem *subsystem, 28 spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg), 0); 29 DEFINE_STUB_V(nvmf_ctrlr_abort_aer, (struct spdk_nvmf_ctrlr *ctrlr)); 30 DEFINE_STUB(nvmf_ctrlr_async_event_error_event, int, (struct spdk_nvmf_ctrlr *ctrlr, 31 union spdk_nvme_async_event_completion event), 0); 32 DEFINE_STUB(spdk_nvme_transport_id_adrfam_str, const char *, (enum spdk_nvmf_adrfam adrfam), NULL); 33 DEFINE_STUB(spdk_nvmf_qpair_get_listen_trid, int, (struct spdk_nvmf_qpair *qpair, 34 struct spdk_nvme_transport_id *trid), 0); 35 DEFINE_STUB(spdk_nvme_transport_id_compare, int, (const struct spdk_nvme_transport_id *trid1, 36 const struct spdk_nvme_transport_id *trid2), 0); 37 DEFINE_STUB(nvmf_subsystem_get_ctrlr, struct spdk_nvmf_ctrlr *, 38 (struct spdk_nvmf_subsystem *subsystem, uint16_t cntlid), NULL); 39 DEFINE_STUB(nvmf_ctrlr_save_aers, int, (struct spdk_nvmf_ctrlr *ctrlr, uint16_t *aer_cids, 40 uint16_t max_aers), 0); 41 DEFINE_STUB(nvmf_ctrlr_save_migr_data, int, (struct spdk_nvmf_ctrlr *ctrlr, 42 struct nvmf_ctrlr_migr_data *data), 0); 43 DEFINE_STUB(nvmf_ctrlr_restore_migr_data, int, (struct spdk_nvmf_ctrlr *ctrlr, 44 struct nvmf_ctrlr_migr_data *data), 0); 45 DEFINE_STUB_V(nvmf_ctrlr_set_fatal_status, (struct spdk_nvmf_ctrlr *ctrlr)); 46 47 static void * 48 gpa_to_vva(void *prv, uint64_t addr, uint64_t len, int prot) 49 { 50 return (void *)(uintptr_t)addr; 51 } 52 53 static void 54 test_nvme_cmd_map_prps(void) 55 { 56 struct spdk_nvme_cmd cmd = {}; 57 struct iovec iovs[33]; 58 uint64_t phy_addr, *prp; 59 uint32_t len; 60 void *buf, *prps; 61 int i, ret; 62 size_t mps = 4096; 63 64 buf = spdk_zmalloc(132 * 1024, 4096, &phy_addr, 0, 0); 65 CU_ASSERT(buf != NULL); 66 prps = spdk_zmalloc(4096, 4096, &phy_addr, 0, 0); 67 CU_ASSERT(prps != NULL); 68 69 /* test case 1: 4KiB with PRP1 only */ 70 cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf; 71 len = 4096; 72 ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 73 CU_ASSERT(ret == 1); 74 CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1); 75 CU_ASSERT(iovs[0].iov_len == len); 76 77 /* test case 2: 4KiB with PRP1 and PRP2, 1KiB in first iov, and 3KiB in second iov */ 78 cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3; 79 cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)buf + 4096; 80 len = 4096; 81 ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 1, len, mps, gpa_to_vva); 82 CU_ASSERT(ret == -ERANGE); 83 ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 84 CU_ASSERT(ret == 2); 85 CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1); 86 CU_ASSERT(iovs[0].iov_len == 1024); 87 CU_ASSERT(iovs[1].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp2); 88 CU_ASSERT(iovs[1].iov_len == 1024 * 3); 89 90 /* test case 3: 128KiB with PRP list, 1KiB in first iov, 3KiB in last iov */ 91 cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3; 92 cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)prps; 93 len = 128 * 1024; 94 prp = prps; 95 for (i = 1; i < 33; i++) { 96 *prp = (uint64_t)(uintptr_t)buf + i * 4096; 97 prp++; 98 } 99 ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 100 CU_ASSERT(ret == 33); 101 CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1); 102 CU_ASSERT(iovs[0].iov_len == 1024); 103 for (i = 1; i < 32; i++) { 104 CU_ASSERT(iovs[i].iov_base == (void *)((uintptr_t)buf + i * 4096)); 105 CU_ASSERT(iovs[i].iov_len == 4096); 106 } 107 CU_ASSERT(iovs[32].iov_base == (void *)((uintptr_t)buf + 32 * 4096)); 108 CU_ASSERT(iovs[32].iov_len == 1024 * 3); 109 110 /* test case 4: 256KiB with PRP list, not enough iovs */ 111 cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3; 112 cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)prps; 113 len = 256 * 1024; 114 ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 115 CU_ASSERT(ret == -ERANGE); 116 117 spdk_free(buf); 118 spdk_free(prps); 119 } 120 121 static void 122 test_nvme_cmd_map_sgls(void) 123 { 124 struct spdk_nvme_cmd cmd = {}; 125 struct iovec iovs[33]; 126 uint64_t phy_addr; 127 uint32_t len; 128 void *buf, *sgls; 129 struct spdk_nvme_sgl_descriptor *sgl; 130 int i, ret; 131 size_t mps = 4096; 132 133 buf = spdk_zmalloc(132 * 1024, 4096, &phy_addr, 0, 0); 134 CU_ASSERT(buf != NULL); 135 sgls = spdk_zmalloc(4096, 4096, &phy_addr, 0, 0); 136 CU_ASSERT(sgls != NULL); 137 138 /* test case 1: 8KiB with 1 data block */ 139 len = 8192; 140 cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 141 cmd.dptr.sgl1.unkeyed.length = len; 142 cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)buf; 143 144 ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 145 CU_ASSERT(ret == 1); 146 CU_ASSERT(iovs[0].iov_base == buf); 147 CU_ASSERT(iovs[0].iov_len == 8192); 148 149 /* test case 2: 8KiB with 2 data blocks and 1 last segment */ 150 sgl = (struct spdk_nvme_sgl_descriptor *)sgls; 151 sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 152 sgl[0].unkeyed.length = 2048; 153 sgl[0].address = (uint64_t)(uintptr_t)buf; 154 sgl[1].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 155 sgl[1].unkeyed.length = len - 2048; 156 sgl[1].address = (uint64_t)(uintptr_t)buf + 16 * 1024; 157 158 cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT; 159 cmd.dptr.sgl1.unkeyed.length = 2 * sizeof(*sgl); 160 cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)sgls; 161 162 ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 163 CU_ASSERT(ret == 2); 164 CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)buf); 165 CU_ASSERT(iovs[0].iov_len == 2048); 166 CU_ASSERT(iovs[1].iov_base == (void *)((uintptr_t)buf + 16 * 1024)); 167 CU_ASSERT(iovs[1].iov_len == len - 2048); 168 169 /* test case 3: 8KiB with 1 segment, 1 last segment and 3 data blocks */ 170 sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 171 sgl[0].unkeyed.length = 2048; 172 sgl[0].address = (uint64_t)(uintptr_t)buf; 173 sgl[1].unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT; 174 sgl[1].unkeyed.length = 2 * sizeof(*sgl); 175 sgl[1].address = (uint64_t)(uintptr_t)&sgl[9]; 176 177 sgl[9].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 178 sgl[9].unkeyed.length = 4096; 179 sgl[9].address = (uint64_t)(uintptr_t)buf + 4 * 1024; 180 sgl[10].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 181 sgl[10].unkeyed.length = 2048; 182 sgl[10].address = (uint64_t)(uintptr_t)buf + 16 * 1024; 183 184 cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_SEGMENT; 185 cmd.dptr.sgl1.unkeyed.length = 2 * sizeof(*sgl); 186 cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)&sgl[0]; 187 188 ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva); 189 CU_ASSERT(ret == 3); 190 CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)buf); 191 CU_ASSERT(iovs[0].iov_len == 2048); 192 CU_ASSERT(iovs[1].iov_base == (void *)((uintptr_t)buf + 4 * 1024)); 193 CU_ASSERT(iovs[1].iov_len == 4096); 194 CU_ASSERT(iovs[2].iov_base == (void *)((uintptr_t)buf + 16 * 1024)); 195 CU_ASSERT(iovs[2].iov_len == 2048); 196 197 /* test case 4: not enough iovs */ 198 len = 12 * 1024; 199 for (i = 0; i < 6; i++) { 200 sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK; 201 sgl[0].unkeyed.length = 2048; 202 sgl[0].address = (uint64_t)(uintptr_t)buf + i * 4096; 203 } 204 205 cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT; 206 cmd.dptr.sgl1.unkeyed.length = 6 * sizeof(*sgl); 207 cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)sgls; 208 209 ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 4, len, mps, gpa_to_vva); 210 CU_ASSERT(ret == -ERANGE); 211 212 spdk_free(buf); 213 spdk_free(sgls); 214 } 215 216 static void 217 ut_transport_destroy_done_cb(void *cb_arg) 218 { 219 int *done = cb_arg; 220 *done = 1; 221 } 222 223 static void 224 test_nvmf_vfio_user_create_destroy(void) 225 { 226 struct spdk_nvmf_transport *transport = NULL; 227 struct nvmf_vfio_user_transport *vu_transport = NULL; 228 struct nvmf_vfio_user_endpoint *endpoint = NULL; 229 struct spdk_nvmf_transport_opts opts = {}; 230 int rc; 231 int done; 232 233 /* Initialize transport_specific NULL to avoid decoding json */ 234 opts.transport_specific = NULL; 235 236 transport = nvmf_vfio_user_create(&opts); 237 CU_ASSERT(transport != NULL); 238 239 vu_transport = SPDK_CONTAINEROF(transport, struct nvmf_vfio_user_transport, 240 transport); 241 /* Allocate a endpoint for destroy */ 242 endpoint = calloc(1, sizeof(*endpoint)); 243 pthread_mutex_init(&endpoint->lock, NULL); 244 TAILQ_INSERT_TAIL(&vu_transport->endpoints, endpoint, link); 245 done = 0; 246 247 rc = nvmf_vfio_user_destroy(transport, ut_transport_destroy_done_cb, &done); 248 CU_ASSERT(rc == 0); 249 CU_ASSERT(done == 1); 250 } 251 252 int 253 main(int argc, char **argv) 254 { 255 CU_pSuite suite = NULL; 256 unsigned int num_failures; 257 258 CU_set_error_action(CUEA_ABORT); 259 CU_initialize_registry(); 260 261 suite = CU_add_suite("vfio_user", NULL, NULL); 262 263 CU_ADD_TEST(suite, test_nvme_cmd_map_prps); 264 CU_ADD_TEST(suite, test_nvme_cmd_map_sgls); 265 CU_ADD_TEST(suite, test_nvmf_vfio_user_create_destroy); 266 267 CU_basic_set_mode(CU_BRM_VERBOSE); 268 CU_basic_run_tests(); 269 num_failures = CU_get_number_of_failures(); 270 CU_cleanup_registry(); 271 return num_failures; 272 } 273