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