diff options
author | Keith Busch <keith.busch@intel.com> | 2015-08-10 15:20:40 -0600 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-08-18 11:56:11 -0600 |
commit | dfbac8c7ac5f58448b2216fe42ff52aaf175421d (patch) | |
tree | 7c04b5a9131d80100f2c0955fe783022af74dc96 /drivers/block | |
parent | b2b1ec9b55ed0840956db15f823c4a73383c08be (diff) | |
download | blackbird-op-linux-dfbac8c7ac5f58448b2216fe42ff52aaf175421d.tar.gz blackbird-op-linux-dfbac8c7ac5f58448b2216fe42ff52aaf175421d.zip |
NVMe: Add nvme subsystem reset support
Controllers part of an NVMe subsystem may be reset by any other controller
in the subsystem. If the device is capable of subsystem resets, this
patch adds detection for such events and performs appropriate controller
initialization upon subsystem reset detection.
The register bit is a RW1C type, so the driver needs to write a 1 to the
status bit to clear the subsystem reset occured bit during initialization.
Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/nvme-core.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 85cd33bf9607..e318a992e2e6 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1735,6 +1735,12 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) page_shift = dev_page_max; } + dev->subsystem = readl(&dev->bar->vs) >= NVME_VS(1, 1) ? + NVME_CAP_NSSRC(cap) : 0; + + if (dev->subsystem && (readl(&dev->bar->csts) & NVME_CSTS_NSSRO)) + writel(NVME_CSTS_NSSRO, &dev->bar->csts); + result = nvme_disable_ctrl(dev, cap); if (result < 0) return result; @@ -2059,7 +2065,10 @@ static int nvme_kthread(void *data) spin_lock(&dev_list_lock); list_for_each_entry_safe(dev, next, &dev_list, node) { int i; - if (readl(&dev->bar->csts) & NVME_CSTS_CFS) { + u32 csts = readl(&dev->bar->csts); + + if ((dev->subsystem && (csts & NVME_CSTS_NSSRO)) || + csts & NVME_CSTS_CFS) { if (work_busy(&dev->reset_work)) continue; list_del_init(&dev->node); |