[PATCH] scsi: mptfusion: avoid freeing an unregistered IRQ
From: Runyu Xiao
Date: Mon Sep 21 2026 - 10:06:59 EST
mpt_do_ioc_recovery() can successfully request an IRQ during IOC bringup
and fail later. The recovery cleanup frees the IRQ but leaves pci_irq
pointing at the released IRQ. A later adapter disposal can then attempt to
free it again.
mpt_suspend() also unconditionally calls free_irq() when the bringup path
did not register an IRQ and left pci_irq at -1. Guard the suspend cleanup
and clear pci_irq after recovery cleanup so the field reflects whether the
handler is registered.
Reproducer:
Build both kernels with a test-only hook that makes the first
SendIocInit() call during resume recovery return -EIO after the IRQ has
been registered. Boot an x86_64 guest in QEMU with an mptsas1068 device:
-device mptsas1068,id=scsi0
As root in the guest, run:
printf mem > /sys/power/state
printf mem > /sys/power/state
dmesg | grep 'Trying to free already-free IRQ'
The unfixed kernel reports the warning during the second suspend, while
the fixed kernel completes both suspend/resume cycles without it. The
failure injection is test-only and does not claim that SendIocInit()
fails spontaneously during normal operation.
Fixes: 9bf0a28c9a24 ("[SCSI] kdump: mpt fusion driver initialization failure fix")
Fixes: 4d4109d0eb69 ("[SCSI] mpt fusion: Power Management fixes for MPT SAS PCI-E controllers")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM Codex
Signed-off-by: Runyu Xiao <runyu.xiao@xxxxxxxxxx>
---
drivers/message/fusion/mptbase.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 3a431ffd3e2eb..79e0cb8fa5c56 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -2160,10 +2160,12 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
/* Clear any lingering interrupt */
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
- free_irq(ioc->pci_irq, ioc);
- if (ioc->msi_enable)
- pci_disable_msi(ioc->pcidev);
- ioc->pci_irq = -1;
+ if (ioc->pci_irq != -1) {
+ free_irq(ioc->pci_irq, ioc);
+ if (ioc->msi_enable)
+ pci_disable_msi(ioc->pcidev);
+ ioc->pci_irq = -1;
+ }
pci_save_state(pdev);
pci_disable_device(pdev);
pci_release_selected_regions(pdev, ioc->bars);
@@ -2615,6 +2617,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
out:
if ((ret != 0) && irq_allocated) {
free_irq(ioc->pci_irq, ioc);
+ ioc->pci_irq = -1;
if (ioc->msi_enable)
pci_disable_msi(ioc->pcidev);
}
--
2.34.1