summaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
authorRanjan Kumar <ranjan.kumar@broadcom.com>2026-09-16 13:57:03 +0530
committerMartin K. Petersen (Oracle) <mkp@kernel.org>2026-09-16 22:14:23 -0400
commit29e3f0856e8544ca185be3403518a102e0ca29fc (patch)
tree4fa7e50f80936755c1e3a5d1b96cf2810559818a /drivers/scsi
parent59f8c361872df3df9c47ad612a4562cd08441cc5 (diff)
downloadlinux-next-29e3f0856e8544ca185be3403518a102e0ca29fc.tar.gz
linux-next-29e3f0856e8544ca185be3403518a102e0ca29fc.zip
scsi: 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. Fix this by adding a NULL check after allocation and freeing the port when registration fails. Additional fixes in the error handling path include: 1. Fixing similar missing NULL checks for rphy allocations. 2. Cleaning up after a failed rphy registration tried to remove a device that was never added, causing a crash. The rphy is now freed directly instead. 3. A failed rphy registration left the target device with a dangling pointer and a stuck pending flag. Both are now cleared. 4. Phys removed on error kept an internal flag set, permanently blocking them from being added to a port again. Now cleared alongside the list removal. 5. Could block in the SCSI mid-layer after a stop or reset had already begun, the same ABBA deadlock class fixed elsewhere. The port allocation path now stops before that call once that is detected. 6. The same reset check on the port removal path caused a memory leak and a kernel BUG() on rediscovery. Reported-by: Sashiko <sashiko-bot@kernel.org> Closes: https://sashiko.dev/#/patchset/20260626114109.43685-1-ranjan.kumar@broadcom.com?part=8 Closes: https://sashiko.dev/#/patchset/20260708183305.244485-1-ranjan.kumar@broadcom.com?part=8 Closes: https://sashiko.dev/#/patchset/20260724102505.115136-1-ranjan.kumar@broadcom.com?part=8 Closes: https://sashiko.dev/#/patchset/20260805110634.346670-1-ranjan.kumar@broadcom.com?part=8 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-9-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_transport.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index be794fe8eb7d..0dacfae6fa9d 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -1436,9 +1436,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;
}
@@ -1458,14 +1464,32 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
mr_sas_port->port = port;
if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
rphy = sas_end_device_alloc(port);
+ if (!rphy) {
+ ioc_err(mrioc, "failure at %s:%d/%s() (sas_end_device_alloc)!\n",
+ __FILE__, __LINE__, __func__);
+ sas_port_delete(port);
+ goto out_fail;
+ }
tgtdev->dev_spec.sas_sata_inf.rphy = rphy;
} else {
rphy = sas_expander_alloc(port,
mr_sas_port->remote_identify.device_type);
+ if (!rphy) {
+ ioc_err(mrioc, "failure at %s:%d/%s() (sas_expander_alloc)!\n",
+ __FILE__, __LINE__, __func__);
+ sas_port_delete(port);
+ goto out_fail;
+ }
}
rphy->identify = mr_sas_port->remote_identify;
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
+ if (mrioc->stop_drv_processing || mrioc->reset_in_progress) {
+ spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
+ sas_rphy_free(rphy);
+ sas_port_delete(port);
+ goto out_fail;
+ }
if (mrioc->current_event)
mrioc->current_event->pending_at_sml = 1;
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
@@ -1473,6 +1497,18 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
if ((sas_rphy_add(rphy))) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
+ spin_lock_irqsave(&mrioc->fwevt_lock, flags);
+ if (mrioc->current_event) {
+ mrioc->current_event->pending_at_sml = 0;
+ discard = mrioc->current_event->discard;
+ }
+ spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
+ if (discard)
+ mpi3mr_print_device_event_notice(mrioc, true);
+ sas_rphy_unlink(rphy);
+ sas_rphy_free(rphy);
+ sas_port_delete(port);
+ goto out_fail;
}
if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;
@@ -1511,9 +1547,17 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
return mr_sas_port;
out_fail:
+ if (tgtdev) {
+ tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;
+ tgtdev->dev_spec.sas_sata_inf.rphy = NULL;
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+
list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,
- port_siblings)
+ port_siblings) {
+ mr_sas_phy->phy_belongs_to_port = 0;
list_del(&mr_sas_phy->port_siblings);
+ }
kfree(mr_sas_port);
return NULL;
}