fusion driver (was: [Linux-ia64] kernel update (relative to 2.5.52))

From: David Mosberger <davidm_at_napali.hpl.hp.com>
Date: 2003-01-03 12:00:06
>>>>> On Sat, 21 Dec 2002 01:00:09 -0800, David Mosberger <davidm@linux.hpl.hp.com> said:

  David> Hoewever, the MPT Fusion SCSI driver broke pretty badly in
  David> 2.5.50: it just freezes the machine while it's probing for
  David> SCSI devices.  Someone who actually knows something about
  David> this driver needs to take a good look at this.

The attached patch is part of 2.5.54 and applies cleanly on top of
2.5.52.  Better still, it makes the fusion driver work again.

Enjoy,

	--david

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.930.1.2 -> 1.930.1.3
#	drivers/message/fusion/mptctl.c	1.10    -> 1.11   
#	drivers/message/fusion/mptbase.h	1.7     -> 1.8    
#	drivers/message/fusion/mptbase.c	1.7     -> 1.8    
#	drivers/message/fusion/linux_compat.h	1.6     -> 1.7    
#	drivers/message/fusion/mptscsih.c	1.15    -> 1.16   
#	drivers/message/fusion/mptctl.h	1.3     -> 1.4    
#	drivers/message/fusion/mptscsih.h	1.13    -> 1.14   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.13
# [ARM] Allow arch/arm/kernel/asm-offsets.s to be regenerated
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.14
# [ARM] Convert semaphore initialisers to C99 syntax.
# 
# The semaphore initialisers were using the old gcc syntax.  Add
# sema_count() implementation for the sa11x0 audio implementation.
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.15
# [ARM] IOP310 build fixes
# 
# Add <asm/arch/iop310.h> include, needed for platform implementation of
# architecture private __virt_to_bus / __bus_to_virt.
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.16
# [ARM] Allow arch/arm/kernel/bios32.c to build for iop310
# 
# bios32.c uses outb(), and therefore should have asm/io.h included.
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.17
# [ARM] Make jornada720 build again
# 
# - Add missing include files.
# - Fail to set pcmcia socket state for invalid socket numbers.
# - Fix locla_ typo.
# - Make pcmcia_jornada720_exit __devexit, not __exit.
# - Don't initialise jornada720 machine specifics if not running
#   on jornada720.
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.18
# [ARM] Minor fixes to drivers/pcmcia/sa1111_generic.c.
# 
# Only set IRQ type after a successful request_irq().
# Driver now known as sa1111-pcmcia in driverfs.
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.19
# [ARM] Fix ups for ARM generic dma mapping interface
# 
# This brings the ARM dma mapping functionality into line with
# the current generic interface, allowing any struct device to
# be passed into the dma_* functions.
# 
# Further cleanups will be possible when the USB layer is
# converted to use the dma_* API.
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.20
# [ARM] Sanitise sa1111 and neponset device driver names.
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.21
# [ARM] Update mach-types
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.22
# [ARM] Add basic support for enable/disable_irq_wake.
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.23
# [ARM] Add support for IRQ-based wakeup for SA11x0 CPUs
# 
# This patch adds support for enable/disable_irq_wake for the SA11x0
# CPUs, allowing drivers or other code to select which IRQs are able
# to wake the CPU from sleep mode.
# --------------------------------------------
# 03/01/01	rmk@flint.arm.linux.org.uk	1.911.26.24
# [ARM] Add IRQ wake support for SA1111 PS/2 interfaces.
# --------------------------------------------
# 03/01/01	pdelaney@lsil.com	1.930.1.3
# [PATCH] Fusion-MPT Update (2.03.01.01)
# 
# 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.
# --------------------------------------------
#
diff -Nru a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
--- a/drivers/message/fusion/linux_compat.h	Thu Jan  2 15:40:31 2003
+++ b/drivers/message/fusion/linux_compat.h	Thu Jan  2 15:40:31 2003
@@ -246,41 +246,30 @@
 #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); \
 	(_task)->data = (void *) (_data); \
 })
 #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
+
 
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
--- a/drivers/message/fusion/mptbase.c	Thu Jan  2 15:40:31 2003
+++ b/drivers/message/fusion/mptbase.c	Thu Jan  2 15:40:31 2003
@@ -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	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 @@
 			 */
 			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 @@
 			}
 			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 @@
 		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 @@
 				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_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 @@
  *	@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 @@
 		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 @@
 		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 @@
 	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 @@
 			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 @@
 #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 @@
 				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_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 @@
 			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 @@
 
 		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 @@
  *
  *	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 @@
 			else
 				statefault = 4;
 		}
-	} 
+	}
 
 	/*
 	 *	Check to see if IOC is in FAULT state.
@@ -2244,7 +2261,7 @@
 		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 @@
 	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 @@
  * 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 @@
 	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 @@
 	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 @@
 		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 @@
  *		 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 @@
 				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 @@
 			/* 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 @@
 #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 @@
 				}
 			}
 			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 @@
 	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 @@
 	}
 	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 @@
 	int			 ii;
 	int			 data, rc = 0;
 
-	/* Allocate memory 
+	/* Allocate memory
 	 */
 	if (!ioc->spi_data.nvram) {
 		int	 sz;
@@ -4446,12 +4458,17 @@
 	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 @@
 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 @@
 		/* 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 @@
 		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 @@
 	 */
 	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 @@
 	/* 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_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_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 @@
 	 * 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 @@
 	} 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 @@
 			 */
 			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_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 @@
 fusion_exit(void)
 {
 	MPT_ADAPTER *this;
+	struct pci_dev *pdev = NULL;
 
 	dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
 
@@ -5861,8 +5983,13 @@
 
 		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);
diff -Nru a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
--- a/drivers/message/fusion/mptbase.h	Thu Jan  2 15:40:31 2003
+++ b/drivers/message/fusion/mptbase.h	Thu Jan  2 15:40:31 2003
@@ -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)  \
@@ -134,8 +134,10 @@
 #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 @@
 #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 @@
 #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_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...
diff -Nru a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
--- a/drivers/message/fusion/mptctl.c	Thu Jan  2 15:40:31 2003
+++ b/drivers/message/fusion/mptctl.c	Thu Jan  2 15:40:31 2003
@@ -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 @@
 #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");
diff -Nru a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
--- a/drivers/message/fusion/mptctl.h	Thu Jan  2 15:40:31 2003
+++ b/drivers/message/fusion/mptctl.h	Thu Jan  2 15:40:31 2003
@@ -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 $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
--- a/drivers/message/fusion/mptscsih.c	Thu Jan  2 15:40:31 2003
+++ b/drivers/message/fusion/mptscsih.c	Thu Jan  2 15:40:31 2003
@@ -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 @@
 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,6 +272,436 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
+ *  Private inline 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 inline 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;
+
+	/*  Must be data _IN!  */
+	default:
+		return SCSI_DATA_READ;
+	}
+} /* mptscsih_io_direction() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	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;
+
+		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);
+
+	} else {
+		SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+		pSge->FlagsLength = cpu_to_le32(flagslength);
+		pSge->Address = cpu_to_le32(dma_addr);
+	}
+} /* mptscsih_add_sge() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	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;
+
+		pChain->Length = cpu_to_le16(length);
+		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+
+		pChain->NextChainOffset = next;
+
+		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() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	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;
+
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
+
+		int offset;
+
+		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);
+
+
+	*retIndex = chain_idx;
+
+	dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
+			hd->ioc->name, *retIndex, chainBuf));
+
+	return rc;
+} /* mptscsih_getFreeChainBuffer() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	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
@@ -294,7 +722,7 @@
 	MPT_SCSI_HOST	*hd;
 	SCSIIORequest_t	*pScsiReq;
 	SCSIIOReply_t	*pScsiReply;
-#ifndef MPT_SCSI_USE_NEW_EH
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
 	unsigned long	 flags;
 #endif
 	u16		 req_idx;
@@ -305,7 +733,6 @@
 	    (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;
 	}
 
@@ -411,12 +838,12 @@
 #ifndef MPT_SCSI_USE_NEW_EH
 			search_taskQ_for_cmd(sc, hd);
 #endif
-			/* Linux handles an unsolicited DID_RESET better 
+			/* Linux handles an unsolicited DID_RESET better
 			 * than an unsolicited DID_ABORT.
 			 */
 			sc->result = DID_RESET << 16;
 
-			/* GEM Workaround. */ 
+			/* GEM Workaround. */
 			if (hd->is_spi)
 				mptscsih_no_negotiate(hd, sc->target);
 			break;
@@ -428,7 +855,7 @@
 #endif
 			sc->result = DID_RESET << 16;
 
-			/* GEM Workaround. */ 
+			/* GEM Workaround. */
 			if (hd->is_spi)
 				mptscsih_no_negotiate(hd, sc->target);
 			break;
@@ -506,7 +933,7 @@
 				;
 			} 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 @@
 
 	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 @@
 	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 @@
 			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 @@
 	 * 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 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int BeenHereDoneThat = 0;
+static char *info_kbuf = NULL;
 
 /*  SCSI host fops start here...  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1263,9 +1693,10 @@
 #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 @@
 				} 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 @@
 				 */
 				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 @@
 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
@@ -1731,7 +2175,7 @@
 const char *
 mptscsih_info(struct Scsi_Host *SChost)
 {
-	MPT_SCSI_HOST *h;
+	MPT_SCSI_HOST *h = NULL;
 	int size = 0;
 
 	if (info_kbuf == NULL)
@@ -1740,12 +2184,307 @@
 
 	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';
+	if (h) {
+		mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
+		info_kbuf[size-1] = '\0';
+	}
 
 	return info_kbuf;
 }
 
+struct info_str {
+	char *buffer;
+	int   length;
+	int   offset;
+	int   pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->length)
+		len = info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+
+	if (info->pos < info->offset) {
+	        data += (info->offset - info->pos);
+	        len  -= (info->offset - info->pos);
+	}
+
+	if (len > 0) {
+                memcpy(info->buffer + info->pos, data, len);
+                info->pos += len;
+	}
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[81];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+	return len;
+}
+
+static int mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
+{
+	struct info_str info;
+
+	info.buffer	= pbuf;
+	info.length	= len;
+	info.offset	= offset;
+	info.pos	= 0;
+
+	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);
+		}
+		break;
+	}
+}
+
+#define is_digit(c)	((c) >= '0' && (c) <= '9')
+#define digit_to_bin(c)	((c) - '0')
+#define is_space(c)	((c) == ' ' || (c) == '\t')
+
+static int skip_spaces(char *ptr, int len)
+{
+	int cnt, c;
+
+	for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --);
+
+	return (len - cnt);
+}
+
+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;
+
+	return (len - cnt);
+}
+
+
+static int is_keyword(char *ptr, int len, char *verb)
+{
+	int verb_len = strlen(verb);
+
+	if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
+		return verb_len;
+	else
+		return 0;
+}
+
+#define SKIP_SPACES(min_spaces)						\
+	if ((arg_len = skip_spaces(ptr,len)) < (min_spaces))		\
+		return -EINVAL;						\
+	ptr += arg_len;							\
+	len -= arg_len;
+
+#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 ((arg_len = is_keyword(ptr, len, "getspeed")) != 0)
+		uc->cmd = UC_GET_SPEED;
+	else
+		arg_len = 0;
+
+	dprintk(("user_command:  arg_len=%d, cmd=%ld\n", arg_len, uc->cmd));
+
+	if (!arg_len)
+		return -EINVAL;
+
+	ptr += arg_len;
+	len -= arg_len;
+
+	switch(uc->cmd) {
+		case UC_GET_SPEED:
+			SKIP_SPACES(1);
+			GET_INT_ARG(target);
+			uc->target = target;
+			break;
+	}
+
+	dprintk(("user_command: target=%ld len=%d\n", uc->target, len));
+
+	if (len)
+		return -EINVAL;
+	else {
+		/* process this command ...
+		 */
+		mptscsih_exec_user_cmd(ioc, uc);
+	}
+	/* Not yet implemented */
+	return length;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	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;
+
+	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 {
+		if (start)
+			*start = buffer;
+
+		size = mptscsih_host_info(ioc, buffer, offset, length);
+	}
+
+	return size;
+}
+
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 	static int max_qd = 1;
 #if 0
@@ -1777,16 +2516,16 @@
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	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 
+ *	@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 
+ *	Handles the call to mptbase for posting request and queue depth
  *	tracking.
  *
  *	Returns none.
  */
-static void
+static inline void
 mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
 {
 	/* Main banana... */
@@ -1973,12 +2712,11 @@
 
 	/*
 	 *  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];
-	for (ii=cmd_len; ii < 16; ii++)
-		pScsiReq->CDB[ii] = 0;
 
 	/* DataLength */
 	pScsiReq->DataLength = cpu_to_le32(datalen);
@@ -1993,7 +2731,7 @@
 	rc = SUCCESS;
 	if (datalen == 0) {
 		/* Add a NULL SGE */
-		mpt_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+		mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
 			(dma_addr_t) -1);
 	} else {
 		/* Add a 32 or 64 bit SGE */
@@ -2057,24 +2795,25 @@
 				}
 
 #ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-				if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) {
+				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); 
+						MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
 
 						SCHEDULE_TASK(&mptscsih_dvTask);
 					} else {
 						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
 					}
-					hd->ioc->spi_data.forceDv = 0;
+					hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
 				}
 
 				/* Trying to do DV to this target, extend timeout.
-				 * Wait to issue intil flag is clear 
+				 * Wait to issue intil flag is clear
 				 */
 				if (dvStatus & MPT_SCSICFG_DV_PENDING) {
 					mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
@@ -2153,283 +2892,6 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	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));
-
-		mpt_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);
-		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++;
-	}
-
-	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);
-		mpt_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.
-			 */
-			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.
-		 */
-
-		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));
-			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);
-		}
-
-		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_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;
-
-	//spin_lock_irqsave(&hd->FreeChainQlock, flags);
-	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-	if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
-
-		int offset;
-
-		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->FreeChainQlock, flags);
-	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-
-
-	*retIndex = chain_idx;
-
-	dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
-			hd->ioc->name, *retIndex, chainBuf));
-
-	return rc;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
  *	mptscsih_freeChainBuffers - Function to free chain buffers associated
  *	with a SCSI IO request
  *	@hd: Pointer to the MPT_SCSI_HOST instance
@@ -2547,8 +3009,8 @@
 
 #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 @@
 
 	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 @@
 	}
 
 	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 @@
 
 	/* 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 @@
 	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_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 @@
 		 *  (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 @@
 		 *  (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 @@
  *	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 @@
 			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 @@
 
 			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 @@
 
 #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 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* 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 @@
 
 		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 @@
 
 	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 @@
 			
 			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 @@
 						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 @@
 		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 @@
 	}
 
 	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 @@
 					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 @@
 #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 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- * 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 @@
 		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 @@
 		/* 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 @@
 			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 @@
 	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 @@
 	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 @@
 	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 @@
 			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 @@
 
 	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 @@
 	/* 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 @@
 
 		/* 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 @@
 			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 @@
 					 * 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 @@
 				}
 
 
-			} 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 @@
 						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 @@
 							patt = -1;
 							continue;
 						}
-					} 
+					}
 					goto target_done;
 				}
 				else
@@ -7048,7 +7474,7 @@
 			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 @@
 		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 @@
 	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 @@
 	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;
diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
--- a/drivers/message/fusion/mptscsih.h	Thu Jan  2 15:40:31 2003
+++ b/drivers/message/fusion/mptscsih.h	Thu Jan  2 15:40:31 2003
@@ -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 $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -73,9 +73,16 @@
  *	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 @@
 #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 @@
 #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 @@
 
 #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 @@
 #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,	\
Received on Thu Jan 02 17:01:52 2003

This archive was generated by hypermail 2.1.8 : 2005-08-02 09:20:11 EST