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