fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / scsi / lpfc / lpfc_sli.c
index 7b785ad..a4128e1 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-2005 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -117,6 +117,10 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
        case CMD_FCP_IREAD_CX:
        case CMD_FCP_ICMND_CR:
        case CMD_FCP_ICMND_CX:
+       case CMD_FCP_TSEND_CX:
+       case CMD_FCP_TRSP_CX:
+       case CMD_FCP_TRECEIVE_CX:
+       case CMD_FCP_AUTO_TRSP_CX:
        case CMD_ADAPTER_MSG:
        case CMD_ADAPTER_DUMP:
        case CMD_XMIT_SEQUENCE64_CR:
@@ -131,6 +135,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
        case CMD_FCP_IREAD64_CX:
        case CMD_FCP_ICMND64_CR:
        case CMD_FCP_ICMND64_CX:
+       case CMD_FCP_TSEND64_CX:
+       case CMD_FCP_TRSP64_CX:
+       case CMD_FCP_TRECEIVE64_CX:
        case CMD_GEN_REQUEST64_CR:
        case CMD_GEN_REQUEST64_CX:
        case CMD_XMIT_ELS_RSP64_CX:
@@ -191,35 +198,12 @@ static int
 lpfc_sli_ringtxcmpl_put(struct lpfc_hba * phba,
                        struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocb)
 {
-       uint16_t iotag;
-
        list_add_tail(&piocb->list, &pring->txcmplq);
        pring->txcmplq_cnt++;
        if (unlikely(pring->ringno == LPFC_ELS_RING))
                mod_timer(&phba->els_tmofunc,
                                        jiffies + HZ * (phba->fc_ratov << 1));
 
-       if (pring->fast_lookup) {
-               /* Setup fast lookup based on iotag for completion */
-               iotag = piocb->iocb.ulpIoTag;
-               if (iotag && (iotag < pring->fast_iotag))
-                       *(pring->fast_lookup + iotag) = piocb;
-               else {
-
-                       /* Cmd ring <ringno> put: iotag <iotag> greater then
-                          configured max <fast_iotag> wd0 <icmd> */
-                       lpfc_printf_log(phba,
-                                       KERN_ERR,
-                                       LOG_SLI,
-                                       "%d:0316 Cmd ring %d put: iotag x%x "
-                                       "greater then configured max x%x "
-                                       "wd0 x%x\n",
-                                       phba->brd_no,
-                                       pring->ringno, iotag,
-                                       pring->fast_iotag,
-                                       *(((uint32_t *)(&piocb->iocb)) + 7));
-               }
-       }
        return (0);
 }
 
@@ -343,7 +327,8 @@ lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
                        kfree(old_arr);
                        return iotag;
                }
-       }
+       } else
+               spin_unlock_irq(phba->host->host_lock);
 
        lpfc_printf_log(phba, KERN_ERR,LOG_SLI,
                        "%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n",
@@ -513,7 +498,9 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
        case MBX_SET_MASK:
        case MBX_SET_SLIM:
        case MBX_UNREG_D_ID:
+       case MBX_KILL_BOARD:
        case MBX_CONFIG_FARP:
+       case MBX_BEACON:
        case MBX_LOAD_AREA:
        case MBX_RUN_BIU_DIAG64:
        case MBX_CONFIG_PORT:
@@ -599,7 +586,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
                        /* Stray Mailbox Interrupt, mbxCommand <cmd> mbxStatus
                           <status> */
                        lpfc_printf_log(phba,
-                                       KERN_ERR,
+                                       KERN_WARNING,
                                        LOG_MBOX | LOG_SLI,
                                        "%d:0304 Stray Mailbox Interrupt "
                                        "mbxCommand x%x mbxStatus x%x\n",
@@ -764,7 +751,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        }
        /* unSolicited Responses */
        if (pring->prt[0].profile) {
-               (pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring, saveq);
+               if (pring->prt[0].lpfc_sli_rcv_unsol_event)
+                       (pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring,
+                                                                       saveq);
                match = 1;
        } else {
                /* We must search, based on rctl / type
@@ -775,8 +764,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                             Rctl)
                            && (pring->prt[i].
                                type == Type)) {
-                               (pring->prt[i].lpfc_sli_rcv_unsol_event)
-                                       (phba, pring, saveq);
+                               if (pring->prt[i].lpfc_sli_rcv_unsol_event)
+                                       (pring->prt[i].lpfc_sli_rcv_unsol_event)
+                                                       (phba, pring, saveq);
                                match = 1;
                                break;
                        }
@@ -987,9 +977,11 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
                         * resources need to be recovered.
                         */
                        if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
-                               printk(KERN_INFO "%s: IOCB cmd 0x%x processed."
-                                      " Skipping completion\n", __FUNCTION__,
-                                      irsp->ulpCommand);
+                               lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                                               "%d:0314 IOCB cmd 0x%x"
+                                               " processed. Skipping"
+                                               " completion", phba->brd_no,
+                                               irsp->ulpCommand);
                                break;
                        }
 
@@ -1113,6 +1105,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
                lpfc_sli_pcimem_bcopy((uint32_t *) entry,
                                      (uint32_t *) &rspiocbq.iocb,
                                      sizeof (IOCB_t));
+               INIT_LIST_HEAD(&(rspiocbq.list));
                irsp = &rspiocbq.iocb;
 
                type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK);
@@ -1122,7 +1115,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
                if (unlikely(irsp->ulpStatus)) {
                        /* Rsp ring <ringno> error: IOCB */
                        lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
-                               "%d:0326 Rsp Ring %d error: IOCB Data: "
+                               "%d:0336 Rsp Ring %d error: IOCB Data: "
                                "x%x x%x x%x x%x x%x x%x x%x x%x\n",
                                phba->brd_no, pring->ringno,
                                irsp->un.ulpWord[0], irsp->un.ulpWord[1],
@@ -1140,23 +1133,35 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
                         * resources need to be recovered.
                         */
                        if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
-                               printk(KERN_INFO "%s: IOCB cmd 0x%x processed. "
-                                      "Skipping completion\n", __FUNCTION__,
-                                      irsp->ulpCommand);
+                               lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                                               "%d:0333 IOCB cmd 0x%x"
+                                               " processed. Skipping"
+                                               " completion\n", phba->brd_no,
+                                               irsp->ulpCommand);
                                break;
                        }
 
                        cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
                                                         &rspiocbq);
                        if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) {
-                               spin_unlock_irqrestore(
-                                      phba->host->host_lock, iflag);
-                               (cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
-                                                     &rspiocbq);
-                               spin_lock_irqsave(phba->host->host_lock,
-                                                 iflag);
+                               if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
+                                       (cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
+                                                             &rspiocbq);
+                               } else {
+                                       spin_unlock_irqrestore(
+                                               phba->host->host_lock, iflag);
+                                       (cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
+                                                             &rspiocbq);
+                                       spin_lock_irqsave(phba->host->host_lock,
+                                                         iflag);
+                               }
                        }
                        break;
+               case LPFC_UNSOL_IOCB:
+                       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+                       lpfc_sli_process_unsol_iocb(phba, pring, &rspiocbq);
+                       spin_lock_irqsave(phba->host->host_lock, iflag);
+                       break;
                default:
                        if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
                                char adaptermsg[LPFC_MAX_ADPTMSG];
@@ -1168,7 +1173,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
                        } else {
                                /* Unknown IOCB command */
                                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-                                       "%d:0321 Unknown IOCB command "
+                                       "%d:0334 Unknown IOCB command "
                                        "Data: x%x, x%x x%x x%x x%x\n",
                                        phba->brd_no, type, irsp->ulpCommand,
                                        irsp->ulpStatus, irsp->ulpIoTag,
@@ -1251,7 +1256,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
                lpfc_printf_log(phba,
                                KERN_ERR,
                                LOG_SLI,
-                               "%d:0312 Ring %d handler: portRspPut %d "
+                               "%d:0303 Ring %d handler: portRspPut %d "
                                "is bigger then rsp ring %d\n",
                                phba->brd_no,
                                pring->ringno, portRspPut, portRspMax);
@@ -1396,7 +1401,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
                                        lpfc_printf_log(phba,
                                                KERN_ERR,
                                                LOG_SLI,
-                                               "%d:0321 Unknown IOCB command "
+                                               "%d:0335 Unknown IOCB command "
                                                "Data: x%x x%x x%x x%x\n",
                                                phba->brd_no,
                                                irsp->ulpCommand,
@@ -1412,11 +1417,11 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
                                                                 next_iocb,
                                                                 &saveq->list,
                                                                 list) {
+                                               list_del(&rspiocbp->list);
                                                lpfc_sli_release_iocbq(phba,
                                                                     rspiocbp);
                                        }
                                }
-
                                lpfc_sli_release_iocbq(phba, saveq);
                        }
                }
@@ -1512,98 +1517,238 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        return errcnt;
 }
 
-/******************************************************************************
-* lpfc_sli_send_reset
-*
-* Note: After returning from this function, the HBA cannot be accessed for
-* 1 ms. Since we do not wish to delay in interrupt context, it is the
-* responsibility of the caller to perform the mdelay(1) and flush via readl().
-******************************************************************************/
-static int
-lpfc_sli_send_reset(struct lpfc_hba * phba, uint16_t skip_post)
+int
+lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
 {
-       MAILBOX_t *swpmb;
-       volatile uint32_t word0;
-       void __iomem *to_slim;
-       unsigned long flags = 0;
-
-       spin_lock_irqsave(phba->host->host_lock, flags);
+       uint32_t status;
+       int i = 0;
+       int retval = 0;
 
-       /* A board reset must use REAL SLIM. */
-       phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
+       /* Read the HBA Host Status Register */
+       status = readl(phba->HSregaddr);
 
-       word0 = 0;
-       swpmb = (MAILBOX_t *) & word0;
-       swpmb->mbxCommand = MBX_RESTART;
-       swpmb->mbxHc = 1;
+       /*
+        * Check status register every 100ms for 5 retries, then every
+        * 500ms for 5, then every 2.5 sec for 5, then reset board and
+        * every 2.5 sec for 4.
+        * Break our of the loop if errors occurred during init.
+        */
+       while (((status & mask) != mask) &&
+              !(status & HS_FFERM) &&
+              i++ < 20) {
 
-       to_slim = phba->MBslimaddr;
-       writel(*(uint32_t *) swpmb, to_slim);
-       readl(to_slim); /* flush */
+               if (i <= 5)
+                       msleep(10);
+               else if (i <= 10)
+                       msleep(500);
+               else
+                       msleep(2500);
 
-       /* Only skip post after fc_ffinit is completed */
-       if (skip_post) {
-               word0 = 1;      /* This is really setting up word1 */
-       } else {
-               word0 = 0;      /* This is really setting up word1 */
+               if (i == 15) {
+                       phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */
+                       lpfc_sli_brdrestart(phba);
+               }
+               /* Read the HBA Host Status Register */
+               status = readl(phba->HSregaddr);
        }
-       to_slim = phba->MBslimaddr + sizeof (uint32_t);
-       writel(*(uint32_t *) swpmb, to_slim);
-       readl(to_slim); /* flush */
-
-       /* Turn off parity checking and serr during the physical reset */
-       pci_read_config_word(phba->pcidev, PCI_COMMAND, &phba->pci_cfg_value);
-       pci_write_config_word(phba->pcidev, PCI_COMMAND,
-                             (phba->pci_cfg_value &
-                              ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
-
-       writel(HC_INITFF, phba->HCregaddr);
 
-       phba->hba_state = LPFC_INIT_START;
-       spin_unlock_irqrestore(phba->host->host_lock, flags);
+       /* Check to see if any errors occurred during init */
+       if ((status & HS_FFERM) || (i >= 20)) {
+               phba->hba_state = LPFC_HBA_ERROR;
+               retval = 1;
+       }
 
-       return 0;
+       return retval;
 }
 
-static int
-lpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post)
+#define BARRIER_TEST_PATTERN (0xdeadbeef)
+
+void lpfc_reset_barrier(struct lpfc_hba * phba)
 {
-       struct lpfc_sli_ring *pring;
-       int i;
-       struct lpfc_dmabuf *mp, *next_mp;
-       unsigned long flags = 0;
+       uint32_t __iomem *resp_buf;
+       uint32_t __iomem *mbox_buf;
+       volatile uint32_t mbox;
+       uint32_t hc_copy;
+       int  i;
+       uint8_t hdrtype;
+
+       pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);
+       if (hdrtype != 0x80 ||
+           (FC_JEDEC_ID(phba->vpd.rev.biuRev) != HELIOS_JEDEC_ID &&
+            FC_JEDEC_ID(phba->vpd.rev.biuRev) != THOR_JEDEC_ID))
+               return;
 
-       lpfc_sli_send_reset(phba, skip_post);
-       mdelay(1);
+       /*
+        * Tell the other part of the chip to suspend temporarily all
+        * its DMA activity.
+        */
+       resp_buf = phba->MBslimaddr;
 
-       spin_lock_irqsave(phba->host->host_lock, flags);
-       /* Risk the write on flush case ie no delay after the readl */
+       /* Disable the error attention */
+       hc_copy = readl(phba->HCregaddr);
+       writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
-       /* Now toggle INITFF bit set by lpfc_sli_send_reset */
-       writel(0, phba->HCregaddr);
+
+       if (readl(phba->HAregaddr) & HA_ERATT) {
+               /* Clear Chip error bit */
+               writel(HA_ERATT, phba->HAregaddr);
+               phba->stopped = 1;
+       }
+
+       mbox = 0;
+       ((MAILBOX_t *)&mbox)->mbxCommand = MBX_KILL_BOARD;
+       ((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP;
+
+       writel(BARRIER_TEST_PATTERN, (resp_buf + 1));
+       mbox_buf = phba->MBslimaddr;
+       writel(mbox, mbox_buf);
+
+       for (i = 0;
+            readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN) && i < 50; i++)
+               mdelay(1);
+
+       if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) {
+               if (phba->sli.sli_flag & LPFC_SLI2_ACTIVE ||
+                   phba->stopped)
+                       goto restore_hc;
+               else
+                       goto clear_errat;
+       }
+
+       ((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST;
+       for (i = 0; readl(resp_buf) != mbox &&  i < 500; i++)
+               mdelay(1);
+
+clear_errat:
+
+       while (!(readl(phba->HAregaddr) & HA_ERATT) && ++i < 500)
+               mdelay(1);
+
+       if (readl(phba->HAregaddr) & HA_ERATT) {
+               writel(HA_ERATT, phba->HAregaddr);
+               phba->stopped = 1;
+       }
+
+restore_hc:
+       writel(hc_copy, phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
+}
 
-       /* Restore PCI cmd register */
-       pci_write_config_word(phba->pcidev, PCI_COMMAND, phba->pci_cfg_value);
+int
+lpfc_sli_brdkill(struct lpfc_hba * phba)
+{
+       struct lpfc_sli *psli;
+       LPFC_MBOXQ_t *pmb;
+       uint32_t status;
+       uint32_t ha_copy;
+       int retval;
+       int i = 0;
 
-       /* perform board reset */
-       phba->fc_eventTag = 0;
-       phba->fc_myDID = 0;
-       phba->fc_prevDID = Mask_DID;
+       psli = &phba->sli;
 
-       /* Reset HBA */
+       /* Kill HBA */
        lpfc_printf_log(phba,
                KERN_INFO,
                LOG_SLI,
-               "%d:0325 Reset HBA Data: x%x x%x x%x\n",
+               "%d:0329 Kill HBA Data: x%x x%x\n",
                phba->brd_no,
                phba->hba_state,
-               phba->sli.sli_flag,
-               skip_post);
+               psli->sli_flag);
+
+       if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+                                                 GFP_KERNEL)) == 0)
+               return 1;
+
+       /* Disable the error attention */
+       spin_lock_irq(phba->host->host_lock);
+       status = readl(phba->HCregaddr);
+       status &= ~HC_ERINT_ENA;
+       writel(status, phba->HCregaddr);
+       readl(phba->HCregaddr); /* flush */
+       spin_unlock_irq(phba->host->host_lock);
+
+       lpfc_kill_board(phba, pmb);
+       pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       retval = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+
+       if (retval != MBX_SUCCESS) {
+               if (retval != MBX_BUSY)
+                       mempool_free(pmb, phba->mbox_mem_pool);
+               return 1;
+       }
+
+       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+
+       mempool_free(pmb, phba->mbox_mem_pool);
+
+       /* There is no completion for a KILL_BOARD mbox cmd. Check for an error
+        * attention every 100ms for 3 seconds. If we don't get ERATT after
+        * 3 seconds we still set HBA_ERROR state because the status of the
+        * board is now undefined.
+        */
+       ha_copy = readl(phba->HAregaddr);
+
+       while ((i++ < 30) && !(ha_copy & HA_ERATT)) {
+               mdelay(100);
+               ha_copy = readl(phba->HAregaddr);
+       }
+
+       del_timer_sync(&psli->mbox_tmo);
+       if (ha_copy & HA_ERATT) {
+               writel(HA_ERATT, phba->HAregaddr);
+               phba->stopped = 1;
+       }
+       spin_lock_irq(phba->host->host_lock);
+       psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       spin_unlock_irq(phba->host->host_lock);
+
+       psli->mbox_active = NULL;
+       lpfc_hba_down_post(phba);
+       phba->hba_state = LPFC_HBA_ERROR;
+
+       return (ha_copy & HA_ERATT ? 0 : 1);
+}
+
+int
+lpfc_sli_brdreset(struct lpfc_hba * phba)
+{
+       struct lpfc_sli *psli;
+       struct lpfc_sli_ring *pring;
+       uint16_t cfg_value;
+       int i;
+
+       psli = &phba->sli;
+
+       /* Reset HBA */
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "%d:0325 Reset HBA Data: x%x x%x\n", phba->brd_no,
+                       phba->hba_state, psli->sli_flag);
+
+       /* perform board reset */
+       phba->fc_eventTag = 0;
+       phba->fc_myDID = 0;
+       phba->fc_prevDID = 0;
+
+       /* Turn off parity checking and serr during the physical reset */
+       pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
+       pci_write_config_word(phba->pcidev, PCI_COMMAND,
+                             (cfg_value &
+                              ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
+
+       psli->sli_flag &= ~(LPFC_SLI2_ACTIVE | LPFC_PROCESS_LA);
+       /* Now toggle INITFF bit in the Host Control Register */
+       writel(HC_INITFF, phba->HCregaddr);
+       mdelay(1);
+       readl(phba->HCregaddr); /* flush */
+       writel(0, phba->HCregaddr);
+       readl(phba->HCregaddr); /* flush */
+
+       /* Restore PCI cmd register */
+       pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value);
 
        /* Initialize relevant SLI info */
-       for (i = 0; i < phba->sli.num_rings; i++) {
-               pring = &phba->sli.ring[i];
+       for (i = 0; i < psli->num_rings; i++) {
+               pring = &psli->ring[i];
                pring->flag = 0;
                pring->rspidx = 0;
                pring->next_cmdidx  = 0;
@@ -1611,27 +1756,67 @@ lpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post)
                pring->cmdidx = 0;
                pring->missbufcnt = 0;
        }
-       spin_unlock_irqrestore(phba->host->host_lock, flags);
 
-       if (skip_post) {
-               mdelay(100);
+       phba->hba_state = LPFC_WARM_START;
+       return 0;
+}
+
+int
+lpfc_sli_brdrestart(struct lpfc_hba * phba)
+{
+       MAILBOX_t *mb;
+       struct lpfc_sli *psli;
+       uint16_t skip_post;
+       volatile uint32_t word0;
+       void __iomem *to_slim;
+
+       spin_lock_irq(phba->host->host_lock);
+
+       psli = &phba->sli;
+
+       /* Restart HBA */
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "%d:0337 Restart HBA Data: x%x x%x\n", phba->brd_no,
+                       phba->hba_state, psli->sli_flag);
+
+       word0 = 0;
+       mb = (MAILBOX_t *) &word0;
+       mb->mbxCommand = MBX_RESTART;
+       mb->mbxHc = 1;
+
+       lpfc_reset_barrier(phba);
+
+       to_slim = phba->MBslimaddr;
+       writel(*(uint32_t *) mb, to_slim);
+       readl(to_slim); /* flush */
+
+       /* Only skip post after fc_ffinit is completed */
+       if (phba->hba_state) {
+               skip_post = 1;
+               word0 = 1;      /* This is really setting up word1 */
        } else {
-               mdelay(2000);
+               skip_post = 0;
+               word0 = 0;      /* This is really setting up word1 */
        }
+       to_slim = phba->MBslimaddr + sizeof (uint32_t);
+       writel(*(uint32_t *) mb, to_slim);
+       readl(to_slim); /* flush */
 
-       spin_lock_irqsave(phba->host->host_lock, flags);
-       /* Cleanup preposted buffers on the ELS ring */
-       pring = &phba->sli.ring[LPFC_ELS_RING];
-       list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
-               list_del(&mp->list);
-               pring->postbufq_cnt--;
-               lpfc_mbuf_free(phba, mp->virt, mp->phys);
-               kfree(mp);
-       }
-       spin_unlock_irqrestore(phba->host->host_lock, flags);
+       lpfc_sli_brdreset(phba);
+       phba->stopped = 0;
+       phba->hba_state = LPFC_INIT_START;
 
-       for (i = 0; i < phba->sli.num_rings; i++)
-               lpfc_sli_abort_iocb_ring(phba, &phba->sli.ring[i]);
+       spin_unlock_irq(phba->host->host_lock);
+
+       memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
+       psli->stats_start = get_seconds();
+
+       if (skip_post)
+               mdelay(100);
+       else
+               mdelay(2000);
+
+       lpfc_hba_down_post(phba);
 
        return 0;
 }
@@ -1691,7 +1876,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
                }
 
                if (i == 15) {
-                       lpfc_sli_brdreset(phba, 0);
+                       phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */
+                       lpfc_sli_brdrestart(phba);
                }
                /* Read the HBA Host Status Register */
                status = readl(phba->HSregaddr);
@@ -1735,13 +1921,19 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba)
        }
 
        while (resetcount < 2 && !done) {
-               phba->hba_state = 0;
-               lpfc_sli_brdreset(phba, 0);
+               spin_lock_irq(phba->host->host_lock);
+               phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+               spin_unlock_irq(phba->host->host_lock);
+               phba->hba_state = LPFC_STATE_UNKNOWN;
+               lpfc_sli_brdrestart(phba);
                msleep(2500);
                rc = lpfc_sli_chipset_init(phba);
                if (rc)
                        break;
 
+               spin_lock_irq(phba->host->host_lock);
+               phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+               spin_unlock_irq(phba->host->host_lock);
                resetcount++;
 
        /* Call pre CONFIG_PORT mailbox command initialization.  A value of 0
@@ -1920,6 +2112,21 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
        mb = &pmbox->mb;
        status = MBX_SUCCESS;
 
+       if (phba->hba_state == LPFC_HBA_ERROR) {
+               spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
+
+               /* Mbox command <mbxCommand> cannot issue */
+               LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
+               return (MBX_NOT_FINISHED);
+       }
+
+       if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT &&
+           !(readl(phba->HCregaddr) & HC_MBINT_ENA)) {
+               spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
+               LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
+               return (MBX_NOT_FINISHED);
+       }
+
        if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
                /* Polling for a mbox command when another one is already active
                 * is not allowed in SLI. Also, the driver must have established
@@ -2002,7 +2209,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
 
        /* If we are not polling, we MUST be in SLI2 mode */
        if (flag != MBX_POLL) {
-               if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) {
+               if (!(psli->sli_flag & LPFC_SLI2_ACTIVE) &&
+                   (mb->mbxCommand != MBX_KILL_BOARD)) {
                        psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
                        spin_unlock_irqrestore(phba->host->host_lock,
                                               drvr_flag);
@@ -2011,7 +2219,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
                        return (MBX_NOT_FINISHED);
                }
                /* timeout active mbox command */
-               mod_timer(&psli->mbox_tmo, jiffies + HZ * LPFC_MBOX_TMO);
+               mod_timer(&psli->mbox_tmo, (jiffies +
+                              (HZ * lpfc_mbox_tmo_val(phba, mb->mbxCommand))));
        }
 
        /* Mailbox cmd <cmd> issue */
@@ -2071,7 +2280,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
                break;
 
        case MBX_POLL:
-               i = 0;
                psli->mbox_active = NULL;
                if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
                        /* First read mbox status word */
@@ -2085,10 +2293,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
                /* Read the HBA Host Attention Register */
                ha_copy = readl(phba->HAregaddr);
 
+               i = lpfc_mbox_tmo_val(phba, mb->mbxCommand);
+               i *= 1000; /* Convert to ms */
+
                /* Wait for command to complete */
-               while (((word0 & OWN_CHIP) == OWN_CHIP)
-                      || !(ha_copy & HA_MBATT)) {
-                       if (i++ >= 100) {
+               while (((word0 & OWN_CHIP) == OWN_CHIP) ||
+                      (!(ha_copy & HA_MBATT) &&
+                       (phba->hba_state > LPFC_WARM_START))) {
+                       if (i-- <= 0) {
                                psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
                                spin_unlock_irqrestore(phba->host->host_lock,
                                                       drvr_flag);
@@ -2106,7 +2318,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
 
                        /* Can be in interrupt context, do not sleep */
                        /* (or might be called with interrupts disabled) */
-                       mdelay(i);
+                       mdelay(1);
 
                        spin_lock_irqsave(phba->host->host_lock, drvr_flag);
 
@@ -2237,16 +2449,6 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                   !(phba->sli.sli_flag & LPFC_PROCESS_LA)))
                goto iocb_busy;
 
-       /*
-        * Check to see if this is a high priority command.
-        * If so bypass tx queue processing.
-        */
-       if (unlikely((flag & SLI_IOCB_HIGH_PRIORITY) &&
-                    (iocb = lpfc_sli_next_iocb_slot(phba, pring)))) {
-               lpfc_sli_submit_iocb(phba, pring, iocb, piocb);
-               piocb = NULL;
-       }
-
        while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
               (nextiocb = lpfc_sli_next_iocb(phba, pring, &piocb)))
                lpfc_sli_submit_iocb(phba, pring, iocb, nextiocb);
@@ -2274,6 +2476,41 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        return IOCB_BUSY;
 }
 
+static int
+lpfc_extra_ring_setup( struct lpfc_hba *phba)
+{
+       struct lpfc_sli *psli;
+       struct lpfc_sli_ring *pring;
+
+       psli = &phba->sli;
+
+       /* Adjust cmd/rsp ring iocb entries more evenly */
+
+       /* Take some away from the FCP ring */
+       pring = &psli->ring[psli->fcp_ring];
+       pring->numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES;
+       pring->numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES;
+       pring->numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES;
+       pring->numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+
+       /* and give them to the extra ring */
+       pring = &psli->ring[psli->extra_ring];
+
+       pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES;
+       pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
+       pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
+       pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+
+       /* Setup default profile for this ring */
+       pring->iotag_max = 4096;
+       pring->num_mask = 1;
+       pring->prt[0].profile = 0;      /* Mask 0 */
+       pring->prt[0].rctl = phba->cfg_multi_ring_rctl;
+       pring->prt[0].type = phba->cfg_multi_ring_type;
+       pring->prt[0].lpfc_sli_rcv_unsol_event = NULL;
+       return 0;
+}
+
 int
 lpfc_sli_setup(struct lpfc_hba *phba)
 {
@@ -2285,7 +2522,7 @@ lpfc_sli_setup(struct lpfc_hba *phba)
        psli->sli_flag = 0;
        psli->fcp_ring = LPFC_FCP_RING;
        psli->next_ring = LPFC_FCP_NEXT_RING;
-       psli->ip_ring = LPFC_IP_RING;
+       psli->extra_ring = LPFC_EXTRA_RING;
 
        psli->iocbq_lookup = NULL;
        psli->iocbq_lookup_len = 0;
@@ -2308,7 +2545,7 @@ lpfc_sli_setup(struct lpfc_hba *phba)
                        pring->fast_iotag = pring->iotag_max;
                        pring->num_mask = 0;
                        break;
-               case LPFC_IP_RING:      /* ring 1 - IP */
+               case LPFC_EXTRA_RING:   /* ring 1 - EXTRA */
                        /* numCiocb and numRiocb are used in config_port */
                        pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES;
                        pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES;
@@ -2357,6 +2594,8 @@ lpfc_sli_setup(struct lpfc_hba *phba)
                                "SLI2 SLIM Data: x%x x%x\n",
                                phba->brd_no, totiocb, MAX_SLI2_IOCB);
        }
+       if (phba->cfg_multi_ring_support == 2)
+               lpfc_extra_ring_setup(phba);
 
        return 0;
 }
@@ -2429,8 +2668,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
 
                INIT_LIST_HEAD(&(pring->txq));
 
-               kfree(pring->fast_lookup);
-               pring->fast_lookup = NULL;
        }
 
        spin_unlock_irqrestore(phba->host->host_lock, flags);
@@ -2465,15 +2702,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
 
        spin_unlock_irqrestore(phba->host->host_lock, flags);
 
-       /*
-        * Provided the hba is not in an error state, reset it.  It is not
-        * capable of IO anymore.
-        */
-       if (phba->hba_state != LPFC_HBA_ERROR) {
-               phba->hba_state = LPFC_INIT_START;
-               lpfc_sli_brdreset(phba, 1);
-       }
-
        return 1;
 }
 
@@ -2772,7 +3000,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
                         struct lpfc_iocbq * prspiocbq,
                         uint32_t timeout)
 {
-       DECLARE_WAIT_QUEUE_HEAD(done_q);
+       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
        long timeleft, timeout_req = 0;
        int retval = IOCB_SUCCESS;
        uint32_t creg_val;
@@ -2809,7 +3037,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
 
                if (timeleft == 0) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-                                       "%d:0329 IOCB wait timeout error - no "
+                                       "%d:0338 IOCB wait timeout error - no "
                                        "wake response Data x%x\n",
                                        phba->brd_no, timeout);
                        retval = IOCB_TIMEDOUT;
@@ -2850,7 +3078,7 @@ int
 lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
                         uint32_t timeout)
 {
-       DECLARE_WAIT_QUEUE_HEAD(done_q);
+       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
        DECLARE_WAITQUEUE(wq_entry, current);
        uint32_t timeleft = 0;
        int retval;
@@ -2877,11 +3105,10 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
                pmboxq->context1 = NULL;
                /* if schedule_timeout returns 0, we timed out and were not
                   woken up */
-               if (timeleft == 0) {
+               if ((timeleft == 0) || signal_pending(current))
                        retval = MBX_TIMEOUT;
-               } else {
+               else
                        retval = MBX_SUCCESS;
-               }
        }
 
 
@@ -2890,8 +3117,26 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
        return retval;
 }
 
+int
+lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
+{
+       int i = 0;
+
+       while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !phba->stopped) {
+               if (i++ > LPFC_MBOX_TMO * 1000)
+                       return 1;
+
+               if (lpfc_sli_handle_mb_event(phba) == 0)
+                       i = 0;
+
+               msleep(1);
+       }
+
+       return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0;
+}
+
 irqreturn_t
-lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
+lpfc_intr_handler(int irq, void *dev_id)
 {
        struct lpfc_hba *phba;
        uint32_t ha_copy;
@@ -2987,13 +3232,7 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
                        /* Clear Chip error bit */
                        writel(HA_ERATT, phba->HAregaddr);
                        readl(phba->HAregaddr); /* flush */
-
-                       /*
-                        * Reseting the HBA is the only reliable way
-                        * to shutdown interrupt when there is a
-                        * ERROR.
-                        */
-                       lpfc_sli_send_reset(phba, phba->hba_state);
+                       phba->stopped = 1;
                }
 
                spin_lock(phba->host->host_lock);
@@ -3016,6 +3255,21 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
                lpfc_sli_handle_fast_ring_event(phba,
                                                &phba->sli.ring[LPFC_FCP_RING],
                                                status);
+
+       if (phba->cfg_multi_ring_support == 2) {
+               /*
+                * Process all events on extra ring.  Take the optimized path
+                * for extra ring IO.  Any other IO is slow path and is handled
+                * by the worker thread.
+                */
+               status = (ha_copy & (HA_RXMASK  << (4*LPFC_EXTRA_RING)));
+               status >>= (4*LPFC_EXTRA_RING);
+               if (status & HA_RXATT) {
+                       lpfc_sli_handle_fast_ring_event(phba,
+                                       &phba->sli.ring[LPFC_EXTRA_RING],
+                                       status);
+               }
+       }
        return IRQ_HANDLED;
 
 } /* lpfc_intr_handler */