|
@@ -539,7 +539,7 @@ static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
|
|
|
+static blk_status_t nvme_setup_prps(struct nvme_dev *dev, struct request *req)
|
|
|
{
|
|
|
struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
|
|
|
struct dma_pool *pool;
|
|
@@ -556,7 +556,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
|
|
|
|
|
|
length -= (page_size - offset);
|
|
|
if (length <= 0)
|
|
|
- return true;
|
|
|
+ return BLK_STS_OK;
|
|
|
|
|
|
dma_len -= (page_size - offset);
|
|
|
if (dma_len) {
|
|
@@ -569,7 +569,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
|
|
|
|
|
|
if (length <= page_size) {
|
|
|
iod->first_dma = dma_addr;
|
|
|
- return true;
|
|
|
+ return BLK_STS_OK;
|
|
|
}
|
|
|
|
|
|
nprps = DIV_ROUND_UP(length, page_size);
|
|
@@ -585,7 +585,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
|
|
|
if (!prp_list) {
|
|
|
iod->first_dma = dma_addr;
|
|
|
iod->npages = -1;
|
|
|
- return false;
|
|
|
+ return BLK_STS_RESOURCE;
|
|
|
}
|
|
|
list[0] = prp_list;
|
|
|
iod->first_dma = prp_dma;
|
|
@@ -595,7 +595,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
|
|
|
__le64 *old_prp_list = prp_list;
|
|
|
prp_list = dma_pool_alloc(pool, GFP_ATOMIC, &prp_dma);
|
|
|
if (!prp_list)
|
|
|
- return false;
|
|
|
+ return BLK_STS_RESOURCE;
|
|
|
list[iod->npages++] = prp_list;
|
|
|
prp_list[0] = old_prp_list[i - 1];
|
|
|
old_prp_list[i - 1] = cpu_to_le64(prp_dma);
|
|
@@ -609,13 +609,29 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
|
|
|
break;
|
|
|
if (dma_len > 0)
|
|
|
continue;
|
|
|
- BUG_ON(dma_len < 0);
|
|
|
+ if (unlikely(dma_len < 0))
|
|
|
+ goto bad_sgl;
|
|
|
sg = sg_next(sg);
|
|
|
dma_addr = sg_dma_address(sg);
|
|
|
dma_len = sg_dma_len(sg);
|
|
|
}
|
|
|
|
|
|
- return true;
|
|
|
+ return BLK_STS_OK;
|
|
|
+
|
|
|
+ bad_sgl:
|
|
|
+ if (WARN_ONCE(1, "Invalid SGL for payload:%d nents:%d\n",
|
|
|
+ blk_rq_payload_bytes(req), iod->nents)) {
|
|
|
+ for_each_sg(iod->sg, sg, iod->nents, i) {
|
|
|
+ dma_addr_t phys = sg_phys(sg);
|
|
|
+ pr_warn("sg[%d] phys_addr:%pad offset:%d length:%d "
|
|
|
+ "dma_address:%pad dma_length:%d\n", i, &phys,
|
|
|
+ sg->offset, sg->length,
|
|
|
+ &sg_dma_address(sg),
|
|
|
+ sg_dma_len(sg));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return BLK_STS_IOERR;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
|
|
@@ -637,7 +653,8 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
|
|
|
DMA_ATTR_NO_WARN))
|
|
|
goto out;
|
|
|
|
|
|
- if (!nvme_setup_prps(dev, req))
|
|
|
+ ret = nvme_setup_prps(dev, req);
|
|
|
+ if (ret != BLK_STS_OK)
|
|
|
goto out_unmap;
|
|
|
|
|
|
ret = BLK_STS_IOERR;
|