git: 62caae230859 - main - nvmf: Honor any data transfer limit imposed by the transport

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Mon, 10 Nov 2025 15:51:22 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=62caae230859423ae045b5d754f30d193ca628c0

commit 62caae230859423ae045b5d754f30d193ca628c0
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-11-10 15:50:47 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2025-11-10 15:50:47 +0000

    nvmf: Honor any data transfer limit imposed by the transport
    
    If the transport has a data transfer limit, restrict I/O transfers to
    the largest multiple of MPS that fits within the limit.
    
    Sponsored by:   Chelsio Communications
---
 sys/dev/nvmf/host/nvmf.c       | 13 ++++++++++---
 sys/dev/nvmf/host/nvmf_qpair.c |  6 ++++++
 sys/dev/nvmf/host/nvmf_var.h   |  1 +
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/sys/dev/nvmf/host/nvmf.c b/sys/dev/nvmf/host/nvmf.c
index 1ac0d142443b..d6afdce54709 100644
--- a/sys/dev/nvmf/host/nvmf.c
+++ b/sys/dev/nvmf/host/nvmf.c
@@ -498,7 +498,7 @@ nvmf_attach(device_t dev)
 	nvlist_t *nvl = device_get_ivars(dev);
 	const nvlist_t * const *io;
 	struct sysctl_oid *oid;
-	uint64_t val;
+	uint64_t mpsmin, val;
 	u_int i;
 	int error;
 
@@ -545,13 +545,20 @@ nvmf_attach(device_t dev)
 	sc->vs = val;
 
 	/* Honor MDTS if it is set. */
+	mpsmin = (uint64_t)1 << (NVME_MPS_SHIFT +
+	    NVME_CAP_HI_MPSMIN(sc->cap >> 32));
 	sc->max_xfer_size = maxphys;
 	if (sc->cdata->mdts != 0) {
 		sc->max_xfer_size = ulmin(sc->max_xfer_size,
-		    1 << (sc->cdata->mdts + NVME_MPS_SHIFT +
-		    NVME_CAP_HI_MPSMIN(sc->cap >> 32)));
+		    mpsmin << sc->cdata->mdts);
 	}
 
+	/* Honor any transfer size restriction imposed by the transport. */
+	val = nvmf_max_xfer_size_qp(sc->io[0]);
+	if (val >= mpsmin)
+		sc->max_xfer_size = ulmin(sc->max_xfer_size,
+		    rounddown2(val, mpsmin));
+
 	io = nvlist_get_nvlist_array(nvl, "io", NULL);
 	sc->max_pending_io = nvlist_get_number(io[0], "qsize") *
 	    sc->num_io_queues;
diff --git a/sys/dev/nvmf/host/nvmf_qpair.c b/sys/dev/nvmf/host/nvmf_qpair.c
index 2f511cf0406d..adb57e52d002 100644
--- a/sys/dev/nvmf/host/nvmf_qpair.c
+++ b/sys/dev/nvmf/host/nvmf_qpair.c
@@ -416,6 +416,12 @@ nvmf_destroy_qp(struct nvmf_host_qpair *qp)
 	free(qp, M_NVMF);
 }
 
+uint64_t
+nvmf_max_xfer_size_qp(struct nvmf_host_qpair *qp)
+{
+	return (nvmf_max_xfer_size(qp->qp));
+}
+
 void
 nvmf_submit_request(struct nvmf_request *req)
 {
diff --git a/sys/dev/nvmf/host/nvmf_var.h b/sys/dev/nvmf/host/nvmf_var.h
index 606245b3969c..9190da300d85 100644
--- a/sys/dev/nvmf/host/nvmf_var.h
+++ b/sys/dev/nvmf/host/nvmf_var.h
@@ -210,6 +210,7 @@ struct nvmf_host_qpair *nvmf_init_qp(struct nvmf_softc *sc,
     enum nvmf_trtype trtype, const nvlist_t *nvl, const char *name, u_int qid);
 void	nvmf_shutdown_qp(struct nvmf_host_qpair *qp);
 void	nvmf_destroy_qp(struct nvmf_host_qpair *qp);
+uint64_t nvmf_max_xfer_size_qp(struct nvmf_host_qpair *qp);
 struct nvmf_request *nvmf_allocate_request(struct nvmf_host_qpair *qp,
     void *sqe, nvmf_request_complete_t *cb, void *cb_arg, int how);
 void	nvmf_submit_request(struct nvmf_request *req);