Skip to contentSkip to conversation

mpt3sas: Limit NVMe request size to 2 MiB

PATCH Superseded Ranjan Kumar 3 participants 6 messages Apr 13 – Apr 14

Subsystems (3)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

Ranjan Kumar

author maintainer
#0 lore raw

PATCH v3 1/1 mpt3sas: Limit NVMe request size to 2 MiB

The HBA firmware reports NVMe MDTS values based on the underlying drive capability. However, due to the 4K PRP page size and a limit of 512 entries, the driver supports a maximum I/O transfer size of 2 MiB.

Limit max_hw_sectors to the smaller of the reported MDTS and the 2 MiB driver limit to prevent issuing oversized I/O that may lead to a kernel oops.

---
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/scsi/mpt3sas/mpt3sas_scsih.c +13 -1
index 6ff788557294..44dd439e6f17 100644
@@ -2738,8 +2738,20 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim)
 				pcie_device->enclosure_level,
 				pcie_device->connector_name);
 
+		/*
+		 * The HBA firmware passes the NVMe drive's MDTS
+		 * (Maximum Data Transfer Size) up to the driver. However,
+		 * the driver hardcodes a 4K page size for the PRP list,
+		 * accommodating at most 512 entries. This strictly limits
+		 * the maximum supported NVMe I/O transfer to 2 MiB.
+		 *
+		 * Cap max_hw_sectors to the smaller of the drive's reported
+		 * MDTS or the 2 MiB driver limit to prevent kernel oopses.
+		 */
+		lim->max_hw_sectors = SZ_2M >> SECTOR_SHIFT;
 		if (pcie_device->nvme_mdts)
-			lim->max_hw_sectors = pcie_device->nvme_mdts / 512;
+			lim->max_hw_sectors = min_t(u32, lim->max_hw_sectors,
+					pcie_device->nvme_mdts >> SECTOR_SHIFT);
 
 		pcie_device_put(pcie_device);
 		spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
Signature · 1 line
2.47.3
#1 lore raw
Quoted 24 lines · On Mon, 13 Apr 2026 23:30:03 +0530 Ranjan Kumar <[email protected]>…

The HBA firmware reports NVMe MDTS values based on the underlying drive capability. However, due to the 4K PRP page size and a limit of 512 entries, the driver supports a maximum I/O transfer size of 2 MiB.

Limit max_hw_sectors to the smaller of the reported MDTS and the 2 MiB driver limit to prevent issuing oversized I/O that may lead to a kernel oops.

---
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/scsi/mpt3sas/mpt3sas_scsih.c +0 -0
index 6ff788557294..44dd439e6f17 100644

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2744

Quoted 7 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +4 -0
@@ -2738,8 +2738,20 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim)
 				pcie_device->enclosure_level,
 				pcie_device->connector_name);
 
+		/*
+		 * The HBA firmware passes the NVMe drive's MDTS
+		 * (Maximum Data Transfer Size) up to the driver. However,
+		 * the driver hardcodes a 4K page size for the PRP list,

^ buffer ?

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2746

Quoted 2 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +2 -0
+		 * accommodating at most 512 entries. This strictly limits
+		 * the maximum supported NVMe I/O transfer to 2 MiB.

Doesn't that make max_fw_entries 4096/8.
Assuming 4096 byte sectors the longest transfer is then 4096/8*4096. So none of this has anything to to with SECTOR_SHIFT.

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2754

Quoted 9 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +7 -1
+		 *
+		 * Cap max_hw_sectors to the smaller of the drive's reported
+		 * MDTS or the 2 MiB driver limit to prevent kernel oopses.
+		 */
+		lim->max_hw_sectors = SZ_2M >> SECTOR_SHIFT;
 		if (pcie_device->nvme_mdts)
-			lim->max_hw_sectors = pcie_device->nvme_mdts / 512;
+			lim->max_hw_sectors = min_t(u32, lim->max_hw_sectors,
+					pcie_device->nvme_mdts >> SECTOR_SHIFT);

Why min_t() ?

David

Quoted 3 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +0 -0
 		pcie_device_put(pcie_device);
 		spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
#2 lore raw
Quoted 35 lines · David Laight
Quoted 24 lines · On Mon, 13 Apr 2026 23:30:03 +0530 Ranjan Kumar <[email protected]>…

The HBA firmware reports NVMe MDTS values based on the underlying drive capability. However, due to the 4K PRP page size and a limit of 512 entries, the driver supports a maximum I/O transfer size of 2 MiB.

Limit max_hw_sectors to the smaller of the reported MDTS and the 2 MiB driver limit to prevent issuing oversized I/O that may lead to a kernel oops.

---
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/scsi/mpt3sas/mpt3sas_scsih.c +0 -0
index 6ff788557294..44dd439e6f17 100644

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2744

Quoted 7 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +4 -0
@@ -2738,8 +2738,20 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim)
 				pcie_device->enclosure_level,
 				pcie_device->connector_name);
 
+		/*
+		 * The HBA firmware passes the NVMe drive's MDTS
+		 * (Maximum Data Transfer Size) up to the driver. However,
+		 * the driver hardcodes a 4K page size for the PRP list,

^ buffer ?

Quoted 4 lines

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2746

Quoted 2 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +2 -0
+		 * accommodating at most 512 entries. This strictly limits
+		 * the maximum supported NVMe I/O transfer to 2 MiB.

Doesn't that make max_fw_entries 4096/8.

What is max_fw_entries ?
What the above explains is that a single NVMe page (4K) can store 512 (4096/8) PRP entries, each pointing at a 4K nvme page, so 512*4096=2M maximum size.

Quoted 1 line

Assuming 4096 byte sectors the longest transfer is then 4096/8*4096.

Yes, that's the SZ_2M Bytes.

Quoted 1 line

So none of this has anything to to with SECTOR_SHIFT.

Apparently, nvme_mdts is in bytes, even though the documentation in mpt3sas_base.h does not mention anything about its unit. So yes, we need a SECTOR_SHIFT to convert that to 512B sectors unit.

Quoted 12 lines

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2754

Quoted 10 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +7 -1
+		 *
+		 * Cap max_hw_sectors to the smaller of the drive's reported
+		 * MDTS or the 2 MiB driver limit to prevent kernel oopses.
+		 */
+		lim->max_hw_sectors = SZ_2M >> SECTOR_SHIFT;
 		if (pcie_device->nvme_mdts)
-			lim->max_hw_sectors = pcie_device->nvme_mdts / 512;
+			lim->max_hw_sectors = min_t(u32, lim->max_hw_sectors,
+					pcie_device->nvme_mdts >> SECTOR_SHIFT);

Why min_t() ?

max_hw_sectors is unsigned int and nvme_mdts is u32. Not sure if that bothers min(). Worth trying.

Quoted 7 lines

David

Quoted 3 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +0 -0
 		pcie_device_put(pcie_device);
 		spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
Signature · 2 lines
Damien Le Moal
Western Digital Research
#3 lore raw
Quoted 36 lines · On Tue, 14 Apr 2026 05:41:59 +0200 Damien Le Moal <[email protected]> wrote:
Quoted 35 lines · David Laight
Quoted 24 lines · On Mon, 13 Apr 2026 23:30:03 +0530 Ranjan Kumar <[email protected]>…

The HBA firmware reports NVMe MDTS values based on the underlying drive capability. However, due to the 4K PRP page size and a limit of 512 entries, the driver supports a maximum I/O transfer size of 2 MiB.

Limit max_hw_sectors to the smaller of the reported MDTS and the 2 MiB driver limit to prevent issuing oversized I/O that may lead to a kernel oops.

---
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/scsi/mpt3sas/mpt3sas_scsih.c +0 -0
index 6ff788557294..44dd439e6f17 100644

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2744

Quoted 7 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +4 -0
@@ -2738,8 +2738,20 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim)
 				pcie_device->enclosure_level,
 				pcie_device->connector_name);
 
+		/*
+		 * The HBA firmware passes the NVMe drive's MDTS
+		 * (Maximum Data Transfer Size) up to the driver. However,
+		 * the driver hardcodes a 4K page size for the PRP list,  

^ buffer ?

Quoted 6 lines
Quoted 4 lines

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2746

Quoted 2 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +2 -0
+		 * accommodating at most 512 entries. This strictly limits
+		 * the maximum supported NVMe I/O transfer to 2 MiB.  

Doesn't that make max_fw_entries 4096/8.

What is max_fw_entries ?

A mistype for max_hw_sectors :-(

Quoted 6 lines

What the above explains is that a single NVMe page (4K) can store 512 (4096/8) PRP entries, each pointing at a 4K nvme page, so 512*4096=2M maximum size.

Quoted 1 line

Assuming 4096 byte sectors the longest transfer is then 4096/8*4096.

Yes, that's the SZ_2M Bytes.

So write it as (4096/8)*4096

Quoted 6 lines
Quoted 2 lines

So none of this has anything to to with SECTOR_SHIFT.

Apparently, nvme_mdts is in bytes, even though the documentation in mpt3sas_base.h does not mention anything about its unit. So yes, we need a SECTOR_SHIFT to convert that to 512B sectors unit.

It is all very confusing because of the 4k and 512 byte sectors and there being another 512 constant.
Perhaps the best expression is:

	(4096 /* NVMe page */ / 8) * (4096 /* hw sector size */ >> SECTOR_SIZE)
Quoted 14 lines
Quoted 13 lines

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2754

Quoted 11 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +7 -1
+		 *
+		 * Cap max_hw_sectors to the smaller of the drive's reported
+		 * MDTS or the 2 MiB driver limit to prevent kernel oopses.
+		 */
+		lim->max_hw_sectors = SZ_2M >> SECTOR_SHIFT;
 		if (pcie_device->nvme_mdts)
-			lim->max_hw_sectors = pcie_device->nvme_mdts / 512;
+			lim->max_hw_sectors = min_t(u32, lim->max_hw_sectors,
+					pcie_device->nvme_mdts >> SECTOR_SHIFT);  

Why min_t() ?

Quoted 2 lines

max_hw_sectors is unsigned int and nvme_mdts is u32. Not sure if that bothers min(). Worth trying.

It doesn't bother it (any more).

David

Quoted 10 lines
Quoted 8 lines

David

Quoted 3 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +0 -0
 		pcie_device_put(pcie_device);
 		spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);  
#4 lore raw
Quoted 48 lines · David Laight
Quoted 36 lines · On Tue, 14 Apr 2026 05:41:59 +0200 Damien Le Moal <[email protected]> wrote:
Quoted 35 lines · David Laight
Quoted 24 lines · On Mon, 13 Apr 2026 23:30:03 +0530 Ranjan Kumar <[email protected]>…

The HBA firmware reports NVMe MDTS values based on the underlying drive capability. However, due to the 4K PRP page size and a limit of 512 entries, the driver supports a maximum I/O transfer size of 2 MiB.

Limit max_hw_sectors to the smaller of the reported MDTS and the 2 MiB driver limit to prevent issuing oversized I/O that may lead to a kernel oops.

---
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/scsi/mpt3sas/mpt3sas_scsih.c +0 -0
index 6ff788557294..44dd439e6f17 100644

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2744

Quoted 7 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +4 -0
@@ -2738,8 +2738,20 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim)
 				pcie_device->enclosure_level,
 				pcie_device->connector_name);
 
+		/*
+		 * The HBA firmware passes the NVMe drive's MDTS
+		 * (Maximum Data Transfer Size) up to the driver. However,
+		 * the driver hardcodes a 4K page size for the PRP list,  

^ buffer ?

Quoted 6 lines
Quoted 4 lines

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2746

Quoted 2 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +2 -0
+		 * accommodating at most 512 entries. This strictly limits
+		 * the maximum supported NVMe I/O transfer to 2 MiB.  

Doesn't that make max_fw_entries 4096/8.

What is max_fw_entries ?

A mistype for max_hw_sectors :-(

Quoted 8 lines
Quoted 6 lines

What the above explains is that a single NVMe page (4K) can store 512 (4096/8) PRP entries, each pointing at a 4K nvme page, so 512*4096=2M maximum size.

Quoted 1 line

Assuming 4096 byte sectors the longest transfer is then 4096/8*4096.

Yes, that's the SZ_2M Bytes.

So write it as (4096/8)*4096

See below.

Quoted 10 lines
Quoted 5 lines
Quoted 1 line

So none of this has anything to to with SECTOR_SHIFT.

Apparently, nvme_mdts is in bytes, even though the documentation in mpt3sas_base.h does not mention anything about its unit. So yes, we need a SECTOR_SHIFT to convert that to 512B sectors unit.

It is all very confusing because of the 4k and 512 byte sectors and there being another 512 constant.
Perhaps the best expression is:

	(4096 /* NVMe page */ / 8) * (4096 /* hw sector size */ >> SECTOR_SIZE)

Yes, we could, but I think the comment is clear enough, so I have no issue with the code as it is. But I will not fight this though. I will let Martin & James decide.

Quoted 12 lines
Quoted 12 lines
Quoted 11 lines

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2754

Quoted 9 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +7 -1
+		 *
+		 * Cap max_hw_sectors to the smaller of the drive's reported
+		 * MDTS or the 2 MiB driver limit to prevent kernel oopses.
+		 */
+		lim->max_hw_sectors = SZ_2M >> SECTOR_SHIFT;
 		if (pcie_device->nvme_mdts)
-			lim->max_hw_sectors = pcie_device->nvme_mdts / 512;
+			lim->max_hw_sectors = min_t(u32, lim->max_hw_sectors,
+					pcie_device->nvme_mdts >> SECTOR_SHIFT);  

Why min_t() ?

Quoted 4 lines
Quoted 2 lines

max_hw_sectors is unsigned int and nvme_mdts is u32. Not sure if that bothers min(). Worth trying.

It doesn't bother it (any more).

OK. Let's drop the min_t() then and use min().

Signature · 2 lines
Damien Le Moal
Western Digital Research
author maintainer
#5 lore raw

Hi Damien and David,
Thanks for the suggestions.

Quoted 101 lines · Damien Le Moal
Quoted 49 lines · David Laight
Quoted 37 lines · On Tue, 14 Apr 2026 05:41:59 +0200 Damien Le Moal <[email protected]> wrote:
Quoted 36 lines · David Laight
Quoted 24 lines · On Mon, 13 Apr 2026 23:30:03 +0530 Ranjan Kumar <[email protected]>…

The HBA firmware reports NVMe MDTS values based on the underlying drive capability. However, due to the 4K PRP page size and a limit of 512 entries, the driver supports a maximum I/O transfer size of 2 MiB.

Limit max_hw_sectors to the smaller of the reported MDTS and the 2 MiB driver limit to prevent issuing oversized I/O that may lead to a kernel oops.

---
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/scsi/mpt3sas/mpt3sas_scsih.c +0 -0
index 6ff788557294..44dd439e6f17 100644

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2744

Quoted 7 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +4 -0
@@ -2738,8 +2738,20 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim)
                           pcie_device->enclosure_level,
                           pcie_device->connector_name);
 
+          /*
+           * The HBA firmware passes the NVMe drive's MDTS
+           * (Maximum Data Transfer Size) up to the driver. However,
+           * the driver hardcodes a 4K page size for the PRP list,

^ buffer ?
I will change page size to "buffer size" .

Quoted 6 lines
Quoted 4 lines

drivers/scsi/mpt3sas/mpt3sas_scsih.c scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) · line 2746

Quoted 2 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +2 -0
+           * accommodating at most 512 entries. This strictly limits
+           * the maximum supported NVMe I/O transfer to 2 MiB.

Doesn't that make max_fw_entries 4096/8.

What is max_fw_entries ?

A mistype for max_hw_sectors :-(

Quoted 8 lines
Quoted 6 lines

What the above explains is that a single NVMe page (4K) can store 512 (4096/8) PRP entries, each pointing at a 4K nvme page, so 512*4096=2M maximum size.

Quoted 1 line

Assuming 4096 byte sectors the longest transfer is then 4096/8*4096.

Yes, that's the SZ_2M Bytes.

So write it as (4096/8)*4096

See below.

Quoted 10 lines
Quoted 5 lines
Quoted 1 line

So none of this has anything to to with SECTOR_SHIFT.

Apparently, nvme_mdts is in bytes, even though the documentation in mpt3sas_base.h does not mention anything about its unit. So yes, we need a SECTOR_SHIFT to convert that to 512B sectors unit.

It is all very confusing because of the 4k and 512 byte sectors and there being another 512 constant.
Perhaps the best expression is:

      (4096 /* NVMe page */ / 8) * (4096 /* hw sector size */ >> SECTOR_SIZE)

Yes, we could, but I think the comment is clear enough, so I have no issue with the code as it is. But I will not fight this though. I will let Martin & James decide.

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
drivers/scsi/mpt3sas/mpt3sas_scsih.c +7 -1
+           *
+           * Cap max_hw_sectors to the smaller of the drive's reported
+           * MDTS or the 2 MiB driver limit to prevent kernel oopses.
+           */
+          lim->max_hw_sectors = SZ_2M >> SECTOR_SHIFT;
           if (pcie_device->nvme_mdts)
-                  lim->max_hw_sectors = pcie_device->nvme_mdts / 512;
+                  lim->max_hw_sectors = min_t(u32, lim->max_hw_sectors,
+                                  pcie_device->nvme_mdts >> SECTOR_SHIFT);
Quoted 6 lines
Quoted 4 lines
Quoted 1 line

Why min_t() ?

max_hw_sectors is unsigned int and nvme_mdts is u32. Not sure if that bothers min(). Worth trying.

It doesn't bother it (any more).

OK. Let's drop the min_t() then and use min().

Quoted 2 lines

I will drop min_t() and will use min().
I'll include these updates in the v4 patch.

--
Damien Le Moal
Western Digital Research