summaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
authorRanjan Kumar <ranjan.kumar@broadcom.com>2026-09-16 13:56:59 +0530
committerMartin K. Petersen (Oracle) <mkp@kernel.org>2026-09-16 22:14:22 -0400
commitfb8b6139770a5dee8ace9e605b5c3d11861506c8 (patch)
tree10f3315703e5a962c984d736d4f653b52a700610 /drivers/scsi
parent48c666139acfef3bce5cc337b7d2cc2e089f87b5 (diff)
downloadlinux-next-fb8b6139770a5dee8ace9e605b5c3d11861506c8.tar.gz
linux-next-fb8b6139770a5dee8ace9e605b5c3d11861506c8.zip
scsi: mpi3mr: Fix NVMe page size caching for non-operational devices
For NVMe devices in an error state, the cached PCIe page size remains unset. This causes management IOCTL validation to fail, preventing requests from reaching firmware and returning incorrect errors to userspace. Populate the page size attribute irrespective of device access status so firmware can process IOCTLs and report appropriate errors. Additionally, harden the device initialization path against invalid firmware data for non-operational devices: 1. Add bounds checking for page_size, falling back to 4096 bytes (shift exponent 12) to prevent undefined shift behavior and kernel panics. The minimum valid NVMe page size shift is 12 and maximum is 27. 2. Initialize reset_to and abort_to timeouts with default values to prevent IOCTLs from failing instantly. To avoid race conditions where concurrent readers might observe these default timeouts before they are updated with firmware values, use local variables to compute the final values before writing them to the device structure. 3. Read the firmware-provided page size once into a local variable before validating and using it, since it lives in memory the device can also write to. Using it directly in both the check and the assignment allowed the two to observe different values. Reported-by: Sashiko <sashiko-bot@kernel.org> Closes: https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=4 Closes: https://sashiko.dev/#/patchset/20260708183305.244485-1-ranjan.kumar@broadcom.com?part=4 Closes: https://sashiko.dev/#/patchset/20260724102505.115136-1-ranjan.kumar@broadcom.com?part=4 Closes: https://sashiko.dev/#/patchset/20260805110634.346670-1-ranjan.kumar@broadcom.com?part=4 Co-developed-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com> Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com> Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com> Link: https://patch.msgid.link/20260916082705.44712-5-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr.h1
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_os.c24
2 files changed, 17 insertions, 8 deletions
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 1f2f0951b560..6128b30112e2 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -169,6 +169,7 @@ extern atomic64_t event_counter;
#define MPI3MR_DEFAULT_MDTS (128 * 1024)
#define MPI3MR_DEFAULT_PGSZEXP (12)
+#define MPI3MR_MAX_PGSZEXP (27)
/* Command retry count definitions */
#define MPI3MR_DEV_RMHS_RETRY_COUNT 3
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 07a2a45b4957..5506fc87f1ca 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -1350,24 +1350,32 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
struct mpi3_device0_pcie_format *pcieinf =
&dev_pg0->device_specific.pcie_format;
u16 dev_info = le16_to_cpu(pcieinf->device_info);
+ u8 pgsz = MPI3MR_DEFAULT_PGSZEXP;
+ u8 reset_to = MPI3MR_INTADMCMD_TIMEOUT;
+ u8 abort_to = MPI3MR_INTADMCMD_TIMEOUT;
+ u8 fw_pgsz = READ_ONCE(pcieinf->page_size);
tgtdev->dev_spec.pcie_inf.dev_info = dev_info;
tgtdev->dev_spec.pcie_inf.capb =
le32_to_cpu(pcieinf->capabilities);
tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS;
- /* 2^12 = 4096 */
- tgtdev->dev_spec.pcie_inf.pgsz = 12;
+ /* Validate firmware page size to prevent undefined shift behavior */
+ if (fw_pgsz >= MPI3MR_DEFAULT_PGSZEXP && fw_pgsz <= MPI3MR_MAX_PGSZEXP)
+ pgsz = fw_pgsz;
+
if (dev_pg0->access_status == MPI3_DEVICE0_ASTATUS_NO_ERRORS) {
tgtdev->dev_spec.pcie_inf.mdts =
le32_to_cpu(pcieinf->maximum_data_transfer_size);
- tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size;
- tgtdev->dev_spec.pcie_inf.reset_to =
- max_t(u8, pcieinf->controller_reset_to,
- MPI3MR_INTADMCMD_TIMEOUT);
- tgtdev->dev_spec.pcie_inf.abort_to =
- max_t(u8, pcieinf->nvme_abort_to,
+ reset_to = max_t(u8, pcieinf->controller_reset_to,
+ MPI3MR_INTADMCMD_TIMEOUT);
+ abort_to = max_t(u8, pcieinf->nvme_abort_to,
MPI3MR_INTADMCMD_TIMEOUT);
}
+
+ tgtdev->dev_spec.pcie_inf.pgsz = pgsz;
+ tgtdev->dev_spec.pcie_inf.reset_to = reset_to;
+ tgtdev->dev_spec.pcie_inf.abort_to = abort_to;
+
if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024))
tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024);
if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=