aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_sli.c
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2007-04-25 09:51:38 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-05-06 10:33:13 -0400
commit07951076aefa4194e1dbf1d8c89eaff040c45155 (patch)
tree636052abb3f9f2a1bdc0d9adfec130b224a02289 /drivers/scsi/lpfc/lpfc_sli.c
parent1dcb58e5680b6673bf984696d3d8b9033b6e41bf (diff)
[SCSI] lpfc 8.1.12 : Modify ELS abort handling to prevent double completion
Modify ELS abort handling to prevent double completion Rework portions of ELS abort handling to prevent double completion - Rework ELS iotags and correct abort routine - Move the (badly wrong) ELS completion logic from the initial ELS abort request function to the ELS completion function. - Fixup the iocb completion handling to account for the ELS abort completions. Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c122
1 files changed, 63 insertions, 59 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 54a8f4d3db1..dcd313ab4a7 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -816,6 +816,14 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
816 * All other are passed to the completion callback. 816 * All other are passed to the completion callback.
817 */ 817 */
818 if (pring->ringno == LPFC_ELS_RING) { 818 if (pring->ringno == LPFC_ELS_RING) {
819 if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) {
820 cmdiocbp->iocb_flag &=
821 ~LPFC_DRIVER_ABORTED;
822 saveq->iocb.ulpStatus =
823 IOSTAT_LOCAL_REJECT;
824 saveq->iocb.un.ulpWord[4] =
825 IOERR_SLI_ABORTED;
826 }
819 spin_unlock_irqrestore(phba->host->host_lock, 827 spin_unlock_irqrestore(phba->host->host_lock,
820 iflag); 828 iflag);
821 (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); 829 (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -2728,85 +2736,81 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
2728} 2736}
2729 2737
2730static void 2738static void
2731lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, 2739lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
2732 struct lpfc_iocbq * rspiocb) 2740 struct lpfc_iocbq * rspiocb)
2733{ 2741{
2734 struct lpfc_dmabuf *buf_ptr, *buf_ptr1; 2742 spin_lock_irq(phba->host->host_lock);
2735 /* Free the resources associated with the ELS_REQUEST64 IOCB the driver
2736 * just aborted.
2737 * In this case, context2 = cmd, context2->next = rsp, context3 = bpl
2738 */
2739 if (cmdiocb->context2) {
2740 buf_ptr1 = (struct lpfc_dmabuf *) cmdiocb->context2;
2741
2742 /* Free the response IOCB before completing the abort
2743 command. */
2744 buf_ptr = NULL;
2745 list_remove_head((&buf_ptr1->list), buf_ptr,
2746 struct lpfc_dmabuf, list);
2747 if (buf_ptr) {
2748 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2749 kfree(buf_ptr);
2750 }
2751 lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
2752 kfree(buf_ptr1);
2753 }
2754
2755 if (cmdiocb->context3) {
2756 buf_ptr = (struct lpfc_dmabuf *) cmdiocb->context3;
2757 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2758 kfree(buf_ptr);
2759 }
2760
2761 lpfc_sli_release_iocbq(phba, cmdiocb); 2743 lpfc_sli_release_iocbq(phba, cmdiocb);
2744 spin_unlock_irq(phba->host->host_lock);
2762 return; 2745 return;
2763} 2746}
2764 2747
2765int 2748int
2766lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba, 2749lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba,
2767 struct lpfc_sli_ring * pring, 2750 struct lpfc_sli_ring * pring,
2768 struct lpfc_iocbq * cmdiocb) 2751 struct lpfc_iocbq * cmdiocb)
2769{ 2752{
2770 struct lpfc_iocbq *abtsiocbp; 2753 struct lpfc_iocbq *abtsiocbp;
2771 IOCB_t *icmd = NULL; 2754 IOCB_t *icmd = NULL;
2772 IOCB_t *iabt = NULL; 2755 IOCB_t *iabt = NULL;
2756 int retval = IOCB_ERROR;
2757
2758 /* There are certain command types we don't want
2759 * to abort.
2760 */
2761 icmd = &cmdiocb->iocb;
2762 if ((icmd->ulpCommand == CMD_ABORT_XRI_CN) ||
2763 (icmd->ulpCommand == CMD_CLOSE_XRI_CN))
2764 return 0;
2765
2766 /* If we're unloading, interrupts are disabled so we
2767 * need to cleanup the iocb here.
2768 */
2769 if (phba->fc_flag & FC_UNLOADING)
2770 goto abort_iotag_exit;
2773 2771
2774 /* issue ABTS for this IOCB based on iotag */ 2772 /* issue ABTS for this IOCB based on iotag */
2775 abtsiocbp = lpfc_sli_get_iocbq(phba); 2773 abtsiocbp = lpfc_sli_get_iocbq(phba);
2776 if (abtsiocbp == NULL) 2774 if (abtsiocbp == NULL)
2777 return 0; 2775 return 0;
2778 2776
2777 /* This signals the response to set the correct status
2778 * before calling the completion handler.
2779 */
2780 cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
2781
2779 iabt = &abtsiocbp->iocb; 2782 iabt = &abtsiocbp->iocb;
2780 icmd = &cmdiocb->iocb; 2783 iabt->un.acxri.abortType = ABORT_TYPE_ABTS;
2781 switch (icmd->ulpCommand) { 2784 iabt->un.acxri.abortContextTag = icmd->ulpContext;
2782 case CMD_ELS_REQUEST64_CR: 2785 iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
2783 /* Even though we abort the ELS command, the firmware may access 2786 iabt->ulpLe = 1;
2784 * the BPL or other resources before it processes our 2787 iabt->ulpClass = icmd->ulpClass;
2785 * ABORT_MXRI64. Thus we must delay reusing the cmdiocb
2786 * resources till the actual abort request completes.
2787 */
2788 abtsiocbp->context1 = (void *)((unsigned long)icmd->ulpCommand);
2789 abtsiocbp->context2 = cmdiocb->context2;
2790 abtsiocbp->context3 = cmdiocb->context3;
2791 cmdiocb->context2 = NULL;
2792 cmdiocb->context3 = NULL;
2793 abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl;
2794 break;
2795 default:
2796 lpfc_sli_release_iocbq(phba, abtsiocbp);
2797 return 0;
2798 }
2799 2788
2800 iabt->un.amxri.abortType = ABORT_TYPE_ABTS; 2789 if (phba->hba_state >= LPFC_LINK_UP)
2801 iabt->un.amxri.iotag32 = icmd->un.elsreq64.bdl.ulpIoTag32; 2790 iabt->ulpCommand = CMD_ABORT_XRI_CN;
2791 else
2792 iabt->ulpCommand = CMD_CLOSE_XRI_CN;
2802 2793
2803 iabt->ulpLe = 1; 2794 abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
2804 iabt->ulpClass = CLASS3; 2795 retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
2805 iabt->ulpCommand = CMD_ABORT_MXRI64_CN;
2806 2796
2807 if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) { 2797abort_iotag_exit:
2808 lpfc_sli_release_iocbq(phba, abtsiocbp); 2798
2809 return 0; 2799 /* If we could not issue an abort dequeue the iocb and handle
2800 * the completion here.
2801 */
2802 if (retval == IOCB_ERROR) {
2803 list_del(&cmdiocb->list);
2804 pring->txcmplq_cnt--;
2805
2806 if (cmdiocb->iocb_cmpl) {
2807 icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
2808 icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
2809 spin_unlock_irq(phba->host->host_lock);
2810 (cmdiocb->iocb_cmpl) (phba, cmdiocb, cmdiocb);
2811 spin_lock_irq(phba->host->host_lock);
2812 } else
2813 lpfc_sli_release_iocbq(phba, cmdiocb);
2810 } 2814 }
2811 2815
2812 return 1; 2816 return 1;