NVMe: Fix command setup on IO retry
[firefly-linux-kernel-4.4.55.git] / drivers / block / nvme-core.c
index 677d7b9ff454dca2c3cf97545dc3ed43830c9c7a..bcbdf832b1b09727213f5532c23404c89df0a12d 100644 (file)
@@ -171,6 +171,13 @@ static int nvme_admin_init_request(void *data, struct request *req,
        return 0;
 }
 
+static void nvme_exit_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
+{
+       struct nvme_queue *nvmeq = hctx->driver_data;
+
+       nvmeq->hctx = NULL;
+}
+
 static int nvme_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
                          unsigned int hctx_idx)
 {
@@ -633,8 +640,6 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
        iod->private = req;
        req->special = iod;
 
-       nvme_set_info(cmd, iod, req_completion);
-
        if (req->cmd_flags & REQ_DISCARD) {
                void *range;
                /*
@@ -670,6 +675,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
        blk_mq_start_request(req);
 
  submit_iod:
+       nvme_set_info(cmd, iod, req_completion);
        spin_lock_irq(&nvmeq->q_lock);
        if (req->cmd_flags & REQ_DISCARD)
                nvme_submit_discard(nvmeq, ns, req, iod);
@@ -1335,6 +1341,7 @@ static struct blk_mq_ops nvme_mq_admin_ops = {
        .queue_rq       = nvme_admin_queue_rq,
        .map_queue      = blk_mq_map_queue,
        .init_hctx      = nvme_admin_init_hctx,
+       .exit_hctx      = nvme_exit_hctx,
        .init_request   = nvme_admin_init_request,
        .timeout        = nvme_timeout,
 };
@@ -1343,6 +1350,7 @@ static struct blk_mq_ops nvme_mq_ops = {
        .queue_rq       = nvme_queue_rq,
        .map_queue      = blk_mq_map_queue,
        .init_hctx      = nvme_init_hctx,
+       .exit_hctx      = nvme_exit_hctx,
        .init_request   = nvme_init_request,
        .timeout        = nvme_timeout,
 };
@@ -1998,6 +2006,13 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
        /* Deregister the admin queue's interrupt */
        free_irq(dev->entry[0].vector, adminq);
 
+       /*
+        * If we enable msix early due to not intx, disable it again before
+        * setting up the full range we need.
+        */
+       if (!pdev->irq)
+               pci_disable_msix(pdev);
+
        for (i = 0; i < nr_io_queues; i++)
                dev->entry[i].entry = i;
        vecs = pci_enable_msix_range(pdev, dev->entry, 1, nr_io_queues);
@@ -2140,6 +2155,9 @@ static int nvme_dev_map(struct nvme_dev *dev)
        dev->entry[0].vector = pdev->irq;
        pci_set_master(pdev);
        bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       if (!bars)
+               goto disable_pci;
+
        if (pci_request_selected_regions(pdev, bars, "nvme"))
                goto disable_pci;
 
@@ -2150,10 +2168,22 @@ static int nvme_dev_map(struct nvme_dev *dev)
        dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
        if (!dev->bar)
                goto disable;
+
        if (readl(&dev->bar->csts) == -1) {
                result = -ENODEV;
                goto unmap;
        }
+
+       /*
+        * Some devices don't advertse INTx interrupts, pre-enable a single
+        * MSIX vec for setup. We'll adjust this later.
+        */
+       if (!pdev->irq) {
+               result = pci_enable_msix(pdev, dev->entry, 1);
+               if (result < 0)
+                       goto unmap;
+       }
+
        cap = readq(&dev->bar->cap);
        dev->q_depth = min_t(int, NVME_CAP_MQES(cap) + 1, NVME_Q_DEPTH);
        dev->db_stride = 1 << NVME_CAP_STRIDE(cap);
@@ -2857,6 +2887,6 @@ static void __exit nvme_exit(void)
 
 MODULE_AUTHOR("Matthew Wilcox <willy@linux.intel.com>");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.9");
+MODULE_VERSION("1.0");
 module_init(nvme_init);
 module_exit(nvme_exit);