diff options
author | Padmakar Kalghatgi <p.kalghatgi@samsung.com> | 2021-04-09 12:55:48 +0530 |
---|---|---|
committer | Klaus Jensen <k.jensen@samsung.com> | 2021-04-12 08:55:20 +0200 |
commit | d357230b20e5f238e5ff6084cdf6d3231d27f0c6 (patch) | |
tree | 6b92cd8de59a3bf1cfdc851f1de23ccd1b299607 /hw | |
parent | a3d9f3a9629bfb22864e83e73f047cd62e9ba283 (diff) | |
download | qemu-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.c | 12 |
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) { |