aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPadmakar Kalghatgi <p.kalghatgi@samsung.com>2021-04-09 12:55:48 +0530
committerKlaus Jensen <k.jensen@samsung.com>2021-04-12 08:55:20 +0200
commitd357230b20e5f238e5ff6084cdf6d3231d27f0c6 (patch)
tree6b92cd8de59a3bf1cfdc851f1de23ccd1b299607 /hw
parenta3d9f3a9629bfb22864e83e73f047cd62e9ba283 (diff)
downloadqemu-d357230b20e5f238e5ff6084cdf6d3231d27f0c6.zip
qemu-d357230b20e5f238e5ff6084cdf6d3231d27f0c6.tar.gz
qemu-d357230b20e5f238e5ff6084cdf6d3231d27f0c6.tar.bz2
hw/block/nvme: map prp fix if prp2 contains non-zero offset
nvme_map_prp needs to calculate the number of list entries based on the offset value. For the subsequent PRP2 list, need to ensure the number of entries is within the MAX number of PRP entries for a page. Signed-off-by: Padmakar Kalghatgi <p.kalghatgi@samsung.com> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/block/nvme.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 6b1f056..8633615 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -655,7 +655,12 @@ static uint16_t nvme_map_prp(NvmeCtrl *n, NvmeSg *sg, uint64_t prp1,
uint32_t nents, prp_trans;
int i = 0;
- nents = (len + n->page_size - 1) >> n->page_bits;
+ /*
+ * The first PRP list entry, pointed to by PRP2 may contain offset.
+ * Hence, we need to calculate the number of entries in based on
+ * that offset.
+ */
+ nents = (n->page_size - (prp2 & (n->page_size - 1))) >> 3;
prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
ret = nvme_addr_read(n, prp2, (void *)prp_list, prp_trans);
if (ret) {
@@ -666,7 +671,7 @@ static uint16_t nvme_map_prp(NvmeCtrl *n, NvmeSg *sg, uint64_t prp1,
while (len != 0) {
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
- if (i == n->max_prp_ents - 1 && len > n->page_size) {
+ if (i == nents - 1 && len > n->page_size) {
if (unlikely(prp_ent & (n->page_size - 1))) {
trace_pci_nvme_err_invalid_prplist_ent(prp_ent);
status = NVME_INVALID_PRP_OFFSET | NVME_DNR;
@@ -675,7 +680,8 @@ static uint16_t nvme_map_prp(NvmeCtrl *n, NvmeSg *sg, uint64_t prp1,
i = 0;
nents = (len + n->page_size - 1) >> n->page_bits;
- prp_trans = MIN(n->max_prp_ents, nents) * sizeof(uint64_t);
+ nents = MIN(nents, n->max_prp_ents);
+ prp_trans = nents * sizeof(uint64_t);
ret = nvme_addr_read(n, prp_ent, (void *)prp_list,
prp_trans);
if (ret) {