Commit f58944e2 authored by Keith Busch's avatar Keith Busch Committed by Jens Axboe

NVMe: Simplify device reset failure

A reset failure schedules the device to unbind from the driver through
the pci driver's remove. This cleans up all intialization, so there is
no need to duplicate the potentially racy cleanup.

To help understand why a reset failed, the status is logged with the
existing warning message.
Signed-off-by: default avatarKeith Busch <keith.busch@intel.com>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent 646017a6
...@@ -86,7 +86,6 @@ struct nvme_queue; ...@@ -86,7 +86,6 @@ struct nvme_queue;
static int nvme_reset(struct nvme_dev *dev); static int nvme_reset(struct nvme_dev *dev);
static void nvme_process_cq(struct nvme_queue *nvmeq); static void nvme_process_cq(struct nvme_queue *nvmeq);
static void nvme_remove_dead_ctrl(struct nvme_dev *dev);
static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown); static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown);
/* /*
...@@ -1897,10 +1896,19 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl) ...@@ -1897,10 +1896,19 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
kfree(dev); kfree(dev);
} }
static void nvme_remove_dead_ctrl(struct nvme_dev *dev, int status)
{
dev_warn(dev->dev, "Removing after probe failure status: %d\n", status);
kref_get(&dev->ctrl.kref);
if (!schedule_work(&dev->remove_work))
nvme_put_ctrl(&dev->ctrl);
}
static void nvme_reset_work(struct work_struct *work) static void nvme_reset_work(struct work_struct *work)
{ {
struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work); struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
int result; int result = -ENODEV;
if (WARN_ON(test_bit(NVME_CTRL_RESETTING, &dev->flags))) if (WARN_ON(test_bit(NVME_CTRL_RESETTING, &dev->flags)))
goto out; goto out;
...@@ -1920,26 +1928,26 @@ static void nvme_reset_work(struct work_struct *work) ...@@ -1920,26 +1928,26 @@ static void nvme_reset_work(struct work_struct *work)
result = nvme_configure_admin_queue(dev); result = nvme_configure_admin_queue(dev);
if (result) if (result)
goto unmap; goto out;
nvme_init_queue(dev->queues[0], 0); nvme_init_queue(dev->queues[0], 0);
result = nvme_alloc_admin_tags(dev); result = nvme_alloc_admin_tags(dev);
if (result) if (result)
goto disable; goto out;
result = nvme_init_identify(&dev->ctrl); result = nvme_init_identify(&dev->ctrl);
if (result) if (result)
goto free_tags; goto out;
result = nvme_setup_io_queues(dev); result = nvme_setup_io_queues(dev);
if (result) if (result)
goto free_tags; goto out;
dev->ctrl.event_limit = NVME_NR_AEN_COMMANDS; dev->ctrl.event_limit = NVME_NR_AEN_COMMANDS;
result = nvme_dev_list_add(dev); result = nvme_dev_list_add(dev);
if (result) if (result)
goto remove; goto out;
/* /*
* Keep the controller around but remove all namespaces if we don't have * Keep the controller around but remove all namespaces if we don't have
...@@ -1956,19 +1964,8 @@ static void nvme_reset_work(struct work_struct *work) ...@@ -1956,19 +1964,8 @@ static void nvme_reset_work(struct work_struct *work)
clear_bit(NVME_CTRL_RESETTING, &dev->flags); clear_bit(NVME_CTRL_RESETTING, &dev->flags);
return; return;
remove:
nvme_dev_list_remove(dev);
free_tags:
nvme_dev_remove_admin(dev);
blk_put_queue(dev->ctrl.admin_q);
dev->ctrl.admin_q = NULL;
dev->queues[0]->tags = NULL;
disable:
nvme_disable_admin_queue(dev, false);
unmap:
nvme_dev_unmap(dev);
out: out:
nvme_remove_dead_ctrl(dev); nvme_remove_dead_ctrl(dev, result);
} }
static void nvme_remove_dead_ctrl_work(struct work_struct *work) static void nvme_remove_dead_ctrl_work(struct work_struct *work)
...@@ -1981,14 +1978,6 @@ static void nvme_remove_dead_ctrl_work(struct work_struct *work) ...@@ -1981,14 +1978,6 @@ static void nvme_remove_dead_ctrl_work(struct work_struct *work)
nvme_put_ctrl(&dev->ctrl); nvme_put_ctrl(&dev->ctrl);
} }
static void nvme_remove_dead_ctrl(struct nvme_dev *dev)
{
dev_warn(dev->dev, "Removing after probe failure\n");
kref_get(&dev->ctrl.kref);
if (!schedule_work(&dev->remove_work))
nvme_put_ctrl(&dev->ctrl);
}
static int nvme_reset(struct nvme_dev *dev) static int nvme_reset(struct nvme_dev *dev)
{ {
if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q)) if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q))
...@@ -2136,6 +2125,11 @@ static void nvme_shutdown(struct pci_dev *pdev) ...@@ -2136,6 +2125,11 @@ static void nvme_shutdown(struct pci_dev *pdev)
nvme_dev_disable(dev, true); nvme_dev_disable(dev, true);
} }
/*
* The driver's remove may be called on a device in a partially initialized
* state. This function must not have any dependencies on the device state in
* order to proceed.
*/
static void nvme_remove(struct pci_dev *pdev) static void nvme_remove(struct pci_dev *pdev)
{ {
struct nvme_dev *dev = pci_get_drvdata(pdev); struct nvme_dev *dev = pci_get_drvdata(pdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment