git: 5258b44e845a - main - nvme: add a timeout for Format NVM commands

From: Warner Losh <imp_at_FreeBSD.org>
Date: Mon, 19 Oct 2026 06:24:35 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=5258b44e845a7ccdc3e07a9244e77dc100feedca

commit 5258b44e845a7ccdc3e07a9244e77dc100feedca
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2026-10-19 04:38:14 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-10-19 06:22:50 +0000

    nvme: add a timeout for Format NVM commands
    
    Format commands need a longer timeout.
    
    Reviewed by:            seuros, chuck
    Differential Revision:  https://reviews.freebsd.org/D59827
---
 sys/dev/nvme/nvme_ctrlr.c   |  6 ++++++
 sys/dev/nvme/nvme_private.h |  3 +++
 sys/dev/nvme/nvme_sysctl.c  | 21 +++++++++++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index 1197cf460c83..ccfbe576fd26 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -1843,6 +1843,12 @@ nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev)
 	timeout_period = max(timeout_period, NVME_MIN_TIMEOUT_PERIOD);
 	ctrlr->timeout_period = timeout_period;
 
+	timeout_period = NVME_FORMAT_TIMEOUT_PERIOD;
+	TUNABLE_INT_FETCH("hw.nvme.format_timeout_period", &timeout_period);
+	timeout_period = min(timeout_period, NVME_MAX_FORMAT_TIMEOUT_PERIOD);
+	timeout_period = max(timeout_period, NVME_MIN_TIMEOUT_PERIOD);
+	ctrlr->format_timeout_period = timeout_period;
+
 	nvme_retry_count = NVME_DEFAULT_RETRY_COUNT;
 	TUNABLE_INT_FETCH("hw.nvme.retry_count", &nvme_retry_count);
 
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
index 6f228cd1427b..c50ddf2a2a3b 100644
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -81,8 +81,10 @@ MALLOC_DECLARE(M_NVME);
 
 #define NVME_ADMIN_TIMEOUT_PERIOD	(60)    /* in seconds */
 #define NVME_DEFAULT_TIMEOUT_PERIOD	(30)    /* in seconds */
+#define NVME_FORMAT_TIMEOUT_PERIOD	(10 * 60) /* in seconds */
 #define NVME_MIN_TIMEOUT_PERIOD		(5)
 #define NVME_MAX_TIMEOUT_PERIOD		(120)
+#define NVME_MAX_FORMAT_TIMEOUT_PERIOD	(60 * 60)
 
 #define NVME_DEFAULT_RETRY_COUNT	(4)
 
@@ -302,6 +304,7 @@ struct nvme_controller {
 
 	/** timeout period in seconds */
 	uint32_t		admin_timeout_period;
+	uint32_t		format_timeout_period;
 	uint32_t		timeout_period;
 
 	/** doorbell stride */
diff --git a/sys/dev/nvme/nvme_sysctl.c b/sys/dev/nvme/nvme_sysctl.c
index 55c5dfec8701..1bc3c2801272 100644
--- a/sys/dev/nvme/nvme_sysctl.c
+++ b/sys/dev/nvme/nvme_sysctl.c
@@ -131,6 +131,22 @@ nvme_sysctl_timeout_period(SYSCTL_HANDLER_ARGS)
 	return (0);
 }
 
+static int
+nvme_sysctl_format_timeout_period(SYSCTL_HANDLER_ARGS)
+{
+	uint32_t *ptr = arg1;
+	uint32_t newval = *ptr;
+	int error = sysctl_handle_int(oidp, &newval, 0, req);
+
+	if (error || req->newptr == NULL)
+		return (error);
+	if (newval > NVME_MAX_FORMAT_TIMEOUT_PERIOD ||
+	    newval < NVME_MIN_TIMEOUT_PERIOD)
+		return (EINVAL);
+	*ptr = newval;
+	return (0);
+}
+
 static void
 nvme_qpair_reset_stats(struct nvme_qpair *qpair)
 {
@@ -279,6 +295,11 @@ nvme_sysctl_initialize_ctrlr(struct nvme_controller *ctrlr)
 	    &ctrlr->timeout_period, 0, nvme_sysctl_timeout_period, "IU",
 	    "Timeout period for I/O queues (in seconds)");
 
+	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
+	    "format_timeout_period", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+	    &ctrlr->format_timeout_period, 0, nvme_sysctl_format_timeout_period,
+	    "IU", "Timeout period for Format NVM commands (in seconds)");
+
 	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
 	    "num_cmds", CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
 	    ctrlr, offsetof(struct nvme_qpair, num_cmds),