diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index 70b49a9ba691242dff56e675a14ca87d5f7000d3..5bf5b8afc53852a7acde6253eb03049588825a6a 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -1,6 +1,6 @@
 #
 # AIC79XX 2.5.X Kernel configuration File.
-# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#3 $
+# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#4 $
 #
 config SCSI_AIC79XX
 	tristate "Adaptec AIC79xx U320 support"
@@ -59,6 +59,7 @@ config AIC79XX_BUILD_FIRMWARE
 config AIC79XX_ENABLE_RD_STRM
 	bool "Enable Read Streaming for All Targets"
 	depends on SCSI_AIC79XX
+	default n
 	help
 	Read Streaming is a U320 protocol option that should enhance
 	performance.  Early U320 drive firmware actually performs slower
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index d30e280d50ceabe2ab93c5076844760877cdc1de..450b0fd1ecfd997c1cccad5f75cbbbd42a7abf60 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -1,6 +1,6 @@
 #
 # AIC7XXX and AIC79XX 2.5.X Kernel configuration File.
-# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#5 $
+# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#6 $
 #
 config SCSI_AIC7XXX
 	tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)"
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index 5229eb2cdafa14ebf5b8a92f666150d955737387..c0df52812a20be9fd0b95808b2e1c198ceaca13c 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#27 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#29 $
  *
  * $FreeBSD$
  */
@@ -59,6 +59,9 @@
 #define	ID_OLV_274x	0x04907782 /* Olivetti OEM */
 #define	ID_OLV_274xD	0x04907783 /* Olivetti OEM (Differential) */
 
+static int aic7770_chip_init(struct ahc_softc *ahc);
+static int aic7770_suspend(struct ahc_softc *ahc);
+static int aic7770_resume(struct ahc_softc *ahc);
 static int aha2840_load_seeprom(struct ahc_softc *ahc);
 static ahc_device_setup_t ahc_aic7770_VL_setup;
 static ahc_device_setup_t ahc_aic7770_EISA_setup;;
@@ -144,6 +147,12 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
 
 	ahc->description = entry->name;
 	error = ahc_softc_init(ahc);
+	if (error != 0)
+		return (error);
+
+	ahc->bus_chip_init = aic7770_chip_init;
+	ahc->bus_suspend = aic7770_suspend;
+	ahc->bus_resume = aic7770_resume;
 
 	error = ahc_reset(ahc);
 	if (error != 0)
@@ -226,6 +235,9 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
 	ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
 	ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
 
+	ahc->bus_softc.aic7770_softc.busspd = hostconf & DFTHRSH;
+	ahc->bus_softc.aic7770_softc.bustime = (hostconf << 2) & BOFF;
+
 	/*
 	 * Generic aic7xxx initialization.
 	 */
@@ -253,6 +265,28 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
 	return (0);
 }
 
+static int
+aic7770_chip_init(struct ahc_softc *ahc)
+{
+	ahc_outb(ahc, BUSSPD, ahc->bus_softc.aic7770_softc.busspd);
+	ahc_outb(ahc, BUSTIME, ahc->bus_softc.aic7770_softc.bustime);
+	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
+	ahc_outb(ahc, BCTL, ENABLE);
+	return (ahc_chip_init(ahc));
+}
+
+static int
+aic7770_suspend(struct ahc_softc *ahc)
+{
+	return (ahc_suspend(ahc));
+}
+
+static int
+aic7770_resume(struct ahc_softc *ahc)
+{
+	return (ahc_resume(ahc));
+}
+
 /*
  * Read the 284x SEEPROM.
  */
@@ -371,5 +405,6 @@ ahc_aic7770_setup(struct ahc_softc *ahc)
 	ahc->features = AHC_AIC7770_FE;
 	ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
 	ahc->flags |= AHC_PAGESCBS;
+	ahc->instruction_ram_size = 448;
 	return (0);
 }
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
index 0646072850b9ac4412e79caf0241637e65a24dff..a374f84f22388e6865169826f5051b0c734e0a0a 100644
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#12 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#13 $
  */
 
 #include "aic7xxx_osm.h"
@@ -66,7 +66,7 @@ aic7770_linux_probe(Scsi_Host_Template *template)
 			continue;
 		request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx");
 #else
-		if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") != 0)
+		if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") == 0)
 			continue;
 #endif
 
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 8197906e03e5c69f0653e328714d7ef9ad631db1..2a906c7d1c6aea0e674410b9ca7b62f22e72c364 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#78 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#88 $
  *
  * $FreeBSD$
  */
@@ -258,27 +258,30 @@ typedef enum {
 	AHD_PCIX_CHIPRST_BUG	= 0x0040,
 	/* MMAPIO is not functional in PCI-X mode.  */
 	AHD_PCIX_MMAPIO_BUG	= 0x0080,
+	/* Reads to SCBRAM fail to reset the discard timer. */
+	AHD_PCIX_SCBRAM_RD_BUG  = 0x0100,
 	/* Bug workarounds that can be disabled on non-PCIX busses. */
 	AHD_PCIX_BUG_MASK	= AHD_PCIX_CHIPRST_BUG
-				| AHD_PCIX_MMAPIO_BUG,
+				| AHD_PCIX_MMAPIO_BUG
+				| AHD_PCIX_SCBRAM_RD_BUG,
 	/*
 	 * LQOSTOP0 status set even for forced selections with ATN
 	 * to perform non-packetized message delivery.
 	 */
-	AHD_LQO_ATNO_BUG	= 0x0100,
+	AHD_LQO_ATNO_BUG	= 0x0200,
 	/* FIFO auto-flush does not always trigger.  */
-	AHD_AUTOFLUSH_BUG	= 0x0200,
+	AHD_AUTOFLUSH_BUG	= 0x0400,
 	/* The CLRLQO registers are not self-clearing. */
-	AHD_CLRLQO_AUTOCLR_BUG	= 0x0400,
+	AHD_CLRLQO_AUTOCLR_BUG	= 0x0800,
 	/* The PACKETIZED status bit refers to the previous connection. */
-	AHD_PKTIZED_STATUS_BUG  = 0x0800,
+	AHD_PKTIZED_STATUS_BUG  = 0x1000,
 	/* "Short Luns" are not placed into outgoing LQ packets correctly. */
-	AHD_PKT_LUN_BUG		= 0x1000,
+	AHD_PKT_LUN_BUG		= 0x2000,
 	/*
 	 * Only the FIFO allocated to the non-packetized connection may
 	 * be in use during a non-packetzied connection.
 	 */
-	AHD_NONPACKFIFO_BUG	= 0x2000,
+	AHD_NONPACKFIFO_BUG	= 0x4000,
 	/*
 	 * Writing to a DFF SCBPTR register may fail if concurent with
 	 * a hardware write to the other DFF SCBPTR register.  This is
@@ -286,30 +289,44 @@ typedef enum {
 	 * this bug have the AHD_NONPACKFIFO_BUG and all writes of concern
 	 * occur in non-packetized connections.
 	 */
-	AHD_MDFF_WSCBPTR_BUG	= 0x4000,
+	AHD_MDFF_WSCBPTR_BUG	= 0x8000,
 	/* SGHADDR updates are slow. */
-	AHD_REG_SLOW_SETTLE_BUG	= 0x8000,
+	AHD_REG_SLOW_SETTLE_BUG	= 0x10000,
 	/*
 	 * Changing the MODE_PTR coincident with an interrupt that
 	 * switches to a different mode will cause the interrupt to
 	 * be in the mode written outside of interrupt context.
 	 */
-	AHD_SET_MODE_BUG	= 0x10000,
+	AHD_SET_MODE_BUG	= 0x20000,
 	/* Non-packetized busfree revision does not work. */
-	AHD_BUSFREEREV_BUG	= 0x20000,
+	AHD_BUSFREEREV_BUG	= 0x40000,
 	/*
 	 * Paced transfers are indicated with a non-standard PPR
 	 * option bit in the neg table, 160MHz is indicated by
 	 * sync factor 0x7, and the offset if off by a factor of 2.
 	 */
-	AHD_PACED_NEGTABLE_BUG	= 0x40000,
+	AHD_PACED_NEGTABLE_BUG	= 0x80000,
 	/* LQOOVERRUN false positives. */
-	AHD_LQOOVERRUN_BUG	= 0x80000,
+	AHD_LQOOVERRUN_BUG	= 0x100000,
 	/*
 	 * Controller write to INTSTAT will lose to a host
 	 * write to CLRINT.
 	 */
-	AHD_INTCOLLISION_BUG	= 0x100000
+	AHD_INTCOLLISION_BUG	= 0x200000,
+	/*
+	 * The GEM318 violates the SCSI spec by not waiting
+	 * the mandated bus settle delay between phase changes
+	 * in some situations.  Some aic79xx chip revs. are more
+	 * strict in this regard and will treat REQ assertions
+	 * that fall within the bus settle delay window as
+	 * glitches.  This flag tells the firmware to tolerate
+	 * early REQ assertions.
+	 */
+	AHD_EARLY_REQ_BUG	= 0x400000,
+	/*
+	 * The LED does not stay on long enough in packetized modes.
+	 */
+	AHD_FAINT_LED_BUG	= 0x800000
 } ahd_bug;
 
 /*
@@ -319,10 +336,7 @@ typedef enum {
  */
 typedef enum {
 	AHD_FNONE	      = 0x00000,
-	AHD_PRIMARY_CHANNEL   = 0x00003,/*
-					 * The channel that should
-					 * be probed first.
-					 */
+	AHD_BOOT_CHANNEL      = 0x00001,/* We were set as the boot channel. */
 	AHD_USEDEFAULTS	      = 0x00004,/*
 					 * For cards without an seeprom
 					 * or a BIOS to initialize the chip's
@@ -411,7 +425,10 @@ typedef uint32_t sense_addr_t;
 #define MAX_CDB_LEN 16
 #define MAX_CDB_LEN_WITH_SENSE_ADDR (MAX_CDB_LEN - sizeof(sense_addr_t))
 union initiator_data {
-	uint64_t cdbptr;
+	struct {
+		uint64_t cdbptr;
+		uint8_t  cdblen;
+	} cdb_from_host;
 	uint8_t	 cdb[MAX_CDB_LEN];
 	struct {
 		uint8_t	 cdb[MAX_CDB_LEN_WITH_SENSE_ADDR];
@@ -727,7 +744,7 @@ struct ahd_tmode_lstate;
 
 #define AHD_WIDTH_UNKNOWN	0xFF
 #define AHD_PERIOD_UNKNOWN	0xFF
-#define AHD_OFFSET_UNKNOWN	0x0
+#define AHD_OFFSET_UNKNOWN	0xFF
 #define AHD_PPR_OPTS_UNKNOWN	0xFF
 
 /*
@@ -884,6 +901,40 @@ struct seeprom_config {
 	uint16_t checksum;		/* word 31 */
 };
 
+/*
+ * Vital Product Data used during POST and by the BIOS.
+ */
+struct vpd_config {
+	uint8_t  bios_flags;
+#define		VPDMASTERBIOS	0x0001
+#define		VPDBOOTHOST	0x0002
+	uint8_t  reserved_1[21];
+	uint8_t  resource_type;
+	uint8_t  resource_len[2];
+	uint8_t  resource_data[8];
+	uint8_t  vpd_tag;
+	uint16_t vpd_len;
+	uint8_t  vpd_keyword[2];
+	uint8_t  length;
+	uint8_t  revision;
+	uint8_t  device_flags;
+	uint8_t  termnation_menus[2];
+	uint8_t  fifo_threshold;
+	uint8_t  end_tag;
+	uint8_t  vpd_checksum;
+	uint16_t default_target_flags;
+	uint16_t default_bios_flags;
+	uint16_t default_ctrl_flags;
+	uint8_t  default_irq;
+	uint8_t  pci_lattime;
+	uint8_t  max_target;
+	uint8_t  boot_lun;
+	uint16_t signature;
+	uint8_t  reserved_2;
+	uint8_t  checksum;
+	uint8_t	 reserved_3[4];
+};
+
 /****************************** Flexport Logic ********************************/
 #define FLXADDR_TERMCTL			0x0
 #define		FLX_TERMCTL_ENSECHIGH	0x8
@@ -916,11 +967,12 @@ struct seeprom_config {
 #define		FLX_CSTAT_INVALID	0x3
 
 int		ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf,
-				 u_int start_addr, u_int count);
+				 u_int start_addr, u_int count, int bstream);
 
 int		ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf,
 				  u_int start_addr, u_int count);
 int		ahd_wait_seeprom(struct ahd_softc *ahd);
+int		ahd_verify_vpd_cksum(struct vpd_config *vpd);
 int		ahd_verify_cksum(struct seeprom_config *sc);
 int		ahd_acquire_seeprom(struct ahd_softc *ahd);
 void		ahd_release_seeprom(struct ahd_softc *ahd);
@@ -1305,6 +1357,8 @@ int			 ahd_softc_init(struct ahd_softc *);
 void			 ahd_controller_info(struct ahd_softc *ahd, char *buf);
 int			 ahd_init(struct ahd_softc *ahd);
 int			 ahd_default_config(struct ahd_softc *ahd);
+int			 ahd_parse_vpddata(struct ahd_softc *ahd,
+					   struct vpd_config *vpd);
 int			 ahd_parse_cfgdata(struct ahd_softc *ahd,
 					   struct seeprom_config *sc);
 void			 ahd_intr_enable(struct ahd_softc *ahd, int enable);
diff --git a/drivers/scsi/aic7xxx/aic79xx.reg b/drivers/scsi/aic7xxx/aic79xx.reg
index 2d22db151c8d824da5fb944c44370b2daab02101..4b921d2c5fb16934bed7ec556337bdfbaa684054 100644
--- a/drivers/scsi/aic7xxx/aic79xx.reg
+++ b/drivers/scsi/aic7xxx/aic79xx.reg
@@ -39,7 +39,7 @@
  *
  * $FreeBSD$
  */
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -2071,14 +2071,14 @@ register LQIMODE1 {
 	address			0x051
 	access_mode	RW
 	modes		M_CFG
-	field	ENLQIPHASE_LQ	0x80
-	field	ENLQIPHASE_NLQ	0x40
+	field	ENLQIPHASE_LQ	0x80	/* LQIPHASE1 */
+	field	ENLQIPHASE_NLQ	0x40	/* LQIPHASE2 */
 	field	ENLIQABORT	0x20
-	field	ENLQICRCI_LQ	0x10
-	field	ENLQICRCI_NLQ	0x08
+	field	ENLQICRCI_LQ	0x10	/* LQICRCI1 */
+	field	ENLQICRCI_NLQ	0x08	/* LQICRCI2 */
 	field	ENLQIBADLQI	0x04
-	field	ENLQIOVERI_LQ	0x02
-	field	ENLQIOVERI_NLQ	0x01
+	field	ENLQIOVERI_LQ	0x02	/* LQIOVERI1 */
+	field	ENLQIOVERI_NLQ	0x01	/* LQIOVERI2 */
 }
 
 /*
@@ -2545,10 +2545,10 @@ const	AHD_PRECOMP_CUTBACK_37	0x07
 const	AHD_SLEWRATE_MASK	0x78
 const	AHD_SLEWRATE_SHIFT	3
 /*
- * Rev A has only a single bit of slew adjustment.
- * Rev B has 4 bits.
+ * Rev A has only a single bit (high bit of field) of slew adjustment.
+ * Rev B has 4 bits.  The current default happens to be the same for both.
  */
-const	AHD_SLEWRATE_DEF_REVA	0x01
+const	AHD_SLEWRATE_DEF_REVA	0x08
 const	AHD_SLEWRATE_DEF_REVB	0x08
 
 /* Rev A does not have any amplitude setting. */
@@ -3769,16 +3769,17 @@ scb {
 	SCB_RESIDUAL_DATACNT {
 		size	4
 		alias	SCB_CDB_STORE
+		alias	SCB_HOST_CDB_PTR
 	}
 	SCB_RESIDUAL_SGPTR {
 		size	4
-		alias	SCB_CDB_PTR
 		field	SG_ADDR_MASK		0xf8	/* In the last byte */
 		field	SG_OVERRUN_RESID	0x02	/* In the first byte */
 		field	SG_LIST_NULL		0x01	/* In the first byte */
 	}
 	SCB_SCSI_STATUS {
 		size	1
+		alias	SCB_HOST_CDB_LEN
 	}
 	SCB_TARGET_PHASES {
 		size	1
diff --git a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq
index 31cc29d9d4ddb7f58cfa83628bcf4bdb9aacfe52..e25c7c5f49d107fa55ecceaa9d4714e861b96b51 100644
--- a/drivers/scsi/aic7xxx/aic79xx.seq
+++ b/drivers/scsi/aic7xxx/aic79xx.seq
@@ -40,7 +40,7 @@
  * $FreeBSD$
  */
 
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $"
 PATCH_ARG_LIST = "struct ahd_softc *ahd"
 PREFIX = "ahd_"
 
@@ -89,6 +89,13 @@ END_CRITICAL;
 idle_loop_check_nonpackreq:
 	test	SSTAT2, NONPACKREQ jz . + 2;
 	call	unexpected_nonpkt_phase_find_ctxt;
+	if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) {
+		and	A, FIFO0FREE|FIFO1FREE, DFFSTAT;
+		cmp	A, FIFO0FREE|FIFO1FREE jne . + 3;
+		and	SBLKCTL, ~DIAGLEDEN|DIAGLEDON;
+		jmp	. + 2;
+		or	SBLKCTL, DIAGLEDEN|DIAGLEDON;
+	}
 	call	idle_loop_gsfifo_in_scsi_mode;
 	call	idle_loop_service_fifos;
 	call	idle_loop_cchan;
@@ -122,22 +129,24 @@ gsfifo_complete_normally:
 	/*
 	 * Since this status did not consume a FIFO, we have to
 	 * be a bit more dilligent in how we check for FIFOs pertaining
-	 * to this transaction.  There are three states that a FIFO still
+	 * to this transaction.  There are two states that a FIFO still
 	 * transferring data may be in.
 	 *
-	 * 1) Configured and draining to the host, with a pending CLRCHN.
-	 * 2) Configured and draining to the host, no pending CLRCHN.
-	 * 3) Pending cfg4data, fifo not empty.
+	 * 1) Configured and draining to the host, with a FIFO handler.
+	 * 2) Pending cfg4data, fifo not empty.
 	 *
-	 * Cases 1 and 2 can be detected by noticing that a longjmp is
-	 * active for the FIFO and LONGJMP_SCB matches our SCB.  In this
-	 * case, we allow the routine servicing the FIFO to complete the SCB.
+	 * Case 1 can be detected by noticing that a longjmp is active for
+	 * the FIFO and LONGJMP_SCB matches our SCB.  In this case, we allow
+	 * the routine servicing the FIFO to complete the SCB.
 	 * 
-	 * Case 3 implies either a pending or yet to occur save data
+	 * Case 2 implies either a pending or yet to occur save data
 	 * pointers for this same context in the other FIFO.  So, if
-	 * we detect case 2, we will properly defer the post of the SCB
+	 * we detect case 1, we will properly defer the post of the SCB
 	 * and achieve the desired result.  The pending cfg4data will
 	 * notice that status has been received and complete the SCB.
+	 *
+	 * If the data-transfer has been completed, or no data transfer
+	 * was needed for this SCB, it is safe to complete the command.
 	 */
 	test	SCB_SGPTR, SG_LIST_NULL jz good_status_check_fifos;
 	/*
@@ -519,7 +528,7 @@ BEGIN_CRITICAL;
 		/*
 		 * For packetized, the LQO manager clears ENSELO on
 		 * the assertion of SELDO.  If we are non-packetized,
-		 * LASTSCB and CURRSCB are acuate.
+		 * LASTSCB and CURRSCB are accurate.
 		 */
 		test	SCSISEQ0, ENSELO jnz use_lastscb;
 
@@ -706,7 +715,7 @@ SET_DST_MODE	M_DFF1;
 	add	NONE, -17, SCB_CDB_LEN;
 	jnc	p_command_embedded;
 p_command_from_host:
-	bmov	HADDR[0], SCB_CDB_PTR, 11;
+	bmov	HADDR[0], SCB_HOST_CDB_PTR, 9;
 	mvi	SG_CACHE_PRE, LAST_SEG;
 	mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
 	jmp	p_command_xfer;
@@ -1030,14 +1039,6 @@ queue_arg1_scb_completion:
 	SET_MODE(M_SCSI, M_SCSI)
 	bmov	SCBPTR, ARG_1, 2;
 queue_scb_completion:
-	if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0) {
-		/*
-		 * Set MK_MESSAGE to trigger an abort should this SCB
-		 * be referenced by a target even though it is not currently
-		 * active.
-		 */
-		or	SCB_CONTROL, MK_MESSAGE;
-	}
 	test	SCB_SCSI_STATUS,0xff	jnz bad_status;
 	/*
 	 * Check for residuals
@@ -1163,7 +1164,28 @@ clear_target_state:
 	mvi	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret;
 
 phase_lock:     
-	test	SCSIPHASE, 0xFF jz .;
+	if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) {
+		/*
+		 * Don't ignore persistent REQ assertions just because
+		 * they were asserted within the bus settle delay window.
+		 * This allows us to tolerate devices like the GEM318
+		 * that violate the SCSI spec.  We are careful not to
+		 * count REQ while we are waiting for it to fall during
+		 * an async phase due to our asserted ACK.  Each
+		 * sequencer instruction takes ~25ns, so the REQ must
+		 * last at least 100ns in order to be counted as a true
+		 * REQ.
+		 */
+		test	SCSIPHASE, 0xFF jnz phase_locked;
+		test	SCSISIGI, ACKI jnz phase_lock;
+		test	SCSISIGI, REQI jz phase_lock;
+		test	SCSIPHASE, 0xFF jnz phase_locked;
+		test	SCSISIGI, ACKI jnz phase_lock;
+		test	SCSISIGI, REQI jz phase_lock;
+phase_locked:
+	} else {
+		test	SCSIPHASE, 0xFF jz .;
+	}
 	test	SSTAT1, SCSIPERR jnz phase_lock;
 phase_lock_latch_phase:
 	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
@@ -1247,7 +1269,7 @@ service_fifo:
 		nop;
 	}
 	and	SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
-	mvi	CCSGCTL, CCSGEN|SG_CACHE_AVAIL|CCSGRESET;
+	mvi	CCSGCTL, CCSGEN|CCSGRESET;
 	or	SG_STATE, FETCH_INPROG ret;
 idle_sgfetch_complete:
 	/*
@@ -1261,6 +1283,15 @@ idle_sgfetch_complete:
 idle_sg_avail:
 	/* Does the hardware have space for another SG entry? */
 	test	DFSTATUS, PRELOAD_AVAIL jz return;
+	/*
+	 * On the A, preloading a segment before HDMAENACK
+	 * comes true can clobber the shaddow address of the
+	 * first segment in the S/G FIFO.  Wait until it is
+	 * safe to proceed.
+	 */
+	if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0) {
+		test	DFCNTRL, HDMAENACK jz return;
+	}
 	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
 		bmov	HADDR, CCSGRAM, 8;
 	} else {
@@ -1290,22 +1321,12 @@ sg_advance:
 	or	SINDEX, LAST_SEG;
 	clr	SG_STATE;
 	mov	SG_CACHE_PRE, SINDEX;
-	/*
-	 * Load the segment.  Or in HDMAEN here too
-	 * just in case HDMAENACK has not come true
-	 * by the time this segment is loaded.  If
-	 * HDMAENACK is not true, this or will disable
-	 * HDMAEN mid-transfer.  We do not want to simply
-	 * mvi our original settings as SCSIEN automatically
-	 * de-asserts and we don't want to accidentally
-	 * re-enable it.
-	 */
 	if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) {
 		/*
 		 * Use SCSIENWRDIS so that SCSIEN is never
 		 * modified by this operation.
 		 */
-		or	DFCNTRL, PRELOADEN|SCSIENWRDIS|HDMAEN;
+		or	DFCNTRL, PRELOADEN|HDMAEN|SCSIENWRDIS;
 	} else {
 		or	DFCNTRL, PRELOADEN|HDMAEN;
 	}
@@ -1510,12 +1531,6 @@ data_phase_done:
  * the idle loop and there is no need to perform
  * any fixups.
  */
-calc_residual:
-	test	SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg;
-	/* Record if we've consumed all S/G entries */
-	test	MDFFSTAT, SHVALID	jz . + 2;
-	bmov	SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;
-	or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret;
 residual_before_last_seg:
 	test    MDFFSTAT, SHVALID	jnz sgptr_fixup;
 	/*
@@ -1525,7 +1540,13 @@ residual_before_last_seg:
 	 */
 	call	idle_loop_service_fifos;
 	RESTORE_MODE(SAVED_MODE)
-	jmp	calc_residual;
+	/* FALLTHROUGH */
+calc_residual:
+	test	SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg;
+	/* Record if we've consumed all S/G entries */
+	test	MDFFSTAT, SHVALID	jz . + 2;
+	bmov	SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;
+	or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret;
 
 sgptr_fixup:
 	/*
@@ -1570,7 +1591,51 @@ export timer_isr:
 	}
 
 export seq_isr:
-	nop;	/* Jumps in the first ISR instruction fail on Rev A. */
+	if ((ahd->features & AHD_RTI) == 0) {
+		/*
+		 * On RevA Silicon, if the target returns us to data-out
+		 * after we have already trained for data-out, it is
+		 * possible for us to transition the free running clock to
+		 * data-valid before the required 100ns P1 setup time (8 P1
+		 * assertions in fast-160 mode).  This will only happen if
+		 * this L-Q is a continuation of a data transfer for which
+		 * we have already prefetched data into our FIFO (LQ/Data
+		 * followed by LQ/Data for the same write transaction).
+		 * This can cause some target implementations to miss the
+		 * first few data transfers on the bus.  We detect this
+		 * situation by noticing that this is the first data transfer
+		 * after an LQ (LQIWORKONLQ true), that the data transfer is
+		 * a continuation of a transfer already setup in our FIFO
+		 * (SAVEPTRS interrupt), and that the transaction is a write
+		 * (DIRECTION set in DFCNTRL). The delay is performed by
+		 * disabling SCSIEN until we see the first REQ from the
+		 * target.
+		 * 
+		 * First instruction in an ISR cannot be a branch on
+		 * Rev A.  Snapshot LQISTAT2 so the status is not missed
+		 * and deffer the test by one instruction.
+		 */
+		mov	REG_ISR, LQISTAT2;
+		test	REG_ISR, LQIWORKONLQ jz data_valid;
+		test	SEQINTSRC, SAVEPTRS  jz data_valid;
+		test	LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo;
+		/*
+		 * Switch to the active FIFO.
+		 */
+		xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+		test	DFCNTRL, DIRECTION jz snapshot_other_fifo;
+		and	DFCNTRL, ~SCSIEN;
+		test	SSTAT1, REQINIT	jz .;
+		or	DFCNTRL, SCSIEN;
+		/* FALLTHROUGH */
+snapshot_other_fifo:
+		xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+		/* FALLTHROUGH */
+snapshot_saveptr:
+		mvi	DFFSXFRCTL, CLRCHN;
+		or	SEQINTCTL, IRET ret;
+data_valid:
+	}
 	test	SEQINTSRC, CFG4DATA	jnz cfg4data_intr;
 	test	SEQINTSRC, CFG4ISTAT	jnz cfg4istat_intr;
 	test	SEQINTSRC, SAVEPTRS	jnz saveptr_intr;
@@ -1583,21 +1648,23 @@ export seq_isr:
  * active and contains a snapshot of the current poniter information.
  * This happens between packets in a stream for a single L_Q.  Since we
  * are not performing a pointer save, we can safely clear the channel
- * so it can be used for other transactions.
+ * so it can be used for other transactions.  On RTI capable controllers,
+ * where snapshots can, and are, disabled, the code to handle this type
+ * of snapshot is not active.
  *
  * The second case is a save pointers on an active FIFO which occurs
- * if the target changes to a new L_Q or busfrees/QAS' and the transfer
+ * if the target changes to a new L_Q or busfrees/QASes and the transfer
  * has a residual.  This should occur coincident with a ctxtdone.  We
  * disable the interrupt and allow our active routine to handle the
  * save.
  */
 saveptr_intr:
-	test	DFCNTRL, HDMAENACK jz snapshot_saveptr;
+	if ((ahd->features & AHD_RTI) == 0) {
+		test	LONGJMP_ADDR[1], INVALID_ADDR jnz snapshot_saveptr;
+	}
+saveptr_active_fifo:
 	and	SEQIMODE, ~ENSAVEPTRS;
 	or	SEQINTCTL, IRET ret;
-snapshot_saveptr:
-	mvi	DFFSXFRCTL, CLRCHN;
-	or	SEQINTCTL, IRET ret;
 
 cfg4data_intr:
 	test	SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun;
@@ -1633,6 +1700,18 @@ cfg4istat_no_taskmgmt_func:
 	call	pkt_handle_status;
 	or	SEQINTCTL, IRET ret;
 
+cfg4icmd_intr:
+	/*
+	 * In the case of DMAing a CDB from the host, the normal
+	 * CDB buffer is formatted with an 8 byte address followed
+	 * by a 1 byte count.
+	 */
+	bmov	HADDR[0], SCB_HOST_CDB_PTR, 9;
+	mvi	SG_CACHE_PRE, LAST_SEG;
+	mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
+	call	pkt_handle_cdb;
+	or	SEQINTCTL, IRET ret;
+
 /*
  * See if the target has gone on in this context creating an
  * overrun condition.  For the write case, the hardware cannot
@@ -1672,7 +1751,7 @@ pkt_service_fifo:
 pkt_last_seg:
 	call	setjmp;
 	test	SEQINTSRC, SAVEPTRS jnz pkt_saveptrs;
-	test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz last_pkt_done;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz last_pkt_xfer_done;
 	test	SCSIPHASE, ~DATA_PHASE_MASK jz . + 2;
 	test	SCSISIGO, ATNO jnz . + 2;
 	test	SSTAT2, NONPACKREQ jz return;
@@ -1716,7 +1795,7 @@ pkt_saveptrs_clrchn:
 	mvi	DFFSXFRCTL, CLRCHN ret;
 END_CRITICAL;
 
-last_pkt_done:
+last_pkt_xfer_done:
 BEGIN_CRITICAL;
 	if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
 		or	DFCNTRL, FIFOFLUSH;
@@ -1765,13 +1844,15 @@ BEGIN_CRITICAL;
 	mvi	DFFSXFRCTL, CLRCHN ret;
 END_CRITICAL;
 
-check_status_overrun:
-	test	SHCNT[2], 0xFF jz status_IU_done;
-	SET_SEQINTCODE(STATUS_OVERRUN)
-	jmp	status_IU_done;
+/*
+ * Watch over the status transfer.  Our host sense buffer is
+ * large enough to take the maximum allowed status packet.
+ * None-the-less, we must still catch and report overruns to
+ * the host.
+ */
 pkt_handle_status:
 	call	setjmp_setscb;
-	test	MDFFSTAT, LASTSDONE jnz check_status_overrun;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jz check_status_overrun;
 	test	SEQINTSRC, CTXTDONE jz return;
 status_IU_done:
 BEGIN_CRITICAL;
@@ -1783,6 +1864,21 @@ BEGIN_CRITICAL;
 	or	SCB_CONTROL, STATUS_RCVD;
 	jmp	last_pkt_complete;
 END_CRITICAL;
+check_status_overrun:
+	/*
+	 * We've filled the entire sense buffer.
+	 * Wait for either context done or a negative
+	 * shaddow count.  If the context completes without
+	 * causing the shaddow count to go negative, then
+	 * this was a successful transfer up to the status
+	 * limit.  Otherwise we report the error.
+	 */
+	test	SHCNT[2], 0xFF jnz report_status_overrun;
+	test	SEQINTSRC, CTXTDONE jz return;
+	test	SHCNT[2], 0xFF jz status_IU_done;
+report_status_overrun:
+	SET_SEQINTCODE(STATUS_OVERRUN)
+	jmp	status_IU_done;
 
 SET_SRC_MODE	M_DFF0;
 SET_DST_MODE	M_DFF0;
@@ -1796,6 +1892,16 @@ check_fifo:
 	stc	ret;
 END_CRITICAL;
 
+/*
+ * Must wait until CDB xfer is over before issuing the
+ * clear channel.
+ */
+pkt_handle_cdb:
+	call	setjmp_setscb;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jz return;
+	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	mvi	DFFSXFRCTL, CLRCHN ret;
+
 /*
  * Nonpackreq is a polled status.  It can come true in three situations:
  * we have received an L_Q, we have sent one or more L_Qs, or there is no
@@ -1865,6 +1971,7 @@ pkt_overrun_end:
 	or	SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID;
 	test	SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase;
 	test	SCB_CONTROL, STATUS_RCVD jnz last_pkt_queue_scb;
+	or	LONGJMP_ADDR[1], INVALID_ADDR;
 	mvi	DFFSXFRCTL, CLRCHN ret;
 
 if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {
@@ -1885,5 +1992,3 @@ load_overrun_buf:
 	mvi	HCNT[1], ((PKT_OVERRUN_BUFSIZE >> 8) & 0xFF);
 	clr	HCNT[2] ret;
 }
-
-cfg4icmd_intr:
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index eb877417ab725bea301e4d182deb5ffdbd878b94..e9080a5cda038936d1c5da0f7d5f0d39601cb65d 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#156 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#178 $
  *
  * $FreeBSD$
  */
@@ -406,7 +406,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
 		u_int	 i;
 		
 		ahd_set_scbptr(ahd, scbid);
-		next_scbid = ahd_inw(ahd, SCB_NEXT_COMPLETE);
+		next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
 			printf("%s: Warning - DMA-up and complete "
@@ -415,7 +415,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
 		}
 		hscb_ptr = (uint8_t *)scb->hscb;
 		for (i = 0; i < sizeof(struct hardware_scb); i++)
-			*hscb_ptr++ = ahd_inb(ahd, SCB_BASE + i);
+			*hscb_ptr++ = ahd_inb_scbram(ahd, SCB_BASE + i);
 
 		ahd_complete_scb(ahd, scb);
 		scbid = next_scbid;
@@ -426,7 +426,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
 	while (!SCBID_IS_NULL(scbid)) {
 
 		ahd_set_scbptr(ahd, scbid);
-		next_scbid = ahd_inw(ahd, SCB_NEXT_COMPLETE);
+		next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
 			printf("%s: Warning - Complete SCB %d invalid\n",
@@ -1249,6 +1249,14 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
 		ahd_outb(ahd, CLRSINT3, status3);
 	} else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {
 		ahd_handle_lqiphase_error(ahd, lqistat1);
+	} else if ((lqistat1 & LQICRCI_NLQ) != 0) {
+		/*
+		 * This status can be delayed during some
+		 * streaming operations.  The SCSIPHASE
+		 * handler has already dealt with this case
+		 * so just clear the error.
+		 */
+		ahd_outb(ahd, CLRLQIINT1, CLRLQICRCI_NLQ);
 	} else if ((status & BUSFREE) != 0) {
 		u_int lqostat1;
 		int   restart;
@@ -1284,9 +1292,9 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
 			scbid = ahd_get_scbptr(ahd);
 			scb = ahd_lookup_scb(ahd, scbid);
 			if (scb == NULL) {
-				printf("%s: Invalid SCB in DFF%d "
+				printf("%s: Invalid SCB %d in DFF%d "
 				       "during unexpected busfree\n",
-				       ahd_name(ahd), mode);
+				       ahd_name(ahd), scbid, mode);
 				packetized = 0;
 			} else
 				packetized = (scb->flags & SCB_PACKETIZED) != 0;
@@ -1626,14 +1634,6 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL)
 		       panic("SCB not valid during LQOBUSFREE");
-		/*
-		 * Return the LQO manager to its idle loop.  It will
-		 * not do this automatically if the busfree occurs
-		 * after the first REQ of either the LQ or command
-		 * packet or between the LQ and command packet.
-		 */
-		ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE);
-
 		/*
 		 * Clear the status.
 		 */
@@ -1641,8 +1641,17 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
 		if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)
 			ahd_outb(ahd, CLRLQOINT1, 0);
 		ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+		ahd_flush_device_writes(ahd);
 		ahd_outb(ahd, CLRSINT0, CLRSELDO);
 
+		/*
+		 * Return the LQO manager to its idle loop.  It will
+		 * not do this automatically if the busfree occurs
+		 * after the first REQ of either the LQ or command
+		 * packet or between the LQ and command packet.
+		 */
+		ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE);
+
 		/*
 		 * Update the waiting for selection queue so
 		 * we restart on the correct SCB.
@@ -1653,12 +1662,12 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
 
 			ahd_outw(ahd, WAITING_TID_HEAD, scbid);
 			waiting_t = ahd_inw(ahd, WAITING_TID_TAIL);
-			next = SCB_LIST_NULL;
 			if (waiting_t == waiting_h) {
 				ahd_outw(ahd, WAITING_TID_TAIL, scbid);
+				next = SCB_LIST_NULL;
 			} else {
 				ahd_set_scbptr(ahd, waiting_h);
-				next = ahd_inw(ahd, SCB_NEXT2);
+				next = ahd_inw_scbram(ahd, SCB_NEXT2);
 			}
 			ahd_set_scbptr(ahd, scbid);
 			ahd_outw(ahd, SCB_NEXT2, next);
@@ -1704,6 +1713,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
 		scb = ahd_lookup_scb(ahd, scbid);
 		ahd_print_path(ahd, scb);
 		printf("Unexpected PKT busfree condition\n");
+		ahd_dump_card_state(ahd);
 		ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A',
 			       SCB_GET_LUN(scb), SCB_GET_TAG(scb),
 			       ROLE_INITIATOR, CAM_UNEXP_BUSFREE);
@@ -1988,7 +1998,8 @@ ahd_handle_proto_violation(struct ahd_softc *ahd)
 		if ((seq_flags & NO_CDB_SENT) != 0) {
 			ahd_print_path(ahd, scb);
 			printf("No or incomplete CDB sent to device.\n");
-		} else if ((ahd_inb(ahd, SCB_CONTROL) & STATUS_RCVD) == 0) {
+		} else if ((ahd_inb_scbram(ahd, SCB_CONTROL)
+			  & STATUS_RCVD) == 0) {
 			/*
 			 * The target never bothered to provide status to
 			 * us prior to completing the command.  Since we don't
@@ -2605,8 +2616,12 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
 				       ahd_name(ahd), devinfo->target,
 				       period, offset);
 				options = 0;
+				if ((ppr_options & MSG_EXT_PPR_RD_STRM) != 0) {
+					printf("(RDSTRM");
+					options++;
+				}
 				if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
-					printf("(DT");
+					printf("%s", options ? "|DT" : "(DT");
 					options++;
 				}
 				if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
@@ -4817,9 +4832,6 @@ ahd_softc_insert(struct ahd_softc *ahd)
 				slave->flags &= ~AHD_BIOS_ENABLED; 
 				slave->flags |=
 				    master->flags & AHD_BIOS_ENABLED;
-				slave->flags &= ~AHD_PRIMARY_CHANNEL; 
-				slave->flags |=
-				    master->flags & AHD_PRIMARY_CHANNEL;
 				break;
 			}
 		}
@@ -4831,7 +4843,7 @@ ahd_softc_insert(struct ahd_softc *ahd)
 	 */
 	list_ahd = TAILQ_FIRST(&ahd_tailq);
 	while (list_ahd != NULL
-	    && ahd_softc_comp(list_ahd, ahd) <= 0)
+	    && ahd_softc_comp(ahd, list_ahd) <= 0)
 		list_ahd = TAILQ_NEXT(list_ahd, links);
 	if (list_ahd != NULL)
 		TAILQ_INSERT_BEFORE(list_ahd, ahd, links);
@@ -4980,6 +4992,8 @@ ahd_reset(struct ahd_softc *ahd)
 	 * to disturb the integrity of the bus.
 	 */
 	ahd_pause(ahd);
+	ahd_update_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 	sxfrctl1 = ahd_inb(ahd, SXFRCTL1);
 
 	cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);
@@ -5028,13 +5042,16 @@ ahd_reset(struct ahd_softc *ahd)
 		ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
 				     cmd, /*bytes*/2);
 	}
-	/* After a reset, we know the state of the mode register. */
-	ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 
-	/* Determine chip configuration */
-	ahd->features &= ~AHD_WIDE;
-	if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0)
-		ahd->features |= AHD_WIDE;
+	/*
+	 * Mode should be SCSI after a chip reset, but lets
+	 * set it just to be safe.  We touch the MODE_PTR
+	 * register directly so as to bypass the lazy update
+	 * code in ahd_set_modes().
+	 */
+	ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	ahd_outb(ahd, MODE_PTR,
+		 ahd_build_mode_state(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI));
 
 	/*
 	 * Restore SXFRCTL1.
@@ -5047,9 +5064,14 @@ ahd_reset(struct ahd_softc *ahd)
 	ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN);
 	ahd_outb(ahd, SXFRCTL1, sxfrctl1);
 
+	/* Determine chip configuration */
+	ahd->features &= ~AHD_WIDE;
+	if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0)
+		ahd->features |= AHD_WIDE;
+
 	/*
 	 * If a recovery action has forced a chip reset,
-	 * re-initialize the chip to our likeing.
+	 * re-initialize the chip to our liking.
 	 */
 	if (ahd->init_level > 0)
 		ahd_chip_init(ahd);
@@ -5158,7 +5180,7 @@ ahd_init_scbdata(struct ahd_softc *ahd)
 	scb_data->init_level++;
 
 	/* DMA tag for our S/G structures. */
-	if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1,
+	if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/8,
 			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
 			       /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
 			       /*highaddr*/BUS_SPACE_MAXADDR,
@@ -5793,7 +5815,9 @@ ahd_init(struct ahd_softc *ahd)
 	/* DMA tag for mapping buffers into device visible space. */
 	if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1,
 			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
-			       /*lowaddr*/BUS_SPACE_MAXADDR,
+			       /*lowaddr*/ahd->flags & AHD_39BIT_ADDRESSING
+					? (bus_addr_t)0x7FFFFFFFFFULL
+					: BUS_SPACE_MAXADDR_32BIT,
 			       /*highaddr*/BUS_SPACE_MAXADDR,
 			       /*filter*/NULL, /*filterarg*/NULL,
 			       /*maxsize*/(AHD_NSEG - 1) * PAGE_SIZE,
@@ -6050,7 +6074,7 @@ ahd_chip_init(struct ahd_softc *ahd)
 	} else {
 		ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE);
 	}
-	ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN);
+	ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN|SHVALIDSTDIS);
 	if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX)
 		/*
 		 * Do not issue a target abort when a split completion
@@ -6341,7 +6365,7 @@ ahd_default_config(struct ahd_softc *ahd)
 #else
 		tinfo->user.period = AHD_SYNCRATE_160;
 #endif
-		tinfo->user.offset= ~0;
+		tinfo->user.offset = MAX_OFFSET;
 		tinfo->user.ppr_options = MSG_EXT_PPR_RD_STRM
 					| MSG_EXT_PPR_WR_FLOW
 					| MSG_EXT_PPR_HOLD_MCS
@@ -6508,6 +6532,22 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc)
 	return (0);
 }
 
+/*
+ * Parse device configuration information.
+ */
+int
+ahd_parse_vpddata(struct ahd_softc *ahd, struct vpd_config *vpd)
+{
+	int error;
+
+	error = ahd_verify_vpd_cksum(vpd);
+	if (error == 0)
+		return (EINVAL);
+	if ((vpd->bios_flags & VPDBOOTHOST) != 0)
+		ahd->flags |= AHD_BOOT_CHANNEL;
+	return (0);
+}
+
 void
 ahd_intr_enable(struct ahd_softc *ahd, int enable)
 {
@@ -6565,13 +6605,13 @@ ahd_enable_coalessing(struct ahd_softc *ahd, int enable)
 void
 ahd_pause_and_flushwork(struct ahd_softc *ahd)
 {
-	u_int intstat;
-	u_int maxloops;
-	int   paused;
+	ahd_mode_state	saved_modes;
+	u_int		intstat;
+	u_int		maxloops;
+	int		paused;
 
 	maxloops = 1000;
 	ahd->flags |= AHD_ALL_INTERRUPTS;
-	intstat = 0;
 	paused = FALSE;
 	do {
 		struct scb *waiting_scb;
@@ -6582,6 +6622,8 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
 		ahd_pause(ahd);
 		paused = TRUE;
 		ahd_clear_critical_section(ahd);
+		saved_modes = ahd_save_modes(ahd);
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 		if ((ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
 			ahd_outb(ahd, SCSISEQ0,
 				 ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
@@ -6598,10 +6640,10 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
 			ahd_outb(ahd, SCSISEQ0,
 				 ahd_inb(ahd, SCSISEQ0) | ENSELO);
 
-		if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0)
-			break;
+		intstat = ahd_inb(ahd, INTSTAT);
 	} while (--maxloops
-	      && (((intstat = ahd_inb(ahd, INTSTAT)) & INT_PEND) != 0
+	      && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0)
+	      && ((intstat & INT_PEND) != 0
 	       || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO))));
 	if (maxloops == 0) {
 		printf("Infinite interrupt loop, INTSTAT = %x",
@@ -6612,6 +6654,7 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
 
 	ahd_platform_flushwork(ahd);
 	ahd->flags &= ~AHD_ALL_INTERRUPTS;
+	ahd_restore_modes(ahd, saved_modes);
 }
 
 int
@@ -6785,7 +6828,6 @@ ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl)
 
 /*
  * Return the untagged transaction id for a given target/channel lun.
- * Optionally, clear the entry.
  */
 u_int
 ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl)
@@ -7295,7 +7337,6 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
 {
 	struct		scb *scbp;
 	struct		scb *scbp_next;
-	u_int		active_scb;
 	u_int		i, j;
 	u_int		maxtarget;
 	u_int		minlun;
@@ -7303,11 +7344,10 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
 	int		found;
 	ahd_mode_state	saved_modes;
 
-	/* restore these when we're done */
-	active_scb = ahd_get_scbptr(ahd);
+	/* restore this when we're done */
 	saved_modes = ahd_save_modes(ahd);
-
 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+
 	found = ahd_search_qinfifo(ahd, target, channel, lun, SCB_LIST_NULL,
 				   role, CAM_REQUEUE_REQ, SEARCH_COMPLETE);
 
@@ -7381,7 +7421,6 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
 			found++;
 		}
 	}
-	ahd_set_scbptr(ahd, active_scb);
 	ahd_restore_modes(ahd, saved_modes);
 	ahd_platform_abort_scbs(ahd, target, channel, lun, tag, role, status);
 	ahd->flags |= AHD_UPDATE_PEND_CMDS;
@@ -7670,7 +7709,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
 {
 	struct hardware_scb *hscb;
 	u_int  qfreeze_cnt;
-	ahd_mode_state saved_modes;
 
 	/*
 	 * The sequencer freezes its select-out queue
@@ -7682,7 +7720,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
 
 	/* Freeze the queue until the client sees the error. */
 	ahd_pause(ahd);
-	saved_modes = ahd_save_modes(ahd);
 	ahd_clear_critical_section(ahd);
 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 	ahd_freeze_devq(ahd, scb);
@@ -8148,7 +8185,7 @@ ahd_loadseq(struct ahd_softc *ahd)
 	/* Start by aligning to the nearest cacheline. */
 	sg_prefetch_align = ahd->pci_cachesize;
 	if (sg_prefetch_align == 0)
-		sg_prefetch_cnt = 8;
+		sg_prefetch_align = 8;
 	/* Round down to the nearest power of 2. */
 	while (powerof2(sg_prefetch_align) == 0)
 		sg_prefetch_align--;
@@ -8744,11 +8781,12 @@ ahd_dump_scbs(struct ahd_softc *ahd)
 /*
  * Read count 16bit words from 16bit word address start_addr from the
  * SEEPROM attached to the controller, into buf, using the controller's
- * SEEPROM reading state machine.
+ * SEEPROM reading state machine.  Optionally treat the data as a byte
+ * stream in terms of byte order.
  */
 int
 ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf,
-		 u_int start_addr, u_int count)
+		 u_int start_addr, u_int count, int bytestream)
 {
 	u_int cur_addr;
 	u_int end_addr;
@@ -8762,13 +8800,26 @@ ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf,
 	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
 	end_addr = start_addr + count;
 	for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) {
+
 		ahd_outb(ahd, SEEADR, cur_addr);
 		ahd_outb(ahd, SEECTL, SEEOP_READ | SEESTART);
 		
 		error = ahd_wait_seeprom(ahd);
 		if (error)
 			break;
-		*buf++ = ahd_inw(ahd, SEEDAT);
+		if (bytestream != 0) {
+			uint8_t *bytestream_ptr;
+
+			bytestream_ptr = (uint8_t *)buf;
+			*bytestream_ptr++ = ahd_inb(ahd, SEEDAT);
+			*bytestream_ptr = ahd_inb(ahd, SEEDAT+1);
+		} else {
+			/*
+			 * ahd_inw() already handles machine byte order.
+			 */
+			*buf = ahd_inw(ahd, SEEDAT);
+		}
+		buf++;
 	}
 	return (error);
 }
@@ -8841,6 +8892,38 @@ ahd_wait_seeprom(struct ahd_softc *ahd)
 	return (0);
 }
 
+/*
+ * Validate the two checksums in the per_channel
+ * vital product data struct.
+ */
+int
+ahd_verify_vpd_cksum(struct vpd_config *vpd)
+{
+	int i;
+	int maxaddr;
+	uint32_t checksum;
+	uint8_t *vpdarray;
+
+	vpdarray = (uint8_t *)vpd;
+	maxaddr = offsetof(struct vpd_config, vpd_checksum);
+	checksum = 0;
+	for (i = offsetof(struct vpd_config, resource_type); i < maxaddr; i++)
+		checksum = checksum + vpdarray[i];
+	if (checksum == 0
+	 || (-checksum & 0xFF) != vpd->vpd_checksum)
+		return (0);
+
+	checksum = 0;
+	maxaddr = offsetof(struct vpd_config, checksum);
+	for (i = offsetof(struct vpd_config, default_target_flags);
+	     i < maxaddr; i++)
+		checksum = checksum + vpdarray[i];
+	if (checksum == 0
+	 || (-checksum & 0xFF) != vpd->checksum)
+		return (0);
+	return (1);
+}
+
 int
 ahd_verify_cksum(struct seeprom_config *sc)
 {
diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
index bdca5c17b33fec27f41bf0e56b32715264e0b8d2..78462adc6457c7513c48ab790a65d12bc4216a02 100644
--- a/drivers/scsi/aic7xxx/aic79xx_inline.h
+++ b/drivers/scsi/aic7xxx/aic79xx_inline.h
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#41 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#44 $
  *
  * $FreeBSD$
  */
@@ -678,7 +678,8 @@ ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
 	 * Razor #528
 	 */
 	value = ahd_inb(ahd, offset);
-	ahd_inb(ahd, MODE_PTR);
+	if ((ahd->flags & AHD_PCIX_SCBRAM_RD_BUG) != 0)
+		ahd_inb(ahd, MODE_PTR);
 	return (value);
 }
 
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index b67dd10f98d2a84fdf56d82d7163c4602a123048..47992fc7b0e0b235b2ed379847a863b34e353211 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC79xx device driver for Linux.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#115 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#141 $
  *
  * --------------------------------------------------------------------------
  * Copyright (c) 1994-2000 Justin T. Gibbs.
@@ -460,12 +460,12 @@ MODULE_PARM_DESC(aic79xx,
 "		Set tag depth on Controller 2/Target 2 to 10 tags\n"
 "		Shorten the selection timeout to 128ms\n"
 "\n"
-"	options aic79xx='\"verbose.tag_info:{{}.{}.{..10}}.seltime:1\"'\n"
+"	options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
 "\n"
 "	Sample /etc/modules.conf line:\n"
 "		Change Read Streaming for Controller's 2 and 3\n"
 "\n"
-"	options aic79xx='\"rd_strm:{..0xFFF0.0xC0F0}\"'");
+"	options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'");
 #endif
 
 static void ahd_linux_handle_scsi_status(struct ahd_softc *,
@@ -482,6 +482,7 @@ static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd);
 static void ahd_linux_start_dv(struct ahd_softc *ahd);
 static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd);
 static int  ahd_linux_dv_thread(void *data);
+static void ahd_linux_kill_dv_thread(struct ahd_softc *ahd);
 static void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target);
 static void ahd_linux_dv_transition(struct ahd_softc *ahd,
 				    struct scsi_cmnd *cmd,
@@ -526,6 +527,7 @@ static void ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ);
 static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd,
 				     struct ahd_devinfo *devinfo);
 static u_int ahd_linux_user_dv_setting(struct ahd_softc *ahd);
+static void ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd);
 static void ahd_linux_device_queue_depth(struct ahd_softc *ahd,
 					 struct ahd_linux_device *dev);
 static struct ahd_linux_target*	ahd_linux_alloc_target(struct ahd_softc*,
@@ -539,11 +541,11 @@ static void			ahd_linux_free_device(struct ahd_softc*,
 						      struct ahd_linux_device*);
 static void ahd_linux_run_device_queue(struct ahd_softc*,
 				       struct ahd_linux_device*);
-static void ahd_linux_setup_tag_info(char *p, char *end, char *s);
 static void ahd_linux_setup_tag_info_global(char *p);
-static void ahd_linux_setup_rd_strm_info(char *p, char *end, char *s);
-static void ahd_linux_setup_dv(char *p, char *end, char *s);
-static void ahd_linux_setup_iocell_info(char *p, char *end, char *s, int index);
+static aic_option_callback_t ahd_linux_setup_tag_info;
+static aic_option_callback_t ahd_linux_setup_rd_strm_info;
+static aic_option_callback_t ahd_linux_setup_dv;
+static aic_option_callback_t ahd_linux_setup_iocell_info;
 static int ahd_linux_next_unit(void);
 static void ahd_runq_tasklet(unsigned long data);
 static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf);
@@ -599,6 +601,9 @@ ahd_schedule_completeq(struct ahd_softc *ahd, struct ahd_cmd *acmd)
 	}
 }
 
+/*
+ * Must be called with our lock held.
+ */
 static __inline void
 ahd_schedule_runq(struct ahd_softc *ahd)
 {
@@ -662,8 +667,8 @@ ahd_linux_run_complete_queue(struct ahd_softc *ahd, struct ahd_cmd *acmd)
 	u_long	done_flags;
 	int	with_errors;
 
-	ahd_done_lock(ahd, &done_flags);
 	with_errors = 0;
+	ahd_done_lock(ahd, &done_flags);
 	while (acmd != NULL) {
 		Scsi_Cmnd *cmd;
 
@@ -994,9 +999,13 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
 				   cmd->device->id, cmd->device->lun,
 				   /*alloc*/TRUE);
 	if (dev == NULL) {
+		ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);
+		ahd_linux_queue_cmd_complete(ahd, cmd);
+		ahd_schedule_completeq(ahd, NULL);
 		ahd_midlayer_entrypoint_unlock(ahd, &flags);
-		printf("aic79xx_linux_queue: Unable to allocate device!\n");
-		return (-ENOMEM);
+		printf("%s: aic79xx_linux_queue - Unable to allocate device!\n",
+		       ahd_name(ahd));
+		return (0);
 	}
 	if (cmd->cmd_len > MAX_CDB_LEN)
 		return (-EINVAL);
@@ -1098,7 +1107,7 @@ ahd_linux_select_queue_depth(struct Scsi_Host * host,
 	int	scbnum;
 
 	ahd = *((struct ahd_softc **)host->hostdata);
-	ahd_midlayer_entrypoint_lock(ahd, &flags);
+	ahd_lock(ahd, &flags);
 	scbnum = 0;
 	for (device = scsi_devs; device != NULL; device = device->next) {
 
@@ -1133,7 +1142,7 @@ ahd_linux_select_queue_depth(struct Scsi_Host * host,
 			}
 		}
 	}
-	ahd_midlayer_entrypoint_unlock(ahd, &flags);
+	ahd_unlock(ahd, &flags);
 }
 #endif
 
@@ -1215,6 +1224,7 @@ ahd_linux_abort(Scsi_Cmnd *cmd)
 	u_int  saved_scbptr;
 	u_int  active_scbptr;
 	u_int  last_phase;
+	u_int  cdb_byte;
 	int    retval;
 	int    paused;
 	int    wait;
@@ -1227,9 +1237,12 @@ ahd_linux_abort(Scsi_Cmnd *cmd)
 	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
 	acmd = (struct ahd_cmd *)cmd;
 
-	printf("%s:%d:%d:%d: Attempting to abort cmd %p\n",
+	printf("%s:%d:%d:%d: Attempting to abort cmd %p:",
 	       ahd_name(ahd), cmd->device->channel, cmd->device->id,
 	       cmd->device->lun, cmd);
+	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
+		printf(" 0x%x", cmd->cmnd[cdb_byte]);
+	printf("\n");
 
 	/*
 	 * In all versions of Linux, we have to work around
@@ -1245,9 +1258,6 @@ ahd_linux_abort(Scsi_Cmnd *cmd)
 	 * by acquiring either the io_request_lock or our own
 	 * lock, this *should* be safe.
 	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_unlock_irq(&io_request_lock);
-#endif
 	ahd_midlayer_entrypoint_lock(ahd, &s);
 
 	/*
@@ -1456,14 +1466,10 @@ ahd_linux_abort(Scsi_Cmnd *cmd)
 		struct timer_list timer;
 		int ret;
 
-		ahd->platform_data->flags |= AHD_UP_EH_SEMAPHORE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		ahd_unlock(ahd, &s);
-#else
-		spin_unlock_irq(ahd->platform_data->host->host_lock);
-#endif
+		pending_scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;
+		spin_unlock_irq(&ahd->platform_data->spin_lock);
 		init_timer(&timer);
-		timer.data = (u_long)ahd;
+		timer.data = (u_long)pending_scb;
 		timer.expires = jiffies + (5 * HZ);
 		timer.function = ahd_linux_sem_timeout;
 		add_timer(&timer);
@@ -1475,27 +1481,17 @@ ahd_linux_abort(Scsi_Cmnd *cmd)
 			printf("Timer Expired\n");
 			retval = FAILED;
 		}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		ahd_lock(ahd, &s);
-#else
-		spin_lock_irq(ahd->platform_data->host->host_lock);
-#endif
+		spin_lock_irq(&ahd->platform_data->spin_lock);
 	}
 	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
 	TAILQ_INIT(&ahd->platform_data->completeq);
-	ahd_midlayer_entrypoint_unlock(ahd, &s);
+	ahd_schedule_runq(ahd);
 	if (acmd != NULL) {
 		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL) {
-			ahd_midlayer_entrypoint_lock(ahd, &s);
+		if (acmd != NULL)
 			ahd_schedule_completeq(ahd, acmd);
-			ahd_midlayer_entrypoint_unlock(ahd, &s);
-		}
 	}
-	ahd_schedule_runq(ahd);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_lock_irq(&io_request_lock);
-#endif
+	ahd_midlayer_entrypoint_unlock(ahd, &s);
 	return (retval);
 }
 
@@ -1524,9 +1520,6 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd)
 	struct	timer_list timer;
 	int	retval;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_unlock_irq(&io_request_lock);
-#endif
 	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
 	recovery_cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);
 	memset(recovery_cmd, 0, sizeof(struct scsi_cmnd));
@@ -1577,14 +1570,10 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd)
 	LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
 	ahd_queue_scb(ahd, scb);
 
-	ahd->platform_data->flags |= AHD_UP_EH_SEMAPHORE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahd_unlock(ahd, &s);
-#else
-	spin_unlock_irq(ahd->platform_data->host->host_lock);
-#endif
+	scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;
+	spin_unlock_irq(&ahd->platform_data->spin_lock);
 	init_timer(&timer);
-	timer.data = (u_long)ahd;
+	timer.data = (u_long)scb;
 	timer.expires = jiffies + (5 * HZ);
 	timer.function = ahd_linux_sem_timeout;
 	add_timer(&timer);
@@ -1596,26 +1585,16 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd)
 		printf("Timer Expired\n");
 		retval = FAILED;
 	}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahd_lock(ahd, &s);
-#else
-	spin_lock_irq(ahd->platform_data->host->host_lock);
-#endif
+	spin_lock_irq(&ahd->platform_data->spin_lock);
 	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
 	TAILQ_INIT(&ahd->platform_data->completeq);
-	ahd_midlayer_entrypoint_unlock(ahd, &s);
+	ahd_schedule_runq(ahd);
 	if (acmd != NULL) {
 		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL) {
-			ahd_midlayer_entrypoint_lock(ahd, &s);
+		if (acmd != NULL)
 			ahd_schedule_completeq(ahd, acmd);
-			ahd_midlayer_entrypoint_unlock(ahd, &s);
-		}
 	}
-	ahd_schedule_runq(ahd);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_lock_irq(&io_request_lock);
-#endif
+	ahd_midlayer_entrypoint_unlock(ahd, &s);
 	printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
 	return (retval);
 }
@@ -1631,9 +1610,6 @@ ahd_linux_bus_reset(Scsi_Cmnd *cmd)
 	u_long s;
 	int    found;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_unlock_irq(&io_request_lock);
-#endif
 	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
@@ -1645,23 +1621,18 @@ ahd_linux_bus_reset(Scsi_Cmnd *cmd)
 				  /*initiate reset*/TRUE);
 	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
 	TAILQ_INIT(&ahd->platform_data->completeq);
-	ahd_midlayer_entrypoint_unlock(ahd, &s);
-	if (bootverbose)
-		printf("%s: SCSI bus reset delivered. "
-		       "%d SCBs aborted.\n", ahd_name(ahd), found);
 
 	if (acmd != NULL) {
 		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL) {
-			ahd_midlayer_entrypoint_lock(ahd, &s);
+		if (acmd != NULL)
 			ahd_schedule_completeq(ahd, acmd);
-			ahd_midlayer_entrypoint_unlock(ahd, &s);
-		}
 	}
+	ahd_midlayer_entrypoint_unlock(ahd, &s);
+
+	if (bootverbose)
+		printf("%s: SCSI bus reset delivered. "
+		       "%d SCBs aborted.\n", ahd_name(ahd), found);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_lock_irq(&io_request_lock);
-#endif
 	return (SUCCESS);
 }
 
@@ -1691,7 +1662,7 @@ Scsi_Host_Template aic79xx_driver_template = {
 	.max_sectors		= 8192,
 #endif
 #if defined CONFIG_HIGHIO || LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
 /* Assume RedHat Distribution with its different HIGHIO conventions. */
 	.can_dma_32		= 1,
 	.single_sg_okay		= 1,
@@ -1713,15 +1684,25 @@ Scsi_Host_Template aic79xx_driver_template = {
 
 /**************************** Tasklet Handler *********************************/
 
+/*
+ * In 2.4.X and above, this routine is called from a tasklet,
+ * so we must re-acquire our lock prior to executing this code.
+ * In all prior kernels, ahd_schedule_runq() calls this routine
+ * directly and ahd_schedule_runq() is called with our lock held.
+ */
 static void
 ahd_runq_tasklet(unsigned long data)
 {
 	struct ahd_softc* ahd;
 	struct ahd_linux_device *dev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	u_long flags;
+#endif
 
 	ahd = (struct ahd_softc *)data;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	ahd_lock(ahd, &flags);
+#endif
 	while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {
 	
 		TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);
@@ -1731,7 +1712,9 @@ ahd_runq_tasklet(unsigned long data)
 		ahd_unlock(ahd, &flags);
 		ahd_lock(ahd, &flags);
 	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	ahd_unlock(ahd, &flags);
+#endif
 }
 
 /************************ Shutdown/halt/reboot hook ***************************/
@@ -1890,361 +1873,109 @@ ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map)
 }
 
 /********************* Platform Dependent Functions ***************************/
+/*
+ * Compare "left hand" softc with "right hand" softc, returning:
+ * < 0 - lahd has a lower priority than rahd
+ *   0 - Softcs are equal
+ * > 0 - lahd has a higher priority than rahd
+ */
 int
 ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
 {
 	int	value;
-	char	primary_channel;
 
 	/*
 	 * Under Linux, cards are ordered as follows:
-	 *	1) PCI devices with BIOS enabled sorted by bus/slot/func.
-	 *	2) All remaining PCI devices sorted by bus/slot/func.
+	 *	1) PCI devices that are marked as the boot controller.
+	 *	2) PCI devices with BIOS enabled sorted by bus/slot/func.
+	 *	3) All remaining PCI devices sorted by bus/slot/func.
 	 */
+#if 0
+	value = (lahd->flags & AHD_BOOT_CHANNEL)
+	      - (rahd->flags & AHD_BOOT_CHANNEL);
+	if (value != 0)
+		/* Controllers set for boot have a *higher* priority */
+		return (value);
+#endif
+
 	value = (lahd->flags & AHD_BIOS_ENABLED)
 	      - (rahd->flags & AHD_BIOS_ENABLED);
 	if (value != 0)
 		/* Controllers with BIOS enabled have a *higher* priority */
-		return (-value);
+		return (value);
 
 	/* Still equal.  Sort by bus/slot/func. */
 	if (aic79xx_reverse_scan != 0)
-		value = ahd_get_pci_bus(rahd->dev_softc)
-		      - ahd_get_pci_bus(lahd->dev_softc);
-	else
 		value = ahd_get_pci_bus(lahd->dev_softc)
 		      - ahd_get_pci_bus(rahd->dev_softc);
+	else
+		value = ahd_get_pci_bus(rahd->dev_softc)
+		      - ahd_get_pci_bus(lahd->dev_softc);
 	if (value != 0)
 		return (value);
 	if (aic79xx_reverse_scan != 0)
-		value = ahd_get_pci_slot(rahd->dev_softc)
-		      - ahd_get_pci_slot(lahd->dev_softc);
-	else
 		value = ahd_get_pci_slot(lahd->dev_softc)
 		      - ahd_get_pci_slot(rahd->dev_softc);
+	else
+		value = ahd_get_pci_slot(rahd->dev_softc)
+		      - ahd_get_pci_slot(lahd->dev_softc);
 	if (value != 0)
 		return (value);
 
-	/*
-	 * On multi-function devices, the user can choose
-	 * to have function 1 probed before function 0.
-	 * Give whichever channel is the primary channel
-	 * the lowest priority.
-	 */
-	primary_channel = (lahd->flags & AHD_PRIMARY_CHANNEL) + 'A';
-	value = 1;
-	if (lahd->channel == primary_channel)
-		value = -1;
+	value = rahd->channel - lahd->channel;
 	return (value);
 }
 
 static void
-ahd_linux_setup_tag_info(char *p, char *end, char *s)
+ahd_linux_setup_tag_info(void *arg, int instance, int targ, int32_t value)
 {
-	char	*base;
-	char	*tok;
-	char	*tok_end;
-	char	*tok_end2;
-	int      i;
-	int      instance;
-	int	 targ;
-	int	 done;
-	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
-
-	if (*p != ':')
-		return;
 
-	instance = -1;
-	targ = -1;
-	done = FALSE;
-	base = p;
-	/* Forward us just past the ':' */
-	tok = base + 1;
-	tok_end = strchr(tok, '\0');
-	if (tok_end < end)
-		*tok_end = ',';
-	while (!done) {
-		switch (*tok) {
-		case '{':
-			if (instance == -1)
-				instance = 0;
-			else if (targ == -1)
-				targ = 0;
-			tok++;
-			break;
-		case '}':
-			if (targ != -1)
-				targ = -1;
-			else if (instance != -1)
-				instance = -1;
-			tok++;
-			break;
-		case ',':
-		case '.':
-			if (instance == -1)
-				done = TRUE;
-			else if (targ >= 0)
-				targ++;
-			else if (instance >= 0)
-				instance++;
-			if ((targ >= AHD_NUM_TARGETS) ||
-			    (instance >= NUM_ELEMENTS(aic79xx_tag_info)))
-				done = TRUE;
-			tok++;
-			if (!done) {
-				base = tok;
-			}
-			break;
-		case '\0':
-			done = TRUE;
-			break;
-		default:
-			done = TRUE;
-			tok_end = strchr(tok, '\0');
-			for (i = 0; tok_list[i]; i++) {
-				tok_end2 = strchr(tok, tok_list[i]);
-				if ((tok_end2) && (tok_end2 < tok_end)) {
-					tok_end = tok_end2;
-					done = FALSE;
-				}
-			}
-			if ((instance >= 0) && (targ >= 0)
-			 && (instance < NUM_ELEMENTS(aic79xx_tag_info))
-			 && (targ < AHD_NUM_TARGETS)) {
-				aic79xx_tag_info[instance].tag_commands[targ] =
-				    simple_strtoul(tok, NULL, 0) & 0xff;
-			}
-			tok = tok_end;
-			break;
-		}
+	if ((instance >= 0) && (targ >= 0)
+	 && (instance < NUM_ELEMENTS(aic79xx_tag_info))
+	 && (targ < AHD_NUM_TARGETS)) {
+		aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF;
+		if (bootverbose)
+			printf("tag_info[%d:%d] = %d\n", instance, targ, value);
 	}
-	while ((p != base) && (p != NULL))
-		p = strsep(&s, ",.");
 }
 
 static void
-ahd_linux_setup_rd_strm_info(char *p, char *end, char *s)
+ahd_linux_setup_rd_strm_info(void *arg, int instance, int targ, int32_t value)
 {
-	char	*base;
-	char	*tok;
-	char	*tok_end;
-	char	*tok_end2;
-	int      i;
-	int      instance;
-	int	 done;
-	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
-
-	if (*p != ':')
-		return;
-
-	instance = -1;
-	done = FALSE;
-	base = p;
-	/* Forward us just past the ':' */
-	tok = base + 1;
-	tok_end = strchr(tok, '\0');
-	if (tok_end < end)
-		*tok_end = ',';
-	while (!done) {
-		switch (*tok) {
-		case '{':
-			if (instance == -1)
-				instance = 0;
-			tok++;
-			break;
-		case '}':
-			if (instance != -1)
-				instance = -1;
-			tok++;
-			break;
-		case ',':
-		case '.':
-			if (instance == -1)
-				done = TRUE;
-			else if (instance >= 0)
-				instance++;
-			if (instance >= NUM_ELEMENTS(aic79xx_rd_strm_info))
-				done = TRUE;
-			tok++;
-			if (!done) {
-				base = tok;
-			}
-			break;
-		case '\0':
-			done = TRUE;
-			break;
-		default:
-			done = TRUE;
-			tok_end = strchr(tok, '\0');
-			for (i = 0; tok_list[i]; i++) {
-				tok_end2 = strchr(tok, tok_list[i]);
-				if ((tok_end2) && (tok_end2 < tok_end)) {
-					tok_end = tok_end2;
-					done = FALSE;
-				}
-			}
-			if ((instance >= 0)
-			 && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) {
-				aic79xx_rd_strm_info[instance] =
-				    simple_strtoul(tok, NULL, 0) & 0xffff;
-			}
-			tok = tok_end;
-			break;
-		}
+	if ((instance >= 0)
+	 && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) {
+		aic79xx_rd_strm_info[instance] = value * 0xFFFF;
+		if (bootverbose)
+			printf("rd_strm[%d] = 0x%x\n", instance, value);
 	}
-	while ((p != base) && (p != NULL))
-		p = strsep(&s, ",.");
 }
 
 static void
-ahd_linux_setup_dv(char *p, char *end, char *s)
+ahd_linux_setup_dv(void *arg, int instance, int targ, int32_t value)
 {
-	char	*base;
-	char	*tok;
-	char	*tok_end;
-	char	*tok_end2;
-	int      i;
-	int      instance;
-	int	 done;
-	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
-
-	if (*p != ':')
-		return;
-
-	instance = -1;
-	done = FALSE;
-	base = p;
-	/* Forward us just past the ':' */
-	tok = base + 1;
-	tok_end = strchr(tok, '\0');
-	if (tok_end < end)
-		*tok_end = ',';
-	while (!done) {
-		switch (*tok) {
-		case '{':
-			if (instance == -1)
-				instance = 0;
-			tok++;
-			break;
-		case '}':
-			if (instance != -1)
-				instance = -1;
-			tok++;
-			break;
-		case ',':
-		case '.':
-			if (instance == -1)
-				done = TRUE;
-			else if (instance >= 0)
-				instance++;
-			if (instance >= NUM_ELEMENTS(aic79xx_dv_settings))
-				done = TRUE;
-			tok++;
-			if (!done) {
-				base = tok;
-			}
-			break;
-		case '\0':
-			done = TRUE;
-			break;
-		default:
-			done = TRUE;
-			tok_end = strchr(tok, '\0');
-			for (i = 0; tok_list[i]; i++) {
-				tok_end2 = strchr(tok, tok_list[i]);
-				if ((tok_end2) && (tok_end2 < tok_end)) {
-					tok_end = tok_end2;
-					done = FALSE;
-				}
-			}
-			if ((instance >= 0)
-			 && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) {
-				aic79xx_dv_settings[instance] =
-				    simple_strtol(tok, NULL, 0);
-			}
-			tok = tok_end;
-			break;
-		}
+	if ((instance >= 0)
+	 && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) {
+		aic79xx_dv_settings[instance] = value;
+		if (bootverbose)
+			printf("dv[%d] = %d\n", instance, value);
 	}
-	while ((p != base) && (p != NULL))
-		p = strsep(&s, ",.");
 }
 
 static void
-ahd_linux_setup_iocell_info(char *p, char *end, char *s, int index)
+ahd_linux_setup_iocell_info(void *arg, int instance, int targ, int32_t value)
 {
-	char	*base;
-	char	*tok;
-	char	*tok_end;
-	char	*tok_end2;
-	uint8_t	*iocell_info;
-	int      i;
-	int      instance;
-	int	 done;
-	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
-
-	if (*p != ':')
-		return;
+	u_int index;
 
-	instance = -1;
-	done = FALSE;
-	base = p;
-	/* Forward us just past the ':' */
-	tok = base + 1;
-	tok_end = strchr(tok, '\0');
-	if (tok_end < end)
-		*tok_end = ',';
-	while (!done) {
-		switch (*tok) {
-		case '{':
-			if (instance == -1)
-				instance = 0;
-			tok++;
-			break;
-		case '}':
-			if (instance != -1)
-				instance = -1;
-			tok++;
-			break;
-		case ',':
-		case '.':
-			if (instance == -1)
-				done = TRUE;
-			else if (instance >= 0)
-				instance++;
-			if (instance >= NUM_ELEMENTS(aic79xx_iocell_info))
-				done = TRUE;
-			tok++;
-			if (!done) {
-				base = tok;
-			}
-			break;
-		case '\0':
-			done = TRUE;
-			break;
-		default:
-			done = TRUE;
-			tok_end = strchr(tok, '\0');
-			for (i = 0; tok_list[i]; i++) {
-				tok_end2 = strchr(tok, tok_list[i]);
-				if ((tok_end2) && (tok_end2 < tok_end)) {
-					tok_end = tok_end2;
-					done = FALSE;
-				}
-			}
-			if ((instance >= 0)
-			 && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {
-				iocell_info =
-				    (uint8_t*)&aic79xx_iocell_info[instance];
-				iocell_info[index] = 
-				    simple_strtoul(tok, NULL, 0) & 0xffff;
-			}
-			tok = tok_end;
-			break;
-		}
+	index = (u_int)arg;
+	if ((instance >= 0)
+	 && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {
+		uint8_t *iocell_info;
+
+		iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];
+		iocell_info[index] = value & 0xFFFF;
+		if (bootverbose)
+			printf("iocell[%d:%d] = %d\n", instance, index, value);
 	}
-	while ((p != base) && (p != NULL))
-		p = strsep(&s, ",.");
 }
 
 static void
@@ -2300,41 +2031,54 @@ aic79xx_setup(char *s)
 
 	end = strchr(s, '\0');
 
+	/*
+	 * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS
+	 * will never be 0 in this case.
+	 */      
+	n = 0;  
+
 	while ((p = strsep(&s, ",.")) != NULL) {
 		if (*p == '\0')
 			continue;
 		for (i = 0; i < NUM_ELEMENTS(options); i++) {
-			n = strlen(options[i].name);
 
-			if (strncmp(options[i].name, p, n) != 0)
-				continue;
+			n = strlen(options[i].name);
+			if (strncmp(options[i].name, p, n) == 0)
+				break;
+		}
+		if (i == NUM_ELEMENTS(options))
+			continue;
 
-			if (!strncmp(p, "global_tag_depth", n)) {
-				ahd_linux_setup_tag_info_global(p + n);
-			} else if (!strncmp(p, "tag_info", n)) {
-				ahd_linux_setup_tag_info(p + n, end, s);
-			} else if (strncmp(p, "rd_strm", n) == 0) {
-				ahd_linux_setup_rd_strm_info(p + n, end, s);
-			} else if (strncmp(p, "dv", n) == 0) {
-				ahd_linux_setup_dv(p + n, end, s);
-			} else if (strncmp(p, "slewrate", n) == 0) {
-				ahd_linux_setup_iocell_info(p + n, end, s,
-				    AIC79XX_SLEWRATE_INDEX);
-			} else if (strncmp(p, "precomp", n) == 0) {
-				ahd_linux_setup_iocell_info(p + n, end, s,
-				    AIC79XX_PRECOMP_INDEX);
-			} else if (strncmp(p, "amplitude", n) == 0) {
-				ahd_linux_setup_iocell_info(p + n, end, s,
-				    AIC79XX_AMPLITUDE_INDEX);
-			} else if (p[n] == ':') {
-				*(options[i].flag) =
-				    simple_strtoul(p + n + 1, NULL, 0);
-			} else if (!strncmp(p, "verbose", n)) {
-				*(options[i].flag) = 1;
-			} else {
-				*(options[i].flag) = ~(*(options[i].flag));
-			}
-			break;
+		if (strncmp(p, "global_tag_depth", n) == 0) {
+			ahd_linux_setup_tag_info_global(p + n);
+		} else if (strncmp(p, "tag_info", n) == 0) {
+			s = aic_parse_brace_option("tag_info", p + n, end,
+			    2, ahd_linux_setup_tag_info, NULL);
+		} else if (strncmp(p, "rd_strm", n) == 0) {
+			printf("Calling brace parse for %s\n", p);
+			s = aic_parse_brace_option("rd_strm", p + n, end,
+			    1, ahd_linux_setup_rd_strm_info, NULL);
+		} else if (strncmp(p, "dv", n) == 0) {
+			s = aic_parse_brace_option("dv", p + n, end, 1,
+			    ahd_linux_setup_dv, NULL);
+		} else if (strncmp(p, "slewrate", n) == 0) {
+			s = aic_parse_brace_option("slewrate",
+			    p + n, end, 1, ahd_linux_setup_iocell_info,
+			    (void *)AIC79XX_SLEWRATE_INDEX);
+		} else if (strncmp(p, "precomp", n) == 0) {
+			s = aic_parse_brace_option("precomp",
+			    p + n, end, 1, ahd_linux_setup_iocell_info,
+			    (void *)AIC79XX_PRECOMP_INDEX);
+		} else if (strncmp(p, "amplitude", n) == 0) {
+			s = aic_parse_brace_option("amplitude",
+			    p + n, end, 1, ahd_linux_setup_iocell_info,
+			    (void *)AIC79XX_AMPLITUDE_INDEX);
+		} else if (p[n] == ':') {
+			*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+		} else if (!strncmp(p, "verbose", n)) {
+			*(options[i].flag) = 1;
+		} else {
+			*(options[i].flag) = ~(*(options[i].flag));
 		}
 	}
 	return 1;
@@ -2364,6 +2108,8 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template)
 	ahd_lock(ahd, &s);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	scsi_assign_lock(host, &ahd->platform_data->spin_lock);
+#elif AHD_SCSI_HAS_HOST_LOCK != 0
+	host->lock = &ahd->platform_data->spin_lock;
 #endif
 	ahd->platform_data->host = host;
 	host->can_queue = AHD_MAX_QUEUE;
@@ -2383,9 +2129,10 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template)
 	}
 	host->unique_id = ahd->unit;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) && \
-    LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+    LINUX_VERSION_CODE  < KERNEL_VERSION(2,5,0)
 	scsi_set_pci_device(host, ahd->dev_softc);
 #endif
+	ahd_linux_setup_user_rd_strm_settings(ahd);
 	ahd_linux_initialize_scsi_bus(ahd);
 	ahd_unlock(ahd, &s);
 	ahd->platform_data->dv_pid = kernel_thread(ahd_linux_dv_thread, ahd, 0);
@@ -2405,13 +2152,28 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template)
 	 * negotiation will occur for the first command, and DV
 	 * will comence should that first command be successful.
 	 */
-	for (target = 0; target < host->max_id; target++)
+	for (target = 0; target < host->max_id; target++) {
+
+		/*
+		 * Skip our own ID.  Some Compaq/HP storage devices
+		 * have enclosure management devices that respond to
+		 * single bit selection (i.e. selecting ourselves).
+		 * It is expected that either an external application
+		 * or a modified kernel will be used to probe this
+		 * ID if it is appropriate.  To accommodate these
+		 * installations, ahc_linux_alloc_target() will allocate
+		 * for our ID if asked to do so.
+		 */
+		if (target == ahd->our_id) 
+			continue;
+
 		ahd_linux_alloc_target(ahd, 0, target);
+	}
 	ahd_intr_enable(ahd, TRUE);
 	ahd_linux_start_dv(ahd);
 	ahd_unlock(ahd, &s);
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	scsi_add_host(host, &ahd->dev_softc->dev);
 #endif
 	return (0);
@@ -2539,29 +2301,13 @@ ahd_platform_free(struct ahd_softc *ahd)
 {
 	struct ahd_linux_target *targ;
 	struct ahd_linux_device *dev;
-	u_long s;
 	int i, j;
 
 	if (ahd->platform_data != NULL) {
-		/* Kill the DV kthread */
-		if (ahd->platform_data->dv_pid != 0) {
-			ahd_lock(ahd, &s);
-			ahd->platform_data->flags |= AHD_DV_SHUTDOWN;
-			ahd_unlock(ahd, &s);
-			up(&ahd->platform_data->dv_sem);
-			do {
-#ifdef AHD_DEBUG
-				if (ahd_debug & AHD_SHOW_DV) {
-					printf("%s: Waiting for DV thread to "
-					       "exit\n", ahd_name(ahd));
-				}
-#endif
-			} while (waitpid(ahd->platform_data->dv_pid, NULL,
-					 __WCLONE) == -ERESTARTSYS);
-		}
+		ahd_linux_kill_dv_thread(ahd);
 		ahd_teardown_runq_tasklet(ahd);
 		if (ahd->platform_data->host != NULL) {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 			scsi_remove_host(ahd->platform_data->host);
 #endif
 			scsi_unregister(ahd->platform_data->host);
@@ -2604,10 +2350,12 @@ ahd_platform_free(struct ahd_softc *ahd)
 #endif
 		}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && \
-    LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+    LINUX_VERSION_CODE  < KERNEL_VERSION(2,5,0)
     		/*
 		 * In 2.4 we detach from the scsi midlayer before the PCI
-		 * layer invokes our remove callback.
+		 * layer invokes our remove callback.  No per-instance
+		 * detach is provided, so we must reach inside the PCI
+		 * subsystem's internals and detach our driver manually.
 		 */
 		if (ahd->dev_softc != NULL)
 			ahd->dev_softc->driver = NULL;
@@ -2659,7 +2407,18 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
 	if (dev == NULL)
 		return;
 	was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED);
-	now_queuing = alg != AHD_QUEUE_NONE;
+	switch (alg) {
+	default:
+	case AHD_QUEUE_NONE:
+		now_queuing = 0;
+		break; 
+	case AHD_QUEUE_BASIC:
+		now_queuing = AHD_DEV_Q_BASIC;
+		break;
+	case AHD_QUEUE_TAGGED:
+		now_queuing = AHD_DEV_Q_TAGGED;
+		break;
+	}
 	if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0
 	 && (was_queuing != now_queuing)
 	 && (dev->active != 0)) {
@@ -2795,24 +2554,12 @@ ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd)
 	ahd->platform_data->flags &= ~AHD_RUN_CMPLT_Q_TIMER;
 	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
 	TAILQ_INIT(&ahd->platform_data->completeq);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahd_unlock(ahd, &flags);
-#endif
 	if (acmd != NULL) {
 		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahd_lock(ahd, &flags);
-#endif
+		if (acmd != NULL)
 			ahd_schedule_completeq(ahd, acmd);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahd_unlock(ahd, &flags);
-#endif
-		}
 	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	ahd_unlock(ahd, &flags);
-#endif
 }
 
 static void
@@ -2851,16 +2598,21 @@ ahd_linux_dv_thread(void *data)
 		printf("In DV Thread\n");
 #endif
 
+	/*
+	 * Complete thread creation.
+	 */
+	lock_kernel();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60)
 	/*
 	 * Don't care about any signals.
 	 */
 	siginitsetinv(&current->blocked, 0);
 
-	/*
-	 * Complete thread creation.
-	 */
-	lock_kernel();
+	daemonize();
+	sprintf(current->comm, "ahd_dv_%d", ahd->unit);
+#else
 	daemonize("ahd_dv_%d", ahd->unit);
+#endif
 	unlock_kernel();
 
 	while (1) {
@@ -2874,7 +2626,7 @@ ahd_linux_dv_thread(void *data)
 		ahd_lock(ahd, &s);
 		if ((ahd->platform_data->flags & AHD_DV_SHUTDOWN) != 0) {
 			ahd_unlock(ahd, &s);
-			return (0);
+			break;
 		}
 		ahd_unlock(ahd, &s);
 
@@ -2920,10 +2672,52 @@ ahd_linux_dv_thread(void *data)
 		 */
 		ahd_release_simq(ahd);
 	}
-
+	up(&ahd->platform_data->eh_sem);
 	return (0);
 }
 
+static void
+ahd_linux_kill_dv_thread(struct ahd_softc *ahd)
+{
+	u_long s;
+
+	ahd_lock(ahd, &s);
+	if (ahd->platform_data->dv_pid != 0) {
+		ahd->platform_data->flags |= AHD_DV_SHUTDOWN;
+		ahd_unlock(ahd, &s);
+		up(&ahd->platform_data->dv_sem);
+
+		/*
+		 * Use the eh_sem as an indicator that the
+		 * dv thread is exiting.  Note that the dv
+		 * thread must still return after performing
+		 * the up on our semaphore before it has
+		 * completely exited this module.  Unfortunately,
+		 * there seems to be no easy way to wait for the
+		 * exit of a thread for which you are not the
+		 * parent (dv threads are parented by init).
+		 * Cross your fingers...
+		 */
+		down(&ahd->platform_data->eh_sem);
+
+		/*
+		 * Mark the dv thread as already dead.  This
+		 * avoids attempting to kill it a second time.
+		 * This is necessary because we must kill the
+		 * DV thread before calling ahd_free() in the
+		 * module shutdown case to avoid bogus locking
+		 * in the SCSI mid-layer, but we ahd_free() is
+		 * called without killing the DV thread in the
+		 * instance detach case, so ahd_platform_free()
+		 * calls us again to verify that the DV thread
+		 * is dead.
+		 */
+		ahd->platform_data->dv_pid = 0;
+	} else {
+		ahd_unlock(ahd, &s);
+	}
+}
+
 #define AHD_LINUX_DV_INQ_SHORT_LEN	36
 #define AHD_LINUX_DV_INQ_LEN		256
 #define AHD_LINUX_DV_TIMEOUT		(HZ / 4)
@@ -3026,6 +2820,7 @@ ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset)
 		}
 		case AHD_DV_STATE_TUR:
 		case AHD_DV_STATE_BUSY:
+			timeout = 5 * HZ;
 			ahd_linux_dv_tur(ahd, cmd, &devinfo);
 			break;
 		case AHD_DV_STATE_REBD:
@@ -3066,14 +2861,19 @@ ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset)
 		/*
 		 * In 2.5.X, it is assumed that all calls from the
 		 * "midlayer" (which we are emulating) will have the
-		 * ahd host lock held.
+		 * ahd host lock held.  For other kernels, the
+		 * io_request_lock must be held.
 		 */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#if AHD_SCSI_HAS_HOST_LOCK != 0
 		ahd_lock(ahd, &s);
+#else
+		spin_lock_irqsave(&io_request_lock, s);
 #endif
 		ahd_linux_queue(cmd, ahd_linux_dv_complete);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#if AHD_SCSI_HAS_HOST_LOCK != 0
 		ahd_unlock(ahd, &s);
+#else
+		spin_unlock_irqrestore(&io_request_lock, s);
 #endif
 		down_interruptible(&ahd->platform_data->dv_cmd_sem);
 		/*
@@ -3961,7 +3761,6 @@ ahd_linux_dv_timeout(struct scsi_cmnd *cmd)
 {
 	struct	ahd_softc *ahd;
 	struct	ahd_cmd *acmd;
-	struct	ahd_linux_device *next_dev;
 	struct	scb *scb;
 	u_long	flags;
 
@@ -4008,36 +3807,17 @@ ahd_linux_dv_timeout(struct scsi_cmnd *cmd)
 	ahd->platform_data->reset_timer.function =
 	    (ahd_linux_callback_t *)ahd_release_simq;
 	add_timer(&ahd->platform_data->reset_timer);
-	/*
-	 * In 2.5.X, the "done lock" is the ahd_lock.
-	 * Instead of dropping and re-acquiring the same
-	 * lock in the 2.5.X case, just hold our ahd_lock
-	 * the whole time.  ahd_done_lock() has been
-	 * made a no-op for 2.5.X too.
-	 */
 	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
 	TAILQ_INIT(&ahd->platform_data->completeq);
-	next_dev = ahd_linux_next_device_to_run(ahd);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahd_unlock(ahd, &flags);
-#endif
-	if (next_dev)
+	if (ahd_linux_next_device_to_run(ahd) != NULL)
 		ahd_schedule_runq(ahd);
 	if (acmd != NULL) {
 		acmd = ahd_linux_run_complete_queue(ahd, acmd);
 		if (acmd != NULL) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahd_lock(ahd, &flags);
-#endif
 			ahd_schedule_completeq(ahd, acmd);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahd_unlock(ahd, &flags);
-#endif
 		}
 	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	ahd_unlock(ahd, &flags);
-#endif
 }
 
 static void
@@ -4126,17 +3906,17 @@ ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
 
 	tags = 0;
 	if ((ahd->user_discenable & devinfo->target_mask) != 0) {
-		if (warned_user == 0
-		 && ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) {
-
-			printf("aic79xx: WARNING, insufficient "
-			       "tag_info instances for installed "
-			       "controllers. Using defaults\n");
-			printf("aic79xx: Please update the "
-			       "aic79xx_tag_info array in the "
-			       "aic79xx.c source file.\n");
+		if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) {
+
+			if (warned_user == 0) {
+				printf(KERN_WARNING
+"aic79xx: WARNING: Insufficient tag_info instances\n"
+"aic79xx: for installed controllers.  Using defaults\n"
+"aic79xx: Please update the aic79xx_tag_info array in\n"
+"aic79xx: the aic79xx_osm.c source file.\n");
+				warned_user++;
+			}
 			tags = AHD_MAX_QUEUE;
-			warned_user++;
 		} else {
 			adapter_tag_info_t *tag_info;
 
@@ -4155,17 +3935,17 @@ ahd_linux_user_dv_setting(struct ahd_softc *ahd)
 	static int warned_user;
 	int dv;
 
-	if (warned_user == 0
-	 && ahd->unit >= NUM_ELEMENTS(aic79xx_dv_settings)) {
+	if (ahd->unit >= NUM_ELEMENTS(aic79xx_dv_settings)) {
 
-		printf("aic79xx: WARNING, insufficient "
-		       "dv settings instances for installed "
-		       "controllers. Using defaults\n");
-		printf("aic79xx: Please update the "
-		       "aic79xx_dv_settings array in the "
-		       "aic79xx.c source file.\n");
+		if (warned_user == 0) {
+			printf(KERN_WARNING
+"aic79xx: WARNING: Insufficient dv settings instances\n"
+"aic79xx: for installed controllers. Using defaults\n"
+"aic79xx: Please update the aic79xx_dv_settings array in"
+"aic79xx: the aic79xx_osm.c source file.\n");
+			warned_user++;
+		}
 		dv = -1;
-		warned_user++;
 	} else {
 
 		dv = aic79xx_dv_settings[ahd->unit];
@@ -4182,6 +3962,48 @@ ahd_linux_user_dv_setting(struct ahd_softc *ahd)
 	return (dv);
 }
 
+static void
+ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd)
+{
+	static	int warned_user;
+	u_int	rd_strm_mask;
+	u_int	target_id;
+
+	/*
+	 * If we have specific read streaming info for this controller,
+	 * apply it.  Otherwise use the defaults.
+	 */
+	 if (ahd->unit >= NUM_ELEMENTS(aic79xx_rd_strm_info)) {
+
+		if (warned_user == 0) {
+
+			printf(KERN_WARNING
+"aic79xx: WARNING: Insufficient rd_strm instances\n"
+"aic79xx: for installed controllers. Using defaults\n"
+"aic79xx: Please update the aic79xx_rd_strm_info array\n"
+"aic79xx: in the aic79xx_osm.c source file.\n");
+			warned_user++;
+		}
+		rd_strm_mask = AIC79XX_CONFIGED_RD_STRM;
+	} else {
+
+		rd_strm_mask = aic79xx_rd_strm_info[ahd->unit];
+	}
+	for (target_id = 0; target_id < 16; target_id++) {
+		struct ahd_devinfo devinfo;
+		struct ahd_initiator_tinfo *tinfo;
+		struct ahd_tmode_tstate *tstate;
+
+		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+					    target_id, &tstate);
+		ahd_compile_devinfo(&devinfo, ahd->our_id, target_id,
+				    CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR);
+		tinfo->user.ppr_options &= ~MSG_EXT_PPR_RD_STRM;
+		if ((rd_strm_mask & devinfo.target_mask) != 0)
+			tinfo->user.ppr_options |= MSG_EXT_PPR_RD_STRM;
+	}
+}
+
 /*
  * Determines the queue depth for a given device.
  */
@@ -4385,41 +4207,21 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
 	struct	ahd_softc *ahd;
 	struct	ahd_cmd *acmd;
 	u_long	flags;
-	struct	ahd_linux_device *next_dev;
 
 	ahd = (struct ahd_softc *) dev_id;
 	ahd_lock(ahd, &flags); 
 	ahd_intr(ahd);
 	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
 	TAILQ_INIT(&ahd->platform_data->completeq);
-	next_dev = ahd_linux_next_device_to_run(ahd);
-	/*
-	 * In 2.5.X, the "done lock" is the ahd_lock.
-	 * Instead of dropping and re-acquiring the same
-	 * lock in the 2.5.X case, just hold our ahd_lock
-	 * the whole time.  ahd_done_lock() has been
-	 * made a no-op for 2.5.X too.
-	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahd_unlock(ahd, &flags);
-#endif
-	if (next_dev)
+	if (ahd_linux_next_device_to_run(ahd) != NULL)
 		ahd_schedule_runq(ahd);
 	if (acmd != NULL) {
 		acmd = ahd_linux_run_complete_queue(ahd, acmd);
 		if (acmd != NULL) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahd_lock(ahd, &flags);
-#endif
 			ahd_schedule_completeq(ahd, acmd);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahd_unlock(ahd, &flags);
-#endif
 		}
 	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	ahd_unlock(ahd, &flags);
-#endif
 }
 
 void
@@ -4437,17 +4239,6 @@ static struct ahd_linux_target*
 ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target)
 {
 	struct ahd_linux_target *targ;
-	u_int target_offset;
-
-	target_offset = target;
-	/*
-	 * Never allow allocation of a target object for
-	 * our own SCSIID.
-	 */
-	if (target == ahd->our_id) {
-		ahd->platform_data->targets[target_offset] = NULL;
-		return (NULL);
-	}
 
 	targ = malloc(sizeof(*targ), M_DEVBUF, M_NOWAIT);
 	if (targ == NULL)
@@ -4457,7 +4248,7 @@ ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target)
 	targ->target = target;
 	targ->ahd = ahd;
 	targ->flags = AHD_DV_REQUIRED;
-	ahd->platform_data->targets[target_offset] = targ;
+	ahd->platform_data->targets[target] = targ;
 	return (targ);
 }
 
@@ -4699,6 +4490,14 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
 #endif
 			ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);
 		} else if (amount_xferred < scb->io_ctx->underflow) {
+			u_int i;
+
+			ahd_print_path(ahd, scb);
+			printf("CDB:");
+			for (i = 0; i < scb->io_ctx->cmd_len; i++)
+				printf(" 0x%x", scb->io_ctx->cmnd[i]);
+			printf("\n");
+			ahd_print_path(ahd, scb);
 			printf("Saw underflow (%ld of %ld bytes). "
 			       "Treated as error\n",
 				ahd_get_residual(scb),
@@ -4755,8 +4554,8 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
 		if (ahd_get_transaction_status(scb) == CAM_BDR_SENT
 		 || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED)
 			ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
-		if ((ahd->platform_data->flags & AHD_UP_EH_SEMAPHORE) != 0) {
-			ahd->platform_data->flags &= ~AHD_UP_EH_SEMAPHORE;
+		if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
+			scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
 			up(&ahd->platform_data->eh_sem);
 		}
 	}
@@ -4869,7 +4668,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
 			 */
 			dev->openings = 0;
 #ifdef AHD_DEBUG
-			if (ahd_debug & AHD_SHOW_QFULL) {
+			if ((ahd_debug & AHD_SHOW_QFULL) != 0) {
 				ahd_print_path(ahd, scb);
 				printf("Dropping tag count to %d\n",
 				       dev->active);
@@ -4899,7 +4698,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
 			}
 			ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
 			ahd_set_scsi_status(scb, SCSI_STATUS_OK);
-			ahd_set_tags(ahd, &devinfo,
+			ahd_platform_set_tags(ahd, &devinfo,
 				     (dev->flags & AHD_DEV_Q_BASIC)
 				   ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
 			break;
@@ -4909,7 +4708,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
 		 * as if the target returned BUSY SCSI status.
 		 */
 		dev->openings = 1;
-		ahd_set_tags(ahd, &devinfo,
+		ahd_platform_set_tags(ahd, &devinfo,
 			     (dev->flags & AHD_DEV_Q_BASIC)
 			   ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
 		ahd_set_scsi_status(scb, SCSI_STATUS_BUSY);
@@ -5108,7 +4907,6 @@ ahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
 	u_int	ppr_options;
 	u_int	trans_version;
 	u_int	prot_version;
-	static	int warned_user;
 
 	/*
 	 * Determine if this lun actually exists.  If so,
@@ -5147,26 +4945,6 @@ ahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
 	trans_version = user->transport_version;
 	prot_version = MIN(user->protocol_version, SID_ANSI_REV(sid));
 
-	/*
-	 * If we have read streaming info for this controller,
-	 * apply it to this target.
-	 */
-	if (warned_user == 0
-	 && ahd->unit >= NUM_ELEMENTS(aic79xx_rd_strm_info)) {
-
-		printf("aic79xx: WARNING, insufficient rd_strm instances "
-		       "for installed controllers. Using defaults\n");
-		printf("aic79xx: Please update the aic79xx_rd_strm_info "
-		       "array in the aic79xx_osm.c source file.\n");
-		warned_user++;
-	} else {
-		uint16_t rd_strm_mask;
-
-		rd_strm_mask = aic79xx_rd_strm_info[ahd->unit];
-		if ((rd_strm_mask & devinfo->target_mask) == 0)
-			ppr_options &= ~MSG_EXT_PPR_RD_STRM;
-	}
-	
 	/*
 	 * Only attempt SPI3/4 once we've verified that
 	 * the device claims to support SPI3/4 features.
@@ -5242,6 +5020,7 @@ ahd_release_simq(struct ahd_softc *ahd)
 		ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_RELEASE;
 		up(&ahd->platform_data->dv_sem);
 	}
+	ahd_schedule_runq(ahd);
 	ahd_unlock(ahd, &s);
 	/*
 	 * There is still a race here.  The mid-layer
@@ -5251,20 +5030,20 @@ ahd_release_simq(struct ahd_softc *ahd)
 	 */
 	if (unblock_reqs)
 		scsi_unblock_requests(ahd->platform_data->host);
-
-	ahd_schedule_runq(ahd);
 }
 
 static void
 ahd_linux_sem_timeout(u_long arg)
 {
+	struct	scb *scb;
 	struct	ahd_softc *ahd;
 	u_long	s;
 
-	ahd = (struct ahd_softc *)arg;
+	scb = (struct scb *)arg;
+	ahd = scb->ahd_softc;
 	ahd_lock(ahd, &s);
-	if ((ahd->platform_data->flags & AHD_UP_EH_SEMAPHORE) != 0) {
-		ahd->platform_data->flags &= ~AHD_UP_EH_SEMAPHORE;
+	if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
+		scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
 		up(&ahd->platform_data->eh_sem);
 	}
 	ahd_unlock(ahd, &s);
@@ -5320,13 +5099,14 @@ ahd_platform_dump_card_state(struct ahd_softc *ahd)
 	}
 }
 
-static int __init ahd_linux_init(void)
+static int __init
+ahd_linux_init(void)
 {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
        return (ahd_linux_detect(&aic79xx_driver_template) ? 0 : -ENODEV);
 #else
 	scsi_register_module(MODULE_SCSI_HA, &aic79xx_driver_template);
-	if (!driver_template.present) {
+	if (aic79xx_driver_template.present == 0) {
 		scsi_unregister_module(MODULE_SCSI_HA,
 				       &aic79xx_driver_template);
 		return (-ENODEV);
@@ -5336,12 +5116,35 @@ static int __init ahd_linux_init(void)
 #endif
 }
 
-static void __exit ahd_linux_exit(void)
+static void __exit
+ahd_linux_exit(void)
 {
+	struct ahd_softc *ahd;
+	u_long l;
+
+	/*
+	 * Shutdown DV threads before going into the SCSI mid-layer.
+	 * This avoids situations where the mid-layer locks the entire
+	 * kernel so that waiting for our DV threads to exit leads
+	 * to deadlock.
+	 */
+	ahd_list_lock(&l);
+	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
+
+		ahd_linux_kill_dv_thread(ahd);
+	}
+	ahd_list_unlock(&l);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	/*
+	 * In 2.4 we have to unregister from the PCI core _after_
+	 * unregistering from the scsi midlayer to avoid dangling
+	 * references.
+	 */
 	scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template);
 #endif
 	ahd_linux_pci_exit();
+
+	unregister_reboot_notifier(&ahd_linux_notifier);
 }
 
 module_init(ahd_linux_init);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index e1267e9bb2973bfe49357bd5c559a74f59af56ec..e2a0eeab5f5c741932fa44025438a805ea955d2e 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#108 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#121 $
  *
  */
 #ifndef _AIC79XX_LINUX_H_
@@ -92,6 +92,7 @@
  * Compile in debugging code, but do not enable any printfs.
  */
 #define AHD_DEBUG 1
+#define AHD_DEBUG_OPTS 0
 #endif
 /* No debugging code. */
 #endif
@@ -286,7 +287,13 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec)
 #include <linux/smp.h>
 #endif
 
-#define AIC79XX_DRIVER_VERSION "1.3.0"
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK))
+#define AHD_SCSI_HAS_HOST_LOCK 1
+#else
+#define AHD_SCSI_HAS_HOST_LOCK 0
+#endif
+
+#define AIC79XX_DRIVER_VERSION "1.3.5"
 
 /**************************** Front End Queues ********************************/
 /*
@@ -487,7 +494,7 @@ struct ahd_linux_target {
  * Per-SCB OSM storage.
  */
 typedef enum {
-	AHD_UP_EH_SEMAPHORE = 0x1
+	AHD_SCB_UP_EH_SEM = 0x1
 } ahd_linux_scb_flags;
 
 struct scb_platform_data {
@@ -733,7 +740,6 @@ ahd_lockinit(struct ahd_softc *ahd)
 static __inline void
 ahd_lock(struct ahd_softc *ahd, unsigned long *flags)
 {
-	*flags = 0;
 	spin_lock_irqsave(&ahd->platform_data->spin_lock, *flags);
 }
 
@@ -747,23 +753,24 @@ static __inline void
 ahd_midlayer_entrypoint_lock(struct ahd_softc *ahd, unsigned long *flags)
 {
 	/*
-	 * In 2.5.X, the midlayer takes our lock just before
-	 * calling us, so avoid locking again.
+	 * In 2.5.X and some 2.4.X versions, the midlayer takes our
+	 * lock just before calling us, so we avoid locking again.
+	 * For other kernel versions, the io_request_lock is taken
+	 * just before our entry point is called.  In this case, we
+	 * trade the io_request_lock for our per-softc lock.
 	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahd_lock(ahd, flags);
+#if AHD_SCSI_HAS_HOST_LOCK == 0
+	spin_unlock(&io_request_lock);
+	spin_lock(&ahd->platform_data->spin_lock);
 #endif
 }
 
 static __inline void
 ahd_midlayer_entrypoint_unlock(struct ahd_softc *ahd, unsigned long *flags)
 {
-	/*
-	 * In 2.5.X, the midlayer takes our lock just before
-	 * calling us and unlocks when we return, so let it do the unlock.
-	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahd_unlock(ahd, flags);
+#if AHD_SCSI_HAS_HOST_LOCK == 0
+	spin_unlock(&ahd->platform_data->spin_lock);
+	spin_lock(&io_request_lock);
 #endif
 }
 
@@ -780,17 +787,16 @@ ahd_done_lockinit(struct ahd_softc *ahd)
 static __inline void
 ahd_done_lock(struct ahd_softc *ahd, unsigned long *flags)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	*flags = 0;
-	spin_lock_irqsave(&io_request_lock, *flags);
+#if AHD_SCSI_HAS_HOST_LOCK == 0
+	spin_lock(&io_request_lock);
 #endif
 }
 
 static __inline void
 ahd_done_unlock(struct ahd_softc *ahd, unsigned long *flags)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_unlock_irqrestore(&io_request_lock, *flags);
+#if AHD_SCSI_HAS_HOST_LOCK == 0
+	spin_unlock(&io_request_lock);
 #endif
 }
 
@@ -803,7 +809,6 @@ ahd_list_lockinit()
 static __inline void
 ahd_list_lock(unsigned long *flags)
 {
-	*flags = 0;
 	spin_lock_irqsave(&ahd_list_spinlock, *flags);
 }
 
@@ -822,7 +827,6 @@ ahd_lockinit(struct ahd_softc *ahd)
 static __inline void
 ahd_lock(struct ahd_softc *ahd, unsigned long *flags)
 {
-	*flags = 0;
 	save_flags(*flags);
 	cli();
 }
@@ -860,7 +864,6 @@ ahd_list_lockinit()
 static __inline void
 ahd_list_lock(unsigned long *flags)
 {
-	*flags = 0;
 	save_flags(*flags);
 	cli();
 }
@@ -947,7 +950,7 @@ void ahd_power_state_change(struct ahd_softc *ahd,
  */
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
 #if defined(__sparc_v9__) || defined(__powerpc__)
-#error "PPC and Sparc platforms are only support under 2.1.92 and above"
+#error "PPC and Sparc platforms are only supported under 2.1.92 and above"
 #endif
 #include <linux/bios32.h>
 #endif
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index eb09fd3b13a571eceea38b616605245203018ed5..8ec854777727d5ca521ae4da28daa535aa137f15 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#20 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#21 $
  */
 
 #include "aic79xx_osm.h"
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index f3cfa41557dc4ccb387e16c1cc062fdc95402678..0fd6e0afa61e479313e4102743884cdb000897db 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -38,7 +38,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#61 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#70 $
  *
  * $FreeBSD$
  */
@@ -80,6 +80,7 @@ ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
 #define ID_AIC7902_B			0x801D9005FFFF9005ull
 #define ID_AIC7902_B_IROC		0x809D9005FFFF9005ull
 #define ID_AHA_39320			0x8010900500409005ull
+#define ID_AHA_39320A			0x8016900500409005ull
 #define ID_AHA_39320D			0x8011900500419005ull
 #define ID_AHA_39320D_B			0x801C900500419005ull
 #define ID_AHA_39320D_HP		0x8011900500AC0E11ull
@@ -137,6 +138,12 @@ struct ahd_pci_identity ahd_pci_ident_table [] =
 		"Adaptec 39320 Ultra320 SCSI adapter",
 		ahd_aic7902_setup
 	},
+	{
+		ID_AHA_39320A,
+		ID_ALL_MASK,
+		"Adaptec 39320A Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
 	{
 		ID_AHA_39320D,
 		ID_ALL_MASK,
@@ -378,12 +385,10 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
 int
 ahd_pci_test_register_access(struct ahd_softc *ahd)
 {
-	ahd_mode_state	saved_modes;
 	uint32_t	cmd;
 	int		error;
 	uint8_t		hcntrl;
 
-	saved_modes = ahd_save_modes(ahd);
 	error = EIO;
 
 	/*
@@ -449,7 +454,6 @@ ahd_pci_test_register_access(struct ahd_softc *ahd)
 		ahd_outb(ahd, CLRINT, CLRPCIINT);
 	}
 
-	ahd_restore_modes(ahd, saved_modes);
 	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS);
 	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2);
 	return (error);
@@ -462,6 +466,7 @@ ahd_pci_test_register_access(struct ahd_softc *ahd)
 static int
 ahd_check_extport(struct ahd_softc *ahd)
 {
+	struct	vpd_config vpd;
 	struct	seeprom_config *sc;
 	u_int	adapter_control;
 	int	have_seeprom;
@@ -472,6 +477,27 @@ ahd_check_extport(struct ahd_softc *ahd)
 	if (have_seeprom) {
 		u_int start_addr;
 
+		/*
+		 * Fetch VPD for this function and parse it.
+		 */
+		if (bootverbose) 
+			printf("%s: Reading VPD from SEEPROM...",
+			       ahd_name(ahd));
+
+		/* Address is always in units of 16bit words */
+		start_addr = ((2 * sizeof(*sc))
+			    + (sizeof(vpd) * (ahd->channel - 'A'))) / 2;
+
+		error = ahd_read_seeprom(ahd, (uint16_t *)&vpd,
+					 start_addr, sizeof(vpd)/2,
+					 /*bytestream*/TRUE);
+		if (error == 0)
+			error = ahd_parse_vpddata(ahd, &vpd);
+		if (bootverbose) 
+			printf("%s: VPD parsing %s\n",
+			       ahd_name(ahd),
+			       error == 0 ? "successful" : "failed");
+
 		if (bootverbose) 
 			printf("%s: Reading SEEPROM...", ahd_name(ahd));
 
@@ -479,7 +505,8 @@ ahd_check_extport(struct ahd_softc *ahd)
 		start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A');
 
 		error = ahd_read_seeprom(ahd, (uint16_t *)sc,
-					 start_addr, sizeof(*sc)/2);
+					 start_addr, sizeof(*sc)/2,
+					 /*bytestream*/FALSE);
 
 		if (error != 0) {
 			printf("Unable to read SEEPROM\n");
@@ -698,7 +725,7 @@ static const char *split_status_strings[] =
 	"%s: Split completion data bucket in %s\n",
 	"%s: Split completion address error in %s\n",
 	"%s: Split completion byte count error in %s\n",
-	"%s: Signaled Target-abort to early terminate a split in %s\n",
+	"%s: Signaled Target-abort to early terminate a split in %s\n"
 };
 
 static const char *pci_status_strings[] =
@@ -799,7 +826,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
 		/* Clear latched errors.  So our interrupt deasserts. */
 		ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]);
 		ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]);
-		if (i != 0)
+		if (i > 1)
 			continue;
 		sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0);
 		sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1);
@@ -821,7 +848,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
 				       split_status_source[i]);
 			}
 
-			if (i != 0)
+			if (i > 1)
 				continue;
 
 			if ((sg_split_status[i] & (0x1 << bit)) != 0) {
@@ -879,11 +906,12 @@ ahd_aic7902_setup(struct ahd_softc *ahd)
 			  |  AHD_NLQICRC_DELAYED_BUG|AHD_SCSIRST_BUG
 			  |  AHD_LQO_ATNO_BUG|AHD_AUTOFLUSH_BUG
 			  |  AHD_CLRLQO_AUTOCLR_BUG|AHD_PCIX_MMAPIO_BUG
-			  |  AHD_PCIX_CHIPRST_BUG|AHD_PKTIZED_STATUS_BUG
-			  |  AHD_PKT_LUN_BUG|AHD_MDFF_WSCBPTR_BUG
-			  |  AHD_REG_SLOW_SETTLE_BUG|AHD_SET_MODE_BUG
-			  |  AHD_BUSFREEREV_BUG|AHD_NONPACKFIFO_BUG
-			  |  AHD_PACED_NEGTABLE_BUG;
+			  |  AHD_PCIX_CHIPRST_BUG|AHD_PCIX_SCBRAM_RD_BUG
+			  |  AHD_PKTIZED_STATUS_BUG|AHD_PKT_LUN_BUG
+			  |  AHD_MDFF_WSCBPTR_BUG|AHD_REG_SLOW_SETTLE_BUG
+			  |  AHD_SET_MODE_BUG|AHD_BUSFREEREV_BUG
+			  |  AHD_NONPACKFIFO_BUG|AHD_PACED_NEGTABLE_BUG
+			  |  AHD_FAINT_LED_BUG;
 
 		/*
 		 * IO Cell paramter setup.
@@ -898,7 +926,7 @@ ahd_aic7902_setup(struct ahd_softc *ahd)
 		ahd->features |= AHD_RTI|AHD_NEW_IOCELL_OPTS
 			      |  AHD_NEW_DFCNTRL_OPTS;
 		ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_ABORT_LQI_BUG
-			  |  AHD_INTCOLLISION_BUG;
+			  |  AHD_INTCOLLISION_BUG|AHD_EARLY_REQ_BUG;
 
 		/*
 		 * IO Cell paramter setup.
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index 85d6ba27b1470bb7e1c041a94a0b95f6728007d8..0c391b793a3829102ca358c28b31fb6166d9f3b6 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -37,7 +37,7 @@
  * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
  * sym driver.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#11 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#14 $
  */
 #include "aic79xx_osm.h"
 #include "aic79xx_inline.h"
@@ -124,8 +124,12 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
 
 		printed_options = 0;
 		copy_info(info, " (%d.%03dMHz", freq / 1000, freq % 1000);
+		if ((tinfo->ppr_options & MSG_EXT_PPR_RD_STRM) != 0) {
+			copy_info(info, " RDSTRM");
+			printed_options++;
+		}
 		if ((tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
-			copy_info(info, " DT");
+			copy_info(info, "%s", printed_options ? "|DT" : " DT");
 			printed_options++;
 		}
 		if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
@@ -258,7 +262,8 @@ ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length)
 		ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr,
 				  sizeof(struct seeprom_config)/2);
 		ahd_read_seeprom(ahd, (uint16_t *)ahd->seep_config,
-				 start_addr, sizeof(struct seeprom_config)/2);
+				 start_addr, sizeof(struct seeprom_config)/2,
+				 /*ByteStream*/FALSE);
 		ahd_release_seeprom(ahd);
 		written = length;
 	}
@@ -311,6 +316,7 @@ ahd_linux_proc_info(char *buffer, char **start, off_t offset,
 
 	copy_info(&info, "Adaptec AIC79xx driver version: %s\n",
 		  AIC79XX_DRIVER_VERSION);
+	copy_info(&info, "%s\n", ahd->description);
 	ahd_controller_info(ahd, ahd_info);
 	copy_info(&info, "%s\n\n", ahd_info);
 
diff --git a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
index 49b45105a4621ec5067c4d880f76eace8091470f..dfac5aa3eb9070a3b01c1ea31a7ef5bb8686bbee 100644
--- a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
+++ b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $
  */
 typedef int (ahd_reg_print_t)(u_int, u_int *, u_int);
 typedef struct ahd_reg_parse_entry {
@@ -3638,13 +3638,14 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 #define	SCB_RESIDUAL_DATACNT		0x180
 #define	SCB_CDB_STORE   		0x180
+#define	SCB_HOST_CDB_PTR		0x180
 
 #define	SCB_RESIDUAL_SGPTR		0x184
-#define	SCB_CDB_PTR     		0x184
 #define		SG_ADDR_MASK    	0xf8
 #define		SG_OVERRUN_RESID	0x02
 
 #define	SCB_SCSI_STATUS 		0x188
+#define	SCB_HOST_CDB_LEN		0x188
 
 #define	SCB_TARGET_PHASES		0x189
 
@@ -3719,7 +3720,7 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define	AHD_AMPLITUDE_SHIFT	0x00
 #define	AHD_AMPLITUDE_MASK	0x07
 #define	AHD_ANNEXCOL_AMPLITUDE	0x06
-#define	AHD_SLEWRATE_DEF_REVA	0x01
+#define	AHD_SLEWRATE_DEF_REVA	0x08
 #define	AHD_SLEWRATE_SHIFT	0x03
 #define	AHD_SLEWRATE_MASK	0x78
 #define	AHD_PRECOMP_CUTBACK_29	0x06
@@ -3774,5 +3775,5 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 
 /* Exported Labels */
-#define	LABEL_seq_isr 	0x263
-#define	LABEL_timer_isr	0x25f
+#define	LABEL_seq_isr 	0x26d
+#define	LABEL_timer_isr	0x269
diff --git a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
index e9c944a93bc60f5a92faf2abe3681f263bc4b6d9..79321cb0960cdf998ba61614e9b162b44d6255c0 100644
--- a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
+++ b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $
  */
 
 #include "aic79xx_osm.h"
diff --git a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
index 56c21cecb17a5483f9e0c1373eb4004a1e03d2c0..b65c8f7fdc44d24c9444c40b6b38b0ce01d205c1 100644
--- a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
+++ b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
@@ -2,97 +2,102 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $
  */
 static uint8_t seqprog[] = {
 	0xff, 0x02, 0x06, 0x78,
-	0x00, 0xea, 0x46, 0x59,
+	0x00, 0xea, 0x50, 0x59,
 	0x01, 0xea, 0x04, 0x30,
 	0xff, 0x04, 0x0c, 0x78,
-	0x19, 0xea, 0x46, 0x59,
+	0x19, 0xea, 0x50, 0x59,
 	0x19, 0xea, 0x04, 0x00,
-	0x33, 0xea, 0x3a, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x60, 0x3a, 0x1a, 0x68,
 	0x04, 0x47, 0x1b, 0x68,
 	0xff, 0x21, 0x1b, 0x70,
-	0x40, 0x4b, 0x88, 0x69,
-	0x00, 0xe2, 0x4a, 0x59,
-	0x40, 0x4b, 0x88, 0x69,
-	0x20, 0x4b, 0x78, 0x69,
+	0x40, 0x4b, 0x92, 0x69,
+	0x00, 0xe2, 0x54, 0x59,
+	0x40, 0x4b, 0x92, 0x69,
+	0x20, 0x4b, 0x82, 0x69,
 	0xfc, 0x42, 0x24, 0x78,
 	0x10, 0x40, 0x24, 0x78,
-	0x00, 0xe2, 0xa4, 0x5d,
+	0x00, 0xe2, 0xe0, 0x5d,
 	0x20, 0x4d, 0x28, 0x78,
-	0x00, 0xe2, 0xa4, 0x5d,
-	0x00, 0xe2, 0x34, 0x58,
-	0x00, 0xe2, 0x66, 0x58,
-	0x00, 0xe2, 0x76, 0x58,
+	0x00, 0xe2, 0xe0, 0x5d,
+	0x30, 0x3f, 0xc0, 0x09,
+	0x30, 0xe0, 0x30, 0x60,
+	0x7f, 0x4a, 0x94, 0x08,
+	0x00, 0xe2, 0x32, 0x40,
+	0xc0, 0x4a, 0x94, 0x00,
+	0x00, 0xe2, 0x3e, 0x58,
+	0x00, 0xe2, 0x70, 0x58,
+	0x00, 0xe2, 0x80, 0x58,
 	0x00, 0xe2, 0x06, 0x40,
-	0x33, 0xea, 0x3a, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x01, 0x52, 0x66, 0x7d,
+	0x01, 0x52, 0x96, 0x7d,
 	0x02, 0x58, 0x50, 0x31,
 	0xff, 0xea, 0x10, 0x0b,
-	0xff, 0x93, 0x45, 0x78,
-	0x50, 0x4b, 0x40, 0x68,
+	0xff, 0x93, 0x4f, 0x78,
+	0x50, 0x4b, 0x4a, 0x68,
 	0xbf, 0x3a, 0x74, 0x08,
-	0x14, 0xea, 0x46, 0x59,
+	0x14, 0xea, 0x50, 0x59,
 	0x14, 0xea, 0x04, 0x00,
 	0x08, 0xa8, 0x51, 0x03,
-	0x01, 0xa4, 0x4d, 0x78,
-	0x00, 0xe2, 0x44, 0x5b,
-	0x00, 0xe2, 0x34, 0x40,
+	0x01, 0xa4, 0x57, 0x78,
+	0x00, 0xe2, 0x4c, 0x5b,
+	0x00, 0xe2, 0x3e, 0x40,
 	0xff, 0xea, 0xd4, 0x19,
 	0x02, 0xa8, 0x84, 0x32,
-	0x00, 0xea, 0x3a, 0x59,
+	0x00, 0xea, 0x44, 0x59,
 	0x01, 0xea, 0x00, 0x30,
-	0x00, 0xe2, 0x98, 0x5d,
-	0x00, 0xe2, 0x66, 0x4d,
-	0x11, 0xea, 0x3a, 0x59,
+	0x00, 0xe2, 0xcc, 0x5d,
+	0x00, 0xe2, 0x96, 0x4d,
+	0x11, 0xea, 0x44, 0x59,
 	0x11, 0xea, 0x00, 0x00,
-	0x00, 0xe2, 0x98, 0x5d,
-	0x00, 0xe2, 0x66, 0x4d,
-	0x33, 0xea, 0x3a, 0x59,
+	0x00, 0xe2, 0xcc, 0x5d,
+	0x00, 0xe2, 0x96, 0x4d,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x00, 0xe2, 0x3a, 0x43,
-	0x00, 0xea, 0x3a, 0x59,
+	0x00, 0xe2, 0x44, 0x43,
+	0x00, 0xea, 0x44, 0x59,
 	0x01, 0xea, 0x00, 0x30,
-	0x80, 0xf9, 0x6e, 0x68,
-	0x00, 0xe2, 0x38, 0x59,
-	0x11, 0xea, 0x3a, 0x59,
+	0x80, 0xf9, 0x78, 0x68,
+	0x00, 0xe2, 0x42, 0x59,
+	0x11, 0xea, 0x44, 0x59,
 	0x11, 0xea, 0x00, 0x00,
-	0x80, 0xf9, 0x38, 0x79,
+	0x80, 0xf9, 0x42, 0x79,
 	0xff, 0xea, 0xd4, 0x0d,
-	0x22, 0xea, 0x3a, 0x59,
+	0x22, 0xea, 0x44, 0x59,
 	0x22, 0xea, 0x00, 0x00,
-	0x10, 0x16, 0x80, 0x78,
+	0x10, 0x16, 0x8a, 0x78,
 	0x01, 0x0b, 0xa2, 0x32,
 	0x10, 0x16, 0x2c, 0x00,
-	0x18, 0xad, 0xee, 0x78,
-	0x04, 0xad, 0xbc, 0x68,
-	0x80, 0xad, 0x66, 0x7d,
-	0x10, 0xad, 0x8a, 0x78,
+	0x18, 0xad, 0xf8, 0x78,
+	0x04, 0xad, 0xc6, 0x68,
+	0x80, 0xad, 0x96, 0x7d,
+	0x10, 0xad, 0x94, 0x78,
 	0xe7, 0xad, 0x5a, 0x0d,
 	0xe7, 0xad, 0x5a, 0x09,
-	0x00, 0xe2, 0x98, 0x58,
+	0x00, 0xe2, 0xa2, 0x58,
 	0xff, 0xea, 0x56, 0x02,
 	0x04, 0x7c, 0x78, 0x32,
-	0x20, 0x16, 0x66, 0x7d,
+	0x20, 0x16, 0x96, 0x7d,
 	0x04, 0x38, 0x79, 0x32,
 	0x80, 0x37, 0x6f, 0x16,
-	0xff, 0x2d, 0xa7, 0x60,
-	0xff, 0x29, 0xa7, 0x60,
-	0x40, 0x51, 0xb7, 0x78,
-	0xff, 0x4f, 0xa7, 0x68,
+	0xff, 0x2d, 0xb1, 0x60,
+	0xff, 0x29, 0xb1, 0x60,
+	0x40, 0x51, 0xc1, 0x78,
+	0xff, 0x4f, 0xb1, 0x68,
 	0xff, 0x4d, 0xc1, 0x19,
 	0x00, 0x4e, 0xd5, 0x19,
-	0x00, 0xe2, 0xb6, 0x50,
+	0x00, 0xe2, 0xc0, 0x50,
 	0x01, 0x4c, 0xc1, 0x31,
 	0x00, 0x50, 0xd5, 0x19,
-	0x00, 0xe2, 0xb6, 0x48,
-	0x80, 0x18, 0x66, 0x7d,
+	0x00, 0xe2, 0xc0, 0x48,
+	0x80, 0x18, 0x96, 0x7d,
 	0x02, 0x4a, 0x1d, 0x30,
 	0x10, 0xea, 0x18, 0x00,
 	0x60, 0x18, 0x30, 0x00,
@@ -100,7 +105,7 @@ static uint8_t seqprog[] = {
 	0x02, 0xea, 0x02, 0x00,
 	0xff, 0xea, 0xa0, 0x0a,
 	0x80, 0x18, 0x30, 0x04,
-	0x40, 0xad, 0x66, 0x7d,
+	0x40, 0xad, 0x96, 0x7d,
 	0xe7, 0xad, 0x5a, 0x09,
 	0x02, 0xa8, 0x40, 0x31,
 	0xff, 0xea, 0xc0, 0x09,
@@ -110,25 +115,25 @@ static uint8_t seqprog[] = {
 	0xff, 0xea, 0x2a, 0x03,
 	0xff, 0xea, 0x2e, 0x03,
 	0x01, 0x10, 0xd4, 0x31,
-	0x10, 0xa8, 0xe3, 0x68,
+	0x10, 0xa8, 0xed, 0x68,
 	0x3d, 0xa9, 0xc5, 0x29,
 	0xfe, 0xe2, 0xc4, 0x09,
 	0x01, 0xea, 0xc6, 0x01,
 	0x02, 0xe2, 0xc8, 0x31,
 	0x02, 0xec, 0x50, 0x31,
 	0x02, 0xa0, 0xda, 0x31,
-	0xff, 0xa9, 0xe2, 0x70,
+	0xff, 0xa9, 0xec, 0x70,
 	0x02, 0xa0, 0x28, 0x37,
-	0xff, 0x21, 0xeb, 0x70,
+	0xff, 0x21, 0xf5, 0x70,
 	0x02, 0x22, 0x51, 0x31,
 	0x02, 0xa0, 0x2c, 0x33,
 	0x02, 0xa0, 0x44, 0x36,
 	0x02, 0xa0, 0x40, 0x32,
 	0x02, 0xa0, 0x44, 0x36,
-	0x04, 0x47, 0xf3, 0x68,
-	0x40, 0x16, 0x1e, 0x69,
-	0xff, 0x2d, 0x23, 0x61,
-	0xff, 0x29, 0x67, 0x75,
+	0x04, 0x47, 0xfd, 0x68,
+	0x40, 0x16, 0x28, 0x69,
+	0xff, 0x2d, 0x2d, 0x61,
+	0xff, 0x29, 0x97, 0x75,
 	0x01, 0x37, 0xc1, 0x31,
 	0x02, 0x28, 0x55, 0x32,
 	0x01, 0xea, 0x5a, 0x01,
@@ -140,20 +145,20 @@ static uint8_t seqprog[] = {
 	0x01, 0x50, 0xa1, 0x1a,
 	0xff, 0x4e, 0x9d, 0x1a,
 	0xff, 0x4f, 0x9f, 0x22,
-	0xff, 0x8d, 0x17, 0x71,
-	0x80, 0xac, 0x16, 0x71,
-	0x20, 0x16, 0x16, 0x69,
+	0xff, 0x8d, 0x21, 0x71,
+	0x80, 0xac, 0x20, 0x71,
+	0x20, 0x16, 0x20, 0x69,
 	0x02, 0x8c, 0x51, 0x31,
-	0x00, 0xe2, 0x00, 0x41,
+	0x00, 0xe2, 0x0a, 0x41,
 	0x01, 0xac, 0x08, 0x31,
 	0x09, 0xea, 0x5a, 0x01,
 	0x02, 0x8c, 0x51, 0x32,
 	0xff, 0xea, 0x1a, 0x07,
 	0x04, 0x24, 0xf9, 0x30,
-	0x1d, 0xea, 0x2e, 0x41,
+	0x1d, 0xea, 0x38, 0x41,
 	0x02, 0x2c, 0x51, 0x31,
 	0x04, 0xac, 0xf9, 0x30,
-	0x19, 0xea, 0x2e, 0x59,
+	0x19, 0xea, 0x38, 0x59,
 	0x02, 0x8c, 0x59, 0x32,
 	0x02, 0x28, 0x19, 0x33,
 	0x02, 0xa8, 0x50, 0x36,
@@ -175,23 +180,23 @@ static uint8_t seqprog[] = {
 	0x02, 0x20, 0xb9, 0x30,
 	0x02, 0x20, 0x51, 0x31,
 	0x4c, 0xa9, 0xd7, 0x28,
-	0x10, 0xa8, 0x59, 0x79,
+	0x10, 0xa8, 0x63, 0x79,
 	0x01, 0x6b, 0xc0, 0x30,
 	0x02, 0x64, 0xc8, 0x00,
 	0x40, 0x3a, 0x74, 0x04,
-	0x00, 0xe2, 0x66, 0x58,
-	0x33, 0xea, 0x3a, 0x59,
+	0x00, 0xe2, 0x70, 0x58,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x30, 0x3f, 0xc0, 0x09,
-	0x30, 0xe0, 0x5a, 0x61,
-	0x20, 0x3f, 0x70, 0x69,
-	0x10, 0x3f, 0x5a, 0x79,
+	0x30, 0xe0, 0x64, 0x61,
+	0x20, 0x3f, 0x7a, 0x69,
+	0x10, 0x3f, 0x64, 0x79,
 	0x02, 0xea, 0x7e, 0x00,
-	0x00, 0xea, 0x3a, 0x59,
+	0x00, 0xea, 0x44, 0x59,
 	0x01, 0xea, 0x00, 0x30,
 	0x02, 0x48, 0x51, 0x35,
 	0x01, 0xea, 0x7e, 0x00,
-	0x11, 0xea, 0x3a, 0x59,
+	0x11, 0xea, 0x44, 0x59,
 	0x11, 0xea, 0x00, 0x00,
 	0x02, 0x48, 0x51, 0x35,
 	0x08, 0xea, 0x98, 0x00,
@@ -201,11 +206,11 @@ static uint8_t seqprog[] = {
 	0x0f, 0x67, 0xc0, 0x09,
 	0x00, 0x34, 0x69, 0x02,
 	0x20, 0xea, 0x96, 0x00,
-	0x00, 0xe2, 0xee, 0x41,
-	0x40, 0x3a, 0xa4, 0x69,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x40, 0x3a, 0xae, 0x69,
 	0x02, 0x55, 0x06, 0x68,
-	0x02, 0x56, 0xa4, 0x69,
-	0xff, 0x5b, 0xa4, 0x61,
+	0x02, 0x56, 0xae, 0x69,
+	0xff, 0x5b, 0xae, 0x61,
 	0x02, 0x20, 0x51, 0x31,
 	0x80, 0xea, 0xb2, 0x01,
 	0x44, 0xea, 0x00, 0x00,
@@ -213,36 +218,36 @@ static uint8_t seqprog[] = {
 	0x33, 0xea, 0x00, 0x00,
 	0xff, 0xea, 0xb2, 0x09,
 	0xff, 0xe0, 0xc0, 0x19,
-	0xff, 0xe0, 0xa6, 0x79,
+	0xff, 0xe0, 0xb0, 0x79,
 	0x02, 0x94, 0x51, 0x31,
-	0x00, 0xe2, 0x9c, 0x41,
+	0x00, 0xe2, 0xa6, 0x41,
 	0x02, 0x5e, 0x50, 0x31,
 	0x02, 0xa8, 0xb8, 0x30,
 	0x02, 0x5c, 0x50, 0x31,
-	0xff, 0x95, 0xb7, 0x71,
+	0xff, 0x95, 0xc1, 0x71,
 	0x02, 0x94, 0x41, 0x31,
 	0x02, 0x22, 0x51, 0x31,
 	0x02, 0xa0, 0x2c, 0x33,
 	0x02, 0xa0, 0x44, 0x32,
-	0x00, 0xe2, 0xc0, 0x41,
-	0x10, 0xa8, 0xc1, 0x69,
+	0x00, 0xe2, 0xca, 0x41,
+	0x10, 0xa8, 0xcb, 0x69,
 	0x3d, 0xa9, 0xc9, 0x29,
 	0x01, 0xe4, 0xc8, 0x01,
 	0x01, 0xea, 0xca, 0x01,
 	0xff, 0xea, 0xda, 0x01,
 	0x02, 0x20, 0x51, 0x31,
 	0x02, 0x96, 0x41, 0x32,
-	0xff, 0x21, 0xc9, 0x61,
+	0xff, 0x21, 0xd3, 0x61,
 	0xff, 0xea, 0x46, 0x02,
 	0x02, 0x5c, 0x50, 0x31,
 	0x40, 0xea, 0x96, 0x00,
-	0x02, 0x56, 0xac, 0x6d,
-	0x01, 0x55, 0xac, 0x6d,
-	0x10, 0xa8, 0xd5, 0x79,
-	0x10, 0x40, 0xde, 0x69,
-	0x01, 0x56, 0xde, 0x79,
+	0x02, 0x56, 0xe8, 0x6d,
+	0x01, 0x55, 0xe8, 0x6d,
+	0x10, 0xa8, 0xdf, 0x79,
+	0x10, 0x40, 0xe8, 0x69,
+	0x01, 0x56, 0xe8, 0x79,
 	0xff, 0x93, 0x07, 0x78,
-	0x13, 0xea, 0x46, 0x59,
+	0x13, 0xea, 0x50, 0x59,
 	0x13, 0xea, 0x04, 0x00,
 	0x00, 0xe2, 0x06, 0x40,
 	0xbf, 0x3a, 0x74, 0x08,
@@ -253,104 +258,104 @@ static uint8_t seqprog[] = {
 	0x40, 0xea, 0x66, 0x02,
 	0x08, 0x3c, 0x78, 0x00,
 	0x80, 0xea, 0x62, 0x02,
-	0x00, 0xe2, 0xa4, 0x5b,
+	0x00, 0xe2, 0xac, 0x5b,
 	0x01, 0x36, 0xc1, 0x31,
-	0x9f, 0xe0, 0x38, 0x7c,
-	0x80, 0xe0, 0x02, 0x72,
-	0xa0, 0xe0, 0x3a, 0x72,
-	0xc0, 0xe0, 0x30, 0x72,
-	0xe0, 0xe0, 0x6a, 0x72,
-	0x01, 0xea, 0x46, 0x59,
+	0x9f, 0xe0, 0x4e, 0x7c,
+	0x80, 0xe0, 0x0c, 0x72,
+	0xa0, 0xe0, 0x44, 0x72,
+	0xc0, 0xe0, 0x3a, 0x72,
+	0xe0, 0xe0, 0x74, 0x72,
+	0x01, 0xea, 0x50, 0x59,
 	0x01, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xee, 0x41,
-	0x80, 0x33, 0x09, 0x7a,
-	0x03, 0xea, 0x46, 0x59,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x80, 0x33, 0x13, 0x7a,
+	0x03, 0xea, 0x50, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0xee, 0x00, 0x10, 0x6a,
+	0xee, 0x00, 0x1a, 0x6a,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x3a, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x02, 0xa8, 0x90, 0x32,
-	0x00, 0xe2, 0x60, 0x59,
+	0x00, 0xe2, 0x6a, 0x59,
 	0xef, 0x92, 0xd5, 0x19,
-	0x00, 0xe2, 0x20, 0x52,
-	0x0b, 0x84, 0xe1, 0x30,
+	0x00, 0xe2, 0x2a, 0x52,
+	0x09, 0x80, 0xe1, 0x30,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x26, 0x42,
+	0x00, 0xe2, 0x30, 0x42,
 	0x01, 0x92, 0xd1, 0x30,
 	0x10, 0x80, 0x89, 0x31,
 	0x20, 0xea, 0x32, 0x00,
 	0xbf, 0x33, 0x67, 0x0a,
-	0x20, 0x19, 0x28, 0x6a,
-	0x02, 0x4d, 0xee, 0x69,
+	0x20, 0x19, 0x32, 0x6a,
+	0x02, 0x4d, 0xf8, 0x69,
 	0x40, 0x33, 0x67, 0x02,
-	0x00, 0xe2, 0xee, 0x41,
-	0x80, 0x33, 0xa7, 0x6a,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x80, 0x33, 0xb1, 0x6a,
 	0x01, 0x44, 0x10, 0x33,
 	0x08, 0xa8, 0x51, 0x03,
-	0x00, 0xe2, 0xee, 0x41,
+	0x00, 0xe2, 0xf8, 0x41,
 	0x10, 0xea, 0x80, 0x00,
 	0x01, 0x31, 0xc5, 0x31,
-	0x80, 0xe2, 0x56, 0x62,
-	0x10, 0xa8, 0x7b, 0x6a,
+	0x80, 0xe2, 0x60, 0x62,
+	0x10, 0xa8, 0x85, 0x6a,
 	0xc0, 0xaa, 0xc5, 0x01,
-	0x40, 0xa8, 0x47, 0x6a,
+	0x40, 0xa8, 0x51, 0x6a,
 	0xbf, 0xe2, 0xc4, 0x09,
-	0x20, 0xa8, 0x5b, 0x7a,
+	0x20, 0xa8, 0x65, 0x7a,
 	0x01, 0xe2, 0x88, 0x30,
-	0x00, 0xe2, 0xa4, 0x5b,
-	0xa0, 0x36, 0x63, 0x62,
+	0x00, 0xe2, 0xac, 0x5b,
+	0xa0, 0x36, 0x6d, 0x62,
 	0x23, 0xa8, 0x89, 0x08,
-	0x00, 0xe2, 0xa4, 0x5b,
-	0xa0, 0x36, 0x63, 0x62,
-	0x00, 0xa8, 0x5a, 0x42,
-	0xff, 0xe2, 0x5a, 0x62,
-	0x00, 0xe2, 0x7a, 0x42,
+	0x00, 0xe2, 0xac, 0x5b,
+	0xa0, 0x36, 0x6d, 0x62,
+	0x00, 0xa8, 0x64, 0x42,
+	0xff, 0xe2, 0x64, 0x62,
+	0x00, 0xe2, 0x84, 0x42,
 	0x40, 0xea, 0x98, 0x00,
 	0x01, 0xe2, 0x88, 0x30,
-	0x00, 0xe2, 0xa4, 0x5b,
-	0xa0, 0x36, 0x39, 0x72,
+	0x00, 0xe2, 0xac, 0x5b,
+	0xa0, 0x36, 0x43, 0x72,
 	0x40, 0xea, 0x98, 0x00,
 	0x01, 0x31, 0x89, 0x32,
 	0x08, 0xea, 0x62, 0x02,
-	0x00, 0xe2, 0xee, 0x41,
-	0xe0, 0xea, 0xb4, 0x5b,
-	0x80, 0xe0, 0xb2, 0x6a,
-	0x04, 0xe0, 0x52, 0x73,
-	0x02, 0xe0, 0x82, 0x73,
-	0x00, 0xea, 0x10, 0x73,
-	0x03, 0xe0, 0x92, 0x73,
-	0x23, 0xe0, 0x8c, 0x72,
-	0x08, 0xe0, 0xae, 0x72,
-	0x00, 0xe2, 0xa4, 0x5b,
-	0x07, 0xea, 0x46, 0x59,
+	0x00, 0xe2, 0xf8, 0x41,
+	0xe0, 0xea, 0xc8, 0x5b,
+	0x80, 0xe0, 0xbc, 0x6a,
+	0x04, 0xe0, 0x5a, 0x73,
+	0x02, 0xe0, 0x8a, 0x73,
+	0x00, 0xea, 0x1a, 0x73,
+	0x03, 0xe0, 0x9a, 0x73,
+	0x23, 0xe0, 0x96, 0x72,
+	0x08, 0xe0, 0xb8, 0x72,
+	0x00, 0xe2, 0xac, 0x5b,
+	0x07, 0xea, 0x50, 0x59,
 	0x07, 0xea, 0x04, 0x00,
-	0x08, 0x42, 0xef, 0x71,
-	0x04, 0x42, 0x89, 0x62,
+	0x08, 0x42, 0xf9, 0x71,
+	0x04, 0x42, 0x93, 0x62,
 	0x01, 0x43, 0x89, 0x30,
-	0x00, 0xe2, 0x7a, 0x42,
+	0x00, 0xe2, 0x84, 0x42,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0x7a, 0x42,
+	0x00, 0xe2, 0x84, 0x42,
 	0x01, 0x00, 0x60, 0x32,
-	0x33, 0xea, 0x3a, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x4c, 0x34, 0xc1, 0x28,
 	0x01, 0x64, 0xc0, 0x31,
-	0x00, 0x30, 0x3b, 0x59,
+	0x00, 0x30, 0x45, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x01, 0xe0, 0xac, 0x7a,
-	0xa0, 0xea, 0xaa, 0x5b,
-	0x01, 0xa0, 0xac, 0x62,
-	0x01, 0x84, 0xa5, 0x7a,
-	0x01, 0xa7, 0xae, 0x7a,
-	0x00, 0xe2, 0xae, 0x42,
-	0x03, 0xea, 0x46, 0x59,
+	0x01, 0xe0, 0xb6, 0x7a,
+	0xa0, 0xea, 0xbe, 0x5b,
+	0x01, 0xa0, 0xb6, 0x62,
+	0x01, 0x84, 0xaf, 0x7a,
+	0x01, 0xa7, 0xb8, 0x7a,
+	0x00, 0xe2, 0xb8, 0x42,
+	0x03, 0xea, 0x50, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xae, 0x42,
-	0x07, 0xea, 0xbc, 0x5b,
+	0x00, 0xe2, 0xb8, 0x42,
+	0x07, 0xea, 0xd0, 0x5b,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0xee, 0x41,
+	0x00, 0xe2, 0xf8, 0x41,
 	0x3f, 0xe0, 0x6a, 0x0a,
 	0xc0, 0x34, 0xc1, 0x09,
 	0x00, 0x35, 0x51, 0x01,
@@ -361,54 +366,54 @@ static uint8_t seqprog[] = {
 	0x01, 0xea, 0xc6, 0x01,
 	0x02, 0xe2, 0xc8, 0x31,
 	0x02, 0xec, 0x40, 0x31,
-	0xff, 0xa1, 0xce, 0x72,
+	0xff, 0xa1, 0xd8, 0x72,
 	0x02, 0xe8, 0xda, 0x31,
 	0x02, 0xa0, 0x50, 0x31,
-	0x00, 0xe2, 0xf0, 0x42,
+	0x00, 0xe2, 0xfa, 0x42,
 	0x80, 0x33, 0x67, 0x02,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0xa4, 0x5b,
+	0x00, 0xe2, 0xac, 0x5b,
 	0x01, 0x33, 0x67, 0x02,
-	0xe0, 0x36, 0x0b, 0x63,
+	0xe0, 0x36, 0x15, 0x63,
 	0x02, 0x33, 0x67, 0x02,
-	0x20, 0x46, 0x04, 0x63,
+	0x20, 0x46, 0x0e, 0x63,
 	0xff, 0xea, 0x52, 0x09,
-	0xa8, 0xea, 0xaa, 0x5b,
-	0x04, 0xa8, 0xeb, 0x7a,
+	0xa8, 0xea, 0xbe, 0x5b,
+	0x04, 0xa8, 0xf5, 0x7a,
 	0x01, 0x34, 0xc1, 0x31,
-	0x00, 0xa9, 0xeb, 0x62,
+	0x00, 0xa9, 0xf5, 0x62,
 	0x01, 0x35, 0xc1, 0x31,
-	0x00, 0xaa, 0xf5, 0x72,
+	0x00, 0xaa, 0xff, 0x72,
 	0x01, 0xa9, 0x52, 0x11,
-	0xff, 0xa9, 0xe0, 0x6a,
-	0x00, 0xe2, 0x04, 0x43,
+	0xff, 0xa9, 0xea, 0x6a,
+	0x00, 0xe2, 0x0e, 0x43,
 	0x10, 0x33, 0x67, 0x02,
-	0x04, 0xa8, 0x05, 0x7b,
+	0x04, 0xa8, 0x0f, 0x7b,
 	0xfb, 0xa8, 0x51, 0x0b,
 	0xff, 0xea, 0x66, 0x0a,
-	0x01, 0xa4, 0xff, 0x6a,
+	0x01, 0xa4, 0x09, 0x6b,
 	0x02, 0xa8, 0x90, 0x32,
-	0x00, 0xe2, 0x60, 0x59,
-	0x10, 0xa8, 0xaf, 0x7a,
-	0xff, 0xea, 0xbc, 0x5b,
-	0x00, 0xe2, 0xae, 0x42,
-	0x04, 0xea, 0x46, 0x59,
+	0x00, 0xe2, 0x6a, 0x59,
+	0x10, 0xa8, 0xb9, 0x7a,
+	0xff, 0xea, 0xd0, 0x5b,
+	0x00, 0xe2, 0xb8, 0x42,
+	0x04, 0xea, 0x50, 0x59,
 	0x04, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xae, 0x42,
-	0x04, 0xea, 0x46, 0x59,
+	0x00, 0xe2, 0xb8, 0x42,
+	0x04, 0xea, 0x50, 0x59,
 	0x04, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xee, 0x41,
-	0x08, 0xa8, 0xa7, 0x7a,
-	0xc0, 0x33, 0x1b, 0x7b,
-	0x80, 0x33, 0xa7, 0x6a,
-	0xff, 0x88, 0x1b, 0x6b,
-	0x40, 0x33, 0xa7, 0x6a,
-	0x10, 0xa8, 0x21, 0x7b,
-	0x0a, 0xea, 0x46, 0x59,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x08, 0xa8, 0xb1, 0x7a,
+	0xc0, 0x33, 0x25, 0x7b,
+	0x80, 0x33, 0xb1, 0x6a,
+	0xff, 0x88, 0x25, 0x6b,
+	0x40, 0x33, 0xb1, 0x6a,
+	0x10, 0xa8, 0x2b, 0x7b,
+	0x0a, 0xea, 0x50, 0x59,
 	0x0a, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x3a, 0x5b,
-	0x00, 0xe2, 0x6e, 0x43,
-	0x50, 0x4b, 0x28, 0x6b,
+	0x00, 0xe2, 0x44, 0x5b,
+	0x00, 0xe2, 0x76, 0x43,
+	0x50, 0x4b, 0x32, 0x6b,
 	0xbf, 0x3a, 0x74, 0x08,
 	0x01, 0xe0, 0xf8, 0x31,
 	0xff, 0xea, 0xc0, 0x09,
@@ -416,24 +421,23 @@ static uint8_t seqprog[] = {
 	0x00, 0x2f, 0x5f, 0x22,
 	0x04, 0x47, 0x8f, 0x02,
 	0x01, 0xfc, 0xc0, 0x35,
-	0x33, 0xea, 0x3a, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x02, 0x42, 0x51, 0x31,
-	0x10, 0xa8, 0x51, 0x03,
-	0xff, 0x88, 0x49, 0x6b,
-	0x01, 0xa4, 0x45, 0x6b,
-	0x02, 0xa4, 0x4d, 0x6b,
-	0x01, 0x84, 0x4d, 0x7b,
+	0xff, 0x88, 0x51, 0x6b,
+	0x01, 0xa4, 0x4d, 0x6b,
+	0x02, 0xa4, 0x55, 0x6b,
+	0x01, 0x84, 0x55, 0x7b,
 	0x02, 0x28, 0x19, 0x33,
 	0x02, 0xa8, 0x50, 0x36,
-	0xff, 0x88, 0x4d, 0x73,
-	0x00, 0xe2, 0x24, 0x5b,
+	0xff, 0x88, 0x55, 0x73,
+	0x00, 0xe2, 0x2e, 0x5b,
 	0x02, 0x2c, 0x19, 0x33,
 	0x02, 0xa8, 0x58, 0x32,
 	0x04, 0xa4, 0x49, 0x07,
-	0xc0, 0x33, 0xa7, 0x6a,
+	0xc0, 0x33, 0xb1, 0x6a,
 	0x04, 0xa8, 0x51, 0x03,
-	0x20, 0xa8, 0x6f, 0x6b,
+	0x20, 0xa8, 0x77, 0x6b,
 	0x02, 0xa8, 0x40, 0x31,
 	0xc0, 0x34, 0xc1, 0x09,
 	0x00, 0x35, 0x51, 0x01,
@@ -448,66 +452,73 @@ static uint8_t seqprog[] = {
 	0xf7, 0x57, 0xae, 0x08,
 	0x08, 0xea, 0x98, 0x00,
 	0x01, 0x44, 0xd4, 0x31,
-	0xee, 0x00, 0x78, 0x6b,
+	0xee, 0x00, 0x80, 0x6b,
 	0x02, 0xea, 0xb4, 0x00,
-	0x00, 0xe2, 0xa0, 0x5b,
-	0x09, 0x4c, 0x7a, 0x7b,
+	0x00, 0xe2, 0xa8, 0x5b,
+	0x09, 0x4c, 0x82, 0x7b,
 	0x08, 0x4c, 0x06, 0x68,
-	0x0b, 0xea, 0x46, 0x59,
+	0x0b, 0xea, 0x50, 0x59,
 	0x0b, 0xea, 0x04, 0x00,
 	0x01, 0x44, 0xd4, 0x31,
-	0x20, 0x33, 0xef, 0x79,
-	0x00, 0xe2, 0x8a, 0x5b,
-	0x00, 0xe2, 0xee, 0x41,
-	0x01, 0x84, 0x8f, 0x7b,
+	0x20, 0x33, 0xf9, 0x79,
+	0x00, 0xe2, 0x92, 0x5b,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x01, 0x84, 0x97, 0x7b,
 	0x01, 0xa4, 0x49, 0x07,
 	0x08, 0x60, 0x30, 0x33,
 	0x08, 0x80, 0x41, 0x37,
 	0xdf, 0x33, 0x67, 0x0a,
-	0xee, 0x00, 0x9c, 0x6b,
+	0xee, 0x00, 0xa4, 0x6b,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x3a, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x00, 0xe2, 0x60, 0x59,
-	0x00, 0xe2, 0xae, 0x42,
+	0x00, 0xe2, 0x6a, 0x59,
+	0x00, 0xe2, 0xb8, 0x42,
 	0x01, 0xea, 0x6c, 0x02,
 	0xc0, 0xea, 0x66, 0x06,
-	0xff, 0x42, 0xa4, 0x7b,
-	0x04, 0x4c, 0xa4, 0x6b,
+	0xff, 0x42, 0xb8, 0x6b,
+	0x01, 0x41, 0xac, 0x6b,
+	0x02, 0x41, 0xac, 0x7b,
+	0xff, 0x42, 0xb8, 0x6b,
+	0x01, 0x41, 0xac, 0x6b,
+	0x02, 0x41, 0xac, 0x7b,
+	0xff, 0x42, 0xb8, 0x7b,
+	0x04, 0x4c, 0xac, 0x6b,
 	0xe0, 0x41, 0x6c, 0x0e,
 	0x01, 0x44, 0xd4, 0x31,
-	0xff, 0x42, 0xac, 0x7b,
-	0x04, 0x4c, 0xac, 0x6b,
+	0xff, 0x42, 0xc0, 0x7b,
+	0x04, 0x4c, 0xc0, 0x6b,
 	0xe0, 0x41, 0x6c, 0x0a,
-	0xe0, 0x36, 0xef, 0x61,
+	0xe0, 0x36, 0xf9, 0x61,
 	0xff, 0xea, 0xca, 0x09,
 	0x01, 0xe2, 0xc8, 0x31,
 	0x01, 0x46, 0xda, 0x35,
 	0x01, 0x44, 0xd4, 0x35,
 	0x10, 0xea, 0x80, 0x00,
 	0x01, 0xe2, 0x62, 0x36,
-	0x04, 0xa6, 0xc4, 0x7b,
+	0x04, 0xa6, 0xd8, 0x7b,
 	0xff, 0xea, 0x5a, 0x09,
 	0xff, 0xea, 0x4c, 0x0d,
-	0x01, 0xa6, 0xe2, 0x6b,
-	0x10, 0xad, 0x66, 0x7d,
-	0x80, 0xad, 0xda, 0x6b,
-	0x08, 0xad, 0x66, 0x6d,
+	0x01, 0xa6, 0xf6, 0x6b,
+	0x10, 0xad, 0x96, 0x7d,
+	0x80, 0xad, 0xee, 0x6b,
+	0x08, 0xad, 0x96, 0x6d,
 	0x04, 0x84, 0xf9, 0x30,
 	0x00, 0xea, 0x08, 0x81,
 	0xff, 0xea, 0xd4, 0x09,
 	0x02, 0x84, 0xf9, 0x88,
-	0x1d, 0xea, 0x5a, 0x01,
+	0x0d, 0xea, 0x5a, 0x01,
 	0x04, 0xa6, 0x4c, 0x05,
-	0x04, 0xa6, 0x66, 0x7d,
+	0x04, 0xa6, 0x96, 0x7d,
 	0xff, 0xea, 0x5a, 0x09,
 	0x03, 0x84, 0x59, 0x89,
 	0x03, 0xea, 0x4c, 0x01,
-	0x80, 0x1a, 0x66, 0x7d,
+	0x80, 0x1a, 0x96, 0x7d,
+	0x08, 0x19, 0x96, 0x7d,
 	0x08, 0xb0, 0xe0, 0x30,
 	0x04, 0xb0, 0xe0, 0x30,
 	0x03, 0xb0, 0xf0, 0x30,
-	0x01, 0x78, 0xee, 0x7b,
+	0x01, 0x78, 0x04, 0x7c,
 	0x01, 0xa7, 0x4e, 0x11,
 	0x01, 0xb0, 0x06, 0x33,
 	0x7f, 0x83, 0xe9, 0x08,
@@ -518,247 +529,267 @@ static uint8_t seqprog[] = {
 	0x00, 0x86, 0x0d, 0x23,
 	0x00, 0x87, 0x0f, 0x23,
 	0x01, 0x84, 0xc5, 0x31,
-	0x01, 0xa7, 0x04, 0x7c,
+	0x01, 0xa7, 0x1a, 0x7c,
 	0x04, 0xe2, 0xc4, 0x01,
-	0x80, 0x83, 0x0b, 0x7c,
+	0x80, 0x83, 0x21, 0x7c,
 	0x02, 0xe2, 0xc4, 0x01,
 	0xff, 0xea, 0x4c, 0x09,
 	0x01, 0xe2, 0x36, 0x30,
 	0xc8, 0x19, 0x32, 0x00,
 	0x88, 0x19, 0x32, 0x00,
 	0x01, 0xac, 0xd4, 0x99,
-	0x00, 0xe2, 0x66, 0x55,
+	0x00, 0xe2, 0x96, 0x55,
 	0xfe, 0xa6, 0x4c, 0x0d,
 	0x0b, 0x98, 0xe1, 0x30,
 	0x01, 0xa0, 0x4f, 0x09,
 	0xfd, 0xa4, 0x49, 0x09,
-	0x80, 0xa3, 0x21, 0x7c,
+	0x80, 0xa3, 0x37, 0x7c,
 	0x02, 0xa4, 0x48, 0x01,
-	0x01, 0xa7, 0x24, 0x7c,
+	0x01, 0xa7, 0x3a, 0x7c,
 	0x04, 0xa4, 0x48, 0x01,
 	0x01, 0xa4, 0x36, 0x30,
 	0xa8, 0xea, 0x32, 0x00,
 	0xfd, 0xa4, 0x49, 0x0b,
 	0x05, 0xa3, 0x07, 0x33,
-	0x80, 0x83, 0x31, 0x6c,
+	0x80, 0x83, 0x47, 0x6c,
 	0x02, 0xea, 0x4c, 0x05,
 	0xff, 0xea, 0x4c, 0x0d,
-	0x00, 0xe2, 0x32, 0x59,
-	0x02, 0xa6, 0xc6, 0x6b,
+	0x00, 0xe2, 0x3c, 0x59,
+	0x02, 0xa6, 0xda, 0x6b,
 	0x80, 0xf9, 0xf2, 0x05,
-	0xc0, 0x33, 0x3f, 0x7c,
-	0x03, 0xea, 0x46, 0x59,
+	0xc0, 0x33, 0x55, 0x7c,
+	0x03, 0xea, 0x50, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0x20, 0x33, 0x63, 0x7c,
-	0x01, 0x84, 0x49, 0x6c,
-	0x06, 0xea, 0x46, 0x59,
+	0x20, 0x33, 0x79, 0x7c,
+	0x01, 0x84, 0x5f, 0x6c,
+	0x06, 0xea, 0x50, 0x59,
 	0x06, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x66, 0x44,
+	0x00, 0xe2, 0x7c, 0x44,
 	0x01, 0x00, 0x60, 0x32,
-	0xee, 0x00, 0x52, 0x6c,
+	0xee, 0x00, 0x68, 0x6c,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x3a, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x80, 0x3d, 0x7a, 0x00,
-	0xfc, 0x42, 0x54, 0x7c,
+	0xfc, 0x42, 0x6a, 0x7c,
 	0x7f, 0x3d, 0x7a, 0x08,
-	0x00, 0x30, 0x3b, 0x59,
+	0x00, 0x30, 0x45, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x09, 0xea, 0x46, 0x59,
+	0x09, 0xea, 0x50, 0x59,
 	0x09, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xee, 0x41,
-	0x01, 0xa4, 0x49, 0x6c,
-	0x00, 0xe2, 0x16, 0x5c,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x01, 0xa4, 0x5f, 0x6c,
+	0x00, 0xe2, 0x2c, 0x5c,
 	0x20, 0x33, 0x67, 0x02,
 	0x01, 0x00, 0x60, 0x32,
-	0x02, 0xa6, 0x6e, 0x7c,
-	0x00, 0xe2, 0x32, 0x5c,
-	0x00, 0xe2, 0x66, 0x58,
-	0x00, 0xe2, 0x76, 0x58,
-	0x00, 0xe2, 0x30, 0x58,
-	0x00, 0x30, 0x3b, 0x59,
+	0x02, 0xa6, 0x84, 0x7c,
+	0x00, 0xe2, 0x48, 0x5c,
+	0x00, 0xe2, 0x70, 0x58,
+	0x00, 0xe2, 0x80, 0x58,
+	0x00, 0xe2, 0x3a, 0x58,
+	0x00, 0x30, 0x45, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x20, 0x19, 0x6e, 0x6c,
-	0x00, 0xe2, 0x96, 0x5c,
-	0x04, 0x19, 0x88, 0x6c,
+	0x20, 0x19, 0x84, 0x6c,
+	0x00, 0xe2, 0xb4, 0x5c,
+	0x04, 0x19, 0x9e, 0x6c,
 	0x02, 0x19, 0x32, 0x00,
-	0x01, 0x84, 0x89, 0x7c,
-	0x01, 0x1b, 0x82, 0x7c,
-	0x01, 0x1a, 0x88, 0x6c,
-	0x00, 0xe2, 0x38, 0x44,
-	0x80, 0x4b, 0x8e, 0x6c,
-	0x01, 0x4c, 0x8a, 0x7c,
-	0x03, 0x42, 0x38, 0x6c,
-	0x00, 0xe2, 0xc0, 0x5b,
+	0x01, 0x84, 0x9f, 0x7c,
+	0x01, 0x1b, 0x98, 0x7c,
+	0x01, 0x1a, 0x9e, 0x6c,
+	0x00, 0xe2, 0x4e, 0x44,
+	0x80, 0x4b, 0xa4, 0x6c,
+	0x01, 0x4c, 0xa0, 0x7c,
+	0x03, 0x42, 0x4e, 0x6c,
+	0x00, 0xe2, 0xd4, 0x5b,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x04, 0x33, 0xef, 0x79,
-	0x00, 0xe2, 0xee, 0x41,
-	0x02, 0x1b, 0x9e, 0x7c,
-	0x08, 0x5d, 0x9c, 0x7c,
+	0x04, 0x33, 0xf9, 0x79,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x08, 0x5d, 0xbc, 0x6c,
+	0x00, 0xe2, 0x70, 0x58,
+	0x00, 0x30, 0x45, 0x59,
+	0x01, 0x30, 0x01, 0x30,
+	0x02, 0x1b, 0xac, 0x7c,
+	0x08, 0x5d, 0xba, 0x7c,
 	0x03, 0x68, 0x00, 0x37,
 	0x01, 0x84, 0x09, 0x07,
-	0x08, 0x5d, 0xa8, 0x6c,
-	0x00, 0xe2, 0x66, 0x58,
-	0x00, 0x30, 0x3b, 0x59,
-	0x01, 0x30, 0x01, 0x30,
-	0x00, 0xe2, 0x96, 0x44,
-	0x80, 0x1b, 0xb2, 0x7c,
-	0x80, 0x84, 0xb3, 0x6c,
+	0x80, 0x1b, 0xc6, 0x7c,
+	0x80, 0x84, 0xc7, 0x6c,
 	0xff, 0x85, 0x0b, 0x1b,
 	0xff, 0x86, 0x0d, 0x23,
 	0xff, 0x87, 0x0f, 0x23,
 	0xf8, 0x1b, 0x08, 0x0b,
 	0xff, 0xea, 0x4e, 0x09,
-	0x04, 0x1b, 0xba, 0x7c,
+	0x04, 0x1b, 0xce, 0x7c,
 	0x01, 0xa7, 0x4e, 0x01,
 	0xff, 0xea, 0x06, 0x0b,
 	0x03, 0x68, 0x00, 0x37,
-	0x00, 0xe2, 0xb6, 0x58,
+	0x00, 0xe2, 0xc0, 0x58,
 	0x10, 0xea, 0x18, 0x00,
 	0xf9, 0xd9, 0xb2, 0x0d,
 	0x01, 0xd9, 0xb2, 0x05,
-	0xff, 0xea, 0xd4, 0x09,
-	0x10, 0x5b, 0xde, 0x6c,
-	0x08, 0x5b, 0xe6, 0x6c,
-	0x20, 0x5b, 0xd4, 0x6c,
-	0x02, 0x5b, 0xfa, 0x6d,
-	0x0e, 0xea, 0x46, 0x59,
+	0x01, 0x52, 0x48, 0x31,
+	0x20, 0xa4, 0xf2, 0x7c,
+	0x20, 0x5b, 0xf2, 0x7c,
+	0x80, 0xf9, 0x00, 0x7d,
+	0x11, 0x00, 0x00, 0x10,
+	0x04, 0x19, 0xec, 0x7c,
+	0xdf, 0x19, 0x32, 0x08,
+	0x01, 0x4c, 0xe8, 0x7c,
+	0x20, 0x19, 0x32, 0x00,
+	0x11, 0x00, 0x00, 0x10,
+	0x02, 0xea, 0xb4, 0x00,
+	0x01, 0xd9, 0xb2, 0x05,
+	0x10, 0x5b, 0x04, 0x6d,
+	0x08, 0x5b, 0x0c, 0x6d,
+	0x20, 0x5b, 0xfe, 0x6c,
+	0x02, 0x5b, 0x2c, 0x6d,
+	0x0e, 0xea, 0x50, 0x59,
 	0x0e, 0xea, 0x04, 0x00,
-	0x08, 0x19, 0xda, 0x7c,
+	0x80, 0xf9, 0xee, 0x6c,
 	0xdf, 0x5c, 0xb8, 0x08,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x02, 0xea, 0xb4, 0x00,
-	0x01, 0xd9, 0xb2, 0x05,
-	0x01, 0xa4, 0xc3, 0x6d,
-	0x00, 0xe2, 0x16, 0x5c,
-	0x00, 0xe2, 0x06, 0x5d,
+	0x01, 0xa4, 0xff, 0x6d,
+	0x00, 0xe2, 0x2c, 0x5c,
+	0x00, 0xe2, 0x36, 0x5d,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x00, 0xe2, 0x24, 0x5b,
+	0x00, 0xe2, 0x2e, 0x5b,
 	0xf3, 0x92, 0xd5, 0x19,
-	0x00, 0xe2, 0xf4, 0x54,
-	0x80, 0x92, 0xf5, 0x6c,
-	0x0f, 0xea, 0x46, 0x59,
+	0x00, 0xe2, 0x1a, 0x55,
+	0x80, 0x92, 0x1b, 0x6d,
+	0x0f, 0xea, 0x50, 0x59,
 	0x0f, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xfc, 0x44,
+	0x00, 0xe2, 0x22, 0x45,
 	0x04, 0x8c, 0xe1, 0x30,
 	0x01, 0xea, 0xf2, 0x00,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0xff, 0x93, 0x03, 0x7d,
-	0x14, 0xea, 0x46, 0x59,
+	0xff, 0x93, 0x29, 0x7d,
+	0x14, 0xea, 0x50, 0x59,
 	0x14, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x88, 0x5d,
+	0x00, 0xe2, 0xb0, 0x5d,
+	0x01, 0xd9, 0xb2, 0x05,
+	0x09, 0x80, 0xe1, 0x30,
+	0x02, 0xea, 0x36, 0x00,
+	0xa8, 0xea, 0x32, 0x00,
+	0x00, 0xe2, 0xd8, 0x5d,
 	0x01, 0xd9, 0xb2, 0x05,
 	0x02, 0xa8, 0xf4, 0x31,
-	0x02, 0xa6, 0x18, 0x7d,
-	0x00, 0xe2, 0x34, 0x59,
-	0x20, 0x5b, 0x26, 0x6d,
-	0xfc, 0x42, 0x12, 0x7d,
-	0x10, 0x40, 0x14, 0x6d,
-	0x20, 0x4d, 0x16, 0x7d,
-	0x08, 0x5d, 0x26, 0x6d,
-	0x02, 0xa6, 0xc6, 0x6b,
-	0x00, 0xe2, 0x34, 0x59,
-	0x20, 0x5b, 0x26, 0x6d,
-	0x01, 0x1b, 0x46, 0x6d,
-	0xfc, 0x42, 0x22, 0x7d,
-	0x10, 0x40, 0x24, 0x6d,
-	0x20, 0x4d, 0x66, 0x7d,
-	0x08, 0x5d, 0x66, 0x7d,
+	0x02, 0xa6, 0x48, 0x7d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x20, 0x5b, 0x56, 0x6d,
+	0xfc, 0x42, 0x42, 0x7d,
+	0x10, 0x40, 0x44, 0x6d,
+	0x20, 0x4d, 0x46, 0x7d,
+	0x08, 0x5d, 0x56, 0x6d,
+	0x02, 0xa6, 0xda, 0x6b,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x20, 0x5b, 0x56, 0x6d,
+	0x01, 0x1b, 0x76, 0x6d,
+	0xfc, 0x42, 0x52, 0x7d,
+	0x10, 0x40, 0x54, 0x6d,
+	0x20, 0x4d, 0x96, 0x7d,
+	0x08, 0x5d, 0x96, 0x7d,
 	0x02, 0x19, 0x32, 0x00,
 	0x01, 0x5b, 0x40, 0x31,
-	0x00, 0xe2, 0x96, 0x5c,
-	0x00, 0xe2, 0x8a, 0x5b,
+	0x00, 0xe2, 0xb4, 0x5c,
+	0x00, 0xe2, 0x92, 0x5b,
 	0x20, 0xea, 0xb6, 0x00,
-	0x00, 0xe2, 0xc0, 0x5b,
+	0x00, 0xe2, 0xd4, 0x5b,
 	0x20, 0x5c, 0xb8, 0x00,
-	0x04, 0x19, 0x3c, 0x6d,
-	0x01, 0x1a, 0x3c, 0x6d,
-	0x00, 0xe2, 0x34, 0x59,
-	0x01, 0x1a, 0x66, 0x7d,
+	0x04, 0x19, 0x6c, 0x6d,
+	0x01, 0x1a, 0x6c, 0x6d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x01, 0x1a, 0x96, 0x7d,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x20, 0xa0, 0xac, 0x7d,
-	0x08, 0xa8, 0x45, 0x7d,
-	0x00, 0xe2, 0x58, 0x45,
+	0x20, 0xa0, 0xe8, 0x7d,
+	0x08, 0xa8, 0x75, 0x7d,
+	0x00, 0xe2, 0x88, 0x45,
 	0x02, 0xea, 0xb4, 0x04,
 	0x02, 0x19, 0x32, 0x00,
-	0x08, 0xa8, 0x69, 0x7d,
-	0x04, 0x5d, 0xc2, 0x7d,
-	0x01, 0x1a, 0xc2, 0x7d,
+	0x08, 0xa8, 0x99, 0x7d,
+	0x04, 0x5d, 0xfe, 0x7d,
+	0x01, 0x1a, 0xfe, 0x7d,
 	0x01, 0xa4, 0x49, 0x03,
 	0x80, 0xf9, 0xf2, 0x01,
 	0x02, 0xa8, 0x84, 0x32,
 	0x02, 0xea, 0xb4, 0x00,
-	0x00, 0xe2, 0x34, 0x43,
+	0x00, 0xe2, 0x3e, 0x43,
 	0x02, 0xa8, 0x84, 0x32,
 	0x02, 0xea, 0xb4, 0x00,
 	0xff, 0xea, 0xd4, 0x19,
-	0x00, 0xe2, 0x40, 0x59,
+	0x00, 0xe2, 0x4a, 0x59,
 	0x11, 0x00, 0x00, 0x10,
-	0x00, 0xe2, 0x98, 0x5d,
-	0x00, 0xe2, 0x34, 0x53,
+	0x00, 0xe2, 0xcc, 0x5d,
+	0x00, 0xe2, 0x3e, 0x53,
 	0xff, 0xea, 0xd4, 0x0d,
-	0x00, 0xe2, 0x34, 0x59,
-	0x40, 0x5b, 0x74, 0x6d,
-	0x04, 0x5d, 0xc2, 0x7d,
-	0x01, 0x1a, 0xc2, 0x7d,
-	0x20, 0x4d, 0x66, 0x7d,
-	0x40, 0x5b, 0xac, 0x7d,
-	0x04, 0x5d, 0xc2, 0x7d,
-	0x01, 0x1a, 0xc2, 0x7d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x40, 0x5b, 0xa4, 0x6d,
+	0x04, 0x5d, 0xfe, 0x7d,
+	0x01, 0x1a, 0xfe, 0x7d,
+	0x20, 0x4d, 0x96, 0x7d,
+	0x40, 0x5b, 0xe8, 0x7d,
+	0x04, 0x5d, 0xfe, 0x7d,
+	0x01, 0x1a, 0xfe, 0x7d,
 	0x80, 0xf9, 0xf2, 0x01,
 	0x01, 0xa4, 0x49, 0x03,
-	0x08, 0xa8, 0x59, 0x6d,
+	0x08, 0xa8, 0x89, 0x6d,
 	0x02, 0xea, 0xb4, 0x04,
-	0xff, 0x6a, 0x8e, 0x7d,
-	0x10, 0xea, 0x46, 0x59,
-	0x10, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x8e, 0x45,
-	0x00, 0xe2, 0x32, 0x59,
-	0x10, 0x5d, 0x80, 0x6d,
-	0x40, 0x5b, 0x66, 0x7d,
+	0x00, 0xe2, 0x3c, 0x59,
+	0x01, 0x1b, 0xc0, 0x7d,
+	0x40, 0x5b, 0x96, 0x7d,
 	0x02, 0x19, 0x32, 0x00,
 	0x80, 0xf9, 0xf2, 0x01,
 	0xff, 0xea, 0x10, 0x03,
 	0x08, 0xa8, 0x51, 0x03,
-	0x00, 0xe2, 0x58, 0x45,
-	0x80, 0xf9, 0x66, 0x6d,
+	0x00, 0xe2, 0x88, 0x45,
+	0xff, 0x6a, 0xc6, 0x6d,
+	0x40, 0x5b, 0x96, 0x7d,
+	0xff, 0x6a, 0xb6, 0x7d,
+	0x10, 0xea, 0x50, 0x59,
+	0x10, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xb6, 0x45,
+	0x80, 0xf9, 0x96, 0x6d,
 	0x01, 0x43, 0xc1, 0x31,
-	0x00, 0xfb, 0x66, 0x65,
+	0x00, 0xfb, 0x96, 0x65,
 	0x01, 0x42, 0xc1, 0x31,
-	0x00, 0xfa, 0x66, 0x65,
+	0x00, 0xfa, 0x96, 0x65,
 	0x01, 0xe8, 0xd4, 0x1d,
+	0x00, 0xe2, 0x3c, 0x59,
+	0x01, 0x1b, 0x96, 0x7d,
+	0x80, 0xf9, 0xf2, 0x01,
+	0x02, 0xea, 0xb4, 0x04,
 	0x30, 0x3f, 0xc0, 0x09,
-	0x30, 0xe0, 0x66, 0x65,
-	0x40, 0x4b, 0x66, 0x6d,
+	0x30, 0xe0, 0x96, 0x65,
+	0x40, 0x4b, 0x96, 0x6d,
 	0xff, 0xea, 0x52, 0x01,
-	0xee, 0x00, 0xb2, 0x6d,
+	0xee, 0x00, 0xee, 0x6d,
 	0x80, 0xf9, 0xf2, 0x01,
 	0x02, 0xea, 0xb4, 0x00,
 	0x20, 0xea, 0x9a, 0x00,
-	0xf3, 0x42, 0xbc, 0x6d,
-	0x12, 0xea, 0x46, 0x59,
+	0xf3, 0x42, 0xf8, 0x6d,
+	0x12, 0xea, 0x50, 0x59,
 	0x12, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xee, 0x41,
-	0x0d, 0xea, 0x46, 0x59,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x0d, 0xea, 0x50, 0x59,
 	0x0d, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xee, 0x41,
-	0x11, 0xea, 0x46, 0x59,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x11, 0xea, 0x50, 0x59,
 	0x11, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x24, 0x5b,
+	0x00, 0xe2, 0x2e, 0x5b,
 	0x08, 0x5a, 0xb4, 0x00,
-	0x00, 0xe2, 0xe4, 0x5d,
+	0x00, 0xe2, 0x22, 0x5e,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x34, 0x59,
-	0x80, 0x1a, 0xd6, 0x7d,
-	0x00, 0xe2, 0xe4, 0x5d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x80, 0x1a, 0x12, 0x7e,
+	0x00, 0xe2, 0x22, 0x5e,
 	0x80, 0x19, 0x32, 0x00,
-	0x40, 0x5b, 0xdc, 0x6d,
-	0x08, 0x5a, 0xdc, 0x7d,
-	0x20, 0x4d, 0x66, 0x7d,
+	0x40, 0x5b, 0x18, 0x6e,
+	0x08, 0x5a, 0x18, 0x7e,
+	0x20, 0x4d, 0x96, 0x7d,
 	0x02, 0x84, 0x09, 0x03,
-	0x40, 0x5b, 0xac, 0x7d,
-	0x08, 0xa8, 0x51, 0x6d,
+	0x40, 0x5b, 0xe8, 0x7d,
+	0x08, 0xa8, 0x81, 0x6d,
+	0x80, 0xf9, 0xf2, 0x01,
 	0x02, 0xea, 0xb4, 0x04,
 	0x01, 0x38, 0xe1, 0x30,
 	0x05, 0x39, 0xe3, 0x98,
@@ -774,12 +805,36 @@ static uint8_t seqprog[] = {
 };
 
 typedef int ahd_patch_func_t (struct ahd_softc *ahd);
+static ahd_patch_func_t ahd_patch21_func;
+
+static int
+ahd_patch21_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch20_func;
+
+static int
+ahd_patch20_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
+}
+
+static ahd_patch_func_t ahd_patch19_func;
+
+static int
+ahd_patch19_func(struct ahd_softc *ahd)
+{
+	return ((ahd->features & AHD_RTI) == 0);
+}
+
 static ahd_patch_func_t ahd_patch18_func;
 
 static int
 ahd_patch18_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
+	return ((ahd->flags & AHD_INITIATORROLE) != 0);
 }
 
 static ahd_patch_func_t ahd_patch17_func;
@@ -787,7 +842,7 @@ static ahd_patch_func_t ahd_patch17_func;
 static int
 ahd_patch17_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
+	return ((ahd->flags & AHD_TARGETROLE) != 0);
 }
 
 static ahd_patch_func_t ahd_patch16_func;
@@ -795,7 +850,7 @@ static ahd_patch_func_t ahd_patch16_func;
 static int
 ahd_patch16_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_INITIATORROLE) != 0);
+	return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch15_func;
@@ -803,7 +858,7 @@ static ahd_patch_func_t ahd_patch15_func;
 static int
 ahd_patch15_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_TARGETROLE) != 0);
+	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0);
 }
 
 static ahd_patch_func_t ahd_patch14_func;
@@ -811,7 +866,7 @@ static ahd_patch_func_t ahd_patch14_func;
 static int
 ahd_patch14_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
+	return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
 }
 
 static ahd_patch_func_t ahd_patch13_func;
@@ -819,7 +874,7 @@ static ahd_patch_func_t ahd_patch13_func;
 static int
 ahd_patch13_func(struct ahd_softc *ahd)
 {
-	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0);
+	return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
 }
 
 static ahd_patch_func_t ahd_patch12_func;
@@ -827,7 +882,7 @@ static ahd_patch_func_t ahd_patch12_func;
 static int
 ahd_patch12_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
+	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0);
 }
 
 static ahd_patch_func_t ahd_patch11_func;
@@ -835,7 +890,7 @@ static ahd_patch_func_t ahd_patch11_func;
 static int
 ahd_patch11_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
+	return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch10_func;
@@ -843,7 +898,7 @@ static ahd_patch_func_t ahd_patch10_func;
 static int
 ahd_patch10_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0);
+	return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch9_func;
@@ -859,7 +914,7 @@ static ahd_patch_func_t ahd_patch8_func;
 static int
 ahd_patch8_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0);
+	return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch7_func;
@@ -867,7 +922,7 @@ static ahd_patch_func_t ahd_patch7_func;
 static int
 ahd_patch7_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
+	return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch6_func;
@@ -875,7 +930,7 @@ static ahd_patch_func_t ahd_patch6_func;
 static int
 ahd_patch6_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0);
+	return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch5_func;
@@ -883,7 +938,7 @@ static ahd_patch_func_t ahd_patch5_func;
 static int
 ahd_patch5_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0);
+	return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch4_func;
@@ -891,7 +946,7 @@ static ahd_patch_func_t ahd_patch4_func;
 static int
 ahd_patch4_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0);
+	return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch3_func;
@@ -899,7 +954,7 @@ static ahd_patch_func_t ahd_patch3_func;
 static int
 ahd_patch3_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0);
+	return ((ahd->bugs & AHD_FAINT_LED_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch2_func;
@@ -940,124 +995,129 @@ static struct patch {
 	{ ahd_patch0_func, 5, 1, 1 },
 	{ ahd_patch2_func, 6, 1, 2 },
 	{ ahd_patch0_func, 7, 1, 1 },
-	{ ahd_patch2_func, 24, 1, 2 },
-	{ ahd_patch0_func, 25, 1, 1 },
-	{ ahd_patch1_func, 32, 1, 2 },
-	{ ahd_patch0_func, 33, 1, 1 },
-	{ ahd_patch2_func, 40, 1, 2 },
-	{ ahd_patch0_func, 41, 1, 1 },
-	{ ahd_patch2_func, 44, 1, 2 },
-	{ ahd_patch0_func, 45, 1, 1 },
-	{ ahd_patch2_func, 48, 1, 2 },
-	{ ahd_patch0_func, 49, 1, 1 },
-	{ ahd_patch2_func, 51, 1, 2 },
-	{ ahd_patch0_func, 52, 1, 1 },
-	{ ahd_patch2_func, 55, 1, 2 },
-	{ ahd_patch0_func, 56, 1, 1 },
-	{ ahd_patch2_func, 59, 1, 2 },
-	{ ahd_patch0_func, 60, 1, 1 },
-	{ ahd_patch2_func, 157, 6, 1 },
-	{ ahd_patch1_func, 163, 2, 1 },
-	{ ahd_patch3_func, 165, 1, 1 },
-	{ ahd_patch2_func, 174, 1, 2 },
-	{ ahd_patch0_func, 175, 1, 1 },
-	{ ahd_patch4_func, 176, 2, 2 },
-	{ ahd_patch0_func, 178, 6, 3 },
-	{ ahd_patch2_func, 181, 1, 2 },
-	{ ahd_patch0_func, 182, 1, 1 },
-	{ ahd_patch2_func, 185, 1, 2 },
-	{ ahd_patch0_func, 186, 1, 1 },
-	{ ahd_patch5_func, 188, 2, 1 },
-	{ ahd_patch3_func, 196, 16, 2 },
-	{ ahd_patch0_func, 212, 1, 1 },
-	{ ahd_patch6_func, 232, 2, 1 },
-	{ ahd_patch1_func, 236, 1, 2 },
-	{ ahd_patch0_func, 237, 1, 1 },
-	{ ahd_patch5_func, 240, 2, 1 },
-	{ ahd_patch1_func, 254, 1, 2 },
-	{ ahd_patch0_func, 255, 1, 1 },
-	{ ahd_patch1_func, 258, 1, 2 },
-	{ ahd_patch0_func, 259, 1, 1 },
-	{ ahd_patch2_func, 262, 1, 2 },
-	{ ahd_patch0_func, 263, 1, 1 },
-	{ ahd_patch1_func, 318, 1, 2 },
-	{ ahd_patch0_func, 319, 1, 1 },
-	{ ahd_patch2_func, 327, 1, 2 },
-	{ ahd_patch0_func, 328, 1, 1 },
-	{ ahd_patch2_func, 331, 1, 2 },
-	{ ahd_patch0_func, 332, 1, 1 },
-	{ ahd_patch1_func, 339, 1, 2 },
-	{ ahd_patch0_func, 340, 1, 1 },
-	{ ahd_patch7_func, 359, 1, 1 },
-	{ ahd_patch7_func, 362, 1, 1 },
-	{ ahd_patch7_func, 364, 1, 1 },
-	{ ahd_patch7_func, 376, 1, 1 },
-	{ ahd_patch1_func, 386, 1, 2 },
-	{ ahd_patch0_func, 387, 1, 1 },
-	{ ahd_patch1_func, 389, 1, 2 },
-	{ ahd_patch0_func, 390, 1, 1 },
-	{ ahd_patch1_func, 398, 1, 2 },
-	{ ahd_patch0_func, 399, 1, 1 },
-	{ ahd_patch2_func, 410, 1, 2 },
-	{ ahd_patch0_func, 411, 1, 1 },
-	{ ahd_patch8_func, 413, 1, 1 },
-	{ ahd_patch9_func, 440, 1, 1 },
-	{ ahd_patch1_func, 447, 1, 2 },
-	{ ahd_patch0_func, 448, 1, 1 },
-	{ ahd_patch2_func, 460, 1, 2 },
-	{ ahd_patch0_func, 461, 1, 1 },
-	{ ahd_patch10_func, 489, 1, 1 },
-	{ ahd_patch11_func, 498, 1, 2 },
-	{ ahd_patch0_func, 499, 1, 1 },
-	{ ahd_patch12_func, 504, 1, 1 },
-	{ ahd_patch11_func, 505, 1, 1 },
-	{ ahd_patch13_func, 518, 1, 2 },
-	{ ahd_patch0_func, 519, 1, 1 },
-	{ ahd_patch1_func, 541, 1, 2 },
-	{ ahd_patch0_func, 542, 1, 1 },
-	{ ahd_patch1_func, 545, 1, 2 },
-	{ ahd_patch0_func, 546, 1, 1 },
-	{ ahd_patch2_func, 551, 1, 2 },
-	{ ahd_patch0_func, 552, 1, 1 },
-	{ ahd_patch2_func, 556, 1, 2 },
+	{ ahd_patch3_func, 20, 5, 1 },
+	{ ahd_patch2_func, 29, 1, 2 },
+	{ ahd_patch0_func, 30, 1, 1 },
+	{ ahd_patch1_func, 37, 1, 2 },
+	{ ahd_patch0_func, 38, 1, 1 },
+	{ ahd_patch2_func, 45, 1, 2 },
+	{ ahd_patch0_func, 46, 1, 1 },
+	{ ahd_patch2_func, 49, 1, 2 },
+	{ ahd_patch0_func, 50, 1, 1 },
+	{ ahd_patch2_func, 53, 1, 2 },
+	{ ahd_patch0_func, 54, 1, 1 },
+	{ ahd_patch2_func, 56, 1, 2 },
+	{ ahd_patch0_func, 57, 1, 1 },
+	{ ahd_patch2_func, 60, 1, 2 },
+	{ ahd_patch0_func, 61, 1, 1 },
+	{ ahd_patch2_func, 64, 1, 2 },
+	{ ahd_patch0_func, 65, 1, 1 },
+	{ ahd_patch2_func, 162, 6, 1 },
+	{ ahd_patch1_func, 168, 2, 1 },
+	{ ahd_patch4_func, 170, 1, 1 },
+	{ ahd_patch2_func, 179, 1, 2 },
+	{ ahd_patch0_func, 180, 1, 1 },
+	{ ahd_patch5_func, 181, 2, 2 },
+	{ ahd_patch0_func, 183, 6, 3 },
+	{ ahd_patch2_func, 186, 1, 2 },
+	{ ahd_patch0_func, 187, 1, 1 },
+	{ ahd_patch2_func, 190, 1, 2 },
+	{ ahd_patch0_func, 191, 1, 1 },
+	{ ahd_patch6_func, 193, 2, 1 },
+	{ ahd_patch4_func, 201, 16, 2 },
+	{ ahd_patch0_func, 217, 1, 1 },
+	{ ahd_patch7_func, 237, 2, 1 },
+	{ ahd_patch1_func, 241, 1, 2 },
+	{ ahd_patch0_func, 242, 1, 1 },
+	{ ahd_patch6_func, 245, 2, 1 },
+	{ ahd_patch1_func, 259, 1, 2 },
+	{ ahd_patch0_func, 260, 1, 1 },
+	{ ahd_patch1_func, 263, 1, 2 },
+	{ ahd_patch0_func, 264, 1, 1 },
+	{ ahd_patch2_func, 267, 1, 2 },
+	{ ahd_patch0_func, 268, 1, 1 },
+	{ ahd_patch1_func, 323, 1, 2 },
+	{ ahd_patch0_func, 324, 1, 1 },
+	{ ahd_patch2_func, 332, 1, 2 },
+	{ ahd_patch0_func, 333, 1, 1 },
+	{ ahd_patch2_func, 336, 1, 2 },
+	{ ahd_patch0_func, 337, 1, 1 },
+	{ ahd_patch1_func, 344, 1, 2 },
+	{ ahd_patch0_func, 345, 1, 1 },
+	{ ahd_patch8_func, 364, 1, 1 },
+	{ ahd_patch8_func, 367, 1, 1 },
+	{ ahd_patch8_func, 369, 1, 1 },
+	{ ahd_patch8_func, 381, 1, 1 },
+	{ ahd_patch1_func, 391, 1, 2 },
+	{ ahd_patch0_func, 392, 1, 1 },
+	{ ahd_patch1_func, 394, 1, 2 },
+	{ ahd_patch0_func, 395, 1, 1 },
+	{ ahd_patch1_func, 403, 1, 2 },
+	{ ahd_patch0_func, 404, 1, 1 },
+	{ ahd_patch2_func, 415, 1, 2 },
+	{ ahd_patch0_func, 416, 1, 1 },
+	{ ahd_patch9_func, 444, 1, 1 },
+	{ ahd_patch1_func, 451, 1, 2 },
+	{ ahd_patch0_func, 452, 1, 1 },
+	{ ahd_patch2_func, 464, 1, 2 },
+	{ ahd_patch0_func, 465, 1, 1 },
+	{ ahd_patch10_func, 470, 6, 2 },
+	{ ahd_patch0_func, 476, 1, 1 },
+	{ ahd_patch11_func, 499, 1, 1 },
+	{ ahd_patch12_func, 508, 1, 1 },
+	{ ahd_patch13_func, 509, 1, 2 },
+	{ ahd_patch0_func, 510, 1, 1 },
+	{ ahd_patch14_func, 515, 1, 1 },
+	{ ahd_patch13_func, 516, 1, 1 },
+	{ ahd_patch15_func, 529, 1, 2 },
+	{ ahd_patch0_func, 530, 1, 1 },
+	{ ahd_patch1_func, 552, 1, 2 },
+	{ ahd_patch0_func, 553, 1, 1 },
+	{ ahd_patch1_func, 556, 1, 2 },
 	{ ahd_patch0_func, 557, 1, 1 },
-	{ ahd_patch1_func, 558, 1, 2 },
-	{ ahd_patch0_func, 559, 1, 1 },
-	{ ahd_patch2_func, 570, 1, 2 },
-	{ ahd_patch0_func, 571, 1, 1 },
-	{ ahd_patch14_func, 575, 1, 1 },
-	{ ahd_patch15_func, 580, 1, 1 },
-	{ ahd_patch16_func, 581, 2, 1 },
-	{ ahd_patch15_func, 585, 1, 2 },
-	{ ahd_patch0_func, 586, 1, 1 },
-	{ ahd_patch2_func, 593, 1, 2 },
-	{ ahd_patch0_func, 594, 1, 1 },
-	{ ahd_patch2_func, 609, 1, 2 },
-	{ ahd_patch0_func, 610, 1, 1 },
-	{ ahd_patch1_func, 616, 1, 2 },
-	{ ahd_patch0_func, 617, 1, 1 },
-	{ ahd_patch1_func, 631, 1, 2 },
-	{ ahd_patch0_func, 632, 1, 1 },
-	{ ahd_patch1_func, 639, 1, 2 },
-	{ ahd_patch0_func, 640, 1, 1 },
-	{ ahd_patch14_func, 659, 1, 1 },
-	{ ahd_patch14_func, 675, 1, 1 },
-	{ ahd_patch2_func, 687, 1, 2 },
-	{ ahd_patch0_func, 688, 1, 1 },
-	{ ahd_patch1_func, 705, 1, 2 },
-	{ ahd_patch0_func, 706, 1, 1 },
-	{ ahd_patch14_func, 711, 1, 1 },
-	{ ahd_patch1_func, 731, 1, 2 },
-	{ ahd_patch0_func, 732, 1, 1 },
-	{ ahd_patch1_func, 734, 1, 2 },
-	{ ahd_patch0_func, 735, 1, 1 },
-	{ ahd_patch1_func, 737, 1, 2 },
-	{ ahd_patch0_func, 738, 1, 1 },
-	{ ahd_patch17_func, 740, 1, 2 },
-	{ ahd_patch0_func, 741, 2, 1 },
-	{ ahd_patch18_func, 744, 4, 2 },
-	{ ahd_patch0_func, 748, 1, 1 },
-	{ ahd_patch18_func, 754, 11, 1 }
+	{ ahd_patch2_func, 562, 1, 2 },
+	{ ahd_patch0_func, 563, 1, 1 },
+	{ ahd_patch2_func, 567, 1, 2 },
+	{ ahd_patch0_func, 568, 1, 1 },
+	{ ahd_patch1_func, 569, 1, 2 },
+	{ ahd_patch0_func, 570, 1, 1 },
+	{ ahd_patch2_func, 581, 1, 2 },
+	{ ahd_patch0_func, 582, 1, 1 },
+	{ ahd_patch16_func, 586, 1, 1 },
+	{ ahd_patch17_func, 591, 1, 1 },
+	{ ahd_patch18_func, 592, 2, 1 },
+	{ ahd_patch17_func, 596, 1, 2 },
+	{ ahd_patch0_func, 597, 1, 1 },
+	{ ahd_patch2_func, 600, 1, 2 },
+	{ ahd_patch0_func, 601, 1, 1 },
+	{ ahd_patch2_func, 619, 1, 2 },
+	{ ahd_patch0_func, 620, 1, 1 },
+	{ ahd_patch19_func, 621, 12, 1 },
+	{ ahd_patch1_func, 637, 1, 2 },
+	{ ahd_patch0_func, 638, 1, 1 },
+	{ ahd_patch19_func, 639, 1, 1 },
+	{ ahd_patch1_func, 650, 1, 2 },
+	{ ahd_patch0_func, 651, 1, 1 },
+	{ ahd_patch1_func, 658, 1, 2 },
+	{ ahd_patch0_func, 659, 1, 1 },
+	{ ahd_patch16_func, 683, 1, 1 },
+	{ ahd_patch16_func, 699, 1, 1 },
+	{ ahd_patch2_func, 711, 1, 2 },
+	{ ahd_patch0_func, 712, 1, 1 },
+	{ ahd_patch16_func, 731, 1, 1 },
+	{ ahd_patch1_func, 739, 1, 2 },
+	{ ahd_patch0_func, 740, 1, 1 },
+	{ ahd_patch1_func, 761, 1, 2 },
+	{ ahd_patch0_func, 762, 1, 1 },
+	{ ahd_patch1_func, 764, 1, 2 },
+	{ ahd_patch0_func, 765, 1, 1 },
+	{ ahd_patch1_func, 767, 1, 2 },
+	{ ahd_patch0_func, 768, 1, 1 },
+	{ ahd_patch20_func, 770, 1, 2 },
+	{ ahd_patch0_func, 771, 2, 1 },
+	{ ahd_patch21_func, 774, 4, 2 },
+	{ ahd_patch0_func, 778, 1, 1 },
+	{ ahd_patch21_func, 785, 11, 1 }
 };
 
 static struct cs {
@@ -1066,19 +1126,19 @@ static struct cs {
 } critical_sections[] = {
 	{ 11, 12 },
 	{ 13, 14 },
-	{ 24, 37 },
-	{ 38, 51 },
-	{ 64, 67 },
-	{ 94, 119 },
-	{ 120, 151 },
-	{ 153, 157 },
-	{ 165, 173 },
-	{ 196, 245 },
-	{ 659, 675 },
-	{ 675, 693 },
-	{ 698, 704 },
-	{ 711, 716 },
-	{ 716, 722 }
+	{ 29, 42 },
+	{ 43, 56 },
+	{ 69, 72 },
+	{ 99, 124 },
+	{ 125, 156 },
+	{ 158, 162 },
+	{ 170, 178 },
+	{ 201, 250 },
+	{ 683, 699 },
+	{ 699, 717 },
+	{ 722, 728 },
+	{ 731, 736 },
+	{ 742, 748 }
 };
 
 static const int num_critical_sections = sizeof(critical_sections)
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index b797b01998a2994b8de8cdb2bb58721e1250a0c2..c5fe1dcfa3f2ee8382721d79344ead98d47a00b7 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#70 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#74 $
  *
  * $FreeBSD$
  */
@@ -365,7 +365,8 @@ typedef enum {
 	AHC_LSCBS_ENABLED     = 0x2000000, /* 64Byte SCBs enabled */
 	AHC_SCB_CONFIG_USED   = 0x4000000, /* No SEEPROM but SCB2 had info. */
 	AHC_NO_BIOS_INIT      = 0x8000000, /* No BIOS left over settings. */
-	AHC_DISABLE_PCI_PERR  = 0x10000000
+	AHC_DISABLE_PCI_PERR  = 0x10000000,
+	AHC_HAS_TERM_LOGIC    = 0x20000000
 } ahc_flag;
 
 /************************* Hardware  SCB Definition ***************************/
@@ -691,7 +692,7 @@ struct ahc_tmode_lstate;
 
 #define AHC_WIDTH_UNKNOWN	0xFF
 #define AHC_PERIOD_UNKNOWN	0xFF
-#define AHC_OFFSET_UNKNOWN	0x0
+#define AHC_OFFSET_UNKNOWN	0xFF
 #define AHC_PPR_OPTS_UNKNOWN	0xFF
 
 /*
@@ -877,31 +878,39 @@ typedef enum {
 /*********************** Software Configuration Structure *********************/
 TAILQ_HEAD(scb_tailq, scb);
 
-struct ahc_suspend_channel_state {
-	uint8_t	scsiseq;
-	uint8_t	sxfrctl0;
-	uint8_t	sxfrctl1;
-	uint8_t	simode0;
-	uint8_t	simode1;
-	uint8_t	seltimer;
-	uint8_t	seqctl;
+struct ahc_aic7770_softc {
+	/*
+	 * Saved register state used for chip_init().
+	 */
+	uint8_t busspd;
+	uint8_t bustime;
+};
+
+struct ahc_pci_softc {
+	/*
+	 * Saved register state used for chip_init().
+	 */
+	uint32_t  devconfig;
+	uint16_t  targcrccnt;
+	uint8_t   command;
+	uint8_t   csize_lattime;
+	uint8_t   optionmode;
+	uint8_t   crccontrol1;
+	uint8_t   dscommand0;
+	uint8_t   dspcistatus;
+	uint8_t   scbbaddr;
+	uint8_t   dff_thrsh;
 };
 
-struct ahc_suspend_state {
-	struct	ahc_suspend_channel_state channel[2];
-	uint8_t	optionmode;
-	uint8_t	dscommand0;
-	uint8_t	dspcistatus;
-	/* hsmailbox */
-	uint8_t	crccontrol1;
-	uint8_t	scbbaddr;
-	/* Host and sequencer SCB counts */
-	uint8_t	dff_thrsh;
-	uint8_t	*scratch_ram;
-	uint8_t	*btt;
+union ahc_bus_softc {
+	struct ahc_aic7770_softc aic7770_softc;
+	struct ahc_pci_softc pci_softc;
 };
 
 typedef void (*ahc_bus_intr_t)(struct ahc_softc *);
+typedef int (*ahc_bus_chip_init_t)(struct ahc_softc *);
+typedef int (*ahc_bus_suspend_t)(struct ahc_softc *);
+typedef int (*ahc_bus_resume_t)(struct ahc_softc *);
 typedef void ahc_callback_t (void *);
 
 struct ahc_softc {
@@ -936,6 +945,11 @@ struct ahc_softc {
 	 */
 	struct scb_tailq	  untagged_queues[AHC_NUM_TARGETS];
 
+	/*
+	 * Bus attachment specific data.
+	 */
+	union ahc_bus_softc	  bus_softc;
+
 	/*
 	 * Platform specific data.
 	 */
@@ -951,6 +965,22 @@ struct ahc_softc {
 	 */
 	ahc_bus_intr_t		  bus_intr;
 
+	/*
+	 * Bus specific initialization required
+	 * after a chip reset.
+	 */
+	ahc_bus_chip_init_t	  bus_chip_init;
+
+	/*
+	 * Bus specific suspend routine.
+	 */
+	ahc_bus_suspend_t	  bus_suspend;
+
+	/*
+	 * Bus specific resume routine.
+	 */
+	ahc_bus_resume_t	  bus_resume;
+
 	/*
 	 * Target mode related state kept on a per enabled lun basis.
 	 * Targets that are not enabled will have null entries.
@@ -1043,9 +1073,6 @@ struct ahc_softc {
 	 */
 	bus_addr_t		  dma_bug_buf;
 
-	/* Information saved through suspend/resume cycles */
-	struct ahc_suspend_state  suspend_state;
-
 	/* Number of enabled target mode device on this card */
 	u_int			  enabled_luns;
 
@@ -1055,7 +1082,8 @@ struct ahc_softc {
 	/* PCI cacheline size. */
 	u_int			  pci_cachesize;
 
-	u_int			  stack_size;
+	/* Maximum number of sequencer instructions supported. */
+	u_int			  instruction_ram_size;
 
 	/* Per-Unit descriptive information */
 	const char		 *description;
@@ -1152,6 +1180,7 @@ int		ahc_match_scb(struct ahc_softc *ahc, struct scb *scb,
 struct ahc_softc	*ahc_alloc(void *platform_arg, char *name);
 int			 ahc_softc_init(struct ahc_softc *);
 void			 ahc_controller_info(struct ahc_softc *ahc, char *buf);
+int			 ahc_chip_init(struct ahc_softc *ahc);
 int			 ahc_init(struct ahc_softc *ahc);
 void			 ahc_intr_enable(struct ahc_softc *ahc, int enable);
 void			 ahc_pause_and_flushwork(struct ahc_softc *ahc);
@@ -1167,7 +1196,6 @@ int			 ahc_reset(struct ahc_softc *ahc);
 void			 ahc_shutdown(void *arg);
 
 /*************************** Interrupt Services *******************************/
-void			ahc_pci_intr(struct ahc_softc *ahc);
 void			ahc_clear_intstat(struct ahc_softc *ahc);
 void			ahc_run_qoutfifo(struct ahc_softc *ahc);
 #ifdef AHC_TARGET_MODE
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
index 7dc8f6d9ab69e1f8abd65588001887d2dba9dfdc..49bc1f2b37cc0c049eda6c6fb141c8bad0d1ea7c 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.reg
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg
@@ -39,7 +39,7 @@
  *
  * $FreeBSD$
  */
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -1580,7 +1580,7 @@ const BUS_32_BIT		0x02
 const MAX_OFFSET_8BIT		0x0f
 const MAX_OFFSET_16BIT		0x08
 const MAX_OFFSET_ULTRA2		0x7f
-const MAX_OFFSET		0xff
+const MAX_OFFSET		0x7f
 const HOST_MSG			0xff
 
 /* Target mode command processing constants */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 0eedbbae0200e7f5c6b9c4217c224dafae667ce8..507fda5a9662ef6a1debcf06b944d92748735061 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#112 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#124 $
  *
  * $FreeBSD$
  */
@@ -144,7 +144,8 @@ static struct ahc_syncrate ahc_syncrates[] =
 #include "aic7xxx_seq.h"
 
 /**************************** Function Declarations ***************************/
-static void		ahc_force_renegotiation(struct ahc_softc *ahc);
+static void		ahc_force_renegotiation(struct ahc_softc *ahc,
+						struct ahc_devinfo *devinfo);
 static struct ahc_tmode_tstate*
 			ahc_alloc_tstate(struct ahc_softc *ahc,
 					 u_int scsi_id, char channel);
@@ -224,7 +225,7 @@ static void		ahc_reset_current_bus(struct ahc_softc *ahc);
 #ifdef AHC_DUMP_SEQ
 static void		ahc_dumpseq(struct ahc_softc *ahc);
 #endif
-static void		ahc_loadseq(struct ahc_softc *ahc);
+static int		ahc_loadseq(struct ahc_softc *ahc);
 static int		ahc_check_patch(struct ahc_softc *ahc,
 					struct patch **start_patch,
 					u_int start_instr, u_int *skip_addr);
@@ -1032,14 +1033,15 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
 		 * we should look at the last phase the sequencer recorded,
 		 * or the current phase presented on the bus.
 		 */
-		u_int mesg_out;
-		u_int curphase;
-		u_int errorphase;
-		u_int lastphase;
-		u_int scsirate;
-		u_int i;
-		u_int sstat2;
-		int   silent;
+		struct	ahc_devinfo devinfo;
+		u_int	mesg_out;
+		u_int	curphase;
+		u_int	errorphase;
+		u_int	lastphase;
+		u_int	scsirate;
+		u_int	i;
+		u_int	sstat2;
+		int	silent;
 
 		lastphase = ahc_inb(ahc, LASTPHASE);
 		curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
@@ -1128,7 +1130,9 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
 		 * case we are out of sync for some external reason
 		 * unknown (or unreported) by the target.
 		 */
-		ahc_force_renegotiation(ahc);
+		ahc_fetch_devinfo(ahc, &devinfo);
+		ahc_force_renegotiation(ahc, &devinfo);
+
 		ahc_outb(ahc, CLRINT, CLRSCSIINT);
 		ahc_unpause(ahc);
 	} else if ((status & SELTO) != 0) {
@@ -1165,6 +1169,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
 			       ahc_name(ahc), scbptr, scb_index);
 			ahc_dump_card_state(ahc);
 		} else {
+			struct ahc_devinfo devinfo;
 #ifdef AHC_DEBUG
 			if ((ahc_debug & AHC_SHOW_SELTO) != 0) {
 				ahc_print_path(ahc, scb);
@@ -1181,7 +1186,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
 			 * a unit attention in this case, so we must always
 			 * renegotiate.
 			 */
-			ahc_force_renegotiation(ahc);
+			ahc_scb_devinfo(ahc, &devinfo, scb);
+			ahc_force_renegotiation(ahc, &devinfo);
 			ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
 			ahc_freeze_devq(ahc, scb);
 		}
@@ -1189,13 +1195,14 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
 		ahc_restart(ahc);
 	} else if ((status & BUSFREE) != 0
 		&& (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
-		u_int lastphase;
-		u_int saved_scsiid;
-		u_int saved_lun;
-		u_int target;
-		u_int initiator_role_id;
-		char channel;
-		int printerror;
+		struct	ahc_devinfo devinfo;
+		u_int	lastphase;
+		u_int	saved_scsiid;
+		u_int	saved_lun;
+		u_int	target;
+		u_int	initiator_role_id;
+		char	channel;
+		int	printerror;
 
 		/*
 		 * Clear our selection hardware as soon as possible.
@@ -1227,13 +1234,13 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
 		target = SCSIID_TARGET(ahc, saved_scsiid);
 		initiator_role_id = SCSIID_OUR_ID(saved_scsiid);
 		channel = SCSIID_CHANNEL(ahc, saved_scsiid);
+		ahc_compile_devinfo(&devinfo, initiator_role_id,
+				    target, saved_lun, channel, ROLE_INITIATOR);
 		printerror = 1;
 
 		if (lastphase == P_MESGOUT) {
-			struct ahc_devinfo devinfo;
 			u_int tag;
 
-			ahc_fetch_devinfo(ahc, &devinfo);
 			tag = SCB_LIST_NULL;
 			if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE)
 			 || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) {
@@ -1344,13 +1351,15 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
 				if (lastphase == ahc_phase_table[i].phase)
 					break;
 			}
-			/*
-			 * Renegotiate with this device at the
-			 * next oportunity just in case this busfree
-			 * is due to a negotiation mismatch with the
-			 * device.
-			 */
-			ahc_force_renegotiation(ahc);
+			if (lastphase != P_BUSFREE) {
+				/*
+				 * Renegotiate with this device at the
+				 * next oportunity just in case this busfree
+				 * is due to a negotiation mismatch with the
+				 * device.
+				 */
+				ahc_force_renegotiation(ahc, &devinfo);
+			}
 			printf("Unexpected busfree %s\n"
 			       "SEQADDR == 0x%x\n",
 			       ahc_phase_table[i].phasemsg,
@@ -1371,19 +1380,17 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
  * a command to the current device.
  */
 static void
-ahc_force_renegotiation(struct ahc_softc *ahc)
+ahc_force_renegotiation(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
 {
-	struct	ahc_devinfo devinfo;
 	struct	ahc_initiator_tinfo *targ_info;
 	struct	ahc_tmode_tstate *tstate;
 
-	ahc_fetch_devinfo(ahc, &devinfo);
 	targ_info = ahc_fetch_transinfo(ahc,
-					devinfo.channel,
-					devinfo.our_scsiid,
-					devinfo.target,
+					devinfo->channel,
+					devinfo->our_scsiid,
+					devinfo->target,
 					&tstate);
-	ahc_update_neg_request(ahc, &devinfo, tstate,
+	ahc_update_neg_request(ahc, devinfo, tstate,
 			       targ_info, AHC_NEG_IF_NON_ASYNC);
 }
 
@@ -3898,7 +3905,7 @@ ahc_softc_insert(struct ahc_softc *ahc)
 	 */
 	list_ahc = TAILQ_FIRST(&ahc_tailq);
 	while (list_ahc != NULL
-	    && ahc_softc_comp(list_ahc, ahc) <= 0)
+	    && ahc_softc_comp(ahc, list_ahc) <= 0)
 		list_ahc = TAILQ_NEXT(list_ahc, links);
 	if (list_ahc != NULL)
 		TAILQ_INSERT_BEFORE(list_ahc, ahc, links);
@@ -4038,6 +4045,7 @@ ahc_reset(struct ahc_softc *ahc)
 {
 	u_int	sblkctl;
 	u_int	sxfrctl1_a, sxfrctl1_b;
+	int	error;
 	int	wait;
 	
 	/*
@@ -4128,12 +4136,19 @@ ahc_reset(struct ahc_softc *ahc)
 	}
 	ahc_outb(ahc, SXFRCTL1, sxfrctl1_a);
 
+	error = 0;
+	if (ahc->init_level > 0)
+		/*
+		 * If a recovery action has forced a chip reset,
+		 * re-initialize the chip to our liking.
+		 */
+		error = ahc->bus_chip_init(ahc);
 #ifdef AHC_DUMP_SEQ
-	if (ahc->init_level == 0)
+	else 
 		ahc_dumpseq(ahc);
 #endif
 
-	return (0);
+	return (error);
 }
 
 /*
@@ -4203,6 +4218,14 @@ ahc_build_free_scb_list(struct ahc_softc *ahc)
 		ahc_outb(ahc, SCB_LUN, 0xFF);
 	}
 
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		/* SCB 0 heads the free list. */
+		ahc_outb(ahc, FREE_SCBH, 0);
+	} else {
+		/* No free list. */
+		ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
+	}
+
 	/* Make sure that the last SCB terminates the free list */
 	ahc_outb(ahc, SCBPTR, i-1);
 	ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);
@@ -4228,20 +4251,11 @@ ahc_init_scbdata(struct ahc_softc *ahc)
 	/* Determine the number of hardware SCBs and initialize them */
 
 	scb_data->maxhscbs = ahc_probe_scbs(ahc);
-	if ((ahc->flags & AHC_PAGESCBS) != 0) {
-		/* SCB 0 heads the free list */
-		ahc_outb(ahc, FREE_SCBH, 0);
-	} else {
-		ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
-	}
-
 	if (ahc->scb_data->maxhscbs == 0) {
 		printf("%s: No SCB space found\n", ahc_name(ahc));
 		return (ENXIO);
 	}
 
-	ahc_build_free_scb_list(ahc);
-
 	/*
 	 * Create our DMA tags.  These tags define the kinds of device
 	 * accessible memory allocations and memory mappings we will
@@ -4343,10 +4357,9 @@ ahc_init_scbdata(struct ahc_softc *ahc)
 	}
 
 	/*
-	 * Tell the sequencer which SCB will be the next one it receives.
+	 * Reserve the next queued SCB.
 	 */
 	ahc->next_queued_scb = ahc_get_scb(ahc);
-	ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
 
 	/*
 	 * Note that we were successfull
@@ -4531,6 +4544,192 @@ ahc_controller_info(struct ahc_softc *ahc, char *buf)
 		sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs);
 }
 
+int
+ahc_chip_init(struct ahc_softc *ahc)
+{
+	int	 term;
+	int	 error;
+	u_int	 i;
+	u_int	 scsi_conf;
+	u_int	 scsiseq_template;
+	uint32_t physaddr;
+
+	ahc_outb(ahc, SEQ_FLAGS, 0);
+	ahc_outb(ahc, SEQ_FLAGS2, 0);
+
+	/* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/
+	if (ahc->features & AHC_TWIN) {
+
+		/*
+		 * Setup Channel B first.
+		 */
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
+		term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0;
+		ahc_outb(ahc, SCSIID, ahc->our_id_b);
+		scsi_conf = ahc_inb(ahc, SCSICONF + 1);
+		ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
+					|term|ahc->seltime_b|ENSTIMER|ACTNEGEN);
+		if ((ahc->features & AHC_ULTRA2) != 0)
+			ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
+		ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+		ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+
+		/* Select Channel A */
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
+	}
+	term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0;
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
+	else
+		ahc_outb(ahc, SCSIID, ahc->our_id);
+	scsi_conf = ahc_inb(ahc, SCSICONF);
+	ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
+				|term|ahc->seltime
+				|ENSTIMER|ACTNEGEN);
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
+	ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+	ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+
+	/* There are no untagged SCBs active yet. */
+	for (i = 0; i < 16; i++) {
+		ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0));
+		if ((ahc->flags & AHC_SCB_BTT) != 0) {
+			int lun;
+
+			/*
+			 * The SCB based BTT allows an entry per
+			 * target and lun pair.
+			 */
+			for (lun = 1; lun < AHC_NUM_LUNS; lun++)
+				ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun));
+		}
+	}
+
+	/* All of our queues are empty */
+	for (i = 0; i < 256; i++)
+		ahc->qoutfifo[i] = SCB_LIST_NULL;
+	ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD);
+
+	for (i = 0; i < 256; i++)
+		ahc->qinfifo[i] = SCB_LIST_NULL;
+
+	if ((ahc->features & AHC_MULTI_TID) != 0) {
+		ahc_outb(ahc, TARGID, 0);
+		ahc_outb(ahc, TARGID + 1, 0);
+	}
+
+	/*
+	 * Tell the sequencer where it can find our arrays in memory.
+	 */
+	physaddr = ahc->scb_data->hscb_busaddr;
+	ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF);
+	ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF);
+	ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF);
+	ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF);
+
+	physaddr = ahc->shared_data_busaddr;
+	ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF);
+	ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF);
+	ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF);
+	ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF);
+
+	/*
+	 * Initialize the group code to command length table.
+	 * This overrides the values in TARG_SCSIRATE, so only
+	 * setup the table after we have processed that information.
+	 */
+	ahc_outb(ahc, CMDSIZE_TABLE, 5);
+	ahc_outb(ahc, CMDSIZE_TABLE + 1, 9);
+	ahc_outb(ahc, CMDSIZE_TABLE + 2, 9);
+	ahc_outb(ahc, CMDSIZE_TABLE + 3, 0);
+	ahc_outb(ahc, CMDSIZE_TABLE + 4, 15);
+	ahc_outb(ahc, CMDSIZE_TABLE + 5, 11);
+	ahc_outb(ahc, CMDSIZE_TABLE + 6, 0);
+	ahc_outb(ahc, CMDSIZE_TABLE + 7, 0);
+		
+	if ((ahc->features & AHC_HS_MAILBOX) != 0)
+		ahc_outb(ahc, HS_MAILBOX, 0);
+
+	/* Tell the sequencer of our initial queue positions */
+	if ((ahc->features & AHC_TARGETMODE) != 0) {
+		ahc->tqinfifonext = 1;
+		ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
+		ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
+	}
+	ahc->qinfifonext = 0;
+	ahc->qoutfifonext = 0;
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256);
+		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+		ahc_outb(ahc, SNSCB_QOFF, ahc->qinfifonext);
+		ahc_outb(ahc, SDSCB_QOFF, 0);
+	} else {
+		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+		ahc_outb(ahc, QINPOS, ahc->qinfifonext);
+		ahc_outb(ahc, QOUTPOS, ahc->qoutfifonext);
+	}
+
+	/* We don't have any waiting selections */
+	ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL);
+
+	/* Our disconnection list is empty too */
+	ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);
+
+	/* Message out buffer starts empty */
+	ahc_outb(ahc, MSG_OUT, MSG_NOOP);
+
+	/*
+	 * Setup the allowed SCSI Sequences based on operational mode.
+	 * If we are a target, we'll enalbe select in operations once
+	 * we've had a lun enabled.
+	 */
+	scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP;
+	if ((ahc->flags & AHC_INITIATORROLE) != 0)
+		scsiseq_template |= ENRSELI;
+	ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template);
+
+	/* Initialize our list of free SCBs. */
+	ahc_build_free_scb_list(ahc);
+
+	/*
+	 * Tell the sequencer which SCB will be the next one it receives.
+	 */
+	ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
+
+	/*
+	 * Load the Sequencer program and Enable the adapter
+	 * in "fast" mode.
+	 */
+	if (bootverbose)
+		printf("%s: Downloading Sequencer Program...",
+		       ahc_name(ahc));
+
+	error = ahc_loadseq(ahc);
+	if (error != 0)
+		return (error);
+
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		int wait;
+
+		/*
+		 * Wait for up to 500ms for our transceivers
+		 * to settle.  If the adapter does not have
+		 * a cable attached, the transceivers may
+		 * never settle, so don't complain if we
+		 * fail here.
+		 */
+		ahc_pause(ahc);
+		for (wait = 5000;
+		     (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
+		     wait--)
+			ahc_delay(100);
+		ahc_unpause(ahc);
+	}
+
+	return (0);
+}
+
 /*
  * Start the board, ready for normal operation
  */
@@ -4538,15 +4737,12 @@ int
 ahc_init(struct ahc_softc *ahc)
 {
 	int	 max_targ;
-	int	 i;
-	int	 term;
+	u_int	 i;
 	u_int	 scsi_conf;
-	u_int	 scsiseq_template;
 	u_int	 ultraenb;
 	u_int	 discenable;
 	u_int	 tagenable;
 	size_t	 driver_data_size;
-	uint32_t physaddr;
 
 #ifdef AHC_DEBUG
 	if ((ahc_debug & AHC_DEBUG_SEQUENCER) != 0)
@@ -4600,7 +4796,9 @@ ahc_init(struct ahc_softc *ahc)
 	/* DMA tag for mapping buffers into device visible space. */
 	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
 			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
-			       /*lowaddr*/BUS_SPACE_MAXADDR,
+			       /*lowaddr*/ahc->flags & AHC_39BIT_ADDRESSING
+					? (bus_addr_t)0x7FFFFFFFFFULL
+					: BUS_SPACE_MAXADDR_32BIT,
 			       /*highaddr*/BUS_SPACE_MAXADDR,
 			       /*filter*/NULL, /*filterarg*/NULL,
 			       /*maxsize*/(AHC_NSEG - 1) * PAGE_SIZE,
@@ -4664,9 +4862,6 @@ ahc_init(struct ahc_softc *ahc)
 		for (i = 0; i < AHC_TMODE_CMDS; i++)
 			ahc->targetcmds[i].cmd_valid = 0;
 		ahc_sync_tqinfifo(ahc, BUS_DMASYNC_PREREAD);
-		ahc->tqinfifonext = 1;
-		ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
-		ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
 		ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256];
 	}
 	ahc->qinfifo = &ahc->qoutfifo[256];
@@ -4697,9 +4892,6 @@ ahc_init(struct ahc_softc *ahc)
 		}
 	}
 
-	ahc_outb(ahc, SEQ_FLAGS, 0);
-	ahc_outb(ahc, SEQ_FLAGS2, 0);
-
 	if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) {
 		ahc->flags |= AHC_PAGESCBS;
 	} else {
@@ -4708,62 +4900,31 @@ ahc_init(struct ahc_softc *ahc)
 
 #ifdef AHC_DEBUG
 	if (ahc_debug & AHC_SHOW_MISC) {
-		printf("%s: hardware scb %Zu bytes; kernel scb %Zu bytes; "
-		       "ahc_dma %Zu bytes\n",
+		printf("%s: hardware scb %u bytes; kernel scb %u bytes; "
+		       "ahc_dma %u bytes\n",
 			ahc_name(ahc),
-			sizeof(struct hardware_scb),
-			sizeof(struct scb),
-			sizeof(struct ahc_dma_seg));
+			(u_int)sizeof(struct hardware_scb),
+			(u_int)sizeof(struct scb),
+			(u_int)sizeof(struct ahc_dma_seg));
 	}
 #endif /* AHC_DEBUG */
 
-	/* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/
+	/*
+	 * Look at the information that board initialization or
+	 * the board bios has left us.
+	 */
 	if (ahc->features & AHC_TWIN) {
-
-		/*
-		 * The device is gated to channel B after a chip reset,
-		 * so set those values first
-		 */
-		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
-		term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0;
-		ahc_outb(ahc, SCSIID, ahc->our_id_b);
 		scsi_conf = ahc_inb(ahc, SCSICONF + 1);
-		ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
-					|term|ahc->seltime_b|ENSTIMER|ACTNEGEN);
-		if ((ahc->features & AHC_ULTRA2) != 0)
-			ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
-		ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
-		ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
-
 		if ((scsi_conf & RESET_SCSI) != 0
 		 && (ahc->flags & AHC_INITIATORROLE) != 0)
 			ahc->flags |= AHC_RESET_BUS_B;
-
-		/* Select Channel A */
-		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
 	}
-	term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0;
-	if ((ahc->features & AHC_ULTRA2) != 0)
-		ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
-	else
-		ahc_outb(ahc, SCSIID, ahc->our_id);
-	scsi_conf = ahc_inb(ahc, SCSICONF);
-	ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
-				|term|ahc->seltime
-				|ENSTIMER|ACTNEGEN);
-	if ((ahc->features & AHC_ULTRA2) != 0)
-		ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
-	ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
-	ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
 
+	scsi_conf = ahc_inb(ahc, SCSICONF);
 	if ((scsi_conf & RESET_SCSI) != 0
 	 && (ahc->flags & AHC_INITIATORROLE) != 0)
 		ahc->flags |= AHC_RESET_BUS_A;
 
-	/*
-	 * Look at the information that board initialization or
-	 * the board bios has left us.
-	 */
 	ultraenb = 0;	
 	tagenable = ALL_TARGETS_MASK;
 
@@ -4815,7 +4976,7 @@ ahc_init(struct ahc_softc *ahc)
 			 * connection type we have with the target.
 			 */
 			tinfo->user.period = ahc_syncrates->period;
-			tinfo->user.offset = ~0;
+			tinfo->user.offset = MAX_OFFSET;
 		} else {
 			u_int scsirate;
 			uint16_t mask;
@@ -4850,7 +5011,7 @@ ahc_init(struct ahc_softc *ahc)
 				if (offset == 0)
 					tinfo->user.period = 0;
 				else
-					tinfo->user.offset = ~0;
+					tinfo->user.offset = MAX_OFFSET;
 				if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/
 				 && (ahc->features & AHC_DT) != 0)
 					tinfo->user.ppr_options =
@@ -4868,7 +5029,7 @@ ahc_init(struct ahc_softc *ahc)
 						   ? AHC_SYNCRATE_ULTRA
 						   : AHC_SYNCRATE_FAST);
 				if (tinfo->user.period != 0)
-					tinfo->user.offset = ~0;
+					tinfo->user.offset = MAX_OFFSET;
 			}
 			if (tinfo->user.period == 0)
 				tinfo->user.offset = 0;
@@ -4890,127 +5051,7 @@ ahc_init(struct ahc_softc *ahc)
 	ahc->user_discenable = discenable;
 	ahc->user_tagenable = tagenable;
 
-	/* There are no untagged SCBs active yet. */
-	for (i = 0; i < 16; i++) {
-		ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0));
-		if ((ahc->flags & AHC_SCB_BTT) != 0) {
-			int lun;
-
-			/*
-			 * The SCB based BTT allows an entry per
-			 * target and lun pair.
-			 */
-			for (lun = 1; lun < AHC_NUM_LUNS; lun++)
-				ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun));
-		}
-	}
-
-	/* All of our queues are empty */
-	for (i = 0; i < 256; i++)
-		ahc->qoutfifo[i] = SCB_LIST_NULL;
-	ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD);
-
-	for (i = 0; i < 256; i++)
-		ahc->qinfifo[i] = SCB_LIST_NULL;
-
-	if ((ahc->features & AHC_MULTI_TID) != 0) {
-		ahc_outb(ahc, TARGID, 0);
-		ahc_outb(ahc, TARGID + 1, 0);
-	}
-
-	/*
-	 * Tell the sequencer where it can find our arrays in memory.
-	 */
-	physaddr = ahc->scb_data->hscb_busaddr;
-	ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF);
-	ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF);
-	ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF);
-	ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF);
-
-	physaddr = ahc->shared_data_busaddr;
-	ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF);
-	ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF);
-	ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF);
-	ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF);
-
-	/*
-	 * Initialize the group code to command length table.
-	 * This overrides the values in TARG_SCSIRATE, so only
-	 * setup the table after we have processed that information.
-	 */
-	ahc_outb(ahc, CMDSIZE_TABLE, 5);
-	ahc_outb(ahc, CMDSIZE_TABLE + 1, 9);
-	ahc_outb(ahc, CMDSIZE_TABLE + 2, 9);
-	ahc_outb(ahc, CMDSIZE_TABLE + 3, 0);
-	ahc_outb(ahc, CMDSIZE_TABLE + 4, 15);
-	ahc_outb(ahc, CMDSIZE_TABLE + 5, 11);
-	ahc_outb(ahc, CMDSIZE_TABLE + 6, 0);
-	ahc_outb(ahc, CMDSIZE_TABLE + 7, 0);
-		
-	/* Tell the sequencer of our initial queue positions */
-	ahc_outb(ahc, KERNEL_QINPOS, 0);
-	ahc_outb(ahc, QINPOS, 0);
-	ahc_outb(ahc, QOUTPOS, 0);
-
-	/*
-	 * Use the built in queue management registers
-	 * if they are available.
-	 */
-	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
-		ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256);
-		ahc_outb(ahc, SDSCB_QOFF, 0);
-		ahc_outb(ahc, SNSCB_QOFF, 0);
-		ahc_outb(ahc, HNSCB_QOFF, 0);
-	}
-
-
-	/* We don't have any waiting selections */
-	ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL);
-
-	/* Our disconnection list is empty too */
-	ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);
-
-	/* Message out buffer starts empty */
-	ahc_outb(ahc, MSG_OUT, MSG_NOOP);
-
-	/*
-	 * Setup the allowed SCSI Sequences based on operational mode.
-	 * If we are a target, we'll enalbe select in operations once
-	 * we've had a lun enabled.
-	 */
-	scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP;
-	if ((ahc->flags & AHC_INITIATORROLE) != 0)
-		scsiseq_template |= ENRSELI;
-	ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template);
-
-	/*
-	 * Load the Sequencer program and Enable the adapter
-	 * in "fast" mode.
-	 */
-	if (bootverbose)
-		printf("%s: Downloading Sequencer Program...",
-		       ahc_name(ahc));
-
-	ahc_loadseq(ahc);
-
-	if ((ahc->features & AHC_ULTRA2) != 0) {
-		int wait;
-
-		/*
-		 * Wait for up to 500ms for our transceivers
-		 * to settle.  If the adapter does not have
-		 * a cable attached, the transceivers may
-		 * never settle, so don't complain if we
-		 * fail here.
-		 */
-		ahc_pause(ahc);
-		for (wait = 5000;
-		     (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
-		     wait--)
-			ahc_delay(100);
-		ahc_unpause(ahc);
-	}
-	return (0);
+	return (ahc->bus_chip_init(ahc));
 }
 
 void
@@ -5046,7 +5087,6 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
 
 	maxloops = 1000;
 	ahc->flags |= AHC_ALL_INTERRUPTS;
-	intstat = 0;
 	paused = FALSE;
 	do {
 		if (paused)
@@ -5056,10 +5096,10 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
 		paused = TRUE;
 		ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO);
 		ahc_clear_critical_section(ahc);
-		if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
-			break;
+		intstat = ahc_inb(ahc, INTSTAT);
 	} while (--maxloops
-	      && (((intstat = ahc_inb(ahc, INTSTAT)) & INT_PEND) != 0
+	      && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0)
+	      && ((intstat & INT_PEND) != 0
 	       || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO))));
 	if (maxloops == 0) {
 		printf("Infinite interrupt loop, INTSTAT = %x",
@@ -5072,13 +5112,13 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
 int
 ahc_suspend(struct ahc_softc *ahc)
 {
-	uint8_t *ptr;
-	int	 i;
 
 	ahc_pause_and_flushwork(ahc);
 
-	if (LIST_FIRST(&ahc->pending_scbs) != NULL)
+	if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
+		ahc_unpause(ahc);
 		return (EBUSY);
+	}
 
 #if AHC_TARGET_MODE
 	/*
@@ -5086,73 +5126,11 @@ ahc_suspend(struct ahc_softc *ahc)
 	 * Perhaps we should just refuse to be suspended if we
 	 * are acting in a target role.
 	 */
-	if (ahc->pending_device != NULL)
+	if (ahc->pending_device != NULL) {
+		ahc_unpause(ahc);
 		return (EBUSY);
-#endif
-
-	/* Save volatile registers */
-	if ((ahc->features & AHC_TWIN) != 0) {
-		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
-		ahc->suspend_state.channel[1].scsiseq = ahc_inb(ahc, SCSISEQ);
-		ahc->suspend_state.channel[1].sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
-		ahc->suspend_state.channel[1].sxfrctl1 = ahc_inb(ahc, SXFRCTL1);
-		ahc->suspend_state.channel[1].simode0 = ahc_inb(ahc, SIMODE0);
-		ahc->suspend_state.channel[1].simode1 = ahc_inb(ahc, SIMODE1);
-		ahc->suspend_state.channel[1].seltimer = ahc_inb(ahc, SELTIMER);
-		ahc->suspend_state.channel[1].seqctl = ahc_inb(ahc, SEQCTL);
-		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
-	}
-	ahc->suspend_state.channel[0].scsiseq = ahc_inb(ahc, SCSISEQ);
-	ahc->suspend_state.channel[0].sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
-	ahc->suspend_state.channel[0].sxfrctl1 = ahc_inb(ahc, SXFRCTL1);
-	ahc->suspend_state.channel[0].simode0 = ahc_inb(ahc, SIMODE0);
-	ahc->suspend_state.channel[0].simode1 = ahc_inb(ahc, SIMODE1);
-	ahc->suspend_state.channel[0].seltimer = ahc_inb(ahc, SELTIMER);
-	ahc->suspend_state.channel[0].seqctl = ahc_inb(ahc, SEQCTL);
-
-	if ((ahc->chip & AHC_PCI) != 0) {
-		ahc->suspend_state.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
-		ahc->suspend_state.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
-	}
-
-	if ((ahc->features & AHC_DT) != 0) {
-		u_int sfunct;
-
-		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
-		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
-		ahc->suspend_state.optionmode = ahc_inb(ahc, OPTIONMODE);
-		ahc_outb(ahc, SFUNCT, sfunct);
-		ahc->suspend_state.crccontrol1 = ahc_inb(ahc, CRCCONTROL1);
-	}
-
-	if ((ahc->features & AHC_MULTI_FUNC) != 0)
-		ahc->suspend_state.scbbaddr = ahc_inb(ahc, SCBBADDR);
-
-	if ((ahc->features & AHC_ULTRA2) != 0)
-		ahc->suspend_state.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
-
-	ptr = ahc->suspend_state.scratch_ram;
-	for (i = 0; i < 64; i++)
-		*ptr++ = ahc_inb(ahc, SRAM_BASE + i);
-
-	if ((ahc->features & AHC_MORE_SRAM) != 0) {
-		for (i = 0; i < 16; i++)
-			*ptr++ = ahc_inb(ahc, TARG_OFFSET + i);
-	}
-
-	ptr = ahc->suspend_state.btt;
-	if ((ahc->flags & AHC_SCB_BTT) != 0) {
-		for (i = 0;i < AHC_NUM_TARGETS; i++) {
-			int j;
-
-			for (j = 0;j < AHC_NUM_LUNS; j++) {
-				u_int tcl;
-
-				tcl = BUILD_TCL(i << 4, j);
-				*ptr = ahc_index_busy_tcl(ahc, tcl);
-			}
-		}
 	}
+#endif
 	ahc_shutdown(ahc);
 	return (0);
 }
@@ -5160,81 +5138,8 @@ ahc_suspend(struct ahc_softc *ahc)
 int
 ahc_resume(struct ahc_softc *ahc)
 {
-	uint8_t *ptr;
-	int	 i;
 
 	ahc_reset(ahc);
-
-	ahc_build_free_scb_list(ahc);
-
-	/* Restore volatile registers */
-	if ((ahc->features & AHC_TWIN) != 0) {
-		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
-		ahc_outb(ahc, SCSIID, ahc->our_id);
-		ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[1].scsiseq);
-		ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[1].sxfrctl0);
-		ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[1].sxfrctl1);
-		ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[1].simode0);
-		ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[1].simode1);
-		ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[1].seltimer);
-		ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[1].seqctl);
-		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
-	}
-	ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[0].scsiseq);
-	ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[0].sxfrctl0);
-	ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[0].sxfrctl1);
-	ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[0].simode0);
-	ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[0].simode1);
-	ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[0].seltimer);
-	ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[0].seqctl);
-	if ((ahc->features & AHC_ULTRA2) != 0)
-		ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
-	else
-		ahc_outb(ahc, SCSIID, ahc->our_id);
-
-	if ((ahc->chip & AHC_PCI) != 0) {
-		ahc_outb(ahc, DSCOMMAND0, ahc->suspend_state.dscommand0);
-		ahc_outb(ahc, DSPCISTATUS, ahc->suspend_state.dspcistatus);
-	}
-
-	if ((ahc->features & AHC_DT) != 0) {
-		u_int sfunct;
-
-		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
-		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
-		ahc_outb(ahc, OPTIONMODE, ahc->suspend_state.optionmode);
-		ahc_outb(ahc, SFUNCT, sfunct);
-		ahc_outb(ahc, CRCCONTROL1, ahc->suspend_state.crccontrol1);
-	}
-
-	if ((ahc->features & AHC_MULTI_FUNC) != 0)
-		ahc_outb(ahc, SCBBADDR, ahc->suspend_state.scbbaddr);
-
-	if ((ahc->features & AHC_ULTRA2) != 0)
-		ahc_outb(ahc, DFF_THRSH, ahc->suspend_state.dff_thrsh);
-
-	ptr = ahc->suspend_state.scratch_ram;
-	for (i = 0; i < 64; i++)
-		ahc_outb(ahc, SRAM_BASE + i, *ptr++);
-
-	if ((ahc->features & AHC_MORE_SRAM) != 0) {
-		for (i = 0; i < 16; i++)
-			ahc_outb(ahc, TARG_OFFSET + i, *ptr++);
-	}
-
-	ptr = ahc->suspend_state.btt;
-	if ((ahc->flags & AHC_SCB_BTT) != 0) {
-		for (i = 0;i < AHC_NUM_TARGETS; i++) {
-			int j;
-
-			for (j = 0;j < AHC_NUM_LUNS; j++) {
-				u_int tcl;
-
-				tcl = BUILD_TCL(i << 4, j);
-				ahc_busy_tcl(ahc, tcl, *ptr);
-			}
-		}
-	}
 	return (0);
 }
 
@@ -6379,19 +6284,11 @@ void
 ahc_dumpseq(struct ahc_softc* ahc)
 {
 	int i;
-	int max_prog;
-
-	if ((ahc->chip & AHC_BUS_MASK) < AHC_PCI)
-		max_prog = 448;
-	else if ((ahc->features & AHC_ULTRA2) != 0)
-		max_prog = 768;
-	else
-		max_prog = 512;
 
 	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
 	ahc_outb(ahc, SEQADDR0, 0);
 	ahc_outb(ahc, SEQADDR1, 0);
-	for (i = 0; i < max_prog; i++) {
+	for (i = 0; i < ahc->instruction_ram_size; i++) {
 		uint8_t ins_bytes[4];
 
 		ahc_insb(ahc, SEQRAM, ins_bytes, 4);
@@ -6403,7 +6300,7 @@ ahc_dumpseq(struct ahc_softc* ahc)
 }
 #endif
 
-static void
+static int
 ahc_loadseq(struct ahc_softc *ahc)
 {
 	struct	cs cs_table[num_critical_sections];
@@ -6413,9 +6310,9 @@ ahc_loadseq(struct ahc_softc *ahc)
 	u_int	cs_count;
 	u_int	cur_cs;
 	u_int	i;
-	int	downloaded;
 	u_int	skip_addr;
 	u_int	sg_prefetch_cnt;
+	int	downloaded;
 	uint8_t	download_consts[7];
 
 	/*
@@ -6456,6 +6353,19 @@ ahc_loadseq(struct ahc_softc *ahc)
 			 */
 			continue;
 		}
+
+		if (downloaded == ahc->instruction_ram_size) {
+			/*
+			 * We're about to exceed the instruction
+			 * storage capacity for this chip.  Fail
+			 * the load.
+			 */
+			printf("\n%s: Program too large for instruction memory "
+			       "size of %d!\n", ahc_name(ahc),
+			       ahc->instruction_ram_size);
+			return (ENOMEM);
+		}
+
 		/*
 		 * Move through the CS table until we find a CS
 		 * that might apply to this instruction.
@@ -6498,6 +6408,7 @@ ahc_loadseq(struct ahc_softc *ahc)
 		printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
 		       ahc_name(ahc), ahc->features, ahc->bugs, ahc->flags);
 	}
+	return (0);
 }
 
 static int
@@ -6942,11 +6853,12 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
 	struct	   ahc_tmode_lstate *lstate;
 	struct	   ccb_en_lun *cel;
 	cam_status status;
+	u_long	   s;
 	u_int	   target;
 	u_int	   lun;
 	u_int	   target_mask;
 	u_int	   our_id;
-	u_long	   s;
+	int	   error;
 	char	   channel;
 
 	status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate,
@@ -7023,7 +6935,8 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
 	 */
 	if ((ahc->flags & AHC_TARGETROLE) == 0
 	 && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
-		u_long	s;
+		u_long	 s;
+		ahc_flag saved_flags;
 
 		printf("Configuring Target Mode\n");
 		ahc_lock(ahc, &s);
@@ -7032,11 +6945,28 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
 			ahc_unlock(ahc, &s);
 			return;
 		}
+		saved_flags = ahc->flags;
 		ahc->flags |= AHC_TARGETROLE;
 		if ((ahc->features & AHC_MULTIROLE) == 0)
 			ahc->flags &= ~AHC_INITIATORROLE;
 		ahc_pause(ahc);
-		ahc_loadseq(ahc);
+		error = ahc_loadseq(ahc);
+		if (error != 0) {
+			/*
+			 * Restore original configuration and notify
+			 * the caller that we cannot support target mode.
+			 * Since the adapter started out in this
+			 * configuration, the firmware load will succeed,
+			 * so there is no point in checking ahc_loadseq's
+			 * return value.
+			 */
+			ahc->flags = saved_flags;
+			(void)ahc_loadseq(ahc);
+			ahc_unpause(ahc);
+			ahc_unlock(ahc, &s);
+			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+			return;
+		}
 		ahc_unlock(ahc, &s);
 	}
 	cel = &ccb->cel;
@@ -7272,7 +7202,11 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
 				ahc->flags &= ~AHC_TARGETROLE;
 				ahc->flags |= AHC_INITIATORROLE;
 				ahc_pause(ahc);
-				ahc_loadseq(ahc);
+				/*
+				 * Returning to a configuration that
+				 * fit previously will always succeed.
+				 */
+				(void)ahc_loadseq(ahc);
 			}
 		}
 		ahc_unpause(ahc);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h
index c38b0cb97d360f369c2af121ade53e3355e30e68..f0fe05c23349744894e5f020861744026a9c3983 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_inline.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#39 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#40 $
  *
  * $FreeBSD$
  */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 2e32a59cbf700d6dfe34e917c241a1d5ffb57f9f..4c5389c237e8bf6d5d40aa8b448d40f8b54156e7 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC7xxx device driver for Linux.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#179 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#206 $
  *
  * Copyright (c) 1994 John Aycock
  *   The University of Calgary Department of Computer Science.
@@ -488,12 +488,11 @@ MODULE_PARM_DESC(aic7xxx,
 "				(0/256ms,1/128ms,2/64ms,3/32ms)\n"
 "\n"
 "	Sample /etc/modules.conf line:\n"
-"		Enable verbose logging\n"
-"		Disable EISA/VLB probing\n"
+"		Toggle EISA/VLB probing\n"
 "		Set tag depth on Controller 1/Target 2 to 10 tags\n"
 "		Shorten the selection timeout to 128ms\n"
 "\n"
-"	options aic7xxx='\"verbose.no_probe.tag_info:{{}.{..10}}.seltime:1\"'\n"
+"	options aic7xxx 'aic7xxx=no_probe.tag_info:{{}.{..10}}.seltime:1'\n"
 );
 #endif
 
@@ -513,6 +512,7 @@ static void ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc);
 static void ahc_linux_start_dv(struct ahc_softc *ahc);
 static void ahc_linux_dv_timeout(struct scsi_cmnd *cmd);
 static int  ahc_linux_dv_thread(void *data);
+static void ahc_linux_kill_dv_thread(struct ahc_softc *ahc);
 static void ahc_linux_dv_target(struct ahc_softc *ahc, u_int target);
 static void ahc_linux_dv_transition(struct ahc_softc *ahc,
 				    struct scsi_cmnd *cmd,
@@ -565,9 +565,9 @@ static void			ahc_linux_free_device(struct ahc_softc*,
 						      struct ahc_linux_device*);
 static void ahc_linux_run_device_queue(struct ahc_softc*,
 				       struct ahc_linux_device*);
-static void ahc_linux_setup_tag_info(char *p, char *end, char *s);
 static void ahc_linux_setup_tag_info_global(char *p);
-static void ahc_linux_setup_dv(char *p, char *end, char *s);
+static aic_option_callback_t ahc_linux_setup_tag_info;
+static aic_option_callback_t ahc_linux_setup_dv;
 static int  aic7xxx_setup(char *s);
 static int  ahc_linux_next_unit(void);
 static void ahc_runq_tasklet(unsigned long data);
@@ -620,6 +620,9 @@ ahc_schedule_completeq(struct ahc_softc *ahc, struct ahc_cmd *acmd)
 	}
 }
 
+/*
+ * Must be called with our lock held.
+ */
 static __inline void
 ahc_schedule_runq(struct ahc_softc *ahc)
 {
@@ -666,8 +669,8 @@ ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd)
 	u_long	done_flags;
 	int	with_errors;
 
-	ahc_done_lock(ahc, &done_flags);
 	with_errors = 0;
+	ahc_done_lock(ahc, &done_flags);
 	while (acmd != NULL) {
 		Scsi_Cmnd *cmd;
 
@@ -995,9 +998,13 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
 	dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
 				   cmd->device->lun, /*alloc*/TRUE);
 	if (dev == NULL) {
+		ahc_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);
+		ahc_linux_queue_cmd_complete(ahc, cmd);
+		ahc_schedule_completeq(ahc, NULL);
 		ahc_midlayer_entrypoint_unlock(ahc, &flags);
-		printf("aic7xxx_linux_queue: Unable to allocate device!\n");
-		return (-ENOMEM);
+		printf("%s: aic7xxx_linux_queue - Unable to allocate device!\n",
+		       ahc_name(ahc));
+		return (0);
 	}
 	cmd->result = CAM_REQ_INPROG << 16;
 	TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe);
@@ -1094,7 +1101,7 @@ ahc_linux_select_queue_depth(struct Scsi_Host * host,
 	u_long	flags;
 
 	ahc = *((struct ahc_softc **)host->hostdata);
-	ahc_midlayer_entrypoint_lock(ahc, &flags);
+	ahc_lock(ahc, &flags);
 	for (device = scsi_devs; device != NULL; device = device->next) {
 		if (device->host == host) {
 			struct	 ahc_linux_device *dev;
@@ -1127,7 +1134,7 @@ ahc_linux_select_queue_depth(struct Scsi_Host * host,
 			}
 		}
 	}
-	ahc_midlayer_entrypoint_unlock(ahc, &flags);
+	ahc_unlock(ahc, &flags);
 }
 #endif
 
@@ -1238,30 +1245,23 @@ ahc_linux_bus_reset(Scsi_Cmnd *cmd)
 	int    found;
 
 	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_unlock_irq(&io_request_lock);
-#endif
 	ahc_midlayer_entrypoint_lock(ahc, &s);
 	found = ahc_reset_channel(ahc, cmd->device->channel + 'A',
 				  /*initiate reset*/TRUE);
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
-	ahc_midlayer_entrypoint_unlock(ahc, &s);
-	if (bootverbose)
-		printf("%s: SCSI bus reset delivered. "
-		       "%d SCBs aborted.\n", ahc_name(ahc), found);
 
 	if (acmd != NULL) {
 		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL) {
-			ahc_midlayer_entrypoint_lock(ahc, &s);
+		if (acmd != NULL)
 			ahc_schedule_completeq(ahc, acmd);
-			ahc_midlayer_entrypoint_unlock(ahc, &s);
-		}
 	}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_lock_irq(&io_request_lock);
-#endif
+	ahc_midlayer_entrypoint_unlock(ahc, &s);
+
+	if (bootverbose)
+		printf("%s: SCSI bus reset delivered. "
+		       "%d SCBs aborted.\n", ahc_name(ahc), found);
+
 	return SUCCESS;
 }
 
@@ -1291,7 +1291,7 @@ Scsi_Host_Template aic7xxx_driver_template = {
 	.max_sectors		= 8192,
 #endif
 #if defined CONFIG_HIGHIO || LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
 /* Assume RedHat Distribution with its different HIGHIO conventions. */
 	.can_dma_32		= 1,
 	.single_sg_okay		= 1,
@@ -1313,15 +1313,25 @@ Scsi_Host_Template aic7xxx_driver_template = {
 
 /**************************** Tasklet Handler *********************************/
 
+/*
+ * In 2.4.X and above, this routine is called from a tasklet,
+ * so we must re-acquire our lock prior to executing this code.
+ * In all prior kernels, ahc_schedule_runq() calls this routine
+ * directly and ahc_schedule_runq() is called with our lock held.
+ */
 static void
 ahc_runq_tasklet(unsigned long data)
 {
 	struct ahc_softc* ahc;
 	struct ahc_linux_device *dev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	u_long flags;
+#endif
 
 	ahc = (struct ahc_softc *)data;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	ahc_lock(ahc, &flags);
+#endif
 	while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) {
 	
 		TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links);
@@ -1331,7 +1341,9 @@ ahc_runq_tasklet(unsigned long data)
 		ahc_unlock(ahc, &flags);
 		ahc_lock(ahc, &flags);
 	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	ahc_unlock(ahc, &flags);
+#endif
 }
 
 /************************ Shutdown/halt/reboot hook ***************************/
@@ -1495,6 +1507,12 @@ ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map)
 }
 
 /********************* Platform Dependent Functions ***************************/
+/*
+ * Compare "left hand" softc with "right hand" softc, returning:
+ * < 0 - lahc has a lower priority than rahc
+ *   0 - Softcs are equal
+ * > 0 - lahc has a higher priority than rahc
+ */
 int
 ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
 {
@@ -1513,7 +1531,7 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
 	      - (rahc->flags & AHC_BIOS_ENABLED);
 	if (value != 0)
 		/* Controllers with BIOS enabled have a *higher* priority */
-		return (-value);
+		return (value);
 
 	/*
 	 * Same BIOS setting, now sort based on bus type.
@@ -1526,7 +1544,7 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
 	lvalue = (lahc->chip & AHC_BUS_MASK);
  	if (lvalue == AHC_VL)
 		lvalue = AHC_EISA;
-	value = lvalue - rvalue;
+	value = rvalue - lvalue;
 	if (value != 0)
 		return (value);
 
@@ -1537,40 +1555,40 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
 		char primary_channel;
 
 		if (aic7xxx_reverse_scan != 0)
-			value = ahc_get_pci_bus(rahc->dev_softc)
-			      - ahc_get_pci_bus(lahc->dev_softc);
-		else
 			value = ahc_get_pci_bus(lahc->dev_softc)
 			      - ahc_get_pci_bus(rahc->dev_softc);
+		else
+			value = ahc_get_pci_bus(rahc->dev_softc)
+			      - ahc_get_pci_bus(lahc->dev_softc);
 		if (value != 0)
 			break;
 		if (aic7xxx_reverse_scan != 0)
-			value = ahc_get_pci_slot(rahc->dev_softc)
-			      - ahc_get_pci_slot(lahc->dev_softc);
-		else
 			value = ahc_get_pci_slot(lahc->dev_softc)
 			      - ahc_get_pci_slot(rahc->dev_softc);
+		else
+			value = ahc_get_pci_slot(rahc->dev_softc)
+			      - ahc_get_pci_slot(lahc->dev_softc);
 		if (value != 0)
 			break;
 		/*
 		 * On multi-function devices, the user can choose
 		 * to have function 1 probed before function 0.
 		 * Give whichever channel is the primary channel
-		 * the lowest priority.
+		 * the highest priority.
 		 */
 		primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A';
-		value = 1;
+		value = -1;
 		if (lahc->channel == primary_channel)
-			value = -1;
+			value = 1;
 		break;
 	}
 	case AHC_EISA:
 		if ((rahc->flags & AHC_BIOS_ENABLED) != 0) {
-			value = lahc->platform_data->bios_address
-			      - rahc->platform_data->bios_address; 
+			value = rahc->platform_data->bios_address
+			      - lahc->platform_data->bios_address; 
 		} else {
-			value = lahc->bsh.ioport
-			      - rahc->bsh.ioport; 
+			value = rahc->bsh.ioport
+			      - lahc->bsh.ioport; 
 		}
 		break;
 	default:
@@ -1579,90 +1597,6 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
 	return (value);
 }
 
-static void
-ahc_linux_setup_tag_info(char *p, char *end, char *s)
-{
-	char	*base;
-	char	*tok;
-	char	*tok_end;
-	char	*tok_end2;
-	int      i;
-	int      instance;
-	int	 targ;
-	int	 done;
-	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
-
-	if (*p != ':')
-		return;
-
-	instance = -1;
-	targ = -1;
-	done = FALSE;
-	base = p;
-	/* Forward us just past the ':' */
-	tok = base + 1;
-	tok_end = strchr(tok, '\0');
-	if (tok_end < end)
-		*tok_end = ',';
-	while (!done) {
-		switch (*tok) {
-		case '{':
-			if (instance == -1)
-				instance = 0;
-			else if (targ == -1)
-				targ = 0;
-			tok++;
-			break;
-		case '}':
-			if (targ != -1)
-				targ = -1;
-			else if (instance != -1)
-				instance = -1;
-			tok++;
-			break;
-		case ',':
-		case '.':
-			if (instance == -1)
-				done = TRUE;
-			else if (targ >= 0)
-				targ++;
-			else if (instance >= 0)
-				instance++;
-			if ((targ >= AHC_NUM_TARGETS) ||
-			    (instance >= NUM_ELEMENTS(aic7xxx_tag_info)))
-				done = TRUE;
-			tok++;
-			if (!done) {
-				base = tok;
-			}
-			break;
-		case '\0':
-			done = TRUE;
-			break;
-		default:
-			done = TRUE;
-			tok_end = strchr(tok, '\0');
-			for (i = 0; tok_list[i]; i++) {
-				tok_end2 = strchr(tok, tok_list[i]);
-				if ((tok_end2) && (tok_end2 < tok_end)) {
-					tok_end = tok_end2;
-					done = FALSE;
-				}
-			}
-			if ((instance >= 0) && (targ >= 0)
-			 && (instance < NUM_ELEMENTS(aic7xxx_tag_info))
-			 && (targ < AHC_NUM_TARGETS)) {
-				aic7xxx_tag_info[instance].tag_commands[targ] =
-				    simple_strtoul(tok, NULL, 0) & 0xff;
-			}
-			tok = tok_end;
-			break;
-		}
-	}
-	while ((p != base) && (p != NULL))
-		p = strsep(&s, ",.");
-}
-
 static void
 ahc_linux_setup_tag_info_global(char *p)
 {
@@ -1679,77 +1613,28 @@ ahc_linux_setup_tag_info_global(char *p)
 }
 
 static void
-ahc_linux_setup_dv(char *p, char *end, char *s)
+ahc_linux_setup_tag_info(void *arg, int instance, int targ, int32_t value)
 {
-	char	*base;
-	char	*tok;
-	char	*tok_end;
-	char	*tok_end2;
-	int      i;
-	int      instance;
-	int	 done;
-	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
-
-	if (*p != ':')
-		return;
 
-	instance = -1;
-	done = FALSE;
-	base = p;
-	/* Forward us just past the ':' */
-	tok = base + 1;
-	tok_end = strchr(tok, '\0');
-	if (tok_end < end)
-		*tok_end = ',';
-	while (!done) {
-		switch (*tok) {
-		case '{':
-			if (instance == -1)
-				instance = 0;
-			tok++;
-			break;
-		case '}':
-			if (instance != -1)
-				instance = -1;
-			tok++;
-			break;
-		case ',':
-		case '.':
-			if (instance == -1)
-				done = TRUE;
-			else if (instance >= 0)
-				instance++;
-			if (instance >= NUM_ELEMENTS(aic7xxx_dv_settings))
-				done = TRUE;
-			tok++;
-			if (!done) {
-				base = tok;
-			}
-			break;
-		case '\0':
-			done = TRUE;
-			break;
-		default:
-			done = TRUE;
-			tok_end = strchr(tok, '\0');
-			for (i = 0; tok_list[i]; i++) {
-				tok_end2 = strchr(tok, tok_list[i]);
-				if ((tok_end2) && (tok_end2 < tok_end)) {
-					tok_end = tok_end2;
-					done = FALSE;
-				}
-			}
-			if ((instance >= 0)
-			 && (instance < NUM_ELEMENTS(aic7xxx_dv_settings))) {
-				aic7xxx_dv_settings[instance] =
-				    simple_strtol(tok, NULL, 0);
-			}
-			tok = tok_end;
-			break;
-		}
+	if ((instance >= 0) && (targ >= 0)
+	 && (instance < NUM_ELEMENTS(aic7xxx_tag_info))
+	 && (targ < AHC_NUM_TARGETS)) {
+		aic7xxx_tag_info[instance].tag_commands[targ] = value & 0xff;
+		if (bootverbose)
+			printf("tag_info[%d:%d] = %d\n", instance, targ, value);
+	}
+}
+
+static void
+ahc_linux_setup_dv(void *arg, int instance, int targ, int32_t value)
+{
+
+	if ((instance >= 0)
+	 && (instance < NUM_ELEMENTS(aic7xxx_dv_settings))) {
+		aic7xxx_dv_settings[instance] = value;
+		if (bootverbose)
+			printf("dv[%d] = %d\n", instance, value);
 	}
-	while ((p != base) && (p != NULL))
-		p = strsep(&s, ",.");
 }
 
 /*
@@ -1787,30 +1672,38 @@ aic7xxx_setup(char *s)
 
 	end = strchr(s, '\0');
 
+	/*
+	 * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS
+	 * will never be 0 in this case.
+	 */
+	n = 0;
+
 	while ((p = strsep(&s, ",.")) != NULL) {
 		if (*p == '\0')
 			continue;
 		for (i = 0; i < NUM_ELEMENTS(options); i++) {
-			n = strlen(options[i].name);
 
-			if (strncmp(options[i].name, p, n) != 0)
-				continue;
+			n = strlen(options[i].name);
+			if (strncmp(options[i].name, p, n) == 0)
+				break;
+		}
+		if (i == NUM_ELEMENTS(options))
+			continue;
 
-			if (!strncmp(p, "global_tag_depth", n)) {
-				ahc_linux_setup_tag_info_global(p + n);
-			} else if (!strncmp(p, "tag_info", n)) {
-				ahc_linux_setup_tag_info(p + n, end, s);
-			} else if (strncmp(p, "dv", n) == 0) {
-				ahc_linux_setup_dv(p + n, end, s);
-			} else if (p[n] == ':') {
-				*(options[i].flag) =
-				    simple_strtoul(p + n + 1, NULL, 0);
-			} else if (!strncmp(p, "verbose", n)) {
-				*(options[i].flag) = 1;
-			} else {
-				*(options[i].flag) = ~(*(options[i].flag));
-			}
-			break;
+		if (strncmp(p, "global_tag_depth", n) == 0) {
+			ahc_linux_setup_tag_info_global(p + n);
+		} else if (strncmp(p, "tag_info", n) == 0) {
+			s = aic_parse_brace_option("tag_info", p + n, end,
+			    2, ahc_linux_setup_tag_info, NULL);
+		} else if (strncmp(p, "dv", n) == 0) {
+			s = aic_parse_brace_option("dv", p + n, end, 1,
+			    ahc_linux_setup_dv, NULL);
+		} else if (p[n] == ':') {
+			*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+		} else if (strncmp(p, "verbose", n) == 0) {
+			*(options[i].flag) = 1;
+		} else {
+			*(options[i].flag) = ~(*(options[i].flag));
 		}
 	}
 	return 1;
@@ -1840,6 +1733,8 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
 	ahc_lock(ahc, &s);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	scsi_assign_lock(host, &ahc->platform_data->spin_lock);
+#elif AHC_SCSI_HAS_HOST_LOCK != 0
+	host->lock = &ahc->platform_data->spin_lock;
 #endif
 	ahc->platform_data->host = host;
 	host->can_queue = AHC_MAX_QUEUE;
@@ -1860,7 +1755,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
 	}
 	host->unique_id = ahc->unit;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) && \
-    LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+    LINUX_VERSION_CODE  < KERNEL_VERSION(2,5,0)
 	scsi_set_pci_device(host, ahc->dev_softc);
 #endif
 	ahc_linux_initialize_scsi_bus(ahc);
@@ -1882,20 +1777,35 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
 	 * negotiation will occur for the first command, and DV
 	 * will comence should that first command be successful.
 	 */
-	for (target = 0; target < host->max_id*host->max_channel+1; target++) {
+	for (target = 0;
+	     target < host->max_id * (host->max_channel + 1); target++) {
 		u_int channel;
 
 		channel = 0;
 		if (target > 7
 		 && (ahc->features & AHC_TWIN) != 0)
 			channel = 1;
+		/*
+		 * Skip our own ID.  Some Compaq/HP storage devices
+		 * have enclosure management devices that respond to
+		 * single bit selection (i.e. selecting ourselves).
+		 * It is expected that either an external application
+		 * or a modified kernel will be used to probe this
+		 * ID if it is appropriate.  To accommodate these
+		 * installations, ahc_linux_alloc_target() will allocate
+		 * for our ID if asked to do so.
+		 */
+		if ((channel == 0 && target == ahc->our_id)
+		 || (channel == 1 && target == ahc->our_id_b))
+			continue;
+
 		ahc_linux_alloc_target(ahc, channel, target);
 	}
 	ahc_intr_enable(ahc, TRUE);
 	ahc_linux_start_dv(ahc);
 	ahc_unlock(ahc, &s);
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL));
 #endif
 	return (0);
@@ -2053,31 +1963,15 @@ ahc_platform_free(struct ahc_softc *ahc)
 {
 	struct ahc_linux_target *targ;
 	struct ahc_linux_device *dev;
-	u_long s;
 	int i, j;
 
 	if (ahc->platform_data != NULL) {
-		/* Kill the DV kthread */
-		if (ahc->platform_data->dv_pid > 0) {
-			ahc_lock(ahc, &s);
-			ahc->platform_data->flags |= AHC_DV_SHUTDOWN;
-			ahc_unlock(ahc, &s);
-			up(&ahc->platform_data->dv_sem);
-			do {
-#ifdef AHC_DEBUG
-				if (ahc_debug & AHC_SHOW_DV) {
-					printf("%s: Waiting for DV thread to "
-					       "exit\n", ahc_name(ahc));
-				}
-#endif
-			} while (waitpid(ahc->platform_data->dv_pid, NULL,
-					 __WCLONE) == -ERESTARTSYS);
-		}
+		ahc_linux_kill_dv_thread(ahc);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 		tasklet_kill(&ahc->platform_data->runq_tasklet);
 #endif
 		if (ahc->platform_data->host != NULL) {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 			scsi_remove_host(ahc->platform_data->host);
 #endif
 			scsi_unregister(ahc->platform_data->host);
@@ -2116,15 +2010,16 @@ ahc_platform_free(struct ahc_softc *ahc)
 					   0x1000);
 #endif
 		}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && \
+    LINUX_VERSION_CODE  < KERNEL_VERSION(2,5,0)
 		/*
 		 * In 2.4 we detach from the scsi midlayer before the PCI
-		 * layer invokes our remove callback.
+		 * layer invokes our remove callback.  No per-instance
+		 * detach is provided, so we must reach inside the PCI
+		 * subsystem's internals and detach our driver manually.
 		 */
 		if (ahc->dev_softc != NULL)
 			ahc->dev_softc->driver = NULL;
-#endif
 #endif
 		free(ahc->platform_data, M_DEVBUF);
 	}
@@ -2153,7 +2048,18 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
 	if (dev == NULL)
 		return;
 	was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
-	now_queuing = alg != AHC_QUEUE_NONE;
+	switch (alg) {
+	default:
+	case AHC_QUEUE_NONE:
+		now_queuing = 0;
+		break; 
+	case AHC_QUEUE_BASIC:
+		now_queuing = AHC_DEV_Q_BASIC;
+		break;
+	case AHC_QUEUE_TAGGED:
+		now_queuing = AHC_DEV_Q_TAGGED;
+		break;
+	}
 	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0
 	 && (was_queuing != now_queuing)
 	 && (dev->active != 0)) {
@@ -2302,24 +2208,12 @@ ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc)
 	ahc->platform_data->flags &= ~AHC_RUN_CMPLT_Q_TIMER;
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahc_unlock(ahc, &flags);
-#endif
 	if (acmd != NULL) {
 		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahc_lock(ahc, &flags);
-#endif
+		if (acmd != NULL)
 			ahc_schedule_completeq(ahc, acmd);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahc_unlock(ahc, &flags);
-#endif
-		}
 	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	ahc_unlock(ahc, &flags);
-#endif
 }
 
 static void
@@ -2328,7 +2222,7 @@ ahc_linux_start_dv(struct ahc_softc *ahc)
 
 	/*
 	 * Freeze the simq and signal ahc_linux_queue to not let any
-	 * more commands through
+	 * more commands through.
 	 */
 	if ((ahc->platform_data->flags & AHC_DV_ACTIVE) == 0) {
 #ifdef AHC_DEBUG
@@ -2344,6 +2238,48 @@ ahc_linux_start_dv(struct ahc_softc *ahc)
 	}
 }
 
+static void
+ahc_linux_kill_dv_thread(struct ahc_softc *ahc)
+{
+	u_long s;
+
+	ahc_lock(ahc, &s);
+	if (ahc->platform_data->dv_pid != 0) {
+		ahc->platform_data->flags |= AHC_DV_SHUTDOWN;
+		ahc_unlock(ahc, &s);
+		up(&ahc->platform_data->dv_sem);
+
+		/*
+		 * Use the eh_sem as an indicator that the
+		 * dv thread is exiting.  Note that the dv
+		 * thread must still return after performing
+		 * the up on our semaphore before it has
+		 * completely exited this module.  Unfortunately,
+		 * there seems to be no easy way to wait for the
+		 * exit of a thread for which you are not the
+		 * parent (dv threads are parented by init).
+		 * Cross your fingers...
+		 */
+		down(&ahc->platform_data->eh_sem);
+
+		/*
+		 * Mark the dv thread as already dead.  This
+		 * avoids attempting to kill it a second time.
+		 * This is necessary because we must kill the
+		 * DV thread before calling ahc_free() in the
+		 * module shutdown case to avoid bogus locking
+		 * in the SCSI mid-layer, but we ahc_free() is
+		 * called without killing the DV thread in the
+		 * instance detach case, so ahc_platform_free()
+		 * calls us again to verify that the DV thread
+		 * is dead.
+		 */
+		ahc->platform_data->dv_pid = 0;
+	} else {
+		ahc_unlock(ahc, &s);
+	}
+}
+
 static int
 ahc_linux_dv_thread(void *data)
 {
@@ -2362,7 +2298,17 @@ ahc_linux_dv_thread(void *data)
 	 * Complete thread creation.
 	 */
 	lock_kernel();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	/*
+	 * Don't care about any signals.
+	 */
+	siginitsetinv(&current->blocked, 0);
+
+	daemonize();
+	sprintf(current->comm, "ahc_dv_%d", ahc->unit);
+#else
 	daemonize("ahc_dv_%d", ahc->unit);
+#endif
 	unlock_kernel();
 
 	while (1) {
@@ -2376,7 +2322,7 @@ ahc_linux_dv_thread(void *data)
 		ahc_lock(ahc, &s);
 		if ((ahc->platform_data->flags & AHC_DV_SHUTDOWN) != 0) {
 			ahc_unlock(ahc, &s);
-			return (0);
+			break;
 		}
 		ahc_unlock(ahc, &s);
 
@@ -2422,7 +2368,7 @@ ahc_linux_dv_thread(void *data)
 		 */
 		ahc_linux_release_simq((u_long)ahc);
 	}
-
+	up(&ahc->platform_data->eh_sem);
 	return (0);
 }
 
@@ -2528,6 +2474,7 @@ ahc_linux_dv_target(struct ahc_softc *ahc, u_int target_offset)
 		}
 		case AHC_DV_STATE_TUR:
 		case AHC_DV_STATE_BUSY:
+			timeout = 5 * HZ;
 			ahc_linux_dv_tur(ahc, cmd, &devinfo);
 			break;
 		case AHC_DV_STATE_REBD:
@@ -2568,14 +2515,19 @@ ahc_linux_dv_target(struct ahc_softc *ahc, u_int target_offset)
 		/*
 		 * In 2.5.X, it is assumed that all calls from the
 		 * "midlayer" (which we are emulating) will have the
-		 * ahc host lock held.
+		 * ahc host lock held.  For other kernels, the
+		 * io_request_lock must be held.
 		 */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#if AHC_SCSI_HAS_HOST_LOCK != 0
 		ahc_lock(ahc, &s);
+#else
+		spin_lock_irqsave(&io_request_lock, s);
 #endif
 		ahc_linux_queue(cmd, ahc_linux_dv_complete);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#if AHC_SCSI_HAS_HOST_LOCK != 0
 		ahc_unlock(ahc, &s);
+#else
+		spin_unlock_irqrestore(&io_request_lock, s);
 #endif
 		down_interruptible(&ahc->platform_data->dv_cmd_sem);
 		/*
@@ -3457,7 +3409,6 @@ ahc_linux_dv_timeout(struct scsi_cmnd *cmd)
 {
 	struct	ahc_softc *ahc;
 	struct	ahc_cmd *acmd;
-	struct	ahc_linux_device *next_dev;
 	struct	scb *scb;
 	u_long	flags;
 
@@ -3504,36 +3455,16 @@ ahc_linux_dv_timeout(struct scsi_cmnd *cmd)
 	ahc->platform_data->reset_timer.function =
 	    (ahc_linux_callback_t *)ahc_linux_release_simq;
 	add_timer(&ahc->platform_data->reset_timer);
-	/*
-	 * In 2.5.X, the "done lock" is the ahc_lock.
-	 * Instead of dropping and re-acquiring the same
-	 * lock in the 2.5.X case, just hold our ahc_lock
-	 * the whole time.  ahc_done_lock() has been
-	 * made a no-op for 2.5.X too.
-	 */
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
-	next_dev = ahc_linux_next_device_to_run(ahc);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahc_unlock(ahc, &flags);
-#endif
-	if (next_dev)
+	if (ahc_linux_next_device_to_run(ahc) != NULL)
 		ahc_schedule_runq(ahc);
 	if (acmd != NULL) {
 		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahc_lock(ahc, &flags);
-#endif
+		if (acmd != NULL)
 			ahc_schedule_completeq(ahc, acmd);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahc_unlock(ahc, &flags);
-#endif
-		}
 	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	ahc_unlock(ahc, &flags);
-#endif
 }
 
 static void
@@ -3621,17 +3552,17 @@ ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
 
 	tags = 0;
 	if ((ahc->user_discenable & devinfo->target_mask) != 0) {
-		if (warned_user == 0
-		 && ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) {
-
-			printf("aic7xxx: WARNING, insufficient "
-			       "tag_info instances for installed "
-			       "controllers. Using defaults\n");
-			printf("aic7xxx: Please update the "
-			       "aic7xxx_tag_info array in the "
-			       "aic7xxx.c source file.\n");
+		if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) {
+			if (warned_user == 0) {
+
+				printf(KERN_WARNING
+"aic7xxx: WARNING: Insufficient tag_info instances\n"
+"aic7xxx: for installed controllers. Using defaults\n"
+"aic7xxx: Please update the aic7xxx_tag_info array in\n"
+"aic7xxx: the aic7xxx_osm..c source file.\n");
+				warned_user++;
+			}
 			tags = AHC_MAX_QUEUE;
-			warned_user++;
 		} else {
 			adapter_tag_info_t *tag_info;
 
@@ -3650,17 +3581,17 @@ ahc_linux_user_dv_setting(struct ahc_softc *ahc)
 	static int warned_user;
 	int dv;
 
-	if (warned_user == 0
-	 && ahc->unit >= NUM_ELEMENTS(aic7xxx_dv_settings)) {
+	if (ahc->unit >= NUM_ELEMENTS(aic7xxx_dv_settings)) {
+		if (warned_user == 0) {
 
-		printf("aic7xxx: WARNING, insufficient "
-		       "dv settings instances for installed "
-		       "controllers. Using defaults\n");
-		printf("aic7xxx: Please update the "
-		       "aic7xxx_dv_settings array in the "
-		       "aic7xxx.c source file.\n");
+			printf(KERN_WARNING
+"aic7xxx: WARNING: Insufficient dv settings instances\n"
+"aic7xxx: for installed controllers. Using defaults\n"
+"aic7xxx: Please update the aic7xxx_dv_settings array\n"
+"aic7xxx: in the aic7xxx_osm.c source file.\n");
+			warned_user++;
+		}
 		dv = -1;
-		warned_user++;
 	} else {
 
 		dv = aic7xxx_dv_settings[ahc->unit];
@@ -3938,41 +3869,20 @@ ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
 	struct	ahc_softc *ahc;
 	struct	ahc_cmd *acmd;
 	u_long	flags;
-	struct	ahc_linux_device *next_dev;
 
 	ahc = (struct ahc_softc *) dev_id;
 	ahc_lock(ahc, &flags); 
 	ahc_intr(ahc);
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
-	next_dev = ahc_linux_next_device_to_run(ahc);
-	/*
-	 * In 2.5.X, the "done lock" is the ahc_lock.
-	 * Instead of dropping and re-acquiring the same
-	 * lock in the 2.5.X case, just hold our ahc_lock
-	 * the whole time.  ahc_done_lock() has been
-	 * made a no-op for 2.5.X too.
-	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	ahc_unlock(ahc, &flags);
-#endif
-	if (next_dev)
+	if (ahc_linux_next_device_to_run(ahc) != NULL)
 		ahc_schedule_runq(ahc);
 	if (acmd != NULL) {
 		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahc_lock(ahc, &flags);
-#endif
+		if (acmd != NULL)
 			ahc_schedule_completeq(ahc, acmd);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-			ahc_unlock(ahc, &flags);
-#endif
-		}
 	}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	ahc_unlock(ahc, &flags);
-#endif
 }
 
 void
@@ -3995,15 +3905,6 @@ ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target)
 	target_offset = target;
 	if (channel != 0)
 		target_offset += 8;
-	/*
-	 * Never allow allocation of a target object for
-	 * our own SCSIID.
-	 */
-	if ((channel == 0 && target == ahc->our_id)
-	 || (channel == 1 && target == ahc->our_id_b)) {
-		ahc->platform_data->targets[target_offset] = NULL;
-		return (NULL);
-	}
 
 	targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT);
 	if (targ == NULL)
@@ -4274,6 +4175,14 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
 #endif
 			ahc_set_transaction_status(scb, CAM_UNCOR_PARITY);
 		} else if (amount_xferred < scb->io_ctx->underflow) {
+			u_int i;
+
+			ahc_print_path(ahc, scb);
+			printf("CDB:");
+			for (i = 0; i < scb->io_ctx->cmd_len; i++)
+				printf(" 0x%x", scb->io_ctx->cmnd[i]);
+			printf("\n");
+			ahc_print_path(ahc, scb);
 			printf("Saw underflow (%ld of %ld bytes). "
 			       "Treated as error\n",
 				ahc_get_residual(scb),
@@ -4456,7 +4365,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
 			}
 			ahc_set_transaction_status(scb, CAM_REQUEUE_REQ);
 			ahc_set_scsi_status(scb, SCSI_STATUS_OK);
-			ahc_set_tags(ahc, &devinfo,
+			ahc_platform_set_tags(ahc, &devinfo,
 				     (dev->flags & AHC_DEV_Q_BASIC)
 				   ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
 			break;
@@ -4467,7 +4376,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
 		 */
 		dev->openings = 1;
 		ahc_set_scsi_status(scb, SCSI_STATUS_BUSY);
-		ahc_set_tags(ahc, &devinfo,
+		ahc_platform_set_tags(ahc, &devinfo,
 			     (dev->flags & AHC_DEV_Q_BASIC)
 			   ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
 		/* FALLTHROUGH */
@@ -4770,6 +4679,7 @@ ahc_linux_release_simq(u_long arg)
 		ahc->platform_data->flags &= ~AHC_DV_WAIT_SIMQ_RELEASE;
 		up(&ahc->platform_data->dv_sem);
 	}
+	ahc_schedule_runq(ahc);
 	ahc_unlock(ahc, &s);
 	/*
 	 * There is still a race here.  The mid-layer
@@ -4779,8 +4689,6 @@ ahc_linux_release_simq(u_long arg)
 	 */
 	if (unblock_reqs)
 		scsi_unblock_requests(ahc->platform_data->host);
-
-	ahc_schedule_runq(ahc);
 }
 
 static void
@@ -4815,6 +4723,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
 	u_int  active_scb_index;
 	u_int  last_phase;
 	u_int  saved_scsiid;
+	u_int  cdb_byte;
 	int    retval;
 	int    paused;
 	int    wait;
@@ -4831,6 +4740,11 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
 	       cmd->device->id, cmd->device->lun,
 	       flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");
 
+	printf("CDB:");
+	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
+		printf(" 0x%x", cmd->cmnd[cdb_byte]);
+	printf("\n");
+
 	/*
 	 * In all versions of Linux, we have to work around
 	 * a major flaw in how the mid-layer is locked down
@@ -4845,9 +4759,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
 	 * by acquiring either the io_request_lock or our own
 	 * lock, this *should* be safe.
 	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_unlock_irq(&io_request_lock);
-#endif
 	ahc_midlayer_entrypoint_lock(ahc, &s);
 
 	/*
@@ -5104,11 +5015,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
 		int ret;
 
 		ahc->platform_data->flags |= AHC_UP_EH_SEMAPHORE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		ahc_unlock(ahc, &s);
-#else
-		spin_unlock_irq(ahc->platform_data->host->host_lock);
-#endif
+		spin_unlock_irq(&ahc->platform_data->spin_lock);
 		init_timer(&timer);
 		timer.data = (u_long)ahc;
 		timer.expires = jiffies + (5 * HZ);
@@ -5122,27 +5029,17 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
 			printf("Timer Expired\n");
 			retval = FAILED;
 		}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		ahc_lock(ahc, &s);
-#else
-		spin_lock_irq(ahc->platform_data->host->host_lock);
-#endif
+		spin_lock_irq(&ahc->platform_data->spin_lock);
 	}
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
-	ahc_midlayer_entrypoint_unlock(ahc, &s);
+	ahc_schedule_runq(ahc);
 	if (acmd != NULL) {
 		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL) {
-			ahc_midlayer_entrypoint_lock(ahc, &s);
+		if (acmd != NULL)
 			ahc_schedule_completeq(ahc, acmd);
-			ahc_midlayer_entrypoint_unlock(ahc, &s);
-		}
 	}
-	ahc_schedule_runq(ahc);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_lock_irq(&io_request_lock);
-#endif
+	ahc_midlayer_entrypoint_unlock(ahc, &s);
 	return (retval);
 }
 
@@ -5185,13 +5082,14 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc)
 	}
 }
 
-static int __init ahc_linux_init(void)
+static int __init
+ahc_linux_init(void)
 {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	return (ahc_linux_detect(&aic7xxx_driver_template) ? 0 : -ENODEV);
 #else
 	scsi_register_module(MODULE_SCSI_HA, &aic7xxx_driver_template);
-	if (!driver_template.present) {
+	if (aic7xxx_driver_template.present == 0) {
 		scsi_unregister_module(MODULE_SCSI_HA,
 				       &aic7xxx_driver_template);
 		return (-ENODEV);
@@ -5201,10 +5099,25 @@ static int __init ahc_linux_init(void)
 #endif
 }
 
-static void __exit ahc_linux_exit(void)
+static void __exit
+ahc_linux_exit(void)
 {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
-	struct	ahc_softc *ahc;
+	struct ahc_softc *ahc;
+	u_long l;
+
+	/*
+	 * Shutdown DV threads before going into the SCSI mid-layer.
+	 * This avoids situations where the mid-layer locks the entire
+	 * kernel so that waiting for our DV threads to exit leads
+	 * to deadlock.
+	 */
+	ahc_list_lock(&l);
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+
+		ahc_linux_kill_dv_thread(ahc);
+	}
+	ahc_list_unlock(&l);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 
 	ahc_linux_pci_exit();
 
@@ -5220,9 +5133,8 @@ static void __exit ahc_linux_exit(void)
 
 	/*
 	 * In 2.4 we have to unregister from the PCI core _after_
-	 * unregistering from the scsi midlayer to avoid danling references.
-	 *
-	 * The 2.4 scsi midlayer is so f***ed..
+	 * unregistering from the scsi midlayer to avoid dangling
+	 * references.
 	 */
 	ahc_linux_pci_exit();
 #endif
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index da982de0053380300c3ede4c157f5c670a6fd252..17ed9a587a04f352a2e625e588c1d115b806e8b1 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -53,7 +53,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#123 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#131 $
  *
  */
 #ifndef _AIC7XXX_LINUX_H_
@@ -299,7 +299,13 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec)
 #include <linux/smp.h>
 #endif
 
-#define AIC7XXX_DRIVER_VERSION "6.2.28"
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK))
+#define AHC_SCSI_HAS_HOST_LOCK 1
+#else
+#define AHC_SCSI_HAS_HOST_LOCK 0
+#endif
+
+#define AIC7XXX_DRIVER_VERSION "6.2.31"
 
 /**************************** Front End Queues ********************************/
 /*
@@ -703,7 +709,6 @@ ahc_lockinit(struct ahc_softc *ahc)
 static __inline void
 ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
 {
-	*flags = 0;
 	spin_lock_irqsave(&ahc->platform_data->spin_lock, *flags);
 }
 
@@ -717,10 +722,13 @@ static __inline void
 ahc_midlayer_entrypoint_lock(struct ahc_softc *ahc, unsigned long *flags)
 {
 	/*
-	 * In 2.5.X, the midlayer takes our lock just before
-	 * calling us, so avoid locking again.
+	 * In 2.5.X and some 2.4.X versions, the midlayer takes our
+	 * lock just before calling us, so we avoid locking again.
+	 * For other kernel versions, the io_request_lock is taken
+	 * just before our entry point is called.  In this case, we
+	 * trade the io_request_lock for our per-softc lock.
 	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#if AHC_SCSI_HAS_HOST_LOCK == 0
 	ahc_lock(ahc, flags);
 #endif
 }
@@ -728,11 +736,7 @@ ahc_midlayer_entrypoint_lock(struct ahc_softc *ahc, unsigned long *flags)
 static __inline void
 ahc_midlayer_entrypoint_unlock(struct ahc_softc *ahc, unsigned long *flags)
 {
-	/*
-	 * In 2.5.X, the midlayer takes our lock just before
-	 * calling us and unlocks when we return, so let it do the unlock.
-	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#if AHC_SCSI_HAS_HOST_LOCK == 0
 	ahc_unlock(ahc, flags);
 #endif
 }
@@ -750,8 +754,7 @@ ahc_done_lockinit(struct ahc_softc *ahc)
 static __inline void
 ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	*flags = 0;
+#if AHC_SCSI_HAS_HOST_LOCK == 0
 	spin_lock_irqsave(&io_request_lock, *flags);
 #endif
 }
@@ -759,7 +762,7 @@ ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags)
 static __inline void
 ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#if AHC_SCSI_HAS_HOST_LOCK == 0
 	spin_unlock_irqrestore(&io_request_lock, *flags);
 #endif
 }
@@ -773,7 +776,6 @@ ahc_list_lockinit()
 static __inline void
 ahc_list_lock(unsigned long *flags)
 {
-	*flags = 0;
 	spin_lock_irqsave(&ahc_list_spinlock, *flags);
 }
 
@@ -793,7 +795,6 @@ ahc_lockinit(struct ahc_softc *ahc)
 static __inline void
 ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
 {
-	*flags = 0;
 	save_flags(*flags);
 	cli();
 }
@@ -832,7 +833,6 @@ ahc_list_lockinit()
 static __inline void
 ahc_list_lock(unsigned long *flags)
 {
-	*flags = 0;
 	save_flags(*flags);
 	cli();
 }
@@ -907,7 +907,7 @@ int			 aic7770_map_int(struct ahc_softc *ahc, u_int irq);
  */
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
 #if defined(__sparc_v9__) || defined(__powerpc__)
-#error "PPC and Sparc platforms are only support under 2.1.92 and above"
+#error "PPC and Sparc platforms are only supported under 2.1.92 and above"
 #endif
 #include <linux/bios32.h>
 #endif
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index b6dcea5c9d5d505fd579f9b66a2d0012ee514c14..1bc16d403d6217af254c7aa14de7041c780561d7 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#43 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#44 $
  */
 
 #include "aic7xxx_osm.h"
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index ed1e641dbbab78aa840d6c304fe503d8283013e9..f20d0b9bbddcbcc01e9c1ef1fcd7e8f81f4cb186 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -39,7 +39,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#57 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#62 $
  *
  * $FreeBSD$
  */
@@ -696,8 +696,12 @@ static void aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
 static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
 				 int *externalcable_present,
 				 int *eeprom_present);
-static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
+static void    write_brdctl(struct ahc_softc *ahc, uint8_t value);
 static uint8_t read_brdctl(struct ahc_softc *ahc);
+static void ahc_pci_intr(struct ahc_softc *ahc);
+static int  ahc_pci_chip_init(struct ahc_softc *ahc);
+static int  ahc_pci_suspend(struct ahc_softc *ahc);
+static int  ahc_pci_resume(struct ahc_softc *ahc);
 
 static int
 ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
@@ -748,10 +752,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
 	device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
 	subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
 	subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
-	full_id = ahc_compose_id(device,
-				 vendor,
-				 subdevice,
-				 subvendor);
+	full_id = ahc_compose_id(device, vendor, subdevice, subvendor);
 
 	/*
 	 * If the second function is not hooked up, ignore it.
@@ -854,6 +855,9 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
 		return (error);
 
 	ahc->bus_intr = ahc_pci_intr;
+	ahc->bus_chip_init = ahc_pci_chip_init;
+	ahc->bus_suspend = ahc_pci_suspend;
+	ahc->bus_resume = ahc_pci_resume;
 
 	/* Remeber how the card was setup in case there is no SEEPROM */
 	if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
@@ -993,6 +997,35 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
 	if ((sxfrctl1 & STPWEN) != 0)
 		ahc->flags |= AHC_TERM_ENB_A;
 
+	/*
+	 * Save chip register configuration data for chip resets
+	 * that occur during runtime and resume events.
+	 */
+	ahc->bus_softc.pci_softc.devconfig =
+	    ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
+	ahc->bus_softc.pci_softc.command =
+	    ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
+	ahc->bus_softc.pci_softc.csize_lattime =
+	    ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1);
+	ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+	ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
+	if ((ahc->features & AHC_DT) != 0) {
+		u_int sfunct;
+
+		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+		ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE);
+		ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT);
+		ahc_outb(ahc, SFUNCT, sfunct);
+		ahc->bus_softc.pci_softc.crccontrol1 =
+		    ahc_inb(ahc, CRCCONTROL1);
+	}
+	if ((ahc->features & AHC_MULTI_FUNC) != 0)
+		ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR);
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
+
 	/* Core initialization */
 	error = ahc_init(ahc);
 	if (error != 0)
@@ -1412,6 +1445,7 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
 	}
 
 	if (have_autoterm) {
+		ahc->flags |= AHC_HAS_TERM_LOGIC;
 		ahc_acquire_seeprom(ahc, &sd);
 		configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);
 		ahc_release_seeprom(&sd);
@@ -1845,11 +1879,14 @@ aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
 	spiocap |= EXT_BRDCTL;
 	ahc_outb(ahc, SPIOCAP, spiocap);
 	ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
+	ahc_flush_device_writes(ahc);
+	ahc_delay(500);
 	ahc_outb(ahc, BRDCTL, 0);
+	ahc_flush_device_writes(ahc);
+	ahc_delay(500);
 	brdctl = ahc_inb(ahc, BRDCTL);
 	*internal50_present = (brdctl & BRDDAT5) ? 0 : 1;
 	*externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
-
 	*eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
 }
 	
@@ -1943,7 +1980,7 @@ read_brdctl(ahc)
 	return (value);
 }
 
-void
+static void
 ahc_pci_intr(struct ahc_softc *ahc)
 {
 	u_int error;
@@ -1995,6 +2032,73 @@ ahc_pci_intr(struct ahc_softc *ahc)
 	ahc_unpause(ahc);
 }
 
+static int
+ahc_pci_chip_init(struct ahc_softc *ahc)
+{
+	ahc_outb(ahc, DSCOMMAND0, ahc->bus_softc.pci_softc.dscommand0);
+	ahc_outb(ahc, DSPCISTATUS, ahc->bus_softc.pci_softc.dspcistatus);
+	if ((ahc->features & AHC_DT) != 0) {
+		u_int sfunct;
+
+		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+		ahc_outb(ahc, OPTIONMODE, ahc->bus_softc.pci_softc.optionmode);
+		ahc_outw(ahc, TARGCRCCNT, ahc->bus_softc.pci_softc.targcrccnt);
+		ahc_outb(ahc, SFUNCT, sfunct);
+		ahc_outb(ahc, CRCCONTROL1,
+			 ahc->bus_softc.pci_softc.crccontrol1);
+	}
+	if ((ahc->features & AHC_MULTI_FUNC) != 0)
+		ahc_outb(ahc, SCBBADDR, ahc->bus_softc.pci_softc.scbbaddr);
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, DFF_THRSH, ahc->bus_softc.pci_softc.dff_thrsh);
+
+	return (ahc_chip_init(ahc));
+}
+
+static int
+ahc_pci_suspend(struct ahc_softc *ahc)
+{
+	return (ahc_suspend(ahc));
+}
+
+static int
+ahc_pci_resume(struct ahc_softc *ahc)
+{
+
+	ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
+
+	/*
+	 * We assume that the OS has restored our register
+	 * mappings, etc.  Just update the config space registers
+	 * that the OS doesn't know about and rely on our chip
+	 * reset handler to handle the rest.
+	 */
+	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4,
+			     ahc->bus_softc.pci_softc.devconfig);
+	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1,
+			     ahc->bus_softc.pci_softc.command);
+	ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1,
+			     ahc->bus_softc.pci_softc.csize_lattime);
+	if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) {
+		struct	seeprom_descriptor sd;
+		u_int	sxfrctl1;
+
+		sd.sd_ahc = ahc;
+		sd.sd_control_offset = SEECTL;		
+		sd.sd_status_offset = SEECTL;		
+		sd.sd_dataout_offset = SEECTL;		
+
+		ahc_acquire_seeprom(ahc, &sd);
+		configure_termination(ahc, &sd,
+				      ahc->seep_config->adapter_control,
+				      &sxfrctl1);
+		ahc_release_seeprom(&sd);
+	}
+	return (ahc_resume(ahc));
+}
+
 static int
 ahc_aic785X_setup(struct ahc_softc *ahc)
 {
@@ -2009,6 +2113,7 @@ ahc_aic785X_setup(struct ahc_softc *ahc)
 	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
 	if (rev >= 1)
 		ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+	ahc->instruction_ram_size = 512;
 	return (0);
 }
 
@@ -2026,6 +2131,7 @@ ahc_aic7860_setup(struct ahc_softc *ahc)
 	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
 	if (rev >= 1)
 		ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+	ahc->instruction_ram_size = 512;
 	return (0);
 }
 
@@ -2049,6 +2155,7 @@ ahc_aic7870_setup(struct ahc_softc *ahc)
 	ahc->chip = AHC_AIC7870;
 	ahc->features = AHC_AIC7870_FE;
 	ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+	ahc->instruction_ram_size = 512;
 	return (0);
 }
 
@@ -2102,6 +2209,7 @@ ahc_aic7880_setup(struct ahc_softc *ahc)
 	} else {
 		ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
 	}
+	ahc->instruction_ram_size = 512;
 	return (0);
 }
 
@@ -2149,6 +2257,7 @@ ahc_aic7890_setup(struct ahc_softc *ahc)
 	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
 	if (rev == 0)
 		ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG;
+	ahc->instruction_ram_size = 768;
 	return (0);
 }
 
@@ -2161,6 +2270,7 @@ ahc_aic7892_setup(struct ahc_softc *ahc)
 	ahc->features = AHC_AIC7892_FE;
 	ahc->flags |= AHC_NEWEEPROM_FMT;
 	ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+	ahc->instruction_ram_size = 1024;
 	return (0);
 }
 
@@ -2216,6 +2326,7 @@ ahc_aic7895_setup(struct ahc_softc *ahc)
 	ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1);
 #endif
 	ahc->flags |= AHC_NEWEEPROM_FMT;
+	ahc->instruction_ram_size = 512;
 	return (0);
 }
 
@@ -2230,6 +2341,7 @@ ahc_aic7896_setup(struct ahc_softc *ahc)
 	ahc->features = AHC_AIC7896_FE;
 	ahc->flags |= AHC_NEWEEPROM_FMT;
 	ahc->bugs |= AHC_CACHETHEN_DIS_BUG;
+	ahc->instruction_ram_size = 768;
 	return (0);
 }
 
@@ -2244,6 +2356,7 @@ ahc_aic7899_setup(struct ahc_softc *ahc)
 	ahc->features = AHC_AIC7899_FE;
 	ahc->flags |= AHC_NEWEEPROM_FMT;
 	ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+	ahc->instruction_ram_size = 1024;
 	return (0);
 }
 
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
index 8a510e7daec181e861f7ca99d9a0717cb6845841..4d39533e9124aa8987b290d1d70efa3f2c539b5e 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -37,7 +37,7 @@
  * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
  * sym driver.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#23 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#24 $
  */
 #include "aic7xxx_osm.h"
 #include "aic7xxx_inline.h"
@@ -325,6 +325,7 @@ ahc_linux_proc_info(char *buffer, char **start, off_t offset,
 
 	copy_info(&info, "Adaptec AIC7xxx driver version: %s\n",
 		  AIC7XXX_DRIVER_VERSION);
+	copy_info(&info, "%s\n", ahc->description);
 	ahc_controller_info(ahc, ahc_info);
 	copy_info(&info, "%s\n\n", ahc_info);
 
diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped
index 769c2d602f9f313a94ccd4b81d663062ac3b4833..cda0b8e5961331e86e66b66009a712e3f5ee5d81 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped
+++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped
@@ -3,7 +3,7 @@
  *		 from the following source files:
  *
  * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $
  */
 typedef int (ahc_reg_print_t)(u_int, u_int *, u_int);
 typedef struct ahc_reg_parse_entry {
@@ -1776,7 +1776,7 @@ ahc_reg_print_t ahc_sg_cache_pre_print;
 #define	SEQ_MAILBOX_SHIFT	0x00
 #define	TARGET_DATA_IN	0x01
 #define	HOST_MSG	0xff
-#define	MAX_OFFSET	0xff
+#define	MAX_OFFSET	0x7f
 #define	BUS_16_BIT	0x01
 #define	SCB_UPLOAD_SIZE	0x20
 #define	STACK_SIZE	0x04
diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
index 63b961c739fb1d1afcd45fb7b0417c7c605dad6e..b0687b13a656fcee9353b35072ba7a8ee05863b9 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
+++ b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
@@ -3,7 +3,7 @@
  *		 from the following source files:
  *
  * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $
  */
 
 #include "aic7xxx_osm.h"
diff --git a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
index def9fc7ef9be03c8605873da26c3fef44d3d4ddd..0f376fb1cf188d1cbeacebcff2f6c1583831caaf 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
+++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
@@ -3,7 +3,7 @@
  *		 from the following source files:
  *
  * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $
  */
 static uint8_t seqprog[] = {
 	0xb2, 0x00, 0x00, 0x08,
diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile
index 7599658d73257b81183df5b9e7d2e2d8f56cb3ce..fa2fbbcc92e633a55df05d157f98454b29975949 100644
--- a/drivers/scsi/aic7xxx/aicasm/Makefile
+++ b/drivers/scsi/aic7xxx/aicasm/Makefile
@@ -11,7 +11,7 @@ GENSRCS=	$(YSRCS:.y=.c) $(LSRCS:.l=.c)
 
 SRCS=	${CSRCS} ${GENSRCS}
 LIBS=	-ldb
-CLEANFILES= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output)
+clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG)
 # Override default kernel CFLAGS.  This is a userland app.
 AICASM_CFLAGS:= -I/usr/include -I.
 YFLAGS= -d
@@ -46,7 +46,6 @@ aicdb.h:
 		echo "*** Install db development libraries";	\
 	 fi
 
-clean-files := $(CLEANFILES) $(PROG)
 clean:
 	rm -f $(clean-files)
 
diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c
index aa2676edc10ead08a6afa46625b261aa34955a99..fa13a1fdce6dbc5df5b38104a381137593501cbd 100644
--- a/drivers/scsi/aic7xxx/aiclib.c
+++ b/drivers/scsi/aic7xxx/aiclib.c
@@ -1333,3 +1333,81 @@ aic_error_action(struct scsi_cmnd *cmd, struct scsi_inquiry_data *inq_data,
 	return (err_action);
 }
 
+char *
+aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
+		       aic_option_callback_t *callback, void *callback_arg)
+{
+	char	*tok_end;
+	char	*tok_end2;
+	int      i;
+	int      instance;
+	int	 targ;
+	int	 done;
+	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
+
+	/* All options use a ':' name/arg separator */
+	if (*opt_arg != ':')
+		return (opt_arg);
+	opt_arg++;
+	instance = -1;
+	targ = -1;
+	done = FALSE;
+	/*
+	 * Restore separator that may be in
+	 * the middle of our option argument.
+	 */
+	tok_end = strchr(opt_arg, '\0');
+	if (tok_end < end)
+		*tok_end = ',';
+	while (!done) {
+		switch (*opt_arg) {
+		case '{':
+			if (instance == -1) {
+				instance = 0;
+			} else {
+				if (depth > 1) {
+					if (targ == -1)
+						targ = 0;
+				} else {
+					printf("Malformed Option %s\n",
+					       opt_name);
+					done = TRUE;
+				}
+			}
+			opt_arg++;
+			break;
+		case '}':
+			if (targ != -1)
+				targ = -1;
+			else if (instance != -1)
+				instance = -1;
+			opt_arg++;
+			break;
+		case ',':
+		case '.':
+			if (instance == -1)
+				done = TRUE;
+			else if (targ >= 0)
+				targ++;
+			else if (instance >= 0)
+				instance++;
+			opt_arg++;
+			break;
+		case '\0':
+			done = TRUE;
+			break;
+		default:
+			tok_end = end;
+			for (i = 0; tok_list[i]; i++) {
+				tok_end2 = strchr(opt_arg, tok_list[i]);
+				if ((tok_end2) && (tok_end2 < tok_end))
+					tok_end = tok_end2;
+			}
+			callback(callback_arg, instance, targ,
+				 simple_strtol(opt_arg, NULL, 0));
+			opt_arg = tok_end;
+			break;
+		}
+	}
+	return (opt_arg);
+}
diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h
index 1b9da8346c5d92a76b3fb32c4fc2035d9cef4404..6fa722e1096fd49bc97e277ac47820acd39c8120 100644
--- a/drivers/scsi/aic7xxx/aiclib.h
+++ b/drivers/scsi/aic7xxx/aiclib.h
@@ -870,6 +870,7 @@ aic_sector_div(sector_t capacity, int heads, int sectors)
 #define	aic_calc_speed			AIC_LIB_ENTRY(_calc_speed)
 #define	aic_inquiry_match		AIC_LIB_ENTRY(_inquiry_match)
 #define	aic_static_inquiry_match	AIC_LIB_ENTRY(_static_inquiry_match)
+#define	aic_parse_brace_option		AIC_LIB_ENTRY(_parse_brace_option)
 
 /******************************************************************************/
 
@@ -905,6 +906,10 @@ int		aic_inquiry_match(caddr_t /*inqbuffer*/,
 int		aic_static_inquiry_match(caddr_t /*inqbuffer*/,
 					 caddr_t /*table_entry*/);
 
+typedef void aic_option_callback_t(void *, int, int, int32_t);
+char *		aic_parse_brace_option(char *opt_name, char *opt_arg,
+				       char *end, int depth,
+				       aic_option_callback_t *, void *);
 
 static __inline void	 scsi_extract_sense(struct scsi_sense_data *sense,
 					    int *error_code, int *sense_key,