diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-04-25 09:51:38 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-05-06 10:33:13 -0400 |
commit | 07951076aefa4194e1dbf1d8c89eaff040c45155 (patch) | |
tree | 636052abb3f9f2a1bdc0d9adfec130b224a02289 /drivers/scsi/lpfc/lpfc_sli.c | |
parent | 1dcb58e5680b6673bf984696d3d8b9033b6e41bf (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.c | 122 |
1 files changed, 63 insertions, 59 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 54a8f4d3db13..dcd313ab4a72 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 | ||
2730 | static void | 2738 | static void |
2731 | lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | 2739 | lpfc_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 | ||
2765 | int | 2748 | int |
2766 | lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba, | 2749 | lpfc_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) { | 2797 | abort_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; |