patch-2.0.21-2.1.0 linux/drivers/scsi/advansys.c

Next file: linux/drivers/scsi/advansys.h
Previous file: linux/drivers/scsi/README.in2000
Back to the patch index
Back to the overall index

diff -u --recursive --new-file lx2.0/v2.0.21/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
@@ -1,4 +1,4 @@
-/* $Id: advansys.c,v 1.15 1996/08/12 17:20:23 bobf Exp bobf $ */
+/* $Id: advansys.c,v 1.20 1996/09/26 00:47:54 bobf Exp bobf $ */
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  * 
@@ -18,9 +18,9 @@
  */
 
 /*
- * The driver has been run with the v1.2.13, v1.3.57, and v2.0.11 kernels.
+ * The driver has been run with the v1.2.13, v1.3.57, and v2.0.21 kernels.
  */
-#define ASC_VERSION "1.5"    /* AdvanSys Driver Version */
+#define ASC_VERSION "1.7"    /* AdvanSys Driver Version */
 
 /*
 
@@ -28,14 +28,15 @@
 
   A. Adapters Supported by this Driver
   B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
-  C. Linux v1.3.X, v2.X.X - Directions for Adding the AdvanSys Driver
-  D. Source Comments
-  E. Driver Compile Time Options and Debugging
-  F. Driver LILO Option
-  G. Release History
-  H. Known Problems or Issues
-  I. Credits
-  J. AdvanSys Contact Information
+  C. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
+  D. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
+  E. Source Comments
+  F. Driver Compile Time Options and Debugging
+  G. Driver LILO Option
+  H. Release History
+  I. Known Problems or Issues
+  J. Credits
+  K. AdvanSys Contact Information
 
   A. Adapters Supported by this Driver
  
@@ -47,8 +48,8 @@
      Descriptor Block) requests that can be stored in the RISC chip
      cache and board LRAM. A CDB is a single SCSI command. The driver
      detect routine will display the number of CDBs available for each
-     adapter detected. This value can be lowered in the BIOS by changing
-     the 'Host Queue Size' adapter setting.
+     adapter detected. The number of CDBs used by the driver can be
+     lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
 
      Connectivity Products:
         ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1)
@@ -56,8 +57,10 @@
         ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
         ABP920 - Bus-Master PCI (16 CDB)
         ABP930 - Bus-Master PCI (16 CDB)
+        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)
+     
      Single Channel Products:
         ABP542 - Bus-Master ISA with floppy (240 CDB)
         ABP742 - Bus-Master EISA (240 CDB)
@@ -65,6 +68,7 @@
         ABP940 - Bus-Master PCI (240 CDB)
         ABP940U - Bus-Master PCI Ultra (240 CDB)
         ABP970 - Bus-Master PCI MAC/PC (240 CDB)
+        ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
      
      Dual Channel Products:
         ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
@@ -72,17 +76,18 @@
         ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
      
      Footnotes:
-       1. These boards have been shipped by HP with the 4020i CD-R drive.
-          They have no BIOS so they cannot control a boot device, but they
-          can control secondary devices.
+       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 shipped by Iomega with the Jaz Jet drive.
+       2. This board has been sold by Iomega as a Jaz Jet PCI adapter.
   
   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.
      but precede v1.3.57 some of the changes for Linux v1.3.X listed
-     below may need to be modified or included.
+     below may need to be modified or included. A patch is available
+     for v1.2.13 from the AdvanSys WWW and FTP sites.
  
      There are two source files: advansys.h and advansys.c. Copy
      both of these files to the directory /usr/src/linux/drivers/scsi.
@@ -148,11 +153,13 @@
         'make modules_install'. Use 'insmod' and 'rmmod' to install
         and remove advansys.o.
  
-  C. Linux v1.3.X, v2.X.X - Directions for Adding the AdvanSys Driver
+  C. Linux v1.3.1 - v1.3.57 - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.3.57. For versions that precede v1.3.57
-     some of these changes may need to be modified or eliminated. Beginning
-     with v1.3.58 this driver is included with the Linux distribution.
+     some of these changes may need to be modified or eliminated. A patch
+     is available for v1.3.57 from the AdvanSys WWW and FTP sites.
+     Beginning with v1.3.58 this driver is included with the Linux
+     distribution eliminating the need for making any changes.
 
      There are two source files: advansys.h and advansys.c. Copy
      both of these files to the directory /usr/src/linux/drivers/scsi.
@@ -212,7 +219,21 @@
         'make modules_install'. Use 'insmod' and 'rmmod' to install
         and remove advansys.o.
 
-  D. Source Comments
+  D. Linux v1.3.58 and Newer - Upgrading the AdvanSys Driver
+
+     To upgrade the AdvanSys driver in a Linux v1.3.58 and newer
+     kernel, first check the version of the current driver. The
+     version is defined by the manifest constant ASC_VERSION at
+     the beginning of advansys.c. The new driver should have a
+     ASC_VERSION value greater than the current version. To install
+     the new driver rename advansys.c and advansys.h in the Linux
+     kernel source tree drivers/scsi directory to different names
+     or save them to a different directory in case you want to revert
+     to the old version of the driver. After the old driver is saved
+     copy the new advansys.c and advansys.h to drivers/scsi, rebuild
+     the kernel, and install the new kernel. No other changes are needed.
+
+  E. Source Comments
  
      1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
  
@@ -251,7 +272,7 @@
            --- Asc Library Constants and Macros
            --- Asc Library Functions
  
-  E. Driver Compile Time Options and Debugging
+  F. Driver Compile Time Options and Debugging
  
      In this source file the following constants can be defined. They are
      defined in the source below. Both of these options are enabled by
@@ -299,7 +320,7 @@
      2. ADVANSYS_STATS - enable statistics
  
         Statistics are maintained on a per adapter basis. Driver entry
-        point call counts and tranfer size counts are maintained.
+        point call counts and transfer size counts are maintained.
         Statistics are only available for kernels greater than or equal
         to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
 
@@ -315,7 +336,7 @@
         contain adapter and device configuration information.
 
 
-  F. Driver LILO Option
+  G. Driver LILO Option
  
      If init/main.c is modified as described in the 'Directions for Adding
      the AdvanSys Driver to Linux' section (B.4.) above, the driver will
@@ -346,7 +367,7 @@
      the 'Driver Compile Time Options and Debugging' section above for
      more information.
 
-  G. Release History
+  H. Release History
 
      BETA-1.0 (12/23/95): 
          First Release
@@ -389,7 +410,7 @@
             request_irq and supplying a dev_id pointer to both request_irq()
             and free_irq().
          3. In AscSearchIOPortAddr11() restore a call to check_region() which
-            should be used before any I/O port probing.
+            should be used before I/O port probing.
          4. Fix bug in asc_prt_hex() which resulted in the displaying
             the wrong data.
          5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
@@ -403,15 +424,28 @@
             made in v1.3.89. The advansys_select_queue_depths() function
             was added for the v1.3.89 changes.
 
-  H. Known Problems or Issues
+     1.6 (9/10/96):
+         1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
+
+     1.7 (9/25/96):
+         1. Enable clustering and optimize the setting of the maximum number
+            of scatter gather elements for any particular board. Clustering
+            increases CPU utilization, but results in a relatively larger
+            increase in I/O throughput.
+         2. Improve the performance of the request queuing functions by
+            adding a last pointer to the queue structure.
+         3. Correct problems with reset and abort request handling that
+            could have hung or crashed Linux.
+         4. Add more information to the adapter /proc file:
+            /proc/scsi/advansys[0...].
+         5. Remove the request timeout issue form the driver issues list.
+         6. Miscellaneous documentation additions and changes.
+
+  I. Known Problems or Issues
 
-     1. For the first scsi command sent to a device the driver increases
-        the timeout value. This gives the driver more time to perform
-        its own initialization for the board and each device. The timeout
-        value is only changed on the first scsi command for each device
-        and never thereafter. The same change is made for reset commands.
+         None
 
-  I. Credits
+  J. Credits
 
      Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
      basis for the Linux v1.3.X changes which were included in the
@@ -420,7 +454,7 @@
      Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
      in advansys_biosparam() which was fixed in the 1.3 release.
 
-  J. AdvanSys Contact Information
+  K. AdvanSys Contact Information
  
      Mail:                   Advanced System Products, Inc.
                              1150 Ringwood Court
@@ -505,8 +539,8 @@
  */
 
 #define ASC_LIB_VERSION_MAJOR  1
-#define ASC_LIB_VERSION_MINOR  21
-#define ASC_LIB_SERIAL_NUMBER  88
+#define ASC_LIB_VERSION_MINOR  22
+#define ASC_LIB_SERIAL_NUMBER  89
 
 typedef unsigned char uchar;
 
@@ -581,6 +615,11 @@
 #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)
+
 #define Lptr
 #define dosfar
 #define far
@@ -592,8 +631,8 @@
 #define outp(port, byte)    outb((byte), (port))
 #define outpw(port, word)   outw((word), (port))
 #define outpl(port, long)   outl((long), (port))
-#define ASC_MAX_SG_QUEUE	5
-#define ASC_MAX_SG_LIST		(1 + ((ASC_SG_LIST_PER_Q) * (ASC_MAX_SG_QUEUE)))
+#define ASC_MAX_SG_QUEUE	7
+#define ASC_MAX_SG_LIST		SG_ALL
 
 #define CC_INIT_INQ_DISPLAY     FALSE
 #define CC_CLEAR_LRAM_SRB_PTR   FALSE
@@ -609,8 +648,6 @@
 #define CC_MEMORY_MAPPED_IO    FALSE
 #define CC_INCLUDE_EEP_CONFIG  TRUE
 #define CC_PCI_ULTRA           TRUE
-#define CC_INIT_TARGET_READ_CAPACITY    TRUE
-#define CC_INIT_TARGET_TEST_UNIT_READY  TRUE
 #define CC_ASC_SCSI_Q_USRDEF         FALSE
 #define CC_ASC_SCSI_REQ_Q_USRDEF     FALSE
 #define CC_ASCISR_CHECK_INT_PENDING  TRUE
@@ -619,13 +656,10 @@
 #define CC_DISABLE_PCI_PARITY_INT    TRUE
 #define CC_INCLUDE_EEP_CONFIG        TRUE
 #define CC_INIT_INQ_DISPLAY          FALSE
-#define CC_INIT_TARGET_TEST_UNIT_READY  TRUE
-#define CC_INIT_TARGET_START_UNIT       TRUE
 #define CC_PLEXTOR_VL                FALSE
 #define CC_TMP_USE_EEP_SDTR          FALSE
 #define CC_CHK_COND_REDO_SDTR        TRUE
 #define CC_SET_PCI_LATENCY_TIMER_ZERO  TRUE
-#define CC_FIX_QUANTUM_XP34301_1071  FALSE
 #define CC_DISABLE_ASYN_FIX_WANGTEK_TAPE  TRUE
 
 #define ASC_CS_TYPE  unsigned short
@@ -666,6 +700,8 @@
 #define ASC_CHIP_MAX_VER_EISA (0x47)
 #define ASC_CHIP_VER_EISA_BIT (0x40)
 #define ASC_CHIP_LATEST_VER_EISA   ( ( ASC_CHIP_MIN_VER_EISA - 1 ) + 3 )
+#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER   0x21
+#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER   0x0A
 #define ASC_MAX_VL_DMA_ADDR     (0x07FFFFFFL)
 #define ASC_MAX_VL_DMA_COUNT    (0x07FFFFFFL)
 #define ASC_MAX_PCI_DMA_ADDR    (0xFFFFFFFFL)
@@ -1313,6 +1349,7 @@
 #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
@@ -1343,10 +1380,10 @@
 #define ASC_IOADR_DEF   ASC_IOADR_8
 #define ASC_LIB_SCSIQ_WK_SP        256
 #define ASC_MAX_SYN_XFER_NO        16
-#define ASC_SYN_XFER_NO            8
 #define ASC_SYN_MAX_OFFSET         0x0F
 #define ASC_DEF_SDTR_OFFSET        0x0F
 #define ASC_DEF_SDTR_INDEX         0x00
+#define ASC_SDTR_ULTRA_PCI_10MB_INDEX  0x02
 #define SYN_XFER_NS_0  25
 #define SYN_XFER_NS_1  30
 #define SYN_XFER_NS_2  35
@@ -1462,9 +1499,9 @@
 	ASC_SCSI_BIT_ID_TYPE no_scam;
 	ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
 	uchar               max_sdtr_index;
-	uchar               res4;
+	uchar               host_init_sdtr_index;
 	ulong               drv_ptr;
-	ulong               res6;
+	ulong               uc_break;
 	ulong               res7;
 	ulong               res8;
 } ASC_DVC_VAR;
@@ -1500,7 +1537,7 @@
 #define ASC_CNTL_INIT_VERBOSE      ( ushort )0x0800
 #define ASC_CNTL_SCSI_PARITY       ( ushort )0x1000
 #define ASC_CNTL_BURST_MODE        ( ushort )0x2000
-#define ASC_CNTL_USE_8_IOP_BASE    ( ushort )0x4000
+#define ASC_CNTL_SDTR_ENABLE_ULTRA ( ushort )0x4000
 #define ASC_EEP_DVC_CFG_BEG_VL    2
 #define ASC_EEP_MAX_DVC_ADDR_VL   15
 #define ASC_EEP_DVC_CFG_BEG      32
@@ -1537,15 +1574,23 @@
 #define ASC_EEP_CMD_WRITE_ABLE    0x30
 #define ASC_EEP_CMD_WRITE_DISABLE 0x00
 #define ASC_OVERRUN_BSIZE  0x00000048UL
+#define ASC_CTRL_BREAK_ONCE        0x0001
+#define ASC_CTRL_BREAK_STAY_IDLE   0x0002
 #define ASCV_MSGOUT_BEG         0x0000
 #define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
 #define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
+#define ASCV_BREAK_SAVED_CODE   ( ushort )0x0006
 #define ASCV_MSGIN_BEG          (ASCV_MSGOUT_BEG+8)
 #define ASCV_MSGIN_SDTR_PERIOD  (ASCV_MSGIN_BEG+3)
 #define ASCV_MSGIN_SDTR_OFFSET  (ASCV_MSGIN_BEG+4)
 #define ASCV_SDTR_DATA_BEG      (ASCV_MSGIN_BEG+8)
 #define ASCV_SDTR_DONE_BEG      (ASCV_SDTR_DATA_BEG+8)
 #define ASCV_MAX_DVC_QNG_BEG    ( ushort )0x0020
+#define ASCV_BREAK_ADDR           ( ushort )0x0028
+#define ASCV_BREAK_NOTIFY_COUNT   ( ushort )0x002A
+#define ASCV_BREAK_CONTROL        ( ushort )0x002C
+#define ASCV_BREAK_HIT_COUNT      ( ushort )0x002E
+
 #define ASCV_ASCDVC_ERR_CODE_W  ( ushort )0x0030
 #define ASCV_MCODE_CHKSUM_W   ( ushort )0x0032
 #define ASCV_MCODE_SIZE_W     ( ushort )0x0034
@@ -2052,7 +2097,11 @@
 #define ASC_NUM_BUS				4
 
 /* Reference Scsi_Host hostdata */
-#define ASC_BOARDP(host) ((struct asc_board *) &((host)->hostdata))
+#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
+
+/* asc_board_t flags */
+#define ASC_HOST_IN_RESET		0x01
+#define ASC_HOST_IN_ABORT		0x02
 
 #define NO_ISA_DMA				0xff		/* No ISA DMA Channel Used */
 
@@ -2102,6 +2151,12 @@
 #define ASC_FRONT		1
 #define ASC_BACK		2
 
+/* asc_dequeue_list() argument */
+#define ASC_TID_ALL		(-1)
+
+/* Return non-zero, if the queue is empty. */
+#define ASC_QUEUE_EMPTY(ascq)	((ascq)->q_tidmask == 0)
+
 /* PCI configuration declarations */
 
 #define PCI_BASE_CLASS_PREDEFINED			0x00
@@ -2364,6 +2419,7 @@
 	ulong 	check_interrupt;/* # advansys_interrupt() check pending calls */
 	ulong 	interrupt;		/* # advansys_interrupt() interrupts */
 	ulong 	callback;		/* # calls asc_isr_callback() */
+	ulong 	done;			/* # calls request scsi_done */
 	/* AscExeScsiQueue() Statistics */
 	ulong 	asc_noerror;	/* # AscExeScsiQueue() ASC_NOERROR returns. */
 	ulong 	asc_busy;		/* # AscExeScsiQueue() ASC_BUSY returns. */
@@ -2374,7 +2430,7 @@
 	ulong 	cont_xfer;		/* # contiguous transfer 512-bytes */
 	ulong 	sg_cnt;			/* # scatter-gather I/O requests received */
 	ulong 	sg_elem;		/* # scatter-gather elements */
-	ulong 	sg_xfer;		/* # scatter-gather tranfer 512-bytes */
+	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];
@@ -2385,11 +2441,12 @@
  * Request queuing structure
  */
 typedef struct asc_queue {
-	ASC_SCSI_BIT_ID_TYPE	tidmask;				  /* queue mask */
-	REQP					queue[ASC_MAX_TID+1];	  /* queue linked list */
+	ASC_SCSI_BIT_ID_TYPE	q_tidmask;				  /* queue mask */
+	REQP					q_first[ASC_MAX_TID+1];	  /* first queued request */
+	REQP					q_last[ASC_MAX_TID+1];	  /* last queued request */
 #ifdef ADVANSYS_STATS
-	short					cur_count[ASC_MAX_TID+1]; /* current queue count */
-	short					max_count[ASC_MAX_TID+1]; /* maximum queue count */
+	short					q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */
+	short					q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */
 #endif /* ADVANSYS_STATS */
 } asc_queue_t;
 
@@ -2400,28 +2457,25 @@
  * of the 'Scsi_Host' structure starting at the 'hostdata'
  * field. It is guaranteed to be allocated from DMA-able memory.
  */
-struct asc_board {
-	int				 	 id;					  /* Board Id */
-	/* Asc Library */
-	ASC_DVC_VAR			 asc_dvc_var;			  /* Board configuration */
-	ASC_DVC_CFG			 asc_dvc_cfg;			  /* Device configuration */
-	/* Queued Commands */
-	asc_queue_t			 active;				  /* Active command queue */
-	asc_queue_t			 pending;		  		  /* Pending command queue */
-	/* Target Initialization */
-	ASC_SCSI_BIT_ID_TYPE init_tidmask;			  /* Target initialized mask */
-	ASC_SCSI_REQ_Q		 scsireqq;
-	ASC_CAP_INFO		 cap_info;
-	ASC_SCSI_INQUIRY	 inquiry;
-	ASCEEP_CONFIG		 eep_config;			  /* EEPROM configuration */
+typedef struct asc_board {
+	int				 	 id;				/* Board Id */
+	uint				 flags;				/* Board flags */
+	ASC_DVC_VAR			 asc_dvc_var;		/* Board configuration */
+	ASC_DVC_CFG			 asc_dvc_cfg;		/* Device configuration */
+	asc_queue_t			 active;			/* Active command queue */
+	asc_queue_t			 waiting;		  	/* Waiting command queue */
+	ASC_SCSI_BIT_ID_TYPE init_tidmask;		/* Target initialized mask */
+	ASCEEP_CONFIG		 eep_config;		/* EEPROM configuration */
+	asc_queue_t			 scsi_done_q;		/* Completion command queue */
+	ulong				 reset_jiffies;		/* Saved time of last reset */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 	/* /proc/scsi/advansys/[0...] */
-	char				 *prtbuf;				  /* Statistics Print Buffer */
+	char				 *prtbuf;			/* Statistics Print Buffer */
 #endif /* version >= v1.3.0 */
 #ifdef ADVANSYS_STATS
-	struct asc_stats	 asc_stats;				  /* Board statistics */
+	struct asc_stats	 asc_stats;			/* Board statistics */
 #endif /* ADVANSYS_STATS */
-};
+} asc_board_t;
 
 /*
  * PCI configuration structures
@@ -2494,12 +2548,22 @@
 STATIC int asc_board_count = 0;
 STATIC struct Scsi_Host	*asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
 
-/* Global list of commands needing done function. */
-STATIC Scsi_Cmnd *asc_scsi_done = NULL;
-
 /* Overrun buffer shared between all boards. */
 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 } };
+STATIC ASC_SG_HEAD asc_sg_head = { 0 };
+
 /* List of supported bus types. */
 STATIC ushort asc_bus[ASC_NUM_BUS] = {
 	ASC_IS_ISA,
@@ -2549,6 +2613,7 @@
 												Scsi_Device *);
 #endif /* version >= v1.3.89 */
 STATIC void 		advansys_command_done(Scsi_Cmnd *);
+STATIC void 		asc_scsi_done_list(Scsi_Cmnd *);
 STATIC int 			asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC void 		asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
 STATIC int 			asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *);
@@ -2561,11 +2626,13 @@
 STATIC void 		asc_put_cfg_byte(PCI_DATA *, uchar);
 void				asc_enqueue(asc_queue_t *, REQP, int);
 REQP 				asc_dequeue(asc_queue_t *, int);
+REQP 				asc_dequeue_list(asc_queue_t *, REQP *, int);
 int					asc_rmqueue(asc_queue_t *, REQP);
 int					asc_isqueued(asc_queue_t *, REQP);
 void				asc_execute_queue(asc_queue_t *);
 STATIC int			asc_prt_board_devices(struct Scsi_Host *, char *, int);
 STATIC int			asc_prt_board_eeprom(struct Scsi_Host *, char *, int);
+STATIC int			asc_prt_driver_conf(struct Scsi_Host *, char *, int);
 STATIC int			asc_prt_board_info(struct Scsi_Host *, char *, int);
 STATIC int			asc_proc_copy(off_t, off_t, char *, int , char *, int);
 STATIC int			asc_prt_line(char *, int, char *fmt, ...);
@@ -2618,7 +2685,7 @@
 				   int hostno, int inout)
 {
 	struct Scsi_Host	*shp;
-	struct asc_board	*boardp;
+	asc_board_t 		*boardp;
 	int					i;
 	char				*cp;
 	int					cplen;
@@ -2738,6 +2805,22 @@
 	advoffset += cplen;
 	curbuf += cnt;
 
+	/*
+	 * Display driver configuration and information for the board.
+	 */
+	cp = boardp->prtbuf;
+	cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
+	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
+
 #ifdef ADVANSYS_STATS
 	/*
 	 * Display driver statistics for the board.
@@ -2800,7 +2883,7 @@
 	int					iop;
 	int					bus;
 	struct Scsi_Host	*shp;
-	struct asc_board	*boardp;
+	asc_board_t			*boardp;
 	ASC_DVC_VAR			*asc_dvc_varp;
 	int					ioport = 0;
 	int					share_irq = FALSE;
@@ -2966,14 +3049,14 @@
 			 * initialize it.
 			 */
 			ASC_DBG(2, "advansys_detect: scsi_register()\n");
-			shp = scsi_register(tpnt, sizeof(struct asc_board));
+			shp = scsi_register(tpnt, sizeof(asc_board_t));
 
 			/* Save a pointer to the Scsi_host of each board found. */
 			asc_host[asc_board_count++] = shp;
 
 			/* Initialize private per board data */
 			boardp = ASC_BOARDP(shp);
-			memset(boardp, 0, sizeof(struct asc_board));
+			memset(boardp, 0, sizeof(asc_board_t));
 			boardp->id = asc_board_count - 1;
 			asc_dvc_varp = &boardp->asc_dvc_var;
 			asc_dvc_varp->cfg = &boardp->asc_dvc_cfg;
@@ -2984,7 +3067,7 @@
 			if ((boardp->prtbuf =
 				kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
 				ASC_PRINT3(
-"advansys_detect: Board %d: kmalloc(%d, %d) returned NULL\n",
+"advansys_detect: board %d: kmalloc(%d, %d) returned NULL\n",
 					boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
 				scsi_unregister(shp);
 				asc_board_count--;
@@ -3021,7 +3104,7 @@
 				break;
 			default:
 				ASC_PRINT2(
-"advansys_detect: Board %d: unknown adapter type: %d",
+"advansys_detect: board %d: unknown adapter type: %d",
 					boardp->id, asc_dvc_varp->bus_type);
 				shp->unchecked_isa_dma = TRUE;
 				share_irq = FALSE;
@@ -3042,38 +3125,38 @@
 				break;
 			case ASC_WARN_IO_PORT_ROTATE:
 				ASC_PRINT1(
-"AscInitGetConfig: Board: %d: I/O port address modified\n",
+"AscInitGetConfig: board %d: I/O port address modified\n",
 					boardp->id);
 				break;
 			case ASC_WARN_AUTO_CONFIG:
 				ASC_PRINT1(
-"AscInitGetConfig: Board %d: I/O port increment switch enabled\n",
+"AscInitGetConfig: board %d: I/O port increment switch enabled\n",
 					boardp->id);
 				break;
 			case ASC_WARN_EEPROM_CHKSUM:
 				ASC_PRINT1(
-"AscInitGetConfig: Board %d: EEPROM checksum error\n",
+"AscInitGetConfig: board %d: EEPROM checksum error\n",
 					boardp->id);
 				break;
 			case ASC_WARN_IRQ_MODIFIED:
 				ASC_PRINT1(
-"AscInitGetConfig: Board %d: IRQ modified\n",
+"AscInitGetConfig: board %d: IRQ modified\n",
 					boardp->id);
 				break;
 			case ASC_WARN_CMD_QNG_CONFLICT:
 				ASC_PRINT1(
-"AscInitGetConfig: Board %d: tag queuing enabled w/o disconnects\n",
+"AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
 					boardp->id);
 				break;
 			default:
 				ASC_PRINT2(
-"AscInitGetConfig: Board %d: unknown warning: %x\n",
+"AscInitGetConfig: board %d: unknown warning: %x\n",
 					boardp->id, ret);
 				break;
 			}
 			if (asc_dvc_varp->err_code != 0) {
 				ASC_PRINT3(
-"AscInitGetConfig: Board %d error: init_state %x, err_code %x\n",
+"AscInitGetConfig: board %d error: init_state %x, err_code %x\n",
 					boardp->id, asc_dvc_varp->init_state,
 					asc_dvc_varp->err_code);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3117,38 +3200,38 @@
 				break;
 			case ASC_WARN_IO_PORT_ROTATE:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: I/O port address modified\n",
+"AscInitSetConfig: board %d: I/O port address modified\n",
 					boardp->id);
 				break;
 			case ASC_WARN_AUTO_CONFIG:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: I/O port increment switch enabled\n",
+"AscInitSetConfig: board %d: I/O port increment switch enabled\n",
 					boardp->id);
 				break;
 			case ASC_WARN_EEPROM_CHKSUM:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: EEPROM checksum error\n",
+"AscInitSetConfig: board %d: EEPROM checksum error\n",
 					boardp->id);
 				break;
 			case ASC_WARN_IRQ_MODIFIED:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: IRQ modified\n",
+"AscInitSetConfig: board %d: IRQ modified\n",
 					boardp->id);
 				break;
 			case ASC_WARN_CMD_QNG_CONFLICT:
 				ASC_PRINT1(
-"AscInitSetConfig: Board %d: tag queuing w/o disconnects\n",
+"AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
 					boardp->id);
 				break;
 			default:
 				ASC_PRINT2(
-"AscInitSetConfig: Board %d: unknown warning: %x\n",
+"AscInitSetConfig: board %d: unknown warning: %x\n",
 					boardp->id, ret);
 				break;
 			}
 			if (asc_dvc_varp->err_code != 0) {
 				ASC_PRINT3(
-"AscInitSetConfig: Board %d error: init_state %x, err_code %x\n",
+"AscInitSetConfig: board %d error: init_state %x, err_code %x\n",
 					boardp->id, asc_dvc_varp->init_state,
 					asc_dvc_varp->err_code);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3168,6 +3251,16 @@
 				shp->irq = asc_dvc_varp->irq_no;
 			}
 
+			/*
+			 * One host supports one channel. There are two different
+			 * hosts for each channel of a dual channel board.
+			 */
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+			shp->max_channel = 0;
+#endif /* version >= v1.3.89 */
+			shp->max_id = ASC_MAX_TID + 1;
+			shp->max_lun = ASC_MAX_LUN + 1;
+
 			shp->io_port = asc_dvc_varp->iop_base;
 			shp->n_io_port = ASC_IOADR_GAP;
 			shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
@@ -3196,7 +3289,6 @@
 			shp->cmd_per_lun = 0; /* 'cmd_per_lun' is no longer used. */
 #endif /* version >= v1.3.89 */
 
-			
 			/*
 			 * Maximum number of scatter-gather elements adapter can handle.
 			 *
@@ -3206,8 +3298,27 @@
 #ifdef MODULE
 			shp->sg_tablesize = 8;
 #else /* MODULE */
-			shp->sg_tablesize = ASC_MAX_SG_LIST;
+			/*
+			 * Allow two commands with 'sg_tablesize' scatter-gather
+			 * elements to be executed simultaneously. This value is
+			 * the theoretical hardware limit. It may be decreased
+			 * below.
+			 */
+			shp->sg_tablesize =
+				(((asc_dvc_varp->max_total_qng - 2) / 2) *
+				ASC_SG_LIST_PER_Q) + 1;
 #endif /* MODULE */
+
+			/*
+			 * The value of 'sg_tablesize' can not exceed the SCSI
+			 * mid-level driver definition of SG_ALL. SG_ALL also
+			 * must not be exceeded, because it is used to define the
+			 * size of the scatter-gather table in 'struct asc_sg_head'.
+			 */
+			if (shp->sg_tablesize > SG_ALL) {
+				shp->sg_tablesize = SG_ALL;
+			}
+
 			ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n",
 				shp->sg_tablesize);
 
@@ -3231,7 +3342,7 @@
 				shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
 				if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) {
 					ASC_PRINT3(
-"advansys_detect: Board %d: request_dma() %d failed %d\n",
+"advansys_detect: board %d: request_dma() %d failed %d\n",
 						boardp->id, shp->dma_channel, ret);
 					release_region(shp->io_port, shp->n_io_port);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3255,7 +3366,7 @@
 							"advansys", boardp)) != 0) {
 #endif /* version >= v1.3.70 */
 				ASC_PRINT2(
-"advansys_detect: Board %d: request_irq() failed %d\n",
+"advansys_detect: board %d: request_irq() failed %d\n",
 					boardp->id, ret);
 				release_region(shp->io_port, shp->n_io_port);
 				if (shp->dma_channel != NO_ISA_DMA) {
@@ -3275,7 +3386,7 @@
 			ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
 			if (AscInitAsc1000Driver(asc_dvc_varp)) {
 				ASC_PRINT3(
-"AscInitAsc1000Driver: Board %d error: init_state %x, err_code %x\n",
+"AscInitAsc1000Driver: board %d: error: init_state %x, err_code %x\n",
 					boardp->id, asc_dvc_varp->init_state,
 					asc_dvc_varp->err_code);
 				release_region(shp->io_port, shp->n_io_port);
@@ -3309,7 +3420,7 @@
 int
 advansys_release(struct Scsi_Host *shp)
 {
-	struct asc_board	*boardp;
+	asc_board_t	*boardp;
 
 	ASC_DBG(1, "advansys_release: begin\n");
 	boardp = ASC_BOARDP(shp);
@@ -3344,18 +3455,23 @@
 const char *
 advansys_info(struct Scsi_Host *shp)
 {
-	static char 		info[ASC_INFO_SIZE];
-	struct asc_board	*boardp;
-	ASC_DVC_VAR			*asc_dvc_varp;
-	char				*busname;
+	static char 	info[ASC_INFO_SIZE];
+	asc_board_t		*boardp;
+	ASC_DVC_VAR		*asc_dvc_varp;
+	char			*busname;
 
 	boardp = ASC_BOARDP(shp);
 	asc_dvc_varp = &boardp->asc_dvc_var;
 	ASC_DBG(1, "advansys_info: begin\n");
 	if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+		if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
+			busname = "ISA PnP";
+		} else {
+			busname = "ISA";
+		}
 		sprintf(info,
-			"AdvanSys SCSI %s: ISA (%u CDB): BIOS %X, IO %X-%X, IRQ %u, DMA %u",
-			ASC_VERSION, boardp->asc_dvc_var.max_total_qng,
+			"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u, DMA %u",
+			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 {
@@ -3364,16 +3480,21 @@
 		} else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
 			busname = "EISA";
 		} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-			busname = "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",
+"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",
+			"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u",
 			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);
@@ -3416,52 +3537,88 @@
 int
 advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
 {
-	struct Scsi_Host		*shp;
-	struct asc_board		*boardp;
-	int						flags = 0;
-	int						interrupts_disabled;
+	struct Scsi_Host	*shp;
+	asc_board_t			*boardp;
+	int					flags;
+	Scsi_Cmnd			*done_scp;
 
 	shp = scp->host;
 	boardp = ASC_BOARDP(shp);
 	ASC_STATS(shp, queuecommand);
 
 	/*
-	 * If there are any pending commands for this board before trying
-	 * to execute them, disable interrupts to preserve request ordering.
-	 *
-	 * The typical case will be no pending commands and interrupts
-	 * not disabled.
+	 * Disable interrupts to preserve request ordering and provide
+	 * mutually exclusive access to global structures used to initiate
+	 * a request.
 	 */
-	if (boardp->pending.tidmask == 0) {
-		interrupts_disabled = ASC_FALSE;
-	} else {
-		/* Disable interrupts */
-		interrupts_disabled = ASC_TRUE;
-		save_flags(flags);
-		cli();
-		ASC_DBG1(1, "advansys_queuecommand: asc_execute_queue() %x\n",
-			boardp->pending.tidmask);
-		asc_execute_queue(&boardp->pending);
-	}
+	save_flags(flags);
+	cli();
 
 	/*
-	 * Save the function pointer to Linux mid-level 'done' function and
-	 * execute the command.
+	 * Block new commands while handling a reset or abort request.
 	 */
-	scp->scsi_done = done;
-	if (asc_execute_scsi_cmnd(scp) == ASC_BUSY) {
-		if (interrupts_disabled == ASC_FALSE) {
-			save_flags(flags);
-			cli();
-			interrupts_disabled = ASC_TRUE;
+	if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
+		if (boardp->flags & ASC_HOST_IN_RESET) {
+			ASC_DBG1(1,
+				"advansys_queuecommand: scp %x blocked for reset request\n",
+				(unsigned) scp);
+			scp->result = HOST_BYTE(DID_RESET);
+		} else {
+			ASC_DBG1(1,
+				"advansys_queuecommand: scp %x blocked for abort request\n",
+				(unsigned) scp);
+			scp->result = HOST_BYTE(DID_ABORT);
 		}
-		asc_enqueue(&boardp->pending, scp, ASC_BACK);
-	}
 
-	if (interrupts_disabled == ASC_TRUE) {
+		/*
+		 * Add blocked requests to the board's 'scsi_done_q'. The queued
+		 * requests will be completed at the end of the abort or reset
+		 * handling.
+		 */
+		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 		restore_flags(flags);
+		return 0;
+	}
+
+	/*
+	 * Attempt to execute any waiting commands for the board.
+	 */
+	if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+		ASC_DBG(1,
+			"advansys_queuecommand: before asc_execute_queue() waiting\n");
+		asc_execute_queue(&boardp->waiting);
+	}
+
+	/*
+	 * Save the function pointer to Linux mid-level 'done' function
+	 * and attempt to execute the command.
+	 *
+	 * If ASC_ERROR is returned the request has been added to the
+	 * board's 'active' queue and will be completed by the interrupt
+	 * handler.
+	 *
+	 * If ASC_BUSY is returned add the request to the board's per
+	 * 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.
+	 */
+	scp->scsi_done = done;
+	switch (asc_execute_scsi_cmnd(scp)) {
+	case ASC_NOERROR:
+		break;
+	case ASC_BUSY:
+		asc_enqueue(&boardp->waiting, scp, ASC_BACK);
+		break;
+	case ASC_ERROR:
+	default:
+		done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL);
+		/* Interrupts could be enabled here. */
+		asc_scsi_done_list(done_scp);
+		break;
 	}
 
+	restore_flags(flags);
 	return 0;
 }
 
@@ -3473,49 +3630,70 @@
 int
 advansys_abort(Scsi_Cmnd *scp)
 {
-	struct asc_board	*boardp;
+	struct Scsi_Host	*shp;
+	asc_board_t			*boardp;
 	ASC_DVC_VAR			*asc_dvc_varp;
 	int					flags;
-	int					abort;
-	int					ret;
+	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);
-	ASC_STATS(scp->host, abort);
 
 	/* Save current flags and disable interrupts. */
 	save_flags(flags);
 	cli();
 
+#ifdef ADVANSYS_STATS
+	if (scp->host != NULL) {
+		ASC_STATS(scp->host, abort);
+	}	
+#endif /* ADVANSYS_STATS */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 	if (scp->serial_number != scp->serial_number_at_timeout) {
 		ret = SCSI_ABORT_NOT_RUNNING;
 	} else
 #endif /* version >= v1.3.89 */
-	if (scp->host == NULL) {
+	if ((shp = scp->host) == NULL) {
+		scp->result = HOST_BYTE(DID_ERROR);
+		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);
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_ABORT_ERROR;
 	} else {
-		boardp = ASC_BOARDP(scp->host);
-		if (asc_rmqueue(&boardp->pending, scp) == ASC_TRUE) {
+		/* Set abort flag to avoid nested reset or abort requests. */
+		boardp->flags |= ASC_HOST_IN_ABORT;
+
+		if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
 			/*
-		 	 * If asc_rmqueue() found the command on the pending
-			 * queue, it had not been sent to the Asc Library.
-			 * After the queue is removed, no other handling is required.
+		 	 * If asc_rmqueue() found the command on the waiting
+			 * queue, it had not been sent to the device. After
+			 * the queue is removed, no other handling is required.
 		 	 */
+			ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n",
+				(unsigned) scp);
 			scp->result = HOST_BYTE(DID_ABORT);
 			ret = SCSI_ABORT_SUCCESS;
 		} else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) {
 			/*
 		 	 * If asc_isqueued() found the command on the active
-			 * queue, it has been sent to the Asc Library. The
-			 * command should be returned through the interrupt
-			 * handler after calling AscAbortSRB().
+			 * queue, it has been sent to the device. The command
+			 * should be returned through the interrupt handler after
+			 * calling AscAbortSRB().
 		 	 */
 			asc_dvc_varp = &boardp->asc_dvc_var;
 			scp->result = HOST_BYTE(DID_ABORT);
-			/* Must enable interrupts for AscAbortSRB() */
-			sti();
-			switch (abort = AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
+
+			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)) {
 			case ASC_TRUE:
 				/* asc_isr_callback() will be called */
 				ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
@@ -3533,25 +3711,69 @@
 				break;
 			}
 			cli();
+
 			/*
 			 * If the abort failed, remove the request from the
 			 * active list and complete it.
 			 */
-			if (abort != ASC_TRUE) {
+			if (status != ASC_TRUE) {
 				if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
 					scp->result = HOST_BYTE(DID_ABORT);
-					scp->scsi_done(scp);
+					abort_do_done = ASC_TRUE;
 				}
 			}
+
 		} else {
 			/*
-			 * The command was not found on the active or pending queues.
+			 * The command was not found on the active or waiting queues.
 			 */
 			ret = SCSI_ABORT_NOT_RUNNING;
 		}
+
+		/* Clear abort flag. */
+		boardp->flags &= ~ASC_HOST_IN_ABORT;
+
+		/*
+		 * 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
+		 * 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);
+
+		/*
+		 * Start any waiting commands for the board.
+		 */
+		if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+			asc_execute_queue(&boardp->waiting);
+		}
+
+		/* Interrupts could be enabled here. */
+
+		/*
+		 * If needed, complete the aborted request.
+		 */
+		if (abort_do_done == ASC_TRUE) {
+			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.
+		 */
+		asc_scsi_done_list(done_scp);
 	}
-	restore_flags(flags);
+
 	ASC_DBG1(1, "advansys_abort: ret %d\n", ret);
+
+	/* Re-enable interrupts, if they were enabled on entry. */
+	restore_flags(flags);
+
+	ASC_ASSERT(ret != ASC_ERROR);
 	return ret;
 }
 
@@ -3567,44 +3789,74 @@
 advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
 #endif /* version >= v1.3.89 */
 {
-	struct asc_board	*boardp;
+	struct Scsi_Host	*shp;
+	asc_board_t			*boardp;
 	ASC_DVC_VAR			*asc_dvc_varp;
 	int					flags;
-	Scsi_Cmnd			*tscp;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+	Scsi_Cmnd			*done_scp = NULL, *last_scp = NULL;
+	Scsi_Cmnd			*tscp, *new_last_scp;
 	int					scp_found = ASC_FALSE;
-#endif /* version >= v1.3.89 */
-	int					i;
-	int					ret;
+	int 				device_reset = ASC_FALSE;
+	int					status;
+	int					target;
+	int					ret = ASC_ERROR;
 
 	ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
-	ASC_STATS(scp->host, reset);
 
 	/* Save current flags and disable interrupts. */
 	save_flags(flags);
 	cli();
 
+#ifdef ADVANSYS_STATS
+	if (scp->host != NULL) {
+		ASC_STATS(scp->host, reset);
+	}	
+#endif /* ADVANSYS_STATS */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 	if (scp->serial_number != scp->serial_number_at_timeout) {
 		ret = SCSI_RESET_NOT_RUNNING;
 	} else
 #endif /* version >= v1.3.89 */
-	if (scp->host == NULL) {
+	if ((shp = scp->host) == NULL) {
+		scp->result = HOST_BYTE(DID_ERROR);
+		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);
+		scp->result = HOST_BYTE(DID_ERROR);
+		ret = SCSI_RESET_ERROR;
+	} else if (jiffies >= boardp->reset_jiffies &&
+			   jiffies < (boardp->reset_jiffies + (10 * HZ))) {
+		/*
+		 * Don't allow a reset to be attempted within 10 seconds
+		 * of the last reset.
+		 *
+		 * If 'jiffies' wrapping occurs, the reset request will go
+		 * through, because a wrapped 'jiffies' would not pass the
+		 * test above.
+		 */
+		ASC_DBG(1,
+			"advansys_reset: reset within 10 sec of last reset ignored\n");
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_RESET_ERROR;
 	} else {
-		boardp = ASC_BOARDP(scp->host);
+		/* Set reset flag to avoid nested reset or abort requests. */
+		boardp->flags |= ASC_HOST_IN_RESET;
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 		/*
-	 	 * If the request is on the target pending or active queue,
-		 * note that it was found.
+	 	 * If the request is on the target waiting or active queue,
+		 * note that it was found and remove it from its queue.
 		 */
-		if ((asc_isqueued(&boardp->pending, scp) == ASC_TRUE) ||
-		    (asc_isqueued(&boardp->active, scp) == ASC_TRUE)) {
+		if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
+			ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n");
+			scp_found = ASC_TRUE;
+		} else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
+			ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n");
 			scp_found = ASC_TRUE;
 		}
-#endif /* version >= v1.3.89 */
 
 		/*
 		 * If the suggest reset bus flags are set, reset the bus.
@@ -3617,85 +3869,192 @@
 #endif /* version >= v1.3.89 */
 
 			/*
-			 * Done all pending requests for all targets with DID_RESET.
-			 */
-			for (i = 0; i <= ASC_MAX_TID; i++) {
-				while ((tscp = asc_dequeue(&boardp->pending, i)) != NULL) {
-					tscp->result = HOST_BYTE(DID_RESET);
-					tscp->scsi_done(tscp);
-				}
-			}
-
-			/*
 			 * Reset the target's SCSI bus.
 			 */
+			ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
 			sti();	/* Enable interrupts for AscResetSB(). */
-			switch (AscResetSB(asc_dvc_varp)) {
+			status = AscResetSB(asc_dvc_varp);
+			cli();
+			switch (status) {
 			case ASC_TRUE:
-				ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
+				ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
 				ret = SCSI_RESET_SUCCESS;
 				break;
 			case ASC_ERROR:
 			default:
-				ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
+				ASC_DBG(1, "advansys_reset: AscResetSB() failed\n");
 				ret = SCSI_RESET_ERROR;
 				break;
 			}
-			cli();
 
-			/*
-			 * Done all active requests for all targets with DID_RESET.
-			 */
-			for (i = 0; i <= ASC_MAX_TID; i++) {
-				while ((tscp = asc_dequeue(&boardp->active, i)) != NULL) {
-					tscp->result = HOST_BYTE(DID_RESET);
-					tscp->scsi_done(tscp);
-				}
-			}
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 		} else {
 			/*
-			 * Done all pending requests for the target with DID_RESET.
+			 * Reset the specified device. If the device reset fails,
+			 * then reset the SCSI bus.
 			 */
-			while ((tscp = asc_dequeue(&boardp->pending, scp->target))
-					!= NULL) {
-				tscp->result = HOST_BYTE(DID_RESET);
-				tscp->scsi_done(tscp);
-			}
 
-			sti();	/* Enabled interrupts for AscResetDevice(). */
-			ASC_DBG(1, "advansys_reset: AscResetDevice()\n");
-			(void) AscResetDevice(asc_dvc_varp, scp->target);
+			ASC_DBG1(1, "advansys_reset: before AscResetDevice(), target %d\n",
+				scp->target);
+			sti();	/* Enable interrupts for AscResetDevice(). */
+			status = AscResetDevice(asc_dvc_varp, scp->target);
 			cli();
 
 			/*
-			 * Done all active requests for the target with DID_RESET.
+			 * If the device has been reset, try to initialize it.
 			 */
-			while ((tscp = asc_dequeue(&boardp->active, scp->target))
-					!= NULL) {
-				tscp->result = HOST_BYTE(DID_RESET);
-				tscp->scsi_done(tscp);
+			if (status == ASC_TRUE) {
+				status = asc_init_dev(asc_dvc_varp, scp);
+			}
+
+			switch (status) {
+			case ASC_TRUE:
+				ASC_DBG(1, "advansys_reset: AscResetDevice() success\n");
+				device_reset = ASC_TRUE;
+				ret = SCSI_RESET_SUCCESS;
+				break;
+			case ASC_ERROR:
+			default:
+				ASC_DBG(1,
+"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
+				sti();	/* Enable interrupts for AscResetSB(). */
+				status = AscResetSB(asc_dvc_varp);
+				cli();
+				switch (status) {
+				case ASC_TRUE:
+					ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
+					ret = SCSI_RESET_SUCCESS;
+					break;
+				case ASC_ERROR:
+				default:
+					ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
+					ret = SCSI_RESET_ERROR;
+					break;
+				}
+				break;
 			}
 		}
 #endif /* version >= v1.3.89 */
 
+		/*
+		 * 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
+		 * prevents waiting commands from being executed,
+		 * these queued requests must be handled here.
+		 */
+		done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp,
+									ASC_TID_ALL);
+
+		/*
+		 * If a device reset was performed dequeue all waiting
+		 * and active requests for the device and set the request
+		 * status to DID_RESET.
+		 *
+		 * If a SCSI bus reset was performed dequeue all waiting
+		 * and active requests for all devices and set the request
+		 * status to DID_RESET.
+		 */
+		if (device_reset == ASC_TRUE) {
+			target = scp->target;
+		} else {
+			target = ASC_TID_ALL;
+		}
+
+		/*
+		 * Add active requests to 'done_scp' and set the request status
+		 * to DID_RESET.
+		 */
+		if (done_scp == NULL) {
+			done_scp = asc_dequeue_list(&boardp->active, &last_scp, target);
+			for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+				tscp->result = HOST_BYTE(DID_RESET);
+			}
+		} else {
+			ASC_ASSERT(last_scp != NULL);
+			REQPNEXT(last_scp) = asc_dequeue_list(&boardp->active,
+				&new_last_scp, target);
+			if (new_last_scp != NULL) {
+				ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+				for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+					tscp->result = HOST_BYTE(DID_RESET);
+				}
+				last_scp = new_last_scp;
+			}
+		}
+
+		/*
+		 * Add waiting requests to 'done_scp' and set the request status
+		 * to DID_RESET.
+		 */
+		if (done_scp == NULL) {
+			done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, target);
+			for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+				tscp->result = HOST_BYTE(DID_RESET);
+			}
+		} else {
+			ASC_ASSERT(last_scp != NULL);
+			REQPNEXT(last_scp) = asc_dequeue_list(&boardp->waiting,
+				&new_last_scp, target);
+			if (new_last_scp != NULL) {
+				ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+				for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+					tscp->result = HOST_BYTE(DID_RESET);
+				}
+				last_scp = new_last_scp;
+			}
+		}
+
+		/* Save the time of the most recently completed reset. */
+		boardp->reset_jiffies = jiffies;
+
+		/* Clear reset flag. */
+		boardp->flags &= ~ASC_HOST_IN_RESET;
+
+		/*
+		 * Start any waiting commands for the board.
+		 */
+		if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+			asc_execute_queue(&boardp->waiting);
+		}
+
+		/* Interrupts could be enabled here. */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 		/*
-		 * If the command was not on the active or pending request
-		 * queues and the SCSI_RESET_SYNCHRONOUS flag is set, then
-		 * done the command now. If the command had been on the
-		 * active or pending request queues it would have already
-		 * been completed.
+		 * 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_FALSE && (reset_flags & SCSI_RESET_SYNCHRONOUS)) {
+		if (scp_found == ASC_TRUE || (reset_flags & SCSI_RESET_SYNCHRONOUS)) {
 			scp->result = HOST_BYTE(DID_RESET);
-			scp->scsi_done(tscp);
+			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_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.
+		 */
+		asc_scsi_done_list(done_scp);
 	}
-	restore_flags(flags);
+
 	ASC_DBG1(1, "advansys_reset: ret %d", ret);
+
+	/* Re-enable interrupts, if they were enabled on entry. */
+	restore_flags(flags);
+
+	ASC_ASSERT(ret != ASC_ERROR);
 	return ret;
 }
 
@@ -3826,10 +4185,10 @@
  * First-level interrupt handler.
  *
  * For versions > v1.3.70, 'dev_id' is a pointer to the interrupting
- * adapter's struct asc_board. Because all boards are currently checked
+ * adapter's asc_board_t. Because all boards are currently checked
  * for interrupts on each interrupt, 'dev_id' is not referenced. 'dev_id'
- * could be used to identify an interrupt passed to the AdvanSys driver
- * but actually for a device sharing an interrupt with an AdvanSys adapter.
+ * could be used to identify an interrupt passed to the AdvanSys driver,
+ * which is for a device sharing an interrupt with an AdvanSys adapter.
  */
 STATIC void
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
@@ -3838,12 +4197,13 @@
 advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 #endif /* version >= v1.3.70 */
 {
-	int			i;
-	int			flags;
-	Scsi_Cmnd	*scp;
-	Scsi_Cmnd	*tscp;
+	int				flags;
+	int				i;
+	asc_board_t		*boardp;
+	Scsi_Cmnd		*done_scp = NULL, *last_scp = NULL;
+	Scsi_Cmnd		*new_last_scp;
 
-	/* Disable interrupts, if the aren't already disabled. */
+	/* Disable interrupts, if they aren't already disabled. */
 	save_flags(flags);
 	cli();
 
@@ -3854,31 +4214,57 @@
 	 */
 	for (i = 0; i < asc_board_count; i++) {
 		ASC_STATS(asc_host[i], check_interrupt);
+		boardp = ASC_BOARDP(asc_host[i]);
 		while (AscIsIntPending(asc_host[i]->io_port)) {
 			ASC_STATS(asc_host[i], interrupt);
 			ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
-			AscISR(&ASC_BOARDP(asc_host[i])->asc_dvc_var);
+			AscISR(&boardp->asc_dvc_var);
+		}
+
+		/*
+		 * Start waiting requests and create a list of completed requests.
+		 * 
+		 * If a reset or abort request is being performed for the board,
+		 * the reset or abort handler will complete pending requests after
+		 * it has completed.
+		 */
+    	if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) {
+			/* Start any waiting commands for the board. */
+			if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+				ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+				asc_execute_queue(&boardp->waiting);
+			}
+
+		 	/*
+			 * 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,
+					ASC_TID_ALL);
+			} else {
+				ASC_ASSERT(last_scp != NULL);
+				REQPNEXT(last_scp) = asc_dequeue_list(&boardp->scsi_done_q,
+					&new_last_scp, ASC_TID_ALL);
+				if (new_last_scp != NULL) {
+					ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+					last_scp = new_last_scp;
+				}
+			}
 		}
 	}
 
+	/* Interrupts could be enabled here. */
+
 	/*
-	 * While interrupts are still disabled save the list of requests that
-	 * need their done function called. After re-enabling interrupts call
-	 * the done function which may re-enable interrupts anyway.
+	 * 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 ((scp = asc_scsi_done) != NULL) {
-		asc_scsi_done = NULL;
-	}
+	asc_scsi_done_list(done_scp);
 
 	/* Re-enable interrupts, if they were enabled on entry. */
 	restore_flags(flags);
 
-	while (scp) {
-		tscp = (Scsi_Cmnd *) scp->host_scribble;
-		scp->scsi_done(scp);
-		scp = tscp;
-	}
-
 	ASC_DBG(1, "advansys_interrupt: end\n");
 	return;
 }
@@ -3891,8 +4277,8 @@
 STATIC void
 advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
 {
-	Scsi_Device			*device;
-	struct asc_board	*boardp;
+	Scsi_Device		*device;
+	asc_board_t		*boardp;
 
 	boardp = ASC_BOARDP(shp);
 	for (device = devicelist; device != NULL; device = device->next) {
@@ -3918,6 +4304,27 @@
 }
 
 /*
+ * Complete all requests on the singly linked list pointed
+ * to by 'scp'.
+ *
+ * Interrupts can be enabled on entry.
+ */
+STATIC void
+asc_scsi_done_list(Scsi_Cmnd *scp)
+{
+	Scsi_Cmnd	*tscp;
+
+	while (scp != NULL) {
+		tscp = REQPNEXT(scp);
+		REQPNEXT(scp) = NULL;
+		ASC_STATS(scp->host, done);
+		scp->scsi_done(scp);
+		scp = tscp;
+	}
+	return;
+}
+
+/*
  * Execute a single 'Scsi_Cmnd'.
  *
  * The function 'done' is called when the request has been completed.
@@ -3952,20 +4359,21 @@
  *  scsi_done - used to save caller's done function
  * 	host_scribble - used for pointer to another Scsi_Cmnd
  *
- * If this function returns ASC_NOERROR or ASC_ERROR the done
- * function has been called. If ASC_BUSY is returned the request
- * must be enqueued by the caller and re-tried later.
+ * If this function returns ASC_NOERROR or ASC_ERROR the request
+ * has been enqueued on the board's 'scsi_done_q' and must be
+ * completed by the caller.
+ *
+ * If ASC_BUSY is returned the request must be enqueued by the
+ * caller and re-tried later.
  */
 STATIC int
 asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
 {
-	struct asc_board	*boardp;
-	ASC_DVC_VAR			*asc_dvc_varp;
-	ASC_SCSI_Q			scsiq;
-	ASC_SG_HEAD			sghead;
-	int					flags;
-	int					ret;
+	asc_board_t		*boardp;
+	ASC_DVC_VAR		*asc_dvc_varp;
+	int				ret;
 
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n",
 		(unsigned) scp, (unsigned) scp->scsi_done);
 
@@ -3979,30 +4387,34 @@
 	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);
-			scp->scsi_done(scp);
+			asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 			return ASC_ERROR;
 		}
 		boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target);
 	}
 
-	memset(&scsiq, 0, sizeof(ASC_SCSI_Q));
+	/*
+	 * Mutually exclusive access is required to 'asc_scsi_q' and
+	 * 'asc_sg_head' until after the request is started.
+	 */
+	memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
 
 	/*
 	 * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'.
 	 */
-	scsiq.q2.srb_ptr = (ulong) scp;
+	asc_scsi_q.q2.srb_ptr = (ulong) scp;
 
 	/*
 	 * Build the ASC_SCSI_Q request.
 	 */
-	scsiq.cdbptr = &scp->cmnd[0];
-	scsiq.q2.cdb_len = scp->cmd_len;
-	scsiq.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-	scsiq.q1.target_lun = scp->lun;
-	scsiq.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
-	scsiq.q1.sense_addr = (ulong) &scp->sense_buffer[0];
-	scsiq.q1.sense_len = sizeof(scp->sense_buffer);
-	scsiq.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+	asc_scsi_q.cdbptr = &scp->cmnd[0];
+	asc_scsi_q.q2.cdb_len = scp->cmd_len;
+	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);
+	asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0];
+	asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
+	asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
 
 	/*
 	 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
@@ -4014,12 +4426,12 @@
 		 */
 		ASC_STATS(scp->host, cont_cnt);
  		/* request_buffer is already a real address. */
-		scsiq.q1.data_addr = (ulong) scp->request_buffer;
-		scsiq.q1.data_cnt = scp->request_bufflen;
+		asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer;
+		asc_scsi_q.q1.data_cnt = scp->request_bufflen;
 		ASC_STATS_ADD(scp->host, cont_xfer,
 					  ASC_CEILING(scp->request_bufflen, 512));
-		scsiq.q1.sg_queue_cnt = 0;
-		scsiq.sg_head = NULL;
+		asc_scsi_q.q1.sg_queue_cnt = 0;
+		asc_scsi_q.sg_head = NULL;
 	} else {
 		/*
 		 * CDB scatter-gather request list.
@@ -4027,11 +4439,12 @@
 		int					sgcnt;
 		struct scatterlist	*slp;
 
-		if (scp->use_sg > ASC_MAX_SG_LIST) {
-			ASC_PRINT3("asc_execute_scsi_cmnd: Board %d: use_sg %d > %d\n",
-				boardp->id, scp->use_sg, ASC_MAX_SG_LIST);
+		if (scp->use_sg > scp->host->sg_tablesize) {
+			ASC_PRINT3(
+"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);
-			scp->scsi_done(scp);
+			asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 			return ASC_ERROR;
 		}
 
@@ -4041,40 +4454,37 @@
 		 * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q
 		 * to point to it.
 		 */
-		memset(&sghead, 0, sizeof(ASC_SG_HEAD));
+		memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
 
-		scsiq.q1.cntl |= QC_SG_HEAD;
-		scsiq.sg_head = &sghead;
-		scsiq.q1.data_cnt = 0;
-		scsiq.q1.data_addr = 0;
-		sghead.entry_cnt = scsiq.q1.sg_queue_cnt = scp->use_sg;
-		ASC_STATS_ADD(scp->host, sg_elem, sghead.entry_cnt);
+		asc_scsi_q.q1.cntl |= QC_SG_HEAD;
+		asc_scsi_q.sg_head = &asc_sg_head;
+		asc_scsi_q.q1.data_cnt = 0;
+		asc_scsi_q.q1.data_addr = 0;
+		asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg;
+		ASC_STATS_ADD(scp->host, sg_elem, asc_sg_head.entry_cnt);
 
 		/*
 		 * Convert scatter-gather list into ASC_SG_HEAD list.
 		 */
 		slp = (struct scatterlist *) scp->request_buffer;
 		for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
-			sghead.sg_list[sgcnt].addr = (ulong) slp->address;
-			sghead.sg_list[sgcnt].bytes = slp->length;
+			asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address;
+			asc_sg_head.sg_list[sgcnt].bytes = slp->length;
 			ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 		}
 	}
 
-	ASC_DBG_PRT_SCSI_Q(2, &scsiq);
+	ASC_DBG_PRT_SCSI_Q(2, &asc_scsi_q);
 	ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
 
 	/*
-	 * Disable interrupts to issue the command and add the
-	 * command to the active queue if it is started.
+	 * Execute the command. If there is no error, add the command
+	 * to the active queue.
 	 */
-	save_flags(flags);
-	cli();
-
-	switch (ret = AscExeScsiQueue(asc_dvc_varp, &scsiq)) {
+	switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
 	case ASC_NOERROR:
-		asc_enqueue(&boardp->active, scp, ASC_BACK);
 		ASC_STATS(scp->host, asc_noerror);
+		asc_enqueue(&boardp->active, scp, ASC_BACK);
 		ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
 		break;
 	case ASC_BUSY:
@@ -4083,24 +4493,24 @@
 		break;
 	case ASC_ERROR:
 		ASC_PRINT2(
-"asc_execute_scsi_cmnd: Board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
+"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);
 		scp->result = HOST_BYTE(DID_ERROR);
-		scp->scsi_done(scp);
+		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 		break;
 	default:
 		ASC_PRINT2(
-"asc_execute_scsi_cmnd: Board %d: AscExeScsiQueue() unknown, err_code %x\n",
+"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);
 		scp->result = HOST_BYTE(DID_ERROR);
-		scp->scsi_done(scp);
+		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
 		break;
 	}
-	restore_flags(flags);
 
 	ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	return ret;
 }
 
@@ -4110,10 +4520,10 @@
 void
 asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
 {
-	struct asc_board	*boardp;
+	asc_board_t			*boardp;
 	Scsi_Cmnd			*scp;
 	struct Scsi_Host	*shp;
-	Scsi_Cmnd			**scpp;
+	int					i;
 
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n",
@@ -4128,16 +4538,40 @@
 	ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp);
 	ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
 
+	if (scp == NULL) {
+		ASC_PRINT("asc_isr_callback: scp is NULL\n");
+		return;
+	}
+
+	/*
+	 * If the request's host pointer is not valid, display a
+	 * message and return.
+	 */
 	shp = scp->host;
-	ASC_ASSERT(shp);
+	for (i = 0; i < asc_board_count; i++) {
+		if (asc_host[i] == shp) {
+			break;
+		}
+	}
+	if (i == asc_board_count) {
+		ASC_PRINT2("asc_isr_callback: scp %x has bad host pointer, host %x\n",
+			(unsigned) scp, (unsigned) shp);
+		return;
+	}
+
 	ASC_STATS(shp, callback);
 	ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp);
 
+	/*
+	 * If the request isn't found on the active queue, it may
+	 * have been removed to handle a reset or abort request.
+	 * Display a message and return.
+	 */
 	boardp = ASC_BOARDP(shp);
 	if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-		ASC_PRINT2(
-"asc_isr_callback: Board %d: scp %x not on active queue\n",
+		ASC_PRINT2("asc_isr_callback: board %d: scp %x not on active queue\n",
 			boardp->id, (unsigned) scp);
+		return;
 	}
 
 	/*
@@ -4205,33 +4639,14 @@
 		break;
 	}
 
-	/*
-	 * Before calling 'scsi_done' for the current 'Scsi_Cmnd' and possibly
-	 * triggering more commands to be issued, try to start any pending
-	 * commands.
-	 */
-	if (boardp->pending.tidmask != 0) {
-	 	/*
-		 * If there are any pending commands for this board before trying
-	 	 * to execute them, disable interrupts to preserve request ordering.
-		 */
-		ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-		ASC_DBG1(1, "asc_isr_callback: asc_execute_queue() %x\n",
-			boardp->pending.tidmask);
-		asc_execute_queue(&boardp->pending);
-	}
-
 	/* 
-	 * Because interrupts may be enabled by the 'Scsi_Cmnd' done function,
-	 * add the command to the end of the global done list. The done function
-	 * for the command will be called in advansys_interrupt().
+	 * Because interrupts may be enabled by the 'Scsi_Cmnd' done
+	 * function, add the command to the end of the board's done queue.
+	 * The done function for the command will be called from
+	 * advansys_interrupt().
 	 */
-	for (scpp = &asc_scsi_done; *scpp;
-	     scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) {
-		;
-	}
-	*scpp = scp;
-	scp->host_scribble = NULL;
+	asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+
 	return;
 }
 
@@ -4243,10 +4658,7 @@
 STATIC int
 asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 {
-	struct asc_board		*boardp;
-	ASC_SCSI_REQ_Q			*scsireqq;
-	ASC_CAP_INFO			*cap_info;
-	ASC_SCSI_INQUIRY		*inquiry;
+	asc_board_t				*boardp;
 	int						found;
 	ASC_SCSI_BIT_ID_TYPE	save_use_tagged_qng;
 	ASC_SCSI_BIT_ID_TYPE	save_can_tagged_qng;
@@ -4257,26 +4669,15 @@
 
 	ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target);
 
-	/* The hosts's target id is set in init_tidmask during initialization. */
+	/* The host's target id is set in init_tidmask during initialization. */
 	ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target);
 
 	boardp = ASC_BOARDP(scp->host);
 
-	/*
-	 * XXX - Host drivers should not modify the timeout field.
-	 * But on the first command only add some extra time to
-	 * allow the driver to complete its initialization for the
-	 * device.
-	 */
-	scp->timeout += 2000;	/* Add 5 seconds to the request timeout. */
-
 	/* Set-up AscInitPollTarget() arguments. */
-	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;
-	memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
+	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));
 
 	/*
 	 * XXX - AscInitPollBegin() re-initializes these fields to
@@ -4289,28 +4690,29 @@
 
 	ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n");
 	if (AscInitPollBegin(asc_dvc_varp)) {
-		ASC_PRINT1("asc_init_dev: Board %d: AscInitPollBegin() failed\n",
+		ASC_PRINT1("asc_init_dev: board %d: AscInitPollBegin() failed\n",
 			boardp->id);
 		return ASC_FALSE;
 	}
 
-	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);
+	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);
 
 	found = ASC_FALSE;
 	ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n");
-	switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry, cap_info)) {
+	switch (ret = AscInitPollTarget(asc_dvc_varp, &asc_scsireqq,
+		&asc_inquiry, &asc_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",
-			cap_info->lba, cap_info->blk_size);
+			asc_cap_info.lba, asc_cap_info.blk_size);
 		ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
-			inquiry->byte0.peri_dvc_type);
+			asc_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]);
@@ -4334,12 +4736,12 @@
 		ASC_DBG(1, "asc_init_dev: no device found\n");
 		break;
 	case ASC_ERROR:
-		ASC_PRINT1("asc_init_dev: Board %d: AscInitPollTarget() ASC_ERROR\n",
+		ASC_PRINT1("asc_init_dev: board %d: AscInitPollTarget() ASC_ERROR\n",
 				boardp->id);
 		break;
 	default:
 		ASC_PRINT2(
-"asc_init_dev: Board %d: AscInitPollTarget() unknown ret %d\n",
+"asc_init_dev: board %d: AscInitPollTarget() unknown ret %d\n",
 				boardp->id, ret);
 		break;
 	}
@@ -4351,6 +4753,8 @@
 	ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n");
 	AscInitPollEnd(asc_dvc_varp);
 
+	ASC_DBG1(1, "asc_init_dev: found %d\n", found); 
+
 	return found;
 }
 
@@ -4753,36 +5157,42 @@
 void
 asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
 {
-	REQP	*reqpp;
 	int		tid;
 
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG3(2, "asc_enqueue: ascq %x, reqp %x, flag %d\n",
 		(unsigned) ascq, (unsigned) reqp, flag);
-	tid = REQPTID(reqp);
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	ASC_ASSERT(reqp != NULL);
 	ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
+	tid = REQPTID(reqp);
+	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
 	if (flag == ASC_FRONT) {
-		REQPNEXT(reqp) = ascq->queue[tid];
-		ascq->queue[tid] = reqp;
+		REQPNEXT(reqp) = ascq->q_first[tid];
+		ascq->q_first[tid] = reqp;
+		/* If the queue was empty, set the last pointer. */
+		if (ascq->q_last[tid] == NULL) {
+			ascq->q_last[tid] = reqp;
+		}
 	} else { /* ASC_BACK */
-		for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) {
-			ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-			;
+		if (ascq->q_last[tid] != NULL) {
+			REQPNEXT(ascq->q_last[tid]) = reqp;
 		}
-		*reqpp = reqp;
+		ascq->q_last[tid] = reqp;
 		REQPNEXT(reqp) = NULL;
+		/* If the queue was empty, set the first pointer. */
+		if (ascq->q_first[tid] == NULL) {
+			ascq->q_first[tid] = reqp;
+		}
 	}
 	/* The queue has at least one entry, set its bit. */
-	ascq->tidmask |= ASC_TIX_TO_TARGET_ID(tid);
+	ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid);
 #ifdef ADVANSYS_STATS
-	/*
-	 * Maintain request queue statistics.
-	 */
-	ascq->cur_count[tid]++;
-	if (ascq->cur_count[tid] > ascq->max_count[tid]) {
-		ascq->max_count[tid] = ascq->cur_count[tid];
-		ASC_DBG2(1, "asc_enqueue: new max_count[%d] %d\n",
-			tid, ascq->max_count[tid]);
+	/* Maintain request queue statistics. */
+	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]);
 	}
 #endif /* ADVANSYS_STATS */
 	ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp);
@@ -4801,30 +5211,103 @@
 {
 	REQP	reqp;
 
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG2(1, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid);
-	if ((reqp = ascq->queue[tid]) != NULL) {
-		ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-		ascq->queue[tid] = REQPNEXT(reqp);
-		/* If the queue is empty, clear its bit. */
-		if (ascq->queue[tid] == NULL) {
-			ascq->tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+	if ((reqp = ascq->q_first[tid]) != NULL) {
+		ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
+		ascq->q_first[tid] = REQPNEXT(reqp);
+		/* If the queue is empty, clear its bit and the last pointer. */
+		if (ascq->q_first[tid] == NULL) {
+			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+			ASC_ASSERT(ascq->q_last[tid] == reqp);
+			ascq->q_last[tid] = NULL;
 		}
-	}
 #ifdef ADVANSYS_STATS
-	/*
-	 * Maintain request queue statistics.
-	 */
-	if (reqp != NULL) {
-		ascq->cur_count[tid]--;
-	}
-	ASC_ASSERT(ascq->cur_count[tid] >= 0);
+		/* Maintain request queue statistics. */
+		ascq->q_cur_cnt[tid]--;
+		ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
+	}
 	ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp);
 	return reqp;
 }
 
 /*
+ * Return a pointer to a singly linked list of all the requests queued
+ * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
+ *
+ * If 'lastpp' is not NULL, '*lastpp' will be set to point to the 
+ * the last request returned in the singly linked list.
+ *
+ * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
+ * then all queued requests are concatenated into one list and
+ * returned.
+ *
+ * Note: If 'lastpp' is used to append a new list to the end of
+ * an old list, only change the old list last pointer if '*lastpp'
+ * (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.
+ */
+REQP
+asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
+{
+	REQP	firstp, lastp;
+	int		i;
+
+	ASC_DBG2(1, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid);
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ASC_MAX_TID));
+
+	/*
+	 * If 'tid' is not ASC_TID_ALL, return requests only for
+	 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
+	 * requests for all tids.
+	 */
+	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. */
+			firstp = lastp = NULL;
+		} else {
+			firstp = ascq->q_first[tid];
+			lastp = ascq->q_last[tid];
+			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;
+#endif /* ADVANSYS_STATS */
+		}
+	} else {
+		/* Return all requests for all tids. */
+		firstp = lastp = NULL;
+		for (i = 0; i <= ASC_MAX_TID; i++) {
+			if (ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
+				if (firstp == NULL) {
+					firstp = ascq->q_first[i];
+					lastp = ascq->q_last[i];
+				} else {
+					ASC_ASSERT(lastp != NULL);
+					REQPNEXT(lastp) = ascq->q_first[i];
+					lastp = ascq->q_last[i];
+				}
+				ascq->q_first[i] = ascq->q_last[i] = NULL;
+				ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
+#ifdef ADVANSYS_STATS
+				ascq->q_cur_cnt[i] = 0;
+#endif /* ADVANSYS_STATS */
+			}
+		}
+	}
+	if (lastpp) {
+		*lastpp = lastp;
+	}
+	ASC_DBG1(1, "asc_dequeue_list: firstp %x\n", (unsigned) firstp);
+	return firstp;
+}
+
+/*
  * Remove the specified 'REQP' from the specified queue for
  * the specified target device. Clear the 'tidmask' bit for the
  * device if no more commands are left queued for it.
@@ -4837,34 +5320,61 @@
 int
 asc_rmqueue(asc_queue_t *ascq, REQP reqp)
 {
-	REQP		*reqpp;
+	REQP		currp, prevp;
 	int			tid;
-	int			ret;
+	int			ret = ASC_FALSE;
 
+	ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %d\n",
+		(unsigned) ascq, (unsigned) reqp);
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ret = ASC_FALSE;
+	ASC_ASSERT(reqp != NULL);
+
 	tid = REQPTID(reqp);
-	for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) {
-		ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-		if (*reqpp == reqp) {
-			ret = ASC_TRUE;
-			*reqpp = REQPNEXT(reqp);
-			REQPNEXT(reqp) = NULL;
-			/* If the queue is now empty, clear its bit. */
-			if (ascq->queue[tid] == NULL) {
-				ascq->tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+
+	/*
+	 * Handle the common case of 'reqp' being the first
+	 * entry on the queue.
+	 */
+	if (reqp == ascq->q_first[tid]) {
+		ret = ASC_TRUE;
+		ascq->q_first[tid] = REQPNEXT(reqp);
+		/* If the queue is now empty, clear its bit and the last pointer. */
+		if (ascq->q_first[tid] == NULL) {
+			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+			ASC_ASSERT(ascq->q_last[tid] == reqp);
+			ascq->q_last[tid] = NULL;
+		}
+	} else if (ascq->q_first[tid] != NULL) {
+		ASC_ASSERT(ascq->q_last[tid] != NULL);
+		/*
+		 * Because the case of 'reqp' being the first entry has been
+		 * handled above and it is known the queue is not empty, if
+		 * 'reqp' is found on the queue it is guaranteed the queue will
+		 * not become empty and that 'q_first[tid]' will not be changed.
+		 *
+		 * Set 'prevp' to the first entry, 'currp' to the second entry,
+		 * and search for 'reqp'.
+		 */
+		for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
+			 currp; prevp = currp, currp = REQPNEXT(currp)) {
+			if (currp == reqp) {
+				ret = ASC_TRUE;
+				REQPNEXT(prevp) = REQPNEXT(currp);
+				REQPNEXT(reqp) = NULL;
+				if (ascq->q_last[tid] == reqp) {
+					ascq->q_last[tid] = prevp;
+				}
+				break;
 			}
-			break; /* Note: *reqpp may now be NULL, don't iterate. */
 		}
 	}
 #ifdef ADVANSYS_STATS
-	/*
-	 * Maintain request queue statistics.
-	 */
+	/* Maintain request queue statistics. */
 	if (ret == ASC_TRUE) {
-		ascq->cur_count[tid]--;
+		ascq->q_cur_cnt[tid]--;
 	}
-	ASC_ASSERT(ascq->cur_count[tid] >= 0);
+	ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
 	ASC_DBG2(1, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret);
 	return ret;
@@ -4877,16 +5387,21 @@
 int
 asc_isqueued(asc_queue_t *ascq, REQP reqp)
 {
-	REQP		*reqpp;
+	REQP		treqp;
 	int			tid;
-	int			ret;
+	int			ret = ASC_FALSE;
 
+	ASC_DBG2(1, "asc_isqueued: ascq %x, reqp %x\n",
+		(unsigned) ascq, (unsigned) reqp);
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-	ret = ASC_FALSE;
+	ASC_ASSERT(reqp != NULL);
+
 	tid = REQPTID(reqp);
-	for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) {
-		ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid));
-		if (*reqpp == reqp) {
+	ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+
+	for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) {
+		ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
+		if (treqp == reqp) {
 			ret = ASC_TRUE;
 			break;
 		}
@@ -4906,13 +5421,13 @@
 	REQP					reqp;
 	int						i;
 
-	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq);
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	/*
 	 * Execute queued commands for devices attached to
 	 * the current board in round-robin fashion.
 	 */
-	scan_tidmask = ascq->tidmask;
+	scan_tidmask = ascq->q_tidmask;
 	do {
 		for (i = 0; i <= ASC_MAX_TID; i++) {
 			if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
@@ -4944,11 +5459,11 @@
 STATIC int
 asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	struct asc_board	*boardp;
-	int					leftlen;
-	int					totlen;
-	int					len;
-	int					i;
+	asc_board_t		*boardp;
+	int				leftlen;
+	int				totlen;
+	int				len;
+	int				i;
 
 	boardp = ASC_BOARDP(shp);
 	leftlen = cplen;
@@ -4989,14 +5504,14 @@
 STATIC int
 asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	struct asc_board	*boardp;
-	ASC_DVC_VAR			*asc_dvc_varp;
-	int					leftlen;
-	int					totlen;
-	int					len;
-	ASCEEP_CONFIG       *ep;
-	int					i;
-	int					isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+	asc_board_t		*boardp;
+	ASC_DVC_VAR		*asc_dvc_varp;
+	int				leftlen;
+	int				totlen;
+	int				len;
+	ASCEEP_CONFIG	*ep;
+	int				i;
+	int				isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
 
 	boardp = ASC_BOARDP(shp);
 	asc_dvc_varp = &boardp->asc_dvc_var;
@@ -5069,6 +5584,70 @@
 }
 
 /*
+ * asc_prt_driver_conf()
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
+{
+	int					leftlen;
+	int					totlen;
+	int					len;
+
+	leftlen = cplen;
+	totlen = len = 0;
+
+	len = asc_prt_line(cp, leftlen,
+"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
+		shp->host_no);
+	ASC_PRT_NEXT();
+
+	len = asc_prt_line(cp, leftlen,
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,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)
+" 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 */
+" unchecked_isa_dma %d, loaded_as_module %d\n",
+		shp->unchecked_isa_dma, 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);
+	ASC_PRT_NEXT();
+
+ 	return totlen;
+}
+
+/*
  * asc_prt_board_info()
  *
  * Print dynamic board configuration information.
@@ -5082,7 +5661,7 @@
 STATIC int
 asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 {
-	struct asc_board	*boardp;
+	asc_board_t			*boardp;
 	int					leftlen;
 	int					totlen;
 	int					len;
@@ -5106,7 +5685,7 @@
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version %u, lib_serial_no %u mcode_date %u\n",
+" chip_version %u, lib_version %u, lib_serial_no %u, mcode_date %u\n",
 		c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
 	ASC_PRT_NEXT();
 
@@ -5115,7 +5694,7 @@
 		 c->mcode_version, v->err_code);
 	ASC_PRT_NEXT();
 
-	/* Current number of commands pending for the host. */
+	/* Current number of commands waiting for the host. */
 	len = asc_prt_line(cp, leftlen,
 " Total Command Pending:    %d\n", v->cur_total_qng);
 	ASC_PRT_NEXT();
@@ -5150,7 +5729,7 @@
 	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
 
-	/* Current number of commands pending for a device. */
+	/* Current number of commands waiting for a device. */
 	len = asc_prt_line(cp, leftlen,
 " Command Queue Pending:   ");
 	ASC_PRT_NEXT();
@@ -5495,7 +6074,7 @@
 }
 
 /*
- * Return the BIOS address of the adatper at the specified
+ * 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.
@@ -5565,7 +6144,7 @@
 	struct asc_stats	*s;
 	int					i;
 	asc_queue_t			*active;
-	asc_queue_t			*pending;
+	asc_queue_t			*waiting;
 
 	leftlen = cplen;
 	totlen = len = 0;
@@ -5581,8 +6160,8 @@
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-" check_interrupt %lu, interrupt %lu, callback %lu\n",
-		s->check_interrupt, s->interrupt, s->callback);
+" check_interrupt %lu, interrupt %lu, callback %lu, done %lu\n",
+		s->check_interrupt, s->interrupt, s->callback, s->done);
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
@@ -5598,13 +6177,13 @@
 	ASC_PRT_NEXT();
 
 	active = &ASC_BOARDP(shp)->active;
-	pending = &ASC_BOARDP(shp)->pending;
+	waiting = &ASC_BOARDP(shp)->waiting;
 	for (i = 0; i < ASC_MAX_TID + 1; i++) {
-		if (active->max_count[i] > 0 || pending->max_count[i] > 0) {
+		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], pending [cur %d, max %d]\n",
-				i, active->cur_count[i], active->max_count[i],
-				pending->cur_count[i], pending->max_count[i]);
+"  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();
 		}
 	}
@@ -6287,10 +6866,11 @@
 					sdtr_xmsg.req_ack_offset = ASC_SYN_MAX_OFFSET;
 				}
 				if (
-					   (sdtr_xmsg.xfer_period < asc_dvc->sdtr_period_tbl[0])
+					   (sdtr_xmsg.xfer_period < asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index])
 					   || (sdtr_xmsg.xfer_period > asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])
 				  ) {
 					sdtr_accept = FALSE;
+					sdtr_xmsg.xfer_period = asc_dvc->sdtr_period_tbl[ asc_dvc->host_init_sdtr_index ] ;
 				}
 				if (sdtr_accept) {
 					sdtr_data = AscCalSDTRData(asc_dvc, sdtr_xmsg.xfer_period,
@@ -6344,7 +6924,7 @@
 			sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
 			q_cntl |= QC_MSG_OUT;
 			AscMsgOutSDTR(asc_dvc,
-						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)],
+						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (asc_dvc->max_sdtr_index - 1)],
 						  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
 		}
 #endif
@@ -6418,8 +6998,8 @@
 				}
 #ifdef ADVANSYS_STATS
 				{
-					struct asc_board   *boardp;
-					int                 i;
+					asc_board_t		*boardp;
+					int				i;
 					for (i = 0; i < ASC_NUM_BOARD_SUPPORTED; i++) {
 						if (asc_host[i] == NULL) {
 							continue;
@@ -6768,156 +7348,156 @@
 	return (0);
 }
 
-uchar               _mcode_buf[] =
-{
-	0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xC4, 0x0C, 0x08, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x23, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00,
-	0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC6, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
-	0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC6, 0x00, 0x92, 0x80,
-	0x20, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x4A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80,
-	0x4F, 0x00, 0xF5, 0x00, 0x4A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
-	0x92, 0x80, 0x00, 0x62, 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
-	0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x00, 0xA8, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
-	0xD2, 0x84, 0xD0, 0xC1, 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE6, 0x01, 0xA8, 0x97,
-	0xD2, 0x81, 0x00, 0x33, 0x02, 0x00, 0xC2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1,
-	0x06, 0x01, 0x4F, 0x00, 0x86, 0x97, 0x07, 0xA6, 0x10, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
-	0x03, 0x03, 0x03, 0xDE, 0x00, 0x33, 0x05, 0x00, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
-	0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x84, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x30, 0x01, 0x84, 0x81,
-	0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x40, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88,
-	0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x6A, 0x98, 0x4D, 0x04, 0xF0, 0x84, 0x05, 0xD8,
-	0x0D, 0x23, 0x6A, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01,
-	0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00,
-	0x07, 0xA3, 0x7A, 0x01, 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
-	0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x94, 0x81, 0x06, 0xAB, 0x8E, 0x01, 0x94, 0x81, 0x4E, 0x00,
-	0x07, 0xA3, 0x9E, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x48, 0x01, 0x00, 0x05, 0x88, 0x81, 0x48, 0x97,
-	0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xCA, 0x81, 0xFD, 0x23,
-	0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xC0, 0x01, 0x80, 0x63,
-	0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0xC2, 0x88, 0x06, 0x23, 0x6A, 0x98, 0xCD, 0x04,
-	0xD2, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xE0, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE6, 0x01, 0xD2, 0x84,
-	0x80, 0x23, 0xA0, 0x01, 0xD2, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x02,
-	0x04, 0x01, 0x0D, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x86, 0x97, 0x08, 0x82, 0x08, 0x23,
-	0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x64, 0x97, 0x48, 0x04, 0xFF, 0x23, 0x84, 0x80, 0xF2, 0x97,
-	0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42,
-	0x06, 0xE2, 0x03, 0xEE, 0x66, 0xEB, 0x11, 0x23, 0xF8, 0x88, 0x06, 0x98, 0xF8, 0x80, 0x80, 0x73,
-	0x80, 0x77, 0x06, 0xA6, 0x3C, 0x02, 0x00, 0x33, 0x31, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x03, 0xD8,
-	0xB4, 0x98, 0x3E, 0x96, 0x4E, 0x82, 0xCE, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D,
-	0x02, 0xA6, 0x78, 0x02, 0x07, 0xA6, 0x66, 0x02, 0x06, 0xA6, 0x6A, 0x02, 0x03, 0xA6, 0x6E, 0x02,
-	0x00, 0x33, 0x10, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0x50, 0x82, 0x34, 0x96, 0x50, 0x82, 0x04, 0x23,
-	0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x28, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61,
-	0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01,
-	0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x66, 0x02,
-	0x06, 0xA6, 0x6A, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43,
-	0x00, 0xA0, 0x98, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01,
-	0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
-	0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0x98, 0xC8, 0x00, 0x33, 0x1F, 0x00,
-	0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x80, 0x98, 0xB6, 0x2D, 0x01, 0xA6,
-	0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
-	0x0C, 0x04, 0x02, 0xA6, 0x78, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0xEE, 0x82,
-	0x34, 0x96, 0xEE, 0x82, 0x84, 0x98, 0x80, 0x42, 0x80, 0x98, 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8,
-	0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x88, 0x98,
-	0x80, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, 0x28, 0x04, 0x06, 0xA6,
-	0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0x32, 0x83,
-	0x34, 0x96, 0x32, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0xC2, 0x88,
-	0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x72, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
-	0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x92, 0x03, 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38,
-	0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x8E, 0x03, 0x00, 0xA6, 0x8E, 0x03, 0x02, 0x84, 0x80, 0x42,
-	0x80, 0x98, 0x01, 0xA6, 0x9C, 0x03, 0x00, 0xA6, 0xB4, 0x03, 0x02, 0x84, 0xA8, 0x98, 0x80, 0x42,
-	0x01, 0xA6, 0x9C, 0x03, 0x07, 0xA6, 0xAA, 0x03, 0xCC, 0x83, 0x6A, 0x95, 0xA0, 0x83, 0x00, 0x33,
-	0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42, 0x00, 0xA6, 0xB4, 0x03, 0x07, 0xA6, 0xC2, 0x03,
-	0xCC, 0x83, 0x6A, 0x95, 0xB8, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
-	0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x02, 0x84, 0x04, 0xF0, 0x80, 0x6B,
-	0x00, 0x33, 0x20, 0x00, 0xC2, 0x88, 0x03, 0xA6, 0x00, 0x04, 0x07, 0xA6, 0xF8, 0x03, 0x06, 0xA6,
-	0xFC, 0x03, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0xE6, 0x83, 0x34, 0x96, 0xE6, 0x83,
-	0x0C, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0xC2, 0x88, 0xB6, 0x2D, 0x03, 0xA6,
-	0x28, 0x04, 0x07, 0xA6, 0x20, 0x04, 0x06, 0xA6, 0x24, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88,
-	0x6A, 0x95, 0x0C, 0x84, 0x34, 0x96, 0x0C, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
-	0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x46, 0x04,
-	0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x50, 0x04,
-	0x23, 0x01, 0x00, 0xA2, 0x72, 0x04, 0x0A, 0xA0, 0x62, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
-	0xC2, 0x88, 0x0B, 0xA0, 0x6E, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0xC2, 0x88, 0x42, 0x23,
-	0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xD2, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x8E, 0x04, 0x28, 0x23,
-	0x22, 0xA3, 0x9A, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xB0, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
-	0x06, 0x61, 0x00, 0xA0, 0x9A, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x06, 0x98, 0x00, 0xA2, 0xAC, 0x04,
-	0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF4, 0x81, 0x47, 0x23, 0xF8, 0x88,
-	0x04, 0x01, 0x0B, 0xDE, 0x06, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
-	0x14, 0x01, 0x00, 0xA0, 0x0E, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23,
-	0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xE0, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88,
-	0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x06, 0x98, 0x14, 0x95,
-	0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x0E, 0x05, 0x00, 0x05, 0x76, 0x00,
-	0x06, 0x61, 0x00, 0xA2, 0x08, 0x05, 0xF6, 0x84, 0x48, 0x97, 0xCD, 0x04, 0x12, 0x85, 0x48, 0x04,
-	0xFF, 0x23, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x22, 0x85, 0x02, 0x23,
-	0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x2E, 0x05, 0x1D, 0x01, 0x04, 0xD6, 0xFF, 0x23,
-	0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81, 0x01, 0x04, 0x01,
-	0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00,
-	0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x4E, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00,
-	0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xCC, 0x05, 0x03, 0x03,
-	0x02, 0xA0, 0x7C, 0x05, 0xC8, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xA2, 0x05,
-	0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x8E, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23,
-	0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x64, 0x97, 0xF0, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01,
-	0xF0, 0x84, 0x08, 0xA0, 0xA8, 0x05, 0xC8, 0x85, 0x03, 0xA0, 0xAE, 0x05, 0xC8, 0x85, 0x01, 0xA0,
-	0xBA, 0x05, 0x88, 0x00, 0x80, 0x63, 0xB8, 0x96, 0x6A, 0x85, 0x07, 0xA0, 0xC6, 0x05, 0x06, 0x23,
-	0x6A, 0x98, 0x48, 0x23, 0xF8, 0x88, 0xC8, 0x86, 0x80, 0x63, 0x6A, 0x85, 0x00, 0x63, 0x4A, 0x00,
-	0x06, 0x61, 0x00, 0xA2, 0x0A, 0x06, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03,
-	0x80, 0x63, 0x06, 0xA6, 0xEC, 0x05, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x02, 0xD6,
-	0x46, 0x23, 0xF8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x04, 0x06, 0x00, 0x33,
-	0x38, 0x00, 0xC2, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
-	0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x22, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
-	0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
-	0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x06, 0xA6,
-	0x50, 0x06, 0x07, 0xA6, 0xA4, 0x06, 0x02, 0xA6, 0xFC, 0x06, 0x00, 0x33, 0x39, 0x00, 0xC2, 0x88,
-	0x00, 0x00, 0x01, 0xA0, 0x16, 0x07, 0xCE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x64, 0x06,
-	0x07, 0xA6, 0xA4, 0x06, 0x00, 0x00, 0x01, 0xA0, 0x16, 0x07, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63,
-	0x01, 0x00, 0x06, 0xA6, 0x80, 0x06, 0x07, 0xA6, 0xA4, 0x06, 0x00, 0x33, 0x3A, 0x00, 0xC2, 0x88,
-	0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x72, 0x06, 0x06, 0xA6, 0x98, 0x06, 0x07, 0xA6,
-	0xA4, 0x06, 0x00, 0x33, 0x3B, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6,
-	0xA4, 0x06, 0x00, 0x63, 0x03, 0x03, 0x80, 0x63, 0x88, 0x00, 0x01, 0xA2, 0xB8, 0x06, 0x07, 0xA2,
-	0xFC, 0x06, 0x00, 0x33, 0x35, 0x00, 0xC2, 0x88, 0x07, 0xA6, 0xC2, 0x06, 0x00, 0x33, 0x2A, 0x00,
-	0xC2, 0x88, 0x03, 0x03, 0x03, 0xA2, 0xCE, 0x06, 0x07, 0x23, 0x80, 0x00, 0x08, 0x87, 0x80, 0x63,
-	0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xDE, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43,
-	0x00, 0xA2, 0xEA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xD4, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80,
-	0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x00, 0x63, 0x80, 0x67, 0x00, 0x33,
-	0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x5C, 0x06,
-	0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x30, 0x07, 0xCE, 0x95, 0x83, 0x03, 0x80, 0x63,
-	0x06, 0xA6, 0x2E, 0x07, 0x07, 0xA6, 0xA4, 0x06, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, 0x00, 0x00,
-	0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x46, 0x07, 0x07, 0xA6, 0xA4, 0x06, 0xBF, 0x23,
-	0x04, 0x61, 0x84, 0x01, 0xD2, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01,
-	0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05,
-	0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00,
-	0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00,
-	0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00,
-	0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04,
-	0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01,
-	0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xC6, 0x07,
-	0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00,
-	0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2,
-	0xE6, 0x07, 0x00, 0x05, 0xDC, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05,
-	0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08,
-	0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02,
-	0x00, 0xA0, 0x16, 0x08, 0x18, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
-	0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2,
-	0x46, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x26, 0x08,
-	0x06, 0x98, 0x14, 0x95, 0x26, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x5C, 0x88,
-	0x02, 0x01, 0x04, 0xD8, 0x48, 0x97, 0x06, 0x98, 0x14, 0x95, 0x4C, 0x88, 0x75, 0x00, 0x00, 0xA3,
-	0x66, 0x08, 0x00, 0x05, 0x50, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
-	0x78, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63,
-	0x38, 0x2B, 0x9E, 0x88, 0x38, 0x2B, 0x94, 0x88, 0x32, 0x09, 0x31, 0x05, 0x94, 0x98, 0x05, 0x05,
-	0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32,
-	0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A,
-	0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3,
-	0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
-	0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01,
-	0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2,
-	0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xD2, 0x84,
-};
+uchar _mcode_buf[ ] = {
+  0x01,  0x03,  0x01,  0x19,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x10,  0x0D,  0x09,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0xFF,  0x80,  0xFF,  0xFF,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x23,  0x00,  0x21,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
+  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xDC,  0x88,  0x00,  0x00,  0x00,  0x00,
+  0x80,  0x73,  0x48,  0x04,  0x36,  0x00,  0x00,  0xA2,  0xC2,  0x00,  0x80,  0x73,  0x03,  0x23,  0x36,  0x40,
+  0xB6,  0x00,  0x36,  0x00,  0x05,  0xD6,  0x0C,  0xD2,  0x12,  0xDA,  0x00,  0xA2,  0xC2,  0x00,  0x92,  0x80,
+  0x18,  0x98,  0x50,  0x00,  0xF5,  0x00,  0x42,  0x98,  0xDF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,
+  0x4F,  0x00,  0xF5,  0x00,  0x42,  0x98,  0xEF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,  0x80,  0x62,
+  0x92,  0x80,  0x00,  0x46,  0x17,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
+  0x00,  0xA3,  0xD6,  0x00,  0xA0,  0x97,  0x7F,  0x23,  0x04,  0x61,  0x84,  0x01,  0xCC,  0x84,  0xD2,  0xC1,
+  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xE2,  0x01,  0xA0,  0x97,  0xCE,  0x81,  0x00,  0x33,
+  0x02,  0x00,  0xBA,  0x88,  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0x02,  0x01,  0x4F,  0x00,
+  0x7E,  0x97,  0x07,  0xA6,  0x0C,  0x01,  0x00,  0x33,  0x03,  0x00,  0xBA,  0x88,  0x03,  0x03,  0x03,  0xDE,
+  0x00,  0x33,  0x05,  0x00,  0xBA,  0x88,  0xCE,  0x00,  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,
+  0x00,  0xA2,  0x80,  0x01,  0x80,  0x63,  0x07,  0xA6,  0x2C,  0x01,  0x80,  0x81,  0x03,  0x03,  0x80,  0x63,
+  0xE2,  0x00,  0x07,  0xA6,  0x3C,  0x01,  0x00,  0x33,  0x04,  0x00,  0xBA,  0x88,  0x03,  0x07,  0x02,  0x01,
+  0x04,  0xCA,  0x0D,  0x23,  0x62,  0x98,  0x4D,  0x04,  0xEA,  0x84,  0x05,  0xD8,  0x0D,  0x23,  0x62,  0x98,
+  0xCD,  0x04,  0x15,  0x23,  0xF0,  0x88,  0xFB,  0x23,  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,
+  0x06,  0xA3,  0x6A,  0x01,  0x00,  0x33,  0x0A,  0x00,  0xBA,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x76,  0x01,
+  0x00,  0x33,  0x0B,  0x00,  0xBA,  0x88,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xBA,  0x88,
+  0x50,  0x04,  0x90,  0x81,  0x06,  0xAB,  0x8A,  0x01,  0x90,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x9A,  0x01,
+  0x50,  0x00,  0x00,  0xA3,  0x44,  0x01,  0x00,  0x05,  0x84,  0x81,  0x40,  0x97,  0x02,  0x01,  0x05,  0xC6,
+  0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,  0xC6,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,
+  0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xBC,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,
+  0x00,  0x33,  0x1B,  0x00,  0xBA,  0x88,  0x06,  0x23,  0x62,  0x98,  0xCD,  0x04,  0xCC,  0x84,  0x06,  0x01,
+  0x00,  0xA2,  0xDC,  0x01,  0x57,  0x60,  0x00,  0xA0,  0xE2,  0x01,  0xCC,  0x84,  0x80,  0x23,  0xA0,  0x01,
+  0xCC,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x08,  0x02,  0x04,  0x01,  0x0C,  0xDE,
+  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x7E,  0x97,  0x04,  0x82,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,
+  0x4F,  0x00,  0x5C,  0x97,  0x48,  0x04,  0x84,  0x80,  0xEA,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,
+  0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x67,  0xEB,
+  0x11,  0x23,  0xF0,  0x88,  0xFE,  0x97,  0xF4,  0x80,  0x80,  0x73,  0x80,  0x77,  0x06,  0xA6,  0x36,  0x02,
+  0x00,  0x33,  0x31,  0x00,  0xBA,  0x88,  0x04,  0x01,  0x03,  0xD8,  0xAC,  0x98,  0x36,  0x96,  0x48,  0x82,
+  0xC6,  0x95,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x02,  0xA6,  0x72,  0x02,  0x07,  0xA6,
+  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x03,  0xA6,  0x68,  0x02,  0x00,  0x33,  0x10,  0x00,  0xBA,  0x88,
+  0x62,  0x95,  0x4A,  0x82,  0x2C,  0x96,  0x4A,  0x82,  0x04,  0x23,  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,
+  0x22,  0x84,  0x04,  0x01,  0x0C,  0xDC,  0xE0,  0x23,  0x25,  0x61,  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,
+  0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,  0x03,  0x23,  0xA4,  0x01,  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,
+  0x1C,  0x01,  0x02,  0xA6,  0xA4,  0x02,  0x07,  0xA6,  0x60,  0x02,  0x06,  0xA6,  0x64,  0x02,  0x00,  0x33,
+  0x12,  0x00,  0xBA,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,  0x92,  0x02,  0x4D,  0x04,
+  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,  0x10,  0x31,  0x12,  0x35,  0x14,  0x01,
+  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xE4,  0x82,  0x18,  0x23,  0x04,  0x61,  0x18,  0xA0,
+  0xDC,  0x02,  0x04,  0x01,  0x98,  0xC8,  0x00,  0x33,  0x1F,  0x00,  0xBA,  0x88,  0x08,  0x31,  0x0A,  0x35,
+  0x0C,  0x39,  0x0E,  0x3D,  0x78,  0x98,  0xB6,  0x2D,  0x01,  0xA6,  0x0E,  0x03,  0x00,  0xA6,  0x0E,  0x03,
+  0x07,  0xA6,  0x06,  0x03,  0x06,  0xA6,  0x0A,  0x03,  0x03,  0xA6,  0x06,  0x04,  0x02,  0xA6,  0x72,  0x02,
+  0x00,  0x33,  0x33,  0x00,  0xBA,  0x88,  0x62,  0x95,  0xE8,  0x82,  0x2C,  0x96,  0xE8,  0x82,  0x7C,  0x98,
+  0x80,  0x42,  0x78,  0x98,  0x60,  0xE4,  0x04,  0x01,  0x29,  0xC8,  0x31,  0x05,  0x07,  0x01,  0x00,  0xA2,
+  0x4E,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x80,  0x98,  0x78,  0x98,  0x00,  0xA6,  0x10,  0x03,
+  0x07,  0xA6,  0x46,  0x03,  0x03,  0xA6,  0x22,  0x04,  0x06,  0xA6,  0x4A,  0x03,  0x01,  0xA6,  0x10,  0x03,
+  0x00,  0x33,  0x25,  0x00,  0xBA,  0x88,  0x62,  0x95,  0x2C,  0x83,  0x2C,  0x96,  0x2C,  0x83,  0x04,  0x01,
+  0x0C,  0xCE,  0x03,  0xC8,  0x00,  0x33,  0x42,  0x00,  0xBA,  0x88,  0x00,  0x01,  0x05,  0x05,  0xFF,  0xA2,
+  0x6C,  0x03,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x28,  0x83,  0x05,  0x05,  0x15,  0x01,  0x00,  0xA2,
+  0x8C,  0x03,  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0x01,  0xA6,
+  0x88,  0x03,  0x00,  0xA6,  0x88,  0x03,  0xFC,  0x83,  0x80,  0x42,  0x78,  0x98,  0x01,  0xA6,  0x96,  0x03,
+  0x00,  0xA6,  0xAE,  0x03,  0xFC,  0x83,  0xA0,  0x98,  0x80,  0x42,  0x01,  0xA6,  0x96,  0x03,  0x07,  0xA6,
+  0xA4,  0x03,  0xC6,  0x83,  0x62,  0x95,  0x9A,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xBA,  0x88,  0xA0,  0x98,
+  0x80,  0x42,  0x00,  0xA6,  0xAE,  0x03,  0x07,  0xA6,  0xBC,  0x03,  0xC6,  0x83,  0x62,  0x95,  0xB2,  0x83,
+  0x00,  0x33,  0x26,  0x00,  0xBA,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,  0xA0,  0x01,
+  0x12,  0x23,  0xA1,  0x01,  0xFC,  0x83,  0x04,  0xF0,  0x80,  0x6B,  0x00,  0x33,  0x20,  0x00,  0xBA,  0x88,
+  0x03,  0xA6,  0xFA,  0x03,  0x07,  0xA6,  0xF2,  0x03,  0x06,  0xA6,  0xF6,  0x03,  0x00,  0x33,  0x17,  0x00,
+  0xBA,  0x88,  0x62,  0x95,  0xE0,  0x83,  0x2C,  0x96,  0xE0,  0x83,  0x06,  0x84,  0x04,  0xF0,  0x80,  0x6B,
+  0x00,  0x33,  0x20,  0x00,  0xBA,  0x88,  0xB6,  0x2D,  0x03,  0xA6,  0x22,  0x04,  0x07,  0xA6,  0x1A,  0x04,
+  0x06,  0xA6,  0x1E,  0x04,  0x00,  0x33,  0x30,  0x00,  0xBA,  0x88,  0x62,  0x95,  0x06,  0x84,  0x2C,  0x96,
+  0x06,  0x84,  0x1D,  0x01,  0x06,  0xCC,  0x00,  0x33,  0x00,  0x84,  0xC0,  0x20,  0x00,  0x23,  0xEA,  0x00,
+  0x81,  0x62,  0xA2,  0x0D,  0x80,  0x63,  0x07,  0xA6,  0x40,  0x04,  0x00,  0x33,  0x18,  0x00,  0xBA,  0x88,
+  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,  0x07,  0xA4,  0x4A,  0x04,  0x23,  0x01,  0x00,  0xA2,  0x6C,  0x04,
+  0x0A,  0xA0,  0x5C,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1D,  0x00,  0xBA,  0x88,  0x0B,  0xA0,  0x68,  0x04,
+  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,  0xBA,  0x88,  0x42,  0x23,  0xF0,  0x88,  0x00,  0x23,  0x22,  0xA3,
+  0xCC,  0x04,  0x08,  0x23,  0x22,  0xA3,  0x88,  0x04,  0x28,  0x23,  0x22,  0xA3,  0x94,  0x04,  0x02,  0x23,
+  0x22,  0xA3,  0xAA,  0x04,  0x42,  0x23,  0xF0,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0x94,  0x04,
+  0x45,  0x23,  0xF0,  0x88,  0xFE,  0x97,  0x00,  0xA2,  0xA6,  0x04,  0xAC,  0x98,  0x00,  0x33,  0x00,  0x82,
+  0xC0,  0x20,  0x81,  0x62,  0xF0,  0x81,  0x47,  0x23,  0xF0,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0xFE,  0x97,
+  0xAC,  0x98,  0x00,  0x33,  0x00,  0x81,  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x08,  0x02,
+  0x43,  0x23,  0xF0,  0x88,  0x04,  0x23,  0xA0,  0x01,  0x44,  0x23,  0xA1,  0x01,  0x80,  0x73,  0x4D,  0x00,
+  0x03,  0xA3,  0xDA,  0x04,  0x00,  0x33,  0x27,  0x00,  0xBA,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,
+  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xFE,  0x97,  0x0C,  0x95,  0x4B,  0x00,  0xF6,  0x00,  0x4F,  0x04,
+  0x4F,  0x00,  0x00,  0xA3,  0x08,  0x05,  0x00,  0x05,  0x76,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x02,  0x05,
+  0xF0,  0x84,  0x40,  0x97,  0xCD,  0x04,  0x0A,  0x85,  0x48,  0x04,  0x84,  0x80,  0x02,  0x01,  0x03,  0xDA,
+  0x80,  0x23,  0x82,  0x01,  0x1A,  0x85,  0x02,  0x23,  0xA0,  0x01,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,
+  0x26,  0x05,  0x1D,  0x01,  0x04,  0xD6,  0xFF,  0x23,  0x86,  0x41,  0x4B,  0x60,  0xCB,  0x00,  0xFF,  0x23,
+  0x80,  0x01,  0x49,  0x00,  0x81,  0x01,  0x04,  0x01,  0x02,  0xC8,  0x30,  0x01,  0x80,  0x01,  0xF7,  0x04,
+  0x03,  0x01,  0x49,  0x04,  0x80,  0x01,  0xC9,  0x00,  0x00,  0x05,  0x00,  0x01,  0xFF,  0xA0,  0x46,  0x05,
+  0x77,  0x04,  0x01,  0x23,  0xEA,  0x00,  0x5D,  0x00,  0xFE,  0xC7,  0x00,  0x62,  0x00,  0x23,  0xEA,  0x00,
+  0x00,  0x63,  0x07,  0xA4,  0xC4,  0x05,  0x03,  0x03,  0x02,  0xA0,  0x74,  0x05,  0xC0,  0x85,  0x00,  0x33,
+  0x2D,  0x00,  0xBA,  0x88,  0x04,  0xA0,  0x9A,  0x05,  0x80,  0x63,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,
+  0x86,  0x05,  0x1D,  0x01,  0x06,  0xD6,  0x02,  0x23,  0x02,  0x41,  0x82,  0x01,  0x50,  0x00,  0x5C,  0x97,
+  0xEA,  0x84,  0x04,  0x23,  0x02,  0x41,  0x82,  0x01,  0xEA,  0x84,  0x08,  0xA0,  0xA0,  0x05,  0xC0,  0x85,
+  0x03,  0xA0,  0xA6,  0x05,  0xC0,  0x85,  0x01,  0xA0,  0xB2,  0x05,  0x88,  0x00,  0x80,  0x63,  0xB0,  0x96,
+  0x62,  0x85,  0x07,  0xA0,  0xBE,  0x05,  0x06,  0x23,  0x62,  0x98,  0x48,  0x23,  0xF0,  0x88,  0xC0,  0x86,
+  0x80,  0x63,  0x62,  0x85,  0x00,  0x63,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x02,  0x06,  0x1D,  0x01,
+  0x18,  0xD4,  0xC0,  0x23,  0x07,  0x41,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0xE4,  0x05,  0x00,  0x33,
+  0x37,  0x00,  0xBA,  0x88,  0x1D,  0x01,  0x02,  0xD6,  0x46,  0x23,  0xF0,  0x88,  0x63,  0x60,  0x83,  0x03,
+  0x80,  0x63,  0x06,  0xA6,  0xFC,  0x05,  0x00,  0x33,  0x38,  0x00,  0xBA,  0x88,  0xEF,  0x04,  0x6F,  0x00,
+  0x00,  0x63,  0x4B,  0x00,  0x06,  0x41,  0xCB,  0x00,  0x52,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x1A,  0x06,
+  0x1D,  0x01,  0x03,  0xCA,  0xC0,  0x23,  0x07,  0x41,  0x00,  0x63,  0x1D,  0x01,  0x04,  0xCC,  0x00,  0x33,
+  0x00,  0x83,  0xC0,  0x20,  0x81,  0x62,  0x80,  0x23,  0x07,  0x41,  0x00,  0x63,  0x80,  0x67,  0x08,  0x23,
+  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x06,  0xA6,  0x48,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x02,  0xA6,
+  0xF4,  0x06,  0x00,  0x33,  0x39,  0x00,  0xBA,  0x88,  0x00,  0x00,  0x01,  0xA0,  0x0E,  0x07,  0xC6,  0x95,
+  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x5C,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x00,  0x01,  0xA0,
+  0x0E,  0x07,  0x00,  0x2B,  0x40,  0x0E,  0x80,  0x63,  0x01,  0x00,  0x06,  0xA6,  0x78,  0x06,  0x07,  0xA6,
+  0x9C,  0x06,  0x00,  0x33,  0x3A,  0x00,  0xBA,  0x88,  0x40,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,
+  0x6A,  0x06,  0x06,  0xA6,  0x90,  0x06,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x33,  0x3B,  0x00,  0xBA,  0x88,
+  0x80,  0x67,  0x40,  0x0E,  0x80,  0x63,  0x07,  0xA6,  0x9C,  0x06,  0x00,  0x63,  0x03,  0x03,  0x80,  0x63,
+  0x88,  0x00,  0x01,  0xA2,  0xB0,  0x06,  0x07,  0xA2,  0xF4,  0x06,  0x00,  0x33,  0x35,  0x00,  0xBA,  0x88,
+  0x07,  0xA6,  0xBA,  0x06,  0x00,  0x33,  0x2A,  0x00,  0xBA,  0x88,  0x03,  0x03,  0x03,  0xA2,  0xC6,  0x06,
+  0x07,  0x23,  0x80,  0x00,  0x00,  0x87,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,  0xD6,  0x06,
+  0x00,  0x33,  0x29,  0x00,  0xBA,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xE2,  0x06,  0xC0,  0x0E,  0x80,  0x63,
+  0xCC,  0x86,  0xC0,  0x0E,  0x00,  0x33,  0x00,  0x80,  0xC0,  0x20,  0x81,  0x62,  0x04,  0x01,  0x08,  0xDA,
+  0x80,  0x63,  0x00,  0x63,  0x80,  0x67,  0x00,  0x33,  0x00,  0x40,  0xC0,  0x20,  0x81,  0x62,  0x00,  0x63,
+  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x54,  0x06,  0x00,  0x33,  0x2C,  0x00,  0xBA,  0x88,  0x0C,  0xA2,
+  0x28,  0x07,  0xC6,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x26,  0x07,  0x07,  0xA6,  0x9C,  0x06,
+  0x00,  0x33,  0x3D,  0x00,  0xBA,  0x88,  0x00,  0x00,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x0C,  0xA0,
+  0x3E,  0x07,  0x07,  0xA6,  0x9C,  0x06,  0xBF,  0x23,  0x04,  0x61,  0x84,  0x01,  0xCC,  0x84,  0x00,  0x63,
+  0xF0,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x00,  0x01,  0xF2,  0x00,  0x01,  0x05,  0x80,  0x01,  0x72,  0x04,
+  0x71,  0x00,  0x81,  0x01,  0x70,  0x04,  0x80,  0x05,  0x81,  0x05,  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,
+  0x72,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x81,  0x01,  0x70,  0x04,  0x71,  0x00,  0x81,  0x01,
+  0x72,  0x00,  0x80,  0x01,  0x71,  0x04,  0x70,  0x00,  0x80,  0x01,  0x70,  0x04,  0x00,  0x63,  0xF0,  0x04,
+  0xF2,  0x00,  0x72,  0x04,  0x00,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x80,  0x01,  0x70,  0x04,  0x71,  0x00,
+  0x80,  0x01,  0x72,  0x00,  0x81,  0x01,  0x71,  0x04,  0x70,  0x00,  0x81,  0x01,  0x70,  0x04,  0x00,  0x63,
+  0x00,  0x23,  0xB3,  0x01,  0x83,  0x05,  0xA3,  0x01,  0xA2,  0x01,  0xA1,  0x01,  0x01,  0x23,  0xA0,  0x01,
+  0x00,  0x01,  0xC8,  0x00,  0x03,  0xA1,  0xBE,  0x07,  0x00,  0x33,  0x07,  0x00,  0xBA,  0x88,  0x80,  0x05,
+  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,
+  0x05,  0x01,  0x48,  0x04,  0x00,  0x43,  0x00,  0xA2,  0xDE,  0x07,  0x00,  0x05,  0xD4,  0x87,  0x00,  0x01,
+  0xC8,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x05,  0x05,  0x00,  0x63,  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,
+  0x6E,  0x04,  0x00,  0x02,  0x80,  0x43,  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF7,  0x04,
+  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x00,  0xA0,  0x0E,  0x08,  0x10,  0x88,  0x00,  0x43,
+  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF3,  0x04,  0x00,  0x23,  0xF4,  0x00,  0x74,  0x00,
+  0x80,  0x43,  0xF4,  0x00,  0xCF,  0x40,  0x00,  0xA2,  0x3E,  0x08,  0x74,  0x04,  0x02,  0x01,  0xF7,  0xC9,
+  0xF6,  0xD9,  0x00,  0x01,  0x01,  0xA1,  0x1E,  0x08,  0xFE,  0x97,  0x0C,  0x95,  0x1E,  0x88,  0x73,  0x04,
+  0x00,  0x63,  0xF3,  0x04,  0x75,  0x04,  0x54,  0x88,  0x02,  0x01,  0x04,  0xD8,  0x40,  0x97,  0xFE,  0x97,
+  0x0C,  0x95,  0x44,  0x88,  0x75,  0x00,  0x00,  0xA3,  0x5E,  0x08,  0x00,  0x05,  0x48,  0x88,  0x73,  0x04,
+  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x70,  0x08,  0x00,  0x33,  0x3E,  0x00,  0xBA,  0x88,
+  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,  0x96,  0x88,  0x38,  0x2B,  0x8C,  0x88,
+  0x32,  0x09,  0x31,  0x05,  0x8C,  0x98,  0x05,  0x05,  0xB2,  0x09,  0x00,  0x63,  0x00,  0x32,  0x00,  0x36,
+  0x00,  0x3A,  0x00,  0x3E,  0x00,  0x63,  0x80,  0x32,  0x80,  0x36,  0x80,  0x3A,  0x80,  0x3E,  0x00,  0x63,
+  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,  0x40,  0x3E,  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,
+  0x00,  0xA0,  0xAC,  0x08,  0x5D,  0x00,  0xFE,  0xC3,  0x00,  0x63,  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,
+  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,  0x13,  0x23,  0xF0,  0x88,  0x66,  0x20,  0xC0,  0x20,
+  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,  0x81,  0x62,  0xDA,  0x88,  0x80,  0x73,  0x80,  0x77,
+  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,  0xF1,  0xC7,  0x41,  0x23,  0xF0,  0x88,  0x11,  0x23,
+  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xCC,  0x84,
+} ;
+
+ushort _mcode_size = sizeof(_mcode_buf);
+ulong  _mcode_chksum = 0x012BA2FAUL ;
 
-ushort              _mcode_size = sizeof (_mcode_buf);
-ulong               _mcode_chksum = 0x012CD3FFUL;
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
 uchar               _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
 {
@@ -6978,7 +7558,9 @@
 		return (ERR);
 	}
 	scsiq->q1.q_no = 0;
-	scsiq->q1.extra_bytes = 0;
+	if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+		scsiq->q1.extra_bytes = 0;
+	}
 	sta = 0;
 	target_ix = scsiq->q2.target_ix;
 	tid_no = ASC_TIX_TO_TID(target_ix);
@@ -6988,7 +7570,7 @@
 			((asc_dvc->sdtr_done & scsiq->q1.target_id) != 0)) {
 			sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
 			AscMsgOutSDTR(asc_dvc,
-						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)],
+						  asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (asc_dvc->max_sdtr_index - 1)],
 						  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
 			scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
 		}
@@ -7082,7 +7664,7 @@
 					addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr +
 					  sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
 					extra_bytes = (uchar) ((ushort) addr & 0x0003);
-					if (extra_bytes != 0) {
+					if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) {
 						scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
 						scsiq->q1.extra_bytes = extra_bytes;
 						sg_head->sg_list[sg_entry_cnt_minus_one].bytes -= (ulong) extra_bytes;
@@ -7122,7 +7704,7 @@
 				  ) {
 					addr = scsiq->q1.data_addr + scsiq->q1.data_cnt;
 					extra_bytes = (uchar) ((ushort) addr & 0x0003);
-					if (extra_bytes != 0) {
+					if ((extra_bytes != 0) && ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0)) {
 						if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) {
 							scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
 							scsiq->q1.data_cnt -= (ulong) extra_bytes;
@@ -7307,7 +7889,7 @@
 		return (cur_free_qs);
 	}
 	if (n_qs > 1) {
-		if (n_qs > asc_dvc->last_q_shortage) {
+		if ((n_qs > asc_dvc->last_q_shortage) && ( n_qs <= ( asc_dvc->max_total_qng - ASC_MIN_FREE_Q ))) {
 			asc_dvc->last_q_shortage = n_qs;
 		}
 	}
@@ -7332,7 +7914,7 @@
 		((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
 		tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
 		sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-		syn_period_ix = (sdtr_data >> 4) & (ASC_SYN_XFER_NO - 1);
+		syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
 		syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
 		AscMsgOutSDTR(asc_dvc,
 					  asc_dvc->sdtr_period_tbl[syn_period_ix],
@@ -8686,8 +9268,7 @@
 	asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
 	asc_dvc->redo_scam = 0;
 	asc_dvc->res2 = 0;
-	asc_dvc->res4 = 0;
-	asc_dvc->res6 = 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;
@@ -8746,7 +9327,6 @@
 		asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L;
 		asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L;
 		asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
-		asc_dvc->cfg->sdtr_period_offset[i] = (uchar) (ASC_DEF_SDTR_OFFSET | (ASC_DEF_SDTR_INDEX << 4));
 	}
 	return (warn_code);
 }
@@ -8855,12 +9435,20 @@
 	}
 	eep_config->chip_scsi_id &= ASC_MAX_TID;
 	asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id;
+	if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA ) == ASC_IS_PCI_ULTRA ) &&
+	    !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+		asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
+	}
+
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 #if CC_TMP_USE_EEP_SDTR
 		asc_dvc->cfg->sdtr_period_offset[i] = eep_config->dos_int13_table[i];
 #endif
 		asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
 		asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+		asc_dvc->cfg->sdtr_period_offset[i] =
+			(uchar) (ASC_DEF_SDTR_OFFSET |
+					 (asc_dvc->host_init_sdtr_index << 4));
 	}
 	eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
 #if CC_CHK_FIX_EEP_CONTENT
@@ -8880,6 +9468,7 @@
 	PortAddr            iop_base;
 	ushort              warn_code;
 	ushort              cfg_msw;
+	int					i;
 	iop_base = asc_dvc->iop_base;
 	warn_code = 0;
 	cfg_msw = AscGetChipCfgMsw(iop_base);
@@ -8889,12 +9478,19 @@
 		AscSetChipCfgMsw(iop_base, cfg_msw);
 	}
 	if (!AscTestExternalLram(asc_dvc)) {
-		if (asc_dvc->bus_type & ASC_IS_PCI) {
+		if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) {
+			asc_dvc->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG ;
+			for( i = 0 ; i <= ASC_MAX_TID ; i++ ) {
+				asc_dvc->cfg->max_tag_qng[ i ] = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG ;
+			}
+		} else {
 			cfg_msw |= 0x0800;
 			AscSetChipCfgMsw(iop_base, cfg_msw);
 			asc_dvc->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+			for (i = 0 ; i <= ASC_MAX_TID ; i++) {
+				asc_dvc->cfg->max_tag_qng[ i ] = ASC_MAX_INRAM_TAG_QNG;
+			}
 		}
-	} else {
 	}
 	if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
 		asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
@@ -8959,6 +9555,7 @@
 	ASC_ISR_CALLBACK    asc_isr_callback;
 	uchar               cp_sen_len;
 	uchar               i;
+	ASC_DBG(1, "AscInitPollIsrCallBack: begin\n");
 	if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) {
 		scsiq_req = (ASC_SCSI_REQ_Q dosfar *) scsi_done_q->d2.srb_ptr;
 		scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat;
@@ -8981,6 +9578,7 @@
 			(*asc_isr_callback) (asc_dvc, scsi_done_q);
 		}
 	}
+	ASC_DBG(1, "AscInitPollIsrCallBack: end\n");
 	return;
 }
 
@@ -9316,6 +9914,7 @@
 		asc_dvc->init_sdtr &= ~tid_bits;
 		tmp_disable_init_sdtr = TRUE;
 	}
+	ASC_DBG(1, "AscInitPollTarget: before PollScsiInquiry\n");
 	if (
 		   PollScsiInquiry(asc_dvc, scsiq, (uchar dosfar *) inq,
 						   sizeof (ASC_SCSI_INQUIRY)) == 1
@@ -9353,19 +9952,8 @@
 					if (inq->byte7.CmdQue) {
 						asc_dvc->cfg->can_tagged_qng |= tid_bits;
 						if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) {
-#if CC_FIX_QUANTUM_XP34301_1071
-							if (
-								   (inq->add_len >= 32)
-								   && (AscCompareString(inq->vendor_id, (uchar *) "QUANTUM XP34301", 15) == 0)
-								   && (AscCompareString(inq->product_rev_level, (uchar *) "1071", 4) == 0)
-							  ) {
-							} else {
-#endif
 								asc_dvc->use_tagged_qng |= tid_bits;
 								asc_dvc->max_dvc_qng[tid_no] = asc_dvc->cfg->max_tag_qng[tid_no];
-#if CC_FIX_QUANTUM_XP34301_1071
-							}
-#endif
 						}
 					}
 					if (!inq->byte7.Sync) {
@@ -9404,12 +9992,12 @@
 				}
 			}
 			sta = 1;
-#if CC_INIT_TARGET_TEST_UNIT_READY
+			ASC_DBG(1, "AscInitPollTarget: before InitTestUnitReady\n");
 			sta = InitTestUnitReady(asc_dvc, scsiq);
-#endif
-#if CC_INIT_TARGET_READ_CAPACITY
 			if (sta == 1) {
 				if ((cap_info != 0L) && support_read_cap) {
+					ASC_DBG(1,
+						"AscInitPollTarget: before PollScsiReadCapacity\n");
 					if (PollScsiReadCapacity(asc_dvc, scsiq,
 											 cap_info) != 1) {
 						cap_info->lba = 0L;
@@ -9418,12 +10006,11 @@
 					}
 				}
 			}
-#endif
 		} else {
 			asc_dvc->start_motor &= ~tid_bits;
 		}
-	} else {
 	}
+	ASC_DBG1(1, "AscInitPollTarget: dvc_found %d\n", dvc_found);
 	return (dvc_found);
 }
 
@@ -9435,13 +10022,14 @@
 )
 {
 	int                 status;
-	int                 retry;
-	retry = 0;
+	int                 retry = 0;
+
+	ASC_DBG1(1, "PollQueueDone: timeout_sec %d", timeout_sec);
 	do {
-		if (
-			   (status = AscExeScsiQueue(asc_dvc,
-										 (ASC_SCSI_Q dosfar *) scsiq)) == 1
-		  ) {
+		ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n");
+		if ((status = AscExeScsiQueue(asc_dvc,
+				(ASC_SCSI_Q dosfar *) scsiq)) == 1) {
+			ASC_DBG(1, "PollQueueDone: before AscPollQDone\n");
 			if ((status = AscPollQDone(asc_dvc, scsiq,
 									   timeout_sec)) != 1) {
 				if (status == 0x80) {
@@ -9461,9 +10049,13 @@
 				scsiq->r3.scsi_msg = 0;
 				AscAbortSRB(asc_dvc, (ulong) scsiq);
 			}
+			ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat);
 			return (scsiq->r3.done_stat);
 		}
-	} while ((status == 0) || (status == 0x80));
+		DvcSleepMilliSecond(5);
+	} while (((status == 0) || (status == 0x80)) &&
+			  retry++ < ASC_MAX_INIT_BUSY_RETRY);
+	ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n");
 	return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
 
@@ -9481,7 +10073,6 @@
 	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 4));
 }
 
-#if CC_INIT_TARGET_START_UNIT
 int
 PollScsiStartUnit(
 					 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9493,9 +10084,7 @@
 	}
 	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 40));
 }
-#endif
 
-#if CC_INIT_TARGET_READ_CAPACITY
 int
 PollScsiReadCapacity(
 						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9522,7 +10111,6 @@
 	}
 	return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
-#endif
 
 ulong dosfar       *
 swapfarbuf4(
@@ -9542,7 +10130,6 @@
 	return ((ulong dosfar *) buf);
 }
 
-#if CC_INIT_TARGET_TEST_UNIT_READY
 int
 PollScsiTestUnitReady(
 						 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9603,7 +10190,6 @@
 	}
 	return (0);
 }
-#endif
 
 int
 AscPollQDone(
@@ -9866,7 +10452,6 @@
 	return (0);
 }
 
-#if CC_INIT_TARGET_READ_CAPACITY
 int
 AscScsiReadCapacity(
 					   REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9890,9 +10475,7 @@
 	scsiq->r2.cdb_len = 10;
 	return (0);
 }
-#endif
 
-#if CC_INIT_TARGET_TEST_UNIT_READY
 int
 AscScsiTestUnitReady(
 						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9913,9 +10496,7 @@
 	scsiq->r2.cdb_len = 6;
 	return (0);
 }
-#endif
 
-#if CC_INIT_TARGET_START_UNIT
 int
 AscScsiStartStopUnit(
 						REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -9936,4 +10517,3 @@
 	scsiq->r2.cdb_len = 6;
 	return (0);
 }
-#endif

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