Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NVMe: Schedule reset for failed controllers

Schedules a controller reset when it indicates it has a failed status. If
the device does not become ready after a reset, the pci device will be
scheduled for removal.

Signed-off-by: Keith Busch <keith.busch@intel.com>
[fixed checkpatch issue]
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>

authored by

Keith Busch and committed by
Matthew Wilcox
d4b4ff8e 9a6b9458

+20 -2
+19 -2
drivers/block/nvme-core.c
··· 60 60 static struct task_struct *nvme_thread; 61 61 static struct workqueue_struct *nvme_workq; 62 62 63 + static void nvme_reset_failed_dev(struct work_struct *ws); 64 + 63 65 /* 64 66 * An NVM Express queue. Each device has at least two (one for admin 65 67 * commands and one for I/O commands). ··· 1614 1612 1615 1613 static int nvme_kthread(void *data) 1616 1614 { 1617 - struct nvme_dev *dev; 1615 + struct nvme_dev *dev, *next; 1618 1616 1619 1617 while (!kthread_should_stop()) { 1620 1618 set_current_state(TASK_INTERRUPTIBLE); 1621 1619 spin_lock(&dev_list_lock); 1622 - list_for_each_entry(dev, &dev_list, node) { 1620 + list_for_each_entry_safe(dev, next, &dev_list, node) { 1623 1621 int i; 1622 + if (readl(&dev->bar->csts) & NVME_CSTS_CFS && 1623 + dev->initialized) { 1624 + if (work_busy(&dev->reset_work)) 1625 + continue; 1626 + list_del_init(&dev->node); 1627 + dev_warn(&dev->pci_dev->dev, 1628 + "Failed status, reset controller\n"); 1629 + INIT_WORK(&dev->reset_work, 1630 + nvme_reset_failed_dev); 1631 + queue_work(nvme_workq, &dev->reset_work); 1632 + continue; 1633 + } 1624 1634 for (i = 0; i < dev->queue_count; i++) { 1625 1635 struct nvme_queue *nvmeq = dev->queues[i]; 1626 1636 if (!nvmeq) ··· 2020 2006 { 2021 2007 int i; 2022 2008 2009 + dev->initialized = 0; 2023 2010 for (i = dev->queue_count - 1; i >= 0; i--) 2024 2011 nvme_disable_queue(dev, i); 2025 2012 ··· 2211 2196 queue_work(nvme_workq, &dev->reset_work); 2212 2197 spin_unlock(&dev_list_lock); 2213 2198 } 2199 + dev->initialized = 1; 2214 2200 return 0; 2215 2201 } 2216 2202 ··· 2285 2269 if (result) 2286 2270 goto remove; 2287 2271 2272 + dev->initialized = 1; 2288 2273 kref_init(&dev->kref); 2289 2274 return 0; 2290 2275
+1
include/linux/nvme.h
··· 95 95 u32 max_hw_sectors; 96 96 u32 stripe_size; 97 97 u16 oncs; 98 + u8 initialized; 98 99 }; 99 100 100 101 /*