git: 22f50379ab93 - main - nvme: delete the I/O queues in the system shutdown path

From: Abdelkader Boudih <seuros_at_FreeBSD.org>
Date: Sun, 04 Oct 2026 17:41:45 UTC
The branch main has been updated by seuros:

URL: https://cgit.FreeBSD.org/src/commit/?id=22f50379ab93024354e98333250d453a6d0eaff5

commit 22f50379ab93024354e98333250d453a6d0eaff5
Author:     Abdelkader Boudih <seuros@FreeBSD.org>
AuthorDate: 2026-10-04 17:40:29 +0000
Commit:     Abdelkader Boudih <seuros@FreeBSD.org>
CommitDate: 2026-10-04 17:40:29 +0000

    nvme: delete the I/O queues in the system shutdown path
    
    A normal shutdown deletes all I/O submission and completion queues
    before setting CC.SHN, as the suspend path already does.  The
    device_shutdown path went straight to the shutdown notification with
    the queues live, which some drives take slowly or record as an
    unclean stop. Skipped the deletion for failed, removed, or
    never-initialized controllers.
    
    Reviewed by:    imp, adrian
    Differential Revision:  https://reviews.freebsd.org/D59633
---
 sys/dev/nvme/nvme.c         | 5 +++++
 sys/dev/nvme/nvme_ctrlr.c   | 2 +-
 sys/dev/nvme/nvme_private.h | 1 +
 3 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/sys/dev/nvme/nvme.c b/sys/dev/nvme/nvme.c
index db50e2b140bc..9af9adaf7d25 100644
--- a/sys/dev/nvme/nvme.c
+++ b/sys/dev/nvme/nvme.c
@@ -44,8 +44,13 @@ int
 nvme_shutdown(device_t dev)
 {
 	struct nvme_controller	*ctrlr;
+	uint32_t		csts;
 
 	ctrlr = DEVICE2SOFTC(dev);
+
+	csts = nvme_mmio_read_4(ctrlr, csts);
+	if (ctrlr->is_initialized && !ctrlr->is_failed && csts != NVME_GONE)
+		nvme_ctrlr_delete_qpairs(ctrlr);
 	nvme_ctrlr_shutdown(ctrlr);
 
 	return (0);
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index ae98482fecbd..ab8b0aa37a35 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -612,7 +612,7 @@ nvme_ctrlr_create_qpairs(struct nvme_controller *ctrlr)
 	return (0);
 }
 
-static int
+int
 nvme_ctrlr_delete_qpairs(struct nvme_controller *ctrlr)
 {
 	struct nvme_completion_poll_status	status;
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
index 9bee1b23bd4e..d801f8285f90 100644
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -437,6 +437,7 @@ void	nvme_completion_poll_cb(void *arg, const struct nvme_completion *cpl);
 int	nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev);
 void	nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev);
 void	nvme_ctrlr_shutdown(struct nvme_controller *ctrlr);
+int	nvme_ctrlr_delete_qpairs(struct nvme_controller *ctrlr);
 void	nvme_ctrlr_reset(struct nvme_controller *ctrlr);
 /* ctrlr defined as void * to allow use with config_intrhook. */
 void	nvme_ctrlr_start_config_hook(void *ctrlr_arg);