* Re: [PATCH] fix: scsi: srp_reconnect_rport: unbalanced scsi_block_targets/scsi_target_unblock
From: James Bottomley @ 2026-06-26 16:50 UTC (permalink / raw)
To: WenTao Liang, James Bottomley, Martin K . Petersen, linux-scsi
Cc: stable, linux-kernel
In-Reply-To: <20260626161402.55116-1-vulab@iscas.ac.cn>
On Sat, 2026-06-27 at 00:14 +0800, WenTao Liang wrote:
> In srp_reconnect_rport(), scsi_block_targets() is called only when
> rport->state is not FAIL_FAST and not LOST. However,
> scsi_target_unblock() is called unconditionally on the success path
> and on some error paths, causing an extra kref_put on sdev_gendev
> when block was never called.
I don't believe this is true: block and unblock calls don't have an
unbalanced kref in them (by design, since you're supposed to be able to
have unblock called on a running device and be a no-op).
Regards,
James
^ permalink raw reply
* Re: [PATCH] fix: scsi: srp_reconnect_rport: unbalanced scsi_block_targets/scsi_target_unblock
From: sashiko-bot @ 2026-06-26 16:18 UTC (permalink / raw)
To: WenTao Liang; +Cc: linux-scsi
In-Reply-To: <20260626161402.55116-1-vulab@iscas.ac.cn>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing curly braces around the `if` block causes `blocked = true;` to execute unconditionally, defeating the intended fix.
--
commit c11303cf8aa2900f23dfb0d36f22857ab2b9cb38
Author: WenTao Liang <vulab@iscas.ac.cn>
fix: scsi: srp_reconnect_rport: unbalanced scsi_block_targets/scsi_target_unblock
This commit introduces a blocked flag to srp_reconnect_rport() to track
if scsi_block_targets() was called. This is intended to prevent an extra
scsi_target_unblock() call which results in an unbalanced kref_put.
> diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
> index a61cbb079ab4e..d7c2608b73ef3 100644
> --- a/drivers/scsi/scsi_transport_srp.c
> +++ b/drivers/scsi/scsi_transport_srp.c
[ ... ]
> @@ -549,6 +550,7 @@ int srp_reconnect_rport(struct srp_rport *rport)
> * treats SDEV_TRANSPORT_OFFLINE like SDEV_BLOCK.
> */
> scsi_block_targets(shost, &shost->shost_gendev);
> + blocked = true;
[Severity: High]
Does this missing brace cause the blocked flag to be set unconditionally?
Looking at srp_reconnect_rport(), the preceding if statement lacks curly
braces:
if (rport->state != SRP_RPORT_FAIL_FAST && rport->state != SRP_RPORT_LOST)
/* ... */
scsi_block_targets(shost, &shost->shost_gendev);
blocked = true;
Because blocked = true is treated as a separate sequential statement, it will
execute regardless of the rport->state check.
Does this entirely defeat the fix by leaving the unbalanced
scsi_target_unblock() reference counting issue active?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626161402.55116-1-vulab@iscas.ac.cn?part=1
^ permalink raw reply
* [PATCH] fix: scsi: srp_reconnect_rport: unbalanced scsi_block_targets/scsi_target_unblock
From: WenTao Liang @ 2026-06-26 16:14 UTC (permalink / raw)
To: James Bottomley, Martin K . Petersen, linux-scsi
Cc: stable, linux-kernel, WenTao Liang
In srp_reconnect_rport(), scsi_block_targets() is called only when
rport->state is not FAIL_FAST and not LOST. However,
scsi_target_unblock() is called unconditionally on the success path and
on some error paths, causing an extra kref_put on sdev_gendev when block
was never called.
Introduce a 'blocked' flag to track whether scsi_block_targets() was
called, and only call scsi_target_unblock() when blocked is true.
Cc: stable@vger.kernel.org
Fixes: 09345f65058b ("[SCSI] add srp transport class")
Signed-off-by: WenTao Liang <vulab@iscas.ac.cn>
---
drivers/scsi/scsi_transport_srp.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
index d71ab5fdb758..b9f67e143b52 100644
--- a/drivers/scsi/scsi_transport_srp.c
+++ b/drivers/scsi/scsi_transport_srp.c
@@ -535,6 +535,7 @@ int srp_reconnect_rport(struct srp_rport *rport)
struct srp_internal *i = to_srp_internal(shost->transportt);
struct scsi_device *sdev;
int res;
+ bool blocked = false;
pr_debug("SCSI host %s\n", dev_name(&shost->shost_gendev));
@@ -549,6 +550,7 @@ int srp_reconnect_rport(struct srp_rport *rport)
* treats SDEV_TRANSPORT_OFFLINE like SDEV_BLOCK.
*/
scsi_block_targets(shost, &shost->shost_gendev);
+ blocked = true;
res = rport->state != SRP_RPORT_LOST ? i->f->reconnect(rport) : -ENODEV;
pr_debug("%s (state %d): transport.reconnect() returned %d\n",
dev_name(&shost->shost_gendev), rport->state, res);
@@ -558,7 +560,8 @@ int srp_reconnect_rport(struct srp_rport *rport)
rport->failed_reconnects = 0;
srp_rport_set_state(rport, SRP_RPORT_RUNNING);
- scsi_target_unblock(&shost->shost_gendev, SDEV_RUNNING);
+ if (blocked)
+ scsi_target_unblock(&shost->shost_gendev, SDEV_RUNNING);
/*
* If the SCSI error handler has offlined one or more devices,
* invoking scsi_target_unblock() won't change the state of
@@ -579,7 +582,8 @@ int srp_reconnect_rport(struct srp_rport *rport)
__rport_fail_io_fast(rport);
__srp_start_tl_fail_timers(rport);
} else if (rport->state != SRP_RPORT_BLOCKED) {
- scsi_target_unblock(&shost->shost_gendev,
+ if (blocked)
+ scsi_target_unblock(&shost->shost_gendev,
SDEV_TRANSPORT_OFFLINE);
}
mutex_unlock(&rport->mutex);
--
2.39.5 (Apple Git-154)
^ permalink raw reply related
* [PATCH] fix: scsi: cxgbi: cxgbi_ep_connect: remove extra cxgbi_sock_get leading to reference leak
From: WenTao Liang @ 2026-06-26 16:11 UTC (permalink / raw)
To: James Bottomley, Martin K . Petersen, linux-scsi
Cc: stable, linux-kernel, WenTao Liang
In cxgbi_ep_connect(), an explicit cxgbi_sock_get(csk) is called before
sock_get_port(csk), which internally calls cxgbi_sock_get(csk) again.
After sock_get_port, all error paths release only one reference via
release_conn, while the success path returns without releasing any. This
results in one leaked reference on every code path.
Remove the redundant cxgbi_sock_get(csk) call, letting sock_get_port's
internal get serve as the sole reference acquisition.
Cc: stable@vger.kernel.org
Signed-off-by: WenTao Liang <vulab@iscas.ac.cn>
---
drivers/scsi/cxgbi/libcxgbi.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 6a109269c68c..d2e8c8b8a138 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -2891,10 +2891,12 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost,
if (IS_ERR(csk))
return (struct iscsi_endpoint *)csk;
+
if (!hba)
hba = csk->cdev->hbas[csk->port_id];
else if (hba != csk->cdev->hbas[csk->port_id]) {
if (ifindex != hba->ndev->ifindex) {
+ cxgbi_sock_put(csk);
cxgbi_sock_closed(csk);
ifindex = hba->ndev->ifindex;
goto check_route;
--
2.39.5 (Apple Git-154)
^ permalink raw reply related
* Re: [PATCH v3 2/6] scsi: Protect INQUIRY sysfs attributes with mutex
From: Hannes Reinecke @ 2026-06-26 14:31 UTC (permalink / raw)
To: Bart Van Assche, Brian Bunker; +Cc: linux-scsi, krishna.kant
In-Reply-To: <5de0e746-1a90-4a41-a36b-e56a4fcfeee6@acm.org>
On 5/2/26 18:37, Bart Van Assche wrote:
> On 5/1/26 3:11 PM, Brian Bunker wrote:
>>> + sdev->vendor = (char *)(sdev->inquiry + 8);
>>> + sdev->model = (char *)(sdev->inquiry + 16);
>>> + sdev->rev = (char *)(sdev->inquiry + 32);
>>>
>>> I really hate these.
>>> Can't we replace them with accessor functions and drop the pointers?
>
> Hannes, what type of accessor functions do you have in mind? I don't
> like accessor functions that only do half of the job (returning the
> start pointer but not the length). Or are you perhaps suggesting to
> define accessor functions that return a struct with both the start
> pointer and the length, something that is uncommon in the Linux kernel?
>
> Another possibility is to change sdev->vendor, sdev->model and
> sdev->rev from pointers to fixed size strings into '\0'-terminated char
> arrays.
>
Well, the strings in the INQUIRY are pretty well defined, and we know
exactly which fields they cover in the inquiry data.
Copying them them out leads to quite some churn (and additional
allocations for storing them) with no real gain.
So for sysfs we can define accesors which copy the data out into the
sysfs buffer, and for comparison we can have accessors
'scsi_inq_model_cmp()' or something which compare the input string
against the data in the inquiry via memcmp().
No need in copying out data methinks.
Cheers,
Hannes
--
Dr. Hannes Reinecke Kernel Storage Architect
hare@suse.de +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich
^ permalink raw reply
* Re: [PATCH v11 5/6] arm64: dts: qcom: monaco: Add OPP-table for ICE UFS and ICE eMMC nodes
From: Konrad Dybcio @ 2026-06-26 14:28 UTC (permalink / raw)
To: Abhinaba Rakshit
Cc: Bjorn Andersson, Konrad Dybcio, Manivannan Sadhasivam,
James E.J. Bottomley, Martin K. Petersen, Adrian Hunter,
Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Neeraj Soni, Harshal Dev, Kuldeep Singh, linux-arm-msm,
linux-kernel, linux-scsi, linux-mmc, devicetree
In-Reply-To: <ajjmXMKdWzae5qqk@hu-arakshit-hyd.qualcomm.com>
On 6/22/26 9:38 AM, Abhinaba Rakshit wrote:
> On Thu, Jun 18, 2026 at 03:04:57PM +0200, Konrad Dybcio wrote:
>> On 6/8/26 11:47 PM, Abhinaba Rakshit wrote:
>>> Qualcomm Inline Crypto Engine (ICE) platform driver now, supports
>>> an optional OPP-table.
>>>
>>> Add OPP-table for ICE UFS and ICE eMMC device nodes for Monaco
>>> platform.
>>>
>>> Signed-off-by: Abhinaba Rakshit <abhinaba.rakshit@oss.qualcomm.com>
>>> ---
>>> arch/arm64/boot/dts/qcom/monaco.dtsi | 37 ++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 37 insertions(+)
>>>
>>> diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
>>> index a1b6e6211b84d0d5008231c55613a0ccd61b9450..d9298d8b7874b8669b2cded2a28a99dce6eadbda 100644
>>> --- a/arch/arm64/boot/dts/qcom/monaco.dtsi
>>> +++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
>>> @@ -2742,6 +2742,27 @@ ice: crypto@1d88000 {
>>> clock-names = "core",
>>> "iface";
>>> power-domains = <&gcc GCC_UFS_PHY_GDSC>;
>>> +
>>> + operating-points-v2 = <&ice_opp_table>;
>>> +
>>> + ice_opp_table: opp-table {
>>> + compatible = "operating-points-v2";
>>> +
>>> + opp-75000000 {
>>> + opp-hz = /bits/ 64 <75000000>;
>>> + required-opps = <&rpmhpd_opp_svs_l1>;
>>> + };
>>> +
>>> + opp-201600000 {
>>> + opp-hz = /bits/ 64 <201600000>;
>>> + required-opps = <&rpmhpd_opp_svs_l1>;
>>> + };
>>
>> Since 75 MHz and 201.6 Mhz require the same power level, is the former
>> OPP any useful?
>
> Yes, both use the same power requirements. However recommended by the ICE team,
> the DT should include all opp/freq supported by the hardware.
Is there any reason at all where the OS would prefer the lower OPP?
I think you at one point mentioned some dependency vs the storage
controller's clock frequency
Konrad
^ permalink raw reply
* Re: [PATCH v1 09/10] mpi3mr: Fix SAS PHY cleanup in host addition error paths
From: sashiko-bot @ 2026-06-26 12:16 UTC (permalink / raw)
To: Ranjan Kumar; +Cc: linux-scsi
In-Reply-To: <20260626114109.43685-10-ranjan.kumar@broadcom.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Unhandled Error Path / NULL Pointer Dereference when adding host PHYs.
--
commit 5d2df761c30d63d86fc3554a56dabf8408d62592
Author: Ranjan Kumar <ranjan.kumar@broadcom.com>
mpi3mr: Fix SAS PHY cleanup in host addition error paths
When adding a SAS host, the driver allocates a PHY array and subsequently
creates individual SAS PHYs. If a later step fails, the error path exits
without cleaning up previously allocated resources, resulting in leaks of
both the PHY array and any registered SAS PHYs.
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> index 1b793d86f7589..0236bbfcff6d9 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
[ ... ]
> @@ -1264,7 +1265,7 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
>
> if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
> if (!mpi3mr_alloc_hba_port(mrioc, port_id))
> - goto out;
> + goto out_free_phy;
>
> mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
> mrioc->sas_hba.phy[i].phy_id = i;
[Severity: High]
This isn't a bug introduced by this patch, but is it safe to ignore the return
value of mpi3mr_add_host_phy() which is called just after this block?
If mpi3mr_add_host_phy() fails (e.g., at sas_phy_add()), it returns -1. At
this point, mr_sas_phy->remote_identify.sas_address is already populated with
the attached device's SAS address, but mr_sas_phy->phy is left as NULL.
Later, when the attached device triggers a device addition event,
mpi3mr_sas_port_add() successfully matches the failed PHY because the
remote_identify.sas_address is populated:
drivers/scsi/mpi3mr/mpi3mr_transport.c:mpi3mr_sas_port_add() {
...
if ((mr_sas_node->phy[i].remote_identify.sas_address !=
mr_sas_port->remote_identify.sas_address) ||
(mr_sas_node->phy[i].hba_port != hba_port))
continue;
...
}
It then unconditionally passes the NULL mr_sas_phy->phy to sas_port_add_phy(),
which dereferences it without checking, causing a kernel panic:
drivers/scsi/mpi3mr/mpi3mr_transport.c:mpi3mr_sas_port_add() {
...
sas_port_add_phy(port, mr_sas_phy->phy);
...
}
Should mpi3mr_sas_host_add() handle the failure of mpi3mr_add_host_phy() and
jump to the new out_free_phy label?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=9
^ permalink raw reply
* Re: [PATCH v1 04/10] mpi3mr: Fix NVMe page size caching for non-operational devices
From: sashiko-bot @ 2026-06-26 12:07 UTC (permalink / raw)
To: Ranjan Kumar; +Cc: linux-scsi
In-Reply-To: <20260626114109.43685-5-ranjan.kumar@broadcom.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Unvalidated firmware-provided `page_size` used as a shift exponent can lead to Undefined Behavior and a divide-by-zero panic.
--
commit f5cd5ed48fb67b9c92c834f74f43b66abd174677
Author: Ranjan Kumar <ranjan.kumar@broadcom.com>
mpi3mr: Fix NVMe page size caching for non-operational devices
This commit updates the driver to populate the PCIe page size attribute
regardless of the device access status, ensuring management IOCTLs can be
processed for non-operational devices.
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -1354,12 +1354,10 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> 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;
> + tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size;
[Severity: High]
This is a pre-existing issue, but does removing the NO_ERRORS check expose
the driver to undefined behavior if the firmware returns garbage data?
For devices in an error state, the firmware might return uninitialized
data like 0xFF for pcieinf->page_size. This unvalidated value is later
used in shift operations:
drivers/scsi/mpi3mr/mpi3mr_app.c:mpi3mr_build_nvme_prp() {
...
dev_pgsz = 1 << (tgtdev->dev_spec.pcie_inf.pgsz);
...
}
and
drivers/scsi/mpi3mr/mpi3mr_os.c:mpi3mr_configure_nvme_dev() {
...
lim->virt_boundary_mask = (1 << pgsz) - 1;
...
}
Since 1 is a 32-bit signed integer, evaluating 1 << pgsz with a value
of 31 or greater results in signed integer overflow or a shift out of
bounds. If the shift evaluates to 0 on some architectures, it could also
cause a divide-by-zero panic when computing MPI3MR_IOCTL_SGE_SIZE % dev_pgsz
later in the code.
Is it possible to add bounds checking for the page_size before assigning
it to tgtdev->dev_spec.pcie_inf.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);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=4
^ permalink raw reply
* Re: [PATCH v1 02/10] mpi3mr: Update MPI Headers to revision 41
From: sashiko-bot @ 2026-06-26 12:07 UTC (permalink / raw)
To: Ranjan Kumar; +Cc: linux-scsi
In-Reply-To: <20260626114109.43685-3-ranjan.kumar@broadcom.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing endian conversion for `driver_pg1.flags` before bitwise AND.
--
commit dcead2e50e7c04fa8f12bc236d238e9408c959bb
Author: Ranjan Kumar <ranjan.kumar@broadcom.com>
mpi3mr: Update MPI Headers to revision 41
Update MPI Headers to revision 41.
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
[ ... ]
> @@ -4128,11 +4128,15 @@ mpi3mr_read_driver_page1(struct mpi3mr_ioc *mrioc)
> struct mpi3_driver_page1 driver_pg1;
> u16 pg_sz = sizeof(driver_pg1);
> int retval = 0;
>
> mrioc->ts_update_interval = MPI3MR_TSUPDATE_INTERVAL;
> + mrioc->skip_dev_shutdown_on_unload = 0;
>
> retval = mpi3mr_cfg_get_driver_pg1(mrioc, &driver_pg1, pg_sz);
> - if (!retval && driver_pg1.time_stamp_update)
> +
> + if (retval)
> + return;
> +
> + if (driver_pg1.time_stamp_update)
> mrioc->ts_update_interval = (driver_pg1.time_stamp_update * 60);
> +
> + mrioc->skip_dev_shutdown_on_unload =
> + (driver_pg1.flags &
> + MPI3_DRIVER1_FLAGS_DEVICE_SHUTDOWN_ON_UNLOAD_DISABLE) ? 1 : 0;
[Severity: High]
Does this code miss an endianness conversion for driver_pg1.flags before the
bitwise AND?
If driver_pg1.flags is populated natively in little-endian format from the
controller without swapping, evaluating it against a host-endian macro could
lead to incorrect logic on Big-Endian architectures.
For example, if the firmware sets
MPI3_DRIVER1_FLAGS_DEVICE_SHUTDOWN_ON_UNLOAD_DISABLE (0x01), a Big-Endian CPU
would read it as 0x01000000, evaluate the check to false, and fail to skip the
requested device shutdown.
Conversely, if a future flag sets bit 24, a Big-Endian CPU reads it as
0x00000001, evaluates the check to true, and falsely skips device shutdown,
which could lead to data loss such as unflushed drive caches.
Is le32_to_cpu() or similar needed here?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=2
^ permalink raw reply
* Re: [PATCH v1 08/10] mpi3mr: Fix SAS port allocation and registration error handling
From: sashiko-bot @ 2026-06-26 12:06 UTC (permalink / raw)
To: Ranjan Kumar; +Cc: linux-scsi
In-Reply-To: <20260626114109.43685-9-ranjan.kumar@broadcom.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] The reference to the target device (`tgtdev`) is leaked and the `pend_sas_rphy_add` state remains inconsistent on error paths.
- [High] Missing NULL pointer check after `rphy` allocation leads to a guaranteed NULL pointer dereference on allocation failure.
- [High] Failure of `sas_rphy_add()` is ignored, leaving the driver and device model in an invalid state.
--
commit 2228b7db89a5c405d93e9a1b01afe8d02a73da5c
Author: Ranjan Kumar <ranjan.kumar@broadcom.com>
mpi3mr: Fix SAS port allocation and registration error handling
During SAS port creation, the driver does not verify successful port
allocation before attempting registration, which can lead to a NULL
pointer dereference. Additionally, if registration fails, the allocated
port is not freed, resulting in a memory leak.
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> index 240f67a8e2e3b..1b793d86f7589 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> @@ -1428,9 +1428,15 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
> }
>
> port = sas_port_alloc_num(mr_sas_node->parent_dev);
> + if (!port) {
> + ioc_err(mrioc, "failure at %s:%d/%s() (sas_port_alloc)!\n",
> + __FILE__, __LINE__, __func__);
> + goto out_fail;
[Severity: High]
This is a pre-existing issue, but does jumping to out_fail here leak the
tgtdev reference?
If mpi3mr_sas_port_add() is called for a SAS_END_DEVICE, it acquires a
reference to tgtdev earlier in the function:
drivers/scsi/mpi3mr/mpi3mr_transport.c:mpi3mr_sas_port_add() {
...
if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
tgtdev = mpi3mr_get_tgtdev_by_addr(mrioc,
mr_sas_port->remote_identify.sas_address,
mr_sas_port->hba_port);
...
}
When sas_port_alloc_num() fails and the code jumps to out_fail, it frees
mr_sas_port but misses the necessary mpi3mr_tgtdev_put(tgtdev) cleanup:
drivers/scsi/mpi3mr/mpi3mr_transport.c:mpi3mr_sas_port_add() {
...
out_fail:
list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,
port_siblings)
list_del(&mr_sas_phy->port_siblings);
kfree(mr_sas_port);
return NULL;
}
Will this lead to a resource leak of the tgtdev structure that prevents
device removal?
> + }
> if ((sas_port_add(port))) {
> ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> __FILE__, __LINE__, __func__);
> + sas_port_free(port);
> goto out_fail;
[Severity: High]
This is a pre-existing issue, but this path also appears to leak the tgtdev
reference in the same way as described above when sas_port_add() fails.
> }
[Severity: High]
This is a pre-existing issue, but can this function unconditionally
dereference rphy if the allocation fails?
Further down in mpi3mr_sas_port_add(), rphy is allocated but immediately
dereferenced without a check:
drivers/scsi/mpi3mr/mpi3mr_transport.c:mpi3mr_sas_port_add() {
...
if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
rphy = sas_end_device_alloc(port);
tgtdev->dev_spec.sas_sata_inf.rphy = rphy;
} else {
rphy = sas_expander_alloc(port,
mr_sas_port->remote_identify.device_type);
}
rphy->identify = mr_sas_port->remote_identify;
...
}
If sas_end_device_alloc() or sas_expander_alloc() return NULL under memory
pressure, wouldn't the assignment to rphy->identify cause a kernel panic?
[Severity: High]
This is a pre-existing issue, but is the driver left in an invalid state if
sas_rphy_add() fails?
Later in the same function, the return value of sas_rphy_add() is caught
but ignored:
drivers/scsi/mpi3mr/mpi3mr_transport.c:mpi3mr_sas_port_add() {
...
if ((sas_rphy_add(rphy))) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
}
...
}
If sas_rphy_add() fails, does the driver leak the rphy memory since
sas_port_delete() won't free it if it wasn't successfully added?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=8
^ permalink raw reply
* Re: [PATCH v1 01/10] mpi3mr: Skip device shutdown during unload per controller configuration
From: sashiko-bot @ 2026-06-26 12:03 UTC (permalink / raw)
To: Ranjan Kumar; +Cc: linux-scsi
In-Reply-To: <20260626114109.43685-2-ranjan.kumar@broadcom.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missing `le32_to_cpu()` conversion when reading the little-endian `flags` field from `driver_pg1`.
--
commit d356c9ee9428175d4bc2bdb0dd4aaf2c6a81d8bd
Author: Ranjan Kumar <ranjan.kumar@broadcom.com>
mpi3mr: Skip device shutdown during unload per controller configuration
This commit updates the driver to cache the Driver Page 1 configuration
and skip device shutdown requests during driver unload when the controller
requests it.
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 31b19ed1528e5..eb730318db474 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
[ ... ]
> static void
> -mpi3mr_read_tsu_interval(struct mpi3mr_ioc *mrioc)
> +mpi3mr_read_driver_page1(struct mpi3mr_ioc *mrioc)
> {
> struct mpi3_driver_page1 driver_pg1;
> u16 pg_sz = sizeof(driver_pg1);
> int retval = 0;
>
> mrioc->ts_update_interval = MPI3MR_TSUPDATE_INTERVAL;
> + mrioc->skip_dev_shutdown_on_unload = 0;
>
> retval = mpi3mr_cfg_get_driver_pg1(mrioc, &driver_pg1, pg_sz);
> - if (!retval && driver_pg1.time_stamp_update)
> +
> + if (retval)
> + return;
> +
> + if (driver_pg1.time_stamp_update)
> mrioc->ts_update_interval = (driver_pg1.time_stamp_update * 60);
> +
> + mrioc->skip_dev_shutdown_on_unload =
> + (driver_pg1.flags &
> + MPI3_DRIVER1_FLAGS_DEVICE_SHUTDOWN_ON_UNLOAD_DISABLE) ? 1 : 0;
[Severity: Medium]
Does this bitwise operation need an endian conversion?
Since driver_pg1.flags is an __le32, evaluating it with a bitwise AND
without conversion on a big-endian system will check the wrong byte.
This might cause the feature to silently fail to activate.
Could this use le32_to_cpu(driver_pg1.flags) before the bitwise AND?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=1
^ permalink raw reply
* Re: [PATCH v1 07/10] mpi3mr: Fix firmware event reference leak during cleanup
From: sashiko-bot @ 2026-06-26 12:03 UTC (permalink / raw)
To: Ranjan Kumar; +Cc: linux-scsi
In-Reply-To: <20260626114109.43685-8-ranjan.kumar@broadcom.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The patch introduces a Use-After-Free and Double-Free vulnerability by prematurely decrementing the reference count of the currently executing firmware event in the early-exit path of `mpi3mr_cleanup_fwevt_list`.
Pre-existing issues:
- [High] Lockless read of `mrioc->current_event` in `mpi3mr_cleanup_fwevt_list` leads to a Time-of-Check to Time-of-Use (TOCTOU) use-after-free when racing with the firmware event worker thread.
--
commit 50f8b457978a02d12ee5baafb77e83f6f06d294f
Author: Ranjan Kumar <ranjan.kumar@broadcom.com>
Subject: mpi3mr: Fix firmware event reference leak during cleanup
This commit attempts to fix a firmware event reference leak during cleanup.
It adds a call to release the firmware event reference before returning from
the early-exit path when an event is currently executing or pending at the
SCSI mid-layer.
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index e361fbb8f7235..b60afaeef68d0 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -399,6 +399,7 @@ void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc)
> */
[Severity: High]
This is a pre-existing issue, but does the lockless read of current_event
earlier in this function create a race condition with the firmware event
worker thread?
If a soft reset thread executes mpi3mr_cleanup_fwevt_list() and reads the
event into the fwevt pointer, and the worker thread finishes and frees the
event before this thread reaches the pending_at_sml check below, could
dereferencing fwevt result in a use-after-free?
> if (current_work() == &fwevt->work || fwevt->pending_at_sml) {
> fwevt->discard = 1;
> + mpi3mr_fwevt_put(fwevt);
[Severity: High]
Does this additional mpi3mr_fwevt_put() cause a double-free or use-after-free
when the active worker thread finishes its execution?
Looking at mpi3mr_fwevt_worker(), the worker thread retains ownership of the
event and appears to drop the reference itself after returning from the bottom
half handler:
mpi3mr_fwevt_worker() {
...
mpi3mr_fwevt_bh(fwevt->mrioc, fwevt);
/*
* Put fwevt reference count after
* dequeuing it from worker queue
*/
mpi3mr_fwevt_put(fwevt);
...
}
Since the worker thread relies on its own reference, will stealing the
reference here cause the count to reach zero prematurely while the worker is
still using the object?
> return;
> }
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=7
^ permalink raw reply
* Re: [PATCH v1 05/10] mpi3mr: Fix performance regression caused by extended IRQ poll sleep
From: sashiko-bot @ 2026-06-26 12:02 UTC (permalink / raw)
To: Ranjan Kumar; +Cc: linux-scsi
In-Reply-To: <20260626114109.43685-6-ranjan.kumar@broadcom.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing dma_rmb() when reading DMA-mapped reply descriptors, risking stale data processing on weakly ordered architectures.
--
commit f91311d5d4eeee7718829b492ee38d52ed25a32a
Author: Ranjan Kumar <ranjan.kumar@broadcom.com>
mpi3mr: Fix performance regression caused by extended IRQ poll sleep
This commit restores the threaded IRQ poll sleep range from 20-21 us back to
2-20 us. The previously extended interval caused an approximate 7% throughput
regression on NVMe direct-attached RAID10 configurations. This reverts the
sleep behavior to recover the lost throughput.
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 1f2f0951b560e..1d11d7c69536b 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -178,7 +178,7 @@ extern atomic64_t event_counter;
> #define MPI3MR_DEFAULT_SDEV_QD 32
>
> /* Definitions for Threaded IRQ poll*/
> -#define MPI3MR_IRQ_POLL_SLEEP 20
> +#define MPI3MR_IRQ_POLL_SLEEP 2
> #define MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT 8
>
> /* Definitions for the controller security status*/
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 496d7ca3ab372..32aeae20481ec 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -744,7 +744,7 @@ static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
> mpi3mr_process_op_reply_q(mrioc,
> intr_info->op_reply_q);
[Severity: High]
This isn't a bug introduced by this patch, but is a dma_rmb() missing when
reading the DMA-mapped reply descriptors?
Looking at mpi3mr_process_op_reply_q() which is called here, the CPU checks
the phase bit of the DMA-mapped descriptor, and then immediately reads the
payload:
mpi3mr_process_op_reply_q() {
...
if ((le16_to_cpu(reply_desc->reply_flags) &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
atomic_dec(&op_reply_q->in_use);
return 0;
}
do {
if (mrioc->unrecoverable || mrioc->io_admin_reset_sync)
break;
req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
...
}
And similarly at the end of the loop:
if ((le16_to_cpu(reply_desc->reply_flags) &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
break;
...
Without an intervening dma_rmb(), could weakly ordered architectures (like
ARM64) fetch the descriptor payload via out-of-order execution or speculation
before the phase bit check is complete?
If the hardware is still updating it, could this result in processing stale
data such as an incorrect request_queue_id?
It looks like mpi3mr_process_admin_reply_q() might have the same pattern
where it reads request_queue_ci right after checking the phase bit without
a memory barrier.
> - usleep_range(MPI3MR_IRQ_POLL_SLEEP, MPI3MR_IRQ_POLL_SLEEP + 1);
> + usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP);
>
> } while (atomic_read(&intr_info->op_reply_q->pend_ios) &&
> (num_op_reply < mrioc->max_host_ios));
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=5
^ permalink raw reply
* Re: [PATCH v1 06/10] mpi3mr: Fix memory leak on operational queue creation failure
From: sashiko-bot @ 2026-06-26 12:02 UTC (permalink / raw)
To: Ranjan Kumar; +Cc: linux-scsi
In-Reply-To: <20260626114109.43685-7-ranjan.kumar@broadcom.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] The newly added cleanup loop unconditionally dereferences `req_qinfo` and `op_reply_qinfo`, causing a kernel panic if their initial allocations fail.
Pre-existing issues:
- [High] Failure during reset leaves `num_op_req_q` non-zero but `req_qinfo` NULL, leading to a deferred kernel panic during driver cleanup.
- [High] The memory leak is not fully fixed: if a queue fails to create but the controller remains in a ready state, the partially allocated segments are leaked.
--
commit 9ead875c2a5e252d14e44cff611d464fadb0d332
Author: Ranjan Kumar <ranjan.kumar@broadcom.com>
mpi3mr: Fix memory leak on operational queue creation failure
This commit modifies the error handling path in mpi3mr_create_op_queues()
to iterate over the number of queues and release the DMA memory segments
before freeing the main queue information arrays.
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 32aeae20481ec..88444f04fb6a6 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -2529,6 +2529,10 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
>
> return retval;
[Severity: High]
This isn't a bug introduced by this patch, but does this function still leak
memory if a queue fails to create and the controller remains ready?
If queue creation fails inside the allocation loop:
mpi3mr_create_op_queues() {
...
for (i = 0; i < num_queues; i++) {
if (mpi3mr_create_op_reply_q(mrioc, i)) {
break;
}
...
}
The loop breaks, but if the controller state is still MRIOC_STATE_READY,
the function skips out_failed entirely, updates mrioc->num_op_req_q = i,
and returns 0. The segments allocated for the failed queue at index i
are abandoned and never cleaned up.
> out_failed:
> + for (i = 0; i < num_queues; i++) {
> + mpi3mr_free_op_req_q_segments(mrioc, i);
> + mpi3mr_free_op_reply_q_segments(mrioc, i);
> + }
[Severity: High]
Will this cause a null pointer dereference if the initial queue information
allocation fails?
If kzalloc() fails to allocate mrioc->req_qinfo or mrioc->op_reply_qinfo
at the start of the function, execution jumps directly to out_failed.
This loop will then execute and call mpi3mr_free_op_req_q_segments(),
which blindly dereferences the unallocated array:
mpi3mr_free_op_req_q_segments() {
...
segments = mrioc->req_qinfo[q_idx].q_segments;
...
}
> kfree(mrioc->req_qinfo);
> mrioc->req_qinfo = NULL;
[Severity: High]
This is a pre-existing issue, but does freeing the array here lead to a
deferred crash if a controller reset fails?
If mpi3mr_create_op_queues() fails during a reset, mrioc->req_qinfo is
freed and set to null here, but mrioc->num_op_req_q retains its non-zero
value from before the reset.
Later, when the driver cleans up, mpi3mr_free_mem() loops up to the stale
num_op_req_q count and calls mpi3mr_free_op_req_q_segments(), which will
dereference the null req_qinfo array.
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=6
^ permalink raw reply
* [PATCH v1 10/10] mpi3mr: Driver version update to 8.18.0.8.50
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
Update driver version to 8.18.0.8.50
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi3mr.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 1d11d7c69536..c6bbd6b33cfe 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -56,8 +56,8 @@ extern struct list_head mrioc_list;
extern int prot_mask;
extern atomic64_t event_counter;
-#define MPI3MR_DRIVER_VERSION "8.17.0.3.50"
-#define MPI3MR_DRIVER_RELDATE "09-January-2026"
+#define MPI3MR_DRIVER_VERSION "8.18.0.8.50"
+#define MPI3MR_DRIVER_RELDATE "26-June-2026"
#define MPI3MR_DRIVER_NAME "mpi3mr"
#define MPI3MR_DRIVER_LICENSE "GPL"
--
2.47.3
^ permalink raw reply related
* [PATCH v1 09/10] mpi3mr: Fix SAS PHY cleanup in host addition error paths
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
When adding a SAS host, the driver allocates a PHY array and
subsequently creates individual SAS PHYs. If a later step fails, the
error path exits without cleaning up previously allocated resources,
resulting in leaks of both the PHY array and any registered SAS PHYs.
Add a dedicated cleanup path that deletes any successfully created SAS
PHYs and frees the PHY array before returning from initialization
failure paths.
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi3mr_transport.c | 28 ++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index 1b793d86f758..0236bbfcff6d 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -1216,13 +1216,14 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
}
num_phys = sas_io_unit_pg0->num_phys;
kfree(sas_io_unit_pg0);
+ sas_io_unit_pg0 = NULL;
mrioc->sas_hba.host_node = 1;
INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list);
mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev;
mrioc->sas_hba.phy = kzalloc_objs(struct mpi3mr_sas_phy, num_phys);
if (!mrioc->sas_hba.phy)
- return;
+ goto out;
mrioc->sas_hba.num_phys = num_phys;
@@ -1230,12 +1231,12 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
(num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
if (!sas_io_unit_pg0)
- return;
+ goto out_free_phy;
if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
- goto out;
+ goto out_free_phy;
}
mrioc->sas_hba.handle = 0;
@@ -1249,12 +1250,12 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, i)) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
- goto out;
+ goto out_free_phy;
}
if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
- goto out;
+ goto out_free_phy;
}
if (!mrioc->sas_hba.handle)
@@ -1264,7 +1265,7 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
if (!mpi3mr_alloc_hba_port(mrioc, port_id))
- goto out;
+ goto out_free_phy;
mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
mrioc->sas_hba.phy[i].phy_id = i;
@@ -1277,13 +1278,13 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
mrioc->sas_hba.handle))) {
ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
- goto out;
+ goto out_free_phy;
}
if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
mrioc->sas_hba.handle, ioc_status, __FILE__, __LINE__,
__func__);
- goto out;
+ goto out_free_phy;
}
mrioc->sas_hba.enclosure_handle =
le16_to_cpu(dev_pg0.enclosure_handle);
@@ -1306,6 +1307,17 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
le64_to_cpu(encl_pg0.enclosure_logical_id);
}
+ goto out;
+
+out_free_phy:
+ for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
+ if (mrioc->sas_hba.phy[i].phy)
+ sas_phy_delete(mrioc->sas_hba.phy[i].phy);
+ }
+ kfree(mrioc->sas_hba.phy);
+ mrioc->sas_hba.phy = NULL;
+ mrioc->sas_hba.num_phys = 0;
+
out:
kfree(sas_io_unit_pg0);
}
--
2.47.3
^ permalink raw reply related
* [PATCH v1 08/10] mpi3mr: Fix SAS port allocation and registration error handling
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
During SAS port creation, the driver does not verify successful port
allocation before attempting registration, which can lead to a NULL
pointer dereference. Additionally, if registration fails, the allocated
port is not freed, resulting in a memory leak.
Fix this by adding a NULL check after allocation and freeing the port
when registration fails.
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi3mr_transport.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index 240f67a8e2e3..1b793d86f758 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -1428,9 +1428,15 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
}
port = sas_port_alloc_num(mr_sas_node->parent_dev);
+ if (!port) {
+ ioc_err(mrioc, "failure at %s:%d/%s() (sas_port_alloc)!\n",
+ __FILE__, __LINE__, __func__);
+ goto out_fail;
+ }
if ((sas_port_add(port))) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
+ sas_port_free(port);
goto out_fail;
}
--
2.47.3
^ permalink raw reply related
* [PATCH v1 07/10] mpi3mr: Fix firmware event reference leak during cleanup
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
During firmware event cleanup, when an event is currently
executing or pending at the SCSI mid-layer,the driver sets
a discard flag and exits the cleanup routine early.
This early exit skips the normal cancel path,resulting in the
firmware event reference count not being decremented,leading
to a reference leak.
Fix this by releasing the firmware event reference before
returning from the early-exit path.
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi3mr_os.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index e361fbb8f723..b60afaeef68d 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -399,6 +399,7 @@ void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc)
*/
if (current_work() == &fwevt->work || fwevt->pending_at_sml) {
fwevt->discard = 1;
+ mpi3mr_fwevt_put(fwevt);
return;
}
--
2.47.3
^ permalink raw reply related
* [PATCH v1 06/10] mpi3mr: Fix memory leak on operational queue creation failure
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
When operational queue creation fails after one or more queues have
been created, the error path frees the queue information arrays but
does not release the DMA memory segments associated with the created
queues, resulting in a memory leak.
Free the allocated request and reply queue segments before freeing the
queue information arrays.
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi3mr_fw.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 32aeae20481e..88444f04fb6a 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -2529,6 +2529,10 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
return retval;
out_failed:
+ for (i = 0; i < num_queues; i++) {
+ mpi3mr_free_op_req_q_segments(mrioc, i);
+ mpi3mr_free_op_reply_q_segments(mrioc, i);
+ }
kfree(mrioc->req_qinfo);
mrioc->req_qinfo = NULL;
--
2.47.3
^ permalink raw reply related
* [PATCH v1 05/10] mpi3mr: Fix performance regression caused by extended IRQ poll sleep
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
Commit 24d7071d9645 ("scsi: mpi3mr: A performance fix") increased the
threaded IRQ poll sleep range from 2-20 us to 20-21 us to work around a
timer slack issue.
On kernels unaffected by the timer slack issue, the longer sleep interval
reduces reply queue processing efficiency and causes an approximately 7%
throughput regression on NVMe direct-attached RAID10 configurations.
Restore the IRQ poll sleep range to 2-20 us to recover the lost
throughput.
Fixes: 24d7071d9645 ("scsi: mpi3mr: A performance fix")
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi3mr.h | 2 +-
drivers/scsi/mpi3mr/mpi3mr_fw.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 1f2f0951b560..1d11d7c69536 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -178,7 +178,7 @@ extern atomic64_t event_counter;
#define MPI3MR_DEFAULT_SDEV_QD 32
/* Definitions for Threaded IRQ poll*/
-#define MPI3MR_IRQ_POLL_SLEEP 20
+#define MPI3MR_IRQ_POLL_SLEEP 2
#define MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT 8
/* Definitions for the controller security status*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 496d7ca3ab37..32aeae20481e 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -744,7 +744,7 @@ static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
mpi3mr_process_op_reply_q(mrioc,
intr_info->op_reply_q);
- usleep_range(MPI3MR_IRQ_POLL_SLEEP, MPI3MR_IRQ_POLL_SLEEP + 1);
+ usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP);
} while (atomic_read(&intr_info->op_reply_q->pend_ios) &&
(num_op_reply < mrioc->max_host_ios));
--
2.47.3
^ permalink raw reply related
* [PATCH v1 04/10] mpi3mr: Fix NVMe page size caching for non-operational devices
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
For NVMe devices reported with an error access status,
the cached PCIe page size may remain unset during device discovery.
This causes management IOCTL validation to fail, preventing requests
from reaching firmware and resulting in an incorrect error
being returned to user space.
Populate the page size attribute irrespective of device access status
so that management IOCTLs are processed by firmware and the appropriate
device-specific error is reported.
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi3mr_os.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index d2a20f2721db..e361fbb8f723 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -1354,12 +1354,10 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
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;
+ tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size;
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);
--
2.47.3
^ permalink raw reply related
* [PATCH v1 03/10] mpi3mr: Add early timestamp synchronization after driver load
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
When the driver is loaded from initramfs, the controller timestamp may
be initialized before the system clock has been synchronized. As a
result, the controller can operate with a stale timestamp until the
first periodic synchronization occurs.
Currently, the first controller timestamp synchronization occurs only
after the configured ts_update_interval expires (15 minutes by default).
Add an early timestamp synchronization 60 seconds after driver load,
followed by the existing periodic synchronization interval.
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi3mr.h | 3 +++
drivers/scsi/mpi3mr/mpi3mr_fw.c | 25 +++++++++++++++++++------
2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 39096004c60a..1f2f0951b560 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -125,6 +125,7 @@ extern atomic64_t event_counter;
#define MPI3MR_RESETTM_TIMEOUT 60
#define MPI3MR_RESET_HOST_IOWAIT_TIMEOUT 5
#define MPI3MR_TSUPDATE_INTERVAL 900
+#define MPI3MR_EARLY_TSUPDATE_SECONDS 60
#define MPI3MR_DEFAULT_SHUTDOWN_TIME 120
#define MPI3MR_RAID_ERRREC_RESET_TIMEOUT 180
#define MPI3MR_PREPARE_FOR_RESET_TIMEOUT 180
@@ -1118,6 +1119,7 @@ struct scmd_priv {
* @evtack_cmds_bitmap: Event Ack bitmap
* @delayed_evtack_cmds_list: Delayed event acknowledgment list
* @ts_update_counter: Timestamp update counter
+ * @early_ts_sync_done: Early (1 min) timestamp sync completed after load
* @ts_update_interval: Timestamp update interval
* @reset_in_progress: Reset in progress flag
* @unrecoverable: Controller unrecoverable flag
@@ -1318,6 +1320,7 @@ struct mpi3mr_ioc {
struct list_head delayed_evtack_cmds_list;
u16 ts_update_counter;
+ u8 early_ts_sync_done;
u16 ts_update_interval;
u8 reset_in_progress;
u8 unrecoverable;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index eb730318db47..496d7ca3ab37 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -2870,8 +2870,9 @@ static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc)
* @work: work struct
*
* Watch dog work periodically executed (1 second interval) to
- * monitor firmware fault and to issue periodic timer sync to
- * the firmware.
+ * monitor firmware fault and perform timestamp synchronization
+ * to firmware, with an early sync 1 minute after load followed
+ * by periodic updates at ts_update_interval seconds (default 15 minutes).
*
* Return: Nothing.
*/
@@ -2917,11 +2918,23 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
}
if (!(mrioc->facts.ioc_capabilities &
- MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC) &&
- (mrioc->ts_update_counter++ >= mrioc->ts_update_interval)) {
+ MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC)) {
+ if (!mrioc->early_ts_sync_done) {
+ /*
+ * Send time sync 1 min after load
+ */
+ if (mrioc->ts_update_counter++ >=
+ MPI3MR_EARLY_TSUPDATE_SECONDS) {
+ mrioc->early_ts_sync_done = 1;
+ mrioc->ts_update_counter = 0;
+ mpi3mr_sync_timestamp(mrioc);
+ }
+ } else if (mrioc->ts_update_counter++ >=
+ mrioc->ts_update_interval) {
+ mrioc->ts_update_counter = 0;
+ mpi3mr_sync_timestamp(mrioc);
+ }
- mrioc->ts_update_counter = 0;
- mpi3mr_sync_timestamp(mrioc);
}
if ((mrioc->prepare_for_reset) &&
--
2.47.3
^ permalink raw reply related
* [PATCH v1 02/10] mpi3mr: Update MPI Headers to revision 41
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
Update MPI Headers to revision 41
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h | 77 +++++++++++++++++++++--
drivers/scsi/mpi3mr/mpi/mpi30_image.h | 7 ++-
drivers/scsi/mpi3mr/mpi/mpi30_ioc.h | 15 +++--
drivers/scsi/mpi3mr/mpi/mpi30_transport.h | 2 +-
4 files changed, 87 insertions(+), 14 deletions(-)
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
index 33dd303c97bb..7cf16a5c15b7 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
@@ -72,6 +72,12 @@
#define MPI3_SECURITY_PGAD_SLOT_GROUP_SHIFT (8)
#define MPI3_SECURITY_PGAD_SLOT_MASK (0x000000ff)
#define MPI3_INSTANCE_PGAD_INSTANCE_MASK (0x0000ffff)
+#define MPI3_INSTANCE_PGAD_INSTANCE_SHIFT (0)
+#define MPI3_INTERFACE_PGAD_INTERFACE_MASK (0x0000000f)
+#define MPI3_INTERFACE_PGAD_INTERFACE_SHIFT (0)
+#define MPI3_INTERFACE_PGAD_INTERFACE_MPI (0)
+#define MPI3_INTERFACE_PGAD_INTERFACE_NVME_VD (1)
+#define MPI3_INTERFACE_PGAD_INTERFACE_NVME_PD (2)
struct mpi3_config_request {
__le16 host_tag;
u8 ioc_use_only02;
@@ -492,10 +498,31 @@ struct mpi3_man10_istwi_ctrlr_entry {
};
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_MASK (0x000c)
-#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_100K (0x0000)
-#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_400K (0x0004)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_100_KHZ (0x0000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_400_KHZ (0x0004)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_TARGET_ENABLED (0x0002)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_INITIATOR_ENABLED (0x0001)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_MASK (0xc000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_SHIFT (14)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_50_NS (0x0000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_10_NS (0x4000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_5_NS (0x8000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_0_NS (0xc000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_MASK (0x3000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_SHIFT (12)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_I2C (0x0000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_I3C (0x1000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_AUTO (0x2000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_MASK (0x0e00)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_SHIFT (9)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_12_5_MHZ (0x0000)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_8_MHZ (0x0200)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_6_MHZ (0x0400)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_4_MHZ (0x0600)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_2_MHZ (0x0800)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_MASK (0x000c)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_SHIFT (0)
+
#ifndef MPI3_MAN10_ISTWI_CTRLR_MAX
#define MPI3_MAN10_ISTWI_CTRLR_MAX (1)
#endif
@@ -1027,6 +1054,16 @@ struct mpi3_io_unit_page5 {
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SWITCH_ATTACHED (0x02)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_AND_EXPANDER (0x03)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_AND_SWITCH (0x03)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_MASK (0xc000)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_NONE (0x0000)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_ALL (0x4000)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_FILTERED (0x8000)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_RESERVED (0xc000)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_MASK (0x3000)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_ALL (0x0000)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_FILTERED (0x1000)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_NONE (0x2000)
+#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_RESERVED (0x3000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_HDD_MASK (0x0300)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_HDD_SHIFT (8)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_HDD_MASK (0x00c0)
@@ -1069,7 +1106,8 @@ struct mpi3_io_unit_page8 {
struct mpi3_config_page_header header;
u8 sb_mode;
u8 sb_state;
- __le16 reserved0a;
+ u8 flags;
+ u8 reserved0b;
u8 num_slots;
u8 slots_available;
u8 current_key_encryption_algo;
@@ -1088,6 +1126,8 @@ struct mpi3_io_unit_page8 {
#define MPI3_IOUNIT8_SBSTATE_SVN_UPDATE_PENDING (0x04)
#define MPI3_IOUNIT8_SBSTATE_KEY_UPDATE_PENDING (0x02)
#define MPI3_IOUNIT8_SBSTATE_SECURE_BOOT_ENABLED (0x01)
+#define MPI3_IOUNIT8_FLAGS_FWQR_CAPABLE (0x80)
+#define MPI3_IOUNIT8_FLAGS_FWQR_SECURED (0x40)
#define MPI3_IOUNIT8_SBMODE_CURRENT_KEY_IOUNIT17 (0x10)
#define MPI3_IOUNIT8_SBMODE_HARD_SECURE_RECERTIFIED (0x08)
struct mpi3_io_unit_page9 {
@@ -1174,10 +1214,16 @@ struct mpi3_io_unit_page12 {
#define MPI3_IOUNIT12_FLAGS_NUMPASSES_32 (0x00000200)
#define MPI3_IOUNIT12_FLAGS_NUMPASSES_64 (0x00000300)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_MASK (0x00000003)
+#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_SHIFT (0)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_DISABLED (0x00000000)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_500US (0x00000001)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_1MS (0x00000002)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_2MS (0x00000003)
+#define MPI3_IOUNIT12_FLAGS_INTERFACE_MASK (0x0000000c)
+#define MPI3_IOUNIT12_FLAGS_INTERFACE_SHIFT (2)
+#define MPI3_IOUNIT12_FLAGS_INTERFACE_MPI (0x00000000)
+#define MPI3_IOUNIT12_FLAGS_INTERFACE_NVME_VD (0x00000004)
+#define MPI3_IOUNIT12_FLAGS_INTERFACE_NVME_PD (0x00000008)
#ifndef MPI3_IOUNIT13_FUNC_MAX
#define MPI3_IOUNIT13_FUNC_MAX (1)
#endif
@@ -1238,6 +1284,7 @@ struct mpi3_io_unit_page15 {
#define MPI3_IOUNIT15_PAGEVERSION (0x00)
#define MPI3_IOUNIT15_FLAGS_EPRINIT_INITREQUIRED (0x04)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_MASK (0x03)
+#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_SHIFT (0)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_NOT_SUPPORTED (0x00)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_WITHOUT_POWER_BRAKE_GPIO (0x01)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_WITH_POWER_BRAKE_GPIO (0x02)
@@ -1255,6 +1302,9 @@ struct mpi3_io_unit_page17 {
__le32 current_key[];
};
#define MPI3_IOUNIT17_PAGEVERSION (0x00)
+#define MPI3_IOUNIT17_FLAGS_KEYROOT_MASK (0x01)
+#define MPI3_IOUNIT17_FLAGS_KEYROOT_HW (0x00)
+#define MPI3_IOUNIT17_FLAGS_KEYROOT_FW (0x01)
struct mpi3_io_unit_page18 {
struct mpi3_config_page_header header;
u8 flags;
@@ -1640,11 +1690,28 @@ struct mpi3_security_page3 {
};
#define MPI3_SECURITY3_PAGEVERSION (0x00)
-#define MPI3_SECURITY3_FLAGS_TYPE_MASK (0x0f)
+#define MPI3_SECURITY3_FLAGS_TYPE_MASK (0x1f)
#define MPI3_SECURITY3_FLAGS_TYPE_SHIFT (0)
#define MPI3_SECURITY3_FLAGS_TYPE_NOT_VALID (0)
#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PRIVATE (1)
#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PUBLIC (2)
+union mpi3_security_digest {
+ __le32 dword[16];
+ __le16 word[32];
+ u8 byte[64];
+};
+struct mpi3_security_page4 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08[2];
+ union mpi3_security_mac mac;
+ union mpi3_security_nonce nonce;
+ u8 num_digests;
+ u8 hash_algorithm;
+ __le16 reserved92;
+ __le32 reserved94[3];
+ union mpi3_security_digest digest[];
+};
+#define MPI3_SECURITY4_PAGEVERSION (0x00)
struct mpi3_security_page10 {
struct mpi3_config_page_header header;
__le32 reserved08[2];
@@ -2074,7 +2141,7 @@ struct mpi3_sas_phy3_phy_event_config {
#define MPI3_SASPHY3_EVENT_CODE_LCCONN_TIME (0xd5)
#define MPI3_SASPHY3_EVENT_CODE_SSP_TX_START_TRANSMIT (0xd6)
#define MPI3_SASPHY3_EVENT_CODE_SATA_TX_START (0xd7)
-#define MPI3_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMT (0xd8)
+#define MPI3_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMIT (0xd8)
#define MPI3_SASPHY3_EVENT_CODE_TX_SMP_BREAK_CONN (0xd9)
#define MPI3_SASPHY3_EVENT_CODE_SSP_RX_START_RECEIVE (0xda)
#define MPI3_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xdb)
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_image.h b/drivers/scsi/mpi3mr/mpi/mpi30_image.h
index 62ddf094d46c..5fa09fa79358 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_image.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_image.h
@@ -18,7 +18,7 @@ struct mpi3_hash_exclusion_format {
__le32 size;
};
-#define MPI3_IMAGE_HASH_EXCUSION_NUM (4)
+#define MPI3_IMAGE_HASH_EXCLUSION_NUM (4)
struct mpi3_component_image_header {
__le32 signature0;
__le32 load_address;
@@ -42,7 +42,7 @@ struct mpi3_component_image_header {
union mpi3_version_union rmc_interface_version;
union mpi3_version_union etp_interface_version;
struct mpi3_comp_image_version component_image_version;
- struct mpi3_hash_exclusion_format hash_exclusion[MPI3_IMAGE_HASH_EXCUSION_NUM];
+ struct mpi3_hash_exclusion_format hash_exclusion[MPI3_IMAGE_HASH_EXCLUSION_NUM];
__le32 next_image_header_offset;
union mpi3_version_union security_version;
__le32 reserved84[31];
@@ -347,7 +347,8 @@ struct mpi3_encrypted_hash_entry {
struct mpi3_encrypted_hash_data {
u8 image_version;
u8 num_hash;
- __le16 reserved02;
+ u8 fw_num_hash;
+ u8 reserved03;
__le32 reserved04;
struct mpi3_encrypted_hash_entry encrypted_hash_entry[MPI3_ENCRYPTED_HASH_ENTRY_MAX];
};
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
index 68efa0d51345..aa42fba7f930 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
@@ -428,10 +428,10 @@ struct mpi3_event_data_sas_discovery {
#define MPI3_EVENT_SAS_DISC_FLAGS_IN_PROGRESS (0x01)
#define MPI3_EVENT_SAS_DISC_RC_STARTED (0x01)
#define MPI3_EVENT_SAS_DISC_RC_COMPLETED (0x02)
-#define MPI3_SAS_DISC_STATUS_MAX_ENCLOSURES_EXCEED (0x80000000)
-#define MPI3_SAS_DISC_STATUS_MAX_EXPANDERS_EXCEED (0x40000000)
-#define MPI3_SAS_DISC_STATUS_MAX_DEVICES_EXCEED (0x20000000)
-#define MPI3_SAS_DISC_STATUS_MAX_TOPO_PHYS_EXCEED (0x10000000)
+#define MPI3_SAS_DISC_STATUS_MAX_ENCLOSURES_EXCEEDED (0x80000000)
+#define MPI3_SAS_DISC_STATUS_MAX_EXPANDERS_EXCEEDED (0x40000000)
+#define MPI3_SAS_DISC_STATUS_MAX_DEVICES_EXCEEDED (0x20000000)
+#define MPI3_SAS_DISC_STATUS_MAX_TOPO_PHYS_EXCEEDED (0x10000000)
#define MPI3_SAS_DISC_STATUS_INVALID_CEI (0x00010000)
#define MPI3_SAS_DISC_STATUS_FECEI_MISMATCH (0x00008000)
#define MPI3_SAS_DISC_STATUS_MULTIPLE_DEVICES_IN_SLOT (0x00004000)
@@ -965,7 +965,7 @@ struct mpi3_ci_download_reply {
u8 flags;
u8 cache_dirty;
u8 pending_count;
- u8 reserved13;
+ u8 additional_flags;
};
#define MPI3_CI_DOWNLOAD_FLAGS_DOWNLOAD_IN_PROGRESS (0x80)
@@ -979,6 +979,11 @@ struct mpi3_ci_download_reply {
#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_ONLINE_PENDING (0x04)
#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_OFFLINE_PENDING (0x06)
#define MPI3_CI_DOWNLOAD_FLAGS_COMPATIBLE (0x01)
+#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_MASK (0x03)
+#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_SHIFT (0)
+#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_NONE (0x00)
+#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_PRIMARY (0x01)
+#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_SECONDARY (0x02)
struct mpi3_ci_upload_request {
__le16 host_tag;
u8 ioc_use_only02;
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h
index 290a1f5c2924..794ecc778945 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h
@@ -18,7 +18,7 @@ union mpi3_version_union {
#define MPI3_VERSION_MAJOR (3)
#define MPI3_VERSION_MINOR (0)
-#define MPI3_VERSION_UNIT (39)
+#define MPI3_VERSION_UNIT (41)
#define MPI3_VERSION_DEV (0)
#define MPI3_DEVHANDLE_INVALID (0xffff)
struct mpi3_sysif_oper_queue_indexes {
--
2.47.3
^ permalink raw reply related
* [PATCH v1 01/10] mpi3mr: Skip device shutdown during unload per controller configuration
From: Ranjan Kumar @ 2026-06-26 11:41 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
In-Reply-To: <20260626114109.43685-1-ranjan.kumar@broadcom.com>
The controller may be configured through Driver Page 1 to suppress
device shutdown requests during driver unload. Cache this setting and
skip the device shutdown request during IOC shutdown when unloading
the driver.
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
drivers/scsi/mpi3mr/mpi3mr.h | 3 +++
drivers/scsi/mpi3mr/mpi3mr_fw.c | 35 ++++++++++++++++++++++++---------
drivers/scsi/mpi3mr/mpi3mr_os.c | 2 ++
3 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index c25525fe0671..39096004c60a 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -1410,6 +1410,9 @@ struct mpi3mr_ioc {
struct dma_pool *trace_buf_pool;
struct segments *trace_buf;
u8 invalid_io_comp;
+ bool is_unload;
+ bool skip_dev_shutdown_on_unload;
+
};
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 31b19ed1528e..eb730318db47 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -4107,26 +4107,35 @@ static int mpi3mr_repost_diag_bufs(struct mpi3mr_ioc *mrioc)
}
/**
- * mpi3mr_read_tsu_interval - Update time stamp interval
+ * mpi3mr_read_driver_page1 - Read Driver Page 1 parameters
* @mrioc: Adapter instance reference
*
- * Update time stamp interval if its defined in driver page 1,
- * otherwise use default value.
+ * Reads and caches Driver Page 1 parameters such as
+ * timestamp update interval and driver behavior flags.
*
* Return: Nothing
*/
static void
-mpi3mr_read_tsu_interval(struct mpi3mr_ioc *mrioc)
+mpi3mr_read_driver_page1(struct mpi3mr_ioc *mrioc)
{
struct mpi3_driver_page1 driver_pg1;
u16 pg_sz = sizeof(driver_pg1);
int retval = 0;
mrioc->ts_update_interval = MPI3MR_TSUPDATE_INTERVAL;
+ mrioc->skip_dev_shutdown_on_unload = 0;
retval = mpi3mr_cfg_get_driver_pg1(mrioc, &driver_pg1, pg_sz);
- if (!retval && driver_pg1.time_stamp_update)
+
+ if (retval)
+ return;
+
+ if (driver_pg1.time_stamp_update)
mrioc->ts_update_interval = (driver_pg1.time_stamp_update * 60);
+
+ mrioc->skip_dev_shutdown_on_unload =
+ (driver_pg1.flags &
+ MPI3_DRIVER1_FLAGS_DEVICE_SHUTDOWN_ON_UNLOAD_DISABLE) ? 1 : 0;
}
/**
@@ -4432,7 +4441,7 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
goto out_failed_noretry;
}
- mpi3mr_read_tsu_interval(mrioc);
+ mpi3mr_read_driver_page1(mrioc);
mpi3mr_print_ioc_info(mrioc);
dprint_init(mrioc, "allocating host diag buffers\n");
@@ -4604,7 +4613,7 @@ int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
goto out_failed_noretry;
}
- mpi3mr_read_tsu_interval(mrioc);
+ mpi3mr_read_driver_page1(mrioc);
mpi3mr_print_ioc_info(mrioc);
if (is_resume) {
@@ -5089,8 +5098,16 @@ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
return;
}
- shutdown_action = MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL |
- MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
+ shutdown_action = MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
+
+ if (!(mrioc->is_unload && mrioc->skip_dev_shutdown_on_unload))
+ shutdown_action |=
+ MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
+ else
+ ioc_info(mrioc,
+ "The shutdown request is issued without the device shutdown bit set\n"
+ "as indicated by the controller configuration\n");
+
ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
ioc_config |= shutdown_action;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 402d1f35d214..d2a20f2721db 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -5665,6 +5665,8 @@ static void mpi3mr_remove(struct pci_dev *pdev)
return;
mrioc = shost_priv(shost);
+ mrioc->is_unload = true;
+
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
ssleep(1);
--
2.47.3
^ permalink raw reply related
* [PATCH v1 00/10] mpi3mr: Few Enhancements and minor fixes
From: Ranjan Kumar @ 2026-06-26 11:40 UTC (permalink / raw)
To: linux-scsi, martin.petersen
Cc: sathya.prakash, chandrakanth.patil, vishakhavc, ipylypiv,
Ranjan Kumar
Few Enhancements and minor fixes of mpi3mr driver.
Ranjan Kumar (10):
mpi3mr: Skip device shutdown during unload per controller
configuration
mpi3mr: Update MPI Headers to revision 41
mpi3mr: Add early timestamp synchronization after driver load
mpi3mr: Fix NVMe page size caching for non-operational devices
mpi3mr: Fix performance regression caused by extended IRQ poll sleep
mpi3mr: Fix memory leak on operational queue creation failure
mpi3mr: Fix firmware event reference leak during cleanup
mpi3mr: Fix SAS port allocation and registration error handling
mpi3mr: Fix SAS PHY cleanup in host addition error paths
mpi3mr: Driver version update to 8.18.0.8.50
drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h | 77 +++++++++++++++++++++--
drivers/scsi/mpi3mr/mpi/mpi30_image.h | 7 ++-
drivers/scsi/mpi3mr/mpi/mpi30_ioc.h | 15 +++--
drivers/scsi/mpi3mr/mpi/mpi30_transport.h | 2 +-
drivers/scsi/mpi3mr/mpi3mr.h | 12 +++-
drivers/scsi/mpi3mr/mpi3mr_fw.c | 66 ++++++++++++++-----
drivers/scsi/mpi3mr/mpi3mr_os.c | 7 ++-
drivers/scsi/mpi3mr/mpi3mr_transport.c | 34 +++++++---
8 files changed, 176 insertions(+), 44 deletions(-)
--
2.47.3
^ permalink raw reply
page: next (older)
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox