Commit 0976e1a6 authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.3.44: Fix Crash in lpfc_els_timeout_handler

Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 646a2dd7
...@@ -6223,19 +6223,17 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) ...@@ -6223,19 +6223,17 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
uint32_t els_command = 0; uint32_t els_command = 0;
uint32_t timeout; uint32_t timeout;
uint32_t remote_ID = 0xffffffff; uint32_t remote_ID = 0xffffffff;
LIST_HEAD(txcmplq_completions);
LIST_HEAD(abort_list); LIST_HEAD(abort_list);
timeout = (uint32_t)(phba->fc_ratov << 1); timeout = (uint32_t)(phba->fc_ratov << 1);
pring = &phba->sli.ring[LPFC_ELS_RING]; pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irq(&phba->hbalock); spin_lock_irq(&phba->hbalock);
list_splice_init(&pring->txcmplq, &txcmplq_completions); if (phba->sli_rev == LPFC_SLI_REV4)
spin_unlock_irq(&phba->hbalock); 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; cmd = &piocb->iocb;
if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 || if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
...@@ -6274,8 +6272,8 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) ...@@ -6274,8 +6272,8 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
} }
list_add_tail(&piocb->dlist, &abort_list); list_add_tail(&piocb->dlist, &abort_list);
} }
spin_lock_irq(&phba->hbalock); if (phba->sli_rev == LPFC_SLI_REV4)
list_splice(&txcmplq_completions, &pring->txcmplq); spin_unlock(&pring->ring_lock);
spin_unlock_irq(&phba->hbalock); spin_unlock_irq(&phba->hbalock);
list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
...@@ -6317,15 +6315,50 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) ...@@ -6317,15 +6315,50 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
void void
lpfc_els_flush_cmd(struct lpfc_vport *vport) lpfc_els_flush_cmd(struct lpfc_vport *vport)
{ {
LIST_HEAD(completions); LIST_HEAD(abort_list);
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
struct lpfc_iocbq *tmp_iocb, *piocb; struct lpfc_iocbq *tmp_iocb, *piocb;
IOCB_t *cmd = NULL; IOCB_t *cmd = NULL;
lpfc_fabric_abort_vport(vport); 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); 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) { list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
cmd = &piocb->iocb; cmd = &piocb->iocb;
...@@ -6343,24 +6376,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) ...@@ -6343,24 +6376,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
if (piocb->vport != vport) if (piocb->vport != vport)
continue; continue;
list_move_tail(&piocb->list, &completions); list_del_init(&piocb->list);
} list_add_tail(&piocb->list, &abort_list);
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);
} }
if (phba->sli_rev == LPFC_SLI_REV4)
spin_unlock(&pring->ring_lock);
spin_unlock_irq(&phba->hbalock); spin_unlock_irq(&phba->hbalock);
/* Cancell all the IOCBs from the completions list */ /* Cancell all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, lpfc_sli_cancel_iocbs(phba, &abort_list,
IOERR_SLI_ABORTED); IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
return; return;
} }
...@@ -6385,35 +6410,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) ...@@ -6385,35 +6410,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
void void
lpfc_els_flush_all_cmd(struct lpfc_hba *phba) lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
{ {
LIST_HEAD(completions); struct lpfc_vport *vport;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; list_for_each_entry(vport, &phba->port_list, listentry)
struct lpfc_iocbq *tmp_iocb, *piocb; lpfc_els_flush_cmd(vport);
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);
return; return;
} }
......
...@@ -203,8 +203,6 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ...@@ -203,8 +203,6 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
int int
lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{ {
LIST_HEAD(completions);
LIST_HEAD(txcmplq_completions);
LIST_HEAD(abort_list); LIST_HEAD(abort_list);
struct lpfc_sli *psli = &phba->sli; struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; 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) ...@@ -216,32 +214,27 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
"Data: x%x x%x x%x\n", "Data: x%x x%x x%x\n",
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi); ndlp->nlp_rpi);
/* Clean up all fabric IOs first.*/
lpfc_fabric_abort_nport(ndlp); 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); spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { if (phba->sli_rev == LPFC_SLI_REV4)
/* Check to see if iocb matches the nport we are looking for */ spin_lock(&pring->ring_lock);
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
/* It matches, so deque and call compl with anp error */ /* Add to abort_list on on NDLP match. */
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 (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
list_add_tail(&iocb->dlist, &abort_list); list_add_tail(&iocb->dlist, &abort_list);
} }
spin_lock_irq(&phba->hbalock); if (phba->sli_rev == LPFC_SLI_REV4)
list_splice(&txcmplq_completions, &pring->txcmplq); spin_unlock(&pring->ring_lock);
spin_unlock_irq(&phba->hbalock); 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) { list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
spin_lock_irq(&phba->hbalock); spin_lock_irq(&phba->hbalock);
list_del_init(&iocb->dlist); list_del_init(&iocb->dlist);
...@@ -249,9 +242,28 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) ...@@ -249,9 +242,28 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
spin_unlock_irq(&phba->hbalock); 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 */ /* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, lpfc_sli_cancel_iocbs(phba, &abort_list,
IOERR_SLI_ABORTED); IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment