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