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