[SCSI] fusion: mptsas, increase discovery timout to 300 seconds
[safe/jmp/linux-2.6] / drivers / message / fusion / mptbase.c
index 14d62d9..780e8be 100644 (file)
@@ -47,7 +47,6 @@
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -135,7 +134,6 @@ static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
 
 static void    MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
 static int     MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
-//static u32   mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
 static int     GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
 static int     GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
 static int     SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
@@ -150,7 +148,6 @@ static int  WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int     WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int     WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int     GetLanConfigPages(MPT_ADAPTER *ioc);
-static int     GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
 static int     GetIoUnitPage2(MPT_ADAPTER *ioc);
 int            mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
 static int     mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
@@ -178,6 +175,7 @@ static int  ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *
 static void    mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
 static void    mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void    mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
+static void    mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
 
 /* module entry point */
 static int  __init    fusion_init  (void);
@@ -209,6 +207,144 @@ pci_enable_io_access(struct pci_dev *pdev)
        pci_write_config_word(pdev, PCI_COMMAND, command_reg);
 }
 
+/*
+ *  Process turbo (context) reply...
+ */
+static void
+mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
+{
+       MPT_FRAME_HDR *mf = NULL;
+       MPT_FRAME_HDR *mr = NULL;
+       int req_idx = 0;
+       int cb_idx;
+
+       dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
+                               ioc->name, pa));
+
+       switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
+       case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
+               req_idx = pa & 0x0000FFFF;
+               cb_idx = (pa & 0x00FF0000) >> 16;
+               mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+               break;
+       case MPI_CONTEXT_REPLY_TYPE_LAN:
+               cb_idx = mpt_lan_index;
+               /*
+                *  Blind set of mf to NULL here was fatal
+                *  after lan_reply says "freeme"
+                *  Fix sort of combined with an optimization here;
+                *  added explicit check for case where lan_reply
+                *  was just returning 1 and doing nothing else.
+                *  For this case skip the callback, but set up
+                *  proper mf value first here:-)
+                */
+               if ((pa & 0x58000000) == 0x58000000) {
+                       req_idx = pa & 0x0000FFFF;
+                       mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+                       mpt_free_msg_frame(ioc, mf);
+                       mb();
+                       return;
+                       break;
+               }
+               mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+               break;
+       case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
+               cb_idx = mpt_stm_index;
+               mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+               break;
+       default:
+               cb_idx = 0;
+               BUG();
+       }
+
+       /*  Check for (valid) IO callback!  */
+       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+                       MptCallbacks[cb_idx] == NULL) {
+               printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
+                               __FUNCTION__, ioc->name, cb_idx);
+               goto out;
+       }
+
+       if (MptCallbacks[cb_idx](ioc, mf, mr))
+               mpt_free_msg_frame(ioc, mf);
+ out:
+       mb();
+}
+
+static void
+mpt_reply(MPT_ADAPTER *ioc, u32 pa)
+{
+       MPT_FRAME_HDR   *mf;
+       MPT_FRAME_HDR   *mr;
+       int              req_idx;
+       int              cb_idx;
+       int              freeme;
+
+       u32 reply_dma_low;
+       u16 ioc_stat;
+
+       /* non-TURBO reply!  Hmmm, something may be up...
+        *  Newest turbo reply mechanism; get address
+        *  via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
+        */
+
+       /* Map DMA address of reply header to cpu address.
+        * pa is 32 bits - but the dma address may be 32 or 64 bits
+        * get offset based only only the low addresses
+        */
+
+       reply_dma_low = (pa <<= 1);
+       mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
+                        (reply_dma_low - ioc->reply_frames_low_dma));
+
+       req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
+       cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
+       mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+
+       dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
+                       ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
+       DBG_DUMP_REPLY_FRAME(mr)
+
+        /*  Check/log IOC log info
+        */
+       ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
+       if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+               u32      log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
+               if (ioc->bus_type == FC)
+                       mpt_fc_log_info(ioc, log_info);
+               else if (ioc->bus_type == SPI)
+                       mpt_sp_log_info(ioc, log_info);
+               else if (ioc->bus_type == SAS)
+                       mpt_sas_log_info(ioc, log_info);
+       }
+       if (ioc_stat & MPI_IOCSTATUS_MASK) {
+               if (ioc->bus_type == SPI &&
+                   cb_idx != mpt_stm_index &&
+                   cb_idx != mpt_lan_index)
+                       mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
+       }
+
+
+       /*  Check for (valid) IO callback!  */
+       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+                       MptCallbacks[cb_idx] == NULL) {
+               printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
+                               __FUNCTION__, ioc->name, cb_idx);
+               freeme = 0;
+               goto out;
+       }
+
+       freeme = MptCallbacks[cb_idx](ioc, mf, mr);
+
+ out:
+       /*  Flush (non-TURBO) reply with a WRITE!  */
+       CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
+
+       if (freeme)
+               mpt_free_msg_frame(ioc, mf);
+       mb();
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
@@ -230,164 +366,21 @@ pci_enable_io_access(struct pci_dev *pdev)
 static irqreturn_t
 mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
 {
-       MPT_ADAPTER     *ioc;
-       MPT_FRAME_HDR   *mf;
-       MPT_FRAME_HDR   *mr;
-       u32              pa;
-       int              req_idx;
-       int              cb_idx;
-       int              type;
-       int              freeme;
-
-       ioc = (MPT_ADAPTER *)bus_id;
+       MPT_ADAPTER *ioc = bus_id;
+       u32 pa;
 
        /*
         *  Drain the reply FIFO!
-        *
-        * NOTES: I've seen up to 10 replies processed in this loop, so far...
-        * Update: I've seen up to 9182 replies processed in this loop! ??
-        * Update: Limit ourselves to processing max of N replies
-        *      (bottom of loop).
         */
        while (1) {
-
-               if ((pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF)
+               pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
+               if (pa == 0xFFFFFFFF)
                        return IRQ_HANDLED;
-
-               cb_idx = 0;
-               freeme = 0;
-
-               /*
-                *  Check for non-TURBO reply!
-                */
-               if (pa & MPI_ADDRESS_REPLY_A_BIT) {
-                       u32 reply_dma_low;
-                       u16 ioc_stat;
-
-                       /* non-TURBO reply!  Hmmm, something may be up...
-                        *  Newest turbo reply mechanism; get address
-                        *  via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
-                        */
-
-                       /* Map DMA address of reply header to cpu address.
-                        * pa is 32 bits - but the dma address may be 32 or 64 bits
-                        * get offset based only only the low addresses
-                        */
-                       reply_dma_low = (pa = (pa << 1));
-                       mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
-                                        (reply_dma_low - ioc->reply_frames_low_dma));
-
-                       req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
-                       cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
-                       mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
-
-                       dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
-                                       ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
-                       DBG_DUMP_REPLY_FRAME(mr)
-
-                        /*  Check/log IOC log info
-                        */
-                       ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
-                       if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
-                               u32      log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
-                               if (ioc->bus_type == FC)
-                                       mpt_fc_log_info(ioc, log_info);
-                               else if (ioc->bus_type == SCSI)
-                                       mpt_sp_log_info(ioc, log_info);
-                       }
-                       if (ioc_stat & MPI_IOCSTATUS_MASK) {
-                               if (ioc->bus_type == SCSI)
-                                       mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
-                       }
-               } else {
-                       /*
-                        *  Process turbo (context) reply...
-                        */
-                       dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n", ioc->name, pa));
-                       type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT);
-                       if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) {
-                               cb_idx = mpt_stm_index;
-                               mf = NULL;
-                               mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
-                       } else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) {
-                               cb_idx = mpt_lan_index;
-                                /*  Blind set of mf to NULL here was fatal
-                                *  after lan_reply says "freeme"
-                                *  Fix sort of combined with an optimization here;
-                                *  added explicit check for case where lan_reply
-                                *  was just returning 1 and doing nothing else.
-                                *  For this case skip the callback, but set up
-                                *  proper mf value first here:-)
-                                */
-                               if ((pa & 0x58000000) == 0x58000000) {
-                                       req_idx = pa & 0x0000FFFF;
-                                       mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
-                                       freeme = 1;
-                                       /*
-                                        *  IMPORTANT!  Invalidate the callback!
-                                        */
-                                       cb_idx = 0;
-                               } else {
-                                       mf = NULL;
-                               }
-                               mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
-                       } else {
-                               req_idx = pa & 0x0000FFFF;
-                               cb_idx = (pa & 0x00FF0000) >> 16;
-                               mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
-                               mr = NULL;
-                       }
-                       pa = 0;                                 /* No reply flush! */
-               }
-
-#ifdef MPT_DEBUG_IRQ
-               if (ioc->bus_type == SCSI) {
-                       /* Verify mf, mr are reasonable.
-                        */
-                       if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
-                               || (mf < ioc->req_frames)) ) {
-                               printk(MYIOC_s_WARN_FMT
-                                       "mpt_interrupt: Invalid mf (%p)!\n", ioc->name, (void *)mf);
-                               cb_idx = 0;
-                               pa = 0;
-                               freeme = 0;
-                       }
-                       if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
-                               || (mr < ioc->reply_frames)) ) {
-                               printk(MYIOC_s_WARN_FMT
-                                       "mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr);
-                               cb_idx = 0;
-                               pa = 0;
-                               freeme = 0;
-                       }
-                       if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) {
-                               printk(MYIOC_s_WARN_FMT
-                                       "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
-                               cb_idx = 0;
-                               pa = 0;
-                               freeme = 0;
-                       }
-               }
-#endif
-
-               /*  Check for (valid) IO callback!  */
-               if (cb_idx) {
-                       /*  Do the callback!  */
-                       freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr);
-               }
-
-               if (pa) {
-                       /*  Flush (non-TURBO) reply with a WRITE!  */
-                       CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
-               }
-
-               if (freeme) {
-                       /*  Put Request back on FreeQ!  */
-                       mpt_free_msg_frame(ioc, mf);
-               }
-
-               mb();
-       }       /* drain reply FIFO */
+               else if (pa & MPI_ADDRESS_REPLY_A_BIT)
+                       mpt_reply(ioc, pa);
+               else
+                       mpt_turbo_reply(ioc, pa);
+       }
 
        return IRQ_HANDLED;
 }
@@ -1065,7 +1058,7 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
                                    ioc->name,
                                    ioc->HostPageBuffer,
                                    ioc->HostPageBuffer_dma,
-                                   hst_page_buffer_sz));
+                                   host_page_buffer_sz));
                                ioc->alloc_total += host_page_buffer_sz;
                                ioc->HostPageBuffer_sz = host_page_buffer_sz;
                                break;
@@ -1124,6 +1117,65 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
        return -1;
 }
 
+int
+mpt_alt_ioc_wait(MPT_ADAPTER *ioc)
+{
+       int loop_count = 30 * 4;  /* Wait 30 seconds */
+       int status = -1; /* -1 means failed to get board READY */
+
+       do {
+               spin_lock(&ioc->initializing_hba_lock);
+               if (ioc->initializing_hba_lock_flag == 0) {
+                       ioc->initializing_hba_lock_flag=1;
+                       spin_unlock(&ioc->initializing_hba_lock);
+                       status = 0;
+                       break;
+               }
+               spin_unlock(&ioc->initializing_hba_lock);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ/4);
+       } while (--loop_count);
+
+       return status;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_bringup_adapter - This is a wrapper function for mpt_do_ioc_recovery
+ *     @ioc: Pointer to MPT adapter structure
+ *     @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
+ *
+ *     This routine performs all the steps necessary to bring the IOC
+ *     to a OPERATIONAL state.
+ *
+ *      Special Note: This function was added with spin lock's so as to allow
+ *      the dv(domain validation) work thread to succeed on the other channel
+ *      that maybe occuring at the same time when this function is called.
+ *      Without this lock, the dv would fail when message frames were
+ *      requested during hba bringup on the alternate ioc.
+ */
+static int
+mpt_bringup_adapter(MPT_ADAPTER *ioc, int sleepFlag)
+{
+       int r;
+
+       if(ioc->alt_ioc) {
+               if((r=mpt_alt_ioc_wait(ioc->alt_ioc)!=0))
+                       return r;
+       }
+
+       r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
+           CAN_SLEEP);
+
+       if(ioc->alt_ioc) {
+               spin_lock(&ioc->alt_ioc->initializing_hba_lock);
+               ioc->alt_ioc->initializing_hba_lock_flag=0;
+               spin_unlock(&ioc->alt_ioc->initializing_hba_lock);
+       }
+
+return r;
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     mpt_attach - Install a PCI intelligent MPT adapter.
@@ -1179,12 +1231,11 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                dprintk((KERN_INFO MYNAM
                        ": Not using 64 bit consistent mask\n"));
 
-       ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
+       ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
        if (ioc == NULL) {
                printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
                return -ENOMEM;
        }
-       memset(ioc, 0, sizeof(MPT_ADAPTER));
        ioc->alloc_total = sizeof(MPT_ADAPTER);
        ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;           /* avoid div by zero! */
        ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
@@ -1192,6 +1243,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        ioc->pcidev = pdev;
        ioc->diagPending = 0;
        spin_lock_init(&ioc->diagLock);
+       spin_lock_init(&ioc->fc_rescan_work_lock);
+       spin_lock_init(&ioc->fc_rport_lock);
+       spin_lock_init(&ioc->initializing_hba_lock);
 
        /* Initialize the event logging.
         */
@@ -1208,12 +1262,16 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* Initilize SCSI Config Data structure
         */
-       memset(&ioc->spi_data, 0, sizeof(ScsiCfgData));
+       memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
 
        /* Initialize the running configQ head.
         */
        INIT_LIST_HEAD(&ioc->configQ);
 
+       /* Initialize the fc rport list head.
+        */
+       INIT_LIST_HEAD(&ioc->fc_rports);
+
        /* Find lookup slot. */
        INIT_LIST_HEAD(&ioc->list);
        ioc->id = mpt_ids++;
@@ -1320,9 +1378,13 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                ioc->bus_type = FC;
                ioc->errata_flag_1064 = 1;
        }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
+               ioc->prod_name = "LSIFC949E";
+               ioc->bus_type = FC;
+       }
        else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
                ioc->prod_name = "LSI53C1030";
-               ioc->bus_type = SCSI;
+               ioc->bus_type = SPI;
                /* 1030 Chip Fix. Disable Split transactions
                 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
                 */
@@ -1335,7 +1397,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        }
        else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
                ioc->prod_name = "LSI53C1035";
-               ioc->bus_type = SCSI;
+               ioc->bus_type = SPI;
        }
        else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
                ioc->prod_name = "LSISAS1064";
@@ -1414,8 +1476,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
         */
        mpt_detect_bound_ports(ioc, pdev);
 
-       if ((r = mpt_do_ioc_recovery(ioc,
-         MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
+       if ((r = mpt_bringup_adapter(ioc, CAN_SLEEP)) != 0){
                printk(KERN_WARNING MYNAM
                  ": WARNING - %s did not initialize properly! (%d)\n",
                  ioc->name, r);
@@ -1569,7 +1630,7 @@ mpt_resume(struct pci_dev *pdev)
        pci_enable_device(pdev);
 
        /* enable interrupts */
-       CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+       CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
        ioc->active = 1;
 
        /* F/W not running */
@@ -1662,7 +1723,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                                /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
                                dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
                                                ioc->alt_ioc->name));
-                               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+                               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
                                ioc->alt_ioc->active = 1;
                        }
 
@@ -1755,15 +1816,30 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                         */
                        if (ret == 0) {
                                rc = mpt_do_upload(ioc, sleepFlag);
-                               if (rc != 0)
+                               if (rc == 0) {
+                                       if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
+                                               /*
+                                                * Maintain only one pointer to FW memory
+                                                * so there will not be two attempt to
+                                                * downloadboot onboard dual function
+                                                * chips (mpt_adapter_disable,
+                                                * mpt_diag_reset)
+                                                */
+                                               ioc->cached_fw = NULL;
+                                               ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload:  alt_%s has cached_fw=%p \n",
+                                                       ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
+                                       }
+                               } else {
                                        printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+                                       ret = -5;
+                               }
                        }
                }
        }
 
        if (ret == 0) {
                /* Enable! (reply interrupt) */
-               CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+               CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
                ioc->active = 1;
        }
 
@@ -1771,7 +1847,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                /* (re)Enable alt-IOC! (reply interrupt) */
                dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
                                ioc->alt_ioc->name));
-               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
                ioc->alt_ioc->active = 1;
        }
 
@@ -1812,7 +1888,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                         *  (FCPortPage0_t stuff)
                         */
                        for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
-                               (void) GetFcPortPage0(ioc, ii);
+                               (void) mptbase_GetFcPortPage0(ioc, ii);
                        }
 
                        if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
@@ -1997,9 +2073,9 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
        }
 
        kfree(ioc->spi_data.nvram);
-       kfree(ioc->spi_data.pIocPg3);
+       kfree(ioc->raid_data.pIocPg3);
        ioc->spi_data.nvram = NULL;
-       ioc->spi_data.pIocPg3 = NULL;
+       ioc->raid_data.pIocPg3 = NULL;
 
        if (ioc->spi_data.pIocPg4 != NULL) {
                sz = ioc->spi_data.IocPg4Sz;
@@ -2694,13 +2770,16 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 
        /* RAID FW may take a long time to enable
         */
-       if ( (ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
-                       > MPI_FW_HEADER_PID_PROD_TARGET_SCSI ) {
-               rc = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
-                               reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag);
+       if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
+           > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
+           (ioc->bus_type == SAS)) {
+               rc = mpt_handshake_req_reply_wait(ioc, req_sz,
+               (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
+               300 /*seconds*/, sleepFlag);
        } else {
-               rc = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
-                               reply_sz, (u16*)&reply_buf, 30 /*seconds*/, sleepFlag);
+               rc = mpt_handshake_req_reply_wait(ioc, req_sz,
+               (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
+               30 /*seconds*/, sleepFlag);
        }
        return rc;
 }
@@ -2974,7 +3053,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
        /* Clear the internal flash bad bit - autoincrementing register,
         * so must do two writes.
         */
-       if (ioc->bus_type == SCSI) {
+       if (ioc->bus_type == SPI) {
                /*
                 * 1030 and 1035 H/W errata, workaround to access
                 * the ClearFlashBadSignatureBit
@@ -3084,7 +3163,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
        int cnt,cntdn;
 
        dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
-       if (ioc->bus_type == SCSI) {
+       if (ioc->bus_type == SPI) {
                /* Always issue a Msg Unit Reset first. This will clear some
                 * SCSI bus hang conditions.
                 */
@@ -3512,7 +3591,7 @@ initChainBuffers(MPT_ADAPTER *ioc)
        dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
                ioc->name, numSGE, num_sge, num_chain));
 
-       if (ioc->bus_type == SCSI)
+       if (ioc->bus_type == SPI)
                num_chain *= MPT_SCSI_CAN_QUEUE;
        else
                num_chain *= MPT_FC_CAN_QUEUE;
@@ -3852,7 +3931,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
        int count = 0;
        u32 intstat=0;
 
-       cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
+       cntdn = 1000 * howlong;
 
        if (sleepFlag == CAN_SLEEP) {
                while (--cntdn) {
@@ -3902,7 +3981,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
        int count = 0;
        u32 intstat=0;
 
-       cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
+       cntdn = 1000 * howlong;
        if (sleepFlag == CAN_SLEEP) {
                while (--cntdn) {
                        intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
@@ -4131,7 +4210,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *     GetFcPortPage0 - Fetch FCPort config Page0.
+ *     mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @portnum: IOC Port number
  *
@@ -4141,8 +4220,8 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
  *             -EAGAIN if no msg frames currently available
  *             -EFAULT for non-successful reply or no reply (timeout)
  */
-static int
-GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
+int
+mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
 {
        ConfigPageHeader_t       hdr;
        CONFIGPARMS              cfg;
@@ -4152,6 +4231,8 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
        int                      data_sz;
        int                      copy_sz;
        int                      rc;
+       int                      count = 400;
+
 
        /* Get FCPort Page 0 header */
        hdr.PageVersion = 0;
@@ -4175,6 +4256,8 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
        rc = -ENOMEM;
        ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
        if (ppage0_alloc) {
+
+ try_again:
                memset((u8 *)ppage0_alloc, 0, data_sz);
                cfg.physAddr = page0_dma;
                cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
@@ -4206,6 +4289,19 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
                        pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
                        pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
 
+                       /*
+                        * if still doing discovery,
+                        * hang loose a while until finished
+                        */
+                       if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
+                               if (count-- > 0) {
+                                       msleep_interruptible(100);
+                                       goto try_again;
+                               }
+                               printk(MYIOC_s_INFO_FMT "Firmware discovery not"
+                                                       " complete.\n",
+                                               ioc->name);
+                       }
                }
 
                pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
@@ -4505,6 +4601,14 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
                                SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t  *) pbuf;
                                MpiDeviceInfo_t *pdevice = NULL;
 
+                               /*
+                                * Save "Set to Avoid SCSI Bus Resets" flag
+                                */
+                               ioc->spi_data.bus_reset =
+                                   (le32_to_cpu(pPP2->PortFlags) &
+                               MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
+                                   0 : 1 ;
+
                                /* Save the Port Page 2 data
                                 * (reformat into a 32bit quantity)
                                 */
@@ -4634,10 +4738,10 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
        if (mpt_config(ioc, &cfg) != 0)
                goto done_and_free;
 
-       if ( (mem = (u8 *)ioc->spi_data.pIocPg2) == NULL ) {
+       if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
                mem = kmalloc(iocpage2sz, GFP_ATOMIC);
                if (mem) {
-                       ioc->spi_data.pIocPg2 = (IOCPage2_t *) mem;
+                       ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
                } else {
                        goto done_and_free;
                }
@@ -4654,7 +4758,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
                /* At least 1 RAID Volume
                 */
                pIocRv = pIoc2->RaidVolume;
-               ioc->spi_data.isRaid = 0;
+               ioc->raid_data.isRaid = 0;
                for (jj = 0; jj < nVols; jj++, pIocRv++) {
                        vid = pIocRv->VolumeID;
                        vbus = pIocRv->VolumeBus;
@@ -4663,7 +4767,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
                        /* find the match
                         */
                        if (vbus == 0) {
-                               ioc->spi_data.isRaid |= (1 << vid);
+                               ioc->raid_data.isRaid |= (1 << vid);
                        } else {
                                /* Error! Always bus 0
                                 */
@@ -4698,8 +4802,8 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
 
        /* Free the old page
         */
-       kfree(ioc->spi_data.pIocPg3);
-       ioc->spi_data.pIocPg3 = NULL;
+       kfree(ioc->raid_data.pIocPg3);
+       ioc->raid_data.pIocPg3 = NULL;
 
        /* There is at least one physical disk.
         * Read and save IOC Page 3
@@ -4736,7 +4840,7 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
                mem = kmalloc(iocpage3sz, GFP_ATOMIC);
                if (mem) {
                        memcpy(mem, (u8 *)pIoc3, iocpage3sz);
-                       ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
+                       ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
                }
        }
 
@@ -6022,6 +6126,111 @@ mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
        printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
 }
 
+/* strings for sas loginfo */
+       static char *originator_str[] = {
+               "IOP",                                          /* 00h */
+               "PL",                                           /* 01h */
+               "IR"                                            /* 02h */
+       };
+       static char *iop_code_str[] = {
+               NULL,                                           /* 00h */
+               "Invalid SAS Address",                          /* 01h */
+               NULL,                                           /* 02h */
+               "Invalid Page",                                 /* 03h */
+               NULL,                                           /* 04h */
+               "Task Terminated"                               /* 05h */
+       };
+       static char *pl_code_str[] = {
+               NULL,                                           /* 00h */
+               "Open Failure",                                 /* 01h */
+               "Invalid Scatter Gather List",                  /* 02h */
+               "Wrong Relative Offset or Frame Length",        /* 03h */
+               "Frame Transfer Error",                         /* 04h */
+               "Transmit Frame Connected Low",                 /* 05h */
+               "SATA Non-NCQ RW Error Bit Set",                /* 06h */
+               "SATA Read Log Receive Data Error",             /* 07h */
+               "SATA NCQ Fail All Commands After Error",       /* 08h */
+               "SATA Error in Receive Set Device Bit FIS",     /* 09h */
+               "Receive Frame Invalid Message",                /* 0Ah */
+               "Receive Context Message Valid Error",          /* 0Bh */
+               "Receive Frame Current Frame Error",            /* 0Ch */
+               "SATA Link Down",                               /* 0Dh */
+               "Discovery SATA Init W IOS",                    /* 0Eh */
+               "Config Invalid Page",                          /* 0Fh */
+               "Discovery SATA Init Timeout",                  /* 10h */
+               "Reset",                                        /* 11h */
+               "Abort",                                        /* 12h */
+               "IO Not Yet Executed",                          /* 13h */
+               "IO Executed",                                  /* 14h */
+               NULL,                                           /* 15h */
+               NULL,                                           /* 16h */
+               NULL,                                           /* 17h */
+               NULL,                                           /* 18h */
+               NULL,                                           /* 19h */
+               NULL,                                           /* 1Ah */
+               NULL,                                           /* 1Bh */
+               NULL,                                           /* 1Ch */
+               NULL,                                           /* 1Dh */
+               NULL,                                           /* 1Eh */
+               NULL,                                           /* 1Fh */
+               "Enclosure Management"                          /* 20h */
+       };
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_sas_log_info - Log information returned from SAS IOC.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @log_info: U32 LogInfo reply word from the IOC
+ *
+ *     Refer to lsi/mpi_log_sas.h.
+ */
+static void
+mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
+{
+union loginfo_type {
+       u32     loginfo;
+       struct {
+               u32     subcode:16;
+               u32     code:8;
+               u32     originator:4;
+               u32     bus_type:4;
+       }dw;
+};
+       union loginfo_type sas_loginfo;
+       char *code_desc = NULL;
+
+       sas_loginfo.loginfo = log_info;
+       if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
+           (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
+               return;
+       if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
+           (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
+               code_desc = iop_code_str[sas_loginfo.dw.code];
+       }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
+           (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
+               code_desc = pl_code_str[sas_loginfo.dw.code];
+       }
+
+       if (code_desc != NULL)
+               printk(MYIOC_s_INFO_FMT
+                       "LogInfo(0x%08x): Originator={%s}, Code={%s},"
+                       " SubCode(0x%04x)\n",
+                       ioc->name,
+                       log_info,
+                       originator_str[sas_loginfo.dw.originator],
+                       code_desc,
+                       sas_loginfo.dw.subcode);
+       else
+               printk(MYIOC_s_INFO_FMT
+                       "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
+                       " SubCode(0x%04x)\n",
+                       ioc->name,
+                       log_info,
+                       originator_str[sas_loginfo.dw.originator],
+                       sas_loginfo.dw.code,
+                       sas_loginfo.dw.subcode);
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
@@ -6184,6 +6393,8 @@ EXPORT_SYMBOL(mpt_read_ioc_pg_3);
 EXPORT_SYMBOL(mpt_alloc_fw_memory);
 EXPORT_SYMBOL(mpt_free_fw_memory);
 EXPORT_SYMBOL(mptbase_sas_persist_operation);
+EXPORT_SYMBOL(mpt_alt_ioc_wait);
+EXPORT_SYMBOL(mptbase_GetFcPortPage0);
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/