|
@@ -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;
|
|
@@ -2282,7 +2299,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
|
|
|
result = nvme_dev_map(dev);
|
|
|
if (result)
|
|
|
- goto free;
|
|
|
+ goto put_pci;
|
|
|
|
|
|
INIT_WORK(&dev->ctrl.reset_work, nvme_reset_work);
|
|
|
INIT_WORK(&dev->remove_work, nvme_remove_dead_ctrl_work);
|
|
@@ -2291,7 +2308,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
|
|
|
result = nvme_setup_prp_pools(dev);
|
|
|
if (result)
|
|
|
- goto put_pci;
|
|
|
+ goto unmap;
|
|
|
|
|
|
quirks |= check_dell_samsung_bug(pdev);
|
|
|
|
|
@@ -2308,9 +2325,10 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
|
|
|
release_pools:
|
|
|
nvme_release_prp_pools(dev);
|
|
|
+ unmap:
|
|
|
+ nvme_dev_unmap(dev);
|
|
|
put_pci:
|
|
|
put_device(dev->dev);
|
|
|
- nvme_dev_unmap(dev);
|
|
|
free:
|
|
|
kfree(dev->queues);
|
|
|
kfree(dev);
|
|
@@ -2466,6 +2484,9 @@ static const struct pci_device_id nvme_id_table[] = {
|
|
|
{ PCI_VDEVICE(INTEL, 0x0a54),
|
|
|
.driver_data = NVME_QUIRK_STRIPE_SIZE |
|
|
|
NVME_QUIRK_DEALLOCATE_ZEROES, },
|
|
|
+ { PCI_VDEVICE(INTEL, 0x0a55),
|
|
|
+ .driver_data = NVME_QUIRK_STRIPE_SIZE |
|
|
|
+ NVME_QUIRK_DEALLOCATE_ZEROES, },
|
|
|
{ PCI_VDEVICE(INTEL, 0xf1a5), /* Intel 600P/P3100 */
|
|
|
.driver_data = NVME_QUIRK_NO_DEEPEST_PS },
|
|
|
{ PCI_VDEVICE(INTEL, 0x5845), /* Qemu emulated controller */
|