]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/test/unit/lib/nvme/nvme.c/nvme_ut.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / test / unit / lib / nvme / nvme.c / nvme_ut.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "spdk_cunit.h"
35
36 #include "spdk/env.h"
37
38 #include "nvme/nvme.c"
39
40 #include "spdk_internal/mock.h"
41
42 #include "common/lib/test_env.c"
43
44 DEFINE_STUB_V(nvme_ctrlr_proc_get_ref, (struct spdk_nvme_ctrlr *ctrlr));
45 DEFINE_STUB_V(nvme_ctrlr_proc_put_ref, (struct spdk_nvme_ctrlr *ctrlr));
46 DEFINE_STUB(spdk_nvme_transport_available, bool,
47 (enum spdk_nvme_transport_type trtype), true);
48 /* return anything non-NULL, this won't be deferenced anywhere in this test */
49 DEFINE_STUB(spdk_nvme_ctrlr_get_current_process, struct spdk_nvme_ctrlr_process *,
50 (struct spdk_nvme_ctrlr *ctrlr), (struct spdk_nvme_ctrlr_process *)(uintptr_t)0x1);
51 DEFINE_STUB(nvme_ctrlr_process_init, int,
52 (struct spdk_nvme_ctrlr *ctrlr), 0);
53 DEFINE_STUB(nvme_ctrlr_get_ref_count, int,
54 (struct spdk_nvme_ctrlr *ctrlr), 0);
55 DEFINE_STUB(dummy_probe_cb, bool,
56 (void *cb_ctx, const struct spdk_nvme_transport_id *trid,
57 struct spdk_nvme_ctrlr_opts *opts), false);
58 DEFINE_STUB(nvme_transport_ctrlr_construct, struct spdk_nvme_ctrlr *,
59 (const struct spdk_nvme_transport_id *trid,
60 const struct spdk_nvme_ctrlr_opts *opts,
61 void *devhandle), NULL);
62
63 static bool ut_destruct_called = false;
64 void
65 nvme_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
66 {
67 ut_destruct_called = true;
68 }
69
70 void
71 spdk_nvme_ctrlr_get_default_ctrlr_opts(struct spdk_nvme_ctrlr_opts *opts, size_t opts_size)
72 {
73 memset(opts, 0, sizeof(*opts));
74 }
75
76 static void
77 memset_trid(struct spdk_nvme_transport_id *trid1, struct spdk_nvme_transport_id *trid2)
78 {
79 memset(trid1, 0, sizeof(struct spdk_nvme_transport_id));
80 memset(trid2, 0, sizeof(struct spdk_nvme_transport_id));
81 }
82
83 static bool ut_check_trtype = false;
84 int
85 nvme_transport_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx,
86 bool direct_connect)
87 {
88 struct spdk_nvme_ctrlr *ctrlr = NULL;
89
90 if (ut_check_trtype == true) {
91 CU_ASSERT(probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE);
92 }
93
94 if (direct_connect == true && probe_ctx->probe_cb) {
95 nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
96 ctrlr = spdk_nvme_get_ctrlr_by_trid(&probe_ctx->trid);
97 nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
98 probe_ctx->probe_cb(probe_ctx->cb_ctx, &probe_ctx->trid, &ctrlr->opts);
99 }
100 return 0;
101 }
102
103 static bool ut_attach_cb_called = false;
104 static void
105 dummy_attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
106 struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
107 {
108 ut_attach_cb_called = true;
109 }
110
111 static void
112 test_spdk_nvme_probe(void)
113 {
114 int rc = 0;
115 const struct spdk_nvme_transport_id *trid = NULL;
116 void *cb_ctx = NULL;
117 spdk_nvme_probe_cb probe_cb = NULL;
118 spdk_nvme_attach_cb attach_cb = dummy_attach_cb;
119 spdk_nvme_remove_cb remove_cb = NULL;
120 struct spdk_nvme_ctrlr ctrlr;
121 pthread_mutexattr_t attr;
122 struct nvme_driver dummy;
123 g_spdk_nvme_driver = &dummy;
124
125 /* driver init fails */
126 MOCK_SET(spdk_process_is_primary, false);
127 MOCK_SET(spdk_memzone_lookup, NULL);
128 rc = spdk_nvme_probe(trid, cb_ctx, probe_cb, attach_cb, remove_cb);
129 CU_ASSERT(rc == -1);
130
131 /*
132 * For secondary processes, the attach_cb should automatically get
133 * called for any controllers already initialized by the primary
134 * process.
135 */
136 MOCK_SET(spdk_nvme_transport_available, false);
137 MOCK_SET(spdk_process_is_primary, true);
138 dummy.initialized = true;
139 g_spdk_nvme_driver = &dummy;
140 rc = spdk_nvme_probe(trid, cb_ctx, probe_cb, attach_cb, remove_cb);
141 CU_ASSERT(rc == -1);
142
143 /* driver init passes, transport available, secondary call attach_cb */
144 MOCK_SET(spdk_nvme_transport_available, true);
145 MOCK_SET(spdk_process_is_primary, false);
146 MOCK_SET(spdk_memzone_lookup, g_spdk_nvme_driver);
147 dummy.initialized = true;
148 memset(&ctrlr, 0, sizeof(struct spdk_nvme_ctrlr));
149 CU_ASSERT(pthread_mutexattr_init(&attr) == 0);
150 CU_ASSERT(pthread_mutex_init(&dummy.lock, &attr) == 0);
151 TAILQ_INIT(&dummy.shared_attached_ctrlrs);
152 TAILQ_INSERT_TAIL(&dummy.shared_attached_ctrlrs, &ctrlr, tailq);
153 ut_attach_cb_called = false;
154 /* setup nvme_transport_ctrlr_scan() stub to also check the trype */
155 ut_check_trtype = true;
156 rc = spdk_nvme_probe(trid, cb_ctx, probe_cb, attach_cb, remove_cb);
157 CU_ASSERT(rc == 0);
158 CU_ASSERT(ut_attach_cb_called == true);
159
160 /* driver init passes, transport available, we are primary */
161 MOCK_SET(spdk_process_is_primary, true);
162 rc = spdk_nvme_probe(trid, cb_ctx, probe_cb, attach_cb, remove_cb);
163 CU_ASSERT(rc == 0);
164
165 g_spdk_nvme_driver = NULL;
166 /* reset to pre-test values */
167 MOCK_CLEAR(spdk_memzone_lookup);
168 ut_check_trtype = false;
169
170 pthread_mutex_destroy(&dummy.lock);
171 pthread_mutexattr_destroy(&attr);
172 }
173
174 static void
175 test_spdk_nvme_connect(void)
176 {
177 struct spdk_nvme_ctrlr *ret_ctrlr = NULL;
178 struct spdk_nvme_transport_id trid = {};
179 struct spdk_nvme_ctrlr_opts opts = {};
180 struct spdk_nvme_ctrlr ctrlr;
181 pthread_mutexattr_t attr;
182 struct nvme_driver dummy;
183
184 /* initialize the variable to prepare the test */
185 dummy.initialized = true;
186 TAILQ_INIT(&dummy.shared_attached_ctrlrs);
187 g_spdk_nvme_driver = &dummy;
188 CU_ASSERT(pthread_mutexattr_init(&attr) == 0);
189 CU_ASSERT(pthread_mutex_init(&g_spdk_nvme_driver->lock, &attr) == 0);
190
191 /* set NULL trid pointer to test immediate return */
192 ret_ctrlr = spdk_nvme_connect(NULL, NULL, 0);
193 CU_ASSERT(ret_ctrlr == NULL);
194
195 /* driver init passes, transport available, secondary process connects ctrlr */
196 MOCK_SET(spdk_process_is_primary, false);
197 MOCK_SET(spdk_memzone_lookup, g_spdk_nvme_driver);
198 MOCK_SET(spdk_nvme_transport_available, true);
199 memset(&trid, 0, sizeof(trid));
200 trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
201 ret_ctrlr = spdk_nvme_connect(&trid, NULL, 0);
202 CU_ASSERT(ret_ctrlr == NULL);
203
204 /* driver init passes, setup one ctrlr on the attached_list */
205 memset(&ctrlr, 0, sizeof(struct spdk_nvme_ctrlr));
206 snprintf(ctrlr.trid.traddr, sizeof(ctrlr.trid.traddr), "0000:01:00.0");
207 ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
208 TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->shared_attached_ctrlrs, &ctrlr, tailq);
209 /* get the ctrlr from the attached list */
210 snprintf(trid.traddr, sizeof(trid.traddr), "0000:01:00.0");
211 ret_ctrlr = spdk_nvme_connect(&trid, NULL, 0);
212 CU_ASSERT(ret_ctrlr == &ctrlr);
213 /* get the ctrlr from the attached list with default ctrlr opts */
214 ctrlr.opts.num_io_queues = DEFAULT_MAX_IO_QUEUES;
215 ret_ctrlr = spdk_nvme_connect(&trid, NULL, 0);
216 CU_ASSERT(ret_ctrlr == &ctrlr);
217 CU_ASSERT_EQUAL(ret_ctrlr->opts.num_io_queues, DEFAULT_MAX_IO_QUEUES);
218 /* get the ctrlr from the attached list with default ctrlr opts and consistent opts_size */
219 opts.num_io_queues = 1;
220 ret_ctrlr = spdk_nvme_connect(&trid, &opts, sizeof(opts));
221 CU_ASSERT(ret_ctrlr == &ctrlr);
222 CU_ASSERT_EQUAL(ret_ctrlr->opts.num_io_queues, 1);
223 /* opts_size must be sizeof(*opts) if opts != NULL */
224 ret_ctrlr = spdk_nvme_connect(&trid, &opts, sizeof(opts) + 1);
225 CU_ASSERT(ret_ctrlr == NULL);
226 /* remove the attached ctrlr on the attached_list */
227 CU_ASSERT(spdk_nvme_detach(&ctrlr) == 0);
228 CU_ASSERT(TAILQ_EMPTY(&g_spdk_nvme_driver->shared_attached_ctrlrs));
229
230 /* driver init passes, transport available, primary process connects ctrlr */
231 MOCK_SET(spdk_process_is_primary, true);
232 /* setup one ctrlr on the attached_list */
233 memset(&ctrlr, 0, sizeof(struct spdk_nvme_ctrlr));
234 snprintf(ctrlr.trid.traddr, sizeof(ctrlr.trid.traddr), "0000:02:00.0");
235 ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
236 TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->shared_attached_ctrlrs, &ctrlr, tailq);
237 /* get the ctrlr from the attached list */
238 snprintf(trid.traddr, sizeof(trid.traddr), "0000:02:00.0");
239 ret_ctrlr = spdk_nvme_connect(&trid, NULL, 0);
240 CU_ASSERT(ret_ctrlr == &ctrlr);
241 /* get the ctrlr from the attached list with default ctrlr opts */
242 ctrlr.opts.num_io_queues = DEFAULT_MAX_IO_QUEUES;
243 ret_ctrlr = spdk_nvme_connect(&trid, NULL, 0);
244 CU_ASSERT(ret_ctrlr == &ctrlr);
245 CU_ASSERT_EQUAL(ret_ctrlr->opts.num_io_queues, DEFAULT_MAX_IO_QUEUES);
246 /* get the ctrlr from the attached list with default ctrlr opts and consistent opts_size */
247 opts.num_io_queues = 2;
248 ret_ctrlr = spdk_nvme_connect(&trid, &opts, sizeof(opts));
249 CU_ASSERT(ret_ctrlr == &ctrlr);
250 CU_ASSERT_EQUAL(ret_ctrlr->opts.num_io_queues, 2);
251 /* remove the attached ctrlr on the attached_list */
252 CU_ASSERT(spdk_nvme_detach(ret_ctrlr) == 0);
253 CU_ASSERT(TAILQ_EMPTY(&g_spdk_nvme_driver->shared_attached_ctrlrs));
254
255 /* test driver init failure return */
256 MOCK_SET(spdk_process_is_primary, false);
257 MOCK_SET(spdk_memzone_lookup, NULL);
258 ret_ctrlr = spdk_nvme_connect(&trid, NULL, 0);
259 CU_ASSERT(ret_ctrlr == NULL);
260 }
261
262 static struct spdk_nvme_probe_ctx *
263 test_nvme_init_get_probe_ctx(void)
264 {
265 struct spdk_nvme_probe_ctx *probe_ctx;
266
267 probe_ctx = calloc(1, sizeof(*probe_ctx));
268 SPDK_CU_ASSERT_FATAL(probe_ctx != NULL);
269 TAILQ_INIT(&probe_ctx->init_ctrlrs);
270
271 return probe_ctx;
272 }
273
274 static void
275 test_nvme_init_controllers(void)
276 {
277 int rc = 0;
278 struct nvme_driver test_driver;
279 void *cb_ctx = NULL;
280 spdk_nvme_attach_cb attach_cb = dummy_attach_cb;
281 struct spdk_nvme_probe_ctx *probe_ctx;
282 struct spdk_nvme_ctrlr *ctrlr;
283 pthread_mutexattr_t attr;
284
285 g_spdk_nvme_driver = &test_driver;
286 ctrlr = calloc(1, sizeof(*ctrlr));
287 SPDK_CU_ASSERT_FATAL(ctrlr != NULL);
288 ctrlr->trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
289 CU_ASSERT(pthread_mutexattr_init(&attr) == 0);
290 CU_ASSERT(pthread_mutex_init(&test_driver.lock, &attr) == 0);
291 TAILQ_INIT(&test_driver.shared_attached_ctrlrs);
292
293 /*
294 * Try to initialize, but nvme_ctrlr_process_init will fail.
295 * Verify correct behavior when it does.
296 */
297 MOCK_SET(nvme_ctrlr_process_init, 1);
298 MOCK_SET(spdk_process_is_primary, 1);
299 g_spdk_nvme_driver->initialized = false;
300 ut_destruct_called = false;
301 probe_ctx = test_nvme_init_get_probe_ctx();
302 TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
303 probe_ctx->cb_ctx = cb_ctx;
304 probe_ctx->attach_cb = attach_cb;
305 probe_ctx->trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
306 rc = nvme_init_controllers(probe_ctx);
307 CU_ASSERT(rc != 0);
308 CU_ASSERT(g_spdk_nvme_driver->initialized == true);
309 CU_ASSERT(ut_destruct_called == true);
310
311 /*
312 * Controller init OK, need to move the controller state machine
313 * forward by setting the ctrl state so that it can be moved
314 * the shared_attached_ctrlrs list.
315 */
316 probe_ctx = test_nvme_init_get_probe_ctx();
317 TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
318 ctrlr->state = NVME_CTRLR_STATE_READY;
319 MOCK_SET(nvme_ctrlr_process_init, 0);
320 rc = nvme_init_controllers(probe_ctx);
321 CU_ASSERT(rc == 0);
322 CU_ASSERT(ut_attach_cb_called == true);
323 CU_ASSERT(TAILQ_EMPTY(&g_nvme_attached_ctrlrs));
324 CU_ASSERT(TAILQ_FIRST(&g_spdk_nvme_driver->shared_attached_ctrlrs) == ctrlr);
325 TAILQ_REMOVE(&g_spdk_nvme_driver->shared_attached_ctrlrs, ctrlr, tailq);
326
327 /*
328 * Non-PCIe controllers should be added to the per-process list, not the shared list.
329 */
330 memset(ctrlr, 0, sizeof(struct spdk_nvme_ctrlr));
331 ctrlr->trid.trtype = SPDK_NVME_TRANSPORT_RDMA;
332 probe_ctx = test_nvme_init_get_probe_ctx();
333 TAILQ_INSERT_TAIL(&probe_ctx->init_ctrlrs, ctrlr, tailq);
334 ctrlr->state = NVME_CTRLR_STATE_READY;
335 MOCK_SET(nvme_ctrlr_process_init, 0);
336 rc = nvme_init_controllers(probe_ctx);
337 CU_ASSERT(rc == 0);
338 CU_ASSERT(ut_attach_cb_called == true);
339 CU_ASSERT(TAILQ_EMPTY(&g_spdk_nvme_driver->shared_attached_ctrlrs));
340 CU_ASSERT(TAILQ_FIRST(&g_nvme_attached_ctrlrs) == ctrlr);
341 TAILQ_REMOVE(&g_nvme_attached_ctrlrs, ctrlr, tailq);
342 free(ctrlr);
343 CU_ASSERT(TAILQ_EMPTY(&g_nvme_attached_ctrlrs));
344
345 g_spdk_nvme_driver = NULL;
346 pthread_mutexattr_destroy(&attr);
347 pthread_mutex_destroy(&test_driver.lock);
348 }
349
350 static void
351 test_nvme_driver_init(void)
352 {
353 int rc;
354 struct nvme_driver dummy;
355 g_spdk_nvme_driver = &dummy;
356
357 /* adjust this so testing doesn't take so long */
358 g_nvme_driver_timeout_ms = 100;
359
360 /* process is primary and mem already reserved */
361 MOCK_SET(spdk_process_is_primary, true);
362 dummy.initialized = true;
363 rc = nvme_driver_init();
364 CU_ASSERT(rc == 0);
365
366 /*
367 * Process is primary and mem not yet reserved but the call
368 * to spdk_memzone_reserve() returns NULL.
369 */
370 g_spdk_nvme_driver = NULL;
371 MOCK_SET(spdk_process_is_primary, true);
372 MOCK_SET(spdk_memzone_reserve, NULL);
373 rc = nvme_driver_init();
374 CU_ASSERT(rc == -1);
375
376 /* process is not primary, no mem already reserved */
377 MOCK_SET(spdk_process_is_primary, false);
378 MOCK_SET(spdk_memzone_lookup, NULL);
379 g_spdk_nvme_driver = NULL;
380 rc = nvme_driver_init();
381 CU_ASSERT(rc == -1);
382
383 /* process is not primary, mem is already reserved & init'd */
384 MOCK_SET(spdk_process_is_primary, false);
385 MOCK_SET(spdk_memzone_lookup, (void *)&dummy);
386 dummy.initialized = true;
387 rc = nvme_driver_init();
388 CU_ASSERT(rc == 0);
389
390 /* process is not primary, mem is reserved but not initialized */
391 /* and times out */
392 MOCK_SET(spdk_process_is_primary, false);
393 MOCK_SET(spdk_memzone_reserve, (void *)&dummy);
394 dummy.initialized = false;
395 rc = nvme_driver_init();
396 CU_ASSERT(rc == -1);
397
398 /* process is primary, got mem but mutex won't init */
399 MOCK_SET(spdk_process_is_primary, true);
400 MOCK_SET(spdk_memzone_reserve, (void *)&dummy);
401 MOCK_SET(pthread_mutexattr_init, -1);
402 g_spdk_nvme_driver = NULL;
403 dummy.initialized = true;
404 rc = nvme_driver_init();
405 /* for FreeBSD we can't can't effectively mock this path */
406 #ifndef __FreeBSD__
407 CU_ASSERT(rc != 0);
408 #else
409 CU_ASSERT(rc == 0);
410 #endif
411
412 /* process is primary, got mem, mutex OK */
413 MOCK_SET(spdk_process_is_primary, true);
414 MOCK_CLEAR(pthread_mutexattr_init);
415 g_spdk_nvme_driver = NULL;
416 rc = nvme_driver_init();
417 CU_ASSERT(g_spdk_nvme_driver->initialized == false);
418 CU_ASSERT(TAILQ_EMPTY(&g_spdk_nvme_driver->shared_attached_ctrlrs));
419 CU_ASSERT(rc == 0);
420
421 g_spdk_nvme_driver = NULL;
422 MOCK_CLEAR(spdk_memzone_reserve);
423 MOCK_CLEAR(spdk_memzone_lookup);
424 }
425
426 static void
427 test_spdk_nvme_detach(void)
428 {
429 int rc = 1;
430 struct spdk_nvme_ctrlr ctrlr;
431 struct spdk_nvme_ctrlr *ret_ctrlr;
432 struct nvme_driver test_driver;
433
434 memset(&ctrlr, 0, sizeof(ctrlr));
435 ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
436
437 g_spdk_nvme_driver = &test_driver;
438 TAILQ_INIT(&test_driver.shared_attached_ctrlrs);
439 TAILQ_INSERT_TAIL(&test_driver.shared_attached_ctrlrs, &ctrlr, tailq);
440 CU_ASSERT(pthread_mutex_init(&test_driver.lock, NULL) == 0);
441
442 /*
443 * Controllers are ref counted so mock the function that returns
444 * the ref count so that detach will actually call the destruct
445 * function which we've mocked simply to verify that it gets
446 * called (we aren't testing what the real destruct function does
447 * here.)
448 */
449 MOCK_SET(nvme_ctrlr_get_ref_count, 0);
450 rc = spdk_nvme_detach(&ctrlr);
451 ret_ctrlr = TAILQ_FIRST(&test_driver.shared_attached_ctrlrs);
452 CU_ASSERT(ret_ctrlr == NULL);
453 CU_ASSERT(ut_destruct_called == true);
454 CU_ASSERT(rc == 0);
455
456 /*
457 * Mock the ref count to 1 so we confirm that the destruct
458 * function is not called and that attached ctrl list is
459 * not empty.
460 */
461 MOCK_SET(nvme_ctrlr_get_ref_count, 1);
462 TAILQ_INSERT_TAIL(&test_driver.shared_attached_ctrlrs, &ctrlr, tailq);
463 ut_destruct_called = false;
464 rc = spdk_nvme_detach(&ctrlr);
465 ret_ctrlr = TAILQ_FIRST(&test_driver.shared_attached_ctrlrs);
466 CU_ASSERT(ret_ctrlr != NULL);
467 CU_ASSERT(ut_destruct_called == false);
468 CU_ASSERT(rc == 0);
469
470 /*
471 * Non-PCIe controllers should be on the per-process attached_ctrlrs list, not the
472 * shared_attached_ctrlrs list. Test an RDMA controller and ensure it is removed
473 * from the correct list.
474 */
475 memset(&ctrlr, 0, sizeof(ctrlr));
476 ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_RDMA;
477 TAILQ_INIT(&g_nvme_attached_ctrlrs);
478 TAILQ_INSERT_TAIL(&g_nvme_attached_ctrlrs, &ctrlr, tailq);
479 MOCK_SET(nvme_ctrlr_get_ref_count, 0);
480 rc = spdk_nvme_detach(&ctrlr);
481 CU_ASSERT(TAILQ_EMPTY(&g_nvme_attached_ctrlrs));
482 CU_ASSERT(ut_destruct_called == true);
483 CU_ASSERT(rc == 0);
484
485 g_spdk_nvme_driver = NULL;
486 pthread_mutex_destroy(&test_driver.lock);
487 }
488
489 static void
490 test_nvme_completion_poll_cb(void)
491 {
492 struct nvme_completion_poll_status status;
493 struct spdk_nvme_cpl cpl;
494
495 memset(&status, 0x0, sizeof(status));
496 memset(&cpl, 0xff, sizeof(cpl));
497
498 nvme_completion_poll_cb(&status, &cpl);
499 CU_ASSERT(status.done == true);
500 CU_ASSERT(memcmp(&cpl, &status.cpl,
501 sizeof(struct spdk_nvme_cpl)) == 0);
502 }
503
504 /* stub callback used by test_nvme_user_copy_cmd_complete() */
505 static struct spdk_nvme_cpl ut_spdk_nvme_cpl = {0};
506 static void
507 dummy_cb(void *user_cb_arg, struct spdk_nvme_cpl *cpl)
508 {
509 ut_spdk_nvme_cpl = *cpl;
510 }
511
512 static void
513 test_nvme_user_copy_cmd_complete(void)
514 {
515 struct nvme_request req;
516 int test_data = 0xdeadbeef;
517 int buff_size = sizeof(int);
518 void *buff;
519 static struct spdk_nvme_cpl cpl;
520
521 memset(&req, 0, sizeof(req));
522 memset(&cpl, 0x5a, sizeof(cpl));
523
524 /* test without a user buffer provided */
525 req.user_cb_fn = (void *)dummy_cb;
526 nvme_user_copy_cmd_complete(&req, &cpl);
527 CU_ASSERT(memcmp(&ut_spdk_nvme_cpl, &cpl, sizeof(cpl)) == 0);
528
529 /* test with a user buffer provided */
530 req.user_buffer = malloc(buff_size);
531 SPDK_CU_ASSERT_FATAL(req.user_buffer != NULL);
532 memset(req.user_buffer, 0, buff_size);
533 req.payload_size = buff_size;
534 buff = spdk_dma_zmalloc(buff_size, 0x100, NULL);
535 SPDK_CU_ASSERT_FATAL(buff != NULL);
536 req.payload = NVME_PAYLOAD_CONTIG(buff, NULL);
537 memcpy(buff, &test_data, buff_size);
538 req.cmd.opc = SPDK_NVME_OPC_GET_LOG_PAGE;
539 req.pid = getpid();
540
541 /* zero out the test value set in the callback */
542 memset(&ut_spdk_nvme_cpl, 0, sizeof(ut_spdk_nvme_cpl));
543
544 nvme_user_copy_cmd_complete(&req, &cpl);
545 CU_ASSERT(memcmp(req.user_buffer, &test_data, buff_size) == 0);
546 CU_ASSERT(memcmp(&ut_spdk_nvme_cpl, &cpl, sizeof(cpl)) == 0);
547
548 /*
549 * Now test the same path as above but this time choose an opc
550 * that results in a different data transfer type.
551 */
552 memset(&ut_spdk_nvme_cpl, 0, sizeof(ut_spdk_nvme_cpl));
553 memset(req.user_buffer, 0, buff_size);
554 buff = spdk_dma_zmalloc(buff_size, 0x100, NULL);
555 SPDK_CU_ASSERT_FATAL(buff != NULL);
556 req.payload = NVME_PAYLOAD_CONTIG(buff, NULL);
557 memcpy(buff, &test_data, buff_size);
558 req.cmd.opc = SPDK_NVME_OPC_SET_FEATURES;
559 nvme_user_copy_cmd_complete(&req, &cpl);
560 CU_ASSERT(memcmp(req.user_buffer, &test_data, buff_size) != 0);
561 CU_ASSERT(memcmp(&ut_spdk_nvme_cpl, &cpl, sizeof(cpl)) == 0);
562
563 /* clean up */
564 free(req.user_buffer);
565 }
566
567 static void
568 test_nvme_allocate_request_null(void)
569 {
570 struct spdk_nvme_qpair qpair;
571 spdk_nvme_cmd_cb cb_fn = (spdk_nvme_cmd_cb)0x1234;
572 void *cb_arg = (void *)0x5678;
573 struct nvme_request *req = NULL;
574 struct nvme_request dummy_req;
575
576 STAILQ_INIT(&qpair.free_req);
577 STAILQ_INIT(&qpair.queued_req);
578
579 /*
580 * Put a dummy on the queue so we can make a request
581 * and confirm that what comes back is what we expect.
582 */
583 STAILQ_INSERT_HEAD(&qpair.free_req, &dummy_req, stailq);
584
585 req = nvme_allocate_request_null(&qpair, cb_fn, cb_arg);
586
587 /*
588 * Compare the req with the parmaters that we passed in
589 * as well as what the function is supposed to update.
590 */
591 SPDK_CU_ASSERT_FATAL(req != NULL);
592 CU_ASSERT(req->cb_fn == cb_fn);
593 CU_ASSERT(req->cb_arg == cb_arg);
594 CU_ASSERT(req->pid == getpid());
595 CU_ASSERT(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_CONTIG);
596 CU_ASSERT(req->payload.md == NULL);
597 CU_ASSERT(req->payload.contig_or_cb_arg == NULL);
598 }
599
600 static void
601 test_nvme_allocate_request(void)
602 {
603 struct spdk_nvme_qpair qpair;
604 struct nvme_payload payload;
605 uint32_t payload_struct_size = sizeof(payload);
606 spdk_nvme_cmd_cb cb_fn = (spdk_nvme_cmd_cb)0x1234;
607 void *cb_arg = (void *)0x6789;
608 struct nvme_request *req = NULL;
609 struct nvme_request dummy_req;
610
611 /* Fill the whole payload struct with a known pattern */
612 memset(&payload, 0x5a, payload_struct_size);
613 STAILQ_INIT(&qpair.free_req);
614 STAILQ_INIT(&qpair.queued_req);
615
616 /* Test trying to allocate a request when no requests are available */
617 req = nvme_allocate_request(&qpair, &payload, payload_struct_size,
618 cb_fn, cb_arg);
619 CU_ASSERT(req == NULL);
620
621 /* put a dummy on the queue, and then allocate one */
622 STAILQ_INSERT_HEAD(&qpair.free_req, &dummy_req, stailq);
623 req = nvme_allocate_request(&qpair, &payload, payload_struct_size,
624 cb_fn, cb_arg);
625
626 /* all the req elements should now match the passed in parameters */
627 SPDK_CU_ASSERT_FATAL(req != NULL);
628 CU_ASSERT(req->cb_fn == cb_fn);
629 CU_ASSERT(req->cb_arg == cb_arg);
630 CU_ASSERT(memcmp(&req->payload, &payload, payload_struct_size) == 0);
631 CU_ASSERT(req->payload_size == payload_struct_size);
632 CU_ASSERT(req->pid == getpid());
633 }
634
635 static void
636 test_nvme_free_request(void)
637 {
638 struct nvme_request match_req;
639 struct spdk_nvme_qpair qpair;
640 struct nvme_request *req;
641
642 /* put a req on the Q, take it off and compare */
643 memset(&match_req.cmd, 0x5a, sizeof(struct spdk_nvme_cmd));
644 match_req.qpair = &qpair;
645 /* the code under tests asserts this condition */
646 match_req.num_children = 0;
647 STAILQ_INIT(&qpair.free_req);
648
649 nvme_free_request(&match_req);
650 req = STAILQ_FIRST(&match_req.qpair->free_req);
651 CU_ASSERT(req == &match_req);
652 }
653
654 static void
655 test_nvme_allocate_request_user_copy(void)
656 {
657 struct spdk_nvme_qpair qpair;
658 spdk_nvme_cmd_cb cb_fn = (spdk_nvme_cmd_cb)0x12345;
659 void *cb_arg = (void *)0x12345;
660 bool host_to_controller = true;
661 struct nvme_request *req;
662 struct nvme_request dummy_req;
663 int test_data = 0xdeadbeef;
664 void *buffer = NULL;
665 uint32_t payload_size = sizeof(int);
666
667 STAILQ_INIT(&qpair.free_req);
668 STAILQ_INIT(&qpair.queued_req);
669
670 /* no buffer or valid payload size, early NULL return */
671 req = nvme_allocate_request_user_copy(&qpair, buffer, payload_size, cb_fn,
672 cb_arg, host_to_controller);
673 CU_ASSERT(req == NULL);
674
675 /* good buffer and valid payload size */
676 buffer = malloc(payload_size);
677 SPDK_CU_ASSERT_FATAL(buffer != NULL);
678 memcpy(buffer, &test_data, payload_size);
679
680 /* put a dummy on the queue */
681 STAILQ_INSERT_HEAD(&qpair.free_req, &dummy_req, stailq);
682
683 MOCK_CLEAR(spdk_malloc);
684 MOCK_CLEAR(spdk_zmalloc);
685 req = nvme_allocate_request_user_copy(&qpair, buffer, payload_size, cb_fn,
686 cb_arg, host_to_controller);
687 SPDK_CU_ASSERT_FATAL(req != NULL);
688 CU_ASSERT(req->user_cb_fn == cb_fn);
689 CU_ASSERT(req->user_cb_arg == cb_arg);
690 CU_ASSERT(req->user_buffer == buffer);
691 CU_ASSERT(req->cb_arg == req);
692 CU_ASSERT(memcmp(req->payload.contig_or_cb_arg, buffer, payload_size) == 0);
693 spdk_dma_free(req->payload.contig_or_cb_arg);
694
695 /* same thing but additional path coverage, no copy */
696 host_to_controller = false;
697 STAILQ_INSERT_HEAD(&qpair.free_req, &dummy_req, stailq);
698
699 req = nvme_allocate_request_user_copy(&qpair, buffer, payload_size, cb_fn,
700 cb_arg, host_to_controller);
701 SPDK_CU_ASSERT_FATAL(req != NULL);
702 CU_ASSERT(req->user_cb_fn == cb_fn);
703 CU_ASSERT(req->user_cb_arg == cb_arg);
704 CU_ASSERT(req->user_buffer == buffer);
705 CU_ASSERT(req->cb_arg == req);
706 CU_ASSERT(memcmp(req->payload.contig_or_cb_arg, buffer, payload_size) != 0);
707 spdk_dma_free(req->payload.contig_or_cb_arg);
708
709 /* good buffer and valid payload size but make spdk_dma_zmalloc fail */
710 /* set the mock pointer to NULL for spdk_dma_zmalloc */
711 MOCK_SET(spdk_dma_zmalloc, NULL);
712 req = nvme_allocate_request_user_copy(&qpair, buffer, payload_size, cb_fn,
713 cb_arg, host_to_controller);
714 CU_ASSERT(req == NULL);
715 free(buffer);
716 MOCK_CLEAR(spdk_dma_zmalloc);
717 }
718
719 static void
720 test_nvme_ctrlr_probe(void)
721 {
722 int rc = 0;
723 struct spdk_nvme_ctrlr ctrlr = {};
724 const struct spdk_nvme_transport_id trid = {};
725 struct spdk_nvme_probe_ctx probe_ctx = {};
726 void *devhandle = NULL;
727 void *cb_ctx = NULL;
728 struct spdk_nvme_ctrlr *dummy = NULL;
729
730 nvme_driver_init();
731
732 /* test when probe_cb returns false */
733
734 MOCK_SET(dummy_probe_cb, false);
735 spdk_nvme_probe_ctx_init(&probe_ctx, &trid, cb_ctx, dummy_probe_cb, NULL, NULL);
736 rc = nvme_ctrlr_probe(&trid, &probe_ctx, devhandle);
737 CU_ASSERT(rc == 1);
738
739 /* probe_cb returns true but we can't construct a ctrl */
740 MOCK_SET(dummy_probe_cb, true);
741 MOCK_SET(nvme_transport_ctrlr_construct, NULL);
742 spdk_nvme_probe_ctx_init(&probe_ctx, &trid, cb_ctx, dummy_probe_cb, NULL, NULL);
743 rc = nvme_ctrlr_probe(&trid, &probe_ctx, devhandle);
744 CU_ASSERT(rc == -1);
745
746 /* happy path */
747 MOCK_SET(dummy_probe_cb, true);
748 MOCK_SET(nvme_transport_ctrlr_construct, &ctrlr);
749 spdk_nvme_probe_ctx_init(&probe_ctx, &trid, cb_ctx, dummy_probe_cb, NULL, NULL);
750 rc = nvme_ctrlr_probe(&trid, &probe_ctx, devhandle);
751 CU_ASSERT(rc == 0);
752 dummy = TAILQ_FIRST(&probe_ctx.init_ctrlrs);
753 CU_ASSERT(dummy == ut_nvme_transport_ctrlr_construct);
754 TAILQ_REMOVE(&probe_ctx.init_ctrlrs, dummy, tailq);
755 MOCK_CLEAR_P(nvme_transport_ctrlr_construct);
756
757 free(g_spdk_nvme_driver);
758 }
759
760 static void
761 test_nvme_robust_mutex_init_shared(void)
762 {
763 pthread_mutex_t mtx;
764 int rc = 0;
765
766 /* test where both pthread calls succeed */
767 MOCK_SET(pthread_mutexattr_init, 0);
768 MOCK_SET(pthread_mutex_init, 0);
769 rc = nvme_robust_mutex_init_shared(&mtx);
770 CU_ASSERT(rc == 0);
771
772 /* test where we can't init attr's but init mutex works */
773 MOCK_SET(pthread_mutexattr_init, -1);
774 MOCK_SET(pthread_mutex_init, 0);
775 rc = nvme_robust_mutex_init_shared(&mtx);
776 /* for FreeBSD the only possible return value is 0 */
777 #ifndef __FreeBSD__
778 CU_ASSERT(rc != 0);
779 #else
780 CU_ASSERT(rc == 0);
781 #endif
782
783 /* test where we can init attr's but the mutex init fails */
784 MOCK_SET(pthread_mutexattr_init, 0);
785 MOCK_SET(pthread_mutex_init, -1);
786 rc = nvme_robust_mutex_init_shared(&mtx);
787 /* for FreeBSD the only possible return value is 0 */
788 #ifndef __FreeBSD__
789 CU_ASSERT(rc != 0);
790 #else
791 CU_ASSERT(rc == 0);
792 #endif
793 }
794
795 static void
796 test_opc_data_transfer(void)
797 {
798 enum spdk_nvme_data_transfer xfer;
799
800 xfer = spdk_nvme_opc_get_data_transfer(SPDK_NVME_OPC_FLUSH);
801 CU_ASSERT(xfer == SPDK_NVME_DATA_NONE);
802
803 xfer = spdk_nvme_opc_get_data_transfer(SPDK_NVME_OPC_WRITE);
804 CU_ASSERT(xfer == SPDK_NVME_DATA_HOST_TO_CONTROLLER);
805
806 xfer = spdk_nvme_opc_get_data_transfer(SPDK_NVME_OPC_READ);
807 CU_ASSERT(xfer == SPDK_NVME_DATA_CONTROLLER_TO_HOST);
808
809 xfer = spdk_nvme_opc_get_data_transfer(SPDK_NVME_OPC_GET_LOG_PAGE);
810 CU_ASSERT(xfer == SPDK_NVME_DATA_CONTROLLER_TO_HOST);
811 }
812
813 static void
814 test_trid_parse_and_compare(void)
815 {
816 struct spdk_nvme_transport_id trid1, trid2;
817 int ret;
818
819 /* set trid1 trid2 value to id parse */
820 ret = spdk_nvme_transport_id_parse(NULL, "trtype:PCIe traddr:0000:04:00.0");
821 CU_ASSERT(ret == -EINVAL);
822 memset(&trid1, 0, sizeof(trid1));
823 ret = spdk_nvme_transport_id_parse(&trid1, NULL);
824 CU_ASSERT(ret == -EINVAL);
825 ret = spdk_nvme_transport_id_parse(NULL, NULL);
826 CU_ASSERT(ret == -EINVAL);
827 memset(&trid1, 0, sizeof(trid1));
828 ret = spdk_nvme_transport_id_parse(&trid1, "trtype-PCIe traddr-0000-04-00.0");
829 CU_ASSERT(ret == -EINVAL);
830 memset(&trid1, 0, sizeof(trid1));
831 ret = spdk_nvme_transport_id_parse(&trid1, "trtype-PCIe traddr-0000-04-00.0-:");
832 CU_ASSERT(ret == -EINVAL);
833 memset(&trid1, 0, sizeof(trid1));
834 ret = spdk_nvme_transport_id_parse(&trid1, " \t\n:");
835 CU_ASSERT(ret == -EINVAL);
836 memset(&trid1, 0, sizeof(trid1));
837 CU_ASSERT(spdk_nvme_transport_id_parse(&trid1,
838 "trtype:rdma\n"
839 "adrfam:ipv4\n"
840 "traddr:192.168.100.8\n"
841 "trsvcid:4420\n"
842 "subnqn:nqn.2014-08.org.nvmexpress.discovery") == 0);
843 CU_ASSERT(trid1.trtype == SPDK_NVME_TRANSPORT_RDMA);
844 CU_ASSERT(trid1.adrfam == SPDK_NVMF_ADRFAM_IPV4);
845 CU_ASSERT(strcmp(trid1.traddr, "192.168.100.8") == 0);
846 CU_ASSERT(strcmp(trid1.trsvcid, "4420") == 0);
847 CU_ASSERT(strcmp(trid1.subnqn, "nqn.2014-08.org.nvmexpress.discovery") == 0);
848
849 memset(&trid2, 0, sizeof(trid2));
850 CU_ASSERT(spdk_nvme_transport_id_parse(&trid2, "trtype:PCIe traddr:0000:04:00.0") == 0);
851 CU_ASSERT(trid2.trtype == SPDK_NVME_TRANSPORT_PCIE);
852 CU_ASSERT(strcmp(trid2.traddr, "0000:04:00.0") == 0);
853
854 CU_ASSERT(spdk_nvme_transport_id_compare(&trid1, &trid2) != 0);
855
856 /* set trid1 trid2 and test id_compare */
857 memset_trid(&trid1, &trid2);
858 trid1.adrfam = SPDK_NVMF_ADRFAM_IPV6;
859 trid2.adrfam = SPDK_NVMF_ADRFAM_IPV4;
860 ret = spdk_nvme_transport_id_compare(&trid1, &trid2);
861 CU_ASSERT(ret > 0);
862
863 memset_trid(&trid1, &trid2);
864 snprintf(trid1.traddr, sizeof(trid1.traddr), "192.168.100.8");
865 snprintf(trid2.traddr, sizeof(trid2.traddr), "192.168.100.9");
866 ret = spdk_nvme_transport_id_compare(&trid1, &trid2);
867 CU_ASSERT(ret < 0);
868
869 memset_trid(&trid1, &trid2);
870 snprintf(trid1.trsvcid, sizeof(trid1.trsvcid), "4420");
871 snprintf(trid2.trsvcid, sizeof(trid2.trsvcid), "4421");
872 ret = spdk_nvme_transport_id_compare(&trid1, &trid2);
873 CU_ASSERT(ret < 0);
874
875 memset_trid(&trid1, &trid2);
876 snprintf(trid1.subnqn, sizeof(trid1.subnqn), "subnqn:nqn.2016-08.org.nvmexpress.discovery");
877 snprintf(trid2.subnqn, sizeof(trid2.subnqn), "subnqn:nqn.2017-08.org.nvmexpress.discovery");
878 ret = spdk_nvme_transport_id_compare(&trid1, &trid2);
879 CU_ASSERT(ret < 0);
880
881 memset_trid(&trid1, &trid2);
882 snprintf(trid1.subnqn, sizeof(trid1.subnqn), "subnqn:nqn.2016-08.org.nvmexpress.discovery");
883 snprintf(trid2.subnqn, sizeof(trid2.subnqn), "subnqn:nqn.2016-08.org.nvmexpress.discovery");
884 ret = spdk_nvme_transport_id_compare(&trid1, &trid2);
885 CU_ASSERT(ret == 0);
886
887 memset_trid(&trid1, &trid2);
888 snprintf(trid1.subnqn, sizeof(trid1.subnqn), "subnqn:nqn.2016-08.org.nvmexpress.discovery");
889 snprintf(trid2.subnqn, sizeof(trid2.subnqn), "subnqn:nqn.2016-08.org.Nvmexpress.discovery");
890 ret = spdk_nvme_transport_id_compare(&trid1, &trid2);
891 CU_ASSERT(ret > 0);
892
893 memset_trid(&trid1, &trid2);
894 ret = spdk_nvme_transport_id_compare(&trid1, &trid2);
895 CU_ASSERT(ret == 0);
896
897 /* Compare PCI addresses via spdk_pci_addr_compare (rather than as strings) */
898 memset_trid(&trid1, &trid2);
899 CU_ASSERT(spdk_nvme_transport_id_parse(&trid1, "trtype:PCIe traddr:0000:04:00.0") == 0);
900 CU_ASSERT(spdk_nvme_transport_id_parse(&trid2, "trtype:PCIe traddr:04:00.0") == 0);
901 CU_ASSERT(spdk_nvme_transport_id_compare(&trid1, &trid2) == 0);
902
903 memset_trid(&trid1, &trid2);
904 CU_ASSERT(spdk_nvme_transport_id_parse(&trid1, "trtype:PCIe traddr:0000:05:00.0") == 0);
905 CU_ASSERT(spdk_nvme_transport_id_parse(&trid2, "trtype:PCIe traddr:04:00.0") == 0);
906 CU_ASSERT(spdk_nvme_transport_id_compare(&trid1, &trid2) > 0);
907
908 memset_trid(&trid1, &trid2);
909 CU_ASSERT(spdk_nvme_transport_id_parse(&trid1, "trtype:PCIe traddr:0000:04:00.0") == 0);
910 CU_ASSERT(spdk_nvme_transport_id_parse(&trid2, "trtype:PCIe traddr:05:00.0") == 0);
911 CU_ASSERT(spdk_nvme_transport_id_compare(&trid1, &trid2) < 0);
912
913 memset_trid(&trid1, &trid2);
914 CU_ASSERT(spdk_nvme_transport_id_parse(&trid1, "trtype=PCIe traddr=0000:04:00.0") == 0);
915 CU_ASSERT(spdk_nvme_transport_id_parse(&trid2, "trtype=PCIe traddr=05:00.0") == 0);
916 CU_ASSERT(spdk_nvme_transport_id_compare(&trid1, &trid2) < 0);
917 }
918
919 static void
920 test_spdk_nvme_transport_id_parse_trtype(void)
921 {
922
923 enum spdk_nvme_transport_type *trtype;
924 enum spdk_nvme_transport_type sct;
925 char *str;
926
927 trtype = NULL;
928 str = "unit_test";
929
930 /* test function returned value when trtype is NULL but str not NULL */
931 CU_ASSERT(spdk_nvme_transport_id_parse_trtype(trtype, str) == (-EINVAL));
932
933 /* test function returned value when str is NULL but trtype not NULL */
934 trtype = &sct;
935 str = NULL;
936 CU_ASSERT(spdk_nvme_transport_id_parse_trtype(trtype, str) == (-EINVAL));
937
938 /* test function returned value when str and strtype not NULL, but str value
939 * not "PCIe" or "RDMA" */
940 str = "unit_test";
941 CU_ASSERT(spdk_nvme_transport_id_parse_trtype(trtype, str) == (-ENOENT));
942
943 /* test trtype value when use function "strcasecmp" to compare str and "PCIe",not case-sensitive */
944 str = "PCIe";
945 spdk_nvme_transport_id_parse_trtype(trtype, str);
946 CU_ASSERT((*trtype) == SPDK_NVME_TRANSPORT_PCIE);
947
948 str = "pciE";
949 spdk_nvme_transport_id_parse_trtype(trtype, str);
950 CU_ASSERT((*trtype) == SPDK_NVME_TRANSPORT_PCIE);
951
952 /* test trtype value when use function "strcasecmp" to compare str and "RDMA",not case-sensitive */
953 str = "RDMA";
954 spdk_nvme_transport_id_parse_trtype(trtype, str);
955 CU_ASSERT((*trtype) == SPDK_NVME_TRANSPORT_RDMA);
956
957 str = "rdma";
958 spdk_nvme_transport_id_parse_trtype(trtype, str);
959 CU_ASSERT((*trtype) == SPDK_NVME_TRANSPORT_RDMA);
960
961 /* test trtype value when use function "strcasecmp" to compare str and "FC",not case-sensitive */
962 str = "FC";
963 spdk_nvme_transport_id_parse_trtype(trtype, str);
964 CU_ASSERT((*trtype) == SPDK_NVME_TRANSPORT_FC);
965
966 str = "fc";
967 spdk_nvme_transport_id_parse_trtype(trtype, str);
968 CU_ASSERT((*trtype) == SPDK_NVME_TRANSPORT_FC);
969
970 /* test trtype value when use function "strcasecmp" to compare str and "TCP",not case-sensitive */
971 str = "TCP";
972 spdk_nvme_transport_id_parse_trtype(trtype, str);
973 CU_ASSERT((*trtype) == SPDK_NVME_TRANSPORT_TCP);
974
975 str = "tcp";
976 spdk_nvme_transport_id_parse_trtype(trtype, str);
977 CU_ASSERT((*trtype) == SPDK_NVME_TRANSPORT_TCP);
978 }
979
980 static void
981 test_spdk_nvme_transport_id_parse_adrfam(void)
982 {
983
984 enum spdk_nvmf_adrfam *adrfam;
985 enum spdk_nvmf_adrfam sct;
986 char *str;
987
988 adrfam = NULL;
989 str = "unit_test";
990
991 /* test function returned value when adrfam is NULL but str not NULL */
992 CU_ASSERT(spdk_nvme_transport_id_parse_adrfam(adrfam, str) == (-EINVAL));
993
994 /* test function returned value when str is NULL but adrfam not NULL */
995 adrfam = &sct;
996 str = NULL;
997 CU_ASSERT(spdk_nvme_transport_id_parse_adrfam(adrfam, str) == (-EINVAL));
998
999 /* test function returned value when str and adrfam not NULL, but str value
1000 * not "IPv4" or "IPv6" or "IB" or "FC" */
1001 str = "unit_test";
1002 CU_ASSERT(spdk_nvme_transport_id_parse_adrfam(adrfam, str) == (-ENOENT));
1003
1004 /* test adrfam value when use function "strcasecmp" to compare str and "IPv4",not case-sensitive */
1005 str = "IPv4";
1006 spdk_nvme_transport_id_parse_adrfam(adrfam, str);
1007 CU_ASSERT((*adrfam) == SPDK_NVMF_ADRFAM_IPV4);
1008
1009 str = "ipV4";
1010 spdk_nvme_transport_id_parse_adrfam(adrfam, str);
1011 CU_ASSERT((*adrfam) == SPDK_NVMF_ADRFAM_IPV4);
1012
1013 /* test adrfam value when use function "strcasecmp" to compare str and "IPv6",not case-sensitive */
1014 str = "IPv6";
1015 spdk_nvme_transport_id_parse_adrfam(adrfam, str);
1016 CU_ASSERT((*adrfam) == SPDK_NVMF_ADRFAM_IPV6);
1017
1018 str = "ipV6";
1019 spdk_nvme_transport_id_parse_adrfam(adrfam, str);
1020 CU_ASSERT((*adrfam) == SPDK_NVMF_ADRFAM_IPV6);
1021
1022 /* test adrfam value when use function "strcasecmp" to compare str and "IB",not case-sensitive */
1023 str = "IB";
1024 spdk_nvme_transport_id_parse_adrfam(adrfam, str);
1025 CU_ASSERT((*adrfam) == SPDK_NVMF_ADRFAM_IB);
1026
1027 str = "ib";
1028 spdk_nvme_transport_id_parse_adrfam(adrfam, str);
1029 CU_ASSERT((*adrfam) == SPDK_NVMF_ADRFAM_IB);
1030
1031 /* test adrfam value when use function "strcasecmp" to compare str and "FC",not case-sensitive */
1032 str = "FC";
1033 spdk_nvme_transport_id_parse_adrfam(adrfam, str);
1034 CU_ASSERT((*adrfam) == SPDK_NVMF_ADRFAM_FC);
1035
1036 str = "fc";
1037 spdk_nvme_transport_id_parse_adrfam(adrfam, str);
1038 CU_ASSERT((*adrfam) == SPDK_NVMF_ADRFAM_FC);
1039
1040 }
1041
1042 static void
1043 test_trid_trtype_str(void)
1044 {
1045 const char *s;
1046
1047 s = spdk_nvme_transport_id_trtype_str(-5);
1048 CU_ASSERT(s == NULL);
1049
1050 s = spdk_nvme_transport_id_trtype_str(SPDK_NVME_TRANSPORT_PCIE);
1051 SPDK_CU_ASSERT_FATAL(s != NULL);
1052 CU_ASSERT(strcmp(s, "PCIe") == 0);
1053
1054 s = spdk_nvme_transport_id_trtype_str(SPDK_NVME_TRANSPORT_RDMA);
1055 SPDK_CU_ASSERT_FATAL(s != NULL);
1056 CU_ASSERT(strcmp(s, "RDMA") == 0);
1057
1058 s = spdk_nvme_transport_id_trtype_str(SPDK_NVME_TRANSPORT_FC);
1059 SPDK_CU_ASSERT_FATAL(s != NULL);
1060 CU_ASSERT(strcmp(s, "FC") == 0);
1061
1062 s = spdk_nvme_transport_id_trtype_str(SPDK_NVME_TRANSPORT_TCP);
1063 SPDK_CU_ASSERT_FATAL(s != NULL);
1064 CU_ASSERT(strcmp(s, "TCP") == 0);
1065 }
1066
1067 static void
1068 test_trid_adrfam_str(void)
1069 {
1070 const char *s;
1071
1072 s = spdk_nvme_transport_id_adrfam_str(-5);
1073 CU_ASSERT(s == NULL);
1074
1075 s = spdk_nvme_transport_id_adrfam_str(SPDK_NVMF_ADRFAM_IPV4);
1076 SPDK_CU_ASSERT_FATAL(s != NULL);
1077 CU_ASSERT(strcmp(s, "IPv4") == 0);
1078
1079 s = spdk_nvme_transport_id_adrfam_str(SPDK_NVMF_ADRFAM_IPV6);
1080 SPDK_CU_ASSERT_FATAL(s != NULL);
1081 CU_ASSERT(strcmp(s, "IPv6") == 0);
1082
1083 s = spdk_nvme_transport_id_adrfam_str(SPDK_NVMF_ADRFAM_IB);
1084 SPDK_CU_ASSERT_FATAL(s != NULL);
1085 CU_ASSERT(strcmp(s, "IB") == 0);
1086
1087 s = spdk_nvme_transport_id_adrfam_str(SPDK_NVMF_ADRFAM_FC);
1088 SPDK_CU_ASSERT_FATAL(s != NULL);
1089 CU_ASSERT(strcmp(s, "FC") == 0);
1090 }
1091
1092 /* stub callback used by the test_nvme_request_check_timeout */
1093 static bool ut_timeout_cb_call = false;
1094 static void
1095 dummy_timeout_cb(void *cb_arg, struct spdk_nvme_ctrlr *ctrlr,
1096 struct spdk_nvme_qpair *qpair, uint16_t cid)
1097 {
1098 ut_timeout_cb_call = true;
1099 }
1100
1101 static void
1102 test_nvme_request_check_timeout(void)
1103 {
1104 int rc;
1105 struct spdk_nvme_qpair qpair;
1106 struct nvme_request req;
1107 struct spdk_nvme_ctrlr_process active_proc;
1108 uint16_t cid = 0;
1109 uint64_t now_tick = 0;
1110
1111 memset(&qpair, 0x0, sizeof(qpair));
1112 memset(&req, 0x0, sizeof(req));
1113 memset(&active_proc, 0x0, sizeof(active_proc));
1114 req.qpair = &qpair;
1115 active_proc.timeout_cb_fn = dummy_timeout_cb;
1116
1117 /* if have called timeout_cb_fn then return directly */
1118 req.timed_out = true;
1119 rc = nvme_request_check_timeout(&req, cid, &active_proc, now_tick);
1120 CU_ASSERT(rc == 0);
1121 CU_ASSERT(ut_timeout_cb_call == false);
1122
1123 /* if timeout isn't enabled then return directly */
1124 req.timed_out = false;
1125 req.submit_tick = 0;
1126 rc = nvme_request_check_timeout(&req, cid, &active_proc, now_tick);
1127 CU_ASSERT(rc == 0);
1128 CU_ASSERT(ut_timeout_cb_call == false);
1129
1130 /* req->pid isn't right then return directly */
1131 req.submit_tick = 1;
1132 req.pid = g_spdk_nvme_pid + 1;
1133 rc = nvme_request_check_timeout(&req, cid, &active_proc, now_tick);
1134 CU_ASSERT(rc == 0);
1135 CU_ASSERT(ut_timeout_cb_call == false);
1136
1137 /* AER command has no timeout */
1138 req.pid = g_spdk_nvme_pid;
1139 req.cmd.opc = SPDK_NVME_OPC_ASYNC_EVENT_REQUEST;
1140 rc = nvme_request_check_timeout(&req, cid, &active_proc, now_tick);
1141 CU_ASSERT(rc == 0);
1142 CU_ASSERT(ut_timeout_cb_call == false);
1143
1144 /* time isn't out */
1145 qpair.id = 1;
1146 rc = nvme_request_check_timeout(&req, cid, &active_proc, now_tick);
1147 CU_ASSERT(rc == 1);
1148 CU_ASSERT(ut_timeout_cb_call == false);
1149
1150 now_tick = 2;
1151 rc = nvme_request_check_timeout(&req, cid, &active_proc, now_tick);
1152 CU_ASSERT(req.timed_out == true);
1153 CU_ASSERT(ut_timeout_cb_call == true);
1154 CU_ASSERT(rc == 0);
1155 }
1156
1157 struct nvme_completion_poll_status g_status;
1158 uint64_t completion_delay, timeout_in_secs;
1159 int
1160 spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions)
1161 {
1162 spdk_delay_us(completion_delay * spdk_get_ticks_hz());
1163
1164 g_status.done = completion_delay < timeout_in_secs ? true : false;
1165
1166 return 0;
1167 }
1168
1169 static void
1170 test_nvme_wait_for_completion(void)
1171 {
1172 struct spdk_nvme_qpair qpair;
1173 int rc = 0;
1174
1175 memset(&qpair, 0, sizeof(qpair));
1176 memset(&g_status, 0, sizeof(g_status));
1177
1178 /* completion timeout */
1179 completion_delay = 2;
1180 timeout_in_secs = 1;
1181 g_status.done = true;
1182 rc = spdk_nvme_wait_for_completion_timeout(&qpair, &g_status, timeout_in_secs);
1183 CU_ASSERT(g_status.done == false);
1184 CU_ASSERT(rc == -EIO);
1185
1186 /* complete in time */
1187 completion_delay = 1;
1188 timeout_in_secs = 2;
1189 rc = spdk_nvme_wait_for_completion_timeout(&qpair, &g_status, timeout_in_secs);
1190 CU_ASSERT(g_status.done == true);
1191 CU_ASSERT(rc == 0);
1192 }
1193
1194 int main(int argc, char **argv)
1195 {
1196 CU_pSuite suite = NULL;
1197 unsigned int num_failures;
1198
1199 if (CU_initialize_registry() != CUE_SUCCESS) {
1200 return CU_get_error();
1201 }
1202
1203 suite = CU_add_suite("nvme", NULL, NULL);
1204 if (suite == NULL) {
1205 CU_cleanup_registry();
1206 return CU_get_error();
1207 }
1208
1209 if (
1210 CU_add_test(suite, "test_opc_data_transfer",
1211 test_opc_data_transfer) == NULL ||
1212 CU_add_test(suite, "test_spdk_nvme_transport_id_parse_trtype",
1213 test_spdk_nvme_transport_id_parse_trtype) == NULL ||
1214 CU_add_test(suite, "test_spdk_nvme_transport_id_parse_adrfam",
1215 test_spdk_nvme_transport_id_parse_adrfam) == NULL ||
1216 CU_add_test(suite, "test_trid_parse_and_compare",
1217 test_trid_parse_and_compare) == NULL ||
1218 CU_add_test(suite, "test_trid_trtype_str",
1219 test_trid_trtype_str) == NULL ||
1220 CU_add_test(suite, "test_trid_adrfam_str",
1221 test_trid_adrfam_str) == NULL ||
1222 CU_add_test(suite, "test_nvme_ctrlr_probe",
1223 test_nvme_ctrlr_probe) == NULL ||
1224 CU_add_test(suite, "test_spdk_nvme_probe",
1225 test_spdk_nvme_probe) == NULL ||
1226 CU_add_test(suite, "test_spdk_nvme_connect",
1227 test_spdk_nvme_connect) == NULL ||
1228 CU_add_test(suite, "test_nvme_init_controllers",
1229 test_nvme_init_controllers) == NULL ||
1230 CU_add_test(suite, "test_nvme_driver_init",
1231 test_nvme_driver_init) == NULL ||
1232 CU_add_test(suite, "test_spdk_nvme_detach",
1233 test_spdk_nvme_detach) == NULL ||
1234 CU_add_test(suite, "test_nvme_completion_poll_cb",
1235 test_nvme_completion_poll_cb) == NULL ||
1236 CU_add_test(suite, "test_nvme_user_copy_cmd_complete",
1237 test_nvme_user_copy_cmd_complete) == NULL ||
1238 CU_add_test(suite, "test_nvme_allocate_request_null",
1239 test_nvme_allocate_request_null) == NULL ||
1240 CU_add_test(suite, "test_nvme_allocate_request",
1241 test_nvme_allocate_request) == NULL ||
1242 CU_add_test(suite, "test_nvme_free_request",
1243 test_nvme_free_request) == NULL ||
1244 CU_add_test(suite, "test_nvme_allocate_request_user_copy",
1245 test_nvme_allocate_request_user_copy) == NULL ||
1246 CU_add_test(suite, "test_nvme_robust_mutex_init_shared",
1247 test_nvme_robust_mutex_init_shared) == NULL ||
1248 CU_add_test(suite, "test_nvme_request_check_timeout",
1249 test_nvme_request_check_timeout) == NULL ||
1250 CU_add_test(suite, "test_nvme_wait_for_completion",
1251 test_nvme_wait_for_completion) == NULL
1252 ) {
1253 CU_cleanup_registry();
1254 return CU_get_error();
1255 }
1256
1257 CU_basic_set_mode(CU_BRM_VERBOSE);
1258 CU_basic_run_tests();
1259 num_failures = CU_get_number_of_failures();
1260 CU_cleanup_registry();
1261 return num_failures;
1262 }