| From b1084964cf7d0fea669647b660313ce1e3290e6e Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 15 Jul 2025 12:16:27 -0700 |
| Subject: nvme-pci: try function level reset on init failure |
| |
| From: Keith Busch <kbusch@kernel.org> |
| |
| [ Upstream commit 5b2c214a95942f7997d1916a4c44017becbc3cac ] |
| |
| NVMe devices from multiple vendors appear to get stuck in a reset state |
| that we can't get out of with an NVMe level Controller Reset. The kernel |
| would report these with messages that look like: |
| |
| Device not ready; aborting reset, CSTS=0x1 |
| |
| These have historically required a power cycle to make them usable |
| again, but in many cases, a PCIe FLR is sufficient to restart operation |
| without a power cycle. Try it if the initial controller reset fails |
| during any nvme reset attempt. |
| |
| Signed-off-by: Keith Busch <kbusch@kernel.org> |
| Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com> |
| Reviewed-by: Nitesh Shetty <nj.shetty@samsung.com> |
| Signed-off-by: Christoph Hellwig <hch@lst.de> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/nvme/host/pci.c | 24 ++++++++++++++++++++++-- |
| 1 file changed, 22 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c |
| index 97ab91a479d1..136dba6221d8 100644 |
| --- a/drivers/nvme/host/pci.c |
| +++ b/drivers/nvme/host/pci.c |
| @@ -1755,8 +1755,28 @@ static int nvme_pci_configure_admin_queue(struct nvme_dev *dev) |
| * might be pointing at! |
| */ |
| result = nvme_disable_ctrl(&dev->ctrl, false); |
| - if (result < 0) |
| - return result; |
| + if (result < 0) { |
| + struct pci_dev *pdev = to_pci_dev(dev->dev); |
| + |
| + /* |
| + * The NVMe Controller Reset method did not get an expected |
| + * CSTS.RDY transition, so something with the device appears to |
| + * be stuck. Use the lower level and bigger hammer PCIe |
| + * Function Level Reset to attempt restoring the device to its |
| + * initial state, and try again. |
| + */ |
| + result = pcie_reset_flr(pdev, false); |
| + if (result < 0) |
| + return result; |
| + |
| + pci_restore_state(pdev); |
| + result = nvme_disable_ctrl(&dev->ctrl, false); |
| + if (result < 0) |
| + return result; |
| + |
| + dev_info(dev->ctrl.device, |
| + "controller reset completed after pcie flr\n"); |
| + } |
| |
| result = nvme_alloc_queue(dev, 0, NVME_AQ_DEPTH); |
| if (result) |
| -- |
| 2.39.5 |
| |