nvme: do not restart the request timeout if we're resetting the controller
authorKeith Busch <keith.busch@intel.com>
Thu, 26 Nov 2015 11:11:07 +0000 (12:11 +0100)
committerJens Axboe <axboe@fb.com>
Tue, 22 Dec 2015 16:38:33 +0000 (09:38 -0700)
Otherwise we're never going to complete a command when it is restarted just
after we completed all other outstanding commands in nvme_clear_queue.

The controller must be disabled prior to completing a presumed lost
command, do this by directly shutting down the controller before
queueing the reset work, and return EH_HANDLED from the timeout handler
after we shut the controller down.

Signed-off-by: Keith Busch <keith.busch@intel.com>
[hch: split and rebase]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@fb.com>
drivers/nvme/host/pci.c

index febcef5ae0aad70d05f309156643cf2b613820c8..6082f2775581ab1cca503d52ab72ac1c66ffc966 100644 (file)
@@ -81,6 +81,7 @@ static int nvme_reset(struct nvme_dev *dev);
 static void nvme_process_cq(struct nvme_queue *nvmeq);
 static void nvme_unmap_data(struct nvme_dev *dev, struct nvme_iod *iod);
 static void nvme_dead_ctrl(struct nvme_dev *dev);
+static void nvme_dev_shutdown(struct nvme_dev *dev);
 
 struct async_cmd_info {
        struct kthread_work work;
@@ -1087,17 +1088,23 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
        struct nvme_command cmd;
 
        /*
-        * Schedule controller reset if the command was already aborted once
-        * before and still hasn't been returned to the driver, or if this is
-        * the admin queue.
+        * Shutdown the controller immediately and schedule a reset if the
+        * command was already aborted once before and still hasn't been
+        * returned to the driver, or if this is the admin queue.
         */
        if (!nvmeq->qid || cmd_rq->aborted) {
-               if (queue_work(nvme_workq, &dev->reset_work)) {
-                       dev_warn(dev->dev,
-                                "I/O %d QID %d timeout, reset controller\n",
-                                req->tag, nvmeq->qid);
-               }
-               return BLK_EH_RESET_TIMER;
+               dev_warn(dev->dev,
+                        "I/O %d QID %d timeout, reset controller\n",
+                        req->tag, nvmeq->qid);
+               nvme_dev_shutdown(dev);
+               queue_work(nvme_workq, &dev->reset_work);
+
+               /*
+                * Mark the request as handled, since the inline shutdown
+                * forces all outstanding requests to complete.
+                */
+               req->errors = NVME_SC_CANCELLED;
+               return BLK_EH_HANDLED;
        }
 
        if (!dev->ctrl.abort_limit)