[PATCH AUTOSEL 6.19-5.15] scsi: mpi3mr: Add NULL checks when resetting request and reply queues

Sasha Levin
2026-03-05T15:37:30Z

From: Ranjan Kumar <ranjan.kumar@broadcom.com>

[ Upstream commit fa96392ebebc8fade2b878acb14cce0f71016503 ]

The driver encountered a crash during resource cleanup when the reply and
request queues were NULL due to freed memory. This issue occurred when the
creation of reply or request queues failed, and the driver freed the memory
first, but attempted to mem set the content of the freed memory, leading to
a system crash.

Add NULL pointer checks for reply and request queues before accessing the
reply/request memory during cleanup

Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
Link: https://patch.msgid.link/20260212070026.30263-1-ranjan.kumar@broadcom.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

### Assessment

**What the fix does:** Adds NULL checks for `mrioc->op_reply_qinfo` and
`mrioc->req_qinfo` inside the loop in `mpi3mr_memset_buffers()`. The
function already has similar NULL checks for other pointers
(`admin_req_base`, `admin_reply_base`, `init_cmds.reply`) but was
missing checks for these two queue arrays.

**Bug mechanism:** When queue creation fails during controller
initialization or re-initialization, the cleanup path calls
`mpi3mr_memset_buffers()`. If `op_reply_qinfo` or `req_qinfo` was
already freed (or never allocated), dereferencing them causes a NULL
pointer dereference → kernel crash/oops.

**Callers:** The function is called from:
- `mpi3mr_init_ioc()` retry path (line 4405) — controller init failure
- `mpi3mr_reinit_ioc()` retry path (line 4598) — controller re-init
failure
- `mpi3mr_soft_reset_handler()` (line 5522) — controller reset
- `mpi3mr_remove()` (line 5748 in mpi3mr_os.c) — device removal

All of these are realistic trigger paths. The crash would happen on real
systems when queue creation fails (e.g., memory pressure, hardware
fault).

**Stable criteria:**
- **Fixes a real bug:** Yes — NULL pointer dereference causing a kernel
crash
- **Obviously correct:** Yes — simple NULL check before dereference,
consistent with existing patterns in the same function
- **Small and contained:** Yes — only adds two `if` checks wrapping
existing code, no behavioral change otherwise
- **No new features:** Correct — purely defensive NULL check
- **Risk:** Very low — the NULL check only skips work that would crash
anyway

### Verification

- Read the `mpi3mr_memset_buffers()` function (line 4667) and confirmed
it already has NULL checks for `admin_req_base`, `admin_reply_base`,
and `init_cmds.reply` but was missing them for `op_reply_qinfo` and
`req_qinfo`
- Confirmed `kfree(mrioc->req_qinfo)` and `kfree(mrioc->op_reply_qinfo)`
in the cleanup function (lines 4804, 4808) set pointers to NULL after
free, establishing the NULL state
- Verified callers of `mpi3mr_memset_buffers()`: called from init retry
paths (4405, 4598), reset handler (5522), and remove (5748) — all
reachable when queues may be NULL
- The commit message explicitly states the driver crashed during cleanup
— this is a reported real-world crash, not theoretical
- The fix follows the same pattern already used in the function for
other pointers
- The mpi3mr driver has been in the kernel since at least v5.15 (long-
standing driver), so this fix applies to stable trees

**YES**

drivers/scsi/mpi3mr/mpi3mr_fw.c | 34 ++++++++++++++++++---------------
1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 8c4bb7169a87c..8382afed12813 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -4705,21 +4705,25 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
}

for (i = 0; i < mrioc->num_queues; i++) {
- mrioc->op_reply_qinfo[i].qid = 0;
- mrioc->op_reply_qinfo[i].ci = 0;
- mrioc->op_reply_qinfo[i].num_replies = 0;
- mrioc->op_reply_qinfo[i].ephase = 0;
- atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
- atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0);
- mpi3mr_memset_op_reply_q_buffers(mrioc, i);
-
- mrioc->req_qinfo[i].ci = 0;
- mrioc->req_qinfo[i].pi = 0;
- mrioc->req_qinfo[i].num_requests = 0;
- mrioc->req_qinfo[i].qid = 0;
- mrioc->req_qinfo[i].reply_qid = 0;
- spin_lock_init(&mrioc->req_qinfo[i].q_lock);
- mpi3mr_memset_op_req_q_buffers(mrioc, i);
+ if (mrioc->op_reply_qinfo) {
+ mrioc->op_reply_qinfo[i].qid = 0;
+ mrioc->op_reply_qinfo[i].ci = 0;
+ mrioc->op_reply_qinfo[i].num_replies = 0;
+ mrioc->op_reply_qinfo[i].ephase = 0;
+ atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
+ atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0);
+ mpi3mr_memset_op_reply_q_buffers(mrioc, i);
+ }
+
+ if (mrioc->req_qinfo) {
+ mrioc->req_qinfo[i].ci = 0;
+ mrioc->req_qinfo[i].pi = 0;
+ mrioc->req_qinfo[i].num_requests = 0;
+ mrioc->req_qinfo[i].qid = 0;
+ mrioc->req_qinfo[i].reply_qid = 0;
+ spin_lock_init(&mrioc->req_qinfo[i].q_lock);
+ mpi3mr_memset_op_req_q_buffers(mrioc, i);
+ }
}

atomic_set(&mrioc->pend_large_data_sz, 0);
--
2.51.0