]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/nvme/host/pci.c
Merge tag 'uuid-for-4.13-2' of git://git.infradead.org/users/hch/uuid
[linux.git] / drivers / nvme / host / pci.c
index d10d2f279d19ad5b5924ffb16a70762f4548da42..8569ee7712693a880d8ece842f3b2ad9f1108fc9 100644 (file)
@@ -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 */