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