mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-21 11:44:01 +08:00
[SCSI] lpfc 8.3.44: Fix Crash in lpfc_els_timeout_handler
Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
646a2dd751
commit
0976e1a650
drivers/scsi/lpfc
@ -6223,19 +6223,17 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
|
||||
uint32_t els_command = 0;
|
||||
uint32_t timeout;
|
||||
uint32_t remote_ID = 0xffffffff;
|
||||
LIST_HEAD(txcmplq_completions);
|
||||
LIST_HEAD(abort_list);
|
||||
|
||||
|
||||
timeout = (uint32_t)(phba->fc_ratov << 1);
|
||||
|
||||
pring = &phba->sli.ring[LPFC_ELS_RING];
|
||||
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_splice_init(&pring->txcmplq, &txcmplq_completions);
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_lock(&pring->ring_lock);
|
||||
|
||||
list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) {
|
||||
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
|
||||
cmd = &piocb->iocb;
|
||||
|
||||
if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
|
||||
@ -6274,8 +6272,8 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
|
||||
}
|
||||
list_add_tail(&piocb->dlist, &abort_list);
|
||||
}
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_splice(&txcmplq_completions, &pring->txcmplq);
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_unlock(&pring->ring_lock);
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
||||
list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
|
||||
@ -6317,15 +6315,50 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
|
||||
void
|
||||
lpfc_els_flush_cmd(struct lpfc_vport *vport)
|
||||
{
|
||||
LIST_HEAD(completions);
|
||||
LIST_HEAD(abort_list);
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
|
||||
struct lpfc_iocbq *tmp_iocb, *piocb;
|
||||
IOCB_t *cmd = NULL;
|
||||
|
||||
lpfc_fabric_abort_vport(vport);
|
||||
/*
|
||||
* For SLI3, only the hbalock is required. But SLI4 needs to coordinate
|
||||
* with the ring insert operation. Because lpfc_sli_issue_abort_iotag
|
||||
* ultimately grabs the ring_lock, the driver must splice the list into
|
||||
* a working list and release the locks before calling the abort.
|
||||
*/
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_lock(&pring->ring_lock);
|
||||
|
||||
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
|
||||
if (piocb->iocb_flag & LPFC_IO_LIBDFC)
|
||||
continue;
|
||||
|
||||
if (piocb->vport != vport)
|
||||
continue;
|
||||
list_add_tail(&piocb->dlist, &abort_list);
|
||||
}
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_unlock(&pring->ring_lock);
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
/* Abort each iocb on the aborted list and remove the dlist links. */
|
||||
list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_del_init(&piocb->dlist);
|
||||
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
}
|
||||
if (!list_empty(&abort_list))
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
|
||||
"3387 abort list for txq not empty\n");
|
||||
INIT_LIST_HEAD(&abort_list);
|
||||
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_lock(&pring->ring_lock);
|
||||
|
||||
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
|
||||
cmd = &piocb->iocb;
|
||||
|
||||
@ -6343,24 +6376,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
|
||||
if (piocb->vport != vport)
|
||||
continue;
|
||||
|
||||
list_move_tail(&piocb->list, &completions);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
|
||||
if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (piocb->vport != vport)
|
||||
continue;
|
||||
|
||||
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
|
||||
list_del_init(&piocb->list);
|
||||
list_add_tail(&piocb->list, &abort_list);
|
||||
}
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_unlock(&pring->ring_lock);
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
||||
/* Cancell all the IOCBs from the completions list */
|
||||
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
|
||||
IOERR_SLI_ABORTED);
|
||||
lpfc_sli_cancel_iocbs(phba, &abort_list,
|
||||
IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -6385,35 +6410,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
|
||||
void
|
||||
lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
|
||||
{
|
||||
LIST_HEAD(completions);
|
||||
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
|
||||
struct lpfc_iocbq *tmp_iocb, *piocb;
|
||||
IOCB_t *cmd = NULL;
|
||||
|
||||
lpfc_fabric_abort_hba(phba);
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
|
||||
cmd = &piocb->iocb;
|
||||
if (piocb->iocb_flag & LPFC_IO_LIBDFC)
|
||||
continue;
|
||||
/* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
|
||||
if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
|
||||
cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
|
||||
cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
|
||||
cmd->ulpCommand == CMD_ABORT_XRI_CN)
|
||||
continue;
|
||||
list_move_tail(&piocb->list, &completions);
|
||||
}
|
||||
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
|
||||
if (piocb->iocb_flag & LPFC_IO_LIBDFC)
|
||||
continue;
|
||||
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
|
||||
}
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
||||
/* Cancel all the IOCBs from the completions list */
|
||||
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
|
||||
IOERR_SLI_ABORTED);
|
||||
struct lpfc_vport *vport;
|
||||
list_for_each_entry(vport, &phba->port_list, listentry)
|
||||
lpfc_els_flush_cmd(vport);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -203,8 +203,6 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
int
|
||||
lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
|
||||
{
|
||||
LIST_HEAD(completions);
|
||||
LIST_HEAD(txcmplq_completions);
|
||||
LIST_HEAD(abort_list);
|
||||
struct lpfc_sli *psli = &phba->sli;
|
||||
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
|
||||
@ -216,32 +214,27 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
|
||||
"Data: x%x x%x x%x\n",
|
||||
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
|
||||
ndlp->nlp_rpi);
|
||||
|
||||
/* Clean up all fabric IOs first.*/
|
||||
lpfc_fabric_abort_nport(ndlp);
|
||||
|
||||
/* First check the txq */
|
||||
/*
|
||||
* Lock the ELS ring txcmplq for SLI3/SLI4 and build a local list
|
||||
* of all ELS IOs that need an ABTS. The IOs need to stay on the
|
||||
* txcmplq so that the abort operation completes them successfully.
|
||||
*/
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
|
||||
/* Check to see if iocb matches the nport we are looking for */
|
||||
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
|
||||
/* It matches, so deque and call compl with anp error */
|
||||
list_move_tail(&iocb->list, &completions);
|
||||
}
|
||||
}
|
||||
|
||||
/* Next check the txcmplq */
|
||||
list_splice_init(&pring->txcmplq, &txcmplq_completions);
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
||||
list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) {
|
||||
/* Check to see if iocb matches the nport we are looking for */
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_lock(&pring->ring_lock);
|
||||
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
|
||||
/* Add to abort_list on on NDLP match. */
|
||||
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
|
||||
list_add_tail(&iocb->dlist, &abort_list);
|
||||
}
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_splice(&txcmplq_completions, &pring->txcmplq);
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_unlock(&pring->ring_lock);
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
||||
/* Abort the targeted IOs and remove them from the abort list. */
|
||||
list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_del_init(&iocb->dlist);
|
||||
@ -249,9 +242,28 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&abort_list);
|
||||
|
||||
/* Now process the txq */
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_lock(&pring->ring_lock);
|
||||
|
||||
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
|
||||
/* Check to see if iocb matches the nport we are looking for */
|
||||
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
|
||||
list_del_init(&iocb->list);
|
||||
list_add_tail(&iocb->list, &abort_list);
|
||||
}
|
||||
}
|
||||
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
spin_unlock(&pring->ring_lock);
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
||||
/* Cancel all the IOCBs from the completions list */
|
||||
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
|
||||
IOERR_SLI_ABORTED);
|
||||
lpfc_sli_cancel_iocbs(phba, &abort_list,
|
||||
IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
|
||||
|
||||
lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user