summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/qemu/qemu/hw-block-nvme-handle-dma-errors.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/qemu/qemu/hw-block-nvme-handle-dma-errors.patch')
-rw-r--r--meta/recipes-devtools/qemu/qemu/hw-block-nvme-handle-dma-errors.patch146
1 files changed, 146 insertions, 0 deletions
diff --git a/meta/recipes-devtools/qemu/qemu/hw-block-nvme-handle-dma-errors.patch b/meta/recipes-devtools/qemu/qemu/hw-block-nvme-handle-dma-errors.patch
new file mode 100644
index 0000000000..0fdae8351a
--- /dev/null
+++ b/meta/recipes-devtools/qemu/qemu/hw-block-nvme-handle-dma-errors.patch
@@ -0,0 +1,146 @@
1From ea2a7c7676d8eb9d1458eaa4b717df46782dcb3a Mon Sep 17 00:00:00 2001
2From: Gaurav Gupta <gauragup@cisco.com>
3Date: Wed, 29 Mar 2023 14:07:17 -0700
4Subject: [PATCH 2/2] hw/block/nvme: handle dma errors
5
6Handling DMA errors gracefully is required for the device to pass the
7block/011 test ("disable PCI device while doing I/O") in the blktests
8suite.
9
10With this patch the device sets the Controller Fatal Status bit in the
11CSTS register when failing to read from a submission queue or writing to
12a completion queue; expecting the host to reset the controller.
13
14If DMA errors occur at any other point in the execution of the command
15(say, while mapping the PRPs), the command is aborted with a Data
16Transfer Error status code.
17
18Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
19Signed-off-by: Gaurav Gupta <gauragup@cisco.com>
20---
21 hw/block/nvme.c | 41 +++++++++++++++++++++++++++++++----------
22 hw/block/trace-events | 3 +++
23 2 files changed, 34 insertions(+), 10 deletions(-)
24
25diff --git a/hw/block/nvme.c b/hw/block/nvme.c
26index e6f24a6..bda446d 100644
27--- a/hw/block/nvme.c
28+++ b/hw/block/nvme.c
29@@ -60,14 +60,14 @@ static bool nvme_addr_is_cmb(NvmeCtrl *n, hwaddr addr)
30 return addr >= low && addr < hi;
31 }
32
33-static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
34+static int nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
35 {
36 if (n->cmbsz && nvme_addr_is_cmb(n, addr)) {
37 memcpy(buf, (void *)&n->cmbuf[addr - n->ctrl_mem.addr], size);
38- return;
39+ return 0;
40 }
41
42- pci_dma_read(&n->parent_obj, addr, buf, size);
43+ return pci_dma_read(&n->parent_obj, addr, buf, size);
44 }
45
46 static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid)
47@@ -152,6 +152,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
48 hwaddr trans_len = n->page_size - (prp1 % n->page_size);
49 trans_len = MIN(len, trans_len);
50 int num_prps = (len >> n->page_bits) + 1;
51+ int ret;
52
53 if (unlikely(!prp1)) {
54 trace_nvme_err_invalid_prp();
55@@ -178,7 +179,11 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
56
57 nents = (len + n->page_size - 1) >> n->page_bits;
58 prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
59- nvme_addr_read(n, prp2, (void *)prp_list, prp_trans);
60+ ret = nvme_addr_read(n, prp2, (void *)prp_list, prp_trans);
61+ if (ret) {
62+ trace_pci_nvme_err_addr_read(prp2);
63+ return NVME_DATA_TRAS_ERROR;
64+ }
65 while (len != 0) {
66 uint64_t prp_ent = le64_to_cpu(prp_list[i]);
67
68@@ -191,8 +196,12 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1,
69 i = 0;
70 nents = (len + n->page_size - 1) >> n->page_bits;
71 prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
72- nvme_addr_read(n, prp_ent, (void *)prp_list,
73- prp_trans);
74+ ret = nvme_addr_read(n, prp_ent, (void *)prp_list,
75+ prp_trans);
76+ if (ret) {
77+ trace_pci_nvme_err_addr_read(prp_ent);
78+ return NVME_DATA_TRAS_ERROR;
79+ }
80 prp_ent = le64_to_cpu(prp_list[i]);
81 }
82
83@@ -286,6 +295,7 @@ static void nvme_post_cqes(void *opaque)
84 NvmeCQueue *cq = opaque;
85 NvmeCtrl *n = cq->ctrl;
86 NvmeRequest *req, *next;
87+ int ret;
88
89 QTAILQ_FOREACH_SAFE(req, &cq->req_list, entry, next) {
90 NvmeSQueue *sq;
91@@ -295,15 +305,21 @@ static void nvme_post_cqes(void *opaque)
92 break;
93 }
94
95- QTAILQ_REMOVE(&cq->req_list, req, entry);
96 sq = req->sq;
97 req->cqe.status = cpu_to_le16((req->status << 1) | cq->phase);
98 req->cqe.sq_id = cpu_to_le16(sq->sqid);
99 req->cqe.sq_head = cpu_to_le16(sq->head);
100 addr = cq->dma_addr + cq->tail * n->cqe_size;
101+ ret = pci_dma_write(&n->parent_obj, addr, (void *)&req->cqe,
102+ sizeof(req->cqe));
103+ if (ret) {
104+ trace_pci_nvme_err_addr_write(addr);
105+ trace_pci_nvme_err_cfs();
106+ n->bar.csts = NVME_CSTS_FAILED;
107+ break;
108+ }
109+ QTAILQ_REMOVE(&cq->req_list, req, entry);
110 nvme_inc_cq_tail(cq);
111- pci_dma_write(&n->parent_obj, addr, (void *)&req->cqe,
112- sizeof(req->cqe));
113 QTAILQ_INSERT_TAIL(&sq->req_list, req, entry);
114 }
115 if (cq->tail != cq->head) {
116@@ -888,7 +904,12 @@ static void nvme_process_sq(void *opaque)
117
118 while (!(nvme_sq_empty(sq) || QTAILQ_EMPTY(&sq->req_list))) {
119 addr = sq->dma_addr + sq->head * n->sqe_size;
120- nvme_addr_read(n, addr, (void *)&cmd, sizeof(cmd));
121+ if (nvme_addr_read(n, addr, (void *)&cmd, sizeof(cmd))) {
122+ trace_pci_nvme_err_addr_read(addr);
123+ trace_pci_nvme_err_cfs();
124+ n->bar.csts = NVME_CSTS_FAILED;
125+ break;
126+ }
127 nvme_inc_sq_head(sq);
128
129 req = QTAILQ_FIRST(&sq->req_list);
130diff --git a/hw/block/trace-events b/hw/block/trace-events
131index c03e80c..4e4ad4e 100644
132--- a/hw/block/trace-events
133+++ b/hw/block/trace-events
134@@ -60,6 +60,9 @@ nvme_mmio_shutdown_set(void) "shutdown bit set"
135 nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
136
137 # nvme traces for error conditions
138+pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64""
139+pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64""
140+pci_nvme_err_cfs(void) "controller fatal status"
141 nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
142 nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
143 nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
144--
1451.8.3.1
146