NVMe: Controller resets
Subsystems (2)
cover NVMe: Controller resets
Some controller reset action. These depend on this patch set here:
http://merlin.infradead.org/pipermail/linux-nvme/2013-July/000331.html
Keith Busch (2):
NVMe: Reset failed controller
NVMe: User initiated controller reset
drivers/block/nvme-core.c | 43 ++++++++++++++++++++++++++++++++++++++++++- include/linux/nvme.h | 1 + 2 files changed, 43 insertions(+), 1 deletion(-)
Signature · 1 line
1.7.10.4
PATCH 1/2 NVMe: Reset failed controller
Polls on the controller fatal status bit and resets the controller per the nvme spec on this condition.
Signed-off-by Keith Busch <keith.busch at intel.com>
--- drivers/block/nvme-core.c | 30 +++++++++++++++++++++++++++++- include/linux/nvme.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-)
drivers/block/nvme-core.c +29 -1
@@ -58,6 +58,7 @@ module_param(use_threaded_interrupts, int, 0);static DEFINE_SPINLOCK (dev_list_lock);static LIST_HEAD (dev_list);static struct task_struct *nvme_thread; +static struct workqueue_struct *nvme_workq;/* * An NVM Express queue. Each device has at least two (one for admin
@@ -1605,6 +1606,12 @@ static int nvme_kthread(void *data)spin_lock (&dev_list_lock);list_for_each_entry (dev, &dev_list, node) {int i; +if (readl (&dev->bar->csts) &NVME_CSTS_CFS ) { +dev_warn (&dev->pci_dev->dev, +"failed status, reset controller\n" ); +queue_work (nvme_workq, &dev->ws); +continue ; + }for (i =0 ; i < dev->queue_count; i++) {struct nvme_queue *nvmeq = dev->queues[i];if (!nvmeq)
@@ -2151,6 +2158,19 @@ static int nvme_dev_start(struct nvme_dev *dev)return result; } +static void nvme_dev_reset (struct nvme_dev *dev) +{ +nvme_dev_shutdown (dev); +if (nvme_dev_start (dev)) +nvme_free_queues (dev); +} + +static void nvme_reset_failed_dev (struct work_struct *ws) +{ + struct nvme_dev *dev = container_of(ws, struct nvme_dev, ws); +nvme_dev_reset (dev); +} +static int nvme_probe (struct pci_dev *pdev,const struct pci_device_id *id) {int result = -ENOMEM ;
@@ -2178,6 +2198,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)if (result) goto release; +INIT_WORK (&dev->ws, nvme_reset_failed_dev); result =nvme_dev_start (dev);if (result) goto release_pools;
@@ -2288,9 +2309,14 @@ static int __init nvme_init(void)if (IS_ERR (nvme_thread))return PTR_ERR (nvme_thread); + result = -ENOMEM ; + nvme_workq =create_workqueue ("nvme" ); +if (!nvme_workq) + goto kill_kthread; + result =register_blkdev (nvme_major,"nvme" );if (result <0 ) - goto kill_thread; + goto kill_workq;else if (result >0 ) nvme_major = result;
@@ -2301,6 +2327,8 @@ static int __init nvme_init(void) unregister_blkdev:unregister_blkdev (nvme_major,"nvme" ); + kill_workq: +destroy_workqueue (nvme_workq); kill_kthread:kthread_stop (nvme_thread);return result;
include/linux/nvme.h +1 -0
@@ -87,6 +87,7 @@ struct nvme_dev {struct list_head namespaces;struct kref kref;struct miscdevice miscdev; +struct work_struct ws;char name[12 ];char serial[20 ];char model[40 ];
Signature · 1 line
1.7.10.4
PATCH 2/2 NVMe: User initiated controller reset
In reply to Keith BuschCreates a sysfs entry for each nvme controller that when written to initiates a controller reset. This may be done by a user if they need to reset the controller for any reason. For example, it may be required as part of an firmware activate procedure.
Signed-off-by Keith Busch <keith.busch at intel.com>
--- drivers/block/nvme-core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/block/nvme-core.c +13 -0
@@ -2171,6 +2171,17 @@ static void nvme_reset_failed_dev(struct work_struct *ws)nvme_dev_reset (dev); } +static ssize_t nvme_reset (struct device *dev, +struct device_attribute *attr,const char *buf,size_t count) +{ + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); +struct nvme_dev *ndev =pci_get_drvdata (pdev); + +nvme_dev_reset (ndev); +return count; +} +static DEVICE_ATTR(reset_controller, S_IWUSR, NULL, nvme_reset); +static int nvme_probe (struct pci_dev *pdev,const struct pci_device_id *id) {int result = -ENOMEM ;
@@ -2217,6 +2228,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto remove;kref_init (&dev->kref); +device_create_file (&pdev->dev, &dev_attr_reset_controller);return 0 ; remove:
@@ -2238,6 +2250,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)static void nvme_remove (struct pci_dev *pdev) {struct nvme_dev *dev =pci_get_drvdata (pdev); +device_remove_file (&pdev->dev, &dev_attr_reset_controller);misc_deregister (&dev->miscdev);kref_put (&dev->kref, nvme_free_dev); }
Signature · 1 line
1.7.10.4