master
c 592 lines 16.7 KB
Raw
1 /*
2 * QTest testcase for NVMe
3 *
4 * Copyright (c) 2014 SUSE LINUX Products GmbH
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 */
9
10 #include "qemu/osdep.h"
11 #include <glib/gstdio.h>
12 #include "qemu/bswap.h"
13 #include "qemu/module.h"
14 #include "qemu/units.h"
15 #include "libqtest.h"
16 #include "libqtest-single.h"
17 #include "libqos/qgraph.h"
18 #include "libqos/pci.h"
19 #include "block/nvme.h"
20
21 typedef struct QNvme QNvme;
22
23 struct QNvme {
24 QOSGraphObject obj;
25 QPCIDevice dev;
26 };
27
28 static void *nvme_get_driver(void *obj, const char *interface)
29 {
30 QNvme *nvme = obj;
31
32 if (!g_strcmp0(interface, "pci-device")) {
33 return &nvme->dev;
34 }
35
36 fprintf(stderr, "%s not present in nvme\n", interface);
37 g_assert_not_reached();
38 }
39
40 static void *nvme_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
41 {
42 QNvme *nvme = g_new0(QNvme, 1);
43 QPCIBus *bus = pci_bus;
44
45 qpci_device_init(&nvme->dev, bus, addr);
46 nvme->obj.get_driver = nvme_get_driver;
47
48 return &nvme->obj;
49 }
50
51 /* This used to cause a NULL pointer dereference. */
52 static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc)
53 {
54 const int cmb_bar_size = 2 * MiB;
55 QNvme *nvme = obj;
56 QPCIDevice *pdev = &nvme->dev;
57 QPCIBar bar;
58
59 qpci_device_enable(pdev);
60 bar = qpci_iomap(pdev, 2, NULL);
61
62 qpci_io_writel(pdev, bar, 0, 0xccbbaa99);
63 g_assert_cmpint(qpci_io_readb(pdev, bar, 0), ==, 0x99);
64 g_assert_cmpint(qpci_io_readw(pdev, bar, 0), ==, 0xaa99);
65
66 /* Test partially out-of-bounds accesses. */
67 qpci_io_writel(pdev, bar, cmb_bar_size - 1, 0x44332211);
68 g_assert_cmpint(qpci_io_readb(pdev, bar, cmb_bar_size - 1), ==, 0x11);
69 g_assert_cmpint(qpci_io_readw(pdev, bar, cmb_bar_size - 1), !=, 0x2211);
70 g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211);
71 }
72
73 static void nvmetest_reg_read_test(void *obj, void *data, QGuestAllocator *alloc)
74 {
75 QNvme *nvme = obj;
76 QPCIDevice *pdev = &nvme->dev;
77 QPCIBar bar;
78 uint32_t cap_lo, cap_hi;
79 uint64_t cap;
80
81 qpci_device_enable(pdev);
82 bar = qpci_iomap(pdev, 0, NULL);
83
84 cap_lo = qpci_io_readl(pdev, bar, 0x0);
85 g_assert_cmpint(NVME_CAP_MQES(cap_lo), ==, 0x7ff);
86
87 cap_hi = qpci_io_readl(pdev, bar, 0x4);
88 g_assert_cmpint(NVME_CAP_MPSMAX((uint64_t)cap_hi << 32), ==, 0x4);
89
90 cap = qpci_io_readq(pdev, bar, 0x0);
91 g_assert_cmpint(NVME_CAP_MQES(cap), ==, 0x7ff);
92 g_assert_cmpint(NVME_CAP_MPSMAX(cap), ==, 0x4);
93
94 qpci_iounmap(pdev, bar);
95 }
96
97 static void nvmetest_pmr_reg_test(void *obj, void *data, QGuestAllocator *alloc)
98 {
99 QNvme *nvme = obj;
100 QPCIDevice *pdev = &nvme->dev;
101 QPCIBar pmr_bar, nvme_bar;
102 uint32_t pmrcap, pmrsts;
103
104 qpci_device_enable(pdev);
105 pmr_bar = qpci_iomap(pdev, 4, NULL);
106
107 /* Without Enabling PMRCTL check bar enablemet */
108 qpci_io_writel(pdev, pmr_bar, 0, 0xccbbaa99);
109 g_assert_cmpint(qpci_io_readb(pdev, pmr_bar, 0), !=, 0x99);
110 g_assert_cmpint(qpci_io_readw(pdev, pmr_bar, 0), !=, 0xaa99);
111
112 /* Map NVMe Bar Register to Enable the Mem Region */
113 nvme_bar = qpci_iomap(pdev, 0, NULL);
114
115 pmrcap = qpci_io_readl(pdev, nvme_bar, 0xe00);
116 g_assert_cmpint(NVME_PMRCAP_RDS(pmrcap), ==, 0x1);
117 g_assert_cmpint(NVME_PMRCAP_WDS(pmrcap), ==, 0x1);
118 g_assert_cmpint(NVME_PMRCAP_BIR(pmrcap), ==, 0x4);
119 g_assert_cmpint(NVME_PMRCAP_PMRWBM(pmrcap), ==, 0x2);
120 g_assert_cmpint(NVME_PMRCAP_CMSS(pmrcap), ==, 0x1);
121
122 /* Enable PMRCTRL */
123 qpci_io_writel(pdev, nvme_bar, 0xe04, 0x1);
124
125 qpci_io_writel(pdev, pmr_bar, 0, 0x44332211);
126 g_assert_cmpint(qpci_io_readb(pdev, pmr_bar, 0), ==, 0x11);
127 g_assert_cmpint(qpci_io_readw(pdev, pmr_bar, 0), ==, 0x2211);
128 g_assert_cmpint(qpci_io_readl(pdev, pmr_bar, 0), ==, 0x44332211);
129
130 pmrsts = qpci_io_readl(pdev, nvme_bar, 0xe08);
131 g_assert_cmpint(NVME_PMRSTS_NRDY(pmrsts), ==, 0x0);
132
133 /* Disable PMRCTRL */
134 qpci_io_writel(pdev, nvme_bar, 0xe04, 0x0);
135
136 qpci_io_writel(pdev, pmr_bar, 0, 0x88776655);
137 g_assert_cmpint(qpci_io_readb(pdev, pmr_bar, 0), !=, 0x55);
138 g_assert_cmpint(qpci_io_readw(pdev, pmr_bar, 0), !=, 0x6655);
139 g_assert_cmpint(qpci_io_readl(pdev, pmr_bar, 0), !=, 0x88776655);
140
141 pmrsts = qpci_io_readl(pdev, nvme_bar, 0xe08);
142 g_assert_cmpint(NVME_PMRSTS_NRDY(pmrsts), ==, 0x1);
143
144 qpci_iounmap(pdev, nvme_bar);
145 qpci_iounmap(pdev, pmr_bar);
146 }
147
148 typedef struct nvme_ctrl nvme_ctrl;
149
150 typedef struct nvme_queue {
151 nvme_ctrl *ctrl;
152 uint64_t doorbell;
153 uint32_t size;
154 } nvme_queue;
155
156 typedef struct nvme_cq {
157 nvme_queue common;
158 uint64_t phys_cqe; /* NvmeCqe* */
159 uint16_t head;
160 uint8_t phase;
161 } nvme_cq;
162
163 typedef struct nvme_sq {
164 nvme_queue common;
165 uint64_t phys_sqe; /* NvmeCmd* */
166 nvme_cq *cq;
167 uint16_t head;
168 uint16_t tail;
169 } nvme_sq;
170
171 struct nvme_ctrl {
172 QGuestAllocator *alloc;
173 QPCIDevice *pdev;
174 QPCIBar bar;
175
176 uint32_t db_stride;
177
178 nvme_sq admin_sq;
179 nvme_cq admin_cq;
180 };
181
182 #define PHYS_ADDR_OF_FIELD(T, base_phys_addr, field) \
183 ((uint64_t)&((T *)(base_phys_addr))->field)
184
185 #define PHYS_ADDR_OF(T, base_phys_addr, accessor) \
186 ((uint64_t)&((T *)(base_phys_addr))accessor)
187
188 static void nvme_init_queue_common(nvme_ctrl *ctrl, nvme_queue *q,
189 uint16_t db_idx, uint32_t size)
190 {
191 q->ctrl = ctrl;
192 q->doorbell = (sizeof(NvmeBar) + db_idx * ctrl->db_stride);
193 g_test_message(" q %p db_idx %u doorbell 0x%" PRIx64, q, db_idx, q->doorbell);
194 q->size = size;
195 }
196
197 static void nvme_init_sq(nvme_ctrl *ctrl, nvme_sq *sq, uint16_t db_idx,
198 uint32_t size, nvme_cq *cq)
199 {
200 nvme_init_queue_common(ctrl, &sq->common, db_idx, size);
201
202 sq->phys_sqe = guest_alloc(ctrl->alloc, sizeof(NvmeCmd) * size);
203 g_assert(sq->phys_sqe);
204
205 g_test_message("sq %p db_idx %u sqe 0x%" PRIx64, sq, db_idx, sq->phys_sqe);
206 sq->cq = cq;
207 sq->head = 0;
208 sq->tail = 0;
209 }
210
211 static void nvme_init_cq(nvme_ctrl *ctrl, nvme_cq *cq, uint16_t db_idx,
212 uint32_t size)
213 {
214 nvme_init_queue_common(ctrl, &cq->common, db_idx, size);
215
216 cq->phys_cqe = guest_alloc(ctrl->alloc, sizeof(NvmeCqe) * size);
217 g_assert(cq->phys_cqe);
218
219 g_test_message("cq %p db_idx %u cqe 0x%" PRIx64, cq, db_idx, cq->phys_cqe);
220 cq->head = 0;
221 cq->phase = 1;
222 }
223
224 static int nvme_cqe_pending(nvme_cq *cq)
225 {
226 uint16_t status = qtest_readw(
227 cq->common.ctrl->pdev->bus->qts,
228 PHYS_ADDR_OF(NvmeCqe, cq->phys_cqe, [cq->head].status));
229 return (status & 1) == cq->phase;
230 }
231
232 static int nvme_is_cqe_success(NvmeCqe *cqe)
233 {
234 return (le16_to_cpu(cqe->status) >> 1) == NVME_SUCCESS;
235 }
236
237 static NvmeCqe nvme_handle_cqe(nvme_sq *sq)
238 {
239 nvme_cq *cq = sq->cq;
240 uint64_t phys_cqe = PHYS_ADDR_OF(
241 NvmeCqe, cq->phys_cqe, [cq->head]); /* NvmeCqe* */
242 NvmeCqe cqe;
243 uint16_t cq_next_head;
244
245 g_assert(nvme_cqe_pending(cq));
246
247 qtest_memread(sq->common.ctrl->pdev->bus->qts, phys_cqe, &cqe, sizeof(cqe));
248
249 cq_next_head = (cq->head + 1) % cq->common.size;
250 g_test_message("cq %p head %u -> %u", cq, cq->head, cq_next_head);
251 if (cq_next_head < cq->head) {
252 cq->phase ^= 1;
253 }
254 cq->head = cq_next_head;
255
256 if (cqe.sq_head != sq->head) {
257 sq->head = cqe.sq_head;
258 g_test_message("sq %p head = %u", sq, sq->head);
259 }
260
261 qpci_io_writel(cq->common.ctrl->pdev, cq->common.ctrl->bar,
262 cq->common.doorbell, cq->head);
263
264 return cqe;
265 }
266
267 static NvmeCqe nvme_wait(nvme_sq *sq)
268 {
269 int i;
270 bool ready = false;
271
272 for (i = 0; i < 10; i++) {
273 if (nvme_cqe_pending(sq->cq)) {
274 ready = true;
275 break;
276 }
277
278 g_usleep(1000);
279 }
280
281 g_assert(ready);
282
283 return nvme_handle_cqe(sq);
284 }
285
286 static uint64_t nvme_get_next_sqe(nvme_sq *sq, uint8_t opcode,
287 uint16_t cid, uint64_t prp1)
288 {
289 uint64_t phys_sqe = PHYS_ADDR_OF(NvmeCmd, sq->phys_sqe, [sq->tail]);
290
291 if (((sq->tail + 1) % sq->common.size) == sq->head) {
292 /* no space in SQ */
293 g_test_message("%s head %d tail %d", __func__, sq->head, sq->tail);
294 g_assert_not_reached();
295 return 0;
296 }
297
298 qtest_memset(sq->common.ctrl->pdev->bus->qts,
299 phys_sqe, 0, sizeof(NvmeCmd));
300
301 #define GUEST_MEM_WRITE(fn, phys_addr, val) \
302 fn(sq->common.ctrl->pdev->bus->qts, phys_addr, (val))
303
304 GUEST_MEM_WRITE(qtest_writeb,
305 PHYS_ADDR_OF_FIELD(NvmeCmd, phys_sqe, opcode), opcode);
306 GUEST_MEM_WRITE(qtest_writew,
307 PHYS_ADDR_OF_FIELD(NvmeCmd, phys_sqe, cid), cid);
308 GUEST_MEM_WRITE(qtest_writeq,
309 PHYS_ADDR_OF_FIELD(NvmeCmd, phys_sqe, dptr.prp1), prp1);
310
311 #undef GUEST_MEM_WRITE
312
313 g_test_message("sq %p next_sqe %u sqe 0x%" PRIx64, sq, sq->tail, phys_sqe);
314 return phys_sqe;
315 }
316
317 static void nvme_commit_sqe(nvme_sq *sq)
318 {
319 g_test_message("sq %p commit sqe tail %u", sq, sq->tail);
320 sq->tail = (sq->tail + 1) % sq->common.size;
321 qpci_io_writel(sq->common.ctrl->pdev, sq->common.ctrl->bar,
322 sq->common.doorbell, sq->tail);
323 }
324
325 static uint64_t nvme_admin_identify_ctrl(nvme_ctrl *ctrl,
326 uint16_t cid, bool no_wait)
327 {
328 uint64_t phys_cmd_identify; /* NvmeCmd* */
329 uint64_t phys_identify; /* NvmeIdCtrl* */
330 NvmeCqe cqe;
331
332 g_test_message("sending req cid %u no_wait %d", cid, no_wait);
333
334 phys_identify = guest_alloc(ctrl->alloc, sizeof(NvmeIdCtrl));
335 g_assert(phys_identify);
336
337 phys_cmd_identify = nvme_get_next_sqe(&ctrl->admin_sq,
338 NVME_ADM_CMD_IDENTIFY, cid,
339 phys_identify);
340 g_assert(phys_cmd_identify);
341
342 #define GUEST_MEM_WRITE(fn, phys_addr, val) \
343 fn(ctrl->pdev->bus->qts, phys_addr, (val))
344
345 GUEST_MEM_WRITE(qtest_writel,
346 PHYS_ADDR_OF_FIELD(NvmeCmd, phys_cmd_identify, nsid), 0);
347 GUEST_MEM_WRITE(qtest_writel,
348 PHYS_ADDR_OF_FIELD(NvmeIdentify, phys_cmd_identify, cns),
349 NVME_ID_CNS_CTRL);
350
351 #undef GUEST_MEM_WRITE
352
353 nvme_commit_sqe(&ctrl->admin_sq);
354
355 if (no_wait) {
356 return phys_identify;
357 }
358
359 cqe = nvme_wait(&ctrl->admin_sq);
360 g_assert(nvme_is_cqe_success(&cqe));
361 g_assert(le16_to_cpu(cqe.cid) == cid);
362
363 return phys_identify;
364 }
365
366 static void nvme_wait_ready(nvme_ctrl *ctrl, int val)
367 {
368 int i;
369
370 for (i = 0; i < 10; i++) {
371 uint32_t csts = qpci_io_readl(ctrl->pdev, ctrl->bar, NVME_REG_CSTS);
372 g_test_message("%s: csts %x", __func__, csts);
373
374 if (NVME_CSTS_RDY(csts) == val) {
375 return;
376 }
377
378 g_usleep(1000);
379 }
380
381 g_assert_not_reached();
382 }
383
384 static void test_migrate_setup_nvme_ctrl(nvme_ctrl *ctrl)
385 {
386 uint64_t cap;
387
388 /* disable controller */
389 qpci_io_writel(ctrl->pdev, ctrl->bar, NVME_REG_CC, 0);
390 nvme_wait_ready(ctrl, 0);
391
392 cap = qpci_io_readq(ctrl->pdev, ctrl->bar, NVME_REG_CAP);
393 ctrl->db_stride = 4 << NVME_CAP_DSTRD(cap);
394
395 nvme_init_cq(ctrl, &ctrl->admin_cq, 1, 2 /* CQEs num */);
396 nvme_init_sq(ctrl, &ctrl->admin_sq, 0, 4 /* SQEs num */, &ctrl->admin_cq);
397
398 qpci_io_writel(ctrl->pdev, ctrl->bar, NVME_REG_AQA,
399 ((ctrl->admin_cq.common.size - 1) << AQA_ACQS_SHIFT) |
400 ((ctrl->admin_sq.common.size - 1) << AQA_ASQS_SHIFT)
401 );
402
403 qpci_io_writeq(ctrl->pdev, ctrl->bar,
404 NVME_REG_ASQ, (uint64_t)ctrl->admin_sq.phys_sqe);
405 qpci_io_writeq(ctrl->pdev, ctrl->bar,
406 NVME_REG_ACQ, (uint64_t)ctrl->admin_cq.phys_cqe);
407
408 /* enable controller */
409 {
410 uint32_t cc = 0;
411 NVME_SET_CC_EN(cc, 1);
412 qpci_io_writel(ctrl->pdev, ctrl->bar, NVME_REG_CC, cc);
413 }
414
415 nvme_wait_ready(ctrl, 1);
416 }
417
418 typedef struct test_migrate_req {
419 uint16_t cid;
420 bool handle_cqe;
421 uint64_t phys_identify; /* NvmeIdCtrl* */
422 } test_migrate_req;
423
424 static void test_migrate_send_nvme_reqs(nvme_ctrl *ctrl, test_migrate_req *reqs,
425 int num)
426 {
427 int i;
428
429 for (i = 0; i < num; i++) {
430 reqs[i].phys_identify = nvme_admin_identify_ctrl(ctrl, reqs[i].cid,
431 !reqs[i].handle_cqe);
432 g_assert(reqs[i].phys_identify);
433
434 if (reqs[i].handle_cqe) {
435 guest_free(ctrl->alloc, reqs[i].phys_identify);
436 }
437 }
438 }
439
440 static void test_migrate_check_nvme(nvme_ctrl *ctrl,
441 test_migrate_req *reqs, int num)
442 {
443 int i;
444
445 for (i = 0; i < num; i++) {
446 NvmeCqe cqe;
447
448 if (reqs[i].handle_cqe) {
449 continue;
450 }
451
452 cqe = nvme_wait(&ctrl->admin_sq);
453 g_assert(nvme_is_cqe_success(&cqe));
454
455 g_assert_cmpint(le16_to_cpu(cqe.cid), ==, reqs[i].cid);
456
457 #define GUEST_MEM_READB(phys_addr) \
458 qtest_readb(ctrl->pdev->bus->qts, (phys_addr))
459
460 g_assert_cmpint(GUEST_MEM_READB(
461 PHYS_ADDR_OF_FIELD(NvmeIdCtrl, reqs[i].phys_identify, ieee[0])),
462 ==, 0x0);
463 g_assert_cmpint(GUEST_MEM_READB(
464 PHYS_ADDR_OF_FIELD(NvmeIdCtrl, reqs[i].phys_identify, ieee[1])),
465 ==, 0x54);
466 g_assert_cmpint(GUEST_MEM_READB(
467 PHYS_ADDR_OF_FIELD(NvmeIdCtrl, reqs[i].phys_identify, ieee[2])),
468 ==, 0x52);
469
470 #undef GUEST_MEM_READB
471
472 guest_free(ctrl->alloc, reqs[i].phys_identify);
473 }
474 }
475
476 static void test_migrate(void *obj, void *data, QGuestAllocator *alloc)
477 {
478 g_autofree gchar *tmpfs = NULL;
479 GError *err = NULL;
480 g_autofree gchar *mig_path = NULL;
481 g_autofree gchar *uri = NULL;
482 GString *dest_cmdline;
483 QTestState *to;
484 QDict *rsp;
485 QNvme *nvme = obj;
486 QPCIDevice *pdev = &nvme->dev;
487 g_autofree nvme_ctrl *ctrl = NULL;
488 test_migrate_req test_reqs[] = {
489 { 123, true },
490 { 456, false },
491 { 300, false },
492 { 333, false }
493 };
494
495 if (qpci_check_buggy_msi(pdev)) {
496 return;
497 }
498
499 /* create temporary dir and prepare unix socket path for migration */
500 tmpfs = g_dir_make_tmp("nvme-test-XXXXXX", &err);
501 if (!tmpfs) {
502 g_test_message("Can't create temporary directory in %s: %s",
503 g_get_tmp_dir(), err->message);
504 g_error_free(err);
505 }
506 g_assert(tmpfs);
507
508 mig_path = g_strdup_printf("%s/socket.mig", tmpfs);
509 uri = g_strdup_printf("unix:%s", mig_path);
510
511 /* enable NVMe PCI device */
512 qpci_device_enable(pdev);
513
514 ctrl = g_malloc0(sizeof(*ctrl));
515 ctrl->alloc = alloc;
516 ctrl->pdev = pdev;
517 ctrl->bar = qpci_iomap(ctrl->pdev, 0, NULL);
518 g_assert(pdev->bus->qts == global_qtest);
519
520 test_migrate_setup_nvme_ctrl(ctrl);
521 test_migrate_send_nvme_reqs(ctrl, test_reqs, ARRAY_SIZE(test_reqs));
522
523 qpci_iounmap(ctrl->pdev, ctrl->bar);
524
525 dest_cmdline = g_string_new(qos_get_current_command_line());
526 g_string_append_printf(dest_cmdline, " -incoming %s", uri);
527
528 /* Create destination VM */
529 to = qtest_init(dest_cmdline->str);
530
531 /* Get access to PCI device from destination VM */
532 nvme = qos_allocate_objects(to, &ctrl->alloc);
533 pdev = &nvme->dev;
534 ctrl->pdev = pdev;
535 ctrl->bar = qpci_iomap(ctrl->pdev, 0, NULL);
536 g_assert(pdev->bus->qts == to);
537
538 /* Migrate VM */
539 rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri);
540 g_assert(qdict_haskey(rsp, "return"));
541 qobject_unref(rsp);
542
543 /* Wait when source VM is stopped */
544 qmp_eventwait("STOP");
545
546 /* Copy guest physical memory allocator state */
547 migrate_allocator(alloc, ctrl->alloc);
548
549 /* Wait for destination VM to become alive */
550 qtest_qmp_eventwait(to, "RESUME");
551
552 test_migrate_check_nvme(ctrl, test_reqs, ARRAY_SIZE(test_reqs));
553
554 qpci_iounmap(ctrl->pdev, ctrl->bar);
555
556 qtest_quit(to);
557 g_unlink(mig_path);
558 g_rmdir(tmpfs);
559 g_string_free(dest_cmdline, true);
560 }
561
562 static void nvme_register_nodes(void)
563 {
564 QOSGraphEdgeOptions opts = {
565 .extra_device_opts = "addr=04.0,drive=drv0,serial=foo",
566 .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
567 "file.read-zeroes=on,format=raw "
568 "-object memory-backend-ram,id=pmr0,"
569 "share=on,size=16",
570 };
571
572 add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
573
574 qos_node_create_driver("nvme", nvme_create);
575 qos_node_consumes("nvme", "pci-bus", &opts);
576 qos_node_produces("nvme", "pci-device");
577
578 qos_add_test("oob-cmb-access", "nvme", nvmetest_oob_cmb_test, &(QOSGraphTestOptions) {
579 .edge.extra_device_opts = "cmb_size_mb=2"
580 });
581
582 qos_add_test("pmr-test-access", "nvme", nvmetest_pmr_reg_test,
583 &(QOSGraphTestOptions) {
584 .edge.extra_device_opts = "pmrdev=pmr0"
585 });
586
587 qos_add_test("reg-read", "nvme", nvmetest_reg_read_test, NULL);
588
589 qos_add_test("migrate", "nvme", test_migrate, NULL);
590 }
591
592 libqos_init(nvme_register_nodes);