Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : :
9 : : #include "spdk_internal/cunit.h"
10 : :
11 : : #define UNIT_TEST_NO_VTOPHYS
12 : :
13 : : #include "nvme/nvme_pcie.c"
14 : : #include "nvme/nvme_pcie_common.c"
15 : : #include "common/lib/nvme/common_stubs.h"
16 : :
17 : : pid_t g_spdk_nvme_pid;
18 : 12 : DEFINE_STUB(spdk_mem_register, int, (void *vaddr, size_t len), 0);
19 : 6 : DEFINE_STUB(spdk_mem_unregister, int, (void *vaddr, size_t len), 0);
20 : :
21 : 0 : DEFINE_STUB(nvme_get_quirks, uint64_t, (const struct spdk_pci_id *id), 0);
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 : 0 : DEFINE_STUB_V(nvme_completion_poll_cb, (void *arg, const struct spdk_nvme_cpl *cpl));
27 : :
28 : 0 : DEFINE_STUB(nvme_ctrlr_submit_admin_request, int, (struct spdk_nvme_ctrlr *ctrlr,
29 : : struct nvme_request *req), 0);
30 : :
31 : 0 : DEFINE_STUB(nvme_ctrlr_proc_get_devhandle, struct spdk_pci_device *,
32 : : (struct spdk_nvme_ctrlr *ctrlr), NULL);
33 : 12 : DEFINE_STUB(spdk_pci_device_unmap_bar, int, (struct spdk_pci_device *dev, uint32_t bar, void *addr),
34 : : 0);
35 : 0 : DEFINE_STUB(spdk_pci_device_attach, int, (struct spdk_pci_driver *driver, spdk_pci_enum_cb enum_cb,
36 : : void *enum_ctx, struct spdk_pci_addr *pci_address), 0);
37 : 0 : DEFINE_STUB(spdk_pci_device_claim, int, (struct spdk_pci_device *dev), 0);
38 : 0 : DEFINE_STUB_V(spdk_pci_device_unclaim, (struct spdk_pci_device *dev));
39 : 0 : DEFINE_STUB_V(spdk_pci_device_detach, (struct spdk_pci_device *device));
40 : 0 : DEFINE_STUB(spdk_pci_device_cfg_write16, int, (struct spdk_pci_device *dev, uint16_t value,
41 : : uint32_t offset), 0);
42 : 0 : DEFINE_STUB(spdk_pci_device_cfg_read16, int, (struct spdk_pci_device *dev, uint16_t *value,
43 : : uint32_t offset), 0);
44 : 0 : DEFINE_STUB(spdk_pci_device_get_id, struct spdk_pci_id, (struct spdk_pci_device *dev), {0});
45 : 0 : DEFINE_STUB(spdk_pci_event_listen, int, (void), 0);
46 : 0 : DEFINE_STUB(spdk_pci_register_error_handler, int, (spdk_pci_error_handler sighandler, void *ctx),
47 : : 0);
48 : 0 : DEFINE_STUB_V(spdk_pci_unregister_error_handler, (spdk_pci_error_handler sighandler));
49 : 0 : DEFINE_STUB(spdk_pci_enumerate, int,
50 : : (struct spdk_pci_driver *driver, spdk_pci_enum_cb enum_cb, void *enum_ctx),
51 : : -1);
52 : :
53 : 6 : SPDK_LOG_REGISTER_COMPONENT(nvme)
54 : :
55 : : struct dev_mem_resource {
56 : : uint64_t phys_addr;
57 : : uint64_t len;
58 : : void *addr;
59 : : };
60 : :
61 : : struct nvme_pcie_ut_bdev_io {
62 : : struct iovec iovs[NVME_MAX_SGL_DESCRIPTORS];
63 : : int iovpos;
64 : : };
65 : :
66 : : struct nvme_driver *g_spdk_nvme_driver = NULL;
67 : :
68 : : int
69 : 12 : spdk_pci_device_map_bar(struct spdk_pci_device *dev, uint32_t bar,
70 : : void **mapped_addr, uint64_t *phys_addr, uint64_t *size)
71 : : {
72 : 12 : struct dev_mem_resource *dev_mem_res = (void *)dev;
73 : :
74 : 12 : *mapped_addr = dev_mem_res->addr;
75 : 12 : *phys_addr = dev_mem_res->phys_addr;
76 : 12 : *size = dev_mem_res->len;
77 : :
78 : 12 : return 0;
79 : : }
80 : :
81 : : void
82 : 18 : nvme_ctrlr_fail(struct spdk_nvme_ctrlr *ctrlr, bool hot_remove)
83 : : {
84 : 18 : CU_ASSERT(ctrlr != NULL);
85 [ + - ]: 18 : if (hot_remove) {
86 : 18 : ctrlr->is_removed = true;
87 : : }
88 : :
89 : 18 : ctrlr->is_failed = true;
90 : 18 : }
91 : :
92 : : static uint64_t g_vtophys_size = 0;
93 : :
94 : : DEFINE_RETURN_MOCK(spdk_vtophys, uint64_t);
95 : : uint64_t
96 : 12330 : spdk_vtophys(const void *buf, uint64_t *size)
97 : : {
98 [ + + + + ]: 12330 : if (size && g_vtophys_size > 0) {
99 : 60 : *size = g_vtophys_size;
100 : : }
101 : :
102 [ + + + + ]: 12330 : HANDLE_RETURN_MOCK(spdk_vtophys);
103 : :
104 : 12270 : return (uintptr_t)buf;
105 : : }
106 : :
107 : 0 : DEFINE_STUB(spdk_pci_device_get_addr, struct spdk_pci_addr, (struct spdk_pci_device *dev), {});
108 : 0 : DEFINE_STUB(nvme_ctrlr_probe, int, (const struct spdk_nvme_transport_id *trid,
109 : : struct spdk_nvme_probe_ctx *probe_ctx, void *devhandle), 0);
110 [ - + ]: 18 : DEFINE_STUB(spdk_pci_device_is_removed, bool, (struct spdk_pci_device *dev), false);
111 : 6 : DEFINE_STUB(nvme_get_ctrlr_by_trid_unsafe, struct spdk_nvme_ctrlr *,
112 : : (const struct spdk_nvme_transport_id *trid), NULL);
113 : 0 : DEFINE_STUB(spdk_nvme_ctrlr_get_regs_csts, union spdk_nvme_csts_register,
114 : : (struct spdk_nvme_ctrlr *ctrlr), {});
115 : 0 : DEFINE_STUB(nvme_ctrlr_get_process, struct spdk_nvme_ctrlr_process *,
116 : : (struct spdk_nvme_ctrlr *ctrlr, pid_t pid), NULL);
117 [ # # ]: 0 : DEFINE_STUB(nvme_completion_is_retry, bool, (const struct spdk_nvme_cpl *cpl), false);
118 : 0 : DEFINE_STUB_V(nvme_ctrlr_process_async_event, (struct spdk_nvme_ctrlr *ctrlr,
119 : : const struct spdk_nvme_cpl *cpl));
120 : 0 : DEFINE_STUB_V(spdk_nvme_qpair_print_command, (struct spdk_nvme_qpair *qpair,
121 : : struct spdk_nvme_cmd *cmd));
122 : 0 : DEFINE_STUB_V(spdk_nvme_qpair_print_completion, (struct spdk_nvme_qpair *qpair,
123 : : struct spdk_nvme_cpl *cpl));
124 : :
125 : : static void
126 : 126 : prp_list_prep(struct nvme_tracker *tr, struct nvme_request *req, uint32_t *prp_index)
127 : : {
128 [ - + ]: 126 : memset(req, 0, sizeof(*req));
129 [ - + ]: 126 : memset(tr, 0, sizeof(*tr));
130 : 126 : tr->req = req;
131 : 126 : tr->prp_sgl_bus_addr = 0xDEADBEEF;
132 [ + + ]: 126 : if (prp_index) {
133 : 102 : *prp_index = 0;
134 : : }
135 : 126 : }
136 : :
137 : : static void
138 : 6 : test_prp_list_append(void)
139 : : {
140 : 5 : struct nvme_request req;
141 : 5 : struct nvme_tracker tr;
142 : 6 : struct spdk_nvme_ctrlr ctrlr = {};
143 : 5 : uint32_t prp_index;
144 : :
145 : 6 : ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
146 : : /* Non-DWORD-aligned buffer (invalid) */
147 : 6 : prp_list_prep(&tr, &req, &prp_index);
148 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100001, 0x1000,
149 : : 0x1000) == -EFAULT);
150 : :
151 : : /* 512-byte buffer, 4K aligned */
152 : 6 : prp_list_prep(&tr, &req, &prp_index);
153 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100000, 0x200, 0x1000) == 0);
154 : 6 : CU_ASSERT(prp_index == 1);
155 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100000);
156 : :
157 : : /* 512-byte buffer, non-4K-aligned */
158 : 6 : prp_list_prep(&tr, &req, &prp_index);
159 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x108000, 0x200, 0x1000) == 0);
160 : 6 : CU_ASSERT(prp_index == 1);
161 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x108000);
162 : :
163 : : /* 4K buffer, 4K aligned */
164 : 6 : prp_list_prep(&tr, &req, &prp_index);
165 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100000, 0x1000,
166 : : 0x1000) == 0);
167 : 6 : CU_ASSERT(prp_index == 1);
168 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100000);
169 : :
170 : : /* 4K buffer, non-4K aligned */
171 : 6 : prp_list_prep(&tr, &req, &prp_index);
172 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100800, 0x1000,
173 : : 0x1000) == 0);
174 : 6 : CU_ASSERT(prp_index == 2);
175 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100800);
176 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp2 == 0x101000);
177 : :
178 : : /* 8K buffer, 4K aligned */
179 : 6 : prp_list_prep(&tr, &req, &prp_index);
180 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100000, 0x2000,
181 : : 0x1000) == 0);
182 : 6 : CU_ASSERT(prp_index == 2);
183 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100000);
184 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp2 == 0x101000);
185 : :
186 : : /* 8K buffer, non-4K aligned */
187 : 6 : prp_list_prep(&tr, &req, &prp_index);
188 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100800, 0x2000,
189 : : 0x1000) == 0);
190 : 6 : CU_ASSERT(prp_index == 3);
191 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100800);
192 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp2 == tr.prp_sgl_bus_addr);
193 : 6 : CU_ASSERT(tr.u.prp[0] == 0x101000);
194 : 6 : CU_ASSERT(tr.u.prp[1] == 0x102000);
195 : :
196 : : /* 12K buffer, 4K aligned */
197 : 6 : prp_list_prep(&tr, &req, &prp_index);
198 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100000, 0x3000,
199 : : 0x1000) == 0);
200 : 6 : CU_ASSERT(prp_index == 3);
201 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100000);
202 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp2 == tr.prp_sgl_bus_addr);
203 : 6 : CU_ASSERT(tr.u.prp[0] == 0x101000);
204 : 6 : CU_ASSERT(tr.u.prp[1] == 0x102000);
205 : :
206 : : /* 12K buffer, non-4K aligned */
207 : 6 : prp_list_prep(&tr, &req, &prp_index);
208 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100800, 0x3000,
209 : : 0x1000) == 0);
210 : 6 : CU_ASSERT(prp_index == 4);
211 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100800);
212 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp2 == tr.prp_sgl_bus_addr);
213 : 6 : CU_ASSERT(tr.u.prp[0] == 0x101000);
214 : 6 : CU_ASSERT(tr.u.prp[1] == 0x102000);
215 : 6 : CU_ASSERT(tr.u.prp[2] == 0x103000);
216 : :
217 : : /* Two 4K buffers, both 4K aligned */
218 : 6 : prp_list_prep(&tr, &req, &prp_index);
219 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100000, 0x1000,
220 : : 0x1000) == 0);
221 : 6 : CU_ASSERT(prp_index == 1);
222 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x900000, 0x1000,
223 : : 0x1000) == 0);
224 : 6 : CU_ASSERT(prp_index == 2);
225 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100000);
226 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp2 == 0x900000);
227 : :
228 : : /* Two 4K buffers, first non-4K aligned, second 4K aligned */
229 : 6 : prp_list_prep(&tr, &req, &prp_index);
230 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100800, 0x1000,
231 : : 0x1000) == 0);
232 : 6 : CU_ASSERT(prp_index == 2);
233 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x900000, 0x1000,
234 : : 0x1000) == 0);
235 : 6 : CU_ASSERT(prp_index == 3);
236 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100800);
237 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp2 == tr.prp_sgl_bus_addr);
238 : 6 : CU_ASSERT(tr.u.prp[0] == 0x101000);
239 : 6 : CU_ASSERT(tr.u.prp[1] == 0x900000);
240 : :
241 : : /* Two 4K buffers, both non-4K aligned (invalid) */
242 : 6 : prp_list_prep(&tr, &req, &prp_index);
243 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100800, 0x1000,
244 : : 0x1000) == 0);
245 : 6 : CU_ASSERT(prp_index == 2);
246 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x900800, 0x1000,
247 : : 0x1000) == -EFAULT);
248 : 6 : CU_ASSERT(prp_index == 2);
249 : :
250 : : /* 4K buffer, 4K aligned, but vtophys fails */
251 : 6 : MOCK_SET(spdk_vtophys, SPDK_VTOPHYS_ERROR);
252 : 6 : prp_list_prep(&tr, &req, &prp_index);
253 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100000, 0x1000,
254 : : 0x1000) == -EFAULT);
255 : 6 : MOCK_CLEAR(spdk_vtophys);
256 : :
257 : : /* Largest aligned buffer that can be described in NVME_MAX_PRP_LIST_ENTRIES (plus PRP1) */
258 : 6 : prp_list_prep(&tr, &req, &prp_index);
259 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100000,
260 : : (NVME_MAX_PRP_LIST_ENTRIES + 1) * 0x1000, 0x1000) == 0);
261 : 6 : CU_ASSERT(prp_index == NVME_MAX_PRP_LIST_ENTRIES + 1);
262 : :
263 : : /* Largest non-4K-aligned buffer that can be described in NVME_MAX_PRP_LIST_ENTRIES (plus PRP1) */
264 : 6 : prp_list_prep(&tr, &req, &prp_index);
265 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100800,
266 : : NVME_MAX_PRP_LIST_ENTRIES * 0x1000, 0x1000) == 0);
267 : 6 : CU_ASSERT(prp_index == NVME_MAX_PRP_LIST_ENTRIES + 1);
268 : :
269 : : /* Buffer too large to be described in NVME_MAX_PRP_LIST_ENTRIES */
270 : 6 : prp_list_prep(&tr, &req, &prp_index);
271 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100000,
272 : : (NVME_MAX_PRP_LIST_ENTRIES + 2) * 0x1000, 0x1000) == -EFAULT);
273 : :
274 : : /* Non-4K-aligned buffer too large to be described in NVME_MAX_PRP_LIST_ENTRIES */
275 : 6 : prp_list_prep(&tr, &req, &prp_index);
276 : 6 : CU_ASSERT(nvme_pcie_prp_list_append(&ctrlr, &tr, &prp_index, (void *)0x100800,
277 : : (NVME_MAX_PRP_LIST_ENTRIES + 1) * 0x1000, 0x1000) == -EFAULT);
278 : 6 : }
279 : :
280 : : struct spdk_event_entry {
281 : : struct spdk_pci_event event;
282 : : STAILQ_ENTRY(spdk_event_entry) link;
283 : : };
284 : :
285 : : static STAILQ_HEAD(, spdk_event_entry) g_events = STAILQ_HEAD_INITIALIZER(g_events);
286 : : static bool g_device_allowed = false;
287 : :
288 : : int
289 : 42 : spdk_pci_get_event(int fd, struct spdk_pci_event *event)
290 : : {
291 : : struct spdk_event_entry *entry;
292 : :
293 [ + + ]: 42 : if (STAILQ_EMPTY(&g_events)) {
294 : 30 : return 0;
295 : : }
296 : :
297 : 12 : entry = STAILQ_FIRST(&g_events);
298 [ + - ]: 12 : STAILQ_REMOVE_HEAD(&g_events, link);
299 : :
300 : 12 : *event = entry->event;
301 : :
302 : 12 : return 1;
303 : : }
304 : :
305 : : int
306 : 6 : spdk_pci_device_allow(struct spdk_pci_addr *pci_addr)
307 : : {
308 : 6 : g_device_allowed = true;
309 : :
310 : 6 : return 0;
311 : : }
312 : :
313 : : static void
314 : 6 : test_nvme_pcie_hotplug_monitor(void)
315 : : {
316 : 6 : struct nvme_pcie_ctrlr pctrlr = {};
317 : 6 : struct spdk_event_entry entry = {};
318 : 5 : struct nvme_driver driver;
319 : 5 : pthread_mutexattr_t attr;
320 : 6 : struct spdk_nvme_probe_ctx test_nvme_probe_ctx = {};
321 : :
322 : : /* Initiate variables and ctrlr */
323 : 6 : driver.initialized = true;
324 : 6 : driver.hotplug_fd = 123;
325 [ - + ]: 6 : CU_ASSERT(pthread_mutexattr_init(&attr) == 0);
326 [ - + ]: 6 : CU_ASSERT(pthread_mutex_init(&pctrlr.ctrlr.ctrlr_lock, &attr) == 0);
327 [ - + ]: 6 : CU_ASSERT(pthread_mutex_init(&driver.lock, &attr) == 0);
328 : 6 : TAILQ_INIT(&driver.shared_attached_ctrlrs);
329 : 6 : g_spdk_nvme_driver = &driver;
330 : :
331 : : /* Case 1: SPDK_NVME_UEVENT_ADD/ NVME_VFIO / NVME_UIO */
332 : 6 : entry.event.action = SPDK_UEVENT_ADD;
333 : 6 : spdk_pci_addr_parse(&entry.event.traddr, "0000:05:00.0");
334 : 6 : CU_ASSERT(STAILQ_EMPTY(&g_events));
335 : 6 : STAILQ_INSERT_TAIL(&g_events, &entry, link);
336 : :
337 : 6 : _nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
338 : :
339 : 6 : CU_ASSERT(STAILQ_EMPTY(&g_events));
340 [ - + ]: 6 : CU_ASSERT(g_device_allowed == true);
341 : 6 : g_device_allowed = false;
342 : :
343 : : /* Case 2: SPDK_NVME_UEVENT_REMOVE/ NVME_UIO */
344 : 6 : entry.event.action = SPDK_UEVENT_REMOVE;
345 : 6 : spdk_pci_addr_parse(&entry.event.traddr, "0000:05:00.0");
346 : 6 : CU_ASSERT(STAILQ_EMPTY(&g_events));
347 : 6 : STAILQ_INSERT_TAIL(&g_events, &entry, link);
348 : :
349 : 6 : MOCK_SET(nvme_get_ctrlr_by_trid_unsafe, &pctrlr.ctrlr);
350 : :
351 : 6 : _nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
352 : :
353 : 6 : CU_ASSERT(STAILQ_EMPTY(&g_events));
354 [ - + ]: 6 : CU_ASSERT(pctrlr.ctrlr.is_failed == true);
355 [ - + ]: 6 : CU_ASSERT(pctrlr.ctrlr.is_removed == true);
356 : 6 : pctrlr.ctrlr.is_failed = false;
357 : 6 : pctrlr.ctrlr.is_removed = false;
358 : 6 : MOCK_CLEAR(nvme_get_ctrlr_by_trid_unsafe);
359 : :
360 : : /* Case 3: SPDK_NVME_UEVENT_REMOVE/ NVME_VFIO without event */
361 : 6 : pctrlr.ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
362 [ - + ]: 6 : snprintf(pctrlr.ctrlr.trid.traddr, sizeof(pctrlr.ctrlr.trid.traddr), "0000:02:00.0");
363 : 6 : pctrlr.ctrlr.remove_cb = NULL;
364 : 6 : pctrlr.ctrlr.is_failed = false;
365 : 6 : pctrlr.ctrlr.is_removed = false;
366 : 6 : TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->shared_attached_ctrlrs, &pctrlr.ctrlr, tailq);
367 : :
368 : : /* This should be set in the vfio req notifier cb */
369 : 6 : MOCK_SET(spdk_pci_device_is_removed, true);
370 : :
371 : 6 : _nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
372 : :
373 : 6 : CU_ASSERT(STAILQ_EMPTY(&g_events));
374 [ - + ]: 6 : CU_ASSERT(pctrlr.ctrlr.is_failed == true);
375 [ - + ]: 6 : CU_ASSERT(pctrlr.ctrlr.is_removed == true);
376 : 6 : pctrlr.ctrlr.is_failed = false;
377 : 6 : pctrlr.ctrlr.is_removed = false;
378 : 6 : MOCK_CLEAR(spdk_pci_device_is_removed);
379 : :
380 : : /* Case 4: Removed device detected in another process */
381 : 6 : MOCK_SET(spdk_pci_device_is_removed, false);
382 : :
383 : 6 : _nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
384 : :
385 [ - + ]: 6 : CU_ASSERT(pctrlr.ctrlr.is_failed == false);
386 : :
387 : 6 : MOCK_SET(spdk_pci_device_is_removed, true);
388 : :
389 : 6 : _nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
390 : :
391 [ - + ]: 6 : CU_ASSERT(pctrlr.ctrlr.is_failed == true);
392 : :
393 [ - + ]: 6 : pthread_mutex_destroy(&driver.lock);
394 [ - + ]: 6 : pthread_mutex_destroy(&pctrlr.ctrlr.ctrlr_lock);
395 [ - + ]: 6 : pthread_mutexattr_destroy(&attr);
396 : 6 : g_spdk_nvme_driver = NULL;
397 : 6 : }
398 : :
399 : : static void
400 : 6 : test_shadow_doorbell_update(void)
401 : : {
402 : : bool ret;
403 : :
404 : : /* nvme_pcie_qpair_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old) */
405 : 6 : ret = nvme_pcie_qpair_need_event(10, 15, 14);
406 : 6 : CU_ASSERT(ret == false);
407 : :
408 : 6 : ret = nvme_pcie_qpair_need_event(14, 15, 14);
409 : 6 : CU_ASSERT(ret == true);
410 : 6 : }
411 : :
412 : : static void
413 : 6 : test_build_contig_hw_sgl_request(void)
414 : : {
415 : 6 : struct spdk_nvme_qpair qpair = {};
416 : 6 : struct nvme_request req = {};
417 : 6 : struct nvme_tracker tr = {};
418 : 6 : struct spdk_nvme_ctrlr ctrlr = {};
419 : : int rc;
420 : :
421 : 6 : ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
422 : 6 : qpair.ctrlr = &ctrlr;
423 : : /* Test 1: Payload covered by a single mapping */
424 : 6 : req.payload_size = 100;
425 : 6 : req.payload = NVME_PAYLOAD_CONTIG((void *)0xbeef0, NULL);
426 : 6 : g_vtophys_size = 100;
427 : 6 : MOCK_SET(spdk_vtophys, 0xDEADBEEF);
428 : :
429 : 6 : rc = nvme_pcie_qpair_build_contig_hw_sgl_request(&qpair, &req, &tr, 0);
430 : 6 : CU_ASSERT(rc == 0);
431 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
432 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0xDEADBEEF);
433 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == 100);
434 : :
435 : 6 : MOCK_CLEAR(spdk_vtophys);
436 : 6 : g_vtophys_size = 0;
437 [ - + ]: 6 : memset(&qpair, 0, sizeof(qpair));
438 [ - + ]: 6 : memset(&req, 0, sizeof(req));
439 [ - + ]: 6 : memset(&tr, 0, sizeof(tr));
440 : :
441 : : /* Test 2: Payload covered by a single mapping, but request is at an offset */
442 : 6 : qpair.ctrlr = &ctrlr;
443 : 6 : req.payload_size = 100;
444 : 6 : req.payload_offset = 50;
445 : 6 : req.payload = NVME_PAYLOAD_CONTIG((void *)0xbeef0, NULL);
446 : 6 : g_vtophys_size = 1000;
447 : 6 : MOCK_SET(spdk_vtophys, 0xDEADBEEF);
448 : :
449 : 6 : rc = nvme_pcie_qpair_build_contig_hw_sgl_request(&qpair, &req, &tr, 0);
450 : 6 : CU_ASSERT(rc == 0);
451 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
452 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0xDEADBEEF);
453 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == 100);
454 : :
455 : 6 : MOCK_CLEAR(spdk_vtophys);
456 : 6 : g_vtophys_size = 0;
457 [ - + ]: 6 : memset(&qpair, 0, sizeof(qpair));
458 [ - + ]: 6 : memset(&req, 0, sizeof(req));
459 [ - + ]: 6 : memset(&tr, 0, sizeof(tr));
460 : :
461 : : /* Test 3: Payload spans two mappings */
462 : 6 : qpair.ctrlr = &ctrlr;
463 : 6 : req.payload_size = 100;
464 : 6 : req.payload = NVME_PAYLOAD_CONTIG((void *)0xbeef0, NULL);
465 : 6 : g_vtophys_size = 60;
466 : 6 : tr.prp_sgl_bus_addr = 0xFF0FF;
467 : 6 : MOCK_SET(spdk_vtophys, 0xDEADBEEF);
468 : :
469 : 6 : rc = nvme_pcie_qpair_build_contig_hw_sgl_request(&qpair, &req, &tr, 0);
470 : 6 : CU_ASSERT(rc == 0);
471 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_LAST_SEGMENT);
472 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.address == tr.prp_sgl_bus_addr);
473 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == 2 * sizeof(struct spdk_nvme_sgl_descriptor));
474 : 6 : CU_ASSERT(tr.u.sgl[0].unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
475 : 6 : CU_ASSERT(tr.u.sgl[0].unkeyed.length == 60);
476 : 6 : CU_ASSERT(tr.u.sgl[0].address == 0xDEADBEEF);
477 : 6 : CU_ASSERT(tr.u.sgl[1].unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
478 : 6 : CU_ASSERT(tr.u.sgl[1].unkeyed.length == 40);
479 : 6 : CU_ASSERT(tr.u.sgl[1].address == 0xDEADBEEF);
480 : :
481 : 6 : MOCK_CLEAR(spdk_vtophys);
482 : 6 : g_vtophys_size = 0;
483 [ - + ]: 6 : memset(&qpair, 0, sizeof(qpair));
484 [ - + ]: 6 : memset(&req, 0, sizeof(req));
485 [ - + ]: 6 : memset(&tr, 0, sizeof(tr));
486 : 6 : }
487 : :
488 : : static void
489 : 6 : test_nvme_pcie_qpair_build_metadata(void)
490 : : {
491 : 6 : struct nvme_pcie_qpair pqpair = {};
492 : 6 : struct spdk_nvme_qpair *qpair = &pqpair.qpair;
493 : 6 : struct nvme_tracker tr = {};
494 : 6 : struct nvme_request req = {};
495 : 6 : struct spdk_nvme_ctrlr ctrlr = {};
496 : : int rc;
497 : :
498 : 6 : ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
499 : 6 : tr.req = &req;
500 : 6 : qpair->ctrlr = &ctrlr;
501 : :
502 : 6 : req.payload = NVME_PAYLOAD_CONTIG(NULL, (void *)0xDEADBEE0);
503 : 6 : req.md_offset = 0;
504 : 6 : req.md_size = 4096;
505 : : /* The nvme_pcie_qpair_build_metadata() function expects the cmd.psdt
506 : : * is set to SPDK_NVME_PSDT_SGL_MPTR_CONTIG, and then if metadata is
507 : : * built using SGL, cmd.psdt is changed to SPDK_NVME_PSDT_SGL_MPTR_SGL
508 : : * by this function. We need to verify if this indeed is the case.
509 : : */
510 : 6 : req.cmd.psdt = SPDK_NVME_PSDT_SGL_MPTR_CONTIG;
511 : 6 : tr.prp_sgl_bus_addr = 0xDBADBEEF;
512 : 6 : MOCK_SET(spdk_vtophys, 0xDCADBEE0);
513 : :
514 : 6 : rc = nvme_pcie_qpair_build_metadata(qpair, &tr, true, true, true);
515 : 6 : CU_ASSERT(rc == 0);
516 : 6 : CU_ASSERT(req.cmd.psdt == SPDK_NVME_PSDT_SGL_MPTR_SGL);
517 : 6 : CU_ASSERT(tr.meta_sgl.address == 0xDCADBEE0);
518 : 6 : CU_ASSERT(tr.meta_sgl.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
519 : 6 : CU_ASSERT(tr.meta_sgl.unkeyed.length == 4096);
520 : 6 : CU_ASSERT(tr.meta_sgl.unkeyed.subtype == 0);
521 : 6 : CU_ASSERT(req.cmd.mptr == (0xDBADBEEF - sizeof(struct spdk_nvme_sgl_descriptor)));
522 : :
523 : : /* Non-IOVA contiguous metadata buffers should fail. */
524 : 6 : g_vtophys_size = 1024;
525 : 6 : req.cmd.psdt = SPDK_NVME_PSDT_SGL_MPTR_CONTIG;
526 : 6 : rc = nvme_pcie_qpair_build_metadata(qpair, &tr, true, true, true);
527 : 6 : CU_ASSERT(rc == -EINVAL);
528 : 6 : g_vtophys_size = 0;
529 : :
530 : 6 : MOCK_CLEAR(spdk_vtophys);
531 : :
532 : : /* Build non sgl metadata */
533 : 6 : MOCK_SET(spdk_vtophys, 0xDDADBEE0);
534 : :
535 : 6 : rc = nvme_pcie_qpair_build_metadata(qpair, &tr, false, false, true);
536 : 6 : CU_ASSERT(rc == 0);
537 : 6 : CU_ASSERT(req.cmd.mptr == 0xDDADBEE0);
538 : :
539 : : /* Build non sgl metadata while sgls are supported */
540 [ - + ]: 6 : memset(&tr.meta_sgl, 0, sizeof(tr.meta_sgl));
541 : : /* If SGLs are supported, but not in metadata, the cmd.psdt
542 : : * shall not be changed to SPDK_NVME_PSDT_SGL_MPTR_SGL
543 : : */
544 : 6 : req.cmd.psdt = SPDK_NVME_PSDT_SGL_MPTR_CONTIG;
545 : 6 : rc = nvme_pcie_qpair_build_metadata(qpair, &tr, true, false, true);
546 : 6 : CU_ASSERT(rc == 0);
547 : 6 : CU_ASSERT(tr.meta_sgl.address == 0);
548 : 6 : CU_ASSERT(tr.meta_sgl.unkeyed.length == 0);
549 : 6 : CU_ASSERT(req.cmd.psdt == SPDK_NVME_PSDT_SGL_MPTR_CONTIG);
550 : 6 : CU_ASSERT(req.cmd.mptr == 0xDDADBEE0);
551 : :
552 : : /* Non-IOVA contiguous metadata buffers should fail. */
553 : 6 : g_vtophys_size = 1024;
554 : 6 : rc = nvme_pcie_qpair_build_metadata(qpair, &tr, false, false, true);
555 : 6 : CU_ASSERT(rc == -EINVAL);
556 : 6 : g_vtophys_size = 0;
557 : :
558 : 6 : MOCK_CLEAR(spdk_vtophys);
559 : 6 : }
560 : :
561 : : static int
562 : 30 : nvme_pcie_ut_next_sge(void *cb_arg, void **address, uint32_t *length)
563 : : {
564 : 30 : struct nvme_pcie_ut_bdev_io *bio = cb_arg;
565 : : struct iovec *iov;
566 : :
567 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(bio->iovpos < NVME_MAX_SGL_DESCRIPTORS);
568 : :
569 : 30 : iov = &bio->iovs[bio->iovpos];
570 : :
571 : 30 : *address = iov->iov_base;
572 : 30 : *length = iov->iov_len;
573 : 30 : bio->iovpos++;
574 : :
575 : 30 : return 0;
576 : : }
577 : :
578 : : static void
579 : 18 : nvme_pcie_ut_reset_sgl(void *cb_arg, uint32_t offset)
580 : : {
581 : 18 : struct nvme_pcie_ut_bdev_io *bio = cb_arg;
582 : : struct iovec *iov;
583 : :
584 [ + - ]: 18 : for (bio->iovpos = 0; bio->iovpos < NVME_MAX_SGL_DESCRIPTORS; bio->iovpos++) {
585 : 18 : iov = &bio->iovs[bio->iovpos];
586 : : /* Offset must be aligned with the start of any SGL entry */
587 [ + - ]: 18 : if (offset == 0) {
588 : 18 : break;
589 : : }
590 : :
591 [ # # ]: 0 : SPDK_CU_ASSERT_FATAL(offset >= iov->iov_len);
592 : 0 : offset -= iov->iov_len;
593 : : }
594 : :
595 [ - + ]: 18 : SPDK_CU_ASSERT_FATAL(offset == 0);
596 [ - + ]: 18 : SPDK_CU_ASSERT_FATAL(bio->iovpos < NVME_MAX_SGL_DESCRIPTORS);
597 : 18 : }
598 : :
599 : : static void
600 : 6 : test_nvme_pcie_qpair_build_prps_sgl_request(void)
601 : : {
602 : 6 : struct spdk_nvme_qpair qpair = {};
603 : 6 : struct nvme_request req = {};
604 : 6 : struct nvme_tracker tr = {};
605 : 6 : struct spdk_nvme_ctrlr ctrlr = {};
606 : 6 : struct nvme_pcie_ut_bdev_io bio = {};
607 : : int rc;
608 : :
609 : 6 : tr.req = &req;
610 : 6 : qpair.ctrlr = &ctrlr;
611 : 6 : req.payload = NVME_PAYLOAD_SGL(nvme_pcie_ut_reset_sgl, nvme_pcie_ut_next_sge, &bio, NULL);
612 : 6 : req.payload_size = 4096;
613 : 6 : ctrlr.page_size = 4096;
614 : 6 : bio.iovs[0].iov_base = (void *)0x100000;
615 : 6 : bio.iovs[0].iov_len = 4096;
616 : :
617 : 6 : rc = nvme_pcie_qpair_build_prps_sgl_request(&qpair, &req, &tr, NULL);
618 : 6 : CU_ASSERT(rc == 0);
619 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100000);
620 : 6 : }
621 : :
622 : : static void
623 : 6 : test_nvme_pcie_qpair_build_hw_sgl_request(void)
624 : : {
625 : 6 : struct spdk_nvme_qpair qpair = {};
626 : 6 : struct nvme_request req = {};
627 : 6 : struct nvme_tracker tr = {};
628 : 6 : struct nvme_pcie_ut_bdev_io bio = {};
629 : 6 : struct spdk_nvme_ctrlr ctrlr = {};
630 : : int rc;
631 : :
632 : 6 : ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
633 : 6 : qpair.ctrlr = &ctrlr;
634 : 6 : req.payload = NVME_PAYLOAD_SGL(nvme_pcie_ut_reset_sgl, nvme_pcie_ut_next_sge, &bio, NULL);
635 : 6 : req.cmd.opc = SPDK_NVME_OPC_WRITE;
636 : 6 : tr.prp_sgl_bus_addr = 0xDAADBEE0;
637 : 6 : g_vtophys_size = 4096;
638 : :
639 : : /* Multiple vectors, 2k + 4k + 2k */
640 : 6 : req.payload_size = 8192;
641 : 6 : bio.iovpos = 3;
642 : 6 : bio.iovs[0].iov_base = (void *)0xDBADBEE0;
643 : 6 : bio.iovs[0].iov_len = 2048;
644 : 6 : bio.iovs[1].iov_base = (void *)0xDCADBEE0;
645 : 6 : bio.iovs[1].iov_len = 4096;
646 : 6 : bio.iovs[2].iov_base = (void *)0xDDADBEE0;
647 : 6 : bio.iovs[2].iov_len = 2048;
648 : :
649 : 6 : rc = nvme_pcie_qpair_build_hw_sgl_request(&qpair, &req, &tr, true);
650 : 6 : CU_ASSERT(rc == 0);
651 : 6 : CU_ASSERT(tr.u.sgl[0].unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
652 : 6 : CU_ASSERT(tr.u.sgl[0].unkeyed.length == 2048);
653 : 6 : CU_ASSERT(tr.u.sgl[0].address == 0xDBADBEE0);
654 : 6 : CU_ASSERT(tr.u.sgl[0].unkeyed.subtype == 0);
655 : 6 : CU_ASSERT(tr.u.sgl[1].unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
656 : 6 : CU_ASSERT(tr.u.sgl[1].unkeyed.length == 4096);
657 : 6 : CU_ASSERT(tr.u.sgl[1].address == 0xDCADBEE0);
658 : 6 : CU_ASSERT(tr.u.sgl[2].unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
659 : 6 : CU_ASSERT(tr.u.sgl[2].unkeyed.length == 2048);
660 : 6 : CU_ASSERT(tr.u.sgl[2].unkeyed.length == 2048);
661 : 6 : CU_ASSERT(tr.u.sgl[2].address == 0xDDADBEE0);
662 : 6 : CU_ASSERT(req.cmd.psdt == SPDK_NVME_PSDT_SGL_MPTR_CONTIG);
663 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == 0);
664 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_LAST_SEGMENT);
665 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0xDAADBEE0);
666 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == 48);
667 : :
668 : : /* Single vector */
669 [ - + ]: 6 : memset(&tr, 0, sizeof(tr));
670 [ - + ]: 6 : memset(&bio, 0, sizeof(bio));
671 [ - + ]: 6 : memset(&req, 0, sizeof(req));
672 : 6 : req.payload = NVME_PAYLOAD_SGL(nvme_pcie_ut_reset_sgl, nvme_pcie_ut_next_sge, &bio, NULL);
673 : 6 : req.cmd.opc = SPDK_NVME_OPC_WRITE;
674 : 6 : req.payload_size = 4096;
675 : 6 : bio.iovpos = 1;
676 : 6 : bio.iovs[0].iov_base = (void *)0xDBADBEE0;
677 : 6 : bio.iovs[0].iov_len = 4096;
678 : :
679 : 6 : rc = nvme_pcie_qpair_build_hw_sgl_request(&qpair, &req, &tr, true);
680 : 6 : CU_ASSERT(rc == 0);
681 : 6 : CU_ASSERT(tr.u.sgl[0].unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
682 : 6 : CU_ASSERT(tr.u.sgl[0].unkeyed.length == 4096);
683 : 6 : CU_ASSERT(tr.u.sgl[0].address == 0xDBADBEE0);
684 : 6 : CU_ASSERT(tr.u.sgl[0].unkeyed.subtype == 0);
685 : 6 : CU_ASSERT(req.cmd.psdt == SPDK_NVME_PSDT_SGL_MPTR_CONTIG);
686 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.subtype == 0);
687 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK);
688 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.address == 0xDBADBEE0);
689 : 6 : CU_ASSERT(req.cmd.dptr.sgl1.unkeyed.length == 4096);
690 : 6 : }
691 : :
692 : : static void
693 : 6 : test_nvme_pcie_qpair_build_contig_request(void)
694 : : {
695 : 6 : struct nvme_pcie_qpair pqpair = {};
696 : 6 : struct nvme_request req = {};
697 : 6 : struct nvme_tracker tr = {};
698 : 6 : struct spdk_nvme_ctrlr ctrlr = {};
699 : : int rc;
700 : :
701 : 6 : pqpair.qpair.ctrlr = &ctrlr;
702 : 6 : ctrlr.page_size = 0x1000;
703 : :
704 : : /* 1 prp, 4k-aligned */
705 : 6 : prp_list_prep(&tr, &req, NULL);
706 : 6 : req.payload = NVME_PAYLOAD_CONTIG((void *)0x100000, NULL);
707 : 6 : req.payload_size = 0x1000;
708 : :
709 : 6 : rc = nvme_pcie_qpair_build_contig_request(&pqpair.qpair, &req, &tr, true);
710 : 6 : CU_ASSERT(rc == 0);
711 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100000);
712 : :
713 : : /* 2 prps, non-4K-aligned */
714 : 6 : prp_list_prep(&tr, &req, NULL);
715 : 6 : req.payload = NVME_PAYLOAD_CONTIG((void *)0x100000, NULL);
716 : 6 : req.payload_size = 0x1000;
717 : 6 : req.payload_offset = 0x800;
718 : :
719 : 6 : rc = nvme_pcie_qpair_build_contig_request(&pqpair.qpair, &req, &tr, true);
720 : 6 : CU_ASSERT(rc == 0);
721 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100800);
722 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp2 == 0x101000);
723 : :
724 : : /* 3 prps, 4k-aligned */
725 : 6 : prp_list_prep(&tr, &req, NULL);
726 : 6 : req.payload = NVME_PAYLOAD_CONTIG((void *)0x100000, NULL);
727 : 6 : req.payload_size = 0x3000;
728 : :
729 : 6 : rc = nvme_pcie_qpair_build_contig_request(&pqpair.qpair, &req, &tr, true);
730 : 6 : CU_ASSERT(rc == 0);
731 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp1 == 0x100000);
732 : 6 : CU_ASSERT(req.cmd.dptr.prp.prp2 == tr.prp_sgl_bus_addr);
733 : 6 : CU_ASSERT(tr.u.prp[0] == 0x101000);
734 : 6 : CU_ASSERT(tr.u.prp[1] == 0x102000);
735 : :
736 : : /* address not dword aligned */
737 : 6 : prp_list_prep(&tr, &req, NULL);
738 : 6 : req.payload = NVME_PAYLOAD_CONTIG((void *)0x100001, NULL);
739 : 6 : req.payload_size = 0x3000;
740 : 6 : req.qpair = &pqpair.qpair;
741 : 6 : TAILQ_INIT(&pqpair.outstanding_tr);
742 : 6 : TAILQ_INSERT_TAIL(&pqpair.outstanding_tr, &tr, tq_list);
743 : :
744 : 6 : rc = nvme_pcie_qpair_build_contig_request(&pqpair.qpair, &req, &tr, true);
745 : 6 : CU_ASSERT(rc == -EFAULT);
746 : 6 : }
747 : :
748 : : static void
749 : 6 : test_nvme_pcie_ctrlr_regs_get_set(void)
750 : : {
751 : 6 : struct nvme_pcie_ctrlr pctrlr = {};
752 : 6 : volatile struct spdk_nvme_registers regs = {};
753 : 5 : uint32_t value_4;
754 : 5 : uint64_t value_8;
755 : : int rc;
756 : :
757 : 6 : pctrlr.regs = ®s;
758 : :
759 : 6 : rc = nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, 8, 4);
760 : 6 : CU_ASSERT(rc == 0);
761 : :
762 : 6 : rc = nvme_pcie_ctrlr_get_reg_4(&pctrlr.ctrlr, 8, &value_4);
763 : 6 : CU_ASSERT(rc == 0);
764 : 6 : CU_ASSERT(value_4 == 4);
765 : :
766 : 6 : rc = nvme_pcie_ctrlr_set_reg_8(&pctrlr.ctrlr, 0, 0x100000000);
767 : 6 : CU_ASSERT(rc == 0);
768 : :
769 : 6 : rc = nvme_pcie_ctrlr_get_reg_8(&pctrlr.ctrlr, 0, &value_8);
770 : 6 : CU_ASSERT(rc == 0);
771 : 6 : CU_ASSERT(value_8 == 0x100000000);
772 : 6 : }
773 : :
774 : : static void
775 : 6 : test_nvme_pcie_ctrlr_map_unmap_cmb(void)
776 : : {
777 : 6 : struct nvme_pcie_ctrlr pctrlr = {};
778 : 6 : volatile struct spdk_nvme_registers regs = {};
779 : 6 : union spdk_nvme_cmbsz_register cmbsz = {};
780 : 6 : union spdk_nvme_cmbloc_register cmbloc = {};
781 : 6 : struct dev_mem_resource cmd_res = {};
782 : : int rc;
783 : :
784 : 6 : pctrlr.regs = ®s;
785 : 6 : pctrlr.devhandle = (void *)&cmd_res;
786 : 6 : cmd_res.addr = (void *)0x7f7c0080d000;
787 : 6 : cmd_res.len = 0x800000;
788 : 6 : cmd_res.phys_addr = 0xFC800000;
789 : : /* Configure cmb size with unit size 4k, offset 100, unsupported SQ */
790 : 6 : cmbsz.bits.sz = 512;
791 : 6 : cmbsz.bits.szu = 0;
792 : 6 : cmbsz.bits.sqs = 0;
793 : 6 : cmbloc.bits.bir = 0;
794 : 6 : cmbloc.bits.ofst = 100;
795 : :
796 : 6 : nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, cmbsz.raw),
797 : : cmbsz.raw);
798 : 6 : nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, cmbloc.raw),
799 : : cmbloc.raw);
800 : :
801 : 6 : nvme_pcie_ctrlr_map_cmb(&pctrlr);
802 : 6 : CU_ASSERT(pctrlr.cmb.bar_va == (void *)0x7f7c0080d000);
803 : 6 : CU_ASSERT(pctrlr.cmb.bar_pa == 0xFC800000);
804 : 6 : CU_ASSERT(pctrlr.cmb.size == 512 * 4096);
805 : 6 : CU_ASSERT(pctrlr.cmb.current_offset == 4096 * 100);
806 [ - + ]: 6 : CU_ASSERT(pctrlr.ctrlr.opts.use_cmb_sqs == false);
807 : :
808 : 6 : rc = nvme_pcie_ctrlr_unmap_cmb(&pctrlr);
809 : 6 : CU_ASSERT(rc == 0);
810 : :
811 : : /* Invalid mapping information */
812 [ - + ]: 6 : memset(&pctrlr.cmb, 0, sizeof(pctrlr.cmb));
813 : 6 : nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, cmbsz.raw), 0);
814 : 6 : nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, cmbloc.raw), 0);
815 : :
816 : 6 : nvme_pcie_ctrlr_map_cmb(&pctrlr);
817 : 6 : CU_ASSERT(pctrlr.cmb.bar_va == NULL);
818 : 6 : CU_ASSERT(pctrlr.cmb.bar_pa == 0);
819 : 6 : CU_ASSERT(pctrlr.cmb.size == 0);
820 : 6 : CU_ASSERT(pctrlr.cmb.current_offset == 0);
821 [ - + ]: 6 : CU_ASSERT(pctrlr.ctrlr.opts.use_cmb_sqs == false);
822 : 6 : }
823 : :
824 : :
825 : : static void
826 : 36 : prepare_map_io_cmd(struct nvme_pcie_ctrlr *pctrlr)
827 : : {
828 : 36 : union spdk_nvme_cmbsz_register cmbsz = {};
829 : 36 : union spdk_nvme_cmbloc_register cmbloc = {};
830 : :
831 : 36 : cmbsz.bits.sz = 512;
832 : 36 : cmbsz.bits.wds = 1;
833 : 36 : cmbsz.bits.rds = 1;
834 : :
835 : 36 : nvme_pcie_ctrlr_set_reg_4(&pctrlr->ctrlr, offsetof(struct spdk_nvme_registers, cmbsz.raw),
836 : : cmbsz.raw);
837 : 36 : nvme_pcie_ctrlr_set_reg_4(&pctrlr->ctrlr, offsetof(struct spdk_nvme_registers, cmbloc.raw),
838 : : cmbloc.raw);
839 : :
840 : 36 : pctrlr->cmb.bar_va = (void *)0x7F7C0080D000;
841 : 36 : pctrlr->cmb.bar_pa = 0xFC800000;
842 : 36 : pctrlr->cmb.current_offset = 1ULL << 22;
843 : 36 : pctrlr->cmb.size = (1ULL << 22) * 512;
844 : 36 : pctrlr->cmb.mem_register_addr = NULL;
845 : 36 : pctrlr->ctrlr.opts.use_cmb_sqs = false;
846 : 36 : }
847 : :
848 : : static void
849 : 6 : test_nvme_pcie_ctrlr_map_io_cmb(void)
850 : : {
851 : 6 : struct nvme_pcie_ctrlr pctrlr = {};
852 : 6 : volatile struct spdk_nvme_registers regs = {};
853 : 6 : union spdk_nvme_cmbsz_register cmbsz = {};
854 : 6 : void *mem_reg_addr = NULL;
855 : 5 : size_t size;
856 : : int rc;
857 : :
858 : 6 : pctrlr.regs = ®s;
859 : 6 : prepare_map_io_cmd(&pctrlr);
860 : :
861 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_cmb(&pctrlr.ctrlr, &size);
862 : : /* Ceil the current cmb vaddr and cmb size to 2MB_aligned */
863 : 6 : CU_ASSERT(mem_reg_addr == (void *)0x7F7C00E00000);
864 : 6 : CU_ASSERT(size == 0x7FE00000);
865 : :
866 : 6 : rc = nvme_pcie_ctrlr_unmap_io_cmb(&pctrlr.ctrlr);
867 : 6 : CU_ASSERT(rc == 0);
868 : 6 : CU_ASSERT(pctrlr.cmb.mem_register_addr == NULL);
869 : 6 : CU_ASSERT(pctrlr.cmb.mem_register_size == 0);
870 : :
871 : : /* cmb mem_register_addr not NULL */
872 : 6 : prepare_map_io_cmd(&pctrlr);
873 : 6 : pctrlr.cmb.mem_register_addr = (void *)0xDEADBEEF;
874 : 6 : pctrlr.cmb.mem_register_size = 1024;
875 : :
876 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_cmb(&pctrlr.ctrlr, &size);
877 : 6 : CU_ASSERT(size == 1024);
878 : 6 : CU_ASSERT(mem_reg_addr == (void *)0xDEADBEEF);
879 : :
880 : : /* cmb.bar_va is NULL */
881 : 6 : prepare_map_io_cmd(&pctrlr);
882 : 6 : pctrlr.cmb.bar_va = NULL;
883 : :
884 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_cmb(&pctrlr.ctrlr, &size);
885 : 6 : CU_ASSERT(mem_reg_addr == NULL);
886 : 6 : CU_ASSERT(size == 0);
887 : :
888 : : /* submission queue already used */
889 : 6 : prepare_map_io_cmd(&pctrlr);
890 : 6 : pctrlr.ctrlr.opts.use_cmb_sqs = true;
891 : :
892 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_cmb(&pctrlr.ctrlr, &size);
893 : 6 : CU_ASSERT(mem_reg_addr == NULL);
894 : 6 : CU_ASSERT(size == 0);
895 : :
896 : 6 : pctrlr.ctrlr.opts.use_cmb_sqs = false;
897 : :
898 : : /* Only SQS is supported */
899 : 6 : prepare_map_io_cmd(&pctrlr);
900 : 6 : cmbsz.bits.wds = 0;
901 : 6 : cmbsz.bits.rds = 0;
902 : 6 : nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, cmbsz.raw),
903 : : cmbsz.raw);
904 : :
905 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_cmb(&pctrlr.ctrlr, &size);
906 : 6 : CU_ASSERT(mem_reg_addr == NULL);
907 : 6 : CU_ASSERT(size == 0);
908 : :
909 : : /* CMB size is less than 4MB */
910 : 6 : prepare_map_io_cmd(&pctrlr);
911 : 6 : pctrlr.cmb.size = 1ULL << 16;
912 : :
913 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_cmb(&pctrlr.ctrlr, &size);
914 : 6 : CU_ASSERT(mem_reg_addr == NULL);
915 : 6 : CU_ASSERT(size == 0);
916 : 6 : }
917 : :
918 : : static void
919 : 6 : test_nvme_pcie_ctrlr_map_unmap_pmr(void)
920 : : {
921 : 6 : struct nvme_pcie_ctrlr pctrlr = {};
922 : 6 : volatile struct spdk_nvme_registers regs = {};
923 : 6 : union spdk_nvme_pmrcap_register pmrcap = {};
924 : 6 : struct dev_mem_resource cmd_res = {};
925 : : int rc;
926 : :
927 : 6 : pctrlr.regs = ®s;
928 : 6 : pctrlr.devhandle = (void *)&cmd_res;
929 : 6 : regs.cap.bits.pmrs = 1;
930 : 6 : cmd_res.addr = (void *)0x7F7C0080d000;
931 : 6 : cmd_res.len = 0x800000;
932 : 6 : cmd_res.phys_addr = 0xFC800000;
933 : 6 : pmrcap.bits.bir = 2;
934 : 6 : pmrcap.bits.cmss = 1;
935 : 6 : nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr,
936 : : offsetof(struct spdk_nvme_registers, pmrcap.raw),
937 : : pmrcap.raw);
938 : :
939 : 6 : nvme_pcie_ctrlr_map_pmr(&pctrlr);
940 : 6 : CU_ASSERT(pctrlr.regs->pmrmscu == 0);
941 : : /* Controller memory space enable, bit 1 */
942 : 6 : CU_ASSERT(pctrlr.regs->pmrmscl.raw == 0xFC800002);
943 : 6 : CU_ASSERT(pctrlr.regs->pmrsts.raw == 0);
944 : 6 : CU_ASSERT(pctrlr.pmr.bar_va == (void *)0x7F7C0080d000);
945 : 6 : CU_ASSERT(pctrlr.pmr.bar_pa == 0xFC800000);
946 : 6 : CU_ASSERT(pctrlr.pmr.size == 0x800000);
947 : :
948 : 6 : rc = nvme_pcie_ctrlr_unmap_pmr(&pctrlr);
949 : 6 : CU_ASSERT(rc == 0);
950 : 6 : CU_ASSERT(pctrlr.regs->pmrmscu == 0);
951 : 6 : CU_ASSERT(pctrlr.regs->pmrmscl.raw == 0);
952 : :
953 : : /* pmrcap value invalid */
954 [ - + ]: 6 : memset(&pctrlr, 0, sizeof(pctrlr));
955 [ - + ]: 6 : memset((void *)®s, 0, sizeof(regs));
956 [ - + ]: 6 : memset(&cmd_res, 0, sizeof(cmd_res));
957 : :
958 : 6 : pctrlr.regs = ®s;
959 : 6 : pctrlr.devhandle = (void *)&cmd_res;
960 : 6 : regs.cap.bits.pmrs = 1;
961 : 6 : cmd_res.addr = (void *)0x7F7C0080d000;
962 : 6 : cmd_res.len = 0x800000;
963 : 6 : cmd_res.phys_addr = 0xFC800000;
964 : 6 : pmrcap.raw = 0;
965 : 6 : nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr,
966 : : offsetof(struct spdk_nvme_registers, pmrcap.raw),
967 : : pmrcap.raw);
968 : :
969 : 6 : nvme_pcie_ctrlr_map_pmr(&pctrlr);
970 : 6 : CU_ASSERT(pctrlr.pmr.bar_va == NULL);
971 : 6 : CU_ASSERT(pctrlr.pmr.bar_pa == 0);
972 : 6 : CU_ASSERT(pctrlr.pmr.size == 0);
973 : 6 : }
974 : :
975 : : static void
976 : 6 : test_nvme_pcie_ctrlr_config_pmr(void)
977 : : {
978 : 6 : struct nvme_pcie_ctrlr pctrlr = {};
979 : 6 : union spdk_nvme_pmrcap_register pmrcap = {};
980 : 6 : union spdk_nvme_pmrsts_register pmrsts = {};
981 : 6 : union spdk_nvme_cap_register cap = {};
982 : 6 : union spdk_nvme_pmrctl_register pmrctl = {};
983 : 6 : volatile struct spdk_nvme_registers regs = {};
984 : : int rc;
985 : :
986 : : /* pmrctl enable */
987 : 6 : pctrlr.regs = ®s;
988 : 6 : pmrcap.bits.pmrtu = 0;
989 : 6 : pmrcap.bits.pmrto = 1;
990 : 6 : pmrsts.bits.nrdy = false;
991 : 6 : pmrctl.bits.en = 0;
992 : 6 : cap.bits.pmrs = 1;
993 : :
994 : 6 : rc = nvme_pcie_ctrlr_set_pmrctl(&pctrlr, &pmrctl);
995 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(rc == 0);
996 : 6 : rc = nvme_pcie_ctrlr_set_reg_8(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, cap.raw),
997 : : cap.raw);
998 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(rc == 0);
999 : 6 : rc = nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, pmrcap.raw),
1000 : : pmrcap.raw);
1001 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(rc == 0);
1002 : 6 : rc = nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, pmrsts.raw),
1003 : : pmrsts.raw);
1004 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(rc == 0);
1005 : :
1006 : 6 : rc = nvme_pcie_ctrlr_config_pmr(&pctrlr.ctrlr, true);
1007 : 6 : CU_ASSERT(rc == 0);
1008 : 6 : rc = nvme_pcie_ctrlr_get_pmrctl(&pctrlr, &pmrctl);
1009 : 6 : CU_ASSERT(rc == 0);
1010 : 6 : CU_ASSERT(pmrctl.bits.en == true);
1011 : :
1012 : : /* pmrctl disable */
1013 : 6 : pmrsts.bits.nrdy = true;
1014 : 6 : rc = nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, pmrsts.raw),
1015 : : pmrsts.raw);
1016 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(rc == 0);
1017 : 6 : rc = nvme_pcie_ctrlr_set_pmrctl(&pctrlr, &pmrctl);
1018 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(rc == 0);
1019 : :
1020 : 6 : rc = nvme_pcie_ctrlr_config_pmr(&pctrlr.ctrlr, false);
1021 : 6 : CU_ASSERT(rc == 0);
1022 : 6 : rc = nvme_pcie_ctrlr_get_pmrctl(&pctrlr, &pmrctl);
1023 : 6 : CU_ASSERT(rc == 0);
1024 : 6 : CU_ASSERT(pmrctl.bits.en == false);
1025 : :
1026 : : /* configuration exist */
1027 : 6 : rc = nvme_pcie_ctrlr_config_pmr(&pctrlr.ctrlr, false);
1028 : 6 : CU_ASSERT(rc == -EINVAL);
1029 : 6 : }
1030 : :
1031 : : static void
1032 : 36 : map_io_pmr_init(struct nvme_pcie_ctrlr *pctrlr, union spdk_nvme_pmrcap_register *pmrcap)
1033 : : {
1034 : 36 : pmrcap->raw = 0;
1035 : 36 : pmrcap->bits.rds = 1;
1036 : 36 : pmrcap->bits.wds = 1;
1037 : 36 : nvme_pcie_ctrlr_set_reg_4(&pctrlr->ctrlr, offsetof(struct spdk_nvme_registers, pmrcap.raw),
1038 : : pmrcap->raw);
1039 : 36 : pctrlr->regs->cap.bits.pmrs = 1;
1040 : 36 : pctrlr->pmr.mem_register_size = 0;
1041 : 36 : pctrlr->pmr.mem_register_addr = NULL;
1042 : 36 : pctrlr->pmr.bar_va = (void *)0x7F7C00E30000;
1043 : 36 : pctrlr->pmr.size = (1 << 22) * 128;
1044 : 36 : }
1045 : :
1046 : : static void
1047 : 6 : test_nvme_pcie_ctrlr_map_io_pmr(void)
1048 : : {
1049 : 6 : struct nvme_pcie_ctrlr pctrlr = {};
1050 : : struct spdk_nvme_ctrlr *ctrlr;
1051 : 6 : volatile struct spdk_nvme_registers regs = {};
1052 : 5 : union spdk_nvme_pmrcap_register pmrcap;
1053 : 6 : void *mem_reg_addr = NULL;
1054 : 6 : size_t rt_size = 0;
1055 : :
1056 : 6 : ctrlr = &pctrlr.ctrlr;
1057 : 6 : pctrlr.regs = ®s;
1058 : :
1059 : : /* PMR is not supported by the controller */
1060 : 6 : map_io_pmr_init(&pctrlr, &pmrcap);
1061 : 6 : regs.cap.bits.pmrs = 0;
1062 : :
1063 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_pmr(ctrlr, &rt_size);
1064 : 6 : CU_ASSERT(mem_reg_addr == NULL);
1065 : :
1066 : : /* mem_register_addr not NULL. */
1067 : 6 : map_io_pmr_init(&pctrlr, &pmrcap);
1068 : 6 : pctrlr.pmr.mem_register_addr = (void *)0xDEADBEEF;
1069 : 6 : pctrlr.pmr.mem_register_size = 1024;
1070 : :
1071 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_pmr(ctrlr, &rt_size);
1072 : 6 : CU_ASSERT(rt_size == 1024);
1073 : 6 : CU_ASSERT(mem_reg_addr == (void *)0xDEADBEEF);
1074 : :
1075 : : /* PMR not available */
1076 : 6 : map_io_pmr_init(&pctrlr, &pmrcap);
1077 : 6 : pctrlr.pmr.bar_va = NULL;
1078 : 6 : pctrlr.pmr.mem_register_addr = NULL;
1079 : :
1080 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_pmr(ctrlr, &rt_size);
1081 : 6 : CU_ASSERT(mem_reg_addr == NULL);
1082 : 6 : CU_ASSERT(rt_size == 0);
1083 : :
1084 : : /* WDS / RDS is not supported */
1085 : 6 : map_io_pmr_init(&pctrlr, &pmrcap);
1086 : 6 : pmrcap.bits.rds = 0;
1087 : 6 : pmrcap.bits.wds = 0;
1088 : 6 : nvme_pcie_ctrlr_set_reg_4(&pctrlr.ctrlr, offsetof(struct spdk_nvme_registers, pmrcap.raw),
1089 : : pmrcap.raw);
1090 : :
1091 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_pmr(ctrlr, &rt_size);
1092 : 6 : CU_ASSERT(mem_reg_addr == NULL);
1093 : 6 : CU_ASSERT(rt_size == 0);
1094 : :
1095 : : /* PMR is less than 4MiB in size then abort PMR mapping */
1096 : 6 : map_io_pmr_init(&pctrlr, &pmrcap);
1097 : 6 : pctrlr.pmr.size = (1ULL << 20);
1098 : :
1099 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_pmr(ctrlr, &rt_size);
1100 : 6 : CU_ASSERT(mem_reg_addr == NULL);
1101 : 6 : CU_ASSERT(rt_size == 0);
1102 : :
1103 : : /* All parameters success */
1104 : 6 : map_io_pmr_init(&pctrlr, &pmrcap);
1105 : :
1106 : 6 : mem_reg_addr = nvme_pcie_ctrlr_map_io_pmr(ctrlr, &rt_size);
1107 : 6 : CU_ASSERT(mem_reg_addr == (void *)0x7F7C01000000);
1108 : 6 : CU_ASSERT(rt_size == 0x1FE00000);
1109 : 6 : }
1110 : :
1111 : : int
1112 : 6 : main(int argc, char **argv)
1113 : : {
1114 : 6 : CU_pSuite suite = NULL;
1115 : : unsigned int num_failures;
1116 : :
1117 : 6 : CU_initialize_registry();
1118 : :
1119 : 6 : suite = CU_add_suite("nvme_pcie", NULL, NULL);
1120 : 6 : CU_ADD_TEST(suite, test_prp_list_append);
1121 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_hotplug_monitor);
1122 : 6 : CU_ADD_TEST(suite, test_shadow_doorbell_update);
1123 : 6 : CU_ADD_TEST(suite, test_build_contig_hw_sgl_request);
1124 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_qpair_build_metadata);
1125 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_qpair_build_prps_sgl_request);
1126 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_qpair_build_hw_sgl_request);
1127 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_qpair_build_contig_request);
1128 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_regs_get_set);
1129 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_map_unmap_cmb);
1130 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_map_io_cmb);
1131 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_map_unmap_pmr);
1132 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_config_pmr);
1133 : 6 : CU_ADD_TEST(suite, test_nvme_pcie_ctrlr_map_io_pmr);
1134 : :
1135 : 6 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
1136 : 6 : CU_cleanup_registry();
1137 : 6 : return num_failures;
1138 : : }
|