nvme: move namespace scanning to core
[linux-2.6-block.git] / drivers / nvme / host / pci.c
index 36b6cdf22de3ef822c53eb2b8e3f729b3c5f6bbe..15bc337553248e6c08fa6a733218edeccf884bf2 100644 (file)
@@ -92,7 +92,6 @@ struct nvme_dev {
        struct msix_entry *entry;
        void __iomem *bar;
        struct work_struct reset_work;
-       struct work_struct scan_work;
        struct work_struct remove_work;
        struct work_struct async_work;
        struct timer_list watchdog_timer;
@@ -102,11 +101,6 @@ struct nvme_dev {
        dma_addr_t cmb_dma_addr;
        u64 cmb_size;
        u32 cmbsz;
-       unsigned long flags;
-
-#define NVME_CTRL_RESETTING    0
-#define NVME_CTRL_REMOVING     1
-
        struct nvme_ctrl ctrl;
        struct completion ioq_wait;
 };
@@ -271,17 +265,6 @@ static int nvme_init_request(void *data, struct request *req,
        return 0;
 }
 
-static void nvme_queue_scan(struct nvme_dev *dev)
-{
-       /*
-        * Do not queue new scan work when a controller is reset during
-        * removal.
-        */
-       if (test_bit(NVME_CTRL_REMOVING, &dev->flags))
-               return;
-       queue_work(nvme_workq, &dev->scan_work);
-}
-
 static void nvme_complete_async_event(struct nvme_dev *dev,
                struct nvme_completion *cqe)
 {
@@ -299,7 +282,7 @@ static void nvme_complete_async_event(struct nvme_dev *dev,
        switch (result & 0xff07) {
        case NVME_AER_NOTICE_NS_CHANGED:
                dev_info(dev->ctrl.device, "rescanning\n");
-               nvme_queue_scan(dev);
+               nvme_queue_scan(&dev->ctrl);
        default:
                dev_warn(dev->ctrl.device, "async event result %08x\n", result);
        }
@@ -901,7 +884,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
         * cancellation error. All outstanding requests are completed on
         * shutdown, so we return BLK_EH_HANDLED.
         */
-       if (test_bit(NVME_CTRL_RESETTING, &dev->flags)) {
+       if (dev->ctrl.state == NVME_CTRL_RESETTING) {
                dev_warn(dev->ctrl.device,
                         "I/O %d QID %d timeout, disable controller\n",
                         req->tag, nvmeq->qid);
@@ -1303,22 +1286,44 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
        return result;
 }
 
+static bool nvme_should_reset(struct nvme_dev *dev, u32 csts)
+{
+
+       /* If true, indicates loss of adapter communication, possibly by a
+        * NVMe Subsystem reset.
+        */
+       bool nssro = dev->subsystem && (csts & NVME_CSTS_NSSRO);
+
+       /* If there is a reset ongoing, we shouldn't reset again. */
+       if (work_busy(&dev->reset_work))
+               return false;
+
+       /* We shouldn't reset unless the controller is on fatal error state
+        * _or_ if we lost the communication with it.
+        */
+       if (!(csts & NVME_CSTS_CFS) && !nssro)
+               return false;
+
+       /* If PCI error recovery process is happening, we cannot reset or
+        * the recovery mechanism will surely fail.
+        */
+       if (pci_channel_offline(to_pci_dev(dev->dev)))
+               return false;
+
+       return true;
+}
+
 static void nvme_watchdog_timer(unsigned long data)
 {
        struct nvme_dev *dev = (struct nvme_dev *)data;
        u32 csts = readl(dev->bar + NVME_REG_CSTS);
 
-       /*
-        * Skip controllers currently under reset.
-        */
-       if (!work_pending(&dev->reset_work) && !work_busy(&dev->reset_work) &&
-           ((csts & NVME_CSTS_CFS) ||
-            (dev->subsystem && (csts & NVME_CSTS_NSSRO)))) {
-               if (queue_work(nvme_workq, &dev->reset_work)) {
+       /* Skip controllers under certain specific conditions. */
+       if (nvme_should_reset(dev, csts)) {
+               if (queue_work(nvme_workq, &dev->reset_work))
                        dev_warn(dev->dev,
                                "Failed status: 0x%x, reset controller.\n",
                                csts);
-               }
                return;
        }
 
@@ -1504,8 +1509,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
        return result;
 }
 
-static void nvme_set_irq_hints(struct nvme_dev *dev)
+static void nvme_pci_post_scan(struct nvme_ctrl *ctrl)
 {
+       struct nvme_dev *dev = to_nvme_dev(ctrl);
        struct nvme_queue *nvmeq;
        int i;
 
@@ -1520,16 +1526,6 @@ static void nvme_set_irq_hints(struct nvme_dev *dev)
        }
 }
 
-static void nvme_dev_scan(struct work_struct *work)
-{
-       struct nvme_dev *dev = container_of(work, struct nvme_dev, scan_work);
-
-       if (!dev->tagset.tags)
-               return;
-       nvme_scan_namespaces(&dev->ctrl);
-       nvme_set_irq_hints(dev);
-}
-
 static void nvme_del_queue_end(struct request *req, int error)
 {
        struct nvme_queue *nvmeq = req->end_io_data;
@@ -1643,7 +1639,6 @@ static int nvme_dev_add(struct nvme_dev *dev)
                nvme_free_queues(dev, dev->online_queues);
        }
 
-       nvme_queue_scan(dev);
        return 0;
 }
 
@@ -1813,7 +1808,7 @@ static void nvme_reset_work(struct work_struct *work)
        struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
        int result = -ENODEV;
 
-       if (WARN_ON(test_bit(NVME_CTRL_RESETTING, &dev->flags)))
+       if (WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING))
                goto out;
 
        /*
@@ -1823,7 +1818,8 @@ static void nvme_reset_work(struct work_struct *work)
        if (dev->ctrl.ctrl_config & NVME_CC_ENABLE)
                nvme_dev_disable(dev, false);
 
-       set_bit(NVME_CTRL_RESETTING, &dev->flags);
+       if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING))
+               goto out;
 
        result = nvme_pci_enable(dev);
        if (result)
@@ -1865,13 +1861,20 @@ static void nvme_reset_work(struct work_struct *work)
         */
        if (dev->online_queues < 2) {
                dev_warn(dev->ctrl.device, "IO queues not created\n");
+               nvme_kill_queues(&dev->ctrl);
                nvme_remove_namespaces(&dev->ctrl);
        } else {
                nvme_start_queues(&dev->ctrl);
                nvme_dev_add(dev);
        }
 
-       clear_bit(NVME_CTRL_RESETTING, &dev->flags);
+       if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_LIVE)) {
+               dev_warn(dev->ctrl.device, "failed to mark controller live\n");
+               goto out;
+       }
+
+       if (dev->online_queues > 1)
+               nvme_queue_scan(&dev->ctrl);
        return;
 
  out:
@@ -1919,13 +1922,6 @@ static int nvme_pci_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val)
        return 0;
 }
 
-static bool nvme_pci_io_incapable(struct nvme_ctrl *ctrl)
-{
-       struct nvme_dev *dev = to_nvme_dev(ctrl);
-
-       return !dev->bar || dev->online_queues < 2;
-}
-
 static int nvme_pci_reset_ctrl(struct nvme_ctrl *ctrl)
 {
        return nvme_reset(to_nvme_dev(ctrl));
@@ -1936,9 +1932,9 @@ static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
        .reg_read32             = nvme_pci_reg_read32,
        .reg_write32            = nvme_pci_reg_write32,
        .reg_read64             = nvme_pci_reg_read64,
-       .io_incapable           = nvme_pci_io_incapable,
        .reset_ctrl             = nvme_pci_reset_ctrl,
        .free_ctrl              = nvme_pci_free_ctrl,
+       .post_scan              = nvme_pci_post_scan,
 };
 
 static int nvme_dev_map(struct nvme_dev *dev)
@@ -1990,7 +1986,6 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (result)
                goto free;
 
-       INIT_WORK(&dev->scan_work, nvme_dev_scan);
        INIT_WORK(&dev->reset_work, nvme_reset_work);
        INIT_WORK(&dev->remove_work, nvme_remove_dead_ctrl_work);
        INIT_WORK(&dev->async_work, nvme_async_event_work);
@@ -2052,11 +2047,10 @@ static void nvme_remove(struct pci_dev *pdev)
 
        del_timer_sync(&dev->watchdog_timer);
 
-       set_bit(NVME_CTRL_REMOVING, &dev->flags);
+       nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING);
+
        pci_set_drvdata(pdev, NULL);
        flush_work(&dev->async_work);
-       flush_work(&dev->scan_work);
-       nvme_remove_namespaces(&dev->ctrl);
        nvme_uninit_ctrl(&dev->ctrl);
        nvme_dev_disable(dev, true);
        flush_work(&dev->reset_work);