patch-2.0.26 linux/drivers/scsi/advansys.c

Next file: linux/drivers/scsi/eata.c
Previous file: linux/drivers/scsi/Config.in
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
@@ -1,4 +1,4 @@
-/* $Id: advansys.c,v 1.20 1996/09/26 00:47:54 bobf Exp bobf $ */
+/* $Id: advansys.c,v 1.29 1996/11/15 00:45:07 bobf Exp bobf $ */
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  * 
@@ -18,9 +18,10 @@
  */
 
 /*
- * The driver has been run with the v1.2.13, v1.3.57, and v2.0.21 kernels.
+ * The driver has been used in the following kernels:
+ *  v1.2.13, v1.3.57, v2.0.25, v2.1.9
  */
-#define ASC_VERSION "1.7"    /* AdvanSys Driver Version */
+#define ASC_VERSION "2.0"    /* AdvanSys Driver Version */
 
 /*
 
@@ -53,10 +54,10 @@
 
      Connectivity Products:
         ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1)
-        ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1)
-        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
+        ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1, 3)
+        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) (Footnote 4)
         ABP920 - Bus-Master PCI (16 CDB)
-        ABP930 - Bus-Master PCI (16 CDB)
+        ABP930 - Bus-Master PCI (16 CDB) (Footnote 5)
         ABP930U - Bus-Master PCI Ultra (16 CDB)
         ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
         ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
@@ -79,9 +80,11 @@
        1. This board has been shipped by HP with the 4020i CD-R drive.
           The board has no BIOS so it cannot control a boot device, but
           it can control any secondary SCSI device.
-   
        2. This board has been sold by Iomega as a Jaz Jet PCI adapter.
-  
+       3. This board has been sold by SIIG as the i540 SpeedMaster.
+       4. This board has been sold by SIIG as the i542 SpeedMaster.
+       5. This board has been sold by SIIG as the Fast SCSI Pro PCI.
+
   B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.2.13. For versions that follow v1.2.13.
@@ -441,9 +444,46 @@
          5. Remove the request timeout issue form the driver issues list.
          6. Miscellaneous documentation additions and changes.
 
+     1.8 (10/4/96):
+         1. Make changes to handle the new v2.1.0 kernel memory mapping
+            in which a kernel virtual address may not be equivalent to its
+            bus or DMA memory address.
+         2. Change abort and reset request handling to make it yet even
+            more robust.
+         3. Try to mitigate request starvation by sending ordered requests
+            to heavily loaded, tag queuing enabled devices.
+         4. Maintain statistics on request response time.
+         5. Add request response time statistics and other information to
+            the adapter /proc file: /proc/scsi/advansys[0...].
+
+     1.9 (10/21/96):
+         1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
+            make use of mid-level SCSI driver device queue depth flow
+            control mechanism. This will eliminate aborts caused by a
+            device being unable to keep up with requests and eliminate
+            repeat busy or QUEUE FULL status returned by a device.
+         2. Incorporate miscellaneous Asc Library bug fixes.
+         3. To allow the driver to work in kernels with broken module
+            support set 'cmd_per_lun' if the driver is compile as a
+            module. This change affects kernels v1.3.89 to present.
+         4. Remove PCI BIOS address from the driver banner. The PCI BIOS
+            is relocated by the motherboard BIOS and its new address can
+            not be determined by the driver.
+         5. Add mid-level SCSI queue depth information to the adapter
+            /proc file: /proc/scsi/advansys[0...].
+
+     2.0 (11/14/96):
+         1. Change allocation of global structures used for device
+            initialization to guarantee they are in DMA-able memory.
+            Previously when the driver was loaded as a module these
+            structures might not have been in DMA-able memory, causing
+            device initialization to fail.
+
   I. Known Problems or Issues
 
-         None
+         1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around
+            the queue depth flow control code when mid-level SCSI changes
+            are included in Linux.
 
   J. Credits
 
@@ -540,7 +580,7 @@
 
 #define ASC_LIB_VERSION_MAJOR  1
 #define ASC_LIB_VERSION_MINOR  22
-#define ASC_LIB_SERIAL_NUMBER  89
+#define ASC_LIB_SERIAL_NUMBER  91
 
 typedef unsigned char uchar;
 
@@ -615,7 +655,6 @@
 #define ASC_PCI_ID2FUNC( id )   (((id) >> 8) & 0x7)
 #define ASC_PCI_MKID( bus, dev, func ) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
 
-#define  Asc_DvcLib_Status   int
 #define  ASC_DVCLIB_CALL_DONE     (1)
 #define  ASC_DVCLIB_CALL_FAILED   (0)
 #define  ASC_DVCLIB_CALL_ERROR    (-1)
@@ -823,7 +862,7 @@
 #define SCSI_SENKEY_MEDIUM_ERR    0x03
 #define SCSI_SENKEY_HW_ERR        0x04
 #define SCSI_SENKEY_ILLEGAL       0x05
-#define SCSI_SENKEY_ATTENSION     0x06
+#define SCSI_SENKEY_ATTENTION     0x06
 #define SCSI_SENKEY_PROTECTED     0x07
 #define SCSI_SENKEY_BLANK         0x08
 #define SCSI_SENKEY_V_UNIQUE      0x09
@@ -1349,7 +1388,6 @@
 #define ASC_IERR_SCAM                 0x0800
 #define ASC_IERR_SET_SDTR             0x1000
 #define ASC_IERR_RW_LRAM              0x8000
-#define ASC_DVCLIB_STATUS             0x00
 #define ASC_DEF_IRQ_NO  10
 #define ASC_MAX_IRQ_NO  15
 #define ASC_MIN_IRQ_NO  10
@@ -2108,7 +2146,7 @@
 #define ASC_INFO_SIZE			128			/* advansys_info() line size */
 
 /* /proc/scsi/advansys/[0...] related definitions */
-#define ASC_PRTBUF_SIZE			1024
+#define ASC_PRTBUF_SIZE			2048
 #define ASC_PRTLINE_SIZE		160
 
 #define ASC_PRT_NEXT() \
@@ -2137,15 +2175,52 @@
 #define DRIVER_BYTE(byte)	((byte) << 24)
 
 /*
- * REQ and REQP are the generic name for a SCSI request block and pointer.
- * REQPTID(reqp) returns reqp's target id.
- * REQPNEXT(reqp) returns reqp's next pointer.
- * REQPNEXTP(reqp) returns a pointer to reqp's next pointer.
+ * The following definitions and macros are OS independent interfaces to
+ * the queue functions:
+ *  REQ - SCSI request structure
+ *  REQP - pointer to SCSI request structure
+ *  REQPTID(reqp) - reqp's target id
+ *  REQPNEXT(reqp) - reqp's next pointer
+ *  REQPNEXTP(reqp) - pointer to reqp's next pointer
+ *  REQPTIME(reqp) - reqp's time stamp value
+ *  REQTIMESTAMP() - system time stamp value
  */
 typedef Scsi_Cmnd			REQ, *REQP;
 #define REQPNEXT(reqp)		((REQP) ((reqp)->host_scribble))
 #define REQPNEXTP(reqp)		((REQP *) &((reqp)->host_scribble))
 #define REQPTID(reqp)		((reqp)->target)
+#define REQPTIME(reqp)		((reqp)->SCp.this_residual)
+#define REQTIMESTAMP()		(jiffies)
+
+#define REQTIMESTAT(function, ascq, reqp, tid) \
+{ \
+	/*
+	 * If the request time stamp is less than the system time stamp, then \
+	 * maybe the system time stamp wrapped. Set the request time to zero.\
+	 */ \
+	if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
+		REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
+	} else { \
+		/* Indicate an error occurred with the assertion. */ \
+		ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
+		REQPTIME(reqp) = 0; \
+	} \
+	/* Handle first minimum time case without external initialization. */ \
+	if (((ascq)->q_tot_cnt[tid] == 1) ||  \
+		(REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
+			(ascq)->q_min_tim[tid] = REQPTIME(reqp); \
+			ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
+				(function), (tid), (ascq)->q_min_tim[tid]); \
+		} \
+	if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
+		(ascq)->q_max_tim[tid] = REQPTIME(reqp); \
+		ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
+			(function), tid, (ascq)->q_max_tim[tid]); \
+	} \
+	(ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
+	/* Reset the time stamp field. */ \
+	REQPTIME(reqp) = 0; \
+}
 
 /* asc_enqueue() flags */
 #define ASC_FRONT		1
@@ -2243,7 +2318,11 @@
 #endif /* ADVANSYS_STATS */
 
 #define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
-#define ASC_TENTHS(num, den) ((((num) * 10)/(den)) - (10 * ((num)/(den))))
+
+/* If the result wraps when calculating tenths, return 0. */
+#define ASC_TENTHS(num, den) \
+	(((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
+	0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
 
 /*
  * Display a message to the console.
@@ -2287,8 +2366,7 @@
 #define	ASC_DBG3(lvl, s, a1, a2, a3)
 #define	ASC_DBG4(lvl, s, a1, a2, a3, a4)
 #define	ASC_DBG_PRT_SCSI_HOST(lvl, s)
-#define	ASC_DBG_PRT_DVC_VAR(lvl, v)
-#define	ASC_DBG_PRT_DVC_CFG(lvl, c)
+#define	ASC_DBG_PRT_SCSI_CMND(lvl, s)
 #define	ASC_DBG_PRT_SCSI_Q(lvl, scsiqp)
 #define	ASC_DBG_PRT_QDONE_INFO(lvl, qdone)
 #define	ASC_DBG_PRT_HEX(lvl, name, start, length)
@@ -2348,17 +2426,10 @@
 		} \
 	}
 
-#define	ASC_DBG_PRT_DVC_VAR(lvl, v) \
+#define	ASC_DBG_PRT_SCSI_CMND(lvl, s) \
 	{ \
 		if (asc_dbglvl >= (lvl)) { \
-			asc_prt_dvc_var(v); \
-		} \
-	}
-
-#define	ASC_DBG_PRT_DVC_CFG(lvl, c) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			asc_prt_dvc_cfg(c); \
+			asc_prt_scsi_cmnd(s); \
 		} \
 	}
 
@@ -2431,9 +2502,6 @@
 	ulong 	sg_cnt;			/* # scatter-gather I/O requests received */
 	ulong 	sg_elem;		/* # scatter-gather elements */
 	ulong 	sg_xfer;		/* # scatter-gather transfer 512-bytes */
-	/* Device SCSI Command Queuing Statistics */
-	ASC_SCSI_BIT_ID_TYPE queue_full;
-	ushort	queue_full_cnt[ASC_MAX_TID+1];
 };
 #endif /* ADVANSYS_STATS */
 
@@ -2447,6 +2515,10 @@
 #ifdef ADVANSYS_STATS
 	short					q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */
 	short					q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */
+	ulong					q_tot_cnt[ASC_MAX_TID+1]; /* total enqueue count */
+	ulong					q_tot_tim[ASC_MAX_TID+1]; /* total time queued */
+	ushort					q_max_tim[ASC_MAX_TID+1]; /* maximum time queued */
+	ushort					q_min_tim[ASC_MAX_TID+1]; /* minimum time queued */
 #endif /* ADVANSYS_STATS */
 } asc_queue_t;
 
@@ -2464,10 +2536,21 @@
 	ASC_DVC_CFG			 asc_dvc_cfg;		/* Device configuration */
 	asc_queue_t			 active;			/* Active command queue */
 	asc_queue_t			 waiting;		  	/* Waiting command queue */
+	asc_queue_t			 done;				/* Done command queue */
 	ASC_SCSI_BIT_ID_TYPE init_tidmask;		/* Target initialized mask */
+	/* The following three structures must be in DMA-able memory. */
+	ASC_SCSI_REQ_Q		 scsireqq;
+	ASC_CAP_INFO		 cap_info;
+	ASC_SCSI_INQUIRY	 inquiry;
+	Scsi_Device			 *device[ASC_MAX_TID+1]; /* Mid-Level Scsi Device */
+	ushort				 reqcnt[ASC_MAX_TID+1]; /* Starvation request count */
+#if ASC_QUEUE_FLOW_CONTROL
+	ushort				 nerrcnt[ASC_MAX_TID+1]; /* No error request count */
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+	ASC_SCSI_BIT_ID_TYPE queue_full;		/* Queue full mask */
+	ushort	queue_full_cnt[ASC_MAX_TID+1];	/* Queue full count */
 	ASCEEP_CONFIG		 eep_config;		/* EEPROM configuration */
-	asc_queue_t			 scsi_done_q;		/* Completion command queue */
-	ulong				 reset_jiffies;		/* Saved time of last reset */
+	ulong				 last_reset;		/* Saved time of last reset */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 	/* /proc/scsi/advansys/[0...] */
 	char				 *prtbuf;			/* Statistics Print Buffer */
@@ -2552,13 +2635,6 @@
 STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
 
 /*
- * Global structures used for device initialization.
- */
-STATIC ASC_SCSI_REQ_Q	 asc_scsireqq = { { 0 } };
-STATIC ASC_CAP_INFO		 asc_cap_info = { 0 };
-STATIC ASC_SCSI_INQUIRY	 asc_inquiry = { { 0 } };
-
-/*
  * Global structures required to issue a command.
  */
 STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } };
@@ -2646,6 +2722,7 @@
 #endif /* ADVANSYS_STATS */
 #ifdef ADVANSYS_DEBUG
 STATIC void 		asc_prt_scsi_host(struct Scsi_Host *);
+STATIC void 		asc_prt_scsi_cmnd(Scsi_Cmnd *);
 STATIC void 		asc_prt_dvc_cfg(ASC_DVC_CFG *);
 STATIC void 		asc_prt_dvc_var(ASC_DVC_VAR *);
 STATIC void 		asc_prt_scsi_q(ASC_SCSI_Q *);
@@ -3059,6 +3136,7 @@
 			memset(boardp, 0, sizeof(asc_board_t));
 			boardp->id = asc_board_count - 1;
 			asc_dvc_varp = &boardp->asc_dvc_var;
+			asc_dvc_varp->drv_ptr = (ulong) boardp;
 			asc_dvc_varp->cfg = &boardp->asc_dvc_cfg;
 			asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
 			asc_dvc_varp->iop_base = iop;
@@ -3114,9 +3192,9 @@
 			/*
 			 * Get the board configuration.
 			 *
-			 * AscInitGetConfig() may change the board's bus_type value.
-			 * The asc_bus[bus] value should no longer be used. If the
-			 * bus_type field must be referenced only use the bit-wise
+			 * NOTE: AscInitGetConfig() may change the board's bus_type
+			 * value. The asc_bus[bus] value should no longer be used. If
+			 * the bus_type field must be referenced only use the bit-wise
 			 * AND operator "&".
 			 */
 			ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
@@ -3247,7 +3325,7 @@
 			 */
 
 			/* AscInitSetConfig() will set the IRQ for non-PCI boards. */
-			if (asc_dvc_varp->bus_type != ASC_IS_PCI) {
+			if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
 				shp->irq = asc_dvc_varp->irq_no;
 			}
 
@@ -3286,16 +3364,33 @@
 			 */
 			shp->select_queue_depths = advansys_select_queue_depths;
 
-			shp->cmd_per_lun = 0; /* 'cmd_per_lun' is no longer used. */
+#ifdef MODULE
+			/*
+			 * Following v1.3.89, 'cmd_per_lun' is no longer needed
+			 * and should be set to zero. But because of a bug introduced
+			 * in v1.3.89 if the driver is compiled as a module and
+			 * 'cmd_per_lun' is zero, the Mid-Level SCSI function
+			 * 'allocate_device' will panic. To allow the driver to
+			 * work as a module in these kernels set 'cmd_per_lun' to 1.
+			 */
+			shp->cmd_per_lun = 1;
+#else /* MODULE */
+			shp->cmd_per_lun = 0;
+#endif /* MODULE */
 #endif /* version >= v1.3.89 */
 
 			/*
-			 * Maximum number of scatter-gather elements adapter can handle.
-			 *
-			 * Set a conservative 'sg_tablesize' value to prevent memory
-			 * allocation failures.
+			 * Set the maximum number of scatter-gather elements adapter
+			 * can handle.
 			 */
+
 #ifdef MODULE
+			/*
+			 * If the driver is compiled as a module, set a conservative
+			 * 'sg_tablesize' value to prevent memory allocation failures.
+			 * Memory allocation errors are more likely to occur at module
+			 * load time, then at driver initialization time.
+			 */
 			shp->sg_tablesize = 8;
 #else /* MODULE */
 			/*
@@ -3474,25 +3569,28 @@
 			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
 			(unsigned) shp->base, shp->io_port,
 			shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel);
+	} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+		if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+			== ASC_IS_PCI_ULTRA) {
+			busname = "PCI Ultra";
+		} else {
+			busname = "PCI";
+		}
+		sprintf(info,
+			"AdvanSys SCSI %s: %s %u CDB: IO %X-%X, IRQ %u",
+			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
+			shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq);
 	} else {
 		if (asc_dvc_varp->bus_type & ASC_IS_VL) {
 			busname = "VL";
 		} else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
 			busname = "EISA";
-		} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-			if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
-				== ASC_IS_PCI_ULTRA) {
-				busname = "PCI Ultra";
-			} else {
-				busname = "PCI";
-			}
 		} else {
 			busname = "?";
 			ASC_PRINT2(
 "advansys_info: board %d: unknown bus type %d\n",
 				boardp->id, asc_dvc_varp->bus_type);
 		}
-		/* No DMA channel for non-ISA busses. */
 		sprintf(info,
 			"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u",
 			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
@@ -3512,7 +3610,9 @@
  * Polled-I/O. Apparently host drivers shouldn't return until
  * command is finished.
  *
- * XXX - Can host drivers block here instead of spinning on command status?
+ * Note: This is an old interface that is no longer used by the SCSI
+ * mid-level driver. The new interface, advansys_queuecommand(),
+ * currently handles all requests.
  */
 int
 advansys_command(Scsi_Cmnd *scp)
@@ -3521,6 +3621,10 @@
 	ASC_STATS(scp->host, command);
 	scp->SCp.Status = 0; /* Set to a known state */
 	advansys_queuecommand(scp, advansys_command_done);
+	/*
+	 * XXX - Can host drivers block here instead of spinning on
+	 * command status?
+	 */
 	while (scp->SCp.Status == 0) {
 		continue;
 	}
@@ -3571,11 +3675,11 @@
 		}
 
 		/*
-		 * Add blocked requests to the board's 'scsi_done_q'. The queued
+		 * Add blocked requests to the board's 'done' queue. The queued
 		 * requests will be completed at the end of the abort or reset
 		 * handling.
 		 */
-		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+		asc_enqueue(&boardp->done, scp, ASC_BACK);
 		restore_flags(flags);
 		return 0;
 	}
@@ -3601,7 +3705,7 @@
 	 * target waiting list.
 	 * 
 	 * If an error occurred, the request will have been placed on the
-	 * board's 'scsi_done_q' and must be completed before returning.
+	 * board's 'done' queue and must be completed before returning.
 	 */
 	scp->scsi_done = done;
 	switch (asc_execute_scsi_cmnd(scp)) {
@@ -3612,7 +3716,7 @@
 		break;
 	case ASC_ERROR:
 	default:
-		done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL);
+		done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
 		/* Interrupts could be enabled here. */
 		asc_scsi_done_list(done_scp);
 		break;
@@ -3634,42 +3738,63 @@
 	asc_board_t			*boardp;
 	ASC_DVC_VAR			*asc_dvc_varp;
 	int					flags;
-	int					status = ASC_FALSE;
-	int					abort_do_done = ASC_FALSE;
-	Scsi_Cmnd			*done_scp;
-	int					ret = ASC_ERROR;
-
-	ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
+	int					do_scsi_done;
+	int					scp_found;
+	Scsi_Cmnd			*done_scp = NULL;
+	int					ret;
 
 	/* Save current flags and disable interrupts. */
 	save_flags(flags);
 	cli();
 
+	ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
+
 #ifdef ADVANSYS_STATS
 	if (scp->host != NULL) {
 		ASC_STATS(scp->host, abort);
 	}	
 #endif /* ADVANSYS_STATS */
 
+#ifdef ADVVANSYS_DEBUG
+	do_scsi_done = ASC_ERROR;
+	scp_found = ASC_ERROR;
+	ret = ASC_ERROR;
+#endif /* ADVANSYS_DEBUG */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 	if (scp->serial_number != scp->serial_number_at_timeout) {
+		ASC_PRINT1(
+"advansys_abort: timeout serial number changed for request %x\n",
+			(unsigned) scp);
+		do_scsi_done = ASC_FALSE;
+		scp_found = ASC_FALSE;
 		ret = SCSI_ABORT_NOT_RUNNING;
 	} else
 #endif /* version >= v1.3.89 */
 	if ((shp = scp->host) == NULL) {
 		scp->result = HOST_BYTE(DID_ERROR);
+		do_scsi_done = ASC_TRUE;
+		scp_found = ASC_FALSE;
 		ret = SCSI_ABORT_ERROR;
 	} else if ((boardp = ASC_BOARDP(shp))->flags & 
 				(ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
 		ASC_PRINT2(
 "advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n",
 			boardp->id, boardp->flags);
+		do_scsi_done = ASC_TRUE;
+		if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
+		    (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
+			scp_found = ASC_TRUE;
+		} else {
+			scp_found = ASC_FALSE;
+		}
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_ABORT_ERROR;
 	} else {
 		/* Set abort flag to avoid nested reset or abort requests. */
 		boardp->flags |= ASC_HOST_IN_ABORT;
 
+		do_scsi_done = ASC_TRUE;
 		if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
 			/*
 		 	 * If asc_rmqueue() found the command on the waiting
@@ -3678,6 +3803,7 @@
 		 	 */
 			ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n",
 				(unsigned) scp);
+			scp_found = ASC_TRUE;
 			scp->result = HOST_BYTE(DID_ABORT);
 			ret = SCSI_ABORT_SUCCESS;
 		} else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) {
@@ -3693,7 +3819,7 @@
 			sti(); /* Enable interrupts for AscAbortSRB(). */
 			ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
 				(unsigned) scp);
-			switch (status = AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
+			switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
 			case ASC_TRUE:
 				/* asc_isr_callback() will be called */
 				ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
@@ -3713,20 +3839,23 @@
 			cli();
 
 			/*
-			 * If the abort failed, remove the request from the
-			 * active list and complete it.
+			 * The request will either still be on the active queue
+			 * or have been added to the board's done queue.
 			 */
-			if (status != ASC_TRUE) {
-				if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
-					scp->result = HOST_BYTE(DID_ABORT);
-					abort_do_done = ASC_TRUE;
-				}
+			if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
+				scp->result = HOST_BYTE(DID_ABORT);
+				scp_found = ASC_TRUE;
+			} else {
+				scp_found = asc_rmqueue(&boardp->done, scp);
+				ASC_ASSERT(scp_found == ASC_TRUE);
 			}
 
 		} else {
 			/*
 			 * The command was not found on the active or waiting queues.
 			 */
+			do_scsi_done = ASC_TRUE;
+			scp_found = ASC_FALSE;
 			ret = SCSI_ABORT_NOT_RUNNING;
 		}
 
@@ -3736,11 +3865,11 @@
 		/*
 		 * Because the ASC_HOST_IN_ABORT flag causes both
 		 * 'advansys_interrupt' and 'asc_isr_callback' to
-		 * queue requests to the board's 'scsi_done_q' and
+		 * queue requests to the board's 'done' queue and
 		 * prevents waiting commands from being executed,
 		 * these queued requests must be handled here.
 		 */
-		done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL);
+		done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
 
 		/*
 		 * Start any waiting commands for the board.
@@ -3749,22 +3878,39 @@
 			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
 			asc_execute_queue(&boardp->waiting);
 		}
+	}
 
-		/* Interrupts could be enabled here. */
+	/* Interrupts could be enabled here. */
 
-		/*
-		 * If needed, complete the aborted request.
-		 */
-		if (abort_do_done == ASC_TRUE) {
+	/*
+	 * Complete the request to be aborted, unless it has been
+	 * restarted as detected above, even if it was not found on
+	 * the device active or waiting queues.
+	 */
+	ASC_ASSERT(do_scsi_done != ASC_ERROR);
+	ASC_ASSERT(scp_found != ASC_ERROR);
+	if (do_scsi_done == ASC_TRUE) {
+		if (scp->scsi_done == NULL) {
+			ASC_PRINT1(
+"advansys_abort: aborted request scsi_done() is NULL, %x\n",
+				(unsigned) scp);
+		} else {
+			if (scp_found == ASC_FALSE) {
+				ASC_PRINT1(
+"advansys_abort: abort request not active or waiting, completing anyway %x\n",
+					(unsigned) scp);
+			}
 			ASC_STATS(scp->host, done);
 			scp->scsi_done(scp);
 		}
+	}
 
-		/*
-		 * It is possible for the request done function to re-enable
-		 * interrupts without confusing the driver. But here interrupts
-		 * aren't enabled until all requests have been completed.
-		 */
+	/*
+	 * It is possible for the request done function to re-enable
+	 * interrupts without confusing the driver. But here interrupts
+	 * aren't enabled until all requests have been completed.
+	 */
+	if (done_scp != NULL) {
 		asc_scsi_done_list(done_scp);
 	}
 
@@ -3795,18 +3941,18 @@
 	int					flags;
 	Scsi_Cmnd			*done_scp = NULL, *last_scp = NULL;
 	Scsi_Cmnd			*tscp, *new_last_scp;
-	int					scp_found = ASC_FALSE;
-	int 				device_reset = ASC_FALSE;
+	int					do_scsi_done;
+	int					scp_found;
 	int					status;
 	int					target;
-	int					ret = ASC_ERROR;
-
-	ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
+	int					ret;
 
 	/* Save current flags and disable interrupts. */
 	save_flags(flags);
 	cli();
 
+	ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
+
 #ifdef ADVANSYS_STATS
 	if (scp->host != NULL) {
 		ASC_STATS(scp->host, reset);
@@ -3815,21 +3961,35 @@
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 	if (scp->serial_number != scp->serial_number_at_timeout) {
+		ASC_PRINT1(
+"advansys_reset: timeout serial number changed for request %x\n",
+			(unsigned) scp);
+		do_scsi_done = ASC_FALSE;
+		scp_found = ASC_FALSE;
 		ret = SCSI_RESET_NOT_RUNNING;
 	} else
 #endif /* version >= v1.3.89 */
 	if ((shp = scp->host) == NULL) {
 		scp->result = HOST_BYTE(DID_ERROR);
+		do_scsi_done = ASC_TRUE;
+		scp_found = ASC_FALSE;
 		ret = SCSI_RESET_ERROR;
 	} else if ((boardp = ASC_BOARDP(shp))->flags & 
 				(ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
 		ASC_PRINT2(
 "advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n",
 			boardp->id, boardp->flags);
+		do_scsi_done = ASC_TRUE;
+		if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
+		    (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
+			scp_found = ASC_TRUE;
+		} else {
+			scp_found = ASC_FALSE;
+		}
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_RESET_ERROR;
-	} else if (jiffies >= boardp->reset_jiffies &&
-			   jiffies < (boardp->reset_jiffies + (10 * HZ))) {
+	} else if (jiffies >= boardp->last_reset &&
+			   jiffies < (boardp->last_reset + (10 * HZ))) {
 		/*
 		 * Don't allow a reset to be attempted within 10 seconds
 		 * of the last reset.
@@ -3840,15 +4000,27 @@
 		 */
 		ASC_DBG(1,
 			"advansys_reset: reset within 10 sec of last reset ignored\n");
+		do_scsi_done = ASC_TRUE;
+		if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
+		    (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
+			scp_found = ASC_TRUE;
+		} else {
+			scp_found = ASC_FALSE;
+		}
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_RESET_ERROR;
 	} else {
+		int device_reset = ASC_FALSE;
+
+		do_scsi_done = ASC_TRUE;
+
 		/* Set reset flag to avoid nested reset or abort requests. */
 		boardp->flags |= ASC_HOST_IN_RESET;
 
 		/*
-	 	 * If the request is on the target waiting or active queue,
-		 * note that it was found and remove it from its queue.
+	 	 * If the request is on the target waiting or active queue
+		 * or the board done queue, then remove it and note that it
+		 * was found.
 		 */
 		if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
 			ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n");
@@ -3856,6 +4028,10 @@
 		} else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
 			ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n");
 			scp_found = ASC_TRUE;
+		} else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) {
+			scp_found = ASC_TRUE;
+		} else {
+			scp_found = ASC_FALSE;
 		}
 
 		/*
@@ -3939,11 +4115,11 @@
 		/*
 		 * Because the ASC_HOST_IN_RESET flag causes both
 		 * 'advansys_interrupt' and 'asc_isr_callback' to
-		 * queue requests to the board's 'scsi_done_q' and
+		 * queue requests to the board's 'done' queue and
 		 * prevents waiting commands from being executed,
 		 * these queued requests must be handled here.
 		 */
-		done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp,
+		done_scp = asc_dequeue_list(&boardp->done, &last_scp,
 									ASC_TID_ALL);
 
 		/*
@@ -4006,7 +4182,7 @@
 		}
 
 		/* Save the time of the most recently completed reset. */
-		boardp->reset_jiffies = jiffies;
+		boardp->last_reset = jiffies;
 
 		/* Clear reset flag. */
 		boardp->flags &= ~ASC_HOST_IN_RESET;
@@ -4018,34 +4194,35 @@
 			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
 			asc_execute_queue(&boardp->waiting);
 		}
+		ret = SCSI_RESET_SUCCESS;
+	}
 
-		/* Interrupts could be enabled here. */
+	/* Interrupts could be enabled here. */
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-		/*
-		 * If the command was found on the active or waiting request
-		 * queues or if the the SCSI_RESET_SYNCHRONOUS flag is set,
-		 * then done the command now.
-		 */
-		if (scp_found == ASC_TRUE || (reset_flags & SCSI_RESET_SYNCHRONOUS)) {
-			scp->result = HOST_BYTE(DID_RESET);
-			ASC_STATS(scp->host, done);
-			scp->scsi_done(scp);
-		}
-#else /* version >= v1.3.89 */
-		if (scp_found == ASC_TRUE) {
-			scp->result = HOST_BYTE(DID_RESET);
+	ASC_ASSERT(do_scsi_done != ASC_ERROR);
+	ASC_ASSERT(scp_found != ASC_ERROR);
+	if (do_scsi_done == ASC_TRUE) {
+		if (scp->scsi_done == NULL) {
+			ASC_PRINT1(
+"advansys_reset: reset request scsi_done() is NULL, %x\n",
+				(unsigned) scp);
+		} else {
+			if (scp_found == ASC_FALSE) {
+				ASC_PRINT1(
+"advansys_reset: reset request not active or waiting, completing anyway %x\n",
+					(unsigned) scp);
+			}
 			ASC_STATS(scp->host, done);
 			scp->scsi_done(scp);
 		}
-#endif /* version >= v1.3.89 */
-		ret = SCSI_RESET_SUCCESS;
+	}
 
-		/*
-		 * It is possible for the request done function to re-enable
-		 * interrupts without confusing the driver. But here interrupts
-		 * aren't enabled until requests have been completed.
-		 */
+	/*
+	 * It is possible for the request done function to re-enable
+	 * interrupts without confusing the driver. But here interrupts
+	 * aren't enabled until requests have been completed.
+	 */
+	if (done_scp != NULL) {
 		asc_scsi_done_list(done_scp);
 	}
 
@@ -4239,11 +4416,11 @@
 			 * Add to the list of requests that must be completed.
 			 */
 			if (done_scp == NULL) {
-				done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp,
+				done_scp = asc_dequeue_list(&boardp->done, &last_scp,
 					ASC_TID_ALL);
 			} else {
 				ASC_ASSERT(last_scp != NULL);
-				REQPNEXT(last_scp) = asc_dequeue_list(&boardp->scsi_done_q,
+				REQPNEXT(last_scp) = asc_dequeue_list(&boardp->done,
 					&new_last_scp, ASC_TID_ALL);
 				if (new_last_scp != NULL) {
 					ASC_ASSERT(REQPNEXT(last_scp) != NULL);
@@ -4285,6 +4462,11 @@
 		if (device->host != shp) {
 			continue;
 		}
+		/*
+		 * Save a pointer to the device and set its initial/maximum
+		 * queue depth.
+		 */
+		boardp->device[device->id] = device;
 		device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id];
 		ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n",
 			(unsigned) shp, device->id, device->queue_depth);
@@ -4318,6 +4500,7 @@
 		tscp = REQPNEXT(scp);
 		REQPNEXT(scp) = NULL;
 		ASC_STATS(scp->host, done);
+		ASC_ASSERT(scp->scsi_done != NULL);
 		scp->scsi_done(scp);
 		scp = tscp;
 	}
@@ -4360,7 +4543,7 @@
  * 	host_scribble - used for pointer to another Scsi_Cmnd
  *
  * If this function returns ASC_NOERROR or ASC_ERROR the request
- * has been enqueued on the board's 'scsi_done_q' and must be
+ * has been enqueued on the board's 'done' queue and must be
  * completed by the caller.
  *
  * If ASC_BUSY is returned the request must be enqueued by the
@@ -4371,6 +4554,7 @@
 {
 	asc_board_t		*boardp;
 	ASC_DVC_VAR		*asc_dvc_varp;
+	Scsi_Device		*device;
 	int				ret;
 
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
@@ -4379,6 +4563,7 @@
 
 	boardp = ASC_BOARDP(scp->host);
 	asc_dvc_varp = &boardp->asc_dvc_var;
+	device = boardp->device[scp->target];
 
 	/*
 	 * If this is the first command, then initialize the device. If
@@ -4387,7 +4572,7 @@
 	if ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(scp->target)) == 0) {
 		if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) {
 			scp->result = HOST_BYTE(DID_BAD_TARGET);
-			asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
 			return ASC_ERROR;
 		}
 		boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target);
@@ -4412,9 +4597,30 @@
 	asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
 	asc_scsi_q.q1.target_lun = scp->lun;
 	asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 	asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0];
+#else /* version >= v2.0.0 */
+	asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]);
+#endif /* version >= v2.0.0 */
 	asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
-	asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+
+	/*
+	 * If there are any outstanding requests for the current target,
+	 * then every 255th request send an ORDERED request. This heuristic
+	 * tries to retain the benefit of request sorting while preventing
+	 * request starvation. 255 is the max number of tags or pending commands
+	 * a device may have outstanding.
+	 *
+	 * The request count is incremented below for every successfully
+	 * started request.
+	 * 
+	 */
+	if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 0) &&
+	    (boardp->reqcnt[scp->target] % 255) == 0) {
+		asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED;
+	} else {
+		asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+	}
 
 	/*
 	 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
@@ -4425,8 +4631,11 @@
 		 * CDB request of single contiguous buffer.
 		 */
 		ASC_STATS(scp->host, cont_cnt);
- 		/* request_buffer is already a real address. */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 		asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer;
+#else /* version >= v2.0.0 */
+		asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer);
+#endif /* version >= v2.0.0 */
 		asc_scsi_q.q1.data_cnt = scp->request_bufflen;
 		ASC_STATS_ADD(scp->host, cont_xfer,
 					  ASC_CEILING(scp->request_bufflen, 512));
@@ -4444,7 +4653,7 @@
 "asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n",
 				boardp->id, scp->use_sg, scp->host->sg_tablesize);
 			scp->result = HOST_BYTE(DID_ERROR);
-			asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
 			return ASC_ERROR;
 		}
 
@@ -4468,7 +4677,11 @@
 		 */
 		slp = (struct scatterlist *) scp->request_buffer;
 		for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 			asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address;
+#else /* version >= v2.0.0 */
+			asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address);
+#endif /* version >= v2.0.0 */
 			asc_sg_head.sg_list[sgcnt].bytes = slp->length;
 			ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 		}
@@ -4484,28 +4697,71 @@
 	switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
 	case ASC_NOERROR:
 		ASC_STATS(scp->host, asc_noerror);
+		/*
+		 * Increment monotonically increasing per device successful
+		 * request counter. Wrapping doesn't matter.
+		 */
+		boardp->reqcnt[scp->target]++;
+
+#if ASC_QUEUE_FLOW_CONTROL
+		/*
+		 * Conditionally increment the device queue depth.
+		 *
+	 	 * If no error occurred and there have been 100 consecutive
+		 * successfull requests and the current queue depth is less
+		 * than the maximum queue depth, then increment the current
+		 * queue depth.
+		 */
+		if (boardp->nerrcnt[scp->target]++ > 100) {
+			boardp->nerrcnt[scp->target] = 0;
+			if ((device->queue_curr_depth < device->queue_depth) &&
+			    (!(boardp->queue_full & ASC_TIX_TO_TARGET_ID(scp->target)) ||
+				 (boardp->queue_full_cnt[scp->target] >
+				  device->queue_curr_depth))) {
+				device->queue_curr_depth++;
+			}
+		}
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		asc_enqueue(&boardp->active, scp, ASC_BACK);
 		ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
 		break;
 	case ASC_BUSY:
 		/* Caller must enqueue request and retry later. */
 		ASC_STATS(scp->host, asc_busy);
+#if ASC_QUEUE_FLOW_CONTROL
+		/*
+		 * Clear consecutive no error counter and if possbile decrement
+		 * queue depth.
+		 */
+		boardp->nerrcnt[scp->target] = 0;
+		if (device->queue_curr_depth > 1) {
+			device->queue_curr_depth--;
+		}
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		break;
 	case ASC_ERROR:
 		ASC_PRINT2(
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
 			boardp->id, asc_dvc_varp->err_code);
 		ASC_STATS(scp->host, asc_error);
+#if ASC_QUEUE_FLOW_CONTROL
+		/* Clear consecutive no error counter. */
+		boardp->nerrcnt[scp->target] = 0;
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		scp->result = HOST_BYTE(DID_ERROR);
-		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+		asc_enqueue(&boardp->done, scp, ASC_BACK);
 		break;
 	default:
 		ASC_PRINT2(
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
 			boardp->id, asc_dvc_varp->err_code);
 		ASC_STATS(scp->host, asc_unknown);
+#if ASC_QUEUE_FLOW_CONTROL
+		/* Clear consecutive no error counter. */
+		boardp->nerrcnt[scp->target] = 0;
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		scp->result = HOST_BYTE(DID_ERROR);
-		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+		asc_enqueue(&boardp->done, scp, ASC_BACK);
 		break;
 	}
 
@@ -4645,7 +4901,7 @@
 	 * The done function for the command will be called from
 	 * advansys_interrupt().
 	 */
-	asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+	asc_enqueue(&boardp->done, scp, ASC_BACK);
 
 	return;
 }
@@ -4659,6 +4915,9 @@
 asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 {
 	asc_board_t				*boardp;
+	ASC_SCSI_REQ_Q			*scsireqq;
+	ASC_CAP_INFO			*cap_info;
+	ASC_SCSI_INQUIRY		*inquiry;
 	int						found;
 	ASC_SCSI_BIT_ID_TYPE	save_use_tagged_qng;
 	ASC_SCSI_BIT_ID_TYPE	save_can_tagged_qng;
@@ -4675,9 +4934,11 @@
 	boardp = ASC_BOARDP(scp->host);
 
 	/* Set-up AscInitPollTarget() arguments. */
-	memset(&asc_scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
-	memset(&asc_cap_info, 0, sizeof(ASC_CAP_INFO));
-	memset(&asc_inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
+	scsireqq = &boardp->scsireqq;
+	memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
+	cap_info = &boardp->cap_info;
+	memset(cap_info, 0, sizeof(ASC_CAP_INFO));
+	inquiry = &boardp->inquiry;
 
 	/*
 	 * XXX - AscInitPollBegin() re-initializes these fields to
@@ -4695,24 +4956,24 @@
 		return ASC_FALSE;
 	}
 
-	asc_scsireqq.sense_ptr = &asc_scsireqq.sense[0];
-	asc_scsireqq.r1.sense_len = ASC_MIN_SENSE_LEN;
-	asc_scsireqq.r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-	asc_scsireqq.r1.target_lun = 0;
-	asc_scsireqq.r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
+	scsireqq->sense_ptr = &scsireqq->sense[0];
+	scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN;
+	scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+	scsireqq->r1.target_lun = 0;
+	scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
 
 	found = ASC_FALSE;
 	ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n");
-	switch (ret = AscInitPollTarget(asc_dvc_varp, &asc_scsireqq,
-		&asc_inquiry, &asc_cap_info)) {
+	switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry,
+		cap_info)) {
 	case ASC_TRUE:
 		found = ASC_TRUE;
 #ifdef ADVANSYS_DEBUG
 		tidmask = ASC_TIX_TO_TARGET_ID(scp->target);
 		ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n",
-			asc_cap_info.lba, asc_cap_info.blk_size);
+			cap_info->lba, cap_info->blk_size);
 		ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
-			asc_inquiry.byte0.peri_dvc_type);
+			inquiry->byte0.peri_dvc_type);
 		if (asc_dvc_varp->use_tagged_qng & tidmask) {
 			ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n",
 				asc_dvc_varp->max_dvc_qng[scp->target]);
@@ -5188,12 +5449,14 @@
 	ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid);
 #ifdef ADVANSYS_STATS
 	/* Maintain request queue statistics. */
+	ascq->q_tot_cnt[tid]++;
 	ascq->q_cur_cnt[tid]++;
 	if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
 		ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
 		ASC_DBG2(1, "asc_enqueue: new q_max_cnt[%d] %d\n",
 			tid, ascq->q_max_cnt[tid]);
 	}
+	REQPTIME(reqp) = REQTIMESTAMP();
 #endif /* ADVANSYS_STATS */
 	ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp);
 	return;
@@ -5227,6 +5490,7 @@
 		/* Maintain request queue statistics. */
 		ascq->q_cur_cnt[tid]--;
 		ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+		REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
 #endif /* ADVANSYS_STATS */
 	}
 	ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp);
@@ -5249,6 +5513,9 @@
  * (or the function return value) is not NULL, i.e. use a temporary
  * variable for 'lastpp' and check its value after the function return
  * before assigning it to the list last pointer.
+ *
+ * Unfortunately collecting queuing time statistics adds overhead to
+ * the function that isn't inherent to the function's algorithm.
  */
 REQP
 asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
@@ -5268,7 +5535,7 @@
 	if (tid != ASC_TID_ALL) {
 		/* Return all requests for the specified 'tid'. */
 		if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) {
-			/* List is empty set first and last return pointers to NULL. */
+			/* List is empty; Set first and last return pointers to NULL. */
 			firstp = lastp = NULL;
 		} else {
 			firstp = ascq->q_first[tid];
@@ -5276,7 +5543,13 @@
 			ascq->q_first[tid] = ascq->q_last[tid] = NULL;
 			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
 #ifdef ADVANSYS_STATS
-			ascq->q_cur_cnt[tid] = 0;
+			{
+				REQP reqp;
+				ascq->q_cur_cnt[tid] = 0;
+				for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+					REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid);
+				}
+			}
 #endif /* ADVANSYS_STATS */
 		}
 	} else {
@@ -5299,6 +5572,14 @@
 #endif /* ADVANSYS_STATS */
 			}
 		}
+#ifdef ADVANSYS_STATS
+		{
+			REQP reqp;
+			for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+				REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->target);
+			}
+		}
+#endif /* ADVANSYS_STATS */
 	}
 	if (lastpp) {
 		*lastpp = lastp;
@@ -5324,7 +5605,7 @@
 	int			tid;
 	int			ret = ASC_FALSE;
 
-	ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %d\n",
+	ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %x\n",
 		(unsigned) ascq, (unsigned) reqp);
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_ASSERT(reqp != NULL);
@@ -5373,6 +5654,7 @@
 	/* Maintain request queue statistics. */
 	if (ret == ASC_TRUE) {
 		ascq->q_cur_cnt[tid]--;
+		REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
 	}
 	ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
@@ -5406,6 +5688,7 @@
 			break;
 		}
 	}
+	ASC_DBG1(1, "asc_isqueued: ret %x\n", ret);
 	return ret;
 }
 
@@ -5478,7 +5761,7 @@
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if (boardp->asc_dvc_cfg.chip_scsi_id == i) {
 			continue;
-		} else if (boardp->init_tidmask & (1 << i)) {
+		} else if (boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
 			len = asc_prt_line(cp, leftlen, " %d,", i);
 			ASC_PRT_NEXT();
 		}
@@ -5534,7 +5817,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->disc_enable & (1 << i)) ? 'Y' : 'N');
+			i, (ep->disc_enable & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5545,7 +5828,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->use_cmd_qng & (1 << i)) ? 'Y' : 'N');
+			i, (ep->use_cmd_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5556,7 +5839,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->start_motor & (1 << i)) ? 'Y' : 'N');
+			i, (ep->start_motor & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5567,7 +5850,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->init_sdtr & (1 << i)) ? 'Y' : 'N');
+			i, (ep->init_sdtr & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5595,9 +5878,15 @@
 STATIC int
 asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
 {
+	asc_board_t			*boardp;
 	int					leftlen;
 	int					totlen;
 	int					len;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+	int					i;
+#endif /* version >= v1.3.89 */
+
+	boardp = ASC_BOARDP(shp);
 
 	leftlen = cplen;
 	totlen = len = 0;
@@ -5608,42 +5897,91 @@
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
+" host_busy %u, last_reset %u, max_id %u, max_lun %u\n",
+		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun);
+#else /* version >= v1.3.89 */
 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
 		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
 		shp->max_channel);
-#else /* version >= v1.3.89 */
-" host_busy %u, last_reset %u, max_id %u, max_lun %u\n",
-		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun);
 #endif /* version >= v1.3.89 */
 	ASC_PRT_NEXT();
 	
 	len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
+" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+		shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun);
+#else /* version >= v1.3.57 */
 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
 		shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
 		shp->cmd_per_lun);
-#else /* version >= v1.3.57 */
-" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
-		shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun);
 #endif /* version >= v1.3.57 */
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57)
-" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
-		shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
-#else /* version >= v1.3.57 */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
 " unchecked_isa_dma %d, loaded_as_module %d\n",
 		shp->unchecked_isa_dma, shp->loaded_as_module);
+#else /* version >= v1.3.57 */
+" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
+		shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
 #endif /* version >= v1.3.57 */
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-" flags %x, reset_jiffies %x, jiffies %x\n",
-		ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->reset_jiffies, jiffies);
+" flags %x, last_reset %x, jiffies %x\n",
+		ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies);
+	ASC_PRT_NEXT();
+
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+	len = asc_prt_line(cp, leftlen,
+" queue_depth:     ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %d:%d",
+			i, boardp->device[i]->queue_depth);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
+#endif /* version >= v1.3.89 */
+
+#if ASC_QUEUE_FLOW_CONTROL
+	len = asc_prt_line(cp, leftlen,
+" queue_curr_depth:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %d:%d",
+			i, boardp->device[i]->queue_curr_depth);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
 
+	len = asc_prt_line(cp, leftlen,
+" queue_count:     ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %d:%d",
+			i, boardp->device[i]->queue_count);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+
  	return totlen;
 }
 
@@ -5668,9 +6006,6 @@
 	ASC_DVC_VAR			*v;
 	ASC_DVC_CFG			*c;
 	int					i;
-#ifdef ADVANSYS_STATS
-	struct asc_stats	*s;
-#endif /* ADVANSYS_STATS */
 
 	boardp = ASC_BOARDP(shp);
 	v = &boardp->asc_dvc_var;
@@ -5704,11 +6039,11 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (v->sdtr_done & (1 << i)) ? 'Y' : 'N');
+			i, (v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5719,11 +6054,11 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (v->use_tagged_qng & (1 << i)) ? 'Y' : 'N');
+			i, (v->use_tagged_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5735,7 +6070,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]);
@@ -5750,7 +6085,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]);
@@ -5759,21 +6094,18 @@
 	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
 
-#ifdef ADVANSYS_STATS
-	s = &boardp->asc_stats;
-
 	/* Indicate whether the device has returned queue full status. */
 	len = asc_prt_line(cp, leftlen,
 " Command Queue Full:      ");
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
-		if (s->queue_full & (1 << i)) {
+		if (boardp->queue_full & ASC_TIX_TO_TARGET_ID(i)) {
 			len = asc_prt_line(cp, leftlen, " %d:Y-%d",
-				i, s->queue_full_cnt[i]);
+				i, boardp->queue_full_cnt[i]);
 		} else {
 			len = asc_prt_line(cp, leftlen, " %d:N", i);
 		}
@@ -5781,7 +6113,6 @@
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
-#endif /* ADVANSYS_STATS */
 
  	return totlen;
 }
@@ -5897,18 +6228,19 @@
 }
 
 /*
- * Convert a virtual address to a virtual address.
- *
- * Apparently Linux is loaded V=R (virtual equals real). Just return
- * the virtual address.
+ * Convert a virtual address to a bus address.
  */
 ulong
 DvcGetPhyAddr(uchar *buf_addr, ulong buf_len)
 {
-	ulong phys_addr;
+	ulong bus_addr;
 
-	phys_addr = (ulong) buf_addr;
-	return phys_addr;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+	bus_addr = (ulong) buf_addr;
+#else /* version >= v2.0.0 */
+	bus_addr = virt_to_bus(buf_addr);
+#endif /* version >= v2.0.0 */
+	return bus_addr;
 }
 
 ulong
@@ -5919,7 +6251,11 @@
 
 	buf_size = buf_len;
 	asc_sg_head_ptr->entry_cnt = 1;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 	asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr;
+#else /* version >= v2.0.0 */
+	asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr);
+#endif /* version >= v2.0.0 */
 	asc_sg_head_ptr->sg_list[0].bytes = buf_size;
 	return buf_size;
 }
@@ -6076,8 +6412,6 @@
 /*
  * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
- *
- * This function was formerly supplied by the library.
  */
 ushort
 AscGetChipBiosAddress(
@@ -6088,13 +6422,15 @@
     ushort  cfg_lsw ;
     ushort  bios_addr ;
 
-    /*
-     *   We can't get the BIOS address for PCI
-     */
-    if ( bus_type & ASC_IS_PCI )
-    {
-        return( 0 );
-    }
+	/*
+	 * The PCI BIOS is re-located by the motherboard BIOS. Because
+	 * of this the driver can not determine where a PCI BIOS is
+	 * loaded and executes.
+	 */
+	if ( bus_type & ASC_IS_PCI )
+	{
+		return( 0 );
+	}
 
     if( ( bus_type & ASC_IS_EISA ) != 0 )
     {
@@ -6170,25 +6506,6 @@
 	ASC_PRT_NEXT();
 
 	/*
-	 * Display request queuing statistics.
-	 */
-	len = asc_prt_line(cp, leftlen,
-" Active and Pending Request Queues:\n");
-	ASC_PRT_NEXT();
-
-	active = &ASC_BOARDP(shp)->active;
-	waiting = &ASC_BOARDP(shp)->waiting;
-	for (i = 0; i < ASC_MAX_TID + 1; i++) {
-		if (active->q_max_cnt[i] > 0 || waiting->q_max_cnt[i] > 0) {
-			len = asc_prt_line(cp, leftlen,
-"  target %d: active [cur %d, max %d], waiting [cur %d, max %d]\n",
-				i, active->q_cur_cnt[i], active->q_max_cnt[i],
-				waiting->q_cur_cnt[i], waiting->q_max_cnt[i]);
-			ASC_PRT_NEXT();
-		}
-	}
-
-	/*
 	 * Display data transfer statistics.
 	 */
 	if (s->cont_cnt > 0) {
@@ -6235,6 +6552,44 @@
 		ASC_PRT_NEXT();
 	}
 
+	/*
+	 * Display request queuing statistics.
+	 */
+	len = asc_prt_line(cp, leftlen,
+" Active and Waiting Request Queues (time unit: %d HZ):\n", HZ);
+	ASC_PRT_NEXT();
+
+	active = &ASC_BOARDP(shp)->active;
+	waiting = &ASC_BOARDP(shp)->waiting;
+	for (i = 0; i < ASC_MAX_TID + 1; i++) {
+		if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) {
+			len = asc_prt_line(cp, leftlen, " target %d\n", i);
+			ASC_PRT_NEXT();
+
+			len = asc_prt_line(cp, leftlen,
+"   active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
+				active->q_cur_cnt[i], active->q_max_cnt[i],
+				active->q_tot_cnt[i],
+				active->q_min_tim[i], active->q_max_tim[i],
+				(active->q_tot_cnt[i] == 0) ? 0 :
+				(active->q_tot_tim[i]/active->q_tot_cnt[i]),
+				(active->q_tot_cnt[i] == 0) ? 0 :
+				ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i]));
+			ASC_PRT_NEXT();
+
+			len = asc_prt_line(cp, leftlen,
+"   waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
+				waiting->q_cur_cnt[i], waiting->q_max_cnt[i],
+				waiting->q_tot_cnt[i],
+				waiting->q_min_tim[i], waiting->q_max_tim[i],
+				(waiting->q_tot_cnt[i] == 0) ? 0 :
+				(waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]),
+				(waiting->q_tot_cnt[i] == 0) ? 0 :
+				ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i]));
+			ASC_PRT_NEXT();
+		}
+	}
+
  	return totlen;
 }
 #endif /* ADVANSYS_STATS */
@@ -6275,6 +6630,60 @@
 }
 
 /*
+ * asc_prt_scsi_cmnd()
+ */
+STATIC void 
+asc_prt_scsi_cmnd(Scsi_Cmnd *s)
+{
+	printk("Scsi_Cmnd at addr %x\n", (unsigned) s);
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+	printk(
+" host %x, device %x, target %u, lun %u\n",
+		(unsigned) s->host, (unsigned) s->device, s->target, s->lun);
+#else /* version >= v1.3.0 */
+	printk(
+" host %x, device %x, target %u, lun %u, channel %u,\n",
+		(unsigned) s->host, (unsigned) s->device, s->target, s->lun,
+		s->channel);
+#endif /* version >= v1.3.0 */
+
+	asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
+
+	printk(
+" use_sg %u, sglist_len %u, abort_reason %x\n",
+		s->use_sg, s->sglist_len, s->abort_reason);
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
+	printk(
+" retries %d, allowed %d\n",
+		 s->retries, s->allowed);
+#else /* version >= v1.3.89 */
+	printk(
+" serial_number %x, serial_number_at_timeout %x, retries %d, allowed %d\n",
+		(unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout,
+		 s->retries, s->allowed);
+#endif /* version >= v1.3.89 */
+
+	printk(
+" timeout_per_command %d, timeout_total %d, timeout %d\n",
+		s->timeout_per_command, s->timeout_total, s->timeout);
+
+	printk(
+" internal_timeout %u, flags %u, this_count %d\n",
+		s->internal_timeout, s->flags, s->this_count);
+
+	printk(
+" scsi_done %x, done %x, host_scribble %x, result %x\n",
+		(unsigned) s->scsi_done, (unsigned) s->done,
+		(unsigned) s->host_scribble, s->result);
+
+	printk(
+" tag %u, pid %u\n",
+		(unsigned) s->tag, (unsigned) s->pid);
+}
+
+/*
  * asc_prt_dvc_var()
  */
 STATIC void 
@@ -6896,6 +7305,8 @@
 						asc_dvc->sdtr_done |= target_id;
 						asc_dvc->init_sdtr |= target_id;
 						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+						sdtr_data = AscCalSDTRData(asc_dvc,
+							sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset);
 						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
 					} else {
 						q_cntl |= QC_MSG_OUT;
@@ -6903,6 +7314,8 @@
 									  sdtr_xmsg.xfer_period,
 									  sdtr_xmsg.req_ack_offset);
 						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+						sdtr_data = AscCalSDTRData(asc_dvc,
+							sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset);
 						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
 						asc_dvc->sdtr_done |= target_id;
 						asc_dvc->init_sdtr |= target_id;
@@ -6996,24 +7409,23 @@
 									 (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) tid_no),
 									 cur_dvc_qng);
 				}
-#ifdef ADVANSYS_STATS
 				{
-					asc_board_t		*boardp;
-					int				i;
-					for (i = 0; i < ASC_NUM_BOARD_SUPPORTED; i++) {
-						if (asc_host[i] == NULL) {
-							continue;
-						}
-						boardp = ASC_BOARDP(asc_host[i]);
-						if (&boardp->asc_dvc_var == asc_dvc) {
-							boardp->asc_stats.queue_full |= target_id;
-							boardp->asc_stats.queue_full_cnt[tid_no] =
-							  cur_dvc_qng;
-							break;
-						}
-					}
+				asc_board_t		*boardp;
+				boardp = (asc_board_t *) asc_dvc->drv_ptr;
+
+				/*
+				 * Set the device queue depth to the number of
+				 * active requests when the QUEUE FULL condition
+				 * was encountered.
+				 */
+				boardp->queue_full |= target_id;
+				boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
+#if ASC_QUEUE_FLOW_CONTROL
+				if (boardp->device[tid_no]->queue_curr_depth > cur_dvc_qng) {
+					boardp->device[tid_no]->queue_curr_depth = cur_dvc_qng;
+				}
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 				}
-#endif
 			}
 		}
 		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
@@ -7331,8 +7743,10 @@
 	scsiq->r3.host_stat = 0;
 	scsiq->r3.done_stat = 0;
 	scsiq->r2.vm_id = 0;
-	scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
 	scsiq->r1.data_cnt = buf_len;
+	scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
+	scsiq->sense_ptr = (uchar dosfar *) scsiq->sense ;
+	scsiq->r1.sense_len = ASC_MIN_SENSE_LEN ;
 	scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE;
 	scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ;
 	scsiq->r2.srb_ptr = (ulong) scsiq;
@@ -7345,6 +7759,12 @@
 		}
 		scsiq->r1.data_addr = phy_addr;
 	}
+	if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
+                       (uchar dosfar *) scsiq->sense_ptr,
+                       (ulong) scsiq->r1.sense_len )) == 0L) {
+		return (ERR);
+	}
+	scsiq->r1.sense_addr = phy_addr ;
 	return (0);
 }
 
@@ -8441,21 +8861,22 @@
 {
 	ruchar             *period_table;
 	int                 max_index;
+	int                 min_index;
 	int                 i;
 	period_table = asc_dvc->sdtr_period_tbl;
 	max_index = (int) asc_dvc->max_sdtr_index;
+	min_index = ( int )asc_dvc->host_init_sdtr_index ;
 	if (
-		   (syn_time >= period_table[0])
-		   && (syn_time <= period_table[max_index])
+		   (syn_time <= period_table[max_index])
 	  ) {
-		for (i = 0; i < (max_index - 1); i++) {
+		for (i = min_index; i < (max_index - 1); i++) {
 			if (syn_time <= period_table[i]) {
-				return (i);
+				return ((uchar) i);
 			}
 		}
-		return (max_index);
+		return ((uchar) max_index);
 	} else {
-		return (max_index + 1);
+		return ((uchar) (max_index + 1));
 	}
 }
 
@@ -9260,20 +9681,20 @@
 	asc_dvc->no_scam = 0;
 	asc_dvc->unit_not_ready = 0;
 	asc_dvc->queue_full_or_busy = 0;
+	asc_dvc->redo_scam = 0 ;
+	asc_dvc->res2 = 0 ;
+	asc_dvc->host_init_sdtr_index = 0 ;
+	asc_dvc->res7 = 0 ;
+	asc_dvc->res8 = 0 ;
+	asc_dvc->cfg->can_tagged_qng = 0 ;
+	asc_dvc->cfg->cmd_qng_enabled = 0;
 	asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
 	asc_dvc->init_sdtr = ASC_SCSI_WIDTH_BIT_SET;
 	asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
 	asc_dvc->scsi_reset_wait = 3;
 	asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
 	asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
-	asc_dvc->redo_scam = 0;
-	asc_dvc->res2 = 0;
-	asc_dvc->host_init_sdtr_index = 0;
-	asc_dvc->res7 = 0;
-	asc_dvc->res8 = 0;
 	asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
-	asc_dvc->cfg->can_tagged_qng = 0;
-	asc_dvc->cfg->cmd_qng_enabled = 0;
 	asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
 	asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
 	asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
@@ -9562,6 +9983,9 @@
 		scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat;
 		scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat;
 		scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg;
+		ASC_DBG4(1, "AscInitPollIsrCallBack: done_stat %x, host_stat %x, scsi_stat %x, scsi_msg %x\n",
+			scsi_done_q->d3.done_stat, scsi_done_q->d3.host_stat,
+			scsi_done_q->d3.scsi_stat, scsi_done_q->d3.scsi_msg);
 		if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) &&
 			(scsi_done_q->d3.host_stat == 0)) {
 			cp_sen_len = (uchar) ASC_MIN_SENSE_LEN;
@@ -9893,21 +10317,12 @@
 	int                 support_read_cap;
 	int                 tmp_disable_init_sdtr;
 	int                 sta;
-	ulong               phy_addr;
 	dvc_found = 0;
 	tmp_disable_init_sdtr = FALSE;
 	tid_bits = scsiq->r1.target_id;
 	lun = scsiq->r1.target_lun;
 	tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix);
 	if (
-		   (phy_addr = AscGetOnePhyAddr(asc_dvc,
-										(uchar dosfar *) scsiq->sense_ptr,
-										(ulong) scsiq->r1.sense_len)) == 0L
-	  ) {
-		return (ERR);
-	}
-	scsiq->r1.sense_addr = phy_addr;
-	if (
 		   ((asc_dvc->init_sdtr & tid_bits) != 0)
 		   && ((asc_dvc->sdtr_done & tid_bits) == 0)
 	  ) {
@@ -10024,7 +10439,7 @@
 	int                 status;
 	int                 retry = 0;
 
-	ASC_DBG1(1, "PollQueueDone: timeout_sec %d", timeout_sec);
+	ASC_DBG1(1, "PollQueueDone: timeout_sec %d\n", timeout_sec);
 	do {
 		ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n");
 		if ((status = AscExeScsiQueue(asc_dvc,
@@ -10032,6 +10447,7 @@
 			ASC_DBG(1, "PollQueueDone: before AscPollQDone\n");
 			if ((status = AscPollQDone(asc_dvc, scsiq,
 									   timeout_sec)) != 1) {
+				ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 				if (status == 0x80) {
 					if (retry++ > ASC_MAX_INIT_BUSY_RETRY) {
 						break;
@@ -10047,14 +10463,18 @@
 				scsiq->r3.host_stat = 0;
 				scsiq->r3.scsi_stat = 0;
 				scsiq->r3.scsi_msg = 0;
+				ASC_DBG(1, "PollQueueDone: before AscAbortSRB()\n");
 				AscAbortSRB(asc_dvc, (ulong) scsiq);
 			}
+			ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 			ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat);
 			return (scsiq->r3.done_stat);
 		}
+		ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 		DvcSleepMilliSecond(5);
 	} while (((status == 0) || (status == 0x80)) &&
 			  retry++ < ASC_MAX_INIT_BUSY_RETRY);
+	ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 	ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n");
 	return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
@@ -10153,12 +10573,12 @@
 	ASC_REQ_SENSE dosfar *sen;
 	retry = 0;
 	tid_bits = scsiq->r1.target_id;
-	while (retry++ < 2) {
+	while (retry++ < 4) {
 		PollScsiTestUnitReady(asc_dvc, scsiq);
 		if (scsiq->r3.done_stat == 0x01) {
 			return (1);
 		} else if (scsiq->r3.done_stat == QD_WITH_ERROR) {
-			DvcSleepMilliSecond(100);
+			DvcSleepMilliSecond(200);
 			sen = (ASC_REQ_SENSE dosfar *) scsiq->sense_ptr;
 			if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) &&
 				((sen->err_code & 0x70) != 0)) {
@@ -10174,9 +10594,10 @@
 					} else {
 						DvcSleepMilliSecond(5000);
 					}
-				} else if (sen->sense_key == SCSI_SENKEY_ATTENSION) {
-					DvcSleepMilliSecond(500);
+				} else if (sen->sense_key == SCSI_SENKEY_ATTENTION) {
+					DvcSleepMilliSecond( ( ulong )( 500L*retry ) ) ;
 				} else {
+					DvcSleepMilliSecond( 500 ) ;
 					break;
 				}
 			} else {
@@ -10208,6 +10629,7 @@
 	while (TRUE) {
 		if (asc_dvc->err_code != 0) {
 			scsiq->r3.done_stat = QD_WITH_ERROR;
+			ASC_DBG1(1, "AscPollQDone: err_code %x\n", asc_dvc->err_code);
 			sta = ERR;
 			break;
 		}
@@ -10220,10 +10642,12 @@
 		}
 		DvcSleepMilliSecond(10);
 		if (loop++ > loop_end) {
+			ASC_DBG(1, "AscPollQDone: loop finished\n");
 			sta = 0;
 			break;
 		}
 		if (AscIsChipHalted(iop_base)) {
+			ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n");
 #if !CC_ASCISR_CHECK_INT_PENDING
 			AscAckInterrupt(iop_base);
 #endif
@@ -10231,6 +10655,7 @@
 			loop = 0;
 		} else {
 			if (AscIsIntPending(iop_base)) {
+				ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n");
 #if !CC_ASCISR_CHECK_INT_PENDING
 				AscAckInterrupt(iop_base);
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov