]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
NVMe: Failed controller initialization fixes
authorKeith Busch <keith.busch@intel.com>
Thu, 6 Aug 2015 18:07:24 +0000 (11:07 -0700)
committerSantosh Shilimkar <santosh.shilimkar@oracle.com>
Fri, 7 Aug 2015 18:21:07 +0000 (11:21 -0700)
This fixes an infinite device reset loop that may occur on devices that
fail initialization. If the drive fails to become ready for any reason
that does not involve an admin command timeout, the probe task should
assume the drive is unavailable and remove it from the topology. In
the case an admin command times out during device probing, the driver's
existing reset action will handle removing the drive.

Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
(cherry picked from commit de3eff2bad56f0a29d3915105223d368f2bbc94e)

Conflicts:

drivers/block/nvme-core.c

Orabug: 21569452

Signed-off-by: Santosh Shilimkar <santosh.shilimkar@oracle.com>
drivers/block/nvme-core.c

index fd26924c87a9f542dbad6f66e5dcf16bd8a0503d..6feae81bb3607b2c1b4b639ebb77ba559ca6a0d1 100644 (file)
@@ -3029,6 +3029,18 @@ static int nvme_dev_resume(struct nvme_dev *dev)
        return 0;
 }
 
+static void nvme_dead_ctrl(struct nvme_dev *dev)
+{
+       dev_warn(&dev->pci_dev->dev, "Device failed to resume\n");
+       kref_get(&dev->kref);
+       if (IS_ERR(kthread_run(nvme_remove_dead_ctrl, dev, "nvme%d",
+                                               dev->instance))) {
+               dev_err(&dev->pci_dev->dev,
+                       "Failed to start controller remove task\n");
+               kref_put(&dev->kref, nvme_free_dev);
+       }
+}
+
 static void nvme_dev_reset(struct nvme_dev *dev)
 {
        bool in_probe = work_busy(&dev->probe_work);
@@ -3042,14 +3054,7 @@ static void nvme_dev_reset(struct nvme_dev *dev)
        /* Fail this device if reset occured during probe to avoid
         * infinite initialization loops. */
        if (in_probe) {
-               dev_warn(&dev->pci_dev->dev, "Device failed to resume\n");
-               kref_get(&dev->kref);
-               if (IS_ERR(kthread_run(nvme_remove_dead_ctrl, dev, "nvme%d",
-                                                       dev->instance))) {
-                       dev_err(&dev->pci_dev->dev,
-                               "Failed to start controller remove task\n");
-                       kref_put(&dev->kref, nvme_free_dev);
-               }
+               nvme_dead_ctrl(dev);
                return;
        }
        /* Schedule device resume asynchronously so the reset work is available
@@ -3184,16 +3189,8 @@ static void nvme_async_probe(struct work_struct *work)
 {
        struct nvme_dev *dev = container_of(work, struct nvme_dev, probe_work);
 
-       if (nvme_dev_resume(dev))
-               goto reset;
-       return;
- reset:
-       spin_lock(&dev_list_lock);
-       if (!work_busy(&dev->reset_work)) {
-               dev->reset_workfn = nvme_reset_failed_dev;
-               queue_work(nvme_workq, &dev->reset_work);
-       }
-       spin_unlock(&dev_list_lock);
+       if (nvme_dev_resume(dev) && !work_busy(&dev->reset_work))
+               nvme_dead_ctrl(dev);
 }
 
 static void nvme_reset_notify(struct pci_dev *pdev, bool prepare)