Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2021 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : : #include "spdk_internal/cunit.h"
9 : : #include "nvme/nvme_pcie_common.c"
10 : : #include "common/lib/test_env.c"
11 : :
12 : 3 : SPDK_LOG_REGISTER_COMPONENT(nvme)
13 : :
14 : : pid_t g_spdk_nvme_pid;
15 : 0 : DEFINE_STUB(nvme_ctrlr_get_process, struct spdk_nvme_ctrlr_process *,
16 : : (struct spdk_nvme_ctrlr *ctrlr, pid_t pid), NULL);
17 : :
18 : 36 : DEFINE_STUB(nvme_ctrlr_submit_admin_request, int, (struct spdk_nvme_ctrlr *ctrlr,
19 : : struct nvme_request *req), 0);
20 : :
21 : 0 : DEFINE_STUB_V(nvme_completion_poll_cb, (void *arg, const struct spdk_nvme_cpl *cpl));
22 : :
23 : 0 : DEFINE_STUB(nvme_wait_for_completion, int,
24 : : (struct spdk_nvme_qpair *qpair,
25 : : struct nvme_completion_poll_status *status), 0);
26 : :
27 [ # # ]: 0 : DEFINE_STUB(nvme_completion_is_retry, bool, (const struct spdk_nvme_cpl *cpl), false);
28 : :
29 : 0 : DEFINE_STUB_V(nvme_ctrlr_process_async_event, (struct spdk_nvme_ctrlr *ctrlr,
30 : : const struct spdk_nvme_cpl *cpl));
31 : :
32 : 0 : DEFINE_STUB_V(spdk_nvme_qpair_print_command, (struct spdk_nvme_qpair *qpair,
33 : : struct spdk_nvme_cmd *cmd));
34 : :
35 : 0 : DEFINE_STUB_V(spdk_nvme_qpair_print_completion, (struct spdk_nvme_qpair *qpair,
36 : : struct spdk_nvme_cpl *cpl));
37 : :
38 : 12 : DEFINE_STUB_V(nvme_qpair_deinit, (struct spdk_nvme_qpair *qpair));
39 : :
40 : 0 : DEFINE_STUB(nvme_ctrlr_get_current_process, struct spdk_nvme_ctrlr_process *,
41 : : (struct spdk_nvme_ctrlr *ctrlr), NULL);
42 : :
43 : 0 : DEFINE_STUB(spdk_nvme_qpair_process_completions, int32_t,
44 : : (struct spdk_nvme_qpair *qpair, uint32_t max_completions), 0);
45 : :
46 : 0 : DEFINE_STUB(nvme_request_check_timeout, int, (struct nvme_request *req, uint16_t cid,
47 : : struct spdk_nvme_ctrlr_process *active_proc, uint64_t now_tick), 0);
48 : 0 : DEFINE_STUB(spdk_strerror, const char *, (int errnum), NULL);
49 : :
50 : 0 : DEFINE_STUB_V(nvme_ctrlr_disable, (struct spdk_nvme_ctrlr *ctrlr));
51 : :
52 : 0 : DEFINE_STUB(nvme_ctrlr_disable_poll, int, (struct spdk_nvme_ctrlr *ctrlr), 0);
53 : :
54 : 0 : DEFINE_STUB_V(nvme_transport_ctrlr_disconnect_qpair_done, (struct spdk_nvme_qpair *qpair));
55 : :
56 : : int
57 : 3 : nvme_qpair_init(struct spdk_nvme_qpair *qpair, uint16_t id,
58 : : struct spdk_nvme_ctrlr *ctrlr,
59 : : enum spdk_nvme_qprio qprio,
60 : : uint32_t num_requests, bool async)
61 : : {
62 : 3 : qpair->id = id;
63 : 3 : qpair->qprio = qprio;
64 : 3 : qpair->ctrlr = ctrlr;
65 : 3 : qpair->async = async;
66 : :
67 : 3 : return 0;
68 : : }
69 : :
70 : : static void
71 : 3 : test_nvme_pcie_ctrlr_alloc_cmb(void)
72 : : {
73 : :
74 : 3 : struct nvme_pcie_ctrlr pctrlr = {};
75 : 3 : void *vaddr = NULL;
76 : : uint64_t alignment;
77 : 3 : uint64_t phys_addr_var;
78 : : uint64_t size;
79 : :
80 : 3 : size = 64;
81 : 3 : alignment = 4096;
82 : 3 : pctrlr.cmb.mem_register_addr = NULL;
83 : 3 : pctrlr.cmb.bar_va = (void *)0xF9000000;
84 : 3 : pctrlr.cmb.bar_pa = 0xF8000000;
85 : 3 : pctrlr.cmb.current_offset = 0x10;
86 : 3 : pctrlr.cmb.size = 1 << 16;
87 : :
88 : : /* Allocate CMB */
89 : 3 : vaddr = nvme_pcie_ctrlr_alloc_cmb(&pctrlr.ctrlr, size, alignment, &phys_addr_var);
90 : 3 : CU_ASSERT(vaddr == (void *)0xF9001000);
91 : 3 : CU_ASSERT(phys_addr_var == 0xF8001000);
92 : 3 : CU_ASSERT(pctrlr.cmb.current_offset == 4160);
93 : :
94 : : /* CMB size overload */
95 : 3 : size = 0x1000000;
96 : :
97 : 3 : vaddr = nvme_pcie_ctrlr_alloc_cmb(&pctrlr.ctrlr, size, alignment, &phys_addr_var);
98 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(vaddr == NULL);
99 : :
100 : : /* BAR is mapped for data */
101 : 3 : pctrlr.cmb.mem_register_addr = (void *)0xF0000000;
102 : :
103 : 3 : vaddr = nvme_pcie_ctrlr_alloc_cmb(&pctrlr.ctrlr, size, alignment, &phys_addr_var);
104 : 3 : CU_ASSERT(vaddr == NULL);
105 : 3 : }
106 : :
107 : : static void
108 : 3 : test_nvme_pcie_qpair_construct_destroy(void)
109 : : {
110 : 3 : struct spdk_nvme_io_qpair_opts opts = {};
111 : 3 : struct nvme_pcie_ctrlr pctrlr = {};
112 : 3 : struct spdk_nvme_cpl cpl[2] = {};
113 : 3 : struct nvme_pcie_qpair *pqpair = NULL;
114 : 3 : size_t page_align = sysconf(_SC_PAGESIZE);
115 : : uint64_t cmb_offset;
116 : : int rc;
117 : :
118 : 3 : opts.sq.paddr = 0xDEADBEEF;
119 : 3 : opts.cq.paddr = 0xDBADBEEF;
120 : 3 : opts.sq.vaddr = (void *)0xDCADBEEF;
121 : 3 : opts.cq.vaddr = cpl;
122 : :
123 : 3 : pctrlr.ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
124 : 3 : pctrlr.ctrlr.opts.transport_retry_count = 1;
125 : 3 : pctrlr.cmb.mem_register_addr = NULL;
126 : 3 : pctrlr.cmb.bar_va = (void *)0xF9000000;
127 : 3 : pctrlr.cmb.bar_pa = 0xF8000000;
128 : 3 : pctrlr.cmb.current_offset = 0x10;
129 : 3 : cmb_offset = pctrlr.cmb.current_offset;
130 : : /* Make sure that CMB size is big enough and includes page alignment */
131 : 3 : pctrlr.cmb.size = (1 << 16) + page_align;
132 : 3 : pctrlr.doorbell_base = (void *)0xF7000000;
133 : 3 : pctrlr.doorbell_stride_u32 = 1;
134 : :
135 : : /* Allocate memory for destroying. */
136 : 3 : pqpair = spdk_zmalloc(sizeof(*pqpair), 64, NULL,
137 : : SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_SHARE);
138 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(pqpair != NULL);
139 : 3 : pqpair->qpair.ctrlr = &pctrlr.ctrlr;
140 : 3 : pqpair->num_entries = 2;
141 : 3 : pqpair->qpair.id = 1;
142 : 3 : pqpair->cpl = cpl;
143 : :
144 : : /* Enable submission queue in controller memory buffer. */
145 : 3 : pctrlr.ctrlr.opts.use_cmb_sqs = true;
146 : :
147 : 3 : rc = nvme_pcie_qpair_construct(&pqpair->qpair, &opts);
148 : 3 : CU_ASSERT(rc == 0);
149 : 3 : CU_ASSERT(pqpair->sq_vaddr == (void *)0xDCADBEEF);
150 : 3 : CU_ASSERT(pqpair->cq_vaddr == cpl);
151 : 3 : CU_ASSERT(pqpair->retry_count == 1);
152 : 3 : CU_ASSERT(pqpair->max_completions_cap == 1);
153 [ - + ]: 3 : CU_ASSERT(pqpair->sq_in_cmb == true);
154 [ + - + - ]: 3 : CU_ASSERT(pqpair->cmd != NULL && pqpair->cmd != (void *)0xDCADBEEF);
155 : 3 : CU_ASSERT(pqpair->cmd_bus_addr == (((pctrlr.cmb.bar_pa + cmb_offset) + page_align - 1) & ~
156 : : (page_align - 1)));
157 : 3 : CU_ASSERT(pqpair->sq_tdbl == (void *)0xF7000008);
158 : 3 : CU_ASSERT(pqpair->cq_hdbl == (void *)0xF700000C);
159 : 3 : CU_ASSERT(pqpair->flags.phase = 1);
160 : 3 : CU_ASSERT(pqpair->tr != NULL);
161 : 3 : CU_ASSERT(pqpair->tr == TAILQ_FIRST(&pqpair->free_tr));
162 : 3 : CU_ASSERT(pctrlr.cmb.current_offset == (uintptr_t)pqpair->cmd + (pqpair->num_entries * sizeof(
163 : : struct spdk_nvme_cmd)) - (uintptr_t)pctrlr.cmb.bar_va);
164 : 3 : cmb_offset = pctrlr.cmb.current_offset;
165 : 3 : nvme_pcie_qpair_destroy(&pqpair->qpair);
166 : :
167 : : /* Disable submission queue in controller memory buffer. */
168 : 3 : pctrlr.ctrlr.opts.use_cmb_sqs = false;
169 : 3 : pqpair = spdk_zmalloc(sizeof(*pqpair), 64, NULL,
170 : : SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_SHARE);
171 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(pqpair != NULL);
172 : 3 : pqpair->qpair.ctrlr = &pctrlr.ctrlr;
173 : 3 : pqpair->num_entries = 2;
174 : 3 : pqpair->qpair.id = 1;
175 : 3 : pqpair->cpl = cpl;
176 : :
177 : 3 : rc = nvme_pcie_qpair_construct(&pqpair->qpair, &opts);
178 : 3 : CU_ASSERT(rc == 0);
179 : 3 : CU_ASSERT(pqpair->sq_vaddr == (void *)0xDCADBEEF);
180 : 3 : CU_ASSERT(pqpair->cq_vaddr == cpl);
181 : 3 : CU_ASSERT(pqpair->retry_count == 1);
182 : 3 : CU_ASSERT(pqpair->max_completions_cap == 1);
183 [ - + ]: 3 : CU_ASSERT(pqpair->sq_in_cmb == false);
184 : 3 : CU_ASSERT(pqpair->cmd == (void *)0xDCADBEEF);
185 : 3 : CU_ASSERT(pqpair->cmd_bus_addr == 0xDEADBEEF);
186 : 3 : CU_ASSERT(pqpair->sq_tdbl == (void *)0xF7000008);
187 : 3 : CU_ASSERT(pqpair->cq_hdbl == (void *)0xF700000C);
188 : 3 : CU_ASSERT(pqpair->flags.phase = 1);
189 : 3 : CU_ASSERT(pqpair->tr != NULL);
190 : 3 : CU_ASSERT(pqpair->tr == TAILQ_FIRST(&pqpair->free_tr));
191 : 3 : nvme_pcie_qpair_destroy(&pqpair->qpair);
192 : :
193 : : /* Disable submission queue in controller memory buffer, sq_vaddr and cq_vaddr invalid. */
194 : 3 : pctrlr.ctrlr.opts.use_cmb_sqs = false;
195 : 3 : pqpair = spdk_zmalloc(sizeof(*pqpair), 64, NULL,
196 : : SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_SHARE);
197 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(pqpair != NULL);
198 : 3 : pqpair->qpair.ctrlr = &pctrlr.ctrlr;
199 : 3 : pqpair->num_entries = 2;
200 : 3 : pqpair->qpair.id = 1;
201 : 3 : pqpair->cpl = cpl;
202 : 3 : MOCK_SET(spdk_vtophys, 0xDAADBEEF);
203 : :
204 : 3 : rc = nvme_pcie_qpair_construct(&pqpair->qpair, NULL);
205 : 3 : CU_ASSERT(rc == 0);
206 : 3 : CU_ASSERT(pqpair->retry_count == 1);
207 : 3 : CU_ASSERT(pqpair->max_completions_cap == 1);
208 [ + - + - ]: 3 : CU_ASSERT(pqpair->cmd != NULL && pqpair->cmd != (void *)0xDCADBEEF);
209 [ - + ]: 3 : CU_ASSERT(pqpair->sq_in_cmb == false);
210 : 3 : CU_ASSERT(pqpair->cmd_bus_addr == 0xDAADBEEF);
211 : 3 : CU_ASSERT(pqpair->sq_tdbl == (void *)0xF7000008);
212 : 3 : CU_ASSERT(pqpair->cq_hdbl == (void *)0xF700000c);
213 : 3 : CU_ASSERT(pqpair->flags.phase = 1);
214 : 3 : CU_ASSERT(pqpair->tr != NULL);
215 : 3 : CU_ASSERT(pqpair->tr == TAILQ_FIRST(&pqpair->free_tr));
216 : 3 : nvme_pcie_qpair_destroy(&pqpair->qpair);
217 : 3 : MOCK_CLEAR(spdk_vtophys);
218 : 3 : }
219 : :
220 : : static void
221 : 3 : test_nvme_pcie_ctrlr_cmd_create_delete_io_queue(void)
222 : : {
223 : 3 : struct spdk_nvme_ctrlr ctrlr = {};
224 : 3 : struct nvme_pcie_qpair pqpair = {};
225 : 3 : struct spdk_nvme_qpair adminq = {};
226 : 3 : struct nvme_request req = {};
227 : : int rc;
228 : :
229 : 3 : ctrlr.adminq = &adminq;
230 : 3 : STAILQ_INIT(&ctrlr.adminq->free_req);
231 [ + - ]: 3 : STAILQ_INSERT_HEAD(&ctrlr.adminq->free_req, &req, stailq);
232 : 3 : pqpair.qpair.id = 1;
233 : 3 : pqpair.num_entries = 1;
234 : 3 : pqpair.cpl_bus_addr = 0xDEADBEEF;
235 : 3 : pqpair.cmd_bus_addr = 0xDDADBEEF;
236 : 3 : pqpair.qpair.qprio = SPDK_NVME_QPRIO_HIGH;
237 : :
238 : 3 : rc = nvme_pcie_ctrlr_cmd_create_io_cq(&ctrlr, &pqpair.qpair, NULL, NULL);
239 : 3 : CU_ASSERT(rc == 0);
240 : 3 : CU_ASSERT(req.cmd.opc == SPDK_NVME_OPC_CREATE_IO_CQ);
241 : 3 : CU_ASSERT(req.cmd.cdw10_bits.create_io_q.qid == 1);
242 : 3 : CU_ASSERT(req.cmd.cdw10_bits.create_io_q.qsize == 0);
243 : 3 : CU_ASSERT(req.cmd.cdw11_bits.create_io_cq.pc == 1);
244 : 3 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0xDEADBEEF);
245 : 3 : CU_ASSERT(STAILQ_EMPTY(&ctrlr.adminq->free_req));
246 : :
247 [ - + ]: 3 : memset(&req, 0, sizeof(req));
248 [ + - ]: 3 : STAILQ_INSERT_HEAD(&ctrlr.adminq->free_req, &req, stailq);
249 : :
250 : 3 : rc = nvme_pcie_ctrlr_cmd_create_io_sq(&ctrlr, &pqpair.qpair, NULL, NULL);
251 : 3 : CU_ASSERT(rc == 0);
252 : 3 : CU_ASSERT(req.cmd.opc == SPDK_NVME_OPC_CREATE_IO_SQ);
253 : 3 : CU_ASSERT(req.cmd.cdw10_bits.create_io_q.qid == 1);
254 : 3 : CU_ASSERT(req.cmd.cdw10_bits.create_io_q.qsize == 0);
255 : 3 : CU_ASSERT(req.cmd.cdw11_bits.create_io_sq.pc == 1);
256 : 3 : CU_ASSERT(req.cmd.cdw11_bits.create_io_sq.qprio == SPDK_NVME_QPRIO_HIGH);
257 : 3 : CU_ASSERT(req.cmd.cdw11_bits.create_io_sq.cqid = 1);
258 : 3 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0xDDADBEEF);
259 : 3 : CU_ASSERT(STAILQ_EMPTY(&ctrlr.adminq->free_req));
260 : :
261 : : /* No free request available */
262 : 3 : rc = nvme_pcie_ctrlr_cmd_create_io_cq(&ctrlr, &pqpair.qpair, NULL, NULL);
263 : 3 : CU_ASSERT(rc == -ENOMEM);
264 : :
265 : 3 : rc = nvme_pcie_ctrlr_cmd_create_io_sq(&ctrlr, &pqpair.qpair, NULL, NULL);
266 : 3 : CU_ASSERT(rc == -ENOMEM);
267 : :
268 : : /* Delete cq or sq */
269 [ - + ]: 3 : memset(&req, 0, sizeof(req));
270 [ + - ]: 3 : STAILQ_INSERT_HEAD(&ctrlr.adminq->free_req, &req, stailq);
271 : :
272 : 3 : rc = nvme_pcie_ctrlr_cmd_delete_io_cq(&ctrlr, &pqpair.qpair, NULL, NULL);
273 : 3 : CU_ASSERT(rc == 0);
274 : 3 : CU_ASSERT(req.cmd.opc == SPDK_NVME_OPC_DELETE_IO_CQ);
275 : 3 : CU_ASSERT(req.cmd.cdw10_bits.delete_io_q.qid == 1);
276 : 3 : CU_ASSERT(STAILQ_EMPTY(&ctrlr.adminq->free_req));
277 : :
278 [ - + ]: 3 : memset(&req, 0, sizeof(req));
279 [ + - ]: 3 : STAILQ_INSERT_HEAD(&ctrlr.adminq->free_req, &req, stailq);
280 : :
281 : 3 : rc = nvme_pcie_ctrlr_cmd_delete_io_sq(&ctrlr, &pqpair.qpair, NULL, NULL);
282 : 3 : CU_ASSERT(rc == 0);
283 : 3 : CU_ASSERT(req.cmd.opc == SPDK_NVME_OPC_DELETE_IO_SQ);
284 : 3 : CU_ASSERT(req.cmd.cdw10_bits.delete_io_q.qid == 1);
285 : 3 : CU_ASSERT(STAILQ_EMPTY(&ctrlr.adminq->free_req));
286 : :
287 : : /* No free request available */
288 : 3 : rc = nvme_pcie_ctrlr_cmd_delete_io_cq(&ctrlr, &pqpair.qpair, NULL, NULL);
289 : 3 : CU_ASSERT(rc == -ENOMEM);
290 : :
291 : 3 : rc = nvme_pcie_ctrlr_cmd_delete_io_sq(&ctrlr, &pqpair.qpair, NULL, NULL);
292 : 3 : CU_ASSERT(rc == -ENOMEM);
293 : 3 : }
294 : :
295 : : static void
296 : 3 : test_nvme_pcie_ctrlr_connect_qpair(void)
297 : : {
298 : 3 : struct nvme_pcie_ctrlr pctrlr = {};
299 : 3 : struct nvme_pcie_qpair pqpair = {};
300 : 3 : struct spdk_nvme_transport_poll_group poll_group = {};
301 : 3 : struct spdk_nvme_cpl cpl = {};
302 : 3 : struct spdk_nvme_qpair adminq = {};
303 : 3 : struct nvme_request req[3] = {};
304 : : int rc;
305 : :
306 : 3 : pqpair.cpl = &cpl;
307 : 3 : pqpair.num_entries = 1;
308 : 3 : pqpair.qpair.ctrlr = &pctrlr.ctrlr;
309 : 3 : pqpair.qpair.id = 1;
310 : 3 : pqpair.num_entries = 1;
311 : 3 : pqpair.cpl_bus_addr = 0xDEADBEEF;
312 : 3 : pqpair.cmd_bus_addr = 0xDDADBEEF;
313 : 3 : pqpair.qpair.qprio = SPDK_NVME_QPRIO_HIGH;
314 : 3 : pqpair.stat = NULL;
315 : 3 : pqpair.qpair.poll_group = &poll_group;
316 : 3 : pctrlr.ctrlr.page_size = 4096;
317 : :
318 : : /* Shadow doorbell available */
319 : 3 : pctrlr.doorbell_stride_u32 = 1;
320 : 3 : pctrlr.ctrlr.shadow_doorbell = spdk_zmalloc(pctrlr.ctrlr.page_size, pctrlr.ctrlr.page_size,
321 : : NULL, SPDK_ENV_LCORE_ID_ANY,
322 : : SPDK_MALLOC_DMA | SPDK_MALLOC_SHARE);
323 : 3 : pctrlr.ctrlr.eventidx = spdk_zmalloc(pctrlr.ctrlr.page_size, pctrlr.ctrlr.page_size,
324 : : NULL, SPDK_ENV_LCORE_ID_ANY,
325 : : SPDK_MALLOC_DMA | SPDK_MALLOC_SHARE);
326 : 3 : pctrlr.ctrlr.adminq = &adminq;
327 : 3 : STAILQ_INIT(&pctrlr.ctrlr.adminq->free_req);
328 [ + + ]: 9 : for (int i = 0; i < 2; i++) {
329 : 6 : STAILQ_INSERT_TAIL(&pctrlr.ctrlr.adminq->free_req, &req[i], stailq);
330 : : }
331 : :
332 : 3 : rc = nvme_pcie_ctrlr_connect_qpair(&pctrlr.ctrlr, &pqpair.qpair);
333 : 3 : CU_ASSERT(rc == 0);
334 : 3 : CU_ASSERT(req[0].cmd.opc == SPDK_NVME_OPC_CREATE_IO_CQ);
335 : 3 : CU_ASSERT(req[0].cmd.cdw10_bits.create_io_q.qid == 1);
336 : 3 : CU_ASSERT(req[0].cmd.cdw10_bits.create_io_q.qsize == 0);
337 : 3 : CU_ASSERT(req[0].cmd.cdw11_bits.create_io_cq.pc == 1);
338 : 3 : CU_ASSERT(req[0].cmd.dptr.prp.prp1 == 0xDEADBEEF);
339 : :
340 : : /* Complete the first request, which triggers the second. */
341 : 3 : req[0].cb_fn(req[0].cb_arg, &cpl);
342 : 3 : CU_ASSERT(req[1].cmd.opc == SPDK_NVME_OPC_CREATE_IO_SQ);
343 : 3 : CU_ASSERT(req[1].cmd.cdw10_bits.create_io_q.qid == 1);
344 : 3 : CU_ASSERT(req[1].cmd.cdw10_bits.create_io_q.qsize == 0);
345 : 3 : CU_ASSERT(req[1].cmd.cdw11_bits.create_io_sq.pc == 1);
346 : 3 : CU_ASSERT(req[1].cmd.cdw11_bits.create_io_sq.qprio == SPDK_NVME_QPRIO_HIGH);
347 : 3 : CU_ASSERT(req[1].cmd.cdw11_bits.create_io_sq.cqid = 1);
348 : 3 : CU_ASSERT(req[1].cmd.dptr.prp.prp1 == 0xDDADBEEF);
349 : :
350 : 3 : pqpair.qpair.state = NVME_QPAIR_CONNECTING;
351 : : /* Complete the second request */
352 : 3 : req[1].cb_fn(req[1].cb_arg, &cpl);
353 : 3 : CU_ASSERT(pqpair.pcie_state == NVME_PCIE_QPAIR_READY);
354 : : /* State is still CONNECTING until the thread is polled again. */
355 : 3 : CU_ASSERT(pqpair.qpair.state == NVME_QPAIR_CONNECTING);
356 : :
357 : : /* doorbell stride and qid are 1 */
358 : 3 : CU_ASSERT(pqpair.shadow_doorbell.sq_tdbl == pctrlr.ctrlr.shadow_doorbell + 2);
359 : 3 : CU_ASSERT(pqpair.shadow_doorbell.cq_hdbl == pctrlr.ctrlr.shadow_doorbell + 3);
360 : 3 : CU_ASSERT(pqpair.shadow_doorbell.sq_eventidx == pctrlr.ctrlr.eventidx + 2);
361 : 3 : CU_ASSERT(pqpair.shadow_doorbell.cq_eventidx == pctrlr.ctrlr.eventidx + 3);
362 : 3 : CU_ASSERT(pqpair.flags.has_shadow_doorbell == 1);
363 : 3 : CU_ASSERT(STAILQ_EMPTY(&pctrlr.ctrlr.adminq->free_req));
364 : :
365 : 3 : spdk_free(pctrlr.ctrlr.shadow_doorbell);
366 : 3 : spdk_free(pctrlr.ctrlr.eventidx);
367 : 3 : pctrlr.ctrlr.shadow_doorbell = NULL;
368 : 3 : pctrlr.ctrlr.eventidx = NULL;
369 : :
370 : : /* Shadow doorbell 0 */
371 [ - + ]: 3 : memset(req, 0, sizeof(struct nvme_request) * 2);
372 [ - + ]: 3 : memset(&pqpair, 0, sizeof(pqpair));
373 : 3 : pqpair.cpl = &cpl;
374 : 3 : pqpair.qpair.ctrlr = &pctrlr.ctrlr;
375 : 3 : pqpair.qpair.id = 1;
376 : 3 : pqpair.num_entries = 1;
377 : 3 : pqpair.cpl_bus_addr = 0xDEADBEEF;
378 : 3 : pqpair.cmd_bus_addr = 0xDDADBEEF;
379 : 3 : pqpair.qpair.qprio = SPDK_NVME_QPRIO_HIGH;
380 : 3 : pqpair.stat = NULL;
381 : 3 : pqpair.qpair.poll_group = &poll_group;
382 [ + + ]: 9 : for (int i = 0; i < 2; i++) {
383 : 6 : STAILQ_INSERT_TAIL(&pctrlr.ctrlr.adminq->free_req, &req[i], stailq);
384 : : }
385 : :
386 : 3 : rc = nvme_pcie_ctrlr_connect_qpair(&pctrlr.ctrlr, &pqpair.qpair);
387 : 3 : CU_ASSERT(rc == 0);
388 : 3 : CU_ASSERT(req[0].cmd.opc == SPDK_NVME_OPC_CREATE_IO_CQ);
389 : 3 : CU_ASSERT(req[0].cmd.cdw10_bits.create_io_q.qid == 1);
390 : 3 : CU_ASSERT(req[0].cmd.cdw10_bits.create_io_q.qsize == 0);
391 : 3 : CU_ASSERT(req[0].cmd.cdw11_bits.create_io_cq.pc == 1);
392 : 3 : CU_ASSERT(req[0].cmd.dptr.prp.prp1 == 0xDEADBEEF);
393 : :
394 : : /* Complete the first request, which triggers the second. */
395 : 3 : req[0].cb_fn(req[0].cb_arg, &cpl);
396 : 3 : CU_ASSERT(req[1].cmd.opc == SPDK_NVME_OPC_CREATE_IO_SQ);
397 : 3 : CU_ASSERT(req[1].cmd.cdw10_bits.create_io_q.qid == 1);
398 : 3 : CU_ASSERT(req[1].cmd.cdw10_bits.create_io_q.qsize == 0);
399 : 3 : CU_ASSERT(req[1].cmd.cdw11_bits.create_io_sq.pc == 1);
400 : 3 : CU_ASSERT(req[1].cmd.cdw11_bits.create_io_sq.qprio == SPDK_NVME_QPRIO_HIGH);
401 : 3 : CU_ASSERT(req[1].cmd.cdw11_bits.create_io_sq.cqid = 1);
402 : 3 : CU_ASSERT(req[1].cmd.dptr.prp.prp1 == 0xDDADBEEF);
403 : :
404 : 3 : pqpair.qpair.state = NVME_QPAIR_CONNECTING;
405 : : /* Complete the second request */
406 : 3 : req[1].cb_fn(req[1].cb_arg, &cpl);
407 : 3 : CU_ASSERT(pqpair.pcie_state == NVME_PCIE_QPAIR_READY);
408 : : /* State is still CONNECTING until the thread is polled again. */
409 : 3 : CU_ASSERT(pqpair.qpair.state == NVME_QPAIR_CONNECTING);
410 : :
411 : 3 : CU_ASSERT(pqpair.shadow_doorbell.sq_tdbl == NULL);
412 : 3 : CU_ASSERT(pqpair.shadow_doorbell.sq_eventidx == NULL);
413 : 3 : CU_ASSERT(pqpair.flags.has_shadow_doorbell == 0);
414 : 3 : CU_ASSERT(STAILQ_EMPTY(&pctrlr.ctrlr.adminq->free_req));
415 : :
416 : : /* Completion error for CQ */
417 [ - + ]: 3 : memset(req, 0, sizeof(struct nvme_request) * 2);
418 [ - + ]: 3 : memset(&pqpair, 0, sizeof(pqpair));
419 : 3 : pqpair.cpl = &cpl;
420 : 3 : pqpair.qpair.ctrlr = &pctrlr.ctrlr;
421 : 3 : pqpair.qpair.id = 1;
422 : 3 : pqpair.num_entries = 1;
423 : 3 : pqpair.cpl_bus_addr = 0xDEADBEEF;
424 : 3 : pqpair.cmd_bus_addr = 0xDDADBEEF;
425 : 3 : pqpair.qpair.qprio = SPDK_NVME_QPRIO_HIGH;
426 : 3 : pqpair.stat = NULL;
427 : 3 : pqpair.qpair.poll_group = &poll_group;
428 : : /* Modify cpl such that CQ fails */
429 : 3 : pqpair.cpl->status.sc = SPDK_NVME_SC_INVALID_FIELD;
430 : 3 : pqpair.cpl->status.sct = SPDK_NVME_SCT_GENERIC;
431 [ + + ]: 9 : for (int i = 0; i < 2; i++) {
432 : 6 : STAILQ_INSERT_TAIL(&pctrlr.ctrlr.adminq->free_req, &req[i], stailq);
433 : : }
434 : :
435 : 3 : rc = nvme_pcie_ctrlr_connect_qpair(&pctrlr.ctrlr, &pqpair.qpair);
436 : 3 : CU_ASSERT(rc == 0);
437 : 3 : CU_ASSERT(req[0].cmd.opc == SPDK_NVME_OPC_CREATE_IO_CQ);
438 : :
439 : : /* Request to complete callback in async operation */
440 : 3 : req[0].cb_fn(req[0].cb_arg, &cpl);
441 : 3 : CU_ASSERT(pqpair.pcie_state == NVME_PCIE_QPAIR_FAILED);
442 : 3 : CU_ASSERT(pqpair.qpair.state == NVME_QPAIR_DISCONNECTED);
443 : :
444 : : /* Remove unused request */
445 [ + - ]: 3 : STAILQ_REMOVE_HEAD(&pctrlr.ctrlr.adminq->free_req, stailq);
446 : 3 : CU_ASSERT(STAILQ_EMPTY(&pctrlr.ctrlr.adminq->free_req));
447 : :
448 : : /* Completion error for SQ */
449 [ - + ]: 3 : memset(req, 0, sizeof(struct nvme_request) * 3);
450 [ - + ]: 3 : memset(&pqpair, 0, sizeof(pqpair));
451 : 3 : pqpair.cpl = &cpl;
452 : 3 : pqpair.qpair.ctrlr = &pctrlr.ctrlr;
453 : 3 : pqpair.qpair.id = 1;
454 : 3 : pqpair.num_entries = 1;
455 : 3 : pqpair.cpl_bus_addr = 0xDEADBEEF;
456 : 3 : pqpair.cmd_bus_addr = 0xDDADBEEF;
457 : 3 : pqpair.qpair.qprio = SPDK_NVME_QPRIO_HIGH;
458 : 3 : pqpair.stat = NULL;
459 : 3 : pqpair.cpl->status.sc = SPDK_NVME_SC_SUCCESS;
460 : 3 : pqpair.cpl->status.sct = SPDK_NVME_SCT_GENERIC;
461 : 3 : pqpair.qpair.poll_group = &poll_group;
462 [ + + ]: 12 : for (int i = 0; i < 3; i++) {
463 : 9 : STAILQ_INSERT_TAIL(&pctrlr.ctrlr.adminq->free_req, &req[i], stailq);
464 : : }
465 : :
466 : 3 : rc = nvme_pcie_ctrlr_connect_qpair(&pctrlr.ctrlr, &pqpair.qpair);
467 : 3 : CU_ASSERT(rc == 0);
468 : 3 : CU_ASSERT(req[0].cmd.opc == SPDK_NVME_OPC_CREATE_IO_CQ);
469 : 3 : CU_ASSERT(pqpair.pcie_state == NVME_PCIE_QPAIR_WAIT_FOR_CQ);
470 : :
471 : : /* Request to complete cq callback in async operation */
472 : 3 : req[0].cb_fn(req[0].cb_arg, &cpl);
473 : 3 : CU_ASSERT(req[1].cmd.opc == SPDK_NVME_OPC_CREATE_IO_SQ);
474 : 3 : CU_ASSERT(pqpair.pcie_state == NVME_PCIE_QPAIR_WAIT_FOR_SQ);
475 : : /* Modify cpl such that SQ fails */
476 : 3 : pqpair.cpl->status.sc = SPDK_NVME_SC_INVALID_FIELD;
477 : 3 : pqpair.cpl->status.sct = SPDK_NVME_SCT_GENERIC;
478 : :
479 : : /* Request to complete sq callback in async operation */
480 : 3 : req[1].cb_fn(req[1].cb_arg, &cpl);
481 : 3 : CU_ASSERT(req[2].cmd.opc == SPDK_NVME_OPC_DELETE_IO_CQ);
482 : : /* Modify cpl back to success */
483 : 3 : pqpair.cpl->status.sc = SPDK_NVME_SC_SUCCESS;
484 : 3 : pqpair.cpl->status.sct = SPDK_NVME_SCT_GENERIC;
485 : 3 : req[2].cb_fn(req[2].cb_arg, &cpl);
486 : 3 : CU_ASSERT(pqpair.pcie_state == NVME_PCIE_QPAIR_FAILED);
487 : 3 : CU_ASSERT(pqpair.qpair.state == NVME_QPAIR_DISCONNECTED);
488 : : /* No need to remove unused requests here */
489 : 3 : CU_ASSERT(STAILQ_EMPTY(&pctrlr.ctrlr.adminq->free_req));
490 : :
491 : :
492 : : /* No available request used */
493 [ - + ]: 3 : memset(req, 0, sizeof(struct nvme_request) * 2);
494 [ - + ]: 3 : memset(&pqpair, 0, sizeof(pqpair));
495 : 3 : pqpair.cpl = &cpl;
496 : 3 : pqpair.qpair.ctrlr = &pctrlr.ctrlr;
497 : 3 : pqpair.qpair.id = 1;
498 : 3 : pqpair.num_entries = 1;
499 : 3 : pqpair.cpl_bus_addr = 0xDEADBEEF;
500 : 3 : pqpair.cmd_bus_addr = 0xDDADBEEF;
501 : 3 : pqpair.qpair.qprio = SPDK_NVME_QPRIO_HIGH;
502 : 3 : pqpair.stat = NULL;
503 : 3 : pqpair.qpair.poll_group = &poll_group;
504 : :
505 : 3 : rc = nvme_pcie_ctrlr_connect_qpair(&pctrlr.ctrlr, &pqpair.qpair);
506 : 3 : CU_ASSERT(rc == -ENOMEM);
507 : 3 : }
508 : :
509 : : static void
510 : 3 : test_nvme_pcie_ctrlr_construct_admin_qpair(void)
511 : : {
512 : 3 : struct nvme_pcie_ctrlr pctrlr = {};
513 : 3 : struct nvme_pcie_qpair *pqpair = NULL;
514 : 3 : int rc = 0;
515 : :
516 : 3 : pctrlr.ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
517 : 3 : pctrlr.ctrlr.opts.admin_queue_size = 32;
518 : 3 : pctrlr.doorbell_base = (void *)0xF7000000;
519 : 3 : pctrlr.doorbell_stride_u32 = 1;
520 : 3 : pctrlr.ctrlr.flags = 0;
521 : 3 : pctrlr.ctrlr.free_io_qids = NULL;
522 : 3 : pctrlr.ctrlr.is_resetting = false;
523 : 3 : pctrlr.ctrlr.is_failed = false;
524 : 3 : pctrlr.ctrlr.is_destructed = false;
525 : 3 : pctrlr.ctrlr.outstanding_aborts = 0;
526 : 3 : pctrlr.ctrlr.ana_log_page = NULL;
527 : 3 : pctrlr.ctrlr.ana_log_page_size = 0;
528 : :
529 : 3 : TAILQ_INIT(&pctrlr.ctrlr.active_io_qpairs);
530 : 3 : STAILQ_INIT(&pctrlr.ctrlr.queued_aborts);
531 : 3 : TAILQ_INIT(&pctrlr.ctrlr.active_procs);
532 : :
533 : 3 : rc = nvme_pcie_ctrlr_construct_admin_qpair(&pctrlr.ctrlr, 32);
534 : 3 : CU_ASSERT(rc == 0);
535 : 3 : pqpair = nvme_pcie_qpair(pctrlr.ctrlr.adminq);
536 [ - + ]: 3 : SPDK_CU_ASSERT_FATAL(pqpair != NULL);
537 : 3 : CU_ASSERT(pqpair->num_entries == 32);
538 : 3 : CU_ASSERT(pqpair->flags.delay_cmd_submit == 0);
539 : 3 : CU_ASSERT(pqpair->qpair.id == 0);
540 : 3 : CU_ASSERT(pqpair->qpair.qprio == SPDK_NVME_QPRIO_URGENT);
541 : 3 : CU_ASSERT(pqpair->qpair.ctrlr == &pctrlr.ctrlr);
542 : 3 : CU_ASSERT(pqpair->stat != NULL);
543 : :
544 : 3 : rc = nvme_pcie_qpair_destroy(pctrlr.ctrlr.adminq);
545 : 3 : CU_ASSERT(rc == 0);
546 : 3 : }
547 : :
548 : : static void
549 : 3 : test_nvme_pcie_poll_group_get_stats(void)
550 : : {
551 : 3 : int rc = 0;
552 : 3 : struct nvme_pcie_poll_group *pgroup = NULL;
553 : 3 : struct spdk_nvme_transport_poll_group *tgroup = NULL;
554 : 3 : struct spdk_nvme_transport_poll_group_stat *tgroup_stat = NULL;
555 : :
556 : 3 : tgroup = nvme_pcie_poll_group_create();
557 : 3 : CU_ASSERT(tgroup != NULL);
558 : 3 : pgroup = SPDK_CONTAINEROF(tgroup, struct nvme_pcie_poll_group, group);
559 : 3 : CU_ASSERT(pgroup != NULL);
560 : :
561 : : /* Invalid group pointer, expect fail and return -EINVAL */
562 : 3 : rc = nvme_pcie_poll_group_get_stats(NULL, &tgroup_stat);
563 : 3 : CU_ASSERT(rc == -EINVAL);
564 : 3 : CU_ASSERT(tgroup_stat == NULL);
565 : :
566 : : /* Invalid stats, expect fail and return -EINVAL */
567 : 3 : rc = nvme_pcie_poll_group_get_stats(tgroup, NULL);
568 : 3 : CU_ASSERT(rc == -EINVAL);
569 : :
570 : : /* Get state success */
571 : 3 : rc = nvme_pcie_poll_group_get_stats(tgroup, &tgroup_stat);
572 : 3 : CU_ASSERT(rc == 0);
573 : 3 : CU_ASSERT(tgroup_stat != NULL);
574 : 3 : CU_ASSERT(tgroup_stat->trtype == SPDK_NVME_TRANSPORT_PCIE);
575 [ - + - + ]: 3 : CU_ASSERT(memcmp(&tgroup_stat->pcie, &pgroup->stats, sizeof(struct spdk_nvme_pcie_stat)) == 0);
576 : :
577 : 3 : nvme_pcie_poll_group_free_stats(tgroup, tgroup_stat);
578 : 3 : rc = nvme_pcie_poll_group_destroy(tgroup);
579 : 3 : CU_ASSERT(rc == 0);
580 : 3 : }
581 : :
582 : : int
583 : 3 : main(int argc, char **argv)
584 : : {
585 : 3 : CU_pSuite suite = NULL;
586 : : unsigned int num_failures;
587 : :
588 : 3 : CU_initialize_registry();
589 : :
590 : 3 : suite = CU_add_suite("nvme_pcie_common", NULL, NULL);
591 : 3 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_alloc_cmb);
592 : 3 : CU_ADD_TEST(suite, test_nvme_pcie_qpair_construct_destroy);
593 : 3 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_cmd_create_delete_io_queue);
594 : 3 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_connect_qpair);
595 : 3 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_construct_admin_qpair);
596 : 3 : CU_ADD_TEST(suite, test_nvme_pcie_poll_group_get_stats);
597 : :
598 : 3 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
599 : 3 : CU_cleanup_registry();
600 : 3 : return num_failures;
601 : : }
|