]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/lpfc/lpfc_sli.c
Pull thermal into release branch
[linux-2.6-omap-h63xx.git] / drivers / scsi / lpfc / lpfc_sli.c
index fd82797df09541cb8357b29aafcaae16c51af17d..a1e721459e2b21a1734bff082c33e4f3c7df2bc7 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -1584,6 +1584,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
        hc_copy = readl(phba->HCregaddr);
        writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
+       phba->fc_flag |= FC_IGNORE_ERATT;
 
        if (readl(phba->HAregaddr) & HA_ERATT) {
                /* Clear Chip error bit */
@@ -1626,6 +1627,7 @@ clear_errat:
        }
 
 restore_hc:
+       phba->fc_flag &= ~FC_IGNORE_ERATT;
        writel(hc_copy, phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
 }
@@ -1661,6 +1663,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
        status &= ~HC_ERINT_ENA;
        writel(status, phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
+       phba->fc_flag |= FC_IGNORE_ERATT;
        spin_unlock_irq(phba->host->host_lock);
 
        lpfc_kill_board(phba, pmb);
@@ -1670,6 +1673,9 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
        if (retval != MBX_SUCCESS) {
                if (retval != MBX_BUSY)
                        mempool_free(pmb, phba->mbox_mem_pool);
+               spin_lock_irq(phba->host->host_lock);
+               phba->fc_flag &= ~FC_IGNORE_ERATT;
+               spin_unlock_irq(phba->host->host_lock);
                return 1;
        }
 
@@ -1696,6 +1702,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
        }
        spin_lock_irq(phba->host->host_lock);
        psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       phba->fc_flag &= ~FC_IGNORE_ERATT;
        spin_unlock_irq(phba->host->host_lock);
 
        psli->mbox_active = NULL;
@@ -2403,7 +2410,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        if (unlikely(phba->hba_state == LPFC_LINK_DOWN)) {
                /*
-                * Only CREATE_XRI, CLOSE_XRI, ABORT_XRI, and QUE_RING_BUF
+                * Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF
                 * can be issued if the link is not up.
                 */
                switch (piocb->iocb.ulpCommand) {
@@ -2417,6 +2424,8 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                piocb->iocb_cmpl = NULL;
                        /*FALLTHROUGH*/
                case CMD_CREATE_XRI_CR:
+               case CMD_CLOSE_XRI_CN:
+               case CMD_CLOSE_XRI_CX:
                        break;
                default:
                        goto iocb_busy;
@@ -2741,7 +2750,58 @@ static void
 lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        struct lpfc_iocbq * rspiocb)
 {
+       IOCB_t *irsp;
+       uint16_t abort_iotag, abort_context;
+       struct lpfc_iocbq *abort_iocb, *rsp_ab_iocb;
+       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+
+       abort_iocb = NULL;
+       irsp = &rspiocb->iocb;
+
        spin_lock_irq(phba->host->host_lock);
+
+       if (irsp->ulpStatus) {
+               abort_context = cmdiocb->iocb.un.acxri.abortContextTag;
+               abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag;
+
+               if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag)
+                       abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
+
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "%d:0327 Cannot abort els iocb %p"
+                               " with tag %x context %x\n",
+                               phba->brd_no, abort_iocb,
+                               abort_iotag, abort_context);
+
+               /*
+                * make sure we have the right iocbq before taking it
+                * off the txcmplq and try to call completion routine.
+                */
+               if (abort_iocb &&
+                   abort_iocb->iocb.ulpContext == abort_context &&
+                   abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) {
+                       list_del(&abort_iocb->list);
+                       pring->txcmplq_cnt--;
+
+                       rsp_ab_iocb = lpfc_sli_get_iocbq(phba);
+                       if (rsp_ab_iocb == NULL)
+                               lpfc_sli_release_iocbq(phba, abort_iocb);
+                       else {
+                               abort_iocb->iocb_flag &=
+                                       ~LPFC_DRIVER_ABORTED;
+                               rsp_ab_iocb->iocb.ulpStatus =
+                                       IOSTAT_LOCAL_REJECT;
+                               rsp_ab_iocb->iocb.un.ulpWord[4] =
+                                       IOERR_SLI_ABORTED;
+                               spin_unlock_irq(phba->host->host_lock);
+                               (abort_iocb->iocb_cmpl)
+                                       (phba, abort_iocb, rsp_ab_iocb);
+                               spin_lock_irq(phba->host->host_lock);
+                               lpfc_sli_release_iocbq(phba, rsp_ab_iocb);
+                       }
+               }
+       }
+
        lpfc_sli_release_iocbq(phba, cmdiocb);
        spin_unlock_irq(phba->host->host_lock);
        return;
@@ -3154,6 +3214,11 @@ lpfc_intr_handler(int irq, void *dev_id)
         */
        spin_lock(phba->host->host_lock);
        ha_copy = readl(phba->HAregaddr);
+       /* If somebody is waiting to handle an eratt don't process it
+        * here.  The brdkill function will do this.
+        */
+       if (phba->fc_flag & FC_IGNORE_ERATT)
+               ha_copy &= ~HA_ERATT;
        writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
        readl(phba->HAregaddr); /* flush */
        spin_unlock(phba->host->host_lock);