patch-2.4.21 linux-2.4.21/drivers/message/fusion/mptscsih.c

Next file: linux-2.4.21/drivers/message/fusion/mptscsih.h
Previous file: linux-2.4.21/drivers/message/fusion/mptlan.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/message/fusion/mptscsih.c linux-2.4.21/drivers/message/fusion/mptscsih.c
@@ -26,7 +26,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.101 2002/09/05 22:30:11 pdelaney Exp $
+ *  $Id: mptscsih.c,v 1.106 2003/01/28 21:31:57 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -78,7 +78,9 @@
 #include <linux/reboot.h>	/* notifier code */
 #include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
 #include "../../scsi/sd.h"
+#endif
 
 #include "mptbase.h"
 #include "mptscsih.h"
@@ -110,6 +112,7 @@
 #define MPT_SCANDV_SENSE		(0x00000002)
 #define MPT_SCANDV_SOME_ERROR		(0x00000004)
 #define MPT_SCANDV_SELECTION_TIMEOUT	(0x00000008)
+#define MPT_SCANDV_ISSUE_SENSE		(0x00000010)
 
 #define MPT_SCANDV_MAX_RETRIES		(10)
 
@@ -156,14 +159,11 @@
 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);
 #ifndef MPT_SCSI_USE_NEW_EH
 static void	search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);
@@ -182,7 +182,9 @@
 
 static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
 void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
+#ifdef MPT_SAVE_AUTOSENSE
 static void	clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
+#endif
 static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
 static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
 static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
@@ -197,8 +199,8 @@
 static int	mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
 static void	mptscsih_domainValidation(void *hd);
 static int	mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
-static void	mptscsih_qas_check(MPT_SCSI_HOST *hd);
-static void	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
+static void	mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
+static int	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
 static void	mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
 static void	mptscsih_fillbuf(char *buffer, int size, int index, int width);
 #endif
@@ -243,7 +245,7 @@
  */
 static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED;
 static int mytaskQ_bh_active = 0;
-static struct tq_struct	mptscsih_ptaskfoo;
+static struct mpt_work_struct	mptscsih_ptaskfoo;
 static atomic_t	mpt_taskQdepth;
 #endif
 
@@ -254,7 +256,7 @@
 static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;
 static int dvtaskQ_active = 0;
 static int dvtaskQ_release = 0;
-static struct tq_struct	mptscsih_dvTask;
+static struct mpt_work_struct	mptscsih_dvTask;
 #endif
 
 /*
@@ -270,164 +272,590 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	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);
-
-		/* 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);
+#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;
 
-		mptscsih_freeChainBuffers(hd, req_idx);
-		return 1;
-	}
+	/*  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;
 
-	dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
-			ioc->name, mf, mr, sc, req_idx));
+	/*  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;
 
-	atomic_dec(&queue_depth);
+	case VERIFY:
+		if (cmd->cmnd[1] & 0x02)	/* VERIFY:BYTCHK (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;
+	case RESERVE_10:
+		if (cmd->cmnd[1] & 0x03)	/* RESERVE:{LongID|Extent} (data out phase)? */
+			return SCSI_DATA_WRITE;
+		else
+			return SCSI_DATA_NONE;
 
-#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-	if (hd->is_spi) {
-		u32 qtag = le32_to_cpu(pScsiReq->Control);
-		if (qtag & MPI_SCSIIO_CONTROL_UNTAGGED)
-			hd->ioc->spi_data.iocntr[sc->target]--;
+	/*  Must be data _IN!  */
+	default:
+		return SCSI_DATA_READ;
 	}
-#endif
+} /* 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;
+
+		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);
 
-		/* If regular Inquiry cmd - save inquiry data
-		 */
-		if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {
-			int	 dlen;
+	} else {
+		SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+		pSge->FlagsLength = cpu_to_le32(flagslength);
+		pSge->Address = cpu_to_le32(dma_addr);
+	}
+} /* mptscsih_add_sge() */
 
-			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);
-			}
-		}
-		clear_sense_flag(hd, pScsiReq);
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	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 {
-		u32	 xfer_cnt;
-		u16	 status;
-		u8	 scsi_state;
+		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() */
 
-		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-		scsi_state = pScsiReply->SCSIState;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	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;
 
-		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)));
+	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+	if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
 
-		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
-			copy_sense_data(sc, hd, mf, pScsiReply);
+		int offset;
 
-		/*
-		 *  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)));
-		}
+		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);
 
-		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;
+	*retIndex = chain_idx;
 
-		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */
-			/* Spoof to SCSI Selection Timeout! */
-			sc->result = DID_NO_CONNECT << 16;
-			break;
+	dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
+			hd->ioc->name, *retIndex, chainBuf));
 
-		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;
+	return rc;
+} /* mptscsih_getFreeChainBuffer() */
 
-			/* GEM Workaround. */ 
-			if (hd->is_spi)
-				mptscsih_no_negotiate(hd, sc->target);
-			break;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	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;
 
-		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */
-		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */
+	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. */ 
+			/* GEM Workaround. */
 			if (hd->is_spi)
 				mptscsih_no_negotiate(hd, sc->target);
 			break;
@@ -443,17 +871,21 @@
 			 *  precedence!
 			 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+#ifdef MPT_SAVE_AUTOSENSE
 			clear_sense_flag(hd, pScsiReq);
-			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#endif
+			if (scsi_state == 0) {
+				;
+			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
 				/* Have already saved the status and sense data
 				 */
 				;
-			} else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+			} else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
 				/* What to do?
 				 */
 				sc->result = DID_SOFT_ERROR << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
 				/*  Not real sure here either...  */
 				sc->result = DID_RESET << 16;
 			}
@@ -494,11 +926,14 @@
 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+#ifdef MPT_SAVE_AUTOSENSE
 			clear_sense_flag(hd, pScsiReq);
-
-			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#endif
+			if (scsi_state == 0) {
+				;
+			} 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.
@@ -527,7 +962,7 @@
 #endif
 
 			}
-			else if (pScsiReply->SCSIState &
+			else if (scsi_state &
 			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
 			   ) {
 				/*
@@ -535,11 +970,11 @@
 				 */
 				sc->result = DID_SOFT_ERROR << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
 				/*  Not real sure here either...  */
 				sc->result = DID_RESET << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
+			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
 				/* Device Inq. data indicates that it supports
 				 * QTags, but rejects QTag messages.
 				 * This command completed OK.
@@ -617,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 */
@@ -886,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
 
@@ -903,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.
 			 */
@@ -946,11 +1383,6 @@
 			mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
 		}
 	}
-#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-	/* Clear untagged counting array */
-	for (ii= 0; ii < MPT_MAX_SCSI_DEVICES; ii++)
-		hd->ioc->spi_data.iocntr[ii] = 0;
-#endif
 
 	return;
 }
@@ -1035,21 +1467,13 @@
 	MPT_FRAME_HDR	*chain;
 	u8		*mem;
 	unsigned long	flags;
-	int		sz, ii, numChain;
+	int		sz, ii, num_chain;
+	int 		scale, num_sge;
 
-
-        /* Chain buffer allocations
-	 * Allocate and initialize tracker structures
+	/* ReqToChain size must equal the req_depth
+	 * index = req_idx
 	 */
-	if (hd->ioc->req_sz <= 64)
-		numChain = MPT_SG_REQ_64_SCALE * hd->ioc->req_depth;
-	else if (hd->ioc->req_sz <= 96)
-		numChain = MPT_SG_REQ_96_SCALE * hd->ioc->req_depth;
-	else
-		numChain = MPT_SG_REQ_128_SCALE * hd->ioc->req_depth;
-
-	sz = numChain * sizeof(int);
-
+	sz = hd->ioc->req_depth * sizeof(int);
 	if (hd->ReqToChain == NULL) {
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
@@ -1061,6 +1485,38 @@
 	}
 	memset(mem, 0xFF, sz);
 
+
+	/* ChainToChain size must equal the total number
+	 * of chain buffers to be allocated.
+	 * index = chain_idx
+	 *
+	 * 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
+	 * scale = num sge per chain buffer if no chain element
+	 */
+	scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+	if (sizeof(dma_addr_t) == sizeof(u64))
+		num_sge =  scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+	else
+		num_sge =  1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+
+	num_chain = 1;
+	while (hd->max_sge - num_sge > 0) {
+		num_chain++;
+		num_sge += (scale - 1);
+	}
+	num_chain++;
+
+	if ((int) hd->ioc->chip_type > (int) FC929)
+		num_chain *= MPT_SCSI_CAN_QUEUE;
+	else
+		num_chain *= MPT_FC_CAN_QUEUE;
+
+	hd->num_chain = num_chain;
+
+	sz = num_chain * sizeof(int);
 	if (hd->ChainToChain == NULL) {
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
@@ -1072,10 +1528,10 @@
 	}
 	memset(mem, 0xFF, sz);
 
+	sz = num_chain * hd->ioc->req_sz;
 	if (hd->ChainBuffer == NULL) {
 		/* Allocate free chain buffer pool
 		 */
-		sz = numChain * hd->ioc->req_sz;
 		mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);
 		if (mem == NULL)
 			return -1;
@@ -1101,7 +1557,7 @@
 	/* Post the chain buffers to the FreeChainQ.
 	 */
 	mem = (u8 *)hd->ChainBuffer;
-	for (ii=0; ii < numChain; ii++) {
+	for (ii=0; ii < num_chain; ii++) {
 		chain = (MPT_FRAME_HDR *) mem;
 		Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR);
 		mem += hd->ioc->req_sz;
@@ -1148,6 +1604,7 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int BeenHereDoneThat = 0;
+static char *info_kbuf = NULL;
 
 /*  SCSI host fops start here...  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1236,10 +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) {
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&this->FreeQlock, flags);
 				sh->io_port = 0;
 				sh->n_io_port = 0;
 				sh->irq = 0;
@@ -1266,12 +1723,23 @@
 				}
 				sh->max_lun = MPT_LAST_LUN + 1;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
+				sh->max_sectors = MPT_SCSI_MAX_SECTORS;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) || defined CONFIG_HIGHIO
+				sh->highmem_io = 1;
+#endif
 				sh->this_id = this->pfacts[portnum].PortSCSIID;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)
 				/* OS entry to allow host drivers to force
 				 * a queue depth on a per device basis.
 				 */
 				sh->select_queue_depths = mptscsih_select_queue_depths;
+#endif
+				/* Required entry.
+				 */
+				sh->unique_id = this->id;
 
 				/* Verify that we won't exceed the maximum
 				 * number of chain buffers
@@ -1289,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 */
@@ -1303,10 +1771,11 @@
 				 */
 				scsi_set_pci_device(sh, this->pcidev);
 
-				restore_flags(flags);
+				spin_unlock_irqrestore(&this->FreeQlock, flags);
 
 				hd = (MPT_SCSI_HOST *) sh->hostdata;
 				hd->ioc = this;
+				hd->max_sge = sh->sg_tablesize;
 
 				if ((int)this->chip_type > (int)FC929)
 					hd->is_spi = 1;
@@ -1465,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
@@ -1546,7 +2028,6 @@
 		int szc2chain = 0;
 		int szchain = 0;
 		int szQ = 0;
-		int scale;
 
 		/* Synchronize disk caches
 		 */
@@ -1554,13 +2035,6 @@
 
 		sz1 = sz2 = sz3 = 0;
 
-		if (hd->ioc->req_sz <= 64)
-			scale = MPT_SG_REQ_64_SCALE;
-		else if (hd->ioc->req_sz <= 96)
-			scale = MPT_SG_REQ_96_SCALE;
-		else
-			scale = MPT_SG_REQ_128_SCALE;
-
 		if (hd->ScsiLookup != NULL) {
 			sz1 = hd->ioc->req_depth * sizeof(void *);
 			kfree(hd->ScsiLookup);
@@ -1568,837 +2042,660 @@
 		}
 
 		if (hd->ReqToChain != NULL) {
-			szr2chain = scale * hd->ioc->req_depth * sizeof(int);
+			szr2chain = hd->ioc->req_depth * sizeof(int);
 			kfree(hd->ReqToChain);
 			hd->ReqToChain = NULL;
 		}
 
 		if (hd->ChainToChain != NULL) {
-			szc2chain = scale * hd->ioc->req_depth * sizeof(int);
+			szc2chain = hd->num_chain * sizeof(int);
 			kfree(hd->ChainToChain);
 			hd->ChainToChain = NULL;
 		}
 
-		if (hd->ChainBuffer != NULL) {
-			sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz;
-			szchain = szr2chain + szc2chain + sz2;
-
-			pci_free_consistent(hd->ioc->pcidev, sz2,
-				    hd->ChainBuffer, hd->ChainBufferDMA);
-			hd->ChainBuffer = NULL;
-		}
-
-		if (hd->memQ != NULL) {
-			szQ = host->can_queue * sizeof(MPT_DONE_Q);
-			kfree(hd->memQ);
-			hd->memQ = NULL;
-		}
-
-		if (hd->Targets != NULL) {
-			int max, ii;
-
-			/*
-			 * Free any target structures that were allocated.
-			 */
-			if (hd->is_spi) {
-				max = MPT_MAX_SCSI_DEVICES;
-			} else {
-				max = MPT_MAX_FC_DEVICES;
-			}
-			for (ii=0; ii < max; ii++) {
-				if (hd->Targets[ii]) {
-					kfree(hd->Targets[ii]);
-					hd->Targets[ii] = NULL;
-					sztarget += sizeof(VirtDevice);
-				}
-			}
-
-			/*
-			 * Free pointer array.
-			 */
-			sz3 = max * sizeof(void *);
-			kfree(hd->Targets);
-			hd->Targets = NULL;
-		}
-
-		dprintk((MYIOC_s_INFO_FMT "Free'd ScsiLookup (%d), chain (%d) and Target (%d+%d) memory\n",
-				hd->ioc->name, sz1, szchain, sz3, sztarget));
-		dprintk(("Free'd done and free Q (%d) memory\n", szQ));
-	}
-	/* NULL the Scsi_Host pointer
-	 */
-	hd->ioc->sh = NULL;
-	scsi_unregister(host);
-
-	if (mpt_scsi_hosts) {
-		if (--mpt_scsi_hosts == 0) {
-			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 0;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	mptscsih_halt - Process the reboot notification
- *	@nb: Pointer to a struct notifier_block (ignored)
- *	@event: event (SYS_HALT, SYS_RESTART, SYS_POWER_OFF)
- *	@buf: Pointer to a data buffer (ignored)
- *
- *	This routine called if a system shutdown or reboot is to occur.
- *
- *	Return NOTIFY_DONE if this is something other than a reboot message.
- *		NOTIFY_OK if this is a reboot message.
- */
-static int
-mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
-{
-	MPT_ADAPTER *ioc = NULL;
-	MPT_SCSI_HOST *hd = NULL;
-
-	/* Ignore all messages other than reboot message
-	 */
-	if ((event != SYS_RESTART) && (event != SYS_HALT)
-		&& (event != SYS_POWER_OFF))
-		return (NOTIFY_DONE);
-
-	for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc =	mpt_adapter_find_next(ioc)) {
-		/* Flush the cache of this adapter
-		 */
-		if (ioc->sh) {
-			hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
-			if (hd) {
-				mptscsih_synchronize_cache(hd, 0);
-			}
-		}
-	}
-
-	unregister_reboot_notifier(&mptscsih_notifier);
-	return NOTIFY_OK;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *	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
- *
- *	(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)
- */
-int
-mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
-{
-	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;
+		if (hd->ChainBuffer != NULL) {
+			sz2 = hd->num_chain * hd->ioc->req_sz;
+			szchain = szr2chain + szc2chain + sz2;
 
-	pTarget = hd->Targets[target];
+			pci_free_consistent(hd->ioc->pcidev, sz2,
+				    hd->ChainBuffer, hd->ChainBufferDMA);
+			hd->ChainBuffer = NULL;
+		}
 
-	dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
-			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
+		if (hd->memQ != NULL) {
+			szQ = host->can_queue * sizeof(MPT_DONE_Q);
+			kfree(hd->memQ);
+			hd->memQ = NULL;
+		}
 
-	/* 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 (hd->Targets != NULL) {
+			int max, ii;
 
-		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;
+			/*
+			 * Free any target structures that were allocated.
+			 */
+			if (hd->is_spi) {
+				max = MPT_MAX_SCSI_DEVICES;
 			} else {
-				struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
-				if (sg)
-					dest = (u8 *)(ulong)sg_dma_address(sg);
+				max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
 			}
-
-			if (dest) {
-				sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen);
-				memcpy(dest, pTarget->sense, sz);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-				SCpnt->resid = SCpnt->request_bufflen - sz;
-#endif
-				SCpnt->result = 0;
-				SCpnt->scsi_done(SCpnt);
-
-				//sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
-
-				return 0;
+			for (ii=0; ii < max; ii++) {
+				if (hd->Targets[ii]) {
+					kfree(hd->Targets[ii]);
+					hd->Targets[ii] = NULL;
+					sztarget += sizeof(VirtDevice);
+				}
 			}
+
+			/*
+			 * Free pointer array.
+			 */
+			sz3 = max * sizeof(void *);
+			kfree(hd->Targets);
+			hd->Targets = NULL;
 		}
-	}
 
-	if (hd->resetPending) {
-		/* Prevent new commands from being issued
-		 * while reloading the FW.
-		 */
-		did_errcode = 1;
-		goto did_error;
+		dprintk((MYIOC_s_INFO_FMT "Free'd ScsiLookup (%d), chain (%d) and Target (%d+%d) memory\n",
+				hd->ioc->name, sz1, szchain, sz3, sztarget));
+		dprintk(("Free'd done and free Q (%d) memory\n", szQ));
 	}
-
-	/*
-	 *  Put together a MPT SCSI request...
+	/* NULL the Scsi_Host pointer
 	 */
-	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;
-	}
-
-	pScsiReq = (SCSIIORequest_t *) mf;
-
-	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+	hd->ioc->sh = NULL;
+	scsi_unregister(host);
 
-	ADD_INDEX_LOG(my_idx);
+	if (mpt_scsi_hosts) {
+		if (--mpt_scsi_hosts == 0) {
+			mpt_reset_deregister(ScsiDoneCtx);
+			dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
 
-	/*
-	 *  The scsi layer should be handling this stuff
-	 *  (In 2.3.x it does -DaveM)
-	 */
+			mpt_event_deregister(ScsiDoneCtx);
+			dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
 
-	/*  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;
-	}
+			mpt_deregister(ScsiScanDvCtx);
+			mpt_deregister(ScsiTaskCtx);
+			mpt_deregister(ScsiDoneCtx);
 
-	/* 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;
+			if (info_kbuf != NULL)
+				kfree(info_kbuf);
 		}
-		else
-			qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
 	}
-	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);
-
-	/*
-	 *  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;
 
-	/* DataLength */
-	pScsiReq->DataLength = cpu_to_le32(datalen);
+	return 0;
+}
 
-	/* SenseBuffer low address */
-	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
-					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptscsih_halt - Process the reboot notification
+ *	@nb: Pointer to a struct notifier_block (ignored)
+ *	@event: event (SYS_HALT, SYS_RESTART, SYS_POWER_OFF)
+ *	@buf: Pointer to a data buffer (ignored)
+ *
+ *	This routine called if a system shutdown or reboot is to occur.
+ *
+ *	Return NOTIFY_DONE if this is something other than a reboot message.
+ *		NOTIFY_OK if this is a reboot message.
+ */
+static int
+mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
+{
+	MPT_ADAPTER *ioc = NULL;
+	MPT_SCSI_HOST *hd = NULL;
 
-	/* Now add the SG list
-	 * Always have a SGE even if null length.
+	/* Ignore all messages other than reboot message
 	 */
-	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);
+	if ((event != SYS_RESTART) && (event != SYS_HALT)
+		&& (event != SYS_POWER_OFF))
+		return (NOTIFY_DONE);
+
+	for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc =	mpt_adapter_find_next(ioc)) {
+		/* Flush the cache of this adapter
+		 */
+		if (ioc->sh) {
+			hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+			if (hd) {
+				mptscsih_synchronize_cache(hd, 0);
+			}
+		}
 	}
 
+	unregister_reboot_notifier(&mptscsih_notifier);
+	return NOTIFY_OK;
+}
 
-	if (rc == SUCCESS) {
-		hd->ScsiLookup[my_idx] = SCpnt;
-		SCpnt->host_scribble = NULL;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	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 = NULL;
+	int size = 0;
 
-#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 (info_kbuf == NULL)
+		if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
+			return info_kbuf;
 
-			if (dropCounter == DROP_THIS_CMD) {
-				dropCounter = 0;
+	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 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 info_kbuf;
+}
 
-					return 0;
-				}
-			}
-		}
-#endif
+struct info_str {
+	char *buffer;
+	int   length;
+	int   offset;
+	int   pos;
+};
 
-		/* SCSI specific processing */
-		issueCmd = 1;
-		if (hd->is_spi) {
-			int dvStatus = hd->ioc->spi_data.dvStatus[target];
+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 (dvStatus || hd->ioc->spi_data.forceDv) {
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
 
-				/* 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;
-				}
+	if (info->pos < info->offset) {
+	        data += (info->offset - info->pos);
+	        len  -= (info->offset - info->pos);
+	}
 
-#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);
-						mptscsih_dvTask.sync = 0;
-						mptscsih_dvTask.routine = mptscsih_domainValidation;
-						mptscsih_dvTask.data = (void *) hd;
+	if (len > 0) {
+                memcpy(info->buffer + info->pos, data, len);
+                info->pos += len;
+	}
+}
 
-						SCHEDULE_TASK(&mptscsih_dvTask);
-					} else {
-						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
-					}
-					hd->ioc->spi_data.forceDv = 0;
-				}
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[81];
+	int 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;
-				}
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
 
-				if (qtag == MPI_SCSIIO_CONTROL_UNTAGGED)
-					hd->ioc->spi_data.iocntr[target]++;
+	copy_mem_info(info, buf, len);
+	return len;
+}
 
-				/* Set the DV flags.
-				 */
-				if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
-					mptscsih_set_dvflags(hd, pScsiReq);
-#endif
-			}
-		}
+static int mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
+{
+	struct info_str info;
 
-		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);
+	info.buffer	= pbuf;
+	info.length	= len;
+	info.offset	= offset;
+	info.pos	= 0;
 
-				/* Save the mf pointer
-				 */
-				buffer->argp = (void *)mf;
+	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);
 
-				/* 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);
-			}
+	return ((info.pos > info.offset) ? info.pos - info.offset : 0);
+}
+
+static int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len)
+{
+	/* Not yet implemented */
+	return len;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	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 {
-		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	 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;
+
+		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);
+			}
 
-		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 (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);
+	/*  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;
+	}
 
-		sg++;		/* Get next SG element from the OS */
-		psge += (sizeof(u32) + sizeof(dma_addr_t));
-		sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
-		sg_done++;
+	/* Default to untagged. Once a target structure has been allocated,
+	 * use the Inquiry data to determine if device supports tagged.
+	 */
+	if (   pTarget
+	    && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+	    && (SCpnt->device->tagged_supported)) {
+		scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
+	} else {
+		scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
 	}
 
-	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;
+	/* 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);
 
-		/* 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);
+	/*
+	 *  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];
 
-		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++;
+	/* DataLength */
+	pScsiReq->DataLength = cpu_to_le32(datalen);
 
-		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.
-		 */
+	/* SenseBuffer low address */
+	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
-		dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
-				hd->ioc->name, sg_done));
+	/* 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);
+	}
 
-		/* 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);
-		}
+	if (rc == SUCCESS) {
+		hd->ScsiLookup[my_idx] = SCpnt;
+		SCpnt->host_scribble = NULL;
 
-		sges_left -= sg_done;
+#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;
 
-		/* 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;
+				/* 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);
 
-		/* Update the tracking arrays.
-		 * If chainSge == NULL, update ReqToChain, else ChainToChain
-		 */
-		if (chainSge) {
-			hd->ChainToChain[chain_idx] = newIndex;
-		} else {
-			hd->ReqToChain[req_idx] = newIndex;
+					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;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2520,8 +2817,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
@@ -2531,14 +2828,13 @@
 
 		/* Isse the Task Mgmt request.
 		 */
+		if (hd->hard_resets < -1)
+			hd->hard_resets++;
 		rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, sleepFlag);
 		if (rc) {
-#ifdef MPT_SCSI_USE_NEW_EH
-			hd->tmState = TM_STATE_ERROR;
-#endif
 			printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
 		} else {
-			printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name);
+			dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
 		}
 	}
 #ifdef DROP_TEST
@@ -2549,7 +2845,7 @@
 	}
 #endif
 
-	if (rc) {
+	if (rc || ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw)) {
 		dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n",
 			 hd->ioc->name));
 		rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
@@ -2666,7 +2962,6 @@
 {
 	MPT_SCSI_HOST	*hd;
 	MPT_FRAME_HDR	*mf;
-	unsigned long	 flags;
 	u32		 ctx2abort;
 	int		 scpnt_idx;
 
@@ -2681,10 +2976,11 @@
 		return FAILED;
 	}
 
-	printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n",
-	       hd->ioc->name, SCpnt);
-	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
-	       hd->ioc->name, atomic_read(&queue_depth));
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p, numIOs=%d)\n",
+	       hd->ioc->name, SCpnt, atomic_read(&queue_depth));
+
+	if (hd->timeouts < -1)
+		hd->timeouts++;
 
 	/* Find this command
 	 */
@@ -2738,11 +3034,9 @@
 	ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
 
 	hd->abortSCpnt = SCpnt;
-
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
-	                       SCpnt->target, SCpnt->lun, ctx2abort, CAN_SLEEP) 
-		< 0
-	    || hd->tmState == TM_STATE_ERROR) {
+	                       SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP)
+		< 0) {
 
 		/* The TM request failed and the subsequent FW-reload failed!
 		 * Fatal error case.
@@ -2750,14 +3044,6 @@
 		printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n",
 		       hd->ioc->name, SCpnt);
 
-		/* If command not found, do not do callback,
-		 *  just return failed.  CHECKME
-		 */
-		if (hd->ScsiLookup[scpnt_idx] != NULL) {
-			SCpnt->result = STS_BUSY;
-			SCpnt->scsi_done(SCpnt);
-		}
-
 		/* We must clear our pending flag before clearing our state.
 		 */
 		hd->tmPending = 0;
@@ -2765,34 +3051,8 @@
 
 		return FAILED;
 	}
+	return FAILED;
 
-	/* Our task management request will either complete or time out.  So we
-	 * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, 
-	 * we encountered an error executing the task management request.
-	 */
-	while (hd->tmPending == 1){
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ/4);
-	}
-	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-	if (hd->tmState == TM_STATE_ERROR){
-		hd->tmState = TM_STATE_NONE;
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
-			   "TM timeout error! (sc=%p)\n",
-			   hd->ioc->name,
-			   SCpnt));
-		return FAILED;
-	}
-	hd->tmState = TM_STATE_NONE;
-	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-
-	nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
-		   "Abort was successful! (sc=%p)\n",
-		   hd->ioc->name,
-		   SCpnt));
-
-	return SUCCESS;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2808,7 +3068,6 @@
 mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
 {
 	MPT_SCSI_HOST	*hd;
-	unsigned long	 flags;
 
 	/* If we can't locate our host adapter structure, return FAILED status.
 	 */
@@ -2819,10 +3078,13 @@
 		return FAILED;
 	}
 
-	printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
-	       hd->ioc->name, SCpnt);
-	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
-	       hd->ioc->name, atomic_read(&queue_depth));
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p, numIOs=%d)\n",
+	       hd->ioc->name, SCpnt, atomic_read(&queue_depth));
+
+	/* Unsupported for SCSI. Suppored for FCP
+	 */
+	if (hd->is_spi)
+		return FAILED;
 
 	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
 	 *  If we time out, then we return a FAILED status to the caller.  This
@@ -2838,7 +3100,7 @@
 	}
 
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-	                       SCpnt->target, 0, 0, CAN_SLEEP) 
+	                       SCpnt->target, 0, 0, NO_SLEEP)
 		< 0){
 		/* The TM request failed and the subsequent FW-reload failed!
 		 * Fatal error case.
@@ -2849,34 +3111,8 @@
 		hd->tmState = TM_STATE_NONE;
 		return FAILED;
 	}
-
-	/* Our task management request will either complete or time out.  So we
-	 * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, 
-	 * we encountered an error executing the task management request.
-	 */
-	while (hd->tmPending == 1){
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ/4);
-	}
-	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-	if (hd->tmState == TM_STATE_ERROR){
-		hd->tmState = TM_STATE_NONE;
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
-			   "TM timeout error! (sc=%p)\n",
-			   hd->ioc->name,
-			   SCpnt));
-		return FAILED;
-	}
-	hd->tmState = TM_STATE_NONE;
-	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-
-	nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
-		   "Device reset was successful! (sc=%p)\n",
-		   hd->ioc->name,
-		   SCpnt));
-
 	return SUCCESS;
+
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2892,7 +3128,6 @@
 mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
 {
 	MPT_SCSI_HOST	*hd;
-	unsigned long	 flags;
 
 	/* If we can't locate our host adapter structure, return FAILED status.
 	 */
@@ -2903,10 +3138,11 @@
 		return FAILED;
 	}
 
-	printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n",
-	       hd->ioc->name, SCpnt);
-	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
-	       hd->ioc->name, atomic_read(&queue_depth));
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p, numIOs=%d)\n",
+	       hd->ioc->name, SCpnt, atomic_read(&queue_depth));
+
+	if (hd->timeouts < -1)
+		hd->timeouts++;
 
 	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
 	 *  If we time out, then we return a FAILED status to the caller.  This
@@ -2917,19 +3153,19 @@
 		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
 			   "Timed out waiting for previous TM to complete! "
 			   "(sc = %p)\n",
-			   hd->ioc->name, SCpnt ) );
+			   hd->ioc->name, SCpnt));
 		return FAILED;
 	}
 
 	/* We are now ready to execute the task management request. */
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-	                       0, 0, 0, CAN_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;
@@ -2937,32 +3173,6 @@
 		return FAILED;
 	}
 
-	/* Our task management request will either complete or time out.  So we
-	 * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, 
-	 * we encountered an error executing the task management request.
-	 */
-	while (hd->tmPending == 1){
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ/4);
-	}
-	spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
-	if (hd->tmState == TM_STATE_ERROR){
-		hd->tmState = TM_STATE_NONE;
-		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
-			   "TM timeout error! (sc=%p)\n",
-			   hd->ioc->name,
-			   SCpnt));
-		return FAILED;
-	}
-	hd->tmState = TM_STATE_NONE;
-	spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-
-	nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
-		   "Bus reset was successful! (sc=%p)\n",
-		   hd->ioc->name,
-		   SCpnt));
-
 	return SUCCESS;
 }
 
@@ -2998,11 +3208,11 @@
 	/*  If our attempts to reset the host failed, then return a failed
 	 *  status.  The host will be taken off line by the SCSI mid-layer.
 	 */
-	if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
+	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;
@@ -3018,7 +3228,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.
  *
@@ -3041,9 +3251,7 @@
 			break;
 		}
 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ/4);
-
+		mdelay(250);
 	} while (--loop_count);
 
 	return status;
@@ -3064,7 +3272,7 @@
 {
 	MPT_SCSI_HOST		*hd;
 	MPT_FRAME_HDR		*mf;
-	struct tq_struct	*ptaskfoo;
+	struct mpt_work_struct	*ptaskfoo;
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
@@ -3078,6 +3286,9 @@
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
 		/* Cmd not found in ScsiLookup.
 		 * If found in doneQ, delete from Q.
@@ -3151,7 +3362,7 @@
 	SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
 
 	/* For the time being, force bus reset on any abort
-	 * requests for the 1030 FW.
+	 * requests for the 1030/1035 FW.
 	 */
 	if (hd->is_spi)
 		mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
@@ -3172,10 +3383,8 @@
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
 		 */
-		ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
+		ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+		MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
 
 		SCHEDULE_TASK(ptaskfoo);
 	} else  {
@@ -3200,7 +3409,7 @@
 {
 	MPT_SCSI_HOST		*hd;
 	MPT_FRAME_HDR		*mf;
-	struct tq_struct	*ptaskfoo;
+	struct mpt_work_struct	*ptaskfoo;
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
@@ -3213,6 +3422,9 @@
 		return SCSI_RESET_SUCCESS;
 	}
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
 		/* Cmd not found in ScsiLookup.
 		 * If found in doneQ, delete from Q.
@@ -3302,10 +3514,8 @@
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
 		 */
-		ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
+		ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+		MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
 
 		SCHEDULE_TASK(ptaskfoo);
 	} else  {
@@ -3572,9 +3782,6 @@
 					}
 				}
 			}
-#ifdef MPT_SCSI_USE_NEW_EH
-			hd->tmState = TM_STATE_ERROR;
-#endif
 		} else {
 			dtmprintk((KERN_INFO "  SCSI TaskMgmt SUCCESS!\n"));
 
@@ -3618,6 +3825,9 @@
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
 	hd->tmPending = 0;
 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+#ifdef MPT_SCSI_USE_NEW_EH
+	hd->tmState = TM_STATE_NONE;
+#endif
 
 	return 1;
 }
@@ -3626,13 +3836,23 @@
 /*
  *	This is anyones guess quite frankly.
  */
-
 int
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
+mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
+		sector_t capacity, int *ip)
+{
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+mptscsih_bios_param(Disk * disk, struct block_device *bdev, int *ip)
+{
+	sector_t capacity = disk->capacity;
+#else
 mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
 {
+	unsigned capacity = disk->capacity;
+#endif
 	int size;
 
-	size = disk->capacity;
+	size = capacity;
 	ip[0] = 64;				/* heads			*/
 	ip[1] = 32;				/* sectors			*/
 	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
@@ -3649,13 +3869,49 @@
  *	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)
+int
+mptscsih_slave_attach(Scsi_Device *device)
+{
+	struct Scsi_Host	*host = device->host;
+	VirtDevice		*pTarget;
+	MPT_SCSI_HOST		*hd;
+
+	hd = (MPT_SCSI_HOST *)host->hostdata;
+	if (hd && (hd->Targets != NULL)) {
+		pTarget = hd->Targets[device->id];
+		if (pTarget) {
+			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,
+							MPT_SCSI_CMD_PER_DEV_LOW);
+			}
+#if 0
+			/* Original Code for 2.5 */
+			} else {
+				scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+						device->host->can_queue >> 1);
+			}
+#endif
+		}
+	}
+	return 0;
+}
+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */
 void
 mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
 {
 	struct scsi_device	*device;
 	VirtDevice		*pTarget;
 	MPT_SCSI_HOST		*hd;
-	int			 ii, max;
 
 	for (device = sdList; device != NULL; device = device->next) {
 
@@ -3667,119 +3923,44 @@
 			continue;
 
 		if (hd->Targets != NULL) {
-			if (hd->is_spi)
-				max = MPT_MAX_SCSI_DEVICES;
-			else
-				max = MPT_MAX_FC_DEVICES;
+			pTarget = NULL;
+			if (device->id > sh->max_id) {
+				/* error case, should never happen */
+				device->queue_depth = 1;
+				continue;
+			} else {
+				pTarget = hd->Targets[device->id];
+			}
 
-			for (ii=0; ii < max; ii++) {
-				pTarget = hd->Targets[ii];
-				if (pTarget && !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
+			if (pTarget == NULL) {
+				/* error case - don't know about this device */
+				device->queue_depth = 1;
+			} else if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+				if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
 					device->queue_depth = 1;
-				}
+				else if (((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;
+
+			} else {
+				/* error case - No Inq. Data */
+				device->queue_depth = 1;
 			}
+			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) */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  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
@@ -3815,7 +3996,8 @@
 
 		/* save sense data to the target device
 		 */
-		if (target) {
+		if (hd->is_spi && target) {
+#ifdef MPT_SAVE_AUTOSENSE
 			int sz;
 
 			sz = MIN(pReq->SenseBufferLength, sense_count);
@@ -3823,10 +4005,11 @@
 				sz =  SCSI_STD_SENSE_BYTES;
 			memcpy(target->sense, sense_data, sz);
 			target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE;
+#endif
 
 #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)) {
@@ -3919,7 +4102,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 *
@@ -4087,6 +4270,8 @@
 			ioc->name));
 
 	} else {
+		ScsiCfgData	*pSpi = NULL;
+
 		dtmprintk((MYIOC_s_WARN_FMT "Do Post-Diag Reset handling\n",
 			ioc->name));
 
@@ -4125,6 +4310,9 @@
 		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 		hd->resetPending = 0;
 		hd->numTMrequests = 0;
+#ifdef MPT_SCSI_USE_NEW_EH
+		hd->tmState = TM_STATE_NONE;
+#endif
 
 		/* 6. If there was an internal command,
 		 * wake this process up.
@@ -4146,6 +4334,14 @@
 
 		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n",
 			ioc->name));
+
+
+		/* 8. Set then flag to force DV and re-read IOC Page 3
+		 */
+		pSpi = &ioc->spi_data;
+		pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
+		ddvtprintk(("Set reload IOC Pg3 Flag\n"));
+
 	}
 
 	return 1;		/* currently means nothing really */
@@ -4166,10 +4362,13 @@
 		/* FIXME! */
 		break;
 	case MPI_EVENT_IOC_BUS_RESET:			/* 04 */
-		/* FIXME! */
-		break;
 	case MPI_EVENT_EXT_BUS_RESET:			/* 05 */
-		/* FIXME! */
+		hd = NULL;
+		if (ioc->sh) {
+			hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+			if (hd && (hd->is_spi) && (hd->soft_resets < -1))
+				hd->soft_resets++;
+		}
 		break;
 	case MPI_EVENT_LOGOUT:				/* 09 */
 		/* FIXME! */
@@ -4189,7 +4388,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;
@@ -4205,11 +4404,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;
@@ -4224,6 +4424,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));
+					}
 				}
 			}
 		}
@@ -4506,6 +4716,7 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#if 0
 static int dump_sd(char *foo, unsigned char *sd)
 {
 	int snsLen = 8 + SD_Additional_Sense_Length(sd);
@@ -4518,6 +4729,7 @@
 
 	return l;
 }
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*  Do ASC/ASCQ lookup/grindage to English readable string(s)  */
@@ -4609,6 +4821,15 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
+ *  SCSI Information Report; desired output format...
+ *---
+SCSI Error: (iocnum:target_id:LUN) Status=02h (CHECK CONDITION)
+  Key=6h (UNIT ATTENTION); FRU=03h
+  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+  CDB: 00 00 00 00 00 00 - TestUnitReady
+ *---
+ */
+/*
  *  SCSI Error Report; desired output format...
  *---
 SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
@@ -4632,6 +4853,22 @@
 	unsigned char	 ascq		= SD_ASCQ(ioop->sensePtr);
 	int		 l;
 
+	/* Change the error logging to only report errors on
+	 * read and write commands. Ignore errors on other commands.
+	 * Should this be configurable via proc?
+	 */
+	switch (ioop->cdbPtr[0]) {
+	case READ_6:
+	case WRITE_6:
+	case READ_10:
+	case WRITE_10:
+	case READ_12:
+	case WRITE_12:
+		break;
+	default:
+		return 0;
+	}
+
 	/*
 	 *  More quiet mode.
 	 *  Filter out common, repetitive, warning-type errors...  like:
@@ -4642,6 +4879,7 @@
 	if (sk == SK_NO_SENSE) {
 		return 0;
 	}
+
 	if (	(sk==SK_UNIT_ATTENTION	&& asc==0x29 && (ascq==0x00 || ascq==0x01))
 	     || (sk==SK_NOT_READY	&& asc==0x04 && (ascq==0x01 || ascq==0x02))
 	     || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
@@ -4659,7 +4897,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;
 		}
@@ -4696,20 +4934,12 @@
 	else if (mpt_ScsiOpcodesPtr)
 		opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
 
-	l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n"
-	  "  SCSI_Status=%02Xh (%s)\n"
-	  "  Original_CDB[]:",
-			ioop->DevIDStr,
-			ioop->SCSIStatus,
-			statstr);
-	l += dump_cdb(foo+l, ioop->cdbPtr);
-	if (opstr)
-		l += sprintf(foo+l, " - \"%s\"", opstr);
-	l += sprintf(foo+l, "\n  SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr));
-	l += dump_sd(foo+l, ioop->sensePtr);
-	l += sprintf(foo+l, "\n  SenseKey=%Xh (%s); FRU=%02Xh\n  ASC/ASCQ=%02Xh/%02Xh",
-			sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
-
+	l = sprintf(foo, "SCSI Error: (%s) Status=%02Xh (%s)\n",
+			  ioop->DevIDStr,
+			  ioop->SCSIStatus,
+			  statstr);
+	l += sprintf(foo+l, " Key=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh",
+		  sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
 	{
 		const char	*x1, *x2, *x3, *x4;
 		x1 = x2 = x3 = x4 = "";
@@ -4721,11 +4951,11 @@
 				l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
 		}
 	}
-
-#if 0
-	if (SPECIAL_ASCQ(asc,ascq))
-		l += sprintf(foo+l, " (%02Xh)", ascq);
-#endif
+	l += sprintf(foo+l, "\n CDB:");
+	l += dump_cdb(foo+l, ioop->cdbPtr);
+	if (opstr)
+		l += sprintf(foo+l, " - \"%s\"", opstr);
+	l += sprintf(foo+l, "\n");
 
 	PrintF(("%s\n", foo));
 
@@ -4782,15 +5012,17 @@
 		}
 	}
 
-	if (vdev) {
-		if (hd->ioc->spi_data.isRaid & (1 << target_id))
+	vdev->raidVolume = 0;
+	if (vdev && hd->is_spi) {
+		if (hd->ioc->spi_data.isRaid & (1 << target_id)) {
 			vdev->raidVolume = 1;
-		else
-			vdev->raidVolume = 0;
+			ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id));
+		}
 	}
 
 	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.
 			*/
@@ -4801,14 +5033,15 @@
 
 			/* Update the target capabilities
 			 */
-			if (dlen > 56)
+			if (dlen > 56) {
 				mptscsih_setTargetNegoParms(hd, vdev, data[56]);
-			else
+				vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
+			} else
 				mptscsih_setTargetNegoParms(hd, vdev, 0);
 
 			/* If LUN 0, tape and have not done DV, set the DV flag.
 			 */
-			if ((lun == 0) && ((data[0] & 0x1F) == 0x01)) {
+			if (hd->is_spi && (lun == 0) && ((data[0] & 0x1F) == 0x01)) {
 				ScsiCfgData *pSpi = &hd->ioc->spi_data;
 				if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
 					pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
@@ -4845,6 +5078,15 @@
 	u8 version, nfactor;
 	u8 noQas = 1;
 
+	ddvtprintk((KERN_INFO "set Target: (id %d) byte56 0x%x\n", id, byte56));
+
+	if (!hd->is_spi) {
+		if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+			if (target->inq_data[7] & 0x02)
+				target->tflags |= MPT_TARGET_FLAGS_Q_YES;
+		}
+		return;
+	}
 	/* Set flags based on Inquiry data
 	 */
 	if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
@@ -4863,12 +5105,18 @@
 				 */
 				if ((byte56 & 0x04) == 0)
 					factor = MPT_ULTRA2;
+				else if ((byte56 & 0x03) == 0)
+					factor = MPT_ULTRA160;
 				else
 					factor = MPT_ULTRA320;
 
-				/* bit 1 QAS support, non-raid only
+				/* If RAID, never disable QAS
+				 * else if non RAID, do not disable
+				 *   QAS if bit 1 is set
+				 * bit 1 QAS support, non-raid only
+				 * bit 0 IU support
 				 */
-				if ((target->raidVolume == 0) && (byte56 & 0x02) != 0)
+				if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0))
 					noQas = 0;
 
 				offset = pspi_data->maxSyncOffset;
@@ -4953,6 +5201,7 @@
 			VirtDevice	*vdev;
 			int ii;
 
+			ddvtprintk((KERN_INFO "Disabling QAS!\n"));
 			pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS;
 			for (ii = 0; ii < id; ii++) {
 				vdev = hd->Targets[id];
@@ -4966,6 +5215,7 @@
 	return;
 }
 
+#ifdef MPT_SAVE_AUTOSENSE
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Clear sense valid flag.
@@ -4981,10 +5231,11 @@
 
 	return;
 }
+#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
@@ -5020,7 +5271,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)
@@ -5179,6 +5430,17 @@
 			//negoFlags = MPT_TARGET_NO_NEGO_SYNC;
 		}
 
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+		/* Force to async and narrow if DV has not been executed
+		 * for this ID
+		 */
+		if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
+			width = 0;
+			factor = MPT_ASYNC;
+			offset = 0;
+		}
+#endif
+
 		/* If id is not a raid volume, get the updated
 		 * transmission settings from the target structure.
 		 */
@@ -5258,9 +5520,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);
@@ -5288,13 +5550,6 @@
 	 */
 	del_timer(&hd->TMtimer);
 
-#ifdef MPT_SCSI_USE_NEW_EH
-	/* Set the error flag to 1 so that the function that started the
-	 * task management request knows it timed out.
-	 */
-	hd->tmState = TM_STATE_ERROR;
-#endif
-
 	/* Call the reset handler. Already had a TM request
 	 * timeout - so issue a diagnostic reset
 	 */
@@ -5306,8 +5561,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;
 	}
@@ -5339,7 +5594,7 @@
  *
  *	Remark: Sets a completion code and (possibly) saves sense data
  *	in the IOC member localReply structure.
- *	Used ONLY for bus scan, DV and other internal commands.
+ *	Used ONLY for DV and other internal commands.
  */
 static int
 mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
@@ -5375,10 +5630,13 @@
 	atomic_dec(&queue_depth);
 
 	hd->pLocal = &hd->localReply;
+	hd->pLocal->scsiStatus = 0;
 
 	/* If target struct exists, clear sense valid flag.
 	 */
+#ifdef MPT_SAVE_AUTOSENSE
 	clear_sense_flag(hd, pReq);
+#endif
 
 	if (mr == NULL) {
 		completionCode = MPT_SCANDV_GOOD;
@@ -5390,7 +5648,7 @@
 
 		status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
 
-		ddvprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+		ddvtprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
 			     status, pReply->SCSIState, pReply->SCSIStatus,
 			     le32_to_cpu(pReply->IOCLogInfo)));
 
@@ -5430,7 +5688,9 @@
 					completionCode = MPT_SCANDV_SOME_ERROR;
 
 			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#ifdef MPT_SAVE_AUTOSENSE
 				VirtDevice	*target;
+#endif
 				u8		*sense_data;
 				int		 sz;
 
@@ -5445,25 +5705,33 @@
 							SCSI_STD_SENSE_BYTES);
 				memcpy(hd->pLocal->sense, sense_data, sz);
 
+#ifdef MPT_SAVE_AUTOSENSE
 				target = hd->Targets[pReq->TargetID];
 				if (target) {
 					memcpy(target->sense, sense_data, sz);
 					target->tflags
 						|= MPT_TARGET_FLAGS_VALID_SENSE;
 				}
+#endif
 
 				ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
 						sense_data));
-			} else if (pReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED |
-							MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
+				if (pReq->CDB[0] == CMD_Inquiry)
+					completionCode = MPT_SCANDV_ISSUE_SENSE;
+				else
+					completionCode = MPT_SCANDV_DID_RESET;
+			}
+			else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
 				completionCode = MPT_SCANDV_DID_RESET;
-			} else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
 				completionCode = MPT_SCANDV_DID_RESET;
-			} else {
+			else {
 				/* If no error, this will be equivalent
 				 * to MPT_SCANDV_GOOD
 				 */
-				completionCode = (int) pReply->SCSIStatus;
+				completionCode = MPT_SCANDV_GOOD;
+				hd->pLocal->scsiStatus = pReply->SCSIStatus;
 			}
 			break;
 
@@ -5480,7 +5748,7 @@
 
 		}	/* switch(status) */
 
-		ddvprintk((KERN_NOTICE "  completionCode set to %08xh\n",
+		ddvtprintk((KERN_NOTICE "  completionCode set to %08xh\n",
 				completionCode));
 	} /* end of address reply case */
 
@@ -5532,7 +5800,7 @@
 			if (hd->tmPending) {
 				spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 				return;
-			} else 
+			} else
 				hd->tmPending = 1;
 			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
@@ -5611,7 +5879,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",
@@ -5703,6 +5971,14 @@
 		cmdTimeout = 15;
 		break;
 
+	case CMD_RequestSense:
+		cmdLen = 6;
+		CDB[0] = cmd;
+		CDB[4] = io->size;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		cmdTimeout = 10;
+		break;
+
 	case CMD_ReadBuffer:
 		cmdLen = 10;
 		dir = MPI_SCSIIO_CONTROL_READ;
@@ -5807,6 +6083,12 @@
 	else
 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
 
+	if (cmd == CMD_RequestSense) {
+		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
+		ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
+			hd->ioc->name, cmd));
+	}
+
 	for (ii=0; ii < 16; ii++)
 		pScsiReq->CDB[ii] = CDB[ii];
 
@@ -5926,7 +6208,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) {
@@ -5988,7 +6270,7 @@
 		/* If target Ptr NULL or if this target is NOT a disk, skip.
 		 */
 	//	if (pTarget && ((pTarget->inq_data[0] & 0x1F) == 0)) {
-		if (pTarget) {
+		if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){
 			for (lun=0; lun <= MPT_LAST_LUN; lun++) {
 				/* If LUN present, issue the command
 				 */
@@ -6049,7 +6331,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.
 	 */
@@ -6080,6 +6362,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++) {
@@ -6093,25 +6392,8 @@
 				dvStatus = hd->ioc->spi_data.dvStatus[id];
 
 				if (dvStatus & MPT_SCSICFG_NEED_DV) {
-					VirtDevice *pTarget = hd->Targets[id];
 					did++;
-					if (pTarget && ((pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) == 0)){
-						if (hd->ioc->spi_data.iocntr[id] == 0) {
-							hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
-						} else {
-							/* Wait until not busy
-							 */
-							ddvtprintk((MYIOC_s_NOTE_FMT 
-							" DV Wait: %d untagged and busy. cntr %d\n",
-							ioc->name, id, 
-							hd->ioc->spi_data.iocntr[id]));
-							continue;
-						}
-					} else {
-						hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
-					}
-
-
+					hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
 					hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
 
 					set_current_state(TASK_INTERRUPTIBLE);
@@ -6130,9 +6412,16 @@
 						}
 					}
 
-					mptscsih_doDv(hd, 0, id);
-
-					hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
+					if (mptscsih_doDv(hd, 0, id) == 1) {
+						/* Untagged device was busy, try again
+						 */
+						hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
+						hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
+					} else {
+						/* DV is complete. Clear flags.
+						 */
+						hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
+					}
 
 					if (isPhysDisk) {
 						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
@@ -6148,7 +6437,7 @@
 					post_pendingQ_commands(hd);
 
 					if (hd->ioc->spi_data.noQas)
-						mptscsih_qas_check(hd);
+						mptscsih_qas_check(hd, id);
 				}
 			}
 		}
@@ -6182,7 +6471,7 @@
 
 /* Write SDP1 if no QAS has been enabled
  */
-static void mptscsih_qas_check(MPT_SCSI_HOST *hd)
+static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
 {
 	VirtDevice *pTarget = NULL;
 	int ii;
@@ -6191,6 +6480,9 @@
 		return;
 
 	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+		if (ii == id)
+			continue;
+
 		if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
 			continue;
 
@@ -6231,7 +6523,7 @@
  *
  *	Return: None.
  */
-static void
+static int
 mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
 {
 	MPT_ADAPTER		*ioc = hd->ioc;
@@ -6259,6 +6551,7 @@
 	int			 notDone;
 	int			 patt;
 	int			 repeat;
+	int			 retcode = 0;
 	char			 firstPass = 1;
 	char			 doFallback = 0;
 	char			 readPage0;
@@ -6266,17 +6559,17 @@
 	char			 inq0 = 0;
 
 	if (ioc->spi_data.sdp1length == 0)
-		return;
+		return 0;
 
 	if (ioc->spi_data.sdp0length == 0)
-		return;
+		return 0;
 
 	if (id == ioc->pfacts[portnum].PortSCSIID)
-		return;
+		return 0;
 
 	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));
 
@@ -6292,7 +6585,7 @@
 	dv.cmd = MPT_GET_NVRAM_VALS;
 	mptscsih_dv_parms(hd, &dv, NULL);
 	if ((!dv.max.width) && (!dv.max.offset))
-		return;
+		return 0;
 
 	/* Prep SCSI IO structure
 	 */
@@ -6303,19 +6596,29 @@
 	iocmd.physDiskNum = -1;
 	iocmd.rsvd = iocmd.rsvd2 = 0;
 
-	/* Use tagged commands if possible.
-	 */
 	pTarget = hd->Targets[id];
-	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
-		iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
-
 	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
 		/* Another GEM workaround. Check peripheral device type,
 		 * if PROCESSOR, quit DV.
 		 */
 		if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) {
 			pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
-			return;
+			return 0;
+		}
+	}
+
+	/* Use tagged commands if possible.
+	 */
+	if (pTarget) {
+		if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+			iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
+		else {
+			if (hd->ioc->facts.FWVersion.Word < 0x01000600)
+				return 0;
+
+			if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+				(hd->ioc->facts.FWVersion.Word < 0x01010B00))
+				return 0;
 		}
 	}
 
@@ -6345,7 +6648,7 @@
 
 	pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
 	if (pDvBuf == NULL)
-		return;
+		return 0;
 
 	sz = 0;
 	pbuf1 = (u8 *)pDvBuf;
@@ -6371,7 +6674,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));
@@ -6427,8 +6730,10 @@
 	hd->pLocal = NULL;
 	readPage0 = 0;
 	sz = SCSI_STD_INQUIRY_BYTES;
+	rc = MPT_SCANDV_GOOD;
 	while (1) {
 		ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name));
+		retcode = 0;
 		dv.cmd = MPT_SET_MIN;
 		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
 
@@ -6439,12 +6744,65 @@
 		if (mpt_config(hd->ioc, &cfg) != 0)
 			goto target_done;
 
+		/* Wide - narrow - wide workaround case
+		 */
+		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) ||
+				((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+				(hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
+
+				iocmd.cmd = CMD_RequestSense;
+				iocmd.data_dma = buf1_dma;
+				iocmd.data = pbuf1;
+				iocmd.size = 0x12;
+				if (mptscsih_do_cmd(hd, &iocmd) < 0)
+					goto target_done;
+				else {
+					if (hd->pLocal == NULL)
+						goto target_done;
+					rc = hd->pLocal->completion;
+					if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
+						dv.max.width = 0;
+						doFallback = 0;
+					} else
+						goto target_done;
+				}
+			} else
+				goto target_done;
+		}
+
 		iocmd.cmd = CMD_Inquiry;
 		iocmd.data_dma = buf1_dma;
 		iocmd.data = pbuf1;
 		iocmd.size = sz;
 		if (mptscsih_do_cmd(hd, &iocmd) < 0)
 			goto target_done;
+		else {
+			if (hd->pLocal == NULL)
+				goto target_done;
+			rc = hd->pLocal->completion;
+			if (rc == MPT_SCANDV_GOOD) {
+				if (hd->pLocal->scsiStatus == STS_BUSY) {
+					if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
+						retcode = 1;
+					else
+						retcode = 0;
+
+					goto target_done;
+				}
+			} else if  (rc == MPT_SCANDV_SENSE) {
+				;
+			} else {
+				/* If first command doesn't complete
+				 * with a good status or with a check condition,
+				 * exit.
+				 */
+				goto target_done;
+			}
+		}
 
 		/* Another GEM workaround. Check peripheral device type,
 		 * if PROCESSOR, quit DV.
@@ -6504,7 +6862,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;
@@ -6528,7 +6886,9 @@
 				}
 
 
-			} else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_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 */
 			else
 				goto target_done;
@@ -6766,7 +7126,7 @@
 						mdelay (2000);
 						notDone++;
 					} else {
-						ddvprintk((MYIOC_s_INFO_FMT 
+						ddvprintk((MYIOC_s_INFO_FMT
 							"DV: Reserved Failed.", ioc->name));
 						goto target_done;
 					}
@@ -6830,7 +7190,7 @@
 							patt = -1;
 							continue;
 						}
-					} 
+					}
 					goto target_done;
 				}
 				else
@@ -6943,7 +7303,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);
 		}
 	}
@@ -6951,8 +7311,7 @@
 
 	/* Set if cfg1_dma_addr contents is valid
 	 */
-	if (cfg.hdr != NULL) {
-
+	if ((cfg.hdr != NULL) && (retcode == 0)){
 		/* If disk, not U320, disable QAS
 		 */
 		if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320))
@@ -6961,6 +7320,10 @@
 		dv.cmd = MPT_SAVE;
 		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
 
+#if 0	
+	/* Double writes to SDP1 can cause problems,
+	 * skip here since unnecessary
+	 */
 		/* Save the final negotiated settings to
 		 * SCSI device page 1.
 		 */
@@ -6969,13 +7332,14 @@
 		cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
 		cfg.dir = 1;
 		mpt_config(hd->ioc, &cfg);
+#endif
 	}
 
 	/* If this is a RAID Passthrough, enable internal IOs
 	 */
 	if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
 		if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
-			ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
+			ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
 	}
 
 	/* Done with the DV scan of the current target
@@ -6986,7 +7350,7 @@
 	ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n",
 			ioc->name, atomic_read(&queue_depth)));
 
-	return;
+	return retcode;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -7113,7 +7477,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;
@@ -7129,14 +7493,13 @@
 			pPage1->Configuration = le32_to_cpu(configuration);
 		}
 		ddvprintk(("width %d, factor %x, offset %x request %x config %x\n",
-				dv->now.width, dv->now.factor,
-				dv->now.offset, val, configuration));
+				width, factor, offset, val, configuration));
 		break;
 
 	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;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)