scsi: lpfc: Fix incorrect txcmplq_cnt during cleanup in lpfc_sli_abort_ring()

When a port is offline in lpfc_sli_abort_ring, the phba->txcmplq is
cleared but the phba->txcmplq_cnt is not reset to zero.  This can
sometimes result in a phba->txcmplq_cnt that never reaches zero, which
hangs the cleanup process.

Update lpfc_sli_abort_ring so that txcmplq_cnt is reset to zero and also
ensure that the LPFC_IO_ON_TXCMPLQ flag is properly cleared.

Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Link: https://patch.msgid.link/20260212213008.149873-9-justintee8345@gmail.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Justin Tee 2026-02-12 13:30:03 -08:00 committed by Martin K. Petersen
parent 6b0bcf4b64
commit 2da10bcaa5

View File

@ -4572,59 +4572,41 @@ void
lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
LIST_HEAD(tx_completions);
LIST_HEAD(txcmplq_completions);
spinlock_t *plock; /* for transmit queue access */
struct lpfc_iocbq *iocb, *next_iocb;
int offline;
if (pring->ringno == LPFC_ELS_RING) {
if (phba->sli_rev >= LPFC_SLI_REV4)
plock = &pring->ring_lock;
else
plock = &phba->hbalock;
if (pring->ringno == LPFC_ELS_RING)
lpfc_fabric_abort_hba(phba);
}
offline = pci_channel_offline(phba->pcidev);
/* Error everything on txq and txcmplq
* First do the txq.
*/
if (phba->sli_rev >= LPFC_SLI_REV4) {
spin_lock_irq(&pring->ring_lock);
list_splice_init(&pring->txq, &tx_completions);
pring->txq_cnt = 0;
if (offline) {
list_splice_init(&pring->txcmplq,
&txcmplq_completions);
} else {
/* Next issue ABTS for everything on the txcmplq */
list_for_each_entry_safe(iocb, next_iocb,
&pring->txcmplq, list)
lpfc_sli_issue_abort_iotag(phba, pring,
iocb, NULL);
}
spin_unlock_irq(&pring->ring_lock);
} else {
spin_lock_irq(&phba->hbalock);
list_splice_init(&pring->txq, &tx_completions);
pring->txq_cnt = 0;
if (offline) {
list_splice_init(&pring->txcmplq, &txcmplq_completions);
} else {
/* Next issue ABTS for everything on the txcmplq */
list_for_each_entry_safe(iocb, next_iocb,
&pring->txcmplq, list)
lpfc_sli_issue_abort_iotag(phba, pring,
iocb, NULL);
}
spin_unlock_irq(&phba->hbalock);
}
/* Cancel everything on txq */
spin_lock_irq(plock);
list_splice_init(&pring->txq, &tx_completions);
pring->txq_cnt = 0;
if (offline) {
/* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &txcmplq_completions,
IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
/* Cancel everything on txcmplq */
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ;
list_splice_init(&pring->txcmplq, &tx_completions);
pring->txcmplq_cnt = 0;
} else {
/* Make sure HBA is alive */
lpfc_issue_hb_tmo(phba);
/* Issue ABTS for everything on the txcmplq */
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL);
}
spin_unlock_irq(plock);
if (!offline)
lpfc_issue_hb_tmo(phba);
/* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);