aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2013-12-10 15:10:39 -0500
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2014-01-27 19:28:43 -0500
commit0e53d18051725da46cbccfb7874a6422d4d4f274 (patch)
treea14f539eae97f2774956978826f6af06d7784943 /drivers/block
parentc30341dc3c436cf43508cd44cdfbb3810c38c195 (diff)
NVMe: Surprise removal handling
This adds checks to see if the nvme pci device was removed. The check reads the status register for the value of -1, which it should never be unless the device is no longer present. If a user performs a surprise removal on an nvme device, the driver will be notified either by the pci driver remove callback if the platform's slot is capable of this event, or via reading the device BAR status register, which will indicate controller failure and trigger a reset. Either way, the device is not present so all outstanding commands would timeout. This will not send queue deletion commands to a drive that isn't present and fail after ioremap, significantly speeding up surprise removal; previously this took over 2 minutes per IO queue pair created, but this will complete removing the device within a few seconds. Signed-off-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/nvme-core.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index 75049532df96..a51126129784 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -1140,8 +1140,9 @@ static void nvme_disable_queue(struct nvme_dev *dev, int qid)
1140 irq_set_affinity_hint(vector, NULL); 1140 irq_set_affinity_hint(vector, NULL);
1141 free_irq(vector, nvmeq); 1141 free_irq(vector, nvmeq);
1142 1142
1143 /* Don't tell the adapter to delete the admin queue */ 1143 /* Don't tell the adapter to delete the admin queue.
1144 if (qid) { 1144 * Don't tell a removed adapter to delete IO queues. */
1145 if (qid && readl(&dev->bar->csts) != -1) {
1145 adapter_delete_sq(dev, qid); 1146 adapter_delete_sq(dev, qid);
1146 adapter_delete_cq(dev, qid); 1147 adapter_delete_cq(dev, qid);
1147 } 1148 }
@@ -2052,12 +2053,18 @@ static int nvme_dev_map(struct nvme_dev *dev)
2052 dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); 2053 dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
2053 if (!dev->bar) 2054 if (!dev->bar)
2054 goto disable; 2055 goto disable;
2055 2056 if (readl(&dev->bar->csts) == -1) {
2057 result = -ENODEV;
2058 goto unmap;
2059 }
2056 dev->db_stride = 1 << NVME_CAP_STRIDE(readq(&dev->bar->cap)); 2060 dev->db_stride = 1 << NVME_CAP_STRIDE(readq(&dev->bar->cap));
2057 dev->dbs = ((void __iomem *)dev->bar) + 4096; 2061 dev->dbs = ((void __iomem *)dev->bar) + 4096;
2058 2062
2059 return 0; 2063 return 0;
2060 2064
2065 unmap:
2066 iounmap(dev->bar);
2067 dev->bar = NULL;
2061 disable: 2068 disable:
2062 pci_release_regions(pdev); 2069 pci_release_regions(pdev);
2063 disable_pci: 2070 disable_pci: