]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nvmet: introduce new mdts configuration entry
authorAurelien Aptel <aaptel@nvidia.com>
Wed, 8 Apr 2026 09:02:26 +0000 (09:02 +0000)
committerKeith Busch <kbusch@kernel.org>
Wed, 8 Apr 2026 15:13:46 +0000 (08:13 -0700)
Using this port configuration, one will be able to set the Maximum Data
Transfer Size (MDTS) for any controller that will be associated to the
configured port. The default value remains 0 (no limit).

Signed-off-by: Max Gurtovoy <mgurtovoy@nvidia.com>
Signed-off-by: Aurelien Aptel <aaptel@nvidia.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/configfs.c
drivers/nvme/target/core.c
drivers/nvme/target/nvmet.h
drivers/nvme/target/zns.c

index 3794ef25855693e18ca9b33172445b12dd0dfaa4..3842087209da553646f249e6bbed83ab54e05b90 100644 (file)
@@ -687,12 +687,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
        id->cmic = NVME_CTRL_CMIC_MULTI_PORT | NVME_CTRL_CMIC_MULTI_CTRL |
                NVME_CTRL_CMIC_ANA;
 
-       /* Limit MDTS according to transport capability */
-       if (ctrl->ops->get_mdts)
-               id->mdts = ctrl->ops->get_mdts(ctrl);
-       else
-               id->mdts = 0;
-
+       /* Limit MDTS according to port config or transport capability */
+       id->mdts = nvmet_ctrl_mdts(req);
        id->cntlid = cpu_to_le16(ctrl->cntlid);
        id->ver = cpu_to_le32(ctrl->subsys->ver);
 
index 463348c7f097bc5d45be4690110314ebe43a82bc..b88f897f06e25e3e604615c75dc55cc5b2a1f1a1 100644 (file)
@@ -301,6 +301,31 @@ static ssize_t nvmet_param_max_queue_size_store(struct config_item *item,
 
 CONFIGFS_ATTR(nvmet_, param_max_queue_size);
 
+static ssize_t nvmet_param_mdts_show(struct config_item *item, char *page)
+{
+       struct nvmet_port *port = to_nvmet_port(item);
+
+       return snprintf(page, PAGE_SIZE, "%d\n", port->mdts);
+}
+
+static ssize_t nvmet_param_mdts_store(struct config_item *item,
+               const char *page, size_t count)
+{
+       struct nvmet_port *port = to_nvmet_port(item);
+       int ret;
+
+       if (nvmet_is_port_enabled(port, __func__))
+               return -EACCES;
+       ret = kstrtoint(page, 0, &port->mdts);
+       if (ret) {
+               pr_err("Invalid value '%s' for mdts\n", page);
+               return -EINVAL;
+       }
+       return count;
+}
+
+CONFIGFS_ATTR(nvmet_, param_mdts);
+
 #ifdef CONFIG_BLK_DEV_INTEGRITY
 static ssize_t nvmet_param_pi_enable_show(struct config_item *item,
                char *page)
@@ -1995,6 +2020,7 @@ static struct configfs_attribute *nvmet_port_attrs[] = {
        &nvmet_attr_addr_tsas,
        &nvmet_attr_param_inline_data_size,
        &nvmet_attr_param_max_queue_size,
+       &nvmet_attr_param_mdts,
 #ifdef CONFIG_BLK_DEV_INTEGRITY
        &nvmet_attr_param_pi_enable,
 #endif
@@ -2053,6 +2079,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group,
        INIT_LIST_HEAD(&port->referrals);
        port->inline_data_size = -1;    /* < 0 == let the transport choose */
        port->max_queue_size = -1;      /* < 0 == let the transport choose */
+       port->mdts = -1;                /* < 0 == let the transport choose */
 
        port->disc_addr.trtype = NVMF_TRTYPE_MAX;
        port->disc_addr.portid = cpu_to_le16(portid);
index 03cc7d5f9683d6daac71ca0f68b26b65a0542f90..33db6c5534e21ed23173ffd0fd7d1e8b8b554274 100644 (file)
@@ -368,6 +368,14 @@ int nvmet_enable_port(struct nvmet_port *port)
                                               NVMET_MIN_QUEUE_SIZE,
                                               NVMET_MAX_QUEUE_SIZE);
 
+       /*
+        * If the transport didn't set the mdts properly, then clamp it to the
+        * target limits. Also set default values in case the transport didn't
+        * set it at all.
+        */
+       if (port->mdts < 0 || port->mdts > NVMET_MAX_MDTS)
+               port->mdts = 0;
+
        port->enabled = true;
        port->tr_ops = ops;
        return 0;
index 5db8f0d6e3f2c564628d51487831c08a71edb659..64af6bf569bf45ddc6e7d935cc4c46f5f2011c9c 100644 (file)
@@ -214,6 +214,7 @@ struct nvmet_port {
        bool                            enabled;
        int                             inline_data_size;
        int                             max_queue_size;
+       int                             mdts;
        const struct nvmet_fabrics_ops  *tr_ops;
        bool                            pi_enable;
 };
@@ -672,6 +673,7 @@ void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
 #define NVMET_MAX_QUEUE_SIZE   1024
 #define NVMET_NR_QUEUES                128
 #define NVMET_MAX_CMD(ctrl)    (NVME_CAP_MQES(ctrl->cap) + 1)
+#define NVMET_MAX_MDTS         255
 
 /*
  * Nice round number that makes a list of nsids fit into a page.
@@ -760,6 +762,17 @@ static inline bool nvmet_is_pci_ctrl(struct nvmet_ctrl *ctrl)
        return ctrl->port->disc_addr.trtype == NVMF_TRTYPE_PCI;
 }
 
+/* Limit MDTS according to port config or transport capability */
+static inline u8 nvmet_ctrl_mdts(struct nvmet_req *req)
+{
+       struct nvmet_ctrl *ctrl = req->sq->ctrl;
+       u8 mdts = req->port->mdts;
+
+       if (!ctrl->ops->get_mdts)
+               return mdts;
+       return min_not_zero(ctrl->ops->get_mdts(ctrl), mdts);
+}
+
 #ifdef CONFIG_NVME_TARGET_PASSTHRU
 void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys);
 int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys);
index aeaf73b54c3a3b42c656b2aa37dc706d4483dca6..f00921931eb64d624554a739b467ed96ec47f848 100644 (file)
@@ -69,7 +69,6 @@ bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
 void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req)
 {
        u8 zasl = req->sq->ctrl->subsys->zasl;
-       struct nvmet_ctrl *ctrl = req->sq->ctrl;
        struct nvme_id_ctrl_zns *id;
        u16 status;
 
@@ -79,10 +78,7 @@ void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req)
                goto out;
        }
 
-       if (ctrl->ops->get_mdts)
-               id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl);
-       else
-               id->zasl = zasl;
+       id->zasl = min_not_zero(nvmet_ctrl_mdts(req), zasl);
 
        status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));