hw/block/nvme: fix prp mapping status codes
Address 0 is not an invalid address. Remove those invalikd checks. Unaligned PRP2 and PRP list entries should result in Invalid PRP Offset status code and not Invalid Field. Fix that. See NVMe Express v1.3d, Section 4.3 ("Physical Region Page Entry and List"). Suggested-by: Keith Busch <kbusch@kernel.org> Signed-off-by: Gollu Appalanaidu <anaidu.gollu@samsung.com> Signed-off-by: Klaus Jensen <k.jensen@samsung.com> Reviewed-by: Keith Busch <kbusch@kernel.org>
This commit is contained in:
parent
b865cabf73
commit
28fee5b5d0
@ -327,11 +327,6 @@ static uint16_t nvme_map_prp(NvmeCtrl *n, uint64_t prp1, uint64_t prp2,
|
|||||||
|
|
||||||
trace_pci_nvme_map_prp(trans_len, len, prp1, prp2, num_prps);
|
trace_pci_nvme_map_prp(trans_len, len, prp1, prp2, num_prps);
|
||||||
|
|
||||||
if (unlikely(!prp1)) {
|
|
||||||
trace_pci_nvme_err_invalid_prp();
|
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nvme_addr_is_cmb(n, prp1)) {
|
if (nvme_addr_is_cmb(n, prp1)) {
|
||||||
qemu_iovec_init(iov, num_prps);
|
qemu_iovec_init(iov, num_prps);
|
||||||
} else {
|
} else {
|
||||||
@ -345,11 +340,6 @@ static uint16_t nvme_map_prp(NvmeCtrl *n, uint64_t prp1, uint64_t prp2,
|
|||||||
|
|
||||||
len -= trans_len;
|
len -= trans_len;
|
||||||
if (len) {
|
if (len) {
|
||||||
if (unlikely(!prp2)) {
|
|
||||||
trace_pci_nvme_err_invalid_prp2_missing();
|
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > n->page_size) {
|
if (len > n->page_size) {
|
||||||
uint64_t prp_list[n->max_prp_ents];
|
uint64_t prp_list[n->max_prp_ents];
|
||||||
uint32_t nents, prp_trans;
|
uint32_t nents, prp_trans;
|
||||||
@ -370,9 +360,9 @@ static uint16_t nvme_map_prp(NvmeCtrl *n, uint64_t prp1, uint64_t prp2,
|
|||||||
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
|
uint64_t prp_ent = le64_to_cpu(prp_list[i]);
|
||||||
|
|
||||||
if (i == n->max_prp_ents - 1 && len > n->page_size) {
|
if (i == n->max_prp_ents - 1 && len > n->page_size) {
|
||||||
if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
|
if (unlikely(prp_ent & (n->page_size - 1))) {
|
||||||
trace_pci_nvme_err_invalid_prplist_ent(prp_ent);
|
trace_pci_nvme_err_invalid_prplist_ent(prp_ent);
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
return NVME_INVALID_PRP_OFFSET | NVME_DNR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prp_list_in_cmb != nvme_addr_is_cmb(n, prp_ent)) {
|
if (prp_list_in_cmb != nvme_addr_is_cmb(n, prp_ent)) {
|
||||||
@ -391,9 +381,9 @@ static uint16_t nvme_map_prp(NvmeCtrl *n, uint64_t prp1, uint64_t prp2,
|
|||||||
prp_ent = le64_to_cpu(prp_list[i]);
|
prp_ent = le64_to_cpu(prp_list[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
|
if (unlikely(prp_ent & (n->page_size - 1))) {
|
||||||
trace_pci_nvme_err_invalid_prplist_ent(prp_ent);
|
trace_pci_nvme_err_invalid_prplist_ent(prp_ent);
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
return NVME_INVALID_PRP_OFFSET | NVME_DNR;
|
||||||
}
|
}
|
||||||
|
|
||||||
trans_len = MIN(len, n->page_size);
|
trans_len = MIN(len, n->page_size);
|
||||||
@ -408,7 +398,7 @@ static uint16_t nvme_map_prp(NvmeCtrl *n, uint64_t prp1, uint64_t prp2,
|
|||||||
} else {
|
} else {
|
||||||
if (unlikely(prp2 & (n->page_size - 1))) {
|
if (unlikely(prp2 & (n->page_size - 1))) {
|
||||||
trace_pci_nvme_err_invalid_prp2_align(prp2);
|
trace_pci_nvme_err_invalid_prp2_align(prp2);
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
return NVME_INVALID_PRP_OFFSET | NVME_DNR;
|
||||||
}
|
}
|
||||||
status = nvme_map_addr(n, qsg, iov, prp2, len);
|
status = nvme_map_addr(n, qsg, iov, prp2, len);
|
||||||
if (status) {
|
if (status) {
|
||||||
|
@ -97,10 +97,8 @@ pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRI
|
|||||||
pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8""
|
pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8""
|
||||||
pci_nvme_err_invalid_sgl_excess_length(uint16_t cid) "cid %"PRIu16""
|
pci_nvme_err_invalid_sgl_excess_length(uint16_t cid) "cid %"PRIu16""
|
||||||
pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
|
pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
|
||||||
pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
|
pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is not page aligned: 0x%"PRIx64""
|
||||||
pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
|
pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
|
||||||
pci_nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred"
|
|
||||||
pci_nvme_err_invalid_prp(void) "invalid PRP"
|
|
||||||
pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
|
pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
|
||||||
pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
|
pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
|
||||||
pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
|
pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
|
||||||
|
@ -655,6 +655,7 @@ enum NvmeStatusCodes {
|
|||||||
NVME_MD_SGL_LEN_INVALID = 0x0010,
|
NVME_MD_SGL_LEN_INVALID = 0x0010,
|
||||||
NVME_SGL_DESCR_TYPE_INVALID = 0x0011,
|
NVME_SGL_DESCR_TYPE_INVALID = 0x0011,
|
||||||
NVME_INVALID_USE_OF_CMB = 0x0012,
|
NVME_INVALID_USE_OF_CMB = 0x0012,
|
||||||
|
NVME_INVALID_PRP_OFFSET = 0x0013,
|
||||||
NVME_LBA_RANGE = 0x0080,
|
NVME_LBA_RANGE = 0x0080,
|
||||||
NVME_CAP_EXCEEDED = 0x0081,
|
NVME_CAP_EXCEEDED = 0x0081,
|
||||||
NVME_NS_NOT_READY = 0x0082,
|
NVME_NS_NOT_READY = 0x0082,
|
||||||
|
Loading…
Reference in New Issue
Block a user