scsi: lpfc: Correct irq handling via locks when taking adapter offline

When taking the board offline while performing i/o, unsafe locking errors
occurred and irq level isn't properly managed.

In lpfc_sli_hba_down, spin_lock_irqsave(&phba->hbalock, flags) does not
disable softirqs raised from timer expiry.  It is possible that a softirq is
raised from the lpfc_els_retry_delay routine and recursively requests the same
phba->hbalock spinlock causing deadlock.

Address the deadlocks by creating a new port_list lock. The softirq behavior
can then be managed a level deeper into the calling sequences.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
这个提交包含在:
James Smart
2018-09-10 10:30:46 -07:00
提交者 Martin K. Petersen
父节点 0ef01a2d95
当前提交 523128e53b
修改 7 个文件,包含 52 行新增22 行删除

查看文件

@@ -10273,8 +10273,12 @@ lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba)
LPFC_MBOXQ_t *pmb;
unsigned long iflag;
/* Disable softirqs, including timers from obtaining phba->hbalock */
local_bh_disable();
/* Flush all the mailbox commands in the mbox system */
spin_lock_irqsave(&phba->hbalock, iflag);
/* The pending mailbox command queue */
list_splice_init(&phba->sli.mboxq, &completions);
/* The outstanding active mailbox command */
@@ -10287,6 +10291,9 @@ lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba)
list_splice_init(&phba->sli.mboxq_cmpl, &completions);
spin_unlock_irqrestore(&phba->hbalock, iflag);
/* Enable softirqs again, done with phba->hbalock */
local_bh_enable();
/* Return all flushed mailbox commands with MBX_NOT_FINISHED status */
while (!list_empty(&completions)) {
list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list);
@@ -10426,6 +10433,9 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
lpfc_hba_down_prep(phba);
/* Disable softirqs, including timers from obtaining phba->hbalock */
local_bh_disable();
lpfc_fabric_abort_hba(phba);
spin_lock_irqsave(&phba->hbalock, flags);
@@ -10479,6 +10489,9 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
kfree(buf_ptr);
}
/* Enable softirqs again, done with phba->hbalock */
local_bh_enable();
/* Return any active mbox cmds */
del_timer_sync(&psli->mbox_tmo);
@@ -11782,6 +11795,9 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action)
}
timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies;
/* Disable softirqs, including timers from obtaining phba->hbalock */
local_bh_disable();
spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK;
@@ -11795,6 +11811,9 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action)
1000) + jiffies;
spin_unlock_irq(&phba->hbalock);
/* Enable softirqs again, done with phba->hbalock */
local_bh_enable();
while (phba->sli.mbox_active) {
/* Check active mailbox complete status every 2ms */
msleep(2);
@@ -11804,9 +11823,13 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action)
*/
break;
}
} else
} else {
spin_unlock_irq(&phba->hbalock);
/* Enable softirqs again, done with phba->hbalock */
local_bh_enable();
}
lpfc_sli_mbox_sys_flush(phba);
}