]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] Fusion-MPT Update (2.03.01.01)
authorPam Delaney <pdelaney@lsil.com>
Wed, 1 Jan 2003 03:56:26 +0000 (19:56 -0800)
committerChristoph Hellwig <hch@lst.de>
Wed, 1 Jan 2003 03:56:26 +0000 (19:56 -0800)
This upgrades the Fusion-MPT driver from 2.03.00.02 to 2.03.01.01.

Bug Fixes:
 o Added back missing queuecommand entry point define ?!
 o Added to code to break marriage of two controllers during unload
  (could cause a panic)
 o SCSI driver will de-register with base driver if no SCSI-capable
   adapters found

Minor Changes:
 o Removed errant spaces at ends of lines  (most of the changes)
 o Moved code around (and in-lined) some functions for performance reasons.
 o Modified /proc functionality to facilitate testing with 2.5
 o Added a call to synchronize_irq on unload (HP request)
 o Modified load of base to close a potential hole
 o Added code to set the FW IO coalescing depth (IBM request)
 o Changed return when mptctl driver registration fails (Kernel.org request)
 o SCSI driver detect routine calls a generic spinlock for all kernels
   (Kernel.org request)
 o Controller RAID page dynamic instead of static

Currently running a multi-disk stress test w/ 2.5.53,  this patch and driver
built-in. Verified basic reset handling is working properly.

drivers/message/fusion/linux_compat.h
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptctl.h
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptscsih.h

index 99575438c0271f47e65cbe8eee9a7cf450144d59..bb8cb954e3a231e65b33c36e8717f3f39fa7887d 100644 (file)
@@ -246,35 +246,17 @@ static __inline__ int __get_order(unsigned long size)
 #endif
 
 /*
- *  We use our new error handling code if the kernel version is 2.5.1 or newer.
+ *  We use our new error handling code if the kernel version is 2.4.18 or newer.
  */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18)
         #define MPT_SCSI_USE_NEW_EH
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
-#define mptscsih_lock(iocp, flags) \
-                spin_lock_irqsave(&iocp->FreeQlock, flags)
-#else
-#define mptscsih_lock(iocp, flags) \
-({     save_flags(flags); \
-       cli(); \
-})
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
-#define mptscsih_unlock(iocp, flags) \
-                spin_unlock_irqrestore(&iocp->FreeQlock, flags)
-#else
-#define mptscsih_unlock(iocp, flags)  restore_flags(flags);
-#endif
-
-
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
-#define mpt_work_struct work_struct 
+#define mpt_work_struct work_struct
 #define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data)
 #else
-#define mpt_work_struct tq_struct 
+#define mpt_work_struct tq_struct
 #define MPT_INIT_WORK(_task, _func, _data) \
 ({     (_task)->sync = 0; \
        (_task)->routine = (_func); \
@@ -282,6 +264,13 @@ static __inline__ int __get_order(unsigned long size)
 })
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+#define mptscsih_sync_irq(_irq) synchronize_irq(_irq)
+#else
+#define mptscsih_sync_irq(_irq) synchronize_irq()
+#endif
+
+
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
index cb7d91bc07a692c99c9207db926addac623ccecb..16e0b31dc75e912e9dd0c4fe2c6030bedd82d554 100644 (file)
@@ -49,7 +49,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.c,v 1.123 2002/10/17 20:15:56 pdelaney Exp $
+ *  $Id: mptbase.c,v 1.125 2002/12/03 21:26:32 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -208,6 +208,7 @@ static int  GetIoUnitPage2(MPT_ADAPTER *ioc);
 static int     mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
 static int     mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
 static int     mpt_findImVolumes(MPT_ADAPTER *ioc);
+static void    mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
 static void    mpt_timer_expired(unsigned long data);
 static int     SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
 static int     SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
@@ -443,7 +444,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
                         */
                        if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
                                || (mf < ioc->req_frames)) ) {
-                               printk(MYIOC_s_WARN_FMT 
+                               printk(MYIOC_s_WARN_FMT
                                        "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx);
                                cb_idx = 0;
                                pa = 0;
@@ -451,14 +452,14 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
                        }
                        if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
                                || (mr < ioc->reply_frames)) ) {
-                               printk(MYIOC_s_WARN_FMT 
+                               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 
+                               printk(MYIOC_s_WARN_FMT
                                        "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
                                cb_idx = 0;
                                pa = 0;
@@ -576,9 +577,11 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
                CONFIGPARMS *pCfg;
                unsigned long flags;
 
-               dprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
+               dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
                                ioc->name, mf, reply));
 
+               DBG_DUMP_REPLY_FRAME(reply)
+
                pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
 
                if (pCfg) {
@@ -599,7 +602,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
                                u16              status;
 
                                status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-                               dprintk((KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+                               dcprintk((KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
                                     status, le32_to_cpu(pReply->IOCLogInfo)));
 
                                pCfg->status = status;
@@ -943,7 +946,7 @@ mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
  *     mpt_add_sge - Place a simple SGE at address pAddr.
  *     @pAddr: virtual address for SGE
  *     @flagslength: SGE flags and data transfer length
- *     @dma_addr: Physical address 
+ *     @dma_addr: Physical address
  *
  *     This routine places a MPT request frame back on the MPT adapter's
  *     FreeQ.
@@ -973,7 +976,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
  *     @pAddr: virtual address for SGE
  *     @next: nextChainOffset value (u32's)
  *     @length: length of next SGL segment
- *     @dma_addr: Physical address 
+ *     @dma_addr: Physical address
  *
  *     This routine places a MPT request frame back on the MPT adapter's
  *     FreeQ.
@@ -986,7 +989,7 @@ mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
                u32 tmp = dma_addr & 0xFFFFFFFF;
 
                pChain->Length = cpu_to_le16(length);
-               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); 
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
 
                pChain->NextChainOffset = next;
 
@@ -1283,7 +1286,7 @@ mpt_adapter_install(struct pci_dev *pdev)
                return r;
 
        if (!pci_set_dma_mask(pdev, mask)) {
-               dprintk((KERN_INFO MYNAM 
+               dprintk((KERN_INFO MYNAM
                        ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
        } else if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
                printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
@@ -1470,6 +1473,12 @@ mpt_adapter_install(struct pci_dev *pdev)
        ioc->active = 0;
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
+       /* tack onto tail of our MPT adapter list */
+       Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
+
+       /* Set lookup ptr. */
+       mpt_adapters[ioc->id] = ioc;
+
        ioc->pci_irq = -1;
        if (pdev->irq) {
                r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
@@ -1482,6 +1491,8 @@ mpt_adapter_install(struct pci_dev *pdev)
                        printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
                                        ioc->name, __irq_itoa(pdev->irq));
 #endif
+                       Q_DEL_ITEM(ioc);
+                       mpt_adapters[ioc->id] = NULL;
                        iounmap(mem);
                        kfree(ioc);
                        return -EBUSY;
@@ -1498,16 +1509,10 @@ mpt_adapter_install(struct pci_dev *pdev)
 #endif
        }
 
-       /* tack onto tail of our MPT adapter list */
-       Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
-
-       /* Set lookup ptr. */
-       mpt_adapters[ioc->id] = ioc;
-
        /* NEW!  20010220 -sralston
         * Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
         */
-       if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) 
+       if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030)
                        || (ioc->chip_type == C1035) || (ioc->chip_type == FC929X))
                mpt_detect_bound_ports(ioc, pdev);
 
@@ -1638,6 +1643,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                                printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
                        /* Handle the alt IOC too */
                        if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){
+                               ddlprintk((MYIOC_s_INFO_FMT
+                                       "Alt-ioc firmware upload required!\n",
+                                       ioc->name));
                                r = mpt_do_upload(ioc->alt_ioc, sleepFlag);
                                if (r != 0)
                                        printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
@@ -1706,14 +1714,18 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                         */
                        mpt_GetScsiPortSettings(ioc, 0);
 
-                       /* Get version and length of SDP 1 
+                       /* Get version and length of SDP 1
                         */
                        mpt_readScsiDevicePageHeaders(ioc, 0);
 
-                       /* Find IM volumes 
+                       /* Find IM volumes
                         */
                        if (ioc->facts.MsgVersion >= 0x0102)
                                mpt_findImVolumes(ioc);
+
+                       /* Check, and possibly reset, the coalescing value
+                        */
+                       mpt_read_ioc_pg_1(ioc);
                }
 
                GetIoUnitPage2(ioc);
@@ -1819,7 +1831,7 @@ mpt_adapter_disable(MPT_ADAPTER *this, int freeup)
                        ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n"));
 
                        if ((state = mpt_downloadboot(this, NO_SLEEP)) < 0) {
-                               printk(KERN_WARNING MYNAM 
+                               printk(KERN_WARNING MYNAM
                                        ": firmware downloadboot failure (%d)!\n", state);
                        }
                }
@@ -1919,6 +1931,11 @@ mpt_adapter_dispose(MPT_ADAPTER *this)
 
                sz_first = this->alloc_total;
 
+               if (this->alt_ioc != NULL) {
+                       this->alt_ioc->alt_ioc = NULL;
+                       this->alt_ioc = NULL;
+               }
+
                mpt_adapter_disable(this, 1);
 
                if (this->pci_irq != -1) {
@@ -1998,8 +2015,8 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
  *
  *     Returns:
  *              1 - DIAG reset and READY
- *              0 - READY initially OR soft reset and READY 
- *             -1 - Any failure on KickStart 
+ *              0 - READY initially OR soft reset and READY
+ *             -1 - Any failure on KickStart
  *             -2 - Msg Unit Reset Failed
  *             -3 - IO Unit Reset Failed
  *             -4 - IOC owned by a PEER
@@ -2042,7 +2059,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
                        else
                                statefault = 4;
                }
-       } 
+       }
 
        /*
         *      Check to see if IOC is in FAULT state.
@@ -2244,7 +2261,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
                facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
 
                /*
-                * FC f/w version changed between 1.1 and 1.2 
+                * FC f/w version changed between 1.1 and 1.2
                 *      Old: u16{Major(4),Minor(4),SubMinor(8)}
                 *      New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
                 */
@@ -2417,10 +2434,10 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
        if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
                if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw))
                        ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE;
-               else 
+               else
                        ioc->upload_fw = 1;
        }
-       ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n", 
+       ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n",
                   ioc->name, ioc_init.Flags, ioc->upload_fw));
 
        if ((int)ioc->chip_type <= (int)FC929) {
@@ -2554,8 +2571,8 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
  * Outputs: frags - number of fragments needed
  * Return NULL if failed.
  */
-void * 
-mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) 
+void *
+mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
 {
        fw_image_t      **cached_fw = NULL;
        u8              *mem = NULL;
@@ -2564,7 +2581,7 @@ mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
        int             bytes_left, bytes, num_frags;
        int             sz, ii;
 
-       /* cached_fw 
+       /* cached_fw
         */
        sz = ioc->num_fw_frags * sizeof(void *);
        mem = kmalloc(sz, GFP_ATOMIC);
@@ -2721,8 +2738,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
        ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1;
        ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32);
 
-       ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc, 
-                       ioc->facts.FWImageSize, &num_frags, &alloc_sz); 
+       ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc,
+                       ioc->facts.FWImageSize, &num_frags, &alloc_sz);
 
        if (ioc->cached_fw == NULL) {
                /* Major Failure.
@@ -2769,8 +2786,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
                sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
        }
 
-       mpt_add_sge(&request[sgeoffset], 
-                       MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size, 
+       mpt_add_sge(&request[sgeoffset],
+                       MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size,
                        ioc->cached_fw[ii]->fw_dma);
 
        sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
@@ -3117,8 +3134,8 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
  *              0 - no reset due to History bit, READY 
  *             -1 - no reset due to History bit but not READY  
  *                  OR reset but failed to come READY
- *             -2 - no reset, could not enter DIAG mode 
- *             -3 - reset but bad FW bit 
+ *             -2 - no reset, could not enter DIAG mode
+ *             -3 - reset but bad FW bit
  */
 static int
 KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
@@ -3254,18 +3271,14 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                                ioc->name, diag0val, diag1val));
 #endif
                /* Write the PreventIocBoot bit */
-#if 1
                if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
-#else
-               if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
-#endif
                        diag0val |= MPI_DIAG_PREVENT_IOC_BOOT;
                        CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
                }
 
                /*
                 * Disable the ARM (Bug fix)
-                * 
+                *
                 */
                CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
                mdelay (1);
@@ -3304,11 +3317,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                        /* FIXME?  Examine results here? */
                }
 
-#if 1
                if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
-#else
-               if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
-#endif
                        /* If the DownloadBoot operation fails, the
                         * IOC will be left unusable. This is a fatal error
                         * case.  _diag_reset will return < 0
@@ -3318,7 +3327,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
 #ifdef MPT_DEBUG
                                if (ioc->alt_ioc)
                                        diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-                               dprintk((MYIOC_s_INFO_FMT 
+                               dprintk((MYIOC_s_INFO_FMT
                                        "DbG2b: diag0=%08x, diag1=%08x\n",
                                        ioc->name, diag0val, diag1val));
 #endif
@@ -3335,7 +3344,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                                }
                        }
                        if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
-                               printk(KERN_WARNING MYNAM 
+                               printk(KERN_WARNING MYNAM
                                        ": firmware downloadboot failure (%d)!\n", count);
                        }
 
@@ -3467,7 +3476,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
        if ((r = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
                return r;
 
-       /* FW ACK'd request, wait for READY state 
+       /* FW ACK'd request, wait for READY state
         */
        cntdn = HZ * 15;
        count = 0;
@@ -3631,6 +3640,9 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
        }
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
+#ifdef MFCNT
+       ioc->mfcnt = 0;
+#endif
 
        if (ioc->sense_buf_pool == NULL) {
                sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
@@ -4267,7 +4279,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
        int                      ii;
        int                      data, rc = 0;
 
-       /* Allocate memory 
+       /* Allocate memory
         */
        if (!ioc->spi_data.nvram) {
                int      sz;
@@ -4446,12 +4458,17 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
        ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
        ioc->spi_data.sdp0length = cfg.hdr->PageLength;
 
+       dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
+                       ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
+
+       dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
+                       ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
        return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes 
+ *     mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
  *     @ioc: Pointer to a Adapter Strucutre
  *     @portnum: IOC port number
  *
@@ -4464,17 +4481,13 @@ static int
 mpt_findImVolumes(MPT_ADAPTER *ioc)
 {
        IOCPage2_t              *pIoc2 = NULL;
-       IOCPage3_t              *pIoc3 = NULL;
        ConfigPageIoc2RaidVol_t *pIocRv = NULL;
-       u8                      *mem;
        dma_addr_t               ioc2_dma;
-       dma_addr_t               ioc3_dma;
        CONFIGPARMS              cfg;
        ConfigPageHeader_t       header;
        int                      jj;
        int                      rc = 0;
        int                      iocpage2sz;
-       int                      iocpage3sz = 0;
        u8                       nVols, nPhys;
        u8                       vid, vbus, vioc;
 
@@ -4541,44 +4554,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
                /* No physical disks. Done.
                 */
        } else {
-               /* There is at least one physical disk.
-                * Read and save IOC Page 3
-                */
-               header.PageVersion = 0;
-               header.PageLength = 0;
-               header.PageNumber = 3;
-               header.PageType = MPI_CONFIG_PAGETYPE_IOC;
-               cfg.hdr = &header;
-               cfg.physAddr = -1;
-               cfg.pageAddr = 0;
-               cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
-               cfg.dir = 0;
-               cfg.timeout = 0;
-               if (mpt_config(ioc, &cfg) != 0)
-                       goto done_and_free;
-
-               if (header.PageLength == 0)
-                       goto done_and_free;
-
-               /* Read Header good, alloc memory
-                */
-               iocpage3sz = header.PageLength * 4;
-               pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
-               if (!pIoc3)
-                       goto done_and_free;
-
-               /* Read the Page and save the data
-                * into malloc'd memory.
-                */
-               cfg.physAddr = ioc3_dma;
-               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
-               if (mpt_config(ioc, &cfg) == 0) {
-                       mem = kmalloc(iocpage3sz, GFP_ATOMIC);
-                       if (mem) {
-                               memcpy(mem, (u8 *)pIoc3, iocpage3sz);
-                               ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
-                       }
-               }
+               mpt_read_ioc_pg_3(ioc);
        }
 
 done_and_free:
@@ -4587,14 +4563,159 @@ done_and_free:
                pIoc2 = NULL;
        }
 
+       return rc;
+}
+
+int
+mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
+{
+       IOCPage3_t              *pIoc3 = NULL;
+       u8                      *mem;
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+       dma_addr_t               ioc3_dma;
+       int                      iocpage3sz = 0;
+
+       /* Free the old page
+        */
+       if (ioc->spi_data.pIocPg3) {
+               kfree(ioc->spi_data.pIocPg3);
+               ioc->spi_data.pIocPg3 = NULL;
+       }
+
+       /* There is at least one physical disk.
+        * Read and save IOC Page 3
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 3;
+       header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+               return 0;
+
+       if (header.PageLength == 0)
+               return 0;
+
+       /* Read Header good, alloc memory
+        */
+       iocpage3sz = header.PageLength * 4;
+       pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
+       if (!pIoc3)
+               return 0;
+
+       /* Read the Page and save the data
+        * into malloc'd memory.
+        */
+       cfg.physAddr = ioc3_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       if (mpt_config(ioc, &cfg) == 0) {
+               mem = kmalloc(iocpage3sz, GFP_ATOMIC);
+               if (mem) {
+                       memcpy(mem, (u8 *)pIoc3, iocpage3sz);
+                       ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
+               }
+       }
+
        if (pIoc3) {
                pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
                pIoc3 = NULL;
        }
 
-       return rc;
+       return 0;
 }
 
+static void
+mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
+{
+       IOCPage1_t              *pIoc1 = NULL;
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+       dma_addr_t               ioc1_dma;
+       int                      iocpage1sz = 0;
+       u32                      tmp;
+
+       /* Check the Coalescing Timeout in IOC Page 1
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 1;
+       header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+               return;
+
+       if (header.PageLength == 0)
+               return;
+
+       /* Read Header good, alloc memory
+        */
+       iocpage1sz = header.PageLength * 4;
+       pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
+       if (!pIoc1)
+               return;
+
+       /* Read the Page and check coalescing timeout
+        */
+       cfg.physAddr = ioc1_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       if (mpt_config(ioc, &cfg) == 0) {
+               
+               tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
+               if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
+                       tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
+
+                       dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
+                                       ioc->name, tmp));
+
+                       if (tmp > MPT_COALESCING_TIMEOUT) {
+                               pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
+
+                               /* Write NVRAM and current
+                                */
+                               cfg.dir = 1;
+                               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+                               if (mpt_config(ioc, &cfg) == 0) {
+                                       dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
+                                                       ioc->name, MPT_COALESCING_TIMEOUT));
+
+                                       cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+                                       if (mpt_config(ioc, &cfg) == 0) {
+                                               dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
+                                                               ioc->name, MPT_COALESCING_TIMEOUT));
+                                       } else {
+                                               dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
+                                                                       ioc->name));
+                                       }
+
+                               } else {
+                                       dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
+                                                               ioc->name));
+                               }
+                       }
+
+               } else {
+                       dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
+               }
+       }
+
+       if (pIoc1) {
+               pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
+               pIoc1 = NULL;
+       }
+
+       return;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -4690,7 +4811,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
         */
        in_isr = in_interrupt();
        if (in_isr) {
-               dprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
+               dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
                                ioc->name));
                return -EPERM;
        }
@@ -4698,7 +4819,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
        /* Get and Populate a free Frame
         */
        if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
-               dprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
+               dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
                                ioc->name));
                return -EAGAIN;
        }
@@ -4731,7 +4852,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
 
        mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
 
-       dprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+       dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
                ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
 
        /* Append pCfg pointer to end of mf
@@ -4778,7 +4899,7 @@ mpt_timer_expired(unsigned long data)
 {
        MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
 
-       dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
+       dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
 
        /* Perform a FW reload */
        if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
@@ -4788,7 +4909,7 @@ mpt_timer_expired(unsigned long data)
         * Hard reset clean-up will wake up
         * process and free all resources.
         */
-       dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
+       dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
 
        return;
 }
@@ -4829,7 +4950,7 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
        } else {
                CONFIGPARMS *pNext;
 
-               /* Search the configQ for internal commands. 
+               /* Search the configQ for internal commands.
                 * Flush the Q, and wake up all suspended threads.
                 */
 #if 1
@@ -5096,8 +5217,7 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo
                         */
                        if (isense_idx == ii)
                                len += sprintf(buf+len, "  Fusion MPT isense driver\n");
-               } else
-                       break;
+               }
        }
 
        MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
@@ -5774,6 +5894,7 @@ EXPORT_SYMBOL(mpt_lan_index);
 EXPORT_SYMBOL(mpt_stm_index);
 EXPORT_SYMBOL(mpt_HardResetHandler);
 EXPORT_SYMBOL(mpt_config);
+EXPORT_SYMBOL(mpt_read_ioc_pg_3);
 EXPORT_SYMBOL(mpt_alloc_fw_memory);
 EXPORT_SYMBOL(mpt_free_fw_memory);
 
@@ -5843,6 +5964,7 @@ static void
 fusion_exit(void)
 {
        MPT_ADAPTER *this;
+       struct pci_dev *pdev = NULL;
 
        dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
 
@@ -5861,9 +5983,14 @@ fusion_exit(void)
 
                this->active = 0;
 
+               pdev = (struct pci_dev *)this->pcidev;
+               mptscsih_sync_irq(pdev->irq);
+
                /* Clear any lingering interrupt */
                CHIPREG_WRITE32(&this->chip->IntStatus, 0);
 
+               CHIPREG_READ32(&this->chip->IntStatus);
+
                Q_DEL_ITEM(this);
                mpt_adapter_dispose(this);
        }
index c992a7f703795bcb5f0f6cc14bf01789337fee74..916b3b299e3dbceb0d857a8663d15f130301458d 100644 (file)
@@ -13,7 +13,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.h,v 1.136 2002/10/21 13:51:54 pdelaney Exp $
+ *  $Id: mptbase.h,v 1.141 2002/12/03 21:26:32 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -80,8 +80,8 @@
 #define COPYRIGHT      "Copyright (c) 1999-2002 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "2.03.00.02"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-2.03.00.02"
+#define MPT_LINUX_VERSION_COMMON       "2.03.01.01"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-2.03.01.01"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
 #define         CAN_SLEEP                      1
 #define  NO_SLEEP                      0
 
-/* 
- * SCSI transfer rate defines. 
+#define MPT_COALESCING_TIMEOUT         0x10
+
+/*
+ * SCSI transfer rate defines.
  */
 #define MPT_ULTRA320                   0x08
 #define MPT_ULTRA160                   0x09
@@ -524,7 +526,7 @@ typedef struct _mpt_ioctl_events {
 #define MPT_SCSICFG_DV_PENDING         0x04    /* DV on this physical id pending */
 #define MPT_SCSICFG_DV_NOT_DONE                0x08    /* DV has not been performed */
 #define MPT_SCSICFG_BLK_NEGO           0x10    /* WriteSDP1 with WDTR and SDTR disabled */
-
+#define MPT_SCSICFG_RELOAD_IOC_PG3     0x20    /* IOC Pg 3 data is obsolete */
                                                /* Args passed to writeSDP1: */
 #define MPT_SCSICFG_USE_NVRAM          0x01    /* WriteSDP1 using NVRAM */
 #define MPT_SCSICFG_ALL_IDS            0x02    /* WriteSDP1 to all IDS */
@@ -756,6 +758,12 @@ typedef struct _mpt_sge {
 #define nehprintk(x)
 #endif
 
+#if defined(MPT_DEBUG_CONFIG) || defined(MPT_DEBUG)
+#define dcprintk(x) printk x
+#else
+#define dcprintk(x)
+#endif
+
 #define MPT_INDEX_2_MFPTR(ioc,idx) \
        (MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
 
@@ -1009,6 +1017,7 @@ extern int         mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 extern int      mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
 extern void    *mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz);
 extern void     mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img);
+extern int      mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
 
 /*
  *  Public data decl's...
index 445afed79fd9f0bc4d0b26124d30cfc6fc0fb658..37b5799fd184b2a2f90f25eebe4a24355125d683 100644 (file)
@@ -34,7 +34,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.c,v 1.61 2002/10/17 20:15:57 pdelaney Exp $
+ *  $Id: mptctl.c,v 1.63 2002/12/03 21:26:33 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -2911,9 +2911,9 @@ int __init mptctl_init(void)
 #endif         /*} sparc */
 
        /* Register this device */
-       if (misc_register(&mptctl_miscdev) == -1) {
+       err = misc_register(&mptctl_miscdev);
+       if (err < 0) {
                printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
-               err = -EBUSY;
                goto out_fail;
        }
        printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
index 444a5009c9babb8da2cd77e461ceba6669ca0481..e7fedd5d38cbc77246e4b71dc75e126b8dfedf91 100644 (file)
@@ -20,7 +20,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.h,v 1.12 2002/10/17 20:15:58 pdelaney Exp $
+ *  $Id: mptctl.h,v 1.13 2002/12/03 21:26:33 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
index 57faa74cba29a0e0eacf684544fa967c9a44f9d4..965c1bb9636da699901391e5c0c884b83d03d317 100644 (file)
@@ -26,7 +26,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.103 2002/10/17 20:15:59 pdelaney Exp $
+ *  $Id: mptscsih.c,v 1.104 2002/12/03 21:26:34 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -159,11 +159,9 @@ typedef struct _dv_parameters {
 static int     mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static void    mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
 static int     mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
-static int     mptscsih_io_direction(Scsi_Cmnd *cmd);
 
 static int     mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
                                 SCSIIORequest_t *pReq, int req_idx);
-static int     mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex);
 static void    mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
 static int     mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
 static void    copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
@@ -274,180 +272,609 @@ static struct mptscsih_driver_setup
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *     mptscsih_io_done - Main SCSI IO callback routine registered to
- *     Fusion MPT (base) driver
- *     @ioc: Pointer to MPT_ADAPTER structure
- *     @mf: Pointer to original MPT request frame
- *     @r: Pointer to MPT reply frame (NULL if TurboReply)
+ *  Private inline routines...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 19991030 -sralston
+ *  Return absolute SCSI data direction:
+ *     1 = _DATA_OUT
+ *     0 = _DIR_NONE
+ *    -1 = _DATA_IN
  *
- *     This routine is called from mpt.c::mpt_interrupt() at the completion
- *     of any SCSI IO request.
- *     This routine is registered with the Fusion MPT (base) driver at driver
- *     load/init time via the mpt_register() API call.
+ * Changed: 3-20-2002 pdelaney to use the default data
+ * direction and the defines set up in the
+ * 2.4 kernel series
+ *     1 = _DATA_OUT   changed to SCSI_DATA_WRITE (1)
+ *     0 = _DIR_NONE   changed to SCSI_DATA_NONE (3)
+ *    -1 = _DATA_IN    changed to SCSI_DATA_READ (2)
+ * If the direction is unknown, fall through to original code.
  *
- *     Returns 1 indicating alloc'd request frame ptr should be freed.
+ * Mid-layer bug fix(): sg interface generates the wrong data
+ * direction in some cases. Set the direction the hard way for
+ * the most common commands.
  */
-static int
-mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+static inline int
+mptscsih_io_direction(Scsi_Cmnd *cmd)
 {
-       Scsi_Cmnd       *sc;
-       MPT_SCSI_HOST   *hd;
-       SCSIIORequest_t *pScsiReq;
-       SCSIIOReply_t   *pScsiReply;
-#ifndef MPT_SCSI_USE_NEW_EH
-       unsigned long    flags;
-#endif
-       u16              req_idx;
-
-       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
-
-       if ((mf == NULL) ||
-           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
-               printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
-                               ioc->name, mf?"BAD":"NULL", (void *) mf);
-               /* return 1; CHECKME SteveR. Don't free. */
-               return 0;
+       switch (cmd->cmnd[0]) {
+       case WRITE_6:           
+       case WRITE_10:          
+               return SCSI_DATA_WRITE;
+               break;
+       case READ_6:            
+       case READ_10:           
+               return SCSI_DATA_READ;
+               break;
        }
 
-       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
-       sc = hd->ScsiLookup[req_idx];
-       if (sc == NULL) {
-               MPIHeader_t *hdr = (MPIHeader_t *)mf;
-
-               atomic_dec(&queue_depth);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN)
+               return cmd->sc_data_direction;
+#endif
+       switch (cmd->cmnd[0]) {
+       /*  _DATA_OUT commands  */
+       case WRITE_6:           case WRITE_10:          case WRITE_12:
+       case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
+       case WRITE_VERIFY:      case WRITE_VERIFY_12:
+       case COMPARE:           case COPY:              case COPY_VERIFY:
+       case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
+       case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:
+       case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
+       case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
+       case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
+       case REASSIGN_BLOCKS:
+       case PERSISTENT_RESERVE_OUT:
+       case 0xea:
+       case 0xa3:
+               return SCSI_DATA_WRITE;
 
-               /* writeSDP1 will use the ScsiDoneCtx
-                * There is no processing for the reply.
-                * Just return to the calling function.
-                */
-               if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
-                       printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);
+       /*  No data transfer commands  */
+       case SEEK_6:            case SEEK_10:
+       case RESERVE:           case RELEASE:
+       case TEST_UNIT_READY:
+       case START_STOP:
+       case ALLOW_MEDIUM_REMOVAL:
+               return SCSI_DATA_NONE;
 
-               mptscsih_freeChainBuffers(hd, req_idx);
-               return 1;
-       }
+       /*  Conditional data transfer commands  */
+       case FORMAT_UNIT:
+               if (cmd->cmnd[1] & 0x10)        /* FmtData (data out phase)? */
+                       return SCSI_DATA_WRITE;
+               else
+                       return SCSI_DATA_NONE;
 
-       dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
-                       ioc->name, mf, mr, sc, req_idx));
+       case VERIFY:
+               if (cmd->cmnd[1] & 0x02)        /* VERIFY:BYTCHK (data out phase)? */
+                       return SCSI_DATA_WRITE;
+               else
+                       return SCSI_DATA_NONE;
 
-       atomic_dec(&queue_depth);
+       case RESERVE_10:
+               if (cmd->cmnd[1] & 0x03)        /* RESERVE:{LongID|Extent} (data out phase)? */
+                       return SCSI_DATA_WRITE;
+               else
+                       return SCSI_DATA_NONE;
 
-       sc->result = DID_OK << 16;              /* Set default reply as OK */
-       pScsiReq = (SCSIIORequest_t *) mf;
-       pScsiReply = (SCSIIOReply_t *) mr;
+       /*  Must be data _IN!  */
+       default:
+               return SCSI_DATA_READ;
+       }
+} /* mptscsih_io_direction() */
 
-       if (pScsiReply == NULL) {
-               /* special context reply handling */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_add_sge - Place a simple SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @flagslength: SGE flags and data transfer length
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+static inline void
+mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+               u32 tmp = dma_addr & 0xFFFFFFFF;
 
-               /* If regular Inquiry cmd - save inquiry data
-                */
-               if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {
-                       int      dlen;
+               pSge->FlagsLength = cpu_to_le32(flagslength);
+               pSge->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32) ((u64)dma_addr >> 32);
+               pSge->Address.High = cpu_to_le32(tmp);
 
-                       dlen = le32_to_cpu(pScsiReq->DataLength);
-                       if (dlen >= SCSI_STD_INQUIRY_BYTES) {
-                               mptscsih_initTarget(hd,
-                                               hd->port,
-                                               sc->target,
-                                               pScsiReq->LUN[1],
-                                               sc->buffer,
-                                               dlen);
-                       }
-               }
-#ifdef MPT_SAVE_AUTOSENSE
-               clear_sense_flag(hd, pScsiReq);
-#endif
        } else {
-               u32      xfer_cnt;
-               u16      status;
-               u8       scsi_state;
+               SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+               pSge->FlagsLength = cpu_to_le32(flagslength);
+               pSge->Address = cpu_to_le32(dma_addr);
+       }
+} /* mptscsih_add_sge() */
 
-               status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-               scsi_state = pScsiReply->SCSIState;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_add_chain - Place a chain SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @next: nextChainOffset value (u32's)
+ *     @length: length of next SGL segment
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+static inline void
+mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
+               u32 tmp = dma_addr & 0xFFFFFFFF;
 
-               dprintk((KERN_NOTICE "  Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
-                               ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
-                               mf, mr, sc));
-               dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"
-                               ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
-                               status, scsi_state, pScsiReply->SCSIStatus,
-                               le32_to_cpu(pScsiReply->IOCLogInfo)));
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
 
-               if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
-                       copy_sense_data(sc, hd, mf, pScsiReply);
+               pChain->NextChainOffset = next;
 
-               /*
-                *  Look for + dump FCP ResponseInfo[]!
-                */
-               if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
-                       dprintk((KERN_NOTICE "  FCP_ResponseInfo=%08xh\n",
-                                            le32_to_cpu(pScsiReply->ResponseInfo)));
-               }
+               pChain->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32) ((u64)dma_addr >> 32);
+               pChain->Address.High = cpu_to_le32(tmp);
+       } else {
+               SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+               pChain->NextChainOffset = next;
+               pChain->Address = cpu_to_le32(dma_addr);
+       }
+} /* mptscsih_add_chain() */
 
-               switch(status) {
-               case MPI_IOCSTATUS_BUSY:                        /* 0x0002 */
-                       /* CHECKME!
-                        * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
-                        * But not: DID_BUS_BUSY lest one risk
-                        * killing interrupt handler:-(
-                        */
-                       sc->result = STS_BUSY;
-                       break;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_getFreeChainBuffes - Function to get a free chain
+ *     from the MPT_SCSI_HOST FreeChainQ.
+ *     @hd: Pointer to the MPT_SCSI_HOST instance
+ *     @req_idx: Index of the SCSI IO request frame. (output)
+ *
+ *     return SUCCESS or FAILED
+ */
+static inline int
+mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
+{
+       MPT_FRAME_HDR *chainBuf = NULL;
+       unsigned long flags;
+       int rc = FAILED;
+       int chain_idx = MPT_HOST_NO_CHAIN;
 
-               case MPI_IOCSTATUS_SCSI_INVALID_BUS:            /* 0x0041 */
-               case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:       /* 0x0042 */
-                       sc->result = DID_BAD_TARGET << 16;
-                       break;
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
 
-               case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
-                       /* Spoof to SCSI Selection Timeout! */
-                       sc->result = DID_NO_CONNECT << 16;
+               int offset;
 
-                       if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
-                               hd->sel_timeout[pScsiReq->TargetID]++;
-                       break;
+               chainBuf = hd->FreeChainQ.head;
+               Q_DEL_ITEM(&chainBuf->u.frame.linkage);
+               offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer;
+               chain_idx = offset / hd->ioc->req_sz;
+               rc = SUCCESS;
+       }
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
-               case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
-#ifndef MPT_SCSI_USE_NEW_EH
-                       search_taskQ_for_cmd(sc, hd);
-#endif
-                       /* Linux handles an unsolicited DID_RESET better 
-                        * than an unsolicited DID_ABORT.
-                        */
-                       sc->result = DID_RESET << 16;
 
-                       /* GEM Workaround. */ 
-                       if (hd->is_spi)
-                               mptscsih_no_negotiate(hd, sc->target);
-                       break;
+       *retIndex = chain_idx;
 
-               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
-               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
-#ifndef MPT_SCSI_USE_NEW_EH
-                       search_taskQ_for_cmd(sc, hd);
-#endif
-                       sc->result = DID_RESET << 16;
+       dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
+                       hd->ioc->name, *retIndex, chainBuf));
 
-                       /* GEM Workaround. */ 
-                       if (hd->is_spi)
-                               mptscsih_no_negotiate(hd, sc->target);
-                       break;
+       return rc;
+} /* mptscsih_getFreeChainBuffer() */
 
-               case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:      /* 0x0049 */
-               case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
-                       /*
-                        *  YIKES!  I just discovered that SCSI IO which
-                        *  returns check condition, SenseKey=05 (ILLEGAL REQUEST)
-                        *  and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
-                        *  comes down this path!
-                        *  Do upfront check for valid SenseData and give it
-                        *  precedence!
-                        */
-                       sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
-#ifdef MPT_SAVE_AUTOSENSE
-                       clear_sense_flag(hd, pScsiReq);
-#endif
-                       if (scsi_state == 0) {
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
+ *     SCSIIORequest_t Message Frame.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @SCpnt: Pointer to Scsi_Cmnd structure
+ *     @pReq: Pointer to SCSIIORequest_t structure
+ *
+ *     Returns ...
+ */
+static int
+mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
+               SCSIIORequest_t *pReq, int req_idx)
+{
+       char    *psge;
+       char    *chainSge;
+       struct scatterlist *sg;
+       int      frm_sz;
+       int      sges_left, sg_done;
+       int      chain_idx = MPT_HOST_NO_CHAIN;
+       int      sgeOffset;
+       int      numSgeSlots, numSgeThisFrame;
+       u32      sgflags, sgdir, thisxfer = 0;
+       int      chain_dma_off = 0;
+       int      newIndex;
+       int      ii;
+       dma_addr_t v2;
+
+       sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
+       if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {
+               sgdir = MPT_TRANSFER_HOST_TO_IOC;
+       } else {
+               sgdir = MPT_TRANSFER_IOC_TO_HOST;
+       }
+
+       psge = (char *) &pReq->SGL;
+       frm_sz = hd->ioc->req_sz;
+
+       /* Map the data portion, if any.
+        * sges_left  = 0 if no data transfer.
+        */
+       sges_left = SCpnt->use_sg;
+       if (SCpnt->use_sg) {
+               sges_left = pci_map_sg(hd->ioc->pcidev,
+                              (struct scatterlist *) SCpnt->request_buffer,
+                              SCpnt->use_sg,
+                              scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+       } else if (SCpnt->request_bufflen) {
+               dma_addr_t       buf_dma_addr;
+               scPrivate       *my_priv;
+
+               buf_dma_addr = pci_map_single(hd->ioc->pcidev,
+                                     SCpnt->request_buffer,
+                                     SCpnt->request_bufflen,
+                                     scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+
+               /* We hide it here for later unmap. */
+               my_priv = (scPrivate *) &SCpnt->SCp;
+               my_priv->p1 = (void *)(ulong) buf_dma_addr;
+
+               dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
+                               hd->ioc->name, SCpnt, SCpnt->request_bufflen));
+
+               mptscsih_add_sge((char *) &pReq->SGL,
+                       0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
+                       buf_dma_addr);
+
+               return SUCCESS;
+       }
+
+       /* Handle the SG case.
+        */
+       sg = (struct scatterlist *) SCpnt->request_buffer;
+       sg_done  = 0;
+       sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
+       chainSge = NULL;
+
+       /* Prior to entering this loop - the following must be set
+        * current MF:  sgeOffset (bytes)
+        *              chainSge (Null if original MF is not a chain buffer)
+        *              sg_done (num SGE done for this MF)
+        */
+
+nextSGEset:
+       numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
+       numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
+
+       sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
+
+       /* Get first (num - 1) SG elements
+        * Skip any SG entries with a length of 0
+        * NOTE: at finish, sg and psge pointed to NEXT data/location positions
+        */
+       for (ii=0; ii < (numSgeThisFrame-1); ii++) {
+               thisxfer = sg_dma_len(sg);
+               if (thisxfer == 0) {
+                       sg ++; /* Get next SG element from the OS */
+                       sg_done++;
+                       continue;
+               }
+
+               v2 = sg_dma_address(sg);
+               mptscsih_add_sge(psge, sgflags | thisxfer, v2);
+
+               sg++;           /* Get next SG element from the OS */
+               psge += (sizeof(u32) + sizeof(dma_addr_t));
+               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               sg_done++;
+       }
+
+       if (numSgeThisFrame == sges_left) {
+               /* Add last element, end of buffer and end of list flags.
+                */
+               sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
+                               MPT_SGE_FLAGS_END_OF_BUFFER |
+                               MPT_SGE_FLAGS_END_OF_LIST;
+
+               /* Add last SGE and set termination flags.
+                * Note: Last SGE may have a length of 0 - which should be ok.
+                */
+               thisxfer = sg_dma_len(sg);
+
+               v2 = sg_dma_address(sg);
+               mptscsih_add_sge(psge, sgflags | thisxfer, v2);
+               /*
+               sg++;
+               psge += (sizeof(u32) + sizeof(dma_addr_t));
+               */
+               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               sg_done++;
+
+               if (chainSge) {
+                       /* The current buffer is a chain buffer,
+                        * but there is not another one.
+                        * Update the chain element
+                        * Offset and Length fields.
+                        */
+                       mptscsih_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
+               } else {
+                       /* The current buffer is the original MF
+                        * and there is no Chain buffer.
+                        */
+                       pReq->ChainOffset = 0;
+               }
+       } else {
+               /* At least one chain buffer is needed.
+                * Complete the first MF
+                *  - last SGE element, set the LastElement bit
+                *  - set ChainOffset (words) for orig MF
+                *             (OR finish previous MF chain buffer)
+                *  - update MFStructPtr ChainIndex
+                *  - Populate chain element
+                * Also
+                * Loop until done.
+                */
+
+               dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
+                               hd->ioc->name, sg_done));
+
+               /* Set LAST_ELEMENT flag for last non-chain element
+                * in the buffer. Since psge points at the NEXT
+                * SGE element, go back one SGE element, update the flags
+                * and reset the pointer. (Note: sgflags & thisxfer are already
+                * set properly).
+                */
+               if (sg_done) {
+                       u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
+                       sgflags = le32_to_cpu(*ptmp);
+                       sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
+                       *ptmp = cpu_to_le32(sgflags);
+               }
+
+               if (chainSge) {
+                       /* The current buffer is a chain buffer.
+                        * chainSge points to the previous Chain Element.
+                        * Update its chain element Offset and Length (must
+                        * include chain element size) fields.
+                        * Old chain element is now complete.
+                        */
+                       u8 nextChain = (u8) (sgeOffset >> 2);
+                       sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+                       mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
+               } else {
+                       /* The original MF buffer requires a chain buffer -
+                        * set the offset.
+                        * Last element in this MF is a chain element.
+                        */
+                       pReq->ChainOffset = (u8) (sgeOffset >> 2);
+               }
+
+               sges_left -= sg_done;
+
+
+               /* NOTE: psge points to the beginning of the chain element
+                * in current buffer. Get a chain buffer.
+                */
+               if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)
+                       return FAILED;
+
+               /* Update the tracking arrays.
+                * If chainSge == NULL, update ReqToChain, else ChainToChain
+                */
+               if (chainSge) {
+                       hd->ChainToChain[chain_idx] = newIndex;
+               } else {
+                       hd->ReqToChain[req_idx] = newIndex;
+               }
+               chain_idx = newIndex;
+               chain_dma_off = hd->ioc->req_sz * chain_idx;
+
+               /* Populate the chainSGE for the current buffer.
+                * - Set chain buffer pointer to psge and fill
+                *   out the Address and Flags fields.
+                */
+               chainSge = (char *) psge;
+               dsgprintk((KERN_INFO "  Current buff @ %p (index 0x%x)",
+                               psge, req_idx));
+
+               /* Start the SGE for the next buffer
+                */
+               psge = (char *) (hd->ChainBuffer + chain_dma_off);
+               sgeOffset = 0;
+               sg_done = 0;
+
+               dsgprintk((KERN_INFO "  Chain buff @ %p (index 0x%x)\n",
+                               psge, chain_idx));
+
+               /* Start the SGE for the next buffer
+                */
+
+               goto nextSGEset;
+       }
+
+       return SUCCESS;
+} /* mptscsih_AddSGE() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_io_done - Main SCSI IO callback routine registered to
+ *     Fusion MPT (base) driver
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to original MPT request frame
+ *     @r: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ *     This routine is called from mpt.c::mpt_interrupt() at the completion
+ *     of any SCSI IO request.
+ *     This routine is registered with the Fusion MPT (base) driver at driver
+ *     load/init time via the mpt_register() API call.
+ *
+ *     Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+       Scsi_Cmnd       *sc;
+       MPT_SCSI_HOST   *hd;
+       SCSIIORequest_t *pScsiReq;
+       SCSIIOReply_t   *pScsiReply;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+       unsigned long    flags;
+#endif
+       u16              req_idx;
+
+       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+       if ((mf == NULL) ||
+           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+               printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
+                               ioc->name, mf?"BAD":"NULL", (void *) mf);
+               return 0;
+       }
+
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       sc = hd->ScsiLookup[req_idx];
+       if (sc == NULL) {
+               MPIHeader_t *hdr = (MPIHeader_t *)mf;
+
+               atomic_dec(&queue_depth);
+
+               /* writeSDP1 will use the ScsiDoneCtx
+                * There is no processing for the reply.
+                * Just return to the calling function.
+                */
+               if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
+                       printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);
+
+               mptscsih_freeChainBuffers(hd, req_idx);
+               return 1;
+       }
+
+       dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
+                       ioc->name, mf, mr, sc, req_idx));
+
+       atomic_dec(&queue_depth);
+
+       sc->result = DID_OK << 16;              /* Set default reply as OK */
+       pScsiReq = (SCSIIORequest_t *) mf;
+       pScsiReply = (SCSIIOReply_t *) mr;
+
+       if (pScsiReply == NULL) {
+               /* special context reply handling */
+
+               /* If regular Inquiry cmd - save inquiry data
+                */
+               if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {
+                       int      dlen;
+
+                       dlen = le32_to_cpu(pScsiReq->DataLength);
+                       if (dlen >= SCSI_STD_INQUIRY_BYTES) {
+                               mptscsih_initTarget(hd,
+                                               hd->port,
+                                               sc->target,
+                                               pScsiReq->LUN[1],
+                                               sc->buffer,
+                                               dlen);
+                       }
+               }
+#ifdef MPT_SAVE_AUTOSENSE
+               clear_sense_flag(hd, pScsiReq);
+#endif
+       } else {
+               u32      xfer_cnt;
+               u16      status;
+               u8       scsi_state;
+
+               status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+               scsi_state = pScsiReply->SCSIState;
+
+               dprintk((KERN_NOTICE "  Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
+                               ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
+                               mf, mr, sc));
+               dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"
+                               ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+                               status, scsi_state, pScsiReply->SCSIStatus,
+                               le32_to_cpu(pScsiReply->IOCLogInfo)));
+
+               if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
+                       copy_sense_data(sc, hd, mf, pScsiReply);
+
+               /*
+                *  Look for + dump FCP ResponseInfo[]!
+                */
+               if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
+                       dprintk((KERN_NOTICE "  FCP_ResponseInfo=%08xh\n",
+                                            le32_to_cpu(pScsiReply->ResponseInfo)));
+               }
+
+               switch(status) {
+               case MPI_IOCSTATUS_BUSY:                        /* 0x0002 */
+                       /* CHECKME!
+                        * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
+                        * But not: DID_BUS_BUSY lest one risk
+                        * killing interrupt handler:-(
+                        */
+                       sc->result = STS_BUSY;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_INVALID_BUS:            /* 0x0041 */
+               case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:       /* 0x0042 */
+                       sc->result = DID_BAD_TARGET << 16;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
+                       /* Spoof to SCSI Selection Timeout! */
+                       sc->result = DID_NO_CONNECT << 16;
+
+                       if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
+                               hd->sel_timeout[pScsiReq->TargetID]++;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
+#ifndef MPT_SCSI_USE_NEW_EH
+                       search_taskQ_for_cmd(sc, hd);
+#endif
+                       /* Linux handles an unsolicited DID_RESET better
+                        * than an unsolicited DID_ABORT.
+                        */
+                       sc->result = DID_RESET << 16;
+
+                       /* GEM Workaround. */
+                       if (hd->is_spi)
+                               mptscsih_no_negotiate(hd, sc->target);
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
+               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
+#ifndef MPT_SCSI_USE_NEW_EH
+                       search_taskQ_for_cmd(sc, hd);
+#endif
+                       sc->result = DID_RESET << 16;
+
+                       /* GEM Workaround. */
+                       if (hd->is_spi)
+                               mptscsih_no_negotiate(hd, sc->target);
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:      /* 0x0049 */
+               case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
+                       /*
+                        *  YIKES!  I just discovered that SCSI IO which
+                        *  returns check condition, SenseKey=05 (ILLEGAL REQUEST)
+                        *  and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
+                        *  comes down this path!
+                        *  Do upfront check for valid SenseData and give it
+                        *  precedence!
+                        */
+                       sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+#ifdef MPT_SAVE_AUTOSENSE
+                       clear_sense_flag(hd, pScsiReq);
+#endif
+                       if (scsi_state == 0) {
                                ;
                        } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
                                /* Have already saved the status and sense data
@@ -506,7 +933,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                ;
                        } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
                                /*
-                                * If running agains circa 200003dd 909 MPT f/w,
+                                * If running against circa 200003dd 909 MPT f/w,
                                 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
                                 * (QUEUE_FULL) returned from device! --> get 0x0000?128
                                 * and with SenseBytes set to 0.
@@ -625,7 +1052,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 
        hd->ScsiLookup[req_idx] = NULL;
 
-       sc->host_scribble = NULL;       /* CHECKME! - Do we need to clear this??? */
+#ifndef MPT_SCSI_USE_NEW_EH
+       sc->host_scribble = NULL;
+#endif
 
         MPT_HOST_LOCK(flags);
        sc->scsi_done(sc);              /* Issue the command callback */
@@ -894,7 +1323,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
        int              ii;
        int              max = hd->ioc->req_depth;
 
-#ifndef MPT_SCSI_USE_NEW_EH
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
        unsigned long    flags;
 #endif
 
@@ -911,7 +1340,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
                        search_taskQ_for_cmd(SCpnt, hd);
 #endif
 
-                       /* Search pendingQ, if found, 
+                       /* Search pendingQ, if found,
                         * delete from Q. If found, do not decrement
                         * queue_depth, command never posted.
                         */
@@ -1061,7 +1490,7 @@ mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init)
         * of chain buffers to be allocated.
         * index = chain_idx
         *
-        * Calculate the number of chain buffers needed(plus 1) per I/O 
+        * Calculate the number of chain buffers needed(plus 1) per I/O
         * then multiply the the maximum number of simultaneous cmds
         *
         * num_sge = num sge in request frame + last chain buffer
@@ -1175,6 +1604,7 @@ mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIOReque
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int BeenHereDoneThat = 0;
+static char *info_kbuf = NULL;
 
 /*  SCSI host fops start here...  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1263,9 +1693,10 @@ mptscsih_detect(Scsi_Host_Template *tpnt)
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
                        tpnt->proc_dir = &proc_mpt_scsihost;
 #endif
+                       tpnt->proc_info = mptscsih_proc_info;
                        sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
                        if (sh != NULL) {
-                               mptscsih_lock(this, flags);
+                               spin_lock_irqsave(&this->FreeQlock, flags);
                                sh->io_port = 0;
                                sh->n_io_port = 0;
                                sh->irq = 0;
@@ -1326,7 +1757,7 @@ mptscsih_detect(Scsi_Host_Template *tpnt)
                                } else {
                                        numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
                                                (this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
-                               } 
+                               }
 
                                if (numSGE < sh->sg_tablesize) {
                                        /* Reset this value */
@@ -1340,7 +1771,7 @@ mptscsih_detect(Scsi_Host_Template *tpnt)
                                 */
                                scsi_set_pci_device(sh, this->pcidev);
 
-                               mptscsih_unlock(this, flags);
+                               spin_unlock_irqrestore(&this->FreeQlock, flags);
 
                                hd = (MPT_SCSI_HOST *) sh->hostdata;
                                hd->ioc = this;
@@ -1503,12 +1934,25 @@ mptscsih_detect(Scsi_Host_Template *tpnt)
 done:
        if (mpt_scsi_hosts > 0)
                register_reboot_notifier(&mptscsih_notifier);
+       else {
+               mpt_reset_deregister(ScsiDoneCtx);
+               dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
+
+               mpt_event_deregister(ScsiDoneCtx);
+               dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
+
+               mpt_deregister(ScsiScanDvCtx);
+               mpt_deregister(ScsiTaskCtx);
+               mpt_deregister(ScsiDoneCtx);
+
+               if (info_kbuf != NULL)
+                       kfree(info_kbuf);
+       }
 
        return mpt_scsi_hosts;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-    static char *info_kbuf = NULL;
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptscsih_release - Unregister SCSI host from linux scsi mid-layer
@@ -1721,711 +2165,729 @@ mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mptscsih_info - Return information about MPT adapter
- *     @SChost: Pointer to Scsi_Host structure
- *
- *     (linux Scsi_Host_Template.info routine)
- *
- *     Returns pointer to buffer where information was written.
- */
-const char *
-mptscsih_info(struct Scsi_Host *SChost)
-{
-       MPT_SCSI_HOST *h;
-       int size = 0;
-
-       if (info_kbuf == NULL)
-               if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
-                       return info_kbuf;
-
-       h = (MPT_SCSI_HOST *)SChost->hostdata;
-       info_kbuf[0] = '\0';
-       mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
-       info_kbuf[size-1] = '\0';
-
-       return info_kbuf;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-       static int max_qd = 1;
-#if 0
-static int index_log[128];
-static int index_ent = 0;
-static __inline__ void ADD_INDEX_LOG(int req_ent)
-{
-       int i = index_ent++;
-
-       index_log[i & (128 - 1)] = req_ent;
-}
-#else
-#define ADD_INDEX_LOG(req_ent) do { } while(0)
-#endif
-
-#ifdef DROP_TEST
-#define DROP_IOC       1       /* IOC to force failures */
-#define DROP_TARGET    3       /* Target ID to force failures */
-#define        DROP_THIS_CMD   10000   /* iteration to drop command */
-static int dropCounter = 0;
-static int dropTestOK = 0;     /* num did good */
-static int dropTestBad = 0;    /* num did bad */
-static int dropTestNum = 0;    /* total = good + bad + incomplete */
-static int numTotCmds = 0;
-static MPT_FRAME_HDR *dropMfPtr = NULL;
-static int numTMrequested = 0;
-#endif
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
- *     @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx) 
- *     @id: IOC id number 
- *     @mf: Pointer to message frame 
- *
- *     Handles the call to mptbase for posting request and queue depth 
- *     tracking.
- *
- *     Returns none.
- */
-static void
-mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
-{
-       /* Main banana... */
-       atomic_inc(&queue_depth);
-       if (atomic_read(&queue_depth) > max_qd) {
-               max_qd = atomic_read(&queue_depth);
-               dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
-       }
-
-       mpt_put_msg_frame(context, id, mf);
-
-       return;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
- *     @SCpnt: Pointer to Scsi_Cmnd structure
- *     @done: Pointer SCSI mid-layer IO completion function
+ *     mptscsih_info - Return information about MPT adapter
+ *     @SChost: Pointer to Scsi_Host structure
  *
- *     (linux Scsi_Host_Template.queuecommand routine)
- *     This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
- *     from a linux Scsi_Cmnd request and send it to the IOC.
+ *     (linux Scsi_Host_Template.info routine)
  *
- *     Returns 0. (rtn value discarded by linux scsi mid-layer)
+ *     Returns pointer to buffer where information was written.
  */
-int
-mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+const char *
+mptscsih_info(struct Scsi_Host *SChost)
 {
-       MPT_SCSI_HOST           *hd;
-       MPT_FRAME_HDR           *mf;
-       SCSIIORequest_t         *pScsiReq;
-       VirtDevice              *pTarget;
-       MPT_DONE_Q              *buffer = NULL;
-       unsigned long            flags;
-       int      target;
-       int      lun;
-       int      datadir;
-       u32      datalen;
-       u32      scsictl;
-       u32      scsidir;
-       u32      qtag;
-       u32      cmd_len;
-       int      my_idx;
-       int      ii;
-       int      rc;
-       int      did_errcode;
-       int      issueCmd;
-
-       did_errcode = 0;
-       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
-       target = SCpnt->target;
-       lun = SCpnt->lun;
-       SCpnt->scsi_done = done;
-
-       pTarget = hd->Targets[target];
-
-       dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
-                       (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
+       MPT_SCSI_HOST *h = NULL;
+       int size = 0;
 
-#ifdef MPT_SAVE_AUTOSENSE
-       /* 20000617 -sralston
-        *  GRRRRR...  Shouldn't have to do this but...
-        *  Do explicit check for REQUEST_SENSE and cached SenseData.
-        *  If yes, return cached SenseData.
-        */
-       if (SCpnt->cmnd[0] == REQUEST_SENSE) {
-               u8 *dest = NULL;
-               int sz;
+       if (info_kbuf == NULL)
+               if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
+                       return info_kbuf;
 
-               if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_SENSE)) {
-                       pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;       //sjr-moved-here
-                       if (!SCpnt->use_sg) {
-                               dest = SCpnt->request_buffer;
-                       } else {
-                               struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
-                               if (sg)
-                                       dest = (u8 *)(ulong)sg_dma_address(sg);
-                       }
+       h = (MPT_SCSI_HOST *)SChost->hostdata;
+       info_kbuf[0] = '\0';
+       if (h) {
+               mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
+               info_kbuf[size-1] = '\0';
+       }
 
-                       if (dest) {
-                               sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen);
-                               memcpy(dest, pTarget->sense, sz);
+       return info_kbuf;
+}
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-                               SCpnt->resid = SCpnt->request_bufflen - sz;
-#endif
-                               SCpnt->result = 0;
-                               SCpnt->scsi_done(SCpnt);
+struct info_str {
+       char *buffer;
+       int   length;
+       int   offset;
+       int   pos;
+};
 
-                               //sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+       if (info->pos + len > info->length)
+               len = info->length - info->pos;
 
-                               return 0;
-                       }
-               }
+       if (info->pos + len < info->offset) {
+               info->pos += len;
+               return;
        }
-#endif
 
-       if (hd->resetPending) {
-               /* Prevent new commands from being issued
-                * while reloading the FW.
-                */
-               did_errcode = 1;
-               goto did_error;
+       if (info->pos < info->offset) {
+               data += (info->offset - info->pos);
+               len  -= (info->offset - info->pos);
        }
 
-       /*
-        *  Put together a MPT SCSI request...
-        */
-       if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
-               dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
-                               hd->ioc->name));
-               did_errcode = 2;
-               goto did_error;
+       if (len > 0) {
+                memcpy(info->buffer + info->pos, data, len);
+                info->pos += len;
        }
+}
 
-       pScsiReq = (SCSIIORequest_t *) mf;
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+       va_list args;
+       char buf[81];
+       int len;
 
-       my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       va_start(args, fmt);
+       len = vsprintf(buf, fmt, args);
+       va_end(args);
 
-       ADD_INDEX_LOG(my_idx);
+       copy_mem_info(info, buf, len);
+       return len;
+}
 
-       /*
-        *  The scsi layer should be handling this stuff
-        *  (In 2.3.x it does -DaveM)
-        */
+static int mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
+{
+       struct info_str info;
 
-       /*  BUG FIX!  19991030 -sralston
-        *    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
-        *    Seems we may receive a buffer (datalen>0) even when there
-        *    will be no data transfer!  GRRRRR...
-        */
-       datadir = mptscsih_io_direction(SCpnt);
-       if (datadir == SCSI_DATA_READ) {
-               datalen = SCpnt->request_bufflen;
-               scsidir = MPI_SCSIIO_CONTROL_READ;      /* DATA IN  (host<--ioc<--dev) */
-       } else if (datadir == SCSI_DATA_WRITE) {
-               datalen = SCpnt->request_bufflen;
-               scsidir = MPI_SCSIIO_CONTROL_WRITE;     /* DATA OUT (host-->ioc-->dev) */
-       } else {
-               datalen = 0;
-               scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
-       }
+       info.buffer     = pbuf;
+       info.length     = len;
+       info.offset     = offset;
+       info.pos        = 0;
 
-       /* Default to untagged. Once a target structure has been allocated,
-        * use the Inquiry data to determine if device supports tagged.
-        */
-       qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
-       if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
-                       && (SCpnt->device->tagged_supported)) {
-               /*
-                *  Some drives are too stupid to handle fairness issues
-                *  with tagged queueing. We throw in the odd ordered
-                *  tag to stop them starving themselves.
-                */
-               if ((jiffies - hd->qtag_tick) > (5*HZ)) {
-                       qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
-                       hd->qtag_tick = jiffies;
+       copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
+       copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
+       copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
+       copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
+
+       return ((info.pos > info.offset) ? info.pos - info.offset : 0);
+}
+
+struct mptscsih_usrcmd {
+       ulong target;
+       ulong lun;
+       ulong data;
+       ulong cmd;
+};
+
+#define UC_GET_SPEED   0x10
+
+static void mptscsih_exec_user_cmd(MPT_ADAPTER *ioc, struct mptscsih_usrcmd *uc)
+{
+       CONFIGPARMS              cfg;
+       dma_addr_t               cfg_dma_addr = -1;
+       ConfigPageHeader_t       header;
+
+       dprintk(("exec_user_command: ioc %p cmd %ld target=%ld\n", 
+                       ioc, uc->cmd, uc->target));
+
+       switch (uc->cmd) {
+       case UC_GET_SPEED:
+               {
+                       SCSIDevicePage0_t       *pData = NULL;
+
+                       if (ioc->spi_data.sdp0length == 0)
+                               return;
+
+                       pData = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev,
+                                ioc->spi_data.sdp0length * 4, &cfg_dma_addr);
+
+                       if (pData == NULL)
+                               return;
+
+                       header.PageVersion = ioc->spi_data.sdp0version;
+                       header.PageLength = ioc->spi_data.sdp0length;
+                       header.PageNumber = 0;
+                       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+                       cfg.hdr = &header;
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+                       cfg.dir = 0;
+                       cfg.pageAddr = (u32) uc->target; /* bus << 8 | target */
+                       cfg.physAddr = cfg_dma_addr;
+
+                       if (mpt_config(ioc, &cfg) == 0) {
+                               u32 np = le32_to_cpu(pData->NegotiatedParameters);
+                               u32 tmp = np & MPI_SCSIDEVPAGE0_NP_WIDE;
+
+                               printk("Target %d: %s;",
+                                               (u32) uc->target,
+                                               tmp ? "Wide" : "Narrow");
+
+                               tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK;
+                               if (tmp) {
+                                       u32 speed = 0;
+                                       printk(" Synchronous");
+                                       tmp = (tmp >> 16);
+                                       printk(" (Offset=0x%x", tmp);
+                                       tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK;
+                                       tmp = (tmp >> 8);
+                                       printk(" Factor=0x%x)", tmp);
+                                       if (tmp <= MPT_ULTRA320)
+                                               speed=160;
+                                       else if (tmp <= MPT_ULTRA160)
+                                               speed=80;
+                                       else if (tmp <= MPT_ULTRA2)
+                                               speed=40;
+                                       else if (tmp <= MPT_ULTRA)
+                                               speed=20;
+                                       else if (tmp <= MPT_FAST)
+                                               speed=10;
+                                       else if (tmp <= MPT_SCSI)
+                                               speed=5;
+
+                                       if (np & MPI_SCSIDEVPAGE0_NP_WIDE)
+                                               speed*=2;
+
+                                       printk(" %dMB/sec\n", speed);
+
+                               } else 
+                                       printk(" Asynchronous.\n");
+                       } else {
+                               printk("failed\n" );
+                       }
+
+                       pci_free_consistent(ioc->pcidev, ioc->spi_data.sdp0length * 4,
+                                           pData, cfg_dma_addr);
                }
-               else
-                       qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+               break;
        }
-       scsictl = scsidir | qtag;
+}
 
-       /* Use the above information to set up the message frame
-        */
-       pScsiReq->TargetID = target;
-       pScsiReq->Bus = hd->port;
-       pScsiReq->ChainOffset = 0;
-       pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
-       pScsiReq->CDBLength = SCpnt->cmd_len;
-       pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
-       pScsiReq->Reserved = 0;
-       pScsiReq->MsgFlags = mpt_msg_flags();
-       pScsiReq->LUN[0] = 0;
-       pScsiReq->LUN[1] = lun;
-       pScsiReq->LUN[2] = 0;
-       pScsiReq->LUN[3] = 0;
-       pScsiReq->LUN[4] = 0;
-       pScsiReq->LUN[5] = 0;
-       pScsiReq->LUN[6] = 0;
-       pScsiReq->LUN[7] = 0;
-       pScsiReq->Control = cpu_to_le32(scsictl);
+#define is_digit(c)    ((c) >= '0' && (c) <= '9')
+#define digit_to_bin(c)        ((c) - '0')
+#define is_space(c)    ((c) == ' ' || (c) == '\t')
 
-       /*
-        *  Write SCSI CDB into the message
-        */
-       cmd_len = SCpnt->cmd_len;
-       for (ii=0; ii < cmd_len; ii++)
-               pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
-       for (ii=cmd_len; ii < 16; ii++)
-               pScsiReq->CDB[ii] = 0;
+static int skip_spaces(char *ptr, int len)
+{
+       int cnt, c;
 
-       /* DataLength */
-       pScsiReq->DataLength = cpu_to_le32(datalen);
+       for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --);
 
-       /* SenseBuffer low address */
-       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
-                                          + (my_idx * MPT_SENSE_BUFFER_ALLOC));
+       return (len - cnt);
+}
 
-       /* Now add the SG list
-        * Always have a SGE even if null length.
-        */
-       rc = SUCCESS;
-       if (datalen == 0) {
-               /* Add a NULL SGE */
-               mpt_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
-                       (dma_addr_t) -1);
-       } else {
-               /* Add a 32 or 64 bit SGE */
-               rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);
+static int get_int_arg(char *ptr, int len, ulong *pv)
+{
+       int cnt, c;
+       ulong   v;
+       for (v =  0, cnt = len; cnt > 0 && (c=*ptr++) && is_digit(c); cnt --) {
+               v = (v * 10) + digit_to_bin(c);
        }
 
+       if (pv)
+               *pv = v;
 
-       if (rc == SUCCESS) {
-               hd->ScsiLookup[my_idx] = SCpnt;
-               SCpnt->host_scribble = NULL;
+       return (len - cnt);
+}
 
-#ifdef DROP_TEST
-               numTotCmds++;
-               /* If the IOC number and target match, increment
-                * counter. If counter matches DROP_THIS, do not
-                * issue command to FW to force a reset.
-                * Save the MF pointer so we can free resources
-                * when task mgmt completes.
-                */
-               if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) {
-                       dropCounter++;
 
-                       if (dropCounter == DROP_THIS_CMD) {
-                               dropCounter = 0;
+static int is_keyword(char *ptr, int len, char *verb)
+{
+       int verb_len = strlen(verb);
 
-                               /* If global is set, then we are already
-                                * doing something - so keep issuing commands.
-                                */
-                               if (dropMfPtr == NULL) {
-                                       dropTestNum++;
-                                       dropMfPtr = mf;
-                                       atomic_inc(&queue_depth);
-                                       printk(MYIOC_s_INFO_FMT
-                                               "Dropped SCSI cmd (%p)\n",
-                                               hd->ioc->name, SCpnt);
-                                       printk("mf (%p) req (%4x) tot cmds (%d)\n",
-                                               mf, my_idx, numTotCmds);
+       if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
+               return verb_len;
+       else
+               return 0;
+}
 
-                                       return 0;
-                               }
-                       }
-               }
-#endif
+#define SKIP_SPACES(min_spaces)                                                \
+       if ((arg_len = skip_spaces(ptr,len)) < (min_spaces))            \
+               return -EINVAL;                                         \
+       ptr += arg_len;                                                 \
+       len -= arg_len;
 
-               /* SCSI specific processing */
-               issueCmd = 1;
-               if (hd->is_spi) {
-                       int dvStatus = hd->ioc->spi_data.dvStatus[target];
+#define GET_INT_ARG(v)                                                 \
+       if (!(arg_len = get_int_arg(ptr,len, &(v))))                    \
+               return -EINVAL;                                         \
+       ptr += arg_len;                                                 \
+       len -= arg_len;
+
+static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length)
+{
+       char *ptr       = buffer;
+       struct mptscsih_usrcmd cmd, *uc = &cmd;
+       ulong           target;
+       int             arg_len;
+       int len         = length;
+
+       uc->target = uc->cmd = uc->lun = uc->data = 0;
+       
+       if ((len > 0) && (ptr[len -1] == '\n'))
+               --len;
 
-                       if (dvStatus || hd->ioc->spi_data.forceDv) {
+       if ((arg_len = is_keyword(ptr, len, "getspeed")) != 0)
+               uc->cmd = UC_GET_SPEED;
+       else
+               arg_len = 0;
 
-                               /* Write SDP1 on this I/O to this target */
-                               if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
-                                       mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
-                                       dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
-                                       hd->ioc->spi_data.dvStatus[target] =  dvStatus;
-                               } else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {
-                                       mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);
-                                       dvStatus &= ~MPT_SCSICFG_BLK_NEGO;
-                                       hd->ioc->spi_data.dvStatus[target] =  dvStatus;
-                               }
+       dprintk(("user_command:  arg_len=%d, cmd=%ld\n", arg_len, uc->cmd));
 
-#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-                               if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) {
-                                       unsigned long lflags;
-                                       /* Schedule DV if necessary */
-                                       spin_lock_irqsave(&dvtaskQ_lock, lflags);
-                                       if (!dvtaskQ_active) {
-                                               dvtaskQ_active = 1;
-                                               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
-                                               MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); 
+       if (!arg_len)
+               return -EINVAL;
 
-                                               SCHEDULE_TASK(&mptscsih_dvTask);
-                                       } else {
-                                               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
-                                       }
-                                       hd->ioc->spi_data.forceDv = 0;
-                               }
+       ptr += arg_len;
+       len -= arg_len;
 
-                               /* Trying to do DV to this target, extend timeout.
-                                * Wait to issue intil flag is clear 
-                                */
-                               if (dvStatus & MPT_SCSICFG_DV_PENDING) {
-                                       mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
-                                       issueCmd = 0;
-                               }
+       switch(uc->cmd) {
+               case UC_GET_SPEED:
+                       SKIP_SPACES(1);
+                       GET_INT_ARG(target);
+                       uc->target = target;
+                       break;
+       }
 
-                               /* Set the DV flags.
-                                */
-                               if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
-                                       mptscsih_set_dvflags(hd, pScsiReq);
-#endif
-                       }
-               }
+       dprintk(("user_command: target=%ld len=%d\n", uc->target, len));
 
-               if (issueCmd) {
-                       mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
-                       dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
-                                       hd->ioc->name, SCpnt, mf, my_idx));
-               } else {
-                       ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",
-                                       hd->ioc->name, SCpnt, my_idx));
-                       /* Place this command on the pendingQ if possible */
-                       spin_lock_irqsave(&hd->freedoneQlock, flags);
-                       if (!Q_IS_EMPTY(&hd->freeQ)) {
-                               buffer = hd->freeQ.head;
-                               Q_DEL_ITEM(buffer);
+       if (len)
+               return -EINVAL;
+       else {
+               /* process this command ...
+                */
+               mptscsih_exec_user_cmd(ioc, uc);
+       }
+       /* Not yet implemented */
+       return length;
+}
 
-                               /* Save the mf pointer
-                                */
-                               buffer->argp = (void *)mf;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_proc_info - Return information about MPT adapter
+ *
+ *     (linux Scsi_Host_Template.info routine)
+ *
+ *     buffer: if write, user data; if read, buffer for user
+ *     length: if write, return length;
+ *     offset: if write, 0; if read, the current offset into the buffer from
+ *             the previous read.
+ *     hostno: scsi host number
+ *     func:   if write = 1; if read = 0
+ */
+int mptscsih_proc_info(char *buffer, char **start, off_t offset,
+                       int length, int hostno, int func)
+{
+       MPT_ADAPTER     *ioc = NULL;
+       MPT_SCSI_HOST   *hd = NULL;
+       int size = 0;
 
-                               /* Add to the pendingQ
-                                */
-                               Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);
-                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
-                       } else {
-                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
-                               SCpnt->result = (DID_BUS_BUSY << 16);
-                               SCpnt->scsi_done(SCpnt);
-                       }
+       dprintk(("Called mptscsih_proc_info: hostno=%d, func=%d\n", hostno, func));
+       dprintk(("buffer %p, start=%p (%p) offset=%ld length = %d\n",
+                       buffer, start, *start, offset, length));
+
+       for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+               if ((ioc->sh) && (ioc->sh->host_no == hostno)) {
+                       hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+                       break;
                }
+       }
+       if ((ioc == NULL) || (ioc->sh == NULL) || (hd == NULL))
+               return 0;
+
+       if (func) {
+               size = mptscsih_user_command(ioc, buffer, length);
        } else {
-               mptscsih_freeChainBuffers(hd, my_idx);
-               mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
-               did_errcode = 3;
-               goto did_error;
+               if (start)
+                       *start = buffer;
+
+               size = mptscsih_host_info(ioc, buffer, offset, length);
        }
 
-       return 0;
+       return size;
+}
 
-did_error:
-       dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",
-                       hd->ioc->name, did_errcode, SCpnt));
-       /* Just wish OS to issue a retry */
-       SCpnt->result = (DID_BUS_BUSY << 16);
-       spin_lock_irqsave(&hd->freedoneQlock, flags);
-       if (!Q_IS_EMPTY(&hd->freeQ)) {
-               buffer = hd->freeQ.head;
-               Q_DEL_ITEM(buffer);
 
-               /* Set the Scsi_Cmnd pointer
-                */
-               buffer->argp = (void *)SCpnt;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+       static int max_qd = 1;
+#if 0
+static int index_log[128];
+static int index_ent = 0;
+static __inline__ void ADD_INDEX_LOG(int req_ent)
+{
+       int i = index_ent++;
 
-               /* Add to the doneQ
-                */
-               Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
-               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
-       } else {
-               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
-               SCpnt->scsi_done(SCpnt);
+       index_log[i & (128 - 1)] = req_ent;
+}
+#else
+#define ADD_INDEX_LOG(req_ent) do { } while(0)
+#endif
+
+#ifdef DROP_TEST
+#define DROP_IOC       1       /* IOC to force failures */
+#define DROP_TARGET    3       /* Target ID to force failures */
+#define        DROP_THIS_CMD   10000   /* iteration to drop command */
+static int dropCounter = 0;
+static int dropTestOK = 0;     /* num did good */
+static int dropTestBad = 0;    /* num did bad */
+static int dropTestNum = 0;    /* total = good + bad + incomplete */
+static int numTotCmds = 0;
+static MPT_FRAME_HDR *dropMfPtr = NULL;
+static int numTMrequested = 0;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
+ *     @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx)
+ *     @id: IOC id number
+ *     @mf: Pointer to message frame
+ *
+ *     Handles the call to mptbase for posting request and queue depth
+ *     tracking.
+ *
+ *     Returns none.
+ */
+static inline void
+mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
+{
+       /* Main banana... */
+       atomic_inc(&queue_depth);
+       if (atomic_read(&queue_depth) > max_qd) {
+               max_qd = atomic_read(&queue_depth);
+               dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
        }
 
-       return 0;
+       mpt_put_msg_frame(context, id, mf);
+
+       return;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
- *     SCSIIORequest_t Message Frame.
- *     @hd: Pointer to MPT_SCSI_HOST structure
+/**
+ *     mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
  *     @SCpnt: Pointer to Scsi_Cmnd structure
- *     @pReq: Pointer to SCSIIORequest_t structure
+ *     @done: Pointer SCSI mid-layer IO completion function
  *
- *     Returns ...
+ *     (linux Scsi_Host_Template.queuecommand routine)
+ *     This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
+ *     from a linux Scsi_Cmnd request and send it to the IOC.
+ *
+ *     Returns 0. (rtn value discarded by linux scsi mid-layer)
  */
-static int
-mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
-                                SCSIIORequest_t *pReq, int req_idx)
+int
+mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
-       char    *psge;
-       char    *chainSge;
-       struct scatterlist *sg;
-       int      frm_sz;
-       int      sges_left, sg_done;
-       int      chain_idx = MPT_HOST_NO_CHAIN;
-       int      sgeOffset;
-       int      numSgeSlots, numSgeThisFrame;
-       u32      sgflags, sgdir, thisxfer = 0;
-       int      chain_dma_off = 0;
-       int      newIndex;
+       MPT_SCSI_HOST           *hd;
+       MPT_FRAME_HDR           *mf;
+       SCSIIORequest_t         *pScsiReq;
+       VirtDevice              *pTarget;
+       MPT_DONE_Q              *buffer = NULL;
+       unsigned long            flags;
+       int      target;
+       int      lun;
+       int      datadir;
+       u32      datalen;
+       u32      scsictl;
+       u32      scsidir;
+       u32      qtag;
+       u32      cmd_len;
+       int      my_idx;
        int      ii;
-       dma_addr_t v2;
+       int      rc;
+       int      did_errcode;
+       int      issueCmd;
 
-       sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
-       if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {
-               sgdir = MPT_TRANSFER_HOST_TO_IOC;
-       } else {
-               sgdir = MPT_TRANSFER_IOC_TO_HOST;
-       }
+       did_errcode = 0;
+       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+       target = SCpnt->target;
+       lun = SCpnt->lun;
+       SCpnt->scsi_done = done;
 
-       psge = (char *) &pReq->SGL;
-       frm_sz = hd->ioc->req_sz;
+       pTarget = hd->Targets[target];
 
-       /* Map the data portion, if any.
-        * sges_left  = 0 if no data transfer.
+       dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
+                       (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
+
+#ifdef MPT_SAVE_AUTOSENSE
+       /* 20000617 -sralston
+        *  GRRRRR...  Shouldn't have to do this but...
+        *  Do explicit check for REQUEST_SENSE and cached SenseData.
+        *  If yes, return cached SenseData.
         */
-       sges_left = SCpnt->use_sg;
-       if (SCpnt->use_sg) {
-               sges_left = pci_map_sg(hd->ioc->pcidev,
-                              (struct scatterlist *) SCpnt->request_buffer,
-                              SCpnt->use_sg,
-                              scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
-       } else if (SCpnt->request_bufflen) {
-               dma_addr_t       buf_dma_addr;
-               scPrivate       *my_priv;
+       if (SCpnt->cmnd[0] == REQUEST_SENSE) {
+               u8 *dest = NULL;
+               int sz;
 
-               buf_dma_addr = pci_map_single(hd->ioc->pcidev,
-                                     SCpnt->request_buffer,
-                                     SCpnt->request_bufflen,
-                                     scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+               if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_SENSE)) {
+                       pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;       //sjr-moved-here
+                       if (!SCpnt->use_sg) {
+                               dest = SCpnt->request_buffer;
+                       } else {
+                               struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+                               if (sg)
+                                       dest = (u8 *)(ulong)sg_dma_address(sg);
+                       }
+
+                       if (dest) {
+                               sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen);
+                               memcpy(dest, pTarget->sense, sz);
 
-               /* We hide it here for later unmap. */
-               my_priv = (scPrivate *) &SCpnt->SCp;
-               my_priv->p1 = (void *)(ulong) buf_dma_addr;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+                               SCpnt->resid = SCpnt->request_bufflen - sz;
+#endif
+                               SCpnt->result = 0;
+                               SCpnt->scsi_done(SCpnt);
 
-               dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
-                               hd->ioc->name, SCpnt, SCpnt->request_bufflen));
+                               //sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
 
-               mpt_add_sge((char *) &pReq->SGL,
-                       0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
-                       buf_dma_addr);
+                               return 0;
+                       }
+               }
+       }
+#endif
 
-               return SUCCESS;
+       if (hd->resetPending) {
+               /* Prevent new commands from being issued
+                * while reloading the FW.
+                */
+               did_errcode = 1;
+               goto did_error;
        }
 
-       /* Handle the SG case.
+       /*
+        *  Put together a MPT SCSI request...
         */
-       sg = (struct scatterlist *) SCpnt->request_buffer;
-       sg_done  = 0;
-       sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
-       chainSge = NULL;
+       if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
+               dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
+                               hd->ioc->name));
+               did_errcode = 2;
+               goto did_error;
+       }
 
-       /* Prior to entering this loop - the following must be set
-        * current MF:  sgeOffset (bytes)
-        *              chainSge (Null if original MF is not a chain buffer)
-        *              sg_done (num SGE done for this MF)
-        */
+       pScsiReq = (SCSIIORequest_t *) mf;
 
-nextSGEset:
-       numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
-       numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
+       my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
 
-       sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
+       ADD_INDEX_LOG(my_idx);
 
-       /* Get first (num - 1) SG elements
-        * Skip any SG entries with a length of 0
-        * NOTE: at finish, sg and psge pointed to NEXT data/location positions
+       /*
+        *  The scsi layer should be handling this stuff
+        *  (In 2.3.x it does -DaveM)
         */
-       for (ii=0; ii < (numSgeThisFrame-1); ii++) {
-               thisxfer = sg_dma_len(sg);
-               if (thisxfer == 0) {
-                       sg ++; /* Get next SG element from the OS */
-                       sg_done++;
-                       continue;
-               }
-
-               v2 = sg_dma_address(sg);
-               mpt_add_sge(psge, sgflags | thisxfer, v2);
 
-               sg++;           /* Get next SG element from the OS */
-               psge += (sizeof(u32) + sizeof(dma_addr_t));
-               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
-               sg_done++;
+       /*  BUG FIX!  19991030 -sralston
+        *    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
+        *    Seems we may receive a buffer (datalen>0) even when there
+        *    will be no data transfer!  GRRRRR...
+        */
+       datadir = mptscsih_io_direction(SCpnt);
+       if (datadir == SCSI_DATA_READ) {
+               datalen = SCpnt->request_bufflen;
+               scsidir = MPI_SCSIIO_CONTROL_READ;      /* DATA IN  (host<--ioc<--dev) */
+       } else if (datadir == SCSI_DATA_WRITE) {
+               datalen = SCpnt->request_bufflen;
+               scsidir = MPI_SCSIIO_CONTROL_WRITE;     /* DATA OUT (host-->ioc-->dev) */
+       } else {
+               datalen = 0;
+               scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
        }
 
-       if (numSgeThisFrame == sges_left) {
-               /* Add last element, end of buffer and end of list flags.
-                */
-               sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
-                               MPT_SGE_FLAGS_END_OF_BUFFER |
-                               MPT_SGE_FLAGS_END_OF_LIST;
-
-               /* Add last SGE and set termination flags.
-                * Note: Last SGE may have a length of 0 - which should be ok.
+       /* Default to untagged. Once a target structure has been allocated,
+        * use the Inquiry data to determine if device supports tagged.
+        */
+       qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
+       if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+                       && (SCpnt->device->tagged_supported)) {
+               /*
+                *  Some drives are too stupid to handle fairness issues
+                *  with tagged queueing. We throw in the odd ordered
+                *  tag to stop them starving themselves.
                 */
-               thisxfer = sg_dma_len(sg);
+               if ((jiffies - hd->qtag_tick) > (5*HZ)) {
+                       qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
+                       hd->qtag_tick = jiffies;
+               }
+               else
+                       qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+       }
+       scsictl = scsidir | qtag;
 
-               v2 = sg_dma_address(sg);
-               mpt_add_sge(psge, sgflags | thisxfer, v2);
-               /*
-               sg++;
-               psge += (sizeof(u32) + sizeof(dma_addr_t));
-               */
-               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
-               sg_done++;
+       /* Use the above information to set up the message frame
+        */
+       pScsiReq->TargetID = target;
+       pScsiReq->Bus = hd->port;
+       pScsiReq->ChainOffset = 0;
+       pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+       pScsiReq->CDBLength = SCpnt->cmd_len;
+       pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+       pScsiReq->Reserved = 0;
+       pScsiReq->MsgFlags = mpt_msg_flags();
+       pScsiReq->LUN[0] = 0;
+       pScsiReq->LUN[1] = lun;
+       pScsiReq->LUN[2] = 0;
+       pScsiReq->LUN[3] = 0;
+       pScsiReq->LUN[4] = 0;
+       pScsiReq->LUN[5] = 0;
+       pScsiReq->LUN[6] = 0;
+       pScsiReq->LUN[7] = 0;
+       pScsiReq->Control = cpu_to_le32(scsictl);
 
-               if (chainSge) {
-                       /* The current buffer is a chain buffer,
-                        * but there is not another one.
-                        * Update the chain element
-                        * Offset and Length fields.
-                        */
-                       mpt_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
-               } else {
-                       /* The current buffer is the original MF
-                        * and there is no Chain buffer.
-                        */
-                       pReq->ChainOffset = 0;
-               }
-       } else {
-               /* At least one chain buffer is needed.
-                * Complete the first MF
-                *  - last SGE element, set the LastElement bit
-                *  - set ChainOffset (words) for orig MF
-                *             (OR finish previous MF chain buffer)
-                *  - update MFStructPtr ChainIndex
-                *  - Populate chain element
-                * Also
-                * Loop until done.
-                */
+       /*
+        *  Write SCSI CDB into the message
+        *  Should write from cmd_len up to 16, but skip for performance reasons.
+        */
+       cmd_len = SCpnt->cmd_len;
+       for (ii=0; ii < cmd_len; ii++)
+               pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
 
-               dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
-                               hd->ioc->name, sg_done));
+       /* DataLength */
+       pScsiReq->DataLength = cpu_to_le32(datalen);
 
-               /* Set LAST_ELEMENT flag for last non-chain element
-                * in the buffer. Since psge points at the NEXT
-                * SGE element, go back one SGE element, update the flags
-                * and reset the pointer. (Note: sgflags & thisxfer are already
-                * set properly).
-                */
-               if (sg_done) {
-                       u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
-                       sgflags = le32_to_cpu(*ptmp);
-                       sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
-                       *ptmp = cpu_to_le32(sgflags);
-               }
+       /* SenseBuffer low address */
+       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+                                          + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
-               if (chainSge) {
-                       /* The current buffer is a chain buffer.
-                        * chainSge points to the previous Chain Element.
-                        * Update its chain element Offset and Length (must
-                        * include chain element size) fields.
-                        * Old chain element is now complete.
-                        */
-                       u8 nextChain = (u8) (sgeOffset >> 2);
-                       sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
-                       mpt_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
-               } else {
-                       /* The original MF buffer requires a chain buffer -
-                        * set the offset.
-                        * Last element in this MF is a chain element.
-                        */
-                       pReq->ChainOffset = (u8) (sgeOffset >> 2);
-               }
+       /* Now add the SG list
+        * Always have a SGE even if null length.
+        */
+       rc = SUCCESS;
+       if (datalen == 0) {
+               /* Add a NULL SGE */
+               mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+                       (dma_addr_t) -1);
+       } else {
+               /* Add a 32 or 64 bit SGE */
+               rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);
+       }
 
-               sges_left -= sg_done;
 
+       if (rc == SUCCESS) {
+               hd->ScsiLookup[my_idx] = SCpnt;
+               SCpnt->host_scribble = NULL;
 
-               /* NOTE: psge points to the beginning of the chain element
-                * in current buffer. Get a chain buffer.
+#ifdef DROP_TEST
+               numTotCmds++;
+               /* If the IOC number and target match, increment
+                * counter. If counter matches DROP_THIS, do not
+                * issue command to FW to force a reset.
+                * Save the MF pointer so we can free resources
+                * when task mgmt completes.
                 */
-               if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)
-                       return FAILED;
+               if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) {
+                       dropCounter++;
 
-               /* Update the tracking arrays.
-                * If chainSge == NULL, update ReqToChain, else ChainToChain
-                */
-               if (chainSge) {
-                       hd->ChainToChain[chain_idx] = newIndex;
-               } else {
-                       hd->ReqToChain[req_idx] = newIndex;
+                       if (dropCounter == DROP_THIS_CMD) {
+                               dropCounter = 0;
+
+                               /* If global is set, then we are already
+                                * doing something - so keep issuing commands.
+                                */
+                               if (dropMfPtr == NULL) {
+                                       dropTestNum++;
+                                       dropMfPtr = mf;
+                                       atomic_inc(&queue_depth);
+                                       printk(MYIOC_s_INFO_FMT
+                                               "Dropped SCSI cmd (%p)\n",
+                                               hd->ioc->name, SCpnt);
+                                       printk("mf (%p) req (%4x) tot cmds (%d)\n",
+                                               mf, my_idx, numTotCmds);
+
+                                       return 0;
+                               }
+                       }
                }
-               chain_idx = newIndex;
-               chain_dma_off = hd->ioc->req_sz * chain_idx;
+#endif
 
-               /* Populate the chainSGE for the current buffer.
-                * - Set chain buffer pointer to psge and fill
-                *   out the Address and Flags fields.
-                */
-               chainSge = (char *) psge;
-               dsgprintk((KERN_INFO "  Current buff @ %p (index 0x%x)",
-                               psge, req_idx));
+               /* SCSI specific processing */
+               issueCmd = 1;
+               if (hd->is_spi) {
+                       int dvStatus = hd->ioc->spi_data.dvStatus[target];
 
-               /* Start the SGE for the next buffer
-                */
-               psge = (char *) (hd->ChainBuffer + chain_dma_off);
-               sgeOffset = 0;
-               sg_done = 0;
+                       if (dvStatus || hd->ioc->spi_data.forceDv) {
 
-               dsgprintk((KERN_INFO "  Chain buff @ %p (index 0x%x)\n",
-                               psge, chain_idx));
+                               /* Write SDP1 on this I/O to this target */
+                               if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
+                                       mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
+                                       dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
+                                       hd->ioc->spi_data.dvStatus[target] =  dvStatus;
+                               } else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {
+                                       mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);
+                                       dvStatus &= ~MPT_SCSICFG_BLK_NEGO;
+                                       hd->ioc->spi_data.dvStatus[target] =  dvStatus;
+                               }
 
-               /* Start the SGE for the next buffer
-                */
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+                               if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
+                                       (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
+                                       unsigned long lflags;
+                                       /* Schedule DV if necessary */
+                                       spin_lock_irqsave(&dvtaskQ_lock, lflags);
+                                       if (!dvtaskQ_active) {
+                                               dvtaskQ_active = 1;
+                                               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+                                               MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
 
-               goto nextSGEset;
-       }
+                                               SCHEDULE_TASK(&mptscsih_dvTask);
+                                       } else {
+                                               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+                                       }
+                                       hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
+                               }
 
-       return SUCCESS;
-}
+                               /* Trying to do DV to this target, extend timeout.
+                                * Wait to issue intil flag is clear
+                                */
+                               if (dvStatus & MPT_SCSICFG_DV_PENDING) {
+                                       mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
+                                       issueCmd = 0;
+                               }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     mptscsih_getFreeChainBuffes - Function to get a free chain
- *     from the MPT_SCSI_HOST FreeChainQ.
- *     @hd: Pointer to the MPT_SCSI_HOST instance
- *     @req_idx: Index of the SCSI IO request frame. (output)
- *
- *     return SUCCESS or FAILED
- */
-static int
-mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
-{
-       MPT_FRAME_HDR *chainBuf = NULL;
-       unsigned long flags;
-       int rc = FAILED;
-       int chain_idx = MPT_HOST_NO_CHAIN;
+                               /* Set the DV flags.
+                                */
+                               if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
+                                       mptscsih_set_dvflags(hd, pScsiReq);
+#endif
+                       }
+               }
 
-       //spin_lock_irqsave(&hd->FreeChainQlock, flags);
-       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-       if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
+               if (issueCmd) {
+                       mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+                       dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
+                                       hd->ioc->name, SCpnt, mf, my_idx));
+               } else {
+                       ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",
+                                       hd->ioc->name, SCpnt, my_idx));
+                       /* Place this command on the pendingQ if possible */
+                       spin_lock_irqsave(&hd->freedoneQlock, flags);
+                       if (!Q_IS_EMPTY(&hd->freeQ)) {
+                               buffer = hd->freeQ.head;
+                               Q_DEL_ITEM(buffer);
 
-               int offset;
+                               /* Save the mf pointer
+                                */
+                               buffer->argp = (void *)mf;
 
-               chainBuf = hd->FreeChainQ.head;
-               Q_DEL_ITEM(&chainBuf->u.frame.linkage);
-               offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer;
-               chain_idx = offset / hd->ioc->req_sz;
-               rc = SUCCESS;
+                               /* Add to the pendingQ
+                                */
+                               Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);
+                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                       } else {
+                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                               SCpnt->result = (DID_BUS_BUSY << 16);
+                               SCpnt->scsi_done(SCpnt);
+                       }
+               }
+       } else {
+               mptscsih_freeChainBuffers(hd, my_idx);
+               mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+               did_errcode = 3;
+               goto did_error;
        }
-       //spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
-       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
+       return 0;
 
-       *retIndex = chain_idx;
+did_error:
+       dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",
+                       hd->ioc->name, did_errcode, SCpnt));
+       /* Just wish OS to issue a retry */
+       SCpnt->result = (DID_BUS_BUSY << 16);
+       spin_lock_irqsave(&hd->freedoneQlock, flags);
+       if (!Q_IS_EMPTY(&hd->freeQ)) {
+               buffer = hd->freeQ.head;
+               Q_DEL_ITEM(buffer);
 
-       dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
-                       hd->ioc->name, *retIndex, chainBuf));
+               /* Set the Scsi_Cmnd pointer
+                */
+               buffer->argp = (void *)SCpnt;
 
-       return rc;
+               /* Add to the doneQ
+                */
+               Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+       } else {
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+               SCpnt->scsi_done(SCpnt);
+       }
+
+       return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2547,8 +3009,8 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort,
 
 #ifdef MPT_DEBUG_RESET
        if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
-               printk(MYIOC_s_WARN_FMT 
-                       "TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n", 
+               printk(MYIOC_s_WARN_FMT
+                       "TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n",
                        hd->ioc->name, ioc_raw_state);
        }
 #endif
@@ -2765,7 +3227,7 @@ mptscsih_abort(Scsi_Cmnd * SCpnt)
 
        hd->abortSCpnt = SCpnt;
        if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
-                              SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP) 
+                              SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP)
                < 0) {
 
                /* The TM request failed and the subsequent FW-reload failed!
@@ -2830,7 +3292,7 @@ mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
        }
 
        if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-                              SCpnt->target, 0, 0, NO_SLEEP) 
+                              SCpnt->target, 0, 0, NO_SLEEP)
                < 0){
                /* The TM request failed and the subsequent FW-reload failed!
                 * Fatal error case.
@@ -2889,13 +3351,13 @@ mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
 
        /* We are now ready to execute the task management request. */
        if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-                              0, 0, 0, NO_SLEEP) 
+                              0, 0, 0, NO_SLEEP)
            < 0){
 
                /* The TM request failed and the subsequent FW-reload failed!
                 * Fatal error case.
                 */
-               printk(MYIOC_s_WARN_FMT 
+               printk(MYIOC_s_WARN_FMT
                       "Error processing TaskMgmt request (sc=%p)\n",
                       hd->ioc->name, SCpnt);
                hd->tmPending = 0;
@@ -2941,8 +3403,8 @@ mptscsih_host_reset(Scsi_Cmnd *SCpnt)
        if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0){
                status = FAILED;
        } else {
-               /*  Make sure TM pending is cleared and TM state is set to 
-                *  NONE. 
+               /*  Make sure TM pending is cleared and TM state is set to
+                *  NONE.
                 */
                hd->tmPending = 0;
                hd->tmState = TM_STATE_NONE;
@@ -2958,7 +3420,7 @@ mptscsih_host_reset(Scsi_Cmnd *SCpnt)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mptscsih_tm_pending_wait - wait for pending task management request to 
+ *     mptscsih_tm_pending_wait - wait for pending task management request to
  *             complete.
  *     @hd: Pointer to MPT host structure.
  *
@@ -3114,7 +3576,7 @@ mptscsih_old_abort(Scsi_Cmnd *SCpnt)
                 *  (bottom/unused portion of) MPT request frame.
                 */
                ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
-               MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); 
+               MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
 
                SCHEDULE_TASK(ptaskfoo);
        } else  {
@@ -3245,7 +3707,7 @@ mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
                 *  (bottom/unused portion of) MPT request frame.
                 */
                ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
-               MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); 
+               MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
 
                SCHEDULE_TASK(ptaskfoo);
        } else  {
@@ -3599,7 +4061,7 @@ mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
  *     Called once per device the bus scan. Use it to force the queue_depth
  *     member to 1 if a device does not support Q tags.
  */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
 int
 mptscsih_slave_configure(Scsi_Device *device)
 {
@@ -3614,15 +4076,21 @@ mptscsih_slave_configure(Scsi_Device *device)
                        if (!device->tagged_supported ||
                            !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
                                scsi_adjust_queue_depth(device, 0, 1);
+
+                       } else if ((pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)
+                                  && (pTarget->inq_data[0] & 0x1f) == 0x00
+                                  && (pTarget->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) {
+                               scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+                                                       MPT_SCSI_CMD_PER_DEV_HIGH);
                        } else {
-                               scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, 
-                                                       device->host->can_queue >> 1);
+                               scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+                                                       MPT_SCSI_CMD_PER_DEV_LOW);
                        }
                }
        }
        return 0;
 }
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) */
 void
 mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
 {
@@ -3648,113 +4116,32 @@ mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
 
                        for (ii=0; ii < max; ii++) {
                                pTarget = hd->Targets[ii];
-                               if (pTarget && !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
+                               if (pTarget == NULL) {
+                                       continue;
+                               }
+                               if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
                                        device->queue_depth = 1;
+                               } else if ((pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)
+                                          && (pTarget->inq_data[0] & 0x1f) == 0x00
+                                          && (pTarget->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) {
+                                       device->queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
+                               } else {
+                                       device->queue_depth = MPT_SCSI_CMD_PER_DEV_LOW;
                                }
+                               dprintk((MYIOC_s_INFO_FMT
+                                        "target = %d, sync factor = %#x, queue depth = %d\n",
+                                        hd->ioc->name, pTarget->target_id,
+                                        pTarget->minSyncFactor, device->queue_depth));
                        }
                }
        }
 }
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Private routines...
  */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* 19991030 -sralston
- *  Return absolute SCSI data direction:
- *     1 = _DATA_OUT
- *     0 = _DIR_NONE
- *    -1 = _DATA_IN
- *
- * Changed: 3-20-2002 pdelaney to use the default data
- * direction and the defines set up in the
- * 2.4 kernel series
- *     1 = _DATA_OUT   changed to SCSI_DATA_WRITE (1)
- *     0 = _DIR_NONE   changed to SCSI_DATA_NONE (3)
- *    -1 = _DATA_IN    changed to SCSI_DATA_READ (2)
- * If the direction is unknown, fall through to original code.
- *
- * Mid-layer bug fix(): sg interface generates the wrong data 
- * direction in some cases. Set the direction the hard way for 
- * the most common commands.
- */
-static int
-mptscsih_io_direction(Scsi_Cmnd *cmd)
-{
-       switch (cmd->cmnd[0]) {
-       case WRITE_6:           
-       case WRITE_10:          
-               return SCSI_DATA_WRITE;
-               break;
-       case READ_6:            
-       case READ_10:           
-               return SCSI_DATA_READ;
-               break;
-       }
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-       if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN)
-               return cmd->sc_data_direction;
-#endif
-       switch (cmd->cmnd[0]) {
-       /*  _DATA_OUT commands  */
-       case WRITE_6:           case WRITE_10:          case WRITE_12:
-       case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
-       case WRITE_VERIFY:      case WRITE_VERIFY_12:
-       case COMPARE:           case COPY:              case COPY_VERIFY:
-       case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
-       case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:
-       case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
-       case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
-       case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
-       case REASSIGN_BLOCKS:
-       case PERSISTENT_RESERVE_OUT:
-       case 0xea:
-       case 0xa3:
-               return SCSI_DATA_WRITE;
-
-       /*  No data transfer commands  */
-       case SEEK_6:            case SEEK_10:
-       case RESERVE:           case RELEASE:
-       case TEST_UNIT_READY:
-       case START_STOP:
-       case ALLOW_MEDIUM_REMOVAL:
-               return SCSI_DATA_NONE;
-
-       /*  Conditional data transfer commands  */
-       case FORMAT_UNIT:
-               if (cmd->cmnd[1] & 0x10)        /* FmtData (data out phase)? */
-                       return SCSI_DATA_WRITE;
-               else
-                       return SCSI_DATA_NONE;
-
-       case VERIFY:
-               if (cmd->cmnd[1] & 0x02)        /* VERIFY:BYTCHK (data out phase)? */
-                       return SCSI_DATA_WRITE;
-               else
-                       return SCSI_DATA_NONE;
-
-       case RESERVE_10:
-               if (cmd->cmnd[1] & 0x03)        /* RESERVE:{LongID|Extent} (data out phase)? */
-                       return SCSI_DATA_WRITE;
-               else
-                       return SCSI_DATA_NONE;
-
-#if 0
-       case REZERO_UNIT:       /* (or REWIND) */
-       case SPACE:
-       case ERASE:             case ERASE_10:
-       case SYNCHRONIZE_CACHE:
-       case LOCK_UNLOCK_CACHE:
-#endif
-
-       /*  Must be data _IN!  */
-       default:
-               return SCSI_DATA_READ;
-       }
-}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* Utility function to copy sense data from the scsi_cmnd buffer
@@ -3803,7 +4190,7 @@ copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply
 
 #ifdef ABORT_FIX
                        if (sz >= SCSI_STD_SENSE_BYTES) {
-                               if ((sense_data[02] == ABORTED_COMMAND) && 
+                               if ((sense_data[02] == ABORTED_COMMAND) &&
                                        (sense_data[12] == 0x47) && (sense_data[13] == 0x00)){
                                        target->numAborts++;
                                        if ((target->raidVolume == 0) && (target->numAborts > 5)) {
@@ -3896,7 +4283,7 @@ SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* Search the pendingQ for a command with specific index.
- * If found, delete and return mf pointer  
+ * If found, delete and return mf pointer
  * If not found, return NULL
  */
 static MPT_FRAME_HDR *
@@ -4126,6 +4513,13 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 
                dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n",
                        ioc->name));
+
+
+               /* 8. Set flag to force DV and re-read IOC Page 3
+                */
+               ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
+               ddvtprintk(("Set reload IOC Pg3 Flag\n"));
+
        }
 
        return 1;               /* currently means nothing really */
@@ -4172,7 +4566,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 
        case MPI_EVENT_INTEGRATED_RAID:                 /* 0B */
 #ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-               /* negoNvram set to 0 if DV enabled and to USE_NVRAM if 
+               /* negoNvram set to 0 if DV enabled and to USE_NVRAM if
                 * if DV disabled. Need to check for target mode.
                 */
                hd = NULL;
@@ -4188,11 +4582,12 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
                        
                        reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
                        if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
-                               /* New or replaced disk. 
+                               /* New or replaced disk.
                                 * Set DV flag and schedule DV.
                                 */
                                pSpi = &ioc->spi_data;
                                physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
+                               ddvtprintk(("DV requested for phys disk id %d\n", physDiskNum));
                                if (pSpi->pIocPg3) {
                                        pPDisk =  pSpi->pIocPg3->PhysDisk;
                                        numPDisk =pSpi->pIocPg3->NumPhysDisks;
@@ -4207,6 +4602,16 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
                                                pPDisk++;
                                                numPDisk--;
                                        }
+
+                                       if (numPDisk == 0) {
+                                               /* The physical disk that needs DV was not found
+                                                * in the stored IOC Page 3. The driver must reload
+                                                * this page. DV routine will set the NEED_DV flag for
+                                                * all phys disks that have DV_NOT_DONE set.
+                                                */
+                                               pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
+                                               ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n", physDiskNum));
+                                       }
                                }
                        }
                }
@@ -4670,7 +5075,7 @@ int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop)
                if (ioop->cdbPtr == NULL) {
                        return 0;
                } else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) ||
-                       (ioop->cdbPtr[0] == CMD_ReadCapacity) || 
+                       (ioop->cdbPtr[0] == CMD_ReadCapacity) ||
                        (ioop->cdbPtr[0] == 0x43)) {
                        return 0;
                }
@@ -4794,7 +5199,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *
        }
 
        if (vdev && data) {
-               if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) || 
+               if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) ||
                ((dlen > 56) && (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56)))) {
 
                        /* Copy the inquiry data  - if we haven't yet.
@@ -4877,7 +5282,7 @@ void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byt
                                        factor = MPT_ULTRA320;
 
                                /* If RAID, never disable QAS
-                                * else if non RAID, do not disable 
+                                * else if non RAID, do not disable
                                 *   QAS if bit 1 is set
                                 * bit 1 QAS support, non-raid only
                                 * bit 0 IU support
@@ -5000,8 +5405,8 @@ static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
 #endif
 
 /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
- * Else set the NEED_DV flag after Read Capacity Issued (disks) 
- * or Mode Sense (cdroms). 
+ * Else set the NEED_DV flag after Read Capacity Issued (disks)
+ * or Mode Sense (cdroms).
  *
  * Tapes, initTarget will set this flag on completion of Inquiry command.
  * Called only if DV_NOT_DONE flag is set
@@ -5037,7 +5442,7 @@ static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- * If no Target, bus reset on 1st I/O. Set the flag to 
+ * If no Target, bus reset on 1st I/O. Set the flag to
  * prevent any future negotiations to this device.
  */
 static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
@@ -5286,9 +5691,9 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
                pData->Reserved = 0;
                pData->Configuration = cpu_to_le32(configuration);
 
-               dprintk((MYIOC_s_INFO_FMT 
+               dprintk((MYIOC_s_INFO_FMT
                        "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
-                               ioc->name, id, (id | (bus<<8)), 
+                               ioc->name, id, (id | (bus<<8)),
                                requested, configuration));
 
                mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf);
@@ -5327,8 +5732,8 @@ static void mptscsih_taskmgmt_timeout(unsigned long data)
                /* Because we have reset the IOC, no TM requests can be
                 * pending.  So let's make sure the tmPending flag is reset.
                 */
-               nehprintk((KERN_WARNING MYNAM 
-                          ": %s: mptscsih_taskmgmt_timeout\n", 
+               nehprintk((KERN_WARNING MYNAM
+                          ": %s: mptscsih_taskmgmt_timeout\n",
                           hd->ioc->name));
                hd->tmPending = 0;
        }
@@ -5566,7 +5971,7 @@ static void mptscsih_timer_expired(unsigned long data)
                        if (hd->tmPending) {
                                spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
                                return;
-                       } else 
+                       } else
                                hd->tmPending = 1;
                        spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
@@ -5645,7 +6050,7 @@ mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
        pReq->ActionDataWord = 0; /* Reserved for this action */
        //pReq->ActionDataSGE = 0;
 
-       mpt_add_sge((char *)&pReq->ActionDataSGE, 
+       mpt_add_sge((char *)&pReq->ActionDataSGE,
                MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
 
        ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
@@ -5974,7 +6379,7 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
        if (id == hostId)
                id++;
 
-       /* Write SDP1 for all SCSI devices 
+       /* Write SDP1 for all SCSI devices
         * Alloc memory and set up config buffer
         */
        if (hd->is_spi) {
@@ -6097,7 +6502,7 @@ mptscsih_domainValidation(void *arg)
        spin_unlock_irqrestore(&dvtaskQ_lock, flags);
 
        /* For this ioc, loop through all devices and do dv to each device.
-        * When complete with this ioc, search through the ioc list, and 
+        * When complete with this ioc, search through the ioc list, and
         * for each scsi ioc found, do dv for all devices. Exit when no
         * device needs dv.
         */
@@ -6128,6 +6533,23 @@ mptscsih_domainValidation(void *arg)
                        if (hd == NULL)
                                continue;
 
+                       if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
+                               mpt_read_ioc_pg_3(ioc);
+                               if (ioc->spi_data.pIocPg3) {
+                                       Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
+                                       int             numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
+
+                                       while (numPDisk) {
+                                               if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
+                                                       ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
+
+                                               pPDisk++;
+                                               numPDisk--;
+                                       }
+                               }
+                               ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
+                       }
+
                        maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
 
                        for (id = 0; id < maxid; id++) {
@@ -6318,7 +6740,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
 
        lun = 0;
        bus = 0;
-       ddvtprintk((MYIOC_s_NOTE_FMT 
+       ddvtprintk((MYIOC_s_NOTE_FMT
                        "DV started: numIOs %d bus=%d, id %d dv @ %p\n",
                        ioc->name, atomic_read(&queue_depth), bus, id, &dv));
 
@@ -6423,7 +6845,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
        /* Skip this ID? Set cfg.hdr to force config page write
         */
        if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) &&
-                       (!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) { 
+                       (!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) {
 
                ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
                        ioc->name, bus, id, lun));
@@ -6495,11 +6917,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
 
                /* Wide - narrow - wide workaround case
                 */
-               if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) { 
+               if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
                        /* Send an untagged command to reset disk Qs corrupted
                         * when a parity error occurs on a Request Sense.
                         */
-                       if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) || 
+                       if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
                                ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
                                (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
 
@@ -6535,7 +6957,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
                        rc = hd->pLocal->completion;
                        if (rc == MPT_SCANDV_GOOD) {
                                if (hd->pLocal->scsiStatus == STS_BUSY) {
-                                       retcode = 1;
+                                       if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
+                                               retcode = 1;
+                                       else
+                                               retcode = 0;
+
                                        goto target_done;
                                }
                        } else if  (rc == MPT_SCANDV_SENSE) {
@@ -6607,7 +7033,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
                                         * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
                                         * Resetart with a request for U160.
                                         */
-                                       if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) { 
+                                       if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
                                                        doFallback = 1;
                                        } else {
                                                dv.cmd = MPT_UPDATE_MAX;
@@ -6631,7 +7057,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
                                }
 
 
-                       } else if (rc == MPT_SCANDV_ISSUE_SENSE) 
+                       } else if (rc == MPT_SCANDV_ISSUE_SENSE)
                                doFallback = 1; /* set fallback flag */
                        else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
                                doFallback = 1; /* set fallback flag */
@@ -6871,7 +7297,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
                                                mdelay (2000);
                                                notDone++;
                                        } else {
-                                               ddvprintk((MYIOC_s_INFO_FMT 
+                                               ddvprintk((MYIOC_s_INFO_FMT
                                                        "DV: Reserved Failed.", ioc->name));
                                                goto target_done;
                                        }
@@ -6935,7 +7361,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
                                                        patt = -1;
                                                        continue;
                                                }
-                                       } 
+                                       }
                                        goto target_done;
                                }
                                else
@@ -7048,7 +7474,7 @@ target_done:
                        if (hd->pLocal->completion == MPT_SCANDV_GOOD)
                                iocmd.flags &= ~MPT_ICFLAG_RESERVED;
                } else {
-                       printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d", 
+                       printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
                                                ioc->name, id);
                }
        }
@@ -7066,7 +7492,7 @@ target_done:
                mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
 
 #if 0  
-       /* Double writes to SDP1 can cause problems, 
+       /* Double writes to SDP1 can cause problems,
         * skip here since unnecessary
         */
                /* Save the final negotiated settings to
@@ -7222,7 +7648,7 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
        case MPT_SET_MIN:
                ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
                                                                hd->ioc->name));
-               /* Set page to asynchronous and narrow 
+               /* Set page to asynchronous and narrow
                 * Do not update now, breaks fallback routine. */
                width = MPT_NARROW;
                offset = 0;
@@ -7244,7 +7670,7 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
        case MPT_FALLBACK:
                ddvprintk((MYIOC_s_NOTE_FMT
                        "Fallback: Start: offset %d, factor %x, width %d \n",
-                               hd->ioc->name, dv->now.offset, 
+                               hd->ioc->name, dv->now.offset,
                                dv->now.factor, dv->now.width));
                width = dv->now.width;
                offset = dv->now.offset;
index 885a1a55c0f1ff1eff28b0f78600a313e7bb5aee..6c78d41038c1312e0e881d62f0a81cafb17923c1 100644 (file)
@@ -20,7 +20,7 @@
  *  (mailto:netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.h,v 1.20 2002/10/17 20:16:00 pdelaney Exp $
+ *  $Id: mptscsih.h,v 1.21 2002/12/03 21:26:35 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     Try to keep these at 2^N-1
  */
 #define MPT_FC_CAN_QUEUE       63
-//#define MPT_SCSI_CAN_QUEUE   31
-#define MPT_SCSI_CAN_QUEUE     MPT_FC_CAN_QUEUE
-#define MPT_SCSI_CMD_PER_LUN    7
+#if defined MPT_SCSI_USE_NEW_EH
+       #define MPT_SCSI_CAN_QUEUE      127
+#else
+       #define MPT_SCSI_CAN_QUEUE      63
+#endif
+
+#define MPT_SCSI_CMD_PER_DEV_HIGH      31
+#define MPT_SCSI_CMD_PER_DEV_LOW       7
+
+#define MPT_SCSI_CMD_PER_LUN           7
 
 #define MPT_SCSI_MAX_SECTORS    8192
 
@@ -206,11 +213,16 @@ struct mptscsih_driver_setup
 #define x_scsi_dev_reset       mptscsih_dev_reset
 #define x_scsi_host_reset      mptscsih_host_reset
 #define x_scsi_bios_param      mptscsih_bios_param
-#define x_scsi_slave_configure mptscsih_slave_configure
 
 #define x_scsi_taskmgmt_bh     mptscsih_taskmgmt_bh
 #define x_scsi_old_abort       mptscsih_old_abort
 #define x_scsi_old_reset       mptscsih_old_reset
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
+#define x_scsi_slave_configure mptscsih_slave_configure
+#else
+#define x_scsi_select_queue_depths     mptscsih_select_queue_depths
+#endif
+#define x_scsi_proc_info       mptscsih_proc_info
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -237,8 +249,14 @@ extern     int              x_scsi_bios_param(Disk *, struct block_device *, int *);
 #else
 extern int              x_scsi_bios_param(Disk *, kdev_t, int *);
 #endif
-extern int              x_scsi_slave_configure(Scsi_Device *);
 extern void             x_scsi_taskmgmt_bh(void *);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
+extern int              x_scsi_slave_configure(Scsi_Device *);
+#else
+extern void             x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *);
+#endif
+
+extern int              x_scsi_proc_info(char *, char **, off_t, int, int, int);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 #define PROC_SCSI_DECL
@@ -248,14 +266,19 @@ extern    void             x_scsi_taskmgmt_bh(void *);
 
 #ifdef MPT_SCSI_USE_NEW_EH
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
 
 #define MPT_SCSIHOST {                                         \
        PROC_SCSI_DECL                                          \
+       .proc_info                      = x_scsi_proc_info,     \
        .name                           = "MPT SCSI Host",      \
        .detect                         = x_scsi_detect,        \
        .release                        = x_scsi_release,       \
        .info                           = x_scsi_info,          \
+       .command                        = NULL,                 \
+       .queuecommand                   = x_scsi_queuecommand,  \
+       .slave_configure                = x_scsi_slave_configure,       \
+       .eh_strategy_handler            = NULL,                 \
        .eh_abort_handler               = x_scsi_abort,         \
        .eh_device_reset_handler        = x_scsi_dev_reset,     \
        .eh_bus_reset_handler           = x_scsi_bus_reset,     \
@@ -275,6 +298,7 @@ extern      void             x_scsi_taskmgmt_bh(void *);
 #define MPT_SCSIHOST {                                         \
        .next                           = NULL,                 \
        PROC_SCSI_DECL                                          \
+       .proc_info                      = x_scsi_proc_info,     \
        .name                           = "MPT SCSI Host",      \
        .detect                         = x_scsi_detect,        \
        .release                        = x_scsi_release,       \