git: 1c31ef40e185 - main - nvme: support per-request timeouts

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

URL: https://cgit.FreeBSD.org/src/commit/?id=1c31ef40e185a09c030d53640f6ebc71bb0c830f

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

    nvme: support per-request timeouts
    
    Allow different timeouts per command.
    
    Reviewed by:            seuros, chuck
    Differential Revision:  https://reviews.freebsd.org/D59828
---
 sys/dev/nvme/nvme_ctrlr.c   |  2 +-
 sys/dev/nvme/nvme_private.h |  8 +++++---
 sys/dev/nvme/nvme_qpair.c   | 17 +++++++++++------
 3 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index ccfbe576fd26..c8c891eaf806 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -795,7 +795,7 @@ nvme_ctrlr_construct_and_submit_aer(struct nvme_controller *ctrlr,
 	 * Disable timeout here, since asynchronous event requests should by
 	 *  nature never be timed out.
 	 */
-	req->timeout = false;
+	req->timeout_ms = NVME_TIMEOUT_NONE;
 	req->cmd.opc = NVME_OPC_ASYNC_EVENT_REQUEST;
 	nvme_ctrlr_submit_admin_request(ctrlr, req);
 }
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
index c50ddf2a2a3b..b55159145de9 100644
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -86,6 +86,9 @@ MALLOC_DECLARE(M_NVME);
 #define NVME_MAX_TIMEOUT_PERIOD		(120)
 #define NVME_MAX_FORMAT_TIMEOUT_PERIOD	(60 * 60)
 
+#define NVME_TIMEOUT_DEFAULT		0U
+#define NVME_TIMEOUT_NONE		UINT32_MAX
+
 #define NVME_DEFAULT_RETRY_COUNT	(4)
 
 /* Maximum log page size to fetch for AERs. */
@@ -115,12 +118,11 @@ struct nvme_request {
 	struct memdesc			payload;
 	nvme_cb_fn_t			cb_fn;
 	void				*cb_arg;
+	uint32_t			timeout_ms;
 	int16_t				retries;
 	uint16_t			ioq;
 #define NVME_IOQ_DEFAULT		0xffff
 	bool				payload_valid;
-	bool				timeout;
-	bool				spare[2];		/* Future use */
 	STAILQ_ENTRY(nvme_request)	stailq;
 };
 
@@ -544,7 +546,7 @@ _nvme_allocate_request(const int how, nvme_cb_fn_t cb_fn, void *cb_arg)
 		req->ioq = NVME_IOQ_DEFAULT;
 		req->cb_fn = cb_fn;
 		req->cb_arg = cb_arg;
-		req->timeout = true;
+		req->timeout_ms = NVME_TIMEOUT_DEFAULT;
 	}
 	return (req);
 }
diff --git a/sys/dev/nvme/nvme_qpair.c b/sys/dev/nvme/nvme_qpair.c
index c918539ce28c..1fd853513fcb 100644
--- a/sys/dev/nvme/nvme_qpair.c
+++ b/sys/dev/nvme/nvme_qpair.c
@@ -1037,7 +1037,7 @@ nvme_qpair_submit_tracker(struct nvme_qpair *qpair, struct nvme_tracker *tr)
 {
 	struct nvme_request	*req;
 	struct nvme_controller	*ctrlr;
-	int timeout;
+	uint32_t timeout_ms;
 
 	mtx_assert(&qpair->lock, MA_OWNED);
 
@@ -1045,14 +1045,19 @@ nvme_qpair_submit_tracker(struct nvme_qpair *qpair, struct nvme_tracker *tr)
 	qpair->act_tr[tr->cid] = tr;
 	ctrlr = qpair->ctrlr;
 
-	if (req->timeout) {
+	if (req->timeout_ms != NVME_TIMEOUT_NONE) {
 		if (req->cb_fn == nvme_completion_poll_cb)
-			timeout = 1;
+			timeout_ms = 1000;
+		else if (req->timeout_ms != NVME_TIMEOUT_DEFAULT)
+			timeout_ms = req->timeout_ms;
+		else if (qpair->id == 0 && req->cmd.opc == NVME_OPC_FORMAT_NVM)
+			timeout_ms = ctrlr->format_timeout_period * 1000;
 		else if (qpair->id == 0)
-			timeout = ctrlr->admin_timeout_period;
+			timeout_ms = ctrlr->admin_timeout_period * 1000;
 		else
-			timeout = ctrlr->timeout_period;
-		tr->deadline = getsbinuptime() + timeout * SBT_1S;
+			timeout_ms = ctrlr->timeout_period * 1000;
+		tr->deadline = getsbinuptime() +
+		    (sbintime_t)timeout_ms * SBT_1MS;
 		if (!qpair->timer_armed) {
 			qpair->timer_armed = true;
 			callout_reset_sbt_on(&qpair->timer, SBT_1S / 2, SBT_1S / 2,