new ahc driver. Adds suport for newer Adaptec controllers. This represents two...
authorsmurph <smurph@openbsd.org>
Wed, 22 Mar 2000 02:48:47 +0000 (02:48 +0000)
committersmurph <smurph@openbsd.org>
Wed, 22 Mar 2000 02:48:47 +0000 (02:48 +0000)
sys/dev/ic/aic7xxx.c
sys/dev/ic/aic7xxxreg.h
sys/dev/ic/aic7xxxvar.h

index 33ef899..782a7a2 100644 (file)
@@ -1,27 +1,25 @@
-/*     $OpenBSD: aic7xxx.c,v 1.18 1999/01/11 05:12:15 millert Exp $    */
-/*     $NetBSD: aic7xxx.c,v 1.17 1996/10/21 22:34:04 thorpej Exp $     */
-
 /*
  * Generic driver for the aic7xxx based adaptec SCSI controllers
  * Product specific probe and attach routines can be found in:
- * i386/eisa/aic7770.c 27/284X and aic7770 motherboard controllers
- * pci/aic7870.c       3940, 2940, aic7880, aic7870 and aic7850 controllers
+ * i386/eisa/ahc_eisa.c        27/284X and aic7770 motherboard controllers
+ * pci/ahc_pci.c       3985, 3980, 3940, 2940, aic7895, aic7890,
+ *                     aic7880, aic7870, aic7860, and aic7850 controllers
  *
- * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
+ * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000 Justin T. Gibbs.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * from Id: aic7xxx.c,v 1.75 1996/06/23 20:02:37 gibbs Exp
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.40 2000/01/07 23:08:17 gibbs Exp $
+ * $OpenBSD: aic7xxx.c,v 1.19 2000/03/22 02:48:47 smurph Exp $
  */
 /*
- * TODO:
- *     Implement Target Mode
- *
- * A few notes on how SCB paging works...
+ * A few notes on features of the driver.
  *
  * SCB paging takes advantage of the fact that devices stay disconnected
  * from the bus a relatively long time and that while they're disconnected,
- * having the SCBs for that device down on the host adapter is of little use.
- * Instead we copy the SCB back up into kernel memory and reuse the SCB slot
- * on the card to schedule another transaction.  This can be a real payoff
- * when doing random I/O to tagged queueing devices since there are more 
- * transactions active at once for the device to sort for optimal seek
- * reduction. The algorithm goes like this...
- *
- * At the sequencer level:
- * 1) Disconnected SCBs are threaded onto a doubly linked list, headed by
- *    DISCONNECTED_SCBH using the SCB_NEXT and SCB_PREV fields.  The most
- *    recently disconnected device is always at the head.
- *
- * 2) The SCB has an added field SCB_TAG that corresponds to the kernel
- *    SCB number (ie 0-254).
- *
- * 3) When a command is queued, the hardware index of the SCB it was downloaded
- *    into is placed into the QINFIFO for easy indexing by the sequencer.
- *
- * 4) The tag field is used as the tag for tagged-queueing, for determining
- *    the related kernel SCB, and is the value put into the QOUTFIFO
- *    so the kernel doesn't have to upload the SCB to determine the kernel SCB
- *    that completed on command completes.
- *
- * 5) When a reconnect occurs, the sequencer must scan the SCB array (even
- *    in the tag case) looking for the appropriate SCB and if it can't find
- *    it, it interrupts the kernel so it can page the SCB in.
+ * having the SCBs for these transactions down on the host adapter is of
+ * little use.  Instead of leaving this idle SCB down on the card we copy
+ * it back up into kernel memory and reuse the SCB slot on the card to
+ * schedule another transaction.  This can be a real payoff when doing random
+ * I/O to tagged queueing devices since there are more transactions active at
+ * once for the device to sort for optimal seek reduction. The algorithm goes
+ * like this...
  *
- * 6) If the sequencer is successful in finding the SCB, it removes it from
- *    the doubly linked list of disconnected SCBS.
+ * The sequencer maintains two lists of its hardware SCBs.  The first is the
+ * singly linked free list which tracks all SCBs that are not currently in
+ * use.  The second is the doubly linked disconnected list which holds the
+ * SCBs of transactions that are in the disconnected state sorted most
+ * recently disconnected first.  When the kernel queues a transaction to
+ * the card, a hardware SCB to "house" this transaction is retrieved from
+ * either of these two lists.  If the SCB came from the disconnected list,
+ * a check is made to see if any data transfer or SCB linking (more on linking
+ * in a bit) information has been changed since it was copied from the host
+ * and if so, DMAs the SCB back up before it can be used.  Once a hardware
+ * SCB has been obtained, the SCB is DMAed from the host.  Before any work
+ * can begin on this SCB, the sequencer must ensure that either the SCB is
+ * for a tagged transaction or the target is not already working on another
+ * non-tagged transaction.  If a conflict arises in the non-tagged case, the
+ * sequencer finds the SCB for the active transactions and sets the SCB_LINKED
+ * field in that SCB to this next SCB to execute.  To facilitate finding
+ * active non-tagged SCBs, the last four bytes of up to the first four hardware
+ * SCBs serve as a storage area for the currently active SCB ID for each
+ * target.
  *
- * At the kernel level:
- * 1) There are four queues that a kernel SCB may reside on:
- *     free_scbs - SCBs that are not in use and have a hardware slot assigned
- *                 to them.
- *      page_scbs - SCBs that are not in use and need to have a hardware slot
- *                 assigned to them (i.e. they will most likely cause a page
- *                 out event).
- *     waiting_scbs - SCBs that are active, don't have an assigned hardware
- *                 slot assigned to them and are waiting for either a
- *                 disconnection or a command complete to free up a slot.
- *     assigned_scbs - SCBs that were in the waiting_scbs queue, but were
- *                 assigned a slot by ahc_free_scb.
+ * When a device reconnects, a search is made of the hardware SCBs to find
+ * the SCB for this transaction.  If the search fails, a hardware SCB is
+ * pulled from either the free or disconnected SCB list and the proper
+ * SCB is DMAed from the host.  If the MK_MESSAGE control bit is set
+ * in the control byte of the SCB while it was disconnected, the sequencer
+ * will assert ATN and attempt to issue a message to the host.
  *
- * 2) When a new request comes in, an SCB is allocated from the free_scbs or
- *    page_scbs queue with preference to SCBs on the free_scbs queue.
+ * When a command completes, a check for non-zero status and residuals is
+ * made.  If either of these conditions exists, the SCB is DMAed back up to
+ * the host so that it can interpret this information.  Additionally, in the
+ * case of bad status, the sequencer generates a special interrupt and pauses
+ * itself.  This allows the host to setup a request sense command if it 
+ * chooses for this target synchronously with the error so that sense
+ * information isn't lost.
  *
- * 3) If there are no free slots (we retrieved the SCB off of the page_scbs
- *    queue), the SCB is inserted onto the tail of the waiting_scbs list and
- *    we attempt to run this queue down.
- *
- * 4) ahc_run_waiting_queues() looks at both the assigned_scbs and waiting_scbs
- *    queues.  In the case of the assigned_scbs, the commands are immediately
- *    downloaded and started.  For waiting_scbs, we page in all that we can
- *    ensuring we don't create a resource deadlock (see comments in
- *    ahc_run_waiting_queues()).
- *
- * 5) After we handle a bunch of command completes, we also try running the
- *    queues since many SCBs may have disconnected since the last command
- *    was started and we have at least one free slot on the card.
- *
- * 6) ahc_free_scb looks at the waiting_scbs queue for a transaction
- *    requiring a slot and moves it to the assigned_scbs queue if it
- *    finds one.  Otherwise it puts the current SCB onto the free_scbs
- *    queue for later use.
- *
- * 7) The driver handles page-in requests from the sequencer in response to
- *    the NO_MATCH sequencer interrupt.  For tagged commands, the appropriate
- *    SCB is easily found since the tag is a direct index into our kernel SCB
- *    array.  For non-tagged commands, we keep a separate array of 16 pointers
- *    that point to the single possible SCB that was paged out for that target.
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#if defined(__NetBSD__) || defined(__OpenBSD__)
 #include <sys/device.h>
 #include <machine/bus.h>
 #include <machine/intr.h>
-#endif /* defined(__NetBSD__) || defined(__OpenBSD__) */
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
 
 #include <sys/malloc.h>
 #include <sys/buf.h>
 
 #include <scsi/scsi_all.h>
 #include <scsi/scsi_message.h>
-#if defined(__NetBSD__) || defined(__OpenBSD__)
 #include <scsi/scsi_debug.h>
-#endif
 #include <scsi/scsiconf.h>
 
-#if defined(__FreeBSD__)
-#include <machine/clock.h>
-#endif
-
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
 
-#if defined(__FreeBSD__)
-#include <i386/scsi/aic7xxx.h>
-
-#include <dev/aic7xxx/aic7xxx_reg.h>
-#endif /* defined(__FreeBSD__) */
-
-#if defined(__NetBSD__) || defined(__OpenBSD__)
 #include <dev/ic/aic7xxxreg.h>
 #include <dev/ic/aic7xxxvar.h>
+#include <dev/microcode/aic7xxx/aic7xxx_seq.h>
+#include <dev/microcode/aic7xxx/sequencer.h>
+#include "pci.h"
 
-#define bootverbose    1
+/*
+ * Some ISA devices (e.g. on a VLB) can perform 32-bit DMA.  This
+ * flag is passed to bus_dmamap_create() to indicate that fact.
+ */
+#ifndef ISABUS_DMA_32BIT
+#define ISABUS_DMA_32BIT       BUS_DMA_BUS1
+#endif 
 
-#define DEBUGTARG      DEBUGTARGET
-#if DEBUGTARG < 0      /* Negative numbers for disabling cause warnings */
-#undef DEBUGTARG
-#define DEBUGTARG      17
+#ifndef AHC_TMODE_ENABLE
+#define AHC_TMODE_ENABLE 0
 #endif
-#ifdef alpha           /* XXX */
-/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */ 
-extern vm_offset_t alpha_XXX_dmamap(vm_offset_t);
-#undef vtophys
-#define        vtophys(va)     alpha_XXX_dmamap((vm_offset_t) va)
-#endif /* alpha */
-#endif /* defined(__NetBSD__) || defined(__OpenBSD__) */
-
 #include <sys/kernel.h>
-#define KVTOPHYS(x)   vtophys(x)
+#define offsetof(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
+
+#define        IS_SCSIBUS_B(ahc, sc_link)      \
+       ((sc_link)->scsibus == (ahc)->sc_link_b.scsibus)
+#define ALL_CHANNELS '\0'
+#define ALL_TARGETS_MASK 0xFFFF
+#define INITIATOR_WILDCARD     (~0)
 
-#define MIN(a,b) ((a < b) ? a : b)
-#define ALL_TARGETS -1
+#define        SIM_IS_SCSIBUS_B(ahc, sc_link)  \
+       ((sc_link)->scsibus == (ahc)->sc_link_b.scsibus)
+#define        SIM_CHANNEL(ahc, sc_link)       \
+       (SIM_IS_SCSIBUS_B(ahc, sc_link) ? 'B' : 'A')
+#define        SIM_SCSI_ID(ahc, sc_link)       \
+       (SIM_IS_SCSIBUS_B(ahc, sc_link) ? ahc->our_id_b : ahc->our_id)
+#define        SCB_IS_SCSIBUS_B(scb)   \
+       (((scb)->hscb->tcl & SELBUSB) != 0)
+#define        SCB_TARGET(scb) \
+       (((scb)->hscb->tcl & TID) >> 4)
+#define        SCB_CHANNEL(scb) \
+       (SCB_IS_SCSIBUS_B(scb) ? 'B' : 'A')
+#define        SCB_LUN(scb)    \
+       ((scb)->hscb->tcl & LID)
+#define SCB_TARGET_OFFSET(scb)         \
+       (SCB_TARGET(scb) + (SCB_IS_SCSIBUS_B(scb) ? 8 : 0))
+#define SCB_TARGET_MASK(scb)           \
+       (0x01 << (SCB_TARGET_OFFSET(scb)))
+#define TCL_CHANNEL(ahc, tcl)          \
+       ((((ahc)->features & AHC_TWIN) && ((tcl) & SELBUSB)) ? 'B' : 'A')
+#define TCL_SCSI_ID(ahc, tcl)          \
+       (TCL_CHANNEL((ahc), (tcl)) == 'B' ? (ahc)->our_id_b : (ahc)->our_id)
+#define TCL_TARGET(tcl) (((tcl) & TID) >> TCL_TARGET_SHIFT)
+#define TCL_LUN(tcl) ((tcl) & LID)
+
+#define XS_TCL(ahc, xs) \
+       ((((xs)->sc_link->target << 4) & 0xF0) \
+       | (SIM_IS_SCSIBUS_B((ahc), (xs)->sc_link) ? SELBUSB : 0) \
+       | ((xs)->sc_link->lun & 0x07))
 
-#if defined(__FreeBSD__)
-u_long ahc_unit = 0;
+/*
+ * Under normal circumstances, these messages are unnecessary
+ * and not terribly cosmetic.
+ */
+#ifdef DEBUG
+#define bootverbose    1
+#define STATIC
+#define INLINE
+#else
+#define bootverbose    0
+#define STATIC static
+#define INLINE __inline
 #endif
 
+typedef enum {
+       ROLE_UNKNOWN,
+       ROLE_INITIATOR,
+       ROLE_TARGET
+} role_t;
+
+struct ahc_devinfo {
+       int       our_scsiid;
+       int       target_offset;
+       u_int16_t target_mask;
+       u_int8_t  target;
+       u_int8_t  lun;
+       char      channel;
+       role_t    role;         /*
+                                * Only guaranteed to be correct if not
+                                * in the busfree state.
+                                */
+};
+
+typedef enum {
+       SEARCH_COMPLETE,
+       SEARCH_COUNT,
+       SEARCH_REMOVE
+} ahc_search_action;
+
 #ifdef AHC_DEBUG
 static int     ahc_debug = AHC_DEBUG;
 #endif
 
-#ifdef AHC_BROKEN_CACHE
-int ahc_broken_cache = 1;
-
-/*
- * "wbinvd" cause writing back whole cache (both CPU internal & external)
- * to memory, so that the instruction takes a lot of time.
- * This makes machine slow.
- */
-#define        INVALIDATE_CACHE()      __asm __volatile("wbinvd")
+#if NPCI > 0
+void ahc_pci_intr(struct ahc_softc *ahc);
 #endif
 
-/**** bit definitions for SCSIDEF ****/
-#define        HSCSIID         0x07            /* our SCSI ID */
-#define HWSCSIID       0x0f            /* our SCSI ID if Wide Bus */
+STATIC int     ahcinitscbdata(struct ahc_softc *ahc);
+STATIC void    ahcfiniscbdata(struct ahc_softc *ahc);
+
+STATIC int     ahc_poll __P((struct ahc_softc *ahc, int wait));
+STATIC void    ahc_shutdown __P((void *arg));
+STATIC int     ahc_execute_scb __P((void *arg, bus_dma_segment_t *dm_segs,
+                                    int nsegments));
+STATIC int     ahc_setup_data __P((struct ahc_softc *ahc,
+                                   struct scsi_xfer *xs, struct scb *scb));
+STATIC void    ahc_freeze_devq __P((struct ahc_softc *ahc,
+                                    struct scsi_link *sc_link));
+STATIC void    ahcallocscbs __P((struct ahc_softc *ahc));
+STATIC void    ahc_fetch_devinfo __P((struct ahc_softc *ahc,
+                                      struct ahc_devinfo *devinfo));
+STATIC void    ahc_compile_devinfo __P((struct ahc_devinfo *devinfo,
+                                        u_int our_id, u_int target,
+                                        u_int lun, char channel,
+                                        role_t role));
+STATIC u_int   ahc_abort_wscb __P((struct ahc_softc *ahc,
+                                   u_int scbpos, u_int prev));
+STATIC void    ahc_done __P((struct ahc_softc *ahc, struct scb *scbp));
+STATIC struct tmode_tstate *
+               ahc_alloc_tstate __P((struct ahc_softc *ahc, u_int scsi_id,
+                                     char channel));
+STATIC void    ahc_handle_seqint __P((struct ahc_softc *ahc, u_int intstat));
+STATIC void    ahc_handle_scsiint __P((struct ahc_softc *ahc, u_int intstat));
+STATIC void    ahc_build_transfer_msg __P((struct ahc_softc *ahc,
+                                           struct ahc_devinfo *devinfo));
+STATIC void    ahc_setup_initiator_msgout __P((struct ahc_softc *ahc,
+                                               struct ahc_devinfo *devinfo,
+                                               struct scb *scb));
+STATIC void    ahc_setup_target_msgin __P((struct ahc_softc *ahc,
+                                           struct ahc_devinfo *devinfo));
+STATIC int     ahc_handle_msg_reject __P((struct ahc_softc *ahc,
+                                          struct ahc_devinfo *devinfo));
+STATIC void    ahc_clear_msg_state __P((struct ahc_softc *ahc));
+STATIC void    ahc_handle_message_phase __P((struct ahc_softc *ahc,
+                                             struct scsi_link *sc_link));
+STATIC int     ahc_sent_msg __P((struct ahc_softc *ahc, u_int msgtype,
+                                 int full));
+
+typedef enum {
+       MSGLOOP_IN_PROG,
+       MSGLOOP_MSGCOMPLETE,
+       MSGLOOP_TERMINATED
+} msg_loop_stat;
+
+STATIC int     ahc_parse_msg __P((struct ahc_softc *ahc,
+                                  struct scsi_link *sc_link,
+                                  struct ahc_devinfo *devinfo));
+STATIC void    ahc_handle_ign_wide_residue __P((struct ahc_softc *ahc,
+                                                struct ahc_devinfo *devinfo));
+STATIC void    ahc_handle_devreset __P((struct ahc_softc *ahc,
+                                        struct ahc_devinfo *devinfo,
+                                        int status, char *message,
+                                        int verbose_level));
+#ifdef AHC_DUMP_SEQ
+STATIC void    ahc_dumpseq __P((struct ahc_softc *ahc));
+#endif
+STATIC void    ahc_loadseq __P((struct ahc_softc *ahc));
+STATIC int     ahc_check_patch __P((struct ahc_softc *ahc,
+                                    struct patch **start_patch,
+                                    int start_instr, int *skip_addr));
+STATIC void    ahc_download_instr __P((struct ahc_softc *ahc,
+                                       int instrptr, u_int8_t *dconsts));
+STATIC int     ahc_match_scb __P((struct scb *scb, int target, char channel,
+                                  int lun, u_int tag, role_t role));
+#ifdef AHC_DEBUG
+STATIC void    ahc_print_scb __P((struct scb *scb));
+#endif
+STATIC int     ahc_search_qinfifo __P((struct ahc_softc *ahc, int target,
+                                       char channel, int lun, u_int tag,
+                                       role_t role, u_int32_t status,
+                                       ahc_search_action action));
+STATIC int     ahc_reset_channel __P((struct ahc_softc *ahc, char channel,
+                                      int initiate_reset));
+STATIC int     ahc_abort_scbs __P((struct ahc_softc *ahc, int target,
+                                   char channel, int lun, u_int tag,
+                                   role_t role, u_int32_t status));
+STATIC int     ahc_search_disc_list __P((struct ahc_softc *ahc, int target,
+                                         char channel, int lun, u_int tag,
+                                         int stop_on_first, int remove,
+                                         int save_state));
+STATIC u_int   ahc_rem_scb_from_disc_list __P((struct ahc_softc *ahc,
+                                               u_int prev, u_int scbptr));
+STATIC void    ahc_add_curscb_to_free_list __P((struct ahc_softc *ahc));
+STATIC void    ahc_clear_intstat __P((struct ahc_softc *ahc));
+STATIC void    ahc_reset_current_bus __P((struct ahc_softc *ahc));
+STATIC struct ahc_syncrate *
+               ahc_devlimited_syncrate __P((struct ahc_softc *ahc, u_int *period));
+STATIC struct ahc_syncrate *
+               ahc_find_syncrate __P((struct ahc_softc *ahc, u_int *period,
+                                      u_int maxsync));
+STATIC u_int ahc_find_period __P((struct ahc_softc *ahc, u_int scsirate,
+                                 u_int maxsync));
+STATIC void    ahc_validate_offset __P((struct ahc_softc *ahc,
+                                        struct ahc_syncrate *syncrate,
+                                        u_int *offset, int wide)); 
+STATIC void    ahc_update_target_msg_request __P((struct ahc_softc *ahc,
+                                             struct ahc_devinfo *devinfo,
+                                             struct ahc_initiator_tinfo *tinfo,
+                                             int force, int paused));
+STATIC void    ahc_set_syncrate __P((struct ahc_softc *ahc,
+                                     struct ahc_devinfo *devinfo,
+                                     struct ahc_syncrate *syncrate,
+                                     u_int period, u_int offset,
+                                     u_int type, int paused, int done));
+STATIC void    ahc_set_width __P((struct ahc_softc *ahc,
+                             struct ahc_devinfo *devinfo,
+                             u_int width, u_int type, int paused, int done));
+STATIC void    ahc_set_tags __P((struct ahc_softc *ahc,
+                                 struct ahc_devinfo *devinfo,int enable));
+STATIC void    ahc_construct_sdtr __P((struct ahc_softc *ahc,
+                                  u_int period, u_int offset));
+STATIC void    ahc_construct_wdtr __P((struct ahc_softc *ahc, u_int bus_width));
+
+STATIC void    ahc_calc_residual __P((struct scb *scb));
+
+STATIC void    ahc_update_pending_syncrates __P((struct ahc_softc *ahc));
+
+STATIC void    ahc_set_recoveryscb __P((struct ahc_softc *ahc,
+                                        struct scb *scb));
+STATIC void ahc_timeout __P((void *));
+
+static __inline int  sequencer_paused __P((struct ahc_softc *ahc));
+static __inline void pause_sequencer __P((struct ahc_softc *ahc));
+static __inline void unpause_sequencer __P((struct ahc_softc *ahc));
+STATIC void restart_sequencer __P((struct ahc_softc *ahc));
+static __inline u_int ahc_index_busy_tcl __P((struct ahc_softc *ahc,
+                                             u_int tcl, int unbusy));
+static __inline void   ahc_busy_tcl __P((struct ahc_softc *ahc,
+                                         struct scb *scb));
+static __inline int    ahc_isbusy_tcl __P((struct ahc_softc *ahc,
+                                           struct scb *scb));
+static __inline void ahc_freeze_ccb __P((struct scb* scb));
+static __inline void ahcsetccbstatus __P((struct scsi_xfer *xs, int status));
+STATIC void ahc_run_qoutfifo __P((struct ahc_softc *ahc));
+
+static __inline struct ahc_initiator_tinfo *
+       ahc_fetch_transinfo __P((struct ahc_softc *ahc, char channel,
+                                u_int our_id, u_int target,
+                                struct tmode_tstate **tstate));
+STATIC void ahcfreescb __P((struct ahc_softc *ahc, struct scb *scb));
+static __inline struct scb *ahcgetscb __P((struct ahc_softc *ahc));
+int    ahc_createdmamem __P((struct ahc_softc *ahc, int size,
+                            bus_dmamap_t *mapp, caddr_t *vaddr,
+                            bus_addr_t *baddr, bus_dma_segment_t *segs,
+                            int *nseg, const char *what));
+STATIC void ahc_freedmamem __P((bus_dma_tag_t tag, int size,
+                               bus_dmamap_t map, caddr_t vaddr,
+                               bus_dma_segment_t *seg, int nseg));
+STATIC void ahcminphys __P((struct buf *bp));
+
+STATIC INLINE  struct scsi_xfer *ahc_first_xs __P((struct ahc_softc *));
+STATIC INLINE  void   ahc_list_insert_before __P((struct ahc_softc *ahc,
+                                                  struct scsi_xfer *xs,
+                                                  struct scsi_xfer *next_xs));
+STATIC INLINE  void   ahc_list_insert_head __P((struct ahc_softc *ahc,
+                                                struct scsi_xfer *xs));
+STATIC INLINE  void   ahc_list_insert_tail __P((struct ahc_softc *ahc,
+                                                struct scsi_xfer *xs));
+STATIC INLINE  void   ahc_list_remove __P((struct ahc_softc *ahc,
+                                           struct scsi_xfer *xs));
+STATIC INLINE  struct scsi_xfer *ahc_list_next __P((struct ahc_softc *ahc,
+                                                    struct scsi_xfer *xs));
+
+STATIC int32_t ahc_scsi_cmd __P((struct scsi_xfer *xs));
 
-static void     ahcminphys __P((struct buf *bp));
-static int32_t  ahc_scsi_cmd __P((struct scsi_xfer *xs));
-static inline void pause_sequencer __P((struct ahc_data *ahc));
-static inline void unpause_sequencer __P((struct ahc_data *ahc,
-                                         int unpause_always));
-static inline void restart_sequencer __P((struct ahc_data *ahc));
+struct cfdriver ahc_cd = {
+       NULL, "ahc", DV_DULL
+};
 
 static struct scsi_adapter ahc_switch =
 {
-        ahc_scsi_cmd,
-        ahcminphys,
-        0,
-        0,
-#if defined(__FreeBSD__)
-        0,
-        "ahc",
-        { 0, 0 }
-#endif
+       ahc_scsi_cmd,
+       ahcminphys,
+       0,
+       0,
 };
 
 /* the below structure is so we have a default dev struct for our link struct */
 static struct scsi_device ahc_dev =
 {
-    NULL,                       /* Use default error handler */
-    NULL,                       /* have a queue, served by this */
-    NULL,                       /* have no async handler */
-    NULL,                       /* Use default 'done' routine */
-#if defined(__FreeBSD__)
-    "ahc",
-    0,
-    { 0, 0 }
-#endif
+       NULL, /* Use default error handler */
+       NULL, /* have a queue, served by this */
+       NULL, /* have no async handler */
+       NULL, /* Use default 'done' routine */
 };
 
-static inline void
+STATIC void
+ahcminphys(bp)
+       struct buf *bp;
+{
+/*
+ * Even though the card can transfer up to 16megs per command
+ * we are limited by the number of segments in the dma segment
+ * list that we can hold.  The worst case is that all pages are
+ * discontinuous physically, hense the "page per segment" limit
+ * enforced here.
+ */
+       if (bp->b_bcount > ((AHC_NSEG - 1) * PAGE_SIZE)) {
+               bp->b_bcount = ((AHC_NSEG - 1) * PAGE_SIZE);
+       }
+       minphys(bp);
+}
+
+
+static __inline u_int32_t
+ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
+{
+       return (ahc->scb_data->hscb_busaddr
+               + (sizeof(struct hardware_scb) * index));
+}
+
+#define AHC_BUSRESET_DELAY     25      /* Reset delay in us */
+
+static __inline int
+sequencer_paused(ahc)
+       struct ahc_softc *ahc;
+{
+       return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
+}
+
+static __inline void
 pause_sequencer(ahc)
-       struct ahc_data *ahc;
+       struct ahc_softc *ahc;
 {
-       AHC_OUTB(ahc, HCNTRL, ahc->pause);
+       ahc_outb(ahc, HCNTRL, ahc->pause);
 
        /*
         * Since the sequencer can disable pausing in a critical section, we
         * must loop until it actually stops.
         */
-       while ((AHC_INB(ahc, HCNTRL) & PAUSE) == 0)
+       while (sequencer_paused(ahc) == 0)
                ;
 }
 
-static inline void
-unpause_sequencer(ahc, unpause_always)
-       struct ahc_data *ahc;
-       int unpause_always;
+static __inline void
+unpause_sequencer(ahc)
+       struct ahc_softc *ahc;
 {
-       if (unpause_always
-        ||(AHC_INB(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
-               AHC_OUTB(ahc, HCNTRL, ahc->unpause);
+       if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
+               ahc_outb(ahc, HCNTRL, ahc->unpause);
 }
 
 /*
  * Restart the sequencer program from address zero
  */
-static inline void
+STATIC void
 restart_sequencer(ahc)
-       struct ahc_data *ahc;
+       struct ahc_softc *ahc;
 {
-       do {
-               AHC_OUTB(ahc, SEQCTL, SEQRESET|FASTMODE);
-       } while((AHC_INB(ahc, SEQADDR0) != 0)
-               || (AHC_INB(ahc, SEQADDR1) != 0));
+       u_int i;
+
+       pause_sequencer(ahc);
+
+       /*
+        * Everytime we restart the sequencer, there
+        * is the possiblitity that we have restarted
+        * within a three instruction window where an
+        * SCB has been marked free but has not made it
+        * onto the free list.  Since SCSI events(bus reset,
+        * unexpected bus free) will always freeze the
+        * sequencer, we cannot close this window.  To
+        * avoid losing an SCB, we reconsitute the free
+        * list every time we restart the sequencer.
+        */
+       ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
+       for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+               
+               ahc_outb(ahc, SCBPTR, i);
+               if (ahc_inb(ahc, SCB_TAG) == SCB_LIST_NULL)
+                       ahc_add_curscb_to_free_list(ahc);
+       }
+       ahc_outb(ahc, SEQCTL, FASTMODE|SEQRESET);
+       unpause_sequencer(ahc);
+}
+
+static __inline u_int
+ahc_index_busy_tcl(ahc, tcl, unbusy)
+       struct ahc_softc *ahc;
+       u_int tcl;
+       int unbusy;
+{
+       u_int scbid;
+
+       scbid = ahc->untagged_scbs[tcl];
+       if (unbusy) {
+               ahc->untagged_scbs[tcl] = SCB_LIST_NULL;
+               bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, 
+                               BUS_DMASYNC_PREWRITE);
+       }
+
+       return (scbid);
+}
+
+static __inline void
+ahc_busy_tcl(ahc, scb)
+       struct ahc_softc *ahc;
+       struct scb *scb;
+{
+       ahc->untagged_scbs[scb->hscb->tcl] = scb->hscb->tag;
+       bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, 
+                       BUS_DMASYNC_PREWRITE);
+}
+
+static __inline int
+ahc_isbusy_tcl(ahc, scb)
+       struct ahc_softc *ahc;
+       struct scb *scb;
+{
+       return ahc->untagged_scbs[scb->hscb->tcl] != SCB_LIST_NULL;
+}
+
+static __inline void
+ahc_freeze_ccb(scb)
+       struct scb *scb;
+{
+       struct scsi_xfer *xs = scb->xs;
+       struct ahc_softc *ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
+       int target;
+
+       target = xs->sc_link->target;
+       if (!(scb->flags & SCB_FREEZE_QUEUE)) {
+               ahc->devqueue_blocked[target]++;
+               scb->flags |= SCB_FREEZE_QUEUE;
+       }
+}
+
+static __inline void
+ahcsetccbstatus(xs, status)
+       struct scsi_xfer *xs;
+       int status;
+{
+       xs->error = status;
+}
+
+static __inline struct ahc_initiator_tinfo *
+ahc_fetch_transinfo(ahc, channel, our_id, remote_id, tstate)
+       struct ahc_softc *ahc;
+       char channel;
+       u_int our_id;
+       u_int remote_id;
+       struct tmode_tstate **tstate;
+{
+       /*
+        * Transfer data structures are stored from the perspective
+        * of the target role.  Since the parameters for a connection
+        * in the initiator role to a given target are the same as
+        * when the roles are reversed, we pretend we are the target.
+        */
+       if (channel == 'B')
+               our_id += 8;
+       *tstate = ahc->enabled_targets[our_id];
+       return (&(*tstate)->transinfo[remote_id]);
+}
+
+STATIC void
+ahc_run_qoutfifo(ahc)
+       struct ahc_softc *ahc;
+{
+       struct scb *scb;
+       u_int  scb_index;
+
+       bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, 
+                       BUS_DMASYNC_POSTREAD);
+
+       while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) {
+               scb_index = ahc->qoutfifo[ahc->qoutfifonext];
+               ahc->qoutfifo[ahc->qoutfifonext++] = SCB_LIST_NULL;
+
+               scb = &ahc->scb_data->scbarray[scb_index];
+               if (scb_index >= ahc->scb_data->numscbs
+                 || (scb->flags & SCB_ACTIVE) == 0) {
+                       printf("%s: WARNING no command for scb %d "
+                              "(cmdcmplt)\nQOUTPOS = %d\n",
+                              ahc_name(ahc), scb_index,
+                              ahc->qoutfifonext - 1);
+                       continue;
+               }
 
-       unpause_sequencer(ahc, /*unpause_always*/TRUE);
+               /*
+                * Save off the residual
+                * if there is one.
+                */
+               if (scb->hscb->residual_SG_count != 0)
+                       ahc_calc_residual(scb);
+               else
+                       scb->xs->resid = 0;
+               ahc_done(ahc, scb);
+       }
 }
 
-#if defined(__NetBSD__) || defined(__OpenBSD__)
+
 /*
- * Is device which is pointed by sc_link connected on second scsi bus ?
+ * An scb (and hence an scb entry on the board) is put onto the
+ * free list.
  */
-#define        IS_SCSIBUS_B(ahc, sc_link)      \
-       ((sc_link)->scsibus == (ahc)->sc_link_b.scsibus)
+STATIC void
+ahcfreescb(ahc, scb)
+       struct ahc_softc *ahc;
+       struct scb *scb;
+{       
+       struct hardware_scb *hscb;
+       int opri;
+
+       hscb = scb->hscb;
+       opri = splbio();
+
+       if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0 ||
+           (scb->flags & SCB_RECOVERY_SCB) != 0) {
+               ahc->flags &= ~AHC_RESOURCE_SHORTAGE;
+               ahc->queue_blocked = 0;
+       }
+
+       /* Clean up for the next user */
+       scb->flags = SCB_FREE;
+       hscb->control = 0;
+       hscb->status = 0;
+
+       SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links);
+       splx(opri);
+}
 
 /*
- * convert FreeBSD's SCSI symbols to Net- & OpenBSD's
+ * Get a free scb, either one already assigned to a hardware slot
+ * on the adapter or one that will require an SCB to be paged out before
+ * use. If there are none, see if we can allocate a new SCB.  Otherwise
+ * either return an error or sleep.
  */
-#define        SCSI_NOMASK     SCSI_POLL
-#define        opennings       openings
-#endif
+static __inline struct scb *
+ahcgetscb(ahc)
+       struct ahc_softc *ahc;
+{
+       struct scb *scbp;
+       int opri;
 
-static u_char  ahc_abort_wscb __P((struct ahc_data *ahc, struct scb *scbp,
-                                   u_char prev,
-                                   u_char timedout_scb, u_int32_t xs_error));
-static void    ahc_add_waiting_scb __P((struct ahc_data *ahc,
-                                        struct scb *scb));
-static void    ahc_done __P((struct ahc_data *ahc, struct scb *scbp));
-static void    ahc_free_scb __P((struct ahc_data *ahc, struct scb *scb,
-                                 int flags));
-static inline void ahc_send_scb __P((struct ahc_data *ahc, struct scb *scb));
-static inline void ahc_fetch_scb __P((struct ahc_data *ahc, struct scb *scb));
-static inline void ahc_page_scb __P((struct ahc_data *ahc, struct scb *out_scb,
-                               struct scb *in_scb));
-static inline void ahc_run_waiting_queues __P((struct ahc_data *ahc));
-static void    ahc_handle_seqint __P((struct ahc_data *ahc, u_int8_t intstat));
-static struct scb *
-               ahc_get_scb __P((struct ahc_data *ahc, int flags));
-static void    ahc_loadseq __P((struct ahc_data *ahc));
-static int     ahc_match_scb __P((struct scb *scb, int target, char channel));
-static int     ahc_poll __P((struct ahc_data *ahc, int wait));
-#ifdef AHC_DEBUG
-static void    ahc_print_scb __P((struct scb *scb));
-#endif
-static int     ahc_reset_channel __P((struct ahc_data *ahc, char channel,
-                                      u_char timedout_scb, u_int32_t xs_error,
-                                      u_char initiate_reset));
-static int     ahc_reset_device __P((struct ahc_data *ahc, int target,
-                                     char channel, u_char timedout_scb,
-                                     u_int32_t xs_error));
-static void    ahc_reset_current_bus __P((struct ahc_data *ahc));
-static void    ahc_run_done_queue __P((struct ahc_data *ahc));
-static void    ahc_scsirate __P((struct ahc_data* ahc, u_int8_t *scsirate,
-                                 u_int8_t *period, u_int8_t *offset,
-                                 char channel, int target));
-#if defined(__FreeBSD__)
-static timeout_t
-               ahc_timeout;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-static void    ahc_timeout __P((void *));
-#endif
-static void    ahc_busy_target __P((struct ahc_data *ahc,
-                                    int target, char channel));
-static void    ahc_unbusy_target __P((struct ahc_data *ahc,
-                                      int target, char channel));
-static void    ahc_construct_sdtr __P((struct ahc_data *ahc, int start_byte,
-                                       u_int8_t period, u_int8_t offset));  
-static void    ahc_construct_wdtr __P((struct ahc_data *ahc, int start_byte,
-                                       u_int8_t bus_width));
-
-#if defined(__NetBSD__) || defined(__OpenBSD__)        /* XXX */
-static void    ahc_xxx_enqueue __P((struct ahc_data *ahc,
-                   struct scsi_xfer *xs, int infront));
-static struct scsi_xfer *ahc_xxx_dequeue __P((struct ahc_data *ahc));
-#endif
+       opri = splbio();
+       if ((scbp = SLIST_FIRST(&ahc->scb_data->free_scbs))) {
+               SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links);
+       } else {
+               ahcallocscbs(ahc);
+               scbp = SLIST_FIRST(&ahc->scb_data->free_scbs);
+               if (scbp != NULL)
+                       SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links);
+       }
+
+       splx(opri);
 
-#if defined(__FreeBSD__)
+       return (scbp);
+}
 
-char *ahc_name(ahc)
-       struct ahc_data *ahc;
+int
+ahc_createdmamem(ahc, size, mapp, vaddr, baddr, seg, nseg, what)
+       struct ahc_softc *ahc;
+       int size;
+       bus_dmamap_t *mapp;
+       caddr_t *vaddr;
+       bus_addr_t *baddr;
+       bus_dma_segment_t *seg;
+       int *nseg;
+       const char *what;
 {
-       static char name[10];
+       int error, rseg, level = 0;
+       int dma_flags = BUS_DMA_NOWAIT;
+       bus_dma_tag_t tag = ahc->sc_dmat;
+       const char *myname = ahc_name(ahc);
+       if ((ahc->chip & AHC_VL) !=0)
+               dma_flags |= ISABUS_DMA_32BIT;
+       
+       if ((error = bus_dmamem_alloc(tag, size, NBPG, 0,
+                       seg, 1, nseg, BUS_DMA_NOWAIT)) != 0) {
+               printf("%s: failed to allocate DMA mem for %s, error = %d\n",
+                       myname, what, error);
+               goto out;
+       }
+       level++;
+
+       if ((error = bus_dmamem_map(tag, seg, *nseg, size, vaddr,
+                       BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
+               printf("%s: failed to map DMA mem for %s, error = %d\n",
+                       myname, what, error);
+               goto out;
+       }
+       level++;
+
+       if ((error = bus_dmamap_create(tag, size, 1, size, 0,
+                       dma_flags, mapp)) != 0) {
+               printf("%s: failed to create DMA map for %s, error = %d\n",
+                       myname, what, error);
+               goto out;
+        }
+       level++;
 
-       sprintf(name, "ahc%d", ahc->unit);
-       return (name);
+       if ((error = bus_dmamap_load(tag, *mapp, *vaddr, size, NULL,
+                       BUS_DMA_NOWAIT)) != 0) {
+               printf("%s: failed to load DMA map for %s, error = %d\n",
+                       myname, what, error);
+               goto out;
+        }
+
+       *baddr = seg[0].ds_addr;
+
+       if (bootverbose)
+               printf("%s: dmamem for %s at phys %lx virt %lx nseg %d size %d\n",
+                      myname, what, (unsigned long)*baddr,
+                      (unsigned long)*vaddr, *nseg, size);
+       return 0;
+out:
+       switch (level) {
+       case 3:
+               bus_dmamap_destroy(tag, *mapp);
+               /* FALLTHROUGH */
+       case 2:
+               bus_dmamem_unmap(tag, *vaddr, size);
+               /* FALLTHROUGH */
+       case 1:
+               bus_dmamem_free(tag, seg, rseg);
+               break;
+       default:
+               break;
+       }
+
+       return error;
 }
 
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-struct cfdriver ahc_cd = {
-       NULL, "ahc", DV_DULL
-};
-#endif
+STATIC void
+ahc_freedmamem(tag, size, map, vaddr, seg, nseg)
+       bus_dma_tag_t tag;
+       int size;
+       bus_dmamap_t map;
+       caddr_t vaddr;
+       bus_dma_segment_t *seg;
+       int nseg;
+{
+
+       bus_dmamap_unload(tag, map);
+       bus_dmamap_destroy(tag, map);
+       bus_dmamem_unmap(tag, vaddr, size);
+       bus_dmamem_free(tag, seg, nseg);
+}
 
 #ifdef  AHC_DEBUG
-static void
+STATIC void
 ahc_print_scb(scb)
-        struct scb *scb;
-{
-        printf("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n"
-           ,scb
-           ,scb->control
-           ,scb->tcl
-           ,scb->cmdlen
-           ,scb->cmdpointer );
-        printf("        datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n"
-           ,scb->datalen
-           ,scb->data
-           ,scb->SG_segment_count
-           ,scb->SG_list_pointer);
-       printf("        sg_addr:%lx sg_len:%ld\n"
-           ,scb->ahc_dma[0].addr
-           ,scb->ahc_dma[0].len);
+       struct scb *scb;
+{
+       struct hardware_scb *hscb = scb->hscb;
+
+       printf("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
+               scb,
+               hscb->control,
+               hscb->tcl,
+               hscb->cmdlen,
+               hscb->cmdpointer );
+       printf("        datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
+               hscb->datalen,
+               hscb->data,
+               hscb->SG_count,
+               hscb->SG_pointer);
+       printf("        sg_addr:%lx sg_len:%ld\n",
+               scb->sg_list[0].addr,
+               scb->sg_list[0].len);
+       printf("        cdb:%x %x %x %x %x %x %x %x %x %x %x %x\n",
+               hscb->cmdstore[0], hscb->cmdstore[1], hscb->cmdstore[2],
+               hscb->cmdstore[3], hscb->cmdstore[4], hscb->cmdstore[5],
+               hscb->cmdstore[6], hscb->cmdstore[7], hscb->cmdstore[8],
+               hscb->cmdstore[9], hscb->cmdstore[10], hscb->cmdstore[11]);
 }
-
 #endif
 
 static struct {
-        u_char errno;
+        u_int8_t errno;
        char *errmesg;
 } hard_error[] = {
-       { ILLHADDR,  "Illegal Host Access" },
-       { ILLSADDR,  "Illegal Sequencer Address referenced" },
-       { ILLOPCODE, "Illegal Opcode in sequencer program" },
-       { PARERR,    "Sequencer Ram Parity Error" }
+       { ILLHADDR,     "Illegal Host Access" },
+       { ILLSADDR,     "Illegal Sequencer Address referrenced" },
+       { ILLOPCODE,    "Illegal Opcode in sequencer program" },
+       { SQPARERR,     "Sequencer Parity Error" },
+       { DPARERR,      "Data-path Parity Error" },
+       { MPARERR,      "Scratch or SCB Memory Parity Error" },
+       { PCIERRSTAT,   "PCI Error detected" },
+       { CIOPARERR,    "CIOBUS Parity Error" },
 };
+static const int num_errors = sizeof(hard_error)/sizeof(hard_error[0]);
 
+static struct {
+        u_int8_t phase;
+        u_int8_t mesg_out; /* Message response to parity errors */
+       char *phasemsg;
+} phase_table[] = {
+       { P_DATAOUT,    MSG_NOOP,               "in Data-out phase"     },
+       { P_DATAIN,     MSG_INITIATOR_DET_ERR,  "in Data-in phase"      },
+       { P_COMMAND,    MSG_NOOP,               "in Command phase"      },
+       { P_MESGOUT,    MSG_NOOP,               "in Message-out phase"  },
+       { P_STATUS,     MSG_INITIATOR_DET_ERR,  "in Status phase"       },
+       { P_MESGIN,     MSG_PARITY_ERROR,       "in Message-in phase"   },
+       { P_BUSFREE,    MSG_NOOP,               "while idle"            },
+       { 0,            MSG_NOOP,               "in unknown phase"      }
+};
+static const int num_phases = (sizeof(phase_table)/sizeof(phase_table[0])) - 1;
 
 /*
  * Valid SCSIRATE values.  (p. 3-17)
  * Provides a mapping of tranfer periods in ns to the proper value to
  * stick in the scsiscfr reg to use that transfer rate.
  */
-static struct {
-       short sxfr;
-       /* Rates in Ultra mode have bit 8 of sxfr set */
-#define                ULTRA_SXFR 0x100
-       int period; /* in ns/4 */
-       char *rate;
-} ahc_syncrates[] = {
-       { 0x100, 12, "20.0"  },
-       { 0x110, 15, "16.0"  },
-       { 0x120, 18, "13.4"  },
-       { 0x000, 25, "10.0"  },
-       { 0x010, 31,  "8.0"  },
-       { 0x020, 37,  "6.67" },
-       { 0x030, 43,  "5.7"  },
-       { 0x040, 50,  "5.0"  },
-       { 0x050, 56,  "4.4"  },
-       { 0x060, 62,  "4.0"  },
-       { 0x070, 68,  "3.6"  }
+#define AHC_SYNCRATE_DT                0
+#define AHC_SYNCRATE_ULTRA2    1
+#define AHC_SYNCRATE_ULTRA     2
+#define AHC_SYNCRATE_FAST      5
+static struct ahc_syncrate ahc_syncrates[] = {
+      /* ultra2    fast/ultra  period     rate */
+       { 0x42,      0x000,      9,      "80.0" },
+       { 0x03,      0x000,     10,      "40.0" },
+       { 0x04,      0x000,     11,      "33.0" },
+       { 0x05,      0x100,     12,      "20.0" },
+       { 0x06,      0x110,     15,      "16.0" },
+       { 0x07,      0x120,     18,      "13.4" },
+       { 0x08,      0x000,     25,      "10.0" },
+       { 0x19,      0x010,     31,      "8.0"  },
+       { 0x1a,      0x020,     37,      "6.67" },
+       { 0x1b,      0x030,     43,      "5.7"  },
+       { 0x1c,      0x040,     50,      "5.0"  },
+       { 0x00,      0x050,     56,      "4.4"  },
+       { 0x00,      0x060,     62,      "4.0"  },
+       { 0x00,      0x070,     68,      "3.6"  },
+       { 0x00,      0x000,      0,      NULL   }
 };
 
-static int ahc_num_syncrates =
-       sizeof(ahc_syncrates) / sizeof(ahc_syncrates[0]);
-
 /*
  * Allocate a controller structure for a new device and initialize it.
  * ahc_reset should be called before now since we assume that the card
  * is paused.
  */
-#if defined(__FreeBSD__)
-struct ahc_data *
-ahc_alloc(unit, iobase, type, flags)
-       int unit;
-       u_long iobase;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
 void
-ahc_construct(ahc, iot, ioh, type, flags)
-       struct  ahc_data *ahc;
+ahc_construct(ahc, iot, ioh, chip, flags, features, channel)
+       struct  ahc_softc *ahc;
        bus_space_tag_t iot;
        bus_space_handle_t ioh;
-#endif
-       ahc_type type;
+       ahc_chip chip;
        ahc_flag flags;
+       ahc_feature features;
+       u_char channel;
 {
-
        /*
         * find unit and check we have that many defined
         */
-
-#if defined(__FreeBSD__)
-       struct  ahc_data *ahc;
-
-       /*
-        * Allocate a storage area for us
-        */
-
-       ahc = malloc(sizeof(struct ahc_data), M_TEMP, M_NOWAIT);
-       if (!ahc) {
-               printf("ahc%d: cannot malloc!\n", unit);
-               return NULL;
-       }
-       bzero(ahc, sizeof(struct ahc_data));
-#endif
-       STAILQ_INIT(&ahc->free_scbs);
-       STAILQ_INIT(&ahc->page_scbs);
-       STAILQ_INIT(&ahc->waiting_scbs);
-       STAILQ_INIT(&ahc->assigned_scbs);
-#if defined(__FreeBSD__)
-       ahc->unit = unit;
-#endif
-#if defined(__FreeBSD__)
-       ahc->baseport = iobase;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
+       LIST_INIT(&ahc->pending_scbs);
        ahc->sc_iot = iot;
        ahc->sc_ioh = ioh;
-#endif
-       ahc->type = type;
+       ahc->chip = chip;
        ahc->flags = flags;
-       ahc->unpause = (AHC_INB(ahc, HCNTRL) & IRQMS) | INTEN;
+       ahc->features = features;
+       ahc->channel = channel;
+       ahc->scb_data = NULL;
+       ahc->pci_intr_func = NULL;
+
+       ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN;
+       /* The IRQMS bit is only valid on VL and EISA chips */
+       if ((ahc->chip & AHC_PCI) != 0)
+               ahc->unpause &= ~IRQMS;
        ahc->pause = ahc->unpause | PAUSE;
-
-#if defined(__FreeBSD__)
-       return (ahc);
-#endif
 }
 
 void
 ahc_free(ahc)
-       struct ahc_data *ahc;
+       struct ahc_softc *ahc;
 {
-#if defined(__FreeBSD__)
-       free(ahc, M_DEVBUF);
+       ahcfiniscbdata(ahc);
+       if (ahc->init_level != 0)
+               ahc_freedmamem(ahc->sc_dmat, ahc->shared_data_size,
+                   ahc->shared_data_dmamap, ahc->qoutfifo,
+                   &ahc->shared_data_seg, ahc->shared_data_nseg);
+
+       if (ahc->scb_data != NULL)
+               free(ahc->scb_data, M_DEVBUF);
+       if (ahc->pci_data != NULL)
+               free(ahc->pci_data, M_DEVBUF);
        return;
-#endif
+}
+
+STATIC int
+ahcinitscbdata(ahc)
+       struct ahc_softc *ahc;
+{
+       struct scb_data *scb_data;
+       int i;
+       
+       scb_data = ahc->scb_data;
+       SLIST_INIT(&scb_data->free_scbs);
+       SLIST_INIT(&scb_data->sg_maps);
+
+       /* Allocate SCB resources */
+       scb_data->scbarray =
+           (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX,
+                                M_DEVBUF, M_NOWAIT);
+       if (scb_data->scbarray == NULL)
+               return (ENOMEM);
+       bzero(scb_data->scbarray, sizeof(struct scb) * AHC_SCB_MAX);
+
+       /* Determine the number of hardware SCBs and initialize them */
+
+       scb_data->maxhscbs = ahc_probe_scbs(ahc);
+       /* SCB 0 heads the free list */
+       ahc_outb(ahc, FREE_SCBH, 0);
+       for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+               ahc_outb(ahc, SCBPTR, i);
+
+               /* Clear the control byte. */
+               ahc_outb(ahc, SCB_CONTROL, 0);
+
+               /* Set the next pointer */
+               ahc_outb(ahc, SCB_NEXT, i+1);
+
+               /* Make the tag number invalid */
+               ahc_outb(ahc, SCB_TAG, 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);
+
+       /* Ensure we clear the 0 SCB's control byte. */
+       ahc_outb(ahc, SCBPTR, 0);
+       ahc_outb(ahc, SCB_CONTROL, 0);
+
+       scb_data->maxhscbs = i;
+
+       if (ahc->scb_data->maxhscbs == 0)
+               panic("%s: No SCB space found", ahc_name(ahc));
+
+       /*
+        * Create our DMA tags.  These tags define the kinds of device
+        * accessable memory allocations and memory mappings we will
+        * need to perform during normal operation.
+        *
+        * Unless we need to further restrict the allocation, we rely
+        * on the restrictions of the parent dmat, hence the common
+        * use of MAXADDR and MAXSIZE.
+        */
+
+       if (ahc_createdmamem(ahc,
+           AHC_SCB_MAX * sizeof(struct hardware_scb), 
+           &scb_data->hscb_dmamap, (caddr_t *)&scb_data->hscbs, 
+           &scb_data->hscb_busaddr, &scb_data->hscb_seg,
+           &scb_data->hscb_nseg, "hardware SCB structures") < 0)
+               goto error_exit;
+
+       scb_data->init_level++;
+
+       if (ahc_createdmamem(ahc,
+           AHC_SCB_MAX * sizeof(struct scsi_sense_data),
+           &scb_data->sense_dmamap, (caddr_t *)&scb_data->sense,
+           &scb_data->sense_busaddr, &scb_data->sense_seg,
+           &scb_data->sense_nseg, "sense buffers") < 0)
+               goto error_exit;
+
+       scb_data->init_level++;
+
+       /* Perform initial CCB allocation */
+       bzero(scb_data->hscbs, AHC_SCB_MAX * sizeof(struct hardware_scb));
+       ahcallocscbs(ahc);
+
+       if (scb_data->numscbs == 0) {
+               printf("%s: ahc_init_scb_data - "
+                      "Unable to allocate initial scbs\n",
+                      ahc_name(ahc));
+               goto error_exit;
+       }
+
+       scb_data->init_level++;
+
+       /*
+        * Note that we were successfull
+        */
+       return 0; 
+
+error_exit:
+
+       return ENOMEM;
+}
+
+STATIC void
+ahcfiniscbdata(ahc)
+       struct ahc_softc *ahc;
+{
+       struct scb_data *scb_data;
+
+       scb_data = ahc->scb_data;
+
+       switch (scb_data->init_level) {
+       default:
+       case 3:
+       {
+               struct sg_map_node *sg_map;
+
+               while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) {
+                       SLIST_REMOVE_HEAD(&scb_data->sg_maps, links);
+                       ahc_freedmamem(ahc->sc_dmat, PAGE_SIZE,
+                           sg_map->sg_dmamap, (caddr_t)sg_map->sg_vaddr,
+                           &sg_map->sg_dmasegs, sg_map->sg_nseg);
+                       free(sg_map, M_DEVBUF);
+               }
+       }
+       /*FALLTHROUGH*/
+       case 2:
+               ahc_freedmamem(ahc->sc_dmat,
+                   AHC_SCB_MAX * sizeof(struct scsi_sense_data),
+                   scb_data->sense_dmamap, (caddr_t)scb_data->sense,
+                   &scb_data->sense_seg, scb_data->sense_nseg);
+       /*FALLTHROUGH*/
+       case 1:
+               ahc_freedmamem(ahc->sc_dmat,
+                   AHC_SCB_MAX * sizeof(struct hardware_scb), 
+                   scb_data->hscb_dmamap, (caddr_t)scb_data->hscbs,
+                   &scb_data->hscb_seg, scb_data->hscb_nseg);
+       /*FALLTHROUGH*/
+       }
+       if (scb_data->scbarray != NULL)
+               free(scb_data->scbarray, M_DEVBUF);
 }
 
 void
-#if defined(__FreeBSD__)
-ahc_reset(iobase)
-       u_long iobase;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-ahc_reset(devname, iot, ioh)
+ahc_xxx_reset(devname, iot, ioh)
        char *devname;
        bus_space_tag_t iot;
        bus_space_handle_t ioh;
-#endif
 {
-        u_char hcntrl;
+       u_char hcntrl;
        int wait;
 
+#ifdef AHC_DUMP_SEQ
+       ahc_dumpseq(ahc);
+#endif
        /* Retain the IRQ type accross the chip reset */
-#if defined(__FreeBSD__)
-       hcntrl = (inb(HCNTRL + iobase) & IRQMS) | INTEN;
-
-       outb(HCNTRL + iobase, CHIPRST | PAUSE);
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
        hcntrl = (bus_space_read_1(iot, ioh, HCNTRL) & IRQMS) | INTEN;
 
        bus_space_write_1(iot, ioh, HCNTRL, CHIPRST | PAUSE);
-#endif
        /*
         * Ensure that the reset has finished
         */
        wait = 1000;
-#if defined(__FreeBSD__)
-       while (--wait && !(inb(HCNTRL + iobase) & CHIPRSTACK))
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
        while (--wait && !(bus_space_read_1(iot, ioh, HCNTRL) & CHIPRSTACK))
-#endif
                DELAY(1000);
-       if(wait == 0) {
-#if defined(__FreeBSD__)
-               printf("ahc at 0x%lx: WARNING - Failed chip reset!  "
-                      "Trying to initialize anyway.\n", iobase);
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
+       if (wait == 0) {
                printf("%s: WARNING - Failed chip reset!  "
-                      "Trying to initialize anyway.\n", devname);
-#endif
+                                "Trying to initialize anyway.\n", devname);
        }
-#if defined(__FreeBSD__)
-       outb(HCNTRL + iobase, hcntrl | PAUSE);
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
        bus_space_write_1(iot, ioh, HCNTRL, hcntrl | PAUSE);
-#endif
 }
 
-/*
- * Look up the valid period to SCSIRATE conversion in our table.
- */
-static void
-ahc_scsirate(ahc, scsirate, period, offset, channel, target )
-       struct   ahc_data *ahc;
-       u_int8_t *scsirate;
-       u_int8_t *period;
-       u_int8_t *offset;
-       char     channel;
-       int      target;
+int
+ahc_reset(ahc)
+       struct ahc_softc *ahc;
 {
-       int i;
-       u_int32_t ultra_enb_addr;
-       u_int8_t  sxfrctl0;
-       u_int8_t  ultra_enb;
-
-       i = ahc_num_syncrates; /* Default to async */
+       u_int   sblkctl;
+       int     wait;
        
-       if (*period >= ahc_syncrates[0].period && *offset != 0) {
-               for (i = 0; i < ahc_num_syncrates; i++) {
+#ifdef AHC_DUMP_SEQ
+       if (ahc->init_level == 0)
+               ahc_dumpseq(ahc);
+#endif
+       ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause);
+       /*
+        * Ensure that the reset has finished
+        */
+       wait = 1000;
+       do {
+               DELAY(1000);
+       } while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK));
 
-                       if (*period <= ahc_syncrates[i].period) {
-                               /*
-                                * Watch out for Ultra speeds when ultra is not
-                                * enabled and vice-versa.
-                                */
-                               if(!(ahc->type & AHC_ULTRA) 
-                                && (ahc_syncrates[i].sxfr & ULTRA_SXFR)) {
-                                       /*
-                                        * This should only happen if the
-                                        * drive is the first to negotiate
-                                        * and chooses a high rate.  We'll
-                                        * just move down the table util
-                                        * we hit a non ultra speed.
-                                        */
-                                       continue;
-                               }
-                               *scsirate = (ahc_syncrates[i].sxfr & 0xF0)
-                                         | (*offset & 0x0f);
-                               *period = ahc_syncrates[i].period;
-
-                               if(bootverbose) {
-                                       printf("%s: target %d synchronous at %sMHz,"
-                                              " offset = 0x%x\n",
-                                               ahc_name(ahc), target,
-                                               ahc_syncrates[i].rate, *offset );
-                               }
-                               break;
-                       }
+       if (wait == 0) {
+               printf("%s: WARNING - Failed chip reset!  "
+                      "Trying to initialize anyway.\n", ahc_name(ahc));
+       }
+       ahc_outb(ahc, HCNTRL, ahc->pause);
+
+       /* Determine channel configuration */
+       sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE);
+       /* No Twin Channel PCI cards */
+       if ((ahc->chip & AHC_PCI) != 0)
+               sblkctl &= ~SELBUSB;
+       switch (sblkctl) {
+       case 0:
+               /* Single Narrow Channel */
+               break;
+       case 2:
+               /* Wide Channel */
+               ahc->features |= AHC_WIDE;
+               break;
+       case 8:
+               /* Twin Channel */
+               ahc->features |= AHC_TWIN;
+               break;
+       default:
+               printf(" Unsupported adapter type.  Ignoring\n");
+               return(-1);
+       }
+       return (0);
+}
+
+/*
+ * Called when we have an active connection to a target on the bus,
+ * this function finds the nearest syncrate to the input period limited
+ * by the capabilities of the bus connectivity of the target.
+ */
+STATIC struct ahc_syncrate *
+ahc_devlimited_syncrate(ahc, period)
+       struct ahc_softc *ahc;
+       u_int *period;
+{
+       u_int   maxsync;
+
+       if ((ahc->features & AHC_ULTRA2) != 0) {
+               if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0
+                && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) {
+                       maxsync = AHC_SYNCRATE_ULTRA2;
+               } else {
+                       maxsync = AHC_SYNCRATE_ULTRA;
+               }
+       } else if ((ahc->features & AHC_ULTRA) != 0) {
+               maxsync = AHC_SYNCRATE_ULTRA;
+       } else {
+               maxsync = AHC_SYNCRATE_FAST;
+       }
+       return (ahc_find_syncrate(ahc, period, maxsync));
+}
+
+/*
+ * Look up the valid period to SCSIRATE conversion in our table.
+ * Return the period and offset that should be sent to the target
+ * if this was the beginning of an SDTR.
+ */
+STATIC struct ahc_syncrate *
+ahc_find_syncrate(ahc, period, maxsync)
+       struct ahc_softc *ahc;
+       u_int *period;
+       u_int maxsync;
+{
+       struct ahc_syncrate *syncrate;
+
+       syncrate = &ahc_syncrates[maxsync];
+       while ((syncrate->rate != NULL)
+           && ((ahc->features & AHC_ULTRA2) == 0
+            || (syncrate->sxfr_u2 != 0))) {
+
+               if (*period <= syncrate->period) {
+                       /*
+                        * When responding to a target that requests
+                        * sync, the requested rate may fall between
+                        * two rates that we can output, but still be
+                        * a rate that we can receive.  Because of this,
+                        * we want to respond to the target with
+                        * the same rate that it sent to us even
+                        * if the period we use to send data to it
+                        * is lower.  Only lower the response period
+                        * if we must.
+                        */
+                       if (syncrate == &ahc_syncrates[maxsync])
+                               *period = syncrate->period;
+                       break;
                }
+               syncrate++;
        }
-       if (i >= ahc_num_syncrates) {
+
+       if ((*period == 0)
+        || (syncrate->rate == NULL)
+        || ((ahc->features & AHC_ULTRA2) != 0
+         && (syncrate->sxfr_u2 == 0))) {
                /* Use asynchronous transfers. */
-               *scsirate = 0;
                *period = 0;
-               *offset = 0;
-               if (bootverbose)
-                       printf("%s: target %d using asynchronous transfers\n",
-                              ahc_name(ahc), target );
+               syncrate = NULL;
+       }
+       return (syncrate);
+}
+
+STATIC u_int
+ahc_find_period(ahc, scsirate, maxsync)
+       struct ahc_softc *ahc;
+       u_int scsirate;
+       u_int maxsync;
+{
+       struct ahc_syncrate *syncrate;
+
+       if ((ahc->features & AHC_ULTRA2) != 0)
+               scsirate &= SXFR_ULTRA2;
+       else
+               scsirate &= SXFR;
+
+       syncrate = &ahc_syncrates[maxsync];
+       while (syncrate->rate != NULL) {
+
+               if ((ahc->features & AHC_ULTRA2) != 0) {
+                       if (syncrate->sxfr_u2 == 0)
+                               break;
+                       else if (scsirate == (syncrate->sxfr_u2 & SXFR_ULTRA2))
+                               return (syncrate->period);
+               } else if (scsirate == (syncrate->sxfr & SXFR)) {
+                               return (syncrate->period);
+               }
+               syncrate++;
+       }
+       return (0); /* async */
+}
+
+STATIC void
+ahc_validate_offset(ahc, syncrate, offset, wide)
+       struct ahc_softc *ahc;
+       struct ahc_syncrate *syncrate;
+       u_int *offset;
+       int wide;
+{
+       u_int maxoffset;
+
+       /* Limit offset to what we can do */
+       if (syncrate == NULL) {
+               maxoffset = 0;
+       } else if ((ahc->features & AHC_ULTRA2) != 0) {
+               maxoffset = MAX_OFFSET_ULTRA2;
+       } else {
+               if (wide)
+                       maxoffset = MAX_OFFSET_16BIT;
+               else
+                       maxoffset = MAX_OFFSET_8BIT;
+       }
+       *offset = MIN(*offset, maxoffset);
+}
+
+STATIC void
+ahc_update_target_msg_request(ahc, devinfo, tinfo, force, paused)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+       struct ahc_initiator_tinfo *tinfo;
+       int force;
+       int paused;
+{
+       u_int targ_msg_req_orig;
+
+       targ_msg_req_orig = ahc->targ_msg_req;
+       if (tinfo->current.period != tinfo->goal.period
+           || tinfo->current.width != tinfo->goal.width
+           || tinfo->current.offset != tinfo->goal.offset
+           || (force && (tinfo->goal.period != 0
+           || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT)))
+               ahc->targ_msg_req |= devinfo->target_mask;
+       else
+               ahc->targ_msg_req &= ~devinfo->target_mask;
+
+       if (ahc->targ_msg_req != targ_msg_req_orig) {
+               /* Update the message request bit for this target */
+               if ((ahc->features & AHC_HS_MAILBOX) != 0) {
+                       if (paused) {
+                               ahc_outb(ahc, TARGET_MSG_REQUEST,
+                                        ahc->targ_msg_req & 0xFF);
+                               ahc_outb(ahc, TARGET_MSG_REQUEST + 1,
+                                        (ahc->targ_msg_req >> 8) & 0xFF);
+                       } else {
+                               ahc_outb(ahc, HS_MAILBOX,
+                                        0x01 << HOST_MAILBOX_SHIFT);
+                       }
+               } else {
+                       if (!paused)
+                               pause_sequencer(ahc);
+
+                       ahc_outb(ahc, TARGET_MSG_REQUEST,
+                                ahc->targ_msg_req & 0xFF);
+                       ahc_outb(ahc, TARGET_MSG_REQUEST + 1,
+                                (ahc->targ_msg_req >> 8) & 0xFF);
+
+                       if (!paused)
+                               unpause_sequencer(ahc);
+               }
+       }
+}
+
+STATIC void
+ahc_set_syncrate(ahc, devinfo, syncrate, period, offset, type, paused, done)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+       struct ahc_syncrate *syncrate;
+       u_int period;
+       u_int offset;
+       u_int type;
+       int paused;
+       int done;
+{
+       struct  ahc_initiator_tinfo *tinfo;
+       struct  tmode_tstate *tstate;
+       u_int   old_period;
+       u_int   old_offset;
+       int     active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+
+       if (syncrate == NULL) {
+               period = 0;
+               offset = 0;
+       }
+
+       tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+                                   devinfo->our_scsiid,
+                                   devinfo->target, &tstate);
+       old_period = tinfo->current.period;
+       old_offset = tinfo->current.offset;
+
+       if ((type & AHC_TRANS_CUR) != 0
+        && (old_period != period || old_offset != offset)) {
+               u_int   scsirate;
+
+               scsirate = tinfo->scsirate;
+               if ((ahc->features & AHC_ULTRA2) != 0) {
+
+                       /* XXX */
+                       /* Force single edge until DT is fully implemented */
+                       scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC);
+                       if (syncrate != NULL)
+                               scsirate |= syncrate->sxfr_u2|SINGLE_EDGE;
+
+                       if (active)
+                               ahc_outb(ahc, SCSIOFFSET, offset);
+               } else {
+
+                       scsirate &= ~(SXFR|SOFS);
+                       /*
+                        * Ensure Ultra mode is set properly for
+                        * this target.
+                        */
+                       tstate->ultraenb &= ~devinfo->target_mask;
+                       if (syncrate != NULL) {
+                               if (syncrate->sxfr & ULTRA_SXFR) {
+                                       tstate->ultraenb |=
+                                               devinfo->target_mask;
+                               }
+                               scsirate |= syncrate->sxfr & SXFR;
+                               scsirate |= offset & SOFS;
+                       }
+                       if (active) {
+                               u_int sxfrctl0;
+
+                               sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
+                               sxfrctl0 &= ~FAST20;
+                               if (tstate->ultraenb & devinfo->target_mask)
+                                       sxfrctl0 |= FAST20;
+                               ahc_outb(ahc, SXFRCTL0, sxfrctl0);
+                       }
+               }
+               if (active)
+                       ahc_outb(ahc, SCSIRATE, scsirate);
+
+               tinfo->scsirate = scsirate;
+               tinfo->current.period = period;
+               tinfo->current.offset = offset;
+
+               /* Update the syncrates in any pending scbs */
+               ahc_update_pending_syncrates(ahc);
        }
+
        /*
-        * Ensure Ultra mode is set properly for
-        * this target.
+        * Print messages if we're verbose and at the end of a negotiation
+        * cycle.
         */
-       ultra_enb_addr = ULTRA_ENB;
-       if(channel == 'B' || target > 7)
-               ultra_enb_addr++;
-       ultra_enb = AHC_INB(ahc, ultra_enb_addr);       
-       sxfrctl0 = AHC_INB(ahc, SXFRCTL0);
-       if (*scsirate != 0 && ahc_syncrates[i].sxfr & ULTRA_SXFR) {
-               ultra_enb |= 0x01 << (target & 0x07);
-               sxfrctl0 |= ULTRAEN;
+       if (done && bootverbose) {
+               if (offset != 0) {
+                       printf("%s: target %d synchronous at %sMHz, "
+                              "offset = 0x%x\n", ahc_name(ahc),
+                              devinfo->target, syncrate->rate, offset);
+               } else {
+                       printf("%s: target %d using "
+                              "asynchronous transfers\n",
+                              ahc_name(ahc), devinfo->target);
+               }
+       }
+
+       if ((type & AHC_TRANS_GOAL) != 0) {
+               tinfo->goal.period = period;
+               tinfo->goal.offset = offset;
+       }
+
+       if ((type & AHC_TRANS_USER) != 0) {
+               tinfo->user.period = period;
+               tinfo->user.offset = offset;
+       }
+
+       ahc_update_target_msg_request(ahc, devinfo, tinfo,
+                                     /*force*/FALSE,
+                                     paused);
+}
+
+STATIC void
+ahc_set_width(ahc, devinfo, width, type, paused, done)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+       u_int width;
+       u_int type;
+       int paused;
+       int done;
+{
+       struct ahc_initiator_tinfo *tinfo;
+       struct tmode_tstate *tstate;
+       u_int  oldwidth;
+       int    active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+
+       tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+                                   devinfo->our_scsiid,
+                                   devinfo->target,
+                                   &tstate);
+       oldwidth = tinfo->current.width;
+
+       if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) {
+               u_int   scsirate;
+
+               scsirate =  tinfo->scsirate;
+               scsirate &= ~WIDEXFER;
+               if (width == MSG_EXT_WDTR_BUS_16_BIT)
+                       scsirate |= WIDEXFER;
+
+               tinfo->scsirate = scsirate;
+
+               if (active)
+                       ahc_outb(ahc, SCSIRATE, scsirate);
+
+               tinfo->current.width = width;
        }
-       else {
-               ultra_enb &= ~(0x01 << (target & 0x07));
-               sxfrctl0 &= ~ULTRAEN;
+
+       if (done) {
+               printf("%s: target %d using %dbit transfers\n",
+                      ahc_name(ahc), devinfo->target,
+                      8 * (0x01 << width));
        }
-       AHC_OUTB(ahc, ultra_enb_addr, ultra_enb);
-       AHC_OUTB(ahc, SXFRCTL0, sxfrctl0);
+
+       if ((type & AHC_TRANS_GOAL) != 0)
+               tinfo->goal.width = width;
+       if ((type & AHC_TRANS_USER) != 0)
+               tinfo->user.width = width;
+
+       ahc_update_target_msg_request(ahc, devinfo, tinfo,
+                                     /*force*/FALSE, paused);
+}
+
+STATIC void
+ahc_set_tags(ahc, devinfo, enable)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+       int enable;
+{
+       struct ahc_initiator_tinfo *tinfo;
+       struct tmode_tstate *tstate;
+
+       tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+                                   devinfo->our_scsiid,
+                                   devinfo->target,
+                                   &tstate);
+       if (enable)
+               tstate->tagenable |= devinfo->target_mask;
+       else
+               tstate->tagenable &= ~devinfo->target_mask;
 }
 
 /*
@@ -626,18 +1474,12 @@ ahc_scsirate(ahc, scsirate, period, offset, channel, target )
  */
 int
 ahc_attach(ahc)
-       struct ahc_data *ahc;
+       struct ahc_softc *ahc;
 {
-#if defined(__FreeBSD__)
-       struct scsibus_data *scbus;
-#endif
-
-#if defined(__NetBSD__) || defined(__OpenBSD__)        /* XXX */
        /*
         * Initialize the software queue.
         */
        LIST_INIT(&ahc->sc_xxxq);
-#endif
 
 #ifdef AHC_BROKEN_CACHE
        if (cpu_class == CPUCLASS_386)  /* doesn't have "wbinvd" instruction */
@@ -646,88 +1488,24 @@ ahc_attach(ahc)
        /*
         * fill in the prototype scsi_links.
         */
-#if defined(__FreeBSD__)
-       ahc->sc_link.adapter_unit = ahc->unit;
-       ahc->sc_link.adapter_targ = ahc->our_id;
-       ahc->sc_link.fordriver = 0;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
        ahc->sc_link.adapter_target = ahc->our_id;
-#ifdef __OpenBSD__
-       if(ahc->type & AHC_WIDE)
+       if (ahc->features & AHC_WIDE)
                ahc->sc_link.adapter_buswidth = 16;
-#endif
-#ifndef __OpenBSD__
-       ahc->sc_link.channel = 0;
-#endif
-#endif
        ahc->sc_link.adapter_softc = ahc;
        ahc->sc_link.adapter = &ahc_switch;
-       ahc->sc_link.opennings = 2;
+       ahc->sc_link.openings = 2;
        ahc->sc_link.device = &ahc_dev;
-#ifdef __OpenBSD__
        ahc->sc_link.flags = SCSIDEBUG_LEVEL;
-#else
-       ahc->sc_link.flags = DEBUGLEVEL;
-#endif
-
-       if(ahc->type & AHC_TWIN) {
+       
+       if (ahc->features & AHC_TWIN) {
                /* Configure the second scsi bus */
                ahc->sc_link_b = ahc->sc_link;
-#if defined(__FreeBSD__)
-               ahc->sc_link_b.adapter_targ = ahc->our_id_b;
-               ahc->sc_link_b.adapter_bus = 1;
-               ahc->sc_link_b.fordriver = (void *)SELBUSB;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
                ahc->sc_link_b.adapter_target = ahc->our_id_b;
-#ifdef __OpenBSD__
-               if(ahc->type & AHC_WIDE)
+               if (ahc->features & AHC_WIDE)
                        ahc->sc_link.adapter_buswidth = 16;
-#endif
-#ifndef __OpenBSD__
-               ahc->sc_link_b.channel = 1;
-#endif
-#endif
        }
 
-
-#if defined(__FreeBSD__)
-       /*
-        * Prepare the scsibus_data area for the upperlevel
-        * scsi code.
-        */
-       scbus = scsi_alloc_bus();
-       if(!scbus) 
-               return 0;
-       scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ?
-                               &ahc->sc_link_b : &ahc->sc_link;
-       if(ahc->type & AHC_WIDE)
-               scbus->maxtarg = 15;
-       
-       /*
-        * ask the adapter what subunits are present
-        */
-       if(bootverbose)
-               printf("ahc%d: Probing channel %c\n", ahc->unit,
-                       (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'B' : 'A');
-       scsi_attachdevs(scbus);
-       scbus = NULL;   /* Upper-level SCSI code owns this now */
-
-       if(ahc->type & AHC_TWIN) {
-               scbus =  scsi_alloc_bus();
-               if(!scbus) 
-                       return 0;
-               scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 
-                                       &ahc->sc_link : &ahc->sc_link_b;
-               if(ahc->type & AHC_WIDE)
-                       scbus->maxtarg = 15;
-               if(bootverbose)
-                       printf("ahc%d: Probing Channel %c\n", ahc->unit,
-                              (ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'A': 'B');
-               scsi_attachdevs(scbus);
-               scbus = NULL;   /* Upper-level SCSI code owns this now */
-       }
-#elif defined(__NetBSD__) || defined (__OpenBSD__)
-       /*
+/*
         * ask the adapter what subunits are present
         */
        if ((ahc->flags & AHC_CHANNEL_B_PRIMARY) == 0) {
@@ -735,7 +1513,7 @@ ahc_attach(ahc)
                ahc->sc_link_b.scsibus = 0xff;
 
                config_found((void *)ahc, &ahc->sc_link, scsiprint);
-               if (ahc->type & AHC_TWIN)
+               if (ahc->features & AHC_TWIN)
                        config_found((void *)ahc, &ahc->sc_link_b, scsiprint);
        } else {
                /*
@@ -744,1283 +1522,1997 @@ ahc_attach(ahc)
                 * is needed, here.
                 */
 
-               /* assert(ahc->type & AHC_TWIN); */
+               /* assert(ahc->features & AHC_TWIN); */
                config_found((void *)ahc, &ahc->sc_link_b, scsiprint);
                config_found((void *)ahc, &ahc->sc_link, scsiprint);
        }
-#endif
        return 1;
 }
 
-/*
- * Send an SCB down to the card via PIO.
- * We assume that the proper SCB is already selected in SCBPTR. 
- */
-static inline void
-ahc_send_scb(ahc, scb)
-        struct ahc_data *ahc;
-        struct scb *scb;
-{
-       AHC_OUTB(ahc, SCBCNT, SCBAUTO);
-       if( ahc->type == AHC_284 )
-               /* Can only do 8bit PIO */
-               AHC_OUTSB(ahc, SCBARRAY, scb, SCB_PIO_TRANSFER_SIZE);
+STATIC void
+ahc_fetch_devinfo(ahc, devinfo)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+{
+       u_int   saved_tcl;
+       role_t  role;
+       int     our_id;
+
+       if (ahc_inb(ahc, SSTAT0) & TARGET)
+               role = ROLE_TARGET;
        else
-               AHC_OUTSL(ahc, SCBARRAY, scb,
-                     (SCB_PIO_TRANSFER_SIZE + 3) / 4);
-       AHC_OUTB(ahc, SCBCNT, 0); 
+               role = ROLE_INITIATOR;
+
+       if (role == ROLE_TARGET
+        && (ahc->features & AHC_MULTI_TID) != 0
+        && (ahc_inb(ahc, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) {
+               /* We were selected, so pull our id from TARGIDIN */
+               our_id = ahc_inb(ahc, TARGIDIN) & OID;
+       } else if ((ahc->features & AHC_ULTRA2) != 0)
+               our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
+       else
+               our_id = ahc_inb(ahc, SCSIID) & OID;
+
+       saved_tcl = ahc_inb(ahc, SAVED_TCL);
+       ahc_compile_devinfo(devinfo, our_id, TCL_TARGET(saved_tcl),
+                           TCL_LUN(saved_tcl), TCL_CHANNEL(ahc, saved_tcl),
+                           role);
 }
 
-/*
- * Retrieve an SCB from the card via PIO.
- * We assume that the proper SCB is already selected in SCBPTR.
- */
-static inline void
-ahc_fetch_scb(ahc, scb)
-       struct  ahc_data *ahc;
-       struct  scb *scb;
+STATIC void
+ahc_compile_devinfo(devinfo, our_id, target, lun, channel, role)
+       struct ahc_devinfo *devinfo;
+       u_int our_id;
+       u_int target;
+       u_int lun;
+       char channel;
+       role_t role;
 {
-       AHC_OUTB(ahc, SCBCNT, 0x80);    /* SCBAUTO */
-
-       /* Can only do 8bit PIO for reads */
-       AHC_INSB(ahc, SCBARRAY, scb, SCB_PIO_TRANSFER_SIZE);
-
-       AHC_OUTB(ahc, SCBCNT, 0);
+       devinfo->our_scsiid = our_id;
+       devinfo->target = target;
+       devinfo->lun = lun;
+       devinfo->target_offset = target;
+       devinfo->channel = channel;
+       devinfo->role = role;
+       if (channel == 'B')
+               devinfo->target_offset += 8;
+       devinfo->target_mask = (0x01 << devinfo->target_offset);
 }
 
 /*
- * Swap in_scbp for out_scbp down in the cards SCB array.
- * We assume that the SCB for out_scbp is already selected in SCBPTR.
+ * Catch an interrupt from the adapter
  */
-static inline void
-ahc_page_scb(ahc, out_scbp, in_scbp)
-       struct ahc_data *ahc;
-       struct scb *out_scbp;
-       struct scb *in_scbp;
-{
-       /* Page-out */
-       ahc_fetch_scb(ahc, out_scbp);
-       out_scbp->flags |= SCB_PAGED_OUT;
-       if(!(out_scbp->control & TAG_ENB))
-       {
-               /* Stick in non-tagged array */
-               int index =  (out_scbp->tcl >> 4)
-                          | (out_scbp->tcl & SELBUSB);
-               ahc->pagedout_ntscbs[index] = out_scbp;
-       }
-
-       /* Page-in */
-       in_scbp->position = out_scbp->position;
-       out_scbp->position = SCB_LIST_NULL;
-       ahc_send_scb(ahc, in_scbp);
-       in_scbp->flags &= ~SCB_PAGED_OUT;
-}
-
-static inline void
-ahc_run_waiting_queues(ahc)
-       struct ahc_data *ahc;
+int
+ahc_intr(void *arg)
 {
-       struct scb* scb;
-       u_char cur_scb;
+       struct  ahc_softc *ahc;
+       u_int   intstat;
 
-       if(!(ahc->assigned_scbs.stqh_first || ahc->waiting_scbs.stqh_first))
-               return;
+       ahc = (struct ahc_softc *)arg; 
 
-       pause_sequencer(ahc);
-       cur_scb = AHC_INB(ahc, SCBPTR);
+       intstat = ahc_inb(ahc, INTSTAT);
 
        /*
-        * First handle SCBs that are waiting but have been
-        * assigned a slot.
+        * Any interrupts to process?
         */
-       while((scb = ahc->assigned_scbs.stqh_first) != NULL) {
-               STAILQ_REMOVE_HEAD(&ahc->assigned_scbs, links);
-               AHC_OUTB(ahc, SCBPTR, scb->position);
-               ahc_send_scb(ahc, scb);
-
-               /* Mark this as an active command */
-               scb->flags ^= SCB_ASSIGNEDQ|SCB_ACTIVE;
-
-               AHC_OUTB(ahc, QINFIFO, scb->position);
-               if (!(scb->xs->flags & SCSI_NOMASK)) {
-                       timeout(ahc_timeout, (caddr_t)scb,
-                               (scb->xs->timeout * hz) / 1000);
+       if ((intstat & INT_PEND) == 0) {
+               if (ahc->pci_intr_func && ahc->pci_intr_func(ahc)) {
+#ifdef AHC_DEBUG
+                       printf("%s: bus intr: CCHADDR %x HADDR %x SEQADDR %x\n",
+                           ahc_name(ahc),
+                           ahc_inb(ahc, CCHADDR) |
+                           (ahc_inb(ahc, CCHADDR+1) << 8)
+                           | (ahc_inb(ahc, CCHADDR+2) << 16)
+                           | (ahc_inb(ahc, CCHADDR+3) << 24),
+                           ahc_inb(ahc, HADDR) | (ahc_inb(ahc, HADDR+1) << 8)
+                           | (ahc_inb(ahc, HADDR+2) << 16)
+                           | (ahc_inb(ahc, HADDR+3) << 24),
+                           ahc_inb(ahc, SEQADDR0) |
+                           (ahc_inb(ahc, SEQADDR1) << 8));
+#endif
+                       return 1;
                }
-               SC_DEBUG(scb->xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
+               return 0;
        }
-       /* Now deal with SCBs that require paging */
-       if((scb = ahc->waiting_scbs.stqh_first) != NULL) {
-               u_char disc_scb = AHC_INB(ahc, DISCONNECTED_SCBH);
-               u_char active = AHC_INB(ahc, FLAGS) & (SELECTED|IDENTIFY_SEEN);
-               int count = 0;
-
-               do {
-                       u_char next_scb;
-
-                       /* Attempt to page this SCB in */
-                       if(disc_scb == SCB_LIST_NULL)
-                               break;
-
-                       /*
-                        * Check the next SCB on in the list.
-                        */
-                       AHC_OUTB(ahc, SCBPTR, disc_scb);
-                       next_scb = AHC_INB(ahc, SCB_NEXT); 
-
-                       /*
-                        * We have to be careful about when we allow
-                        * an SCB to be paged out.  There must always
-                        * be at least one slot available for a
-                        * reconnecting target in case it references
-                        * an SCB that has been paged out.  Our
-                        * heuristic is that either the disconnected
-                        * list has at least two entries in it or
-                        * there is one entry and the sequencer is
-                        * actively working on an SCB which implies that
-                        * it will either complete or disconnect before
-                        * another reconnection can occur.
-                        */
-                       if((next_scb != SCB_LIST_NULL) || active)
-                       {
-                               u_char out_scbi;
-                               struct scb* out_scbp;
-
-                               STAILQ_REMOVE_HEAD(&ahc->waiting_scbs, links);
-
-                               /*
-                                * Find the in-core SCB for the one
-                                * we're paging out.
-                                */
-                               out_scbi = AHC_INB(ahc, SCB_TAG); 
-                               out_scbp = ahc->scbarray[out_scbi];
-
-                               /* Do the page out */
-                               ahc_page_scb(ahc, out_scbp, scb);
 
-                               /* Mark this as an active command */
-                               scb->flags ^= SCB_WAITINGQ|SCB_ACTIVE;
-
-                               /* Queue the command */
-                               AHC_OUTB(ahc, QINFIFO, scb->position);
-                               if (!(scb->xs->flags & SCSI_NOMASK)) {
-                                       timeout(ahc_timeout, (caddr_t)scb,
-                                               (scb->xs->timeout * hz) / 1000);
-                               }
-                               SC_DEBUG(scb->xs->sc_link, SDEV_DB3,
-                                       ("cmd_paged-in\n"));
-                               count++;
+       if (intstat & CMDCMPLT) {
+               ahc_outb(ahc, CLRINT, CLRCMDINT);
+               ahc_run_qoutfifo(ahc);
+       }
+       if (intstat & BRKADRINT) {
+               /*
+                * We upset the sequencer :-(
+                * Lookup the error message
+                */
+               int i, error, num_errors;
 
-                               /* Advance to the next disconnected SCB */
-                               disc_scb = next_scb;
-                       }
-                       else
-                               break;
-               } while((scb = ahc->waiting_scbs.stqh_first) != NULL);
+               error = ahc_inb(ahc, ERROR);
+               num_errors =  sizeof(hard_error)/sizeof(hard_error[0]);
+               for (i = 0; error != 1 && i < num_errors; i++)
+                       error >>= 1;
+               panic("%s: brkadrint, %s at seqaddr = 0x%x\n",
+                     ahc_name(ahc), hard_error[i].errmesg,
+                     ahc_inb(ahc, SEQADDR0) |
+                     (ahc_inb(ahc, SEQADDR1) << 8));
 
-               if(count) {
-                       /* 
-                        * Update the head of the disconnected list.
-                        */
-                       AHC_OUTB(ahc, DISCONNECTED_SCBH, disc_scb);
-                       if(disc_scb != SCB_LIST_NULL) {
-                               AHC_OUTB(ahc, SCBPTR, disc_scb);
-                               AHC_OUTB(ahc, SCB_PREV, SCB_LIST_NULL);
-                       }
-               }
+               /* Tell everyone that this HBA is no longer availible */
+               ahc_abort_scbs(ahc, ALL_TARGETS, ALL_CHANNELS,
+                              ALL_LUNS, SCB_LIST_NULL, ROLE_UNKNOWN,
+                              XS_DRIVER_STUFFUP);
        }
-       /* Restore old position */
-       AHC_OUTB(ahc, SCBPTR, cur_scb);
-       unpause_sequencer(ahc, /*unpause_always*/FALSE);
+       if (intstat & SEQINT)
+               ahc_handle_seqint(ahc, intstat);
+
+       if (intstat & SCSIINT)
+               ahc_handle_scsiint(ahc, intstat);
+       return(1);
 }
 
-/*
- * Add this SCB to the head of the "waiting for selection" list.
- */
-static
-void ahc_add_waiting_scb(ahc, scb)
-       struct ahc_data *ahc;
-       struct scb *scb;
+STATIC struct tmode_tstate *
+ahc_alloc_tstate(ahc, scsi_id, channel)
+       struct ahc_softc *ahc;
+       u_int scsi_id;
+       char channel;
 {
-       u_char next; 
-       u_char curscb;
-
-       curscb = AHC_INB(ahc, SCBPTR);
-       next = AHC_INB(ahc, WAITING_SCBH);
-
-       AHC_OUTB(ahc, SCBPTR, scb->position);
-       AHC_OUTB(ahc, SCB_NEXT, next);
-       AHC_OUTB(ahc, WAITING_SCBH, scb->position);
+       struct tmode_tstate *master_tstate;
+       struct tmode_tstate *tstate;
+       int i, s;
+
+       master_tstate = ahc->enabled_targets[ahc->our_id];
+       if (channel == 'B') {
+               scsi_id += 8;
+               master_tstate = ahc->enabled_targets[ahc->our_id_b + 8];
+       }
+       if (ahc->enabled_targets[scsi_id] != NULL
+        && ahc->enabled_targets[scsi_id] != master_tstate)
+               panic("%s: ahc_alloc_tstate - Target already allocated",
+                     ahc_name(ahc));
+       tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT);
+       if (tstate == NULL)
+               return (NULL);
 
-       AHC_OUTB(ahc, SCBPTR, curscb);
+       /*
+        * If we have allocated a master tstate, copy user settings from
+        * the master tstate (taken from SRAM or the EEPROM) for this
+        * channel, but reset our current and goal settings to async/narrow
+        * until an initiator talks to us.
+        */
+       if (master_tstate != NULL) {
+               bcopy(master_tstate, tstate, sizeof(*tstate));
+               tstate->ultraenb = 0;
+               for (i = 0; i < 16; i++) {
+                       bzero(&tstate->transinfo[i].current,
+                             sizeof(tstate->transinfo[i].current));
+                       bzero(&tstate->transinfo[i].goal,
+                             sizeof(tstate->transinfo[i].goal));
+               }
+       } else
+               bzero(tstate, sizeof(*tstate));
+       s = splbio();
+       ahc->enabled_targets[scsi_id] = tstate;
+       splx(s);
+       return (tstate);
 }
 
-/*
- * Catch an interrupt from the adapter
- */
-#if defined(__FreeBSD__)
-void
-#elif defined (__NetBSD__) || defined (__OpenBSD__)
-int
-#endif
-ahc_intr(arg)
-        void *arg;
+STATIC void
+ahc_handle_seqint(ahc, intstat)
+       struct ahc_softc *ahc;
+       u_int intstat;
 {
-       int     intstat;
-       u_char  status;
-       struct  scb *scb;
-       struct  scsi_xfer *xs;
-       struct  ahc_data *ahc = (struct ahc_data *)arg;
+       struct scb *scb;
+       struct ahc_devinfo devinfo;
+       
+       ahc_fetch_devinfo(ahc, &devinfo);
 
-       intstat = AHC_INB(ahc, INTSTAT);
        /*
-        * Is this interrupt for me? or for
-        * someone who is sharing my interrupt?
+        * Clear the upper byte that holds SEQINT status
+        * codes and clear the SEQINT bit. We will unpause
+        * the sequencer, if appropriate, after servicing
+        * the request.
         */
-       if (!(intstat & INT_PEND))
-#if defined(__FreeBSD__)
+       ahc_outb(ahc, CLRINT, CLRSEQINT);
+       switch (intstat & SEQINT_MASK) {
+       case NO_MATCH:
+       {
+               /* Ensure we don't leave the selection hardware on */
+               ahc_outb(ahc, SCSISEQ,
+                        ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+
+               printf("%s:%c:%d: no active SCB for reconnecting "
+                      "target - issuing BUS DEVICE RESET\n",
+                      ahc_name(ahc), devinfo.channel, devinfo.target);
+               printf("SAVED_TCL == 0x%x, ARG_1 == 0x%x, SEQ_FLAGS == 0x%x\n",
+                      ahc_inb(ahc, SAVED_TCL), ahc_inb(ahc, ARG_1),
+                      ahc_inb(ahc, SEQ_FLAGS));
+               ahc->msgout_buf[0] = MSG_BUS_DEV_RESET;
+               ahc->msgout_len = 1;
+               ahc->msgout_index = 0;
+               ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+               ahc_outb(ahc, MSG_OUT, HOST_MSG);
+               ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO);
+               break;
+       }
+       case UPDATE_TMSG_REQ:
+               ahc_outb(ahc, TARGET_MSG_REQUEST, ahc->targ_msg_req & 0xFF);
+               ahc_outb(ahc, TARGET_MSG_REQUEST + 1,
+                        (ahc->targ_msg_req >> 8) & 0xFF);
+               ahc_outb(ahc, HS_MAILBOX, 0);
+               break;
+       case SEND_REJECT: 
+       {
+               u_int rejbyte = ahc_inb(ahc, ACCUM);
+               printf("%s:%c:%d: Warning - unknown message received from "
+                      "target (0x%x).  Rejecting\n", 
+                      ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte);
+               break; 
+       }
+       case NO_IDENT: 
+       {
+               /*
+                * The reconnecting target either did not send an identify
+                * message, or did, but we didn't find and SCB to match and
+                * before it could respond to our ATN/abort, it hit a dataphase.
+                * The only safe thing to do is to blow it away with a bus
+                * reset.
+                */
+               int found;
+
+               printf("%s:%c:%d: Target did not send an IDENTIFY message. "
+                      "LASTPHASE = 0x%x, SAVED_TCL == 0x%x\n",
+                      ahc_name(ahc), devinfo.channel, devinfo.target,
+                      ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_TCL));
+               found = ahc_reset_channel(ahc, devinfo.channel, 
+                                         /*initiate reset*/TRUE);
+               printf("%s: Issued Channel %c Bus Reset. "
+                      "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel,
+                      found);
                return;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-               return 0;
-#endif
-
-        if (intstat & BRKADRINT) {
-               /* We upset the sequencer :-( */
-
-               /* Lookup the error message */
-               int i, error = AHC_INB(ahc, ERROR);
-               int num_errors =  sizeof(hard_error)/sizeof(hard_error[0]);
-               for(i = 0; error != 1 && i < num_errors; i++)
-                       error >>= 1;
-                panic("%s: brkadrint, %s at seqaddr = 0x%x",
-                     ahc_name(ahc), hard_error[i].errmesg,
-                     (AHC_INB(ahc, SEQADDR1) << 8) |
-                     AHC_INB(ahc, SEQADDR0));
-        }
-        if (intstat & SEQINT)
-               ahc_handle_seqint(ahc, intstat);
+       }
+       case BAD_PHASE:
+       {
+               u_int lastphase;
 
-       if (intstat & SCSIINT) {
-
-               int scb_index = AHC_INB(ahc, SCB_TAG);
-               status = AHC_INB(ahc, SSTAT1);
-               scb = ahc->scbarray[scb_index];
-
-               if (status & SCSIRSTI) {
-                       char channel;
-                       channel = AHC_INB(ahc, SBLKCTL);
-                       channel = channel & SELBUSB ? 'B' : 'A';
-                       printf("%s: Someone reset channel %c\n",
-                               ahc_name(ahc), channel);
-                       ahc_reset_channel(ahc, 
-                                         channel,
-                                         SCB_LIST_NULL,
-                                         XS_BUSY,
-                                         /* Initiate Reset */FALSE);
-                       scb = NULL;
-               }
-               else if (!(scb && (scb->flags & SCB_ACTIVE))){
-                       printf("%s: ahc_intr - referenced scb not "
-                              "valid during scsiint 0x%x scb(%d)\n",
-                               ahc_name(ahc), status, scb_index);
-                       AHC_OUTB(ahc, CLRSINT1, status);
-                       unpause_sequencer(ahc, /*unpause_always*/TRUE);
-                       AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
-                       scb = NULL;
+               lastphase = ahc_inb(ahc, LASTPHASE);
+               if (lastphase == P_BUSFREE) {
+                       printf("%s:%c:%d: Missed busfree.  Curphase = 0x%x\n",
+                              ahc_name(ahc), devinfo.channel, devinfo.target,
+                              ahc_inb(ahc, SCSISIGI));
+                       restart_sequencer(ahc);
+                       return;
+               } else {
+                       printf("%s:%c:%d: unknown scsi bus phase %x.  "
+                              "Attempting to continue\n",
+                              ahc_name(ahc), devinfo.channel, devinfo.target,
+                              ahc_inb(ahc, SCSISIGI));
                }
-               else if (status & SCSIPERR) {
-                       /*
-                        * Determine the bus phase and
-                        * queue an appropriate message
-                        */
-                       char    *phase;
-                       u_char  mesg_out = MSG_NOOP;
-                       u_char  lastphase = AHC_INB(ahc, LASTPHASE);
-
-                       xs = scb->xs;
-                       sc_print_addr(xs->sc_link);
-
-                       switch(lastphase) {
-                               case P_DATAOUT:
-                                       phase = "Data-Out";
-                                       break;
-                               case P_DATAIN:
-                                       phase = "Data-In";
-                                       mesg_out = MSG_INITIATOR_DET_ERR;
-                                       break;
-                               case P_COMMAND:
-                                       phase = "Command";
-                                       break;
-                               case P_MESGOUT:
-                                       phase = "Message-Out";
-                                       break;
-                               case P_STATUS:
-                                       phase = "Status";
-                                       mesg_out = MSG_INITIATOR_DET_ERR;
-                                       break;
-                               case P_MESGIN:
-                                       phase = "Message-In";
-                                       mesg_out = MSG_PARITY_ERROR;
-                                       break;
-                               default:
-                                       phase = "unknown";
+               break; 
+       }
+       case BAD_STATUS:
+       {
+               u_int  scb_index;
+               struct hardware_scb *hscb;
+               struct scsi_xfer *xs;
+               /*
+                * The sequencer will notify us when a command
+                * has an error that would be of interest to
+                * the kernel.  This allows us to leave the sequencer
+                * running in the common case of command completes
+                * without error.  The sequencer will already have
+                * dma'd the SCB back up to us, so we can reference
+                * the in kernel copy directly.
+                */
+               scb_index = ahc_inb(ahc, SCB_TAG);
+               scb = &ahc->scb_data->scbarray[scb_index];
+
+               /*
+                * Set the default return value to 0 (don't
+                * send sense).  The sense code will change
+                * this if needed.
+                */
+               ahc_outb(ahc, RETURN_1, 0);
+               if (!(scb_index < ahc->scb_data->numscbs
+                  && (scb->flags & SCB_ACTIVE) != 0)) {
+                       printf("%s:%c:%d: ahc_intr - referenced scb "
+                              "not valid during seqint 0x%x scb(%d)\n",
+                              ahc_name(ahc), devinfo.channel,
+                              devinfo.target, intstat, scb_index);
+                       goto unpause;
+               }
+
+               hscb = scb->hscb; 
+               xs = scb->xs;
+
+               /* Don't want to clobber the original sense code */
+               if ((scb->flags & SCB_SENSE) != 0) {
+                       /*
+                        * Clear the SCB_SENSE Flag and have
+                        * the sequencer do a normal command
+                        * complete.
+                        */
+                       scb->flags &= ~SCB_SENSE;
+                       ahcsetccbstatus(xs, XS_DRIVER_STUFFUP);
+                       break;
+               }
+               /* Freeze the queue unit the client sees the error. */
+               ahc_freeze_devq(ahc, xs->sc_link);
+               ahc_freeze_ccb(scb);
+               xs->status = hscb->status;
+               switch (hscb->status) {
+               case SCSI_OK:
+                       printf("%s: Interrupted for staus of 0???\n",
+                              ahc_name(ahc));
+                       break;
+               case SCSI_CHECK:
+#ifdef AHC_DEBUG
+                       if (ahc_debug & AHC_SHOWSENSE) {
+                               sc_print_addr(scb->xs->sc_link);
+                               printf("SCB %d: requests Check Status\n",
+                                      scb->hscb->tag);
+                       }
+#endif
+                               
+                       if (xs->error == XS_NOERROR &&
+                           !(scb->flags & SCB_SENSE)) {
+                               struct ahc_dma_seg *sg;
+                               struct scsi_sense *sc;
+                               struct ahc_initiator_tinfo *tinfo;
+                               struct tmode_tstate *tstate;
+
+                               sg = scb->sg_list;
+                               sc = (struct scsi_sense *)(&hscb->cmdstore); 
+                               /*
+                                * Save off the residual if there is one.
+                                */
+                               if (hscb->residual_SG_count != 0)
+                                       ahc_calc_residual(scb);
+                               else
+                                       xs->resid = 0;
+
+#ifdef AHC_DEBUG
+                               if (ahc_debug & AHC_SHOWSENSE) {
+                                       sc_print_addr(scb->xs->sc_link);
+                                       printf("Sending Sense\n");
+                               }
+#endif
+                               sg->addr = ahc->scb_data->sense_busaddr +
+                                       (hscb->tag*sizeof(struct scsi_sense_data));
+                               
+                               sg->len = sizeof(struct scsi_sense_data);
+
+                               sc->opcode = REQUEST_SENSE;
+                               sc->byte2 =  SCB_LUN(scb) << 5;
+                               sc->unused[0] = 0;
+                               sc->unused[1] = 0;
+                               sc->length = sg->len;
+                               sc->control = 0;
+
+                               /*
+                                * Would be nice to preserve DISCENB here,
+                                * but due to the way we page SCBs, we can't.
+                                */
+                               hscb->control = 0;
+
+                               /*
+                                * This request sense could be because the
+                                * the device lost power or in some other
+                                * way has lost our transfer negotiations.
+                                * Renegotiate if appropriate.
+                                */
+                               ahc_calc_residual(scb);
+#ifdef AHC_DEBUG
+                               if (ahc_debug & AHC_SHOWSENSE) {
+                                       sc_print_addr(xs->sc_link);
+                                       printf("Sense: datalen %d resid %d"
+                                              "chan %d id %d targ %d\n",
+                                              xs->datalen, xs->resid,
+                                              devinfo.channel,
+                                              devinfo.our_scsiid,
+                                              devinfo.target);
+                               }
+#endif
+                               if (xs->datalen > 0 &&
+                                   xs->resid == xs->datalen) {
+                               tinfo = ahc_fetch_transinfo(ahc,
+                                                           devinfo.channel,
+                                                           devinfo.our_scsiid,
+                                                           devinfo.target,
+                                                           &tstate);
+                                       ahc_update_target_msg_request(ahc,
+                                                             &devinfo,
+                                                             tinfo,
+                                                             /*force*/TRUE,
+                                                             /*paused*/TRUE);
+                               }
+                               hscb->status = 0;
+                               hscb->SG_count = 1;
+                               hscb->SG_pointer = scb->sg_list_phys;
+                               hscb->data = sg->addr; 
+                               hscb->datalen = sg->len;
+                               hscb->cmdpointer = hscb->cmdstore_busaddr;
+                               hscb->cmdlen = sizeof(*sc);
+                               scb->sg_count = hscb->SG_count;
+                               scb->flags |= SCB_SENSE;
+                               /*
+                                * Ensure the target is busy since this
+                                * will be an untagged request.
+                                */
+                               ahc_busy_tcl(ahc, scb);
+                               ahc_outb(ahc, RETURN_1, SEND_SENSE);
+
+                               /*
+                                * Ensure we have enough time to actually
+                                * retrieve the sense.
+                                */
+                               if (!(scb->xs->flags & SCSI_POLL)) {
+                               untimeout(ahc_timeout, (caddr_t)scb);
+                                       timeout(ahc_timeout, (caddr_t)scb,
+                                           5 * hz);
+                               }
+                       }
+                       break;
+               case SCSI_BUSY:
+                       /*
+                        * Requeue any transactions that haven't been
+                        * sent yet.
+                        */
+                       ahc_freeze_devq(ahc, xs->sc_link);
+                       ahc_freeze_ccb(scb);
+                       break;
+               }
+               break;
+       }
+       case TRACE_POINT:
+       {
+               printf("SSTAT2 = 0x%x DFCNTRL = 0x%x\n", ahc_inb(ahc, SSTAT2),
+                      ahc_inb(ahc, DFCNTRL));
+               printf("SSTAT3 = 0x%x DSTATUS = 0x%x\n", ahc_inb(ahc, SSTAT3),
+                      ahc_inb(ahc, DFSTATUS));
+               printf("SSTAT0 = 0x%x, SCB_DATACNT = 0x%x\n",
+                      ahc_inb(ahc, SSTAT0),
+                      ahc_inb(ahc, SCB_DATACNT));
+               break;
+       }
+       case HOST_MSG_LOOP:
+       {
+               /*
+                * The sequencer has encountered a message phase
+                * that requires host assistance for completion.
+                * While handling the message phase(s), we will be
+                * notified by the sequencer after each byte is
+                * transfered so we can track bus phases.
+                *
+                * If this is the first time we've seen a HOST_MSG_LOOP,
+                * initialize the state of the host message loop.
+                */
+               if (ahc->msg_type == MSG_TYPE_NONE) {
+                       u_int bus_phase;
+
+                       bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+                       if (bus_phase != P_MESGIN
+                        && bus_phase != P_MESGOUT) {
+                               printf("ahc_intr: HOST_MSG_LOOP bad "
+                                      "phase 0x%x\n",
+                                     bus_phase);
+                               /*
+                                * Probably transitioned to bus free before
+                                * we got here.  Just punt the message.
+                                */
+                               ahc_clear_intstat(ahc);
+                               restart_sequencer(ahc);
+                       }
+
+                       if (devinfo.role == ROLE_INITIATOR) {
+                               struct scb *scb;
+                               u_int scb_index;
+
+                               scb_index = ahc_inb(ahc, SCB_TAG);
+                               scb = &ahc->scb_data->scbarray[scb_index];
+
+                               if (bus_phase == P_MESGOUT)
+                                       ahc_setup_initiator_msgout(ahc,
+                                                                  &devinfo,
+                                                                  scb);
+                               else {
+                                       ahc->msg_type =
+                                           MSG_TYPE_INITIATOR_MSGIN;
+                                       ahc->msgin_index = 0;
+                               }
+                       } else {
+                               if (bus_phase == P_MESGOUT) {
+                                       ahc->msg_type =
+                                           MSG_TYPE_TARGET_MSGOUT;
+                                       ahc->msgin_index = 0;
+                               } else 
+                                       /* XXX Ever executed??? */
+                                       ahc_setup_target_msgin(ahc, &devinfo);
+                       }
+                       }
+
+               /* Pass a NULL path so that handlers generate their own */
+               ahc_handle_message_phase(ahc, /*path*/NULL);
+               break;
+               }
+       case PERR_DETECTED:
+       {
+               /*
+                * If we've cleared the parity error interrupt
+                * but the sequencer still believes that SCSIPERR
+                * is true, it must be that the parity error is
+                * for the currently presented byte on the bus,
+                * and we are not in a phase (data-in) where we will
+                * eventually ack this byte.  Ack the byte and
+                * throw it away in the hope that the target will
+                * take us to message out to deliver the appropriate
+                * error message.
+                */
+               if ((intstat & SCSIINT) == 0
+                && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) {
+                       u_int curphase;
+
+                       /*
+                        * The hardware will only let you ack bytes
+                        * if the expected phase in SCSISIGO matches
+                        * the current phase.  Make sure this is
+                        * currently the case.
+                        */
+                       curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+                       ahc_outb(ahc, LASTPHASE, curphase);
+                       ahc_outb(ahc, SCSISIGO, curphase);
+                       ahc_inb(ahc, SCSIDATL);
+               }
+               break;
+       }
+       case DATA_OVERRUN:
+       {
+               /*
+                * When the sequencer detects an overrun, it
+                * places the controller in "BITBUCKET" mode
+                * and allows the target to complete its transfer.
+                * Unfortunately, none of the counters get updated
+                * when the controller is in this mode, so we have
+                * no way of knowing how large the overrun was.
+                */
+               u_int scbindex = ahc_inb(ahc, SCB_TAG);
+               u_int lastphase = ahc_inb(ahc, LASTPHASE);
+               int i;
+
+               scb = &ahc->scb_data->scbarray[scbindex];
+               for (i = 0; i < num_phases; i++) {
+                       if (lastphase == phase_table[i].phase)
+                               break;
+               }
+               sc_print_addr(scb->xs->sc_link);
+               printf("data overrun detected %s."
+                      "  Tag == 0x%x.\n",
+                      phase_table[i].phasemsg,
+                      scb->hscb->tag);
+               sc_print_addr(scb->xs->sc_link);
+               printf("%s seen Data Phase.  Length = %d.  NumSGs = %d.\n",
+                      ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
+                      scb->xs->datalen, scb->sg_count);
+               if (scb->sg_count > 0) {
+                       for (i = 0; i < scb->sg_count; i++) {
+                               printf("sg[%d] - Addr 0x%x : Length %d\n",
+                                      i,
+                                      scb->sg_list[i].addr,
+                                      scb->sg_list[i].len);
+                       }
+               }
+               /*
+                * Set this and it will take affect when the
+                * target does a command complete.
+                */
+               ahc_freeze_devq(ahc, scb->xs->sc_link);
+               ahcsetccbstatus(scb->xs, XS_DRIVER_STUFFUP);
+               ahc_freeze_ccb(scb);
+               break;
+       }
+       case TRACEPOINT:
+       {
+               printf("TRACEPOINT: RETURN_2 = %d\n", ahc_inb(ahc, RETURN_2));
+#if 0
+               printf("SSTAT1 == 0x%x\n", ahc_inb(ahc, SSTAT1));
+               printf("SSTAT0 == 0x%x\n", ahc_inb(ahc, SSTAT0));
+               printf(", SCSISIGI == 0x%x\n", ahc_inb(ahc, SCSISIGI));
+               printf("TRACEPOINT: CCHCNT = %d, SG_COUNT = %d\n",
+                      ahc_inb(ahc, CCHCNT), ahc_inb(ahc, SG_COUNT));
+               printf("TRACEPOINT: SCB_TAG = %d\n", ahc_inb(ahc, SCB_TAG));
+               printf("TRACEPOINT1: CCHADDR = %d, CCHCNT = %d, SCBPTR = %d\n",
+                      ahc_inb(ahc, CCHADDR)
+                   | (ahc_inb(ahc, CCHADDR+1) << 8)
+                   | (ahc_inb(ahc, CCHADDR+2) << 16)
+                   | (ahc_inb(ahc, CCHADDR+3) << 24),
+                      ahc_inb(ahc, CCHCNT)
+                   | (ahc_inb(ahc, CCHCNT+1) << 8)
+                   | (ahc_inb(ahc, CCHCNT+2) << 16),
+                      ahc_inb(ahc, SCBPTR));
+               printf("TRACEPOINT: WAITING_SCBH = %d\n", 
+                      ahc_inb(ahc, WAITING_SCBH));
+               printf("TRACEPOINT: SCB_TAG = %d\n", ahc_inb(ahc, SCB_TAG));
+#endif
+               break;
+       }
+#if NOT_YET
+       /* XXX Fill these in later */
+       case MESG_BUFFER_BUSY:
+               break;
+       case MSGIN_PHASEMIS:
+               break;
+#endif
+       default:
+               printf("ahc_intr: seqint, "
+                      "intstat == 0x%x, scsisigi = 0x%x\n",
+                      intstat, ahc_inb(ahc, SCSISIGI));
+               break;
+       }
+       
+unpause:
+       /*
+        *  The sequencer is paused immediately on
+        *  a SEQINT, so we should restart it when
+        *  we're done.
+        */
+       unpause_sequencer(ahc);
+}
+
+STATIC void
+ahc_handle_scsiint(ahc, intstat)
+       struct ahc_softc *ahc;
+       u_int intstat;
+{
+       u_int   scb_index;
+       u_int   status;
+       struct  scb *scb;
+       char    cur_channel;
+       char    intr_channel;
+
+       if ((ahc->features & AHC_TWIN) != 0
+        && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0))
+               cur_channel = 'B';
+       else
+               cur_channel = 'A';
+       intr_channel = cur_channel;
+
+       status = ahc_inb(ahc, SSTAT1);
+       if (status == 0) {
+               if ((ahc->features & AHC_TWIN) != 0) {
+                       /* Try the other channel */
+                       ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB);
+                       status = ahc_inb(ahc, SSTAT1);
+                       ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB);
+                       intr_channel = (cur_channel == 'A') ? 'B' : 'A';
+               }
+               if (status == 0) {
+                       printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc));
+                       return;
+               }
+       }
+
+       scb_index = ahc_inb(ahc, SCB_TAG);
+       if (scb_index < ahc->scb_data->numscbs) {
+               scb = &ahc->scb_data->scbarray[scb_index];
+               if ((scb->flags & SCB_ACTIVE) == 0
+                || (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) == 0)
+                       scb = NULL;
+       } else
+               scb = NULL;
+
+       if ((status & SCSIRSTI) != 0) {
+               printf("%s: Someone reset channel %c\n",
+                       ahc_name(ahc), intr_channel);
+               ahc_reset_channel(ahc, intr_channel, /* Initiate Reset */FALSE);
+       } else if ((status & SCSIPERR) != 0) {
+               /*
+                * Determine the bus phase and queue an appropriate message.
+                * SCSIPERR is latched true as soon as a parity error
+                * occurs.  If the sequencer acked the transfer that
+                * caused the parity error and the currently presented
+                * transfer on the bus has correct parity, SCSIPERR will
+                * be cleared by CLRSCSIPERR.  Use this to determine if
+                * 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;
+               int   i;
+
+               lastphase = ahc_inb(ahc, LASTPHASE);
+               curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+               ahc_outb(ahc, CLRSINT1, CLRSCSIPERR);
+               /*
+                * For all phases save DATA, the sequencer won't
+                * automatically ack a byte that has a parity error
+                * in it.  So the only way that the current phase
+                * could be 'data-in' is if the parity error is for
+                * an already acked byte in the data phase.  During
+                * synchronous data-in transfers, we may actually
+                * ack bytes before latching the current phase in
+                * LASTPHASE, leading to the discrepancy between
+                * curphase and lastphase.
+                */
+               if ((ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0
+                || curphase == P_DATAIN)
+                       errorphase = curphase;
+               else
+                       errorphase = lastphase;
+
+               for (i = 0; i < num_phases; i++) {
+                       if (errorphase == phase_table[i].phase)
+                               break;
+               }
+               mesg_out = phase_table[i].mesg_out;
+               if (scb != NULL)
+                       sc_print_addr(scb->xs->sc_link);
+               else
+                       printf("%s:%c:%d: ", ahc_name(ahc),
+                              intr_channel,
+                              TCL_TARGET(ahc_inb(ahc, SAVED_TCL)));
+               
+               printf("parity error detected %s. "
+                      "SEQADDR(0x%x) SCSIRATE(0x%x)\n",
+                      phase_table[i].phasemsg,
+                      ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8),
+                      ahc_inb(ahc, SCSIRATE));
+
+               /*
+                * We've set the hardware to assert ATN if we   
+                * get a parity error on "in" phases, so all we  
+                * need to do is stuff the message buffer with
+                * the appropriate message.  "In" phases have set
+                * mesg_out to something other than MSG_NOP.
+                */
+               if (mesg_out != MSG_NOOP) {
+                       if (ahc->msg_type != MSG_TYPE_NONE)
+                               ahc->send_msg_perror = TRUE;
+                       else
+                               ahc_outb(ahc, MSG_OUT, mesg_out);
+               }
+               ahc_outb(ahc, CLRINT, CLRSCSIINT);
+               unpause_sequencer(ahc);
+       } else if ((status & BUSFREE) != 0
+               && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
+               /*
+                * First look at what phase we were last in.
+                * If its message out, chances are pretty good
+                * that the busfree was in response to one of
+                * our abort requests.
+                */
+               u_int lastphase = ahc_inb(ahc, LASTPHASE);
+               u_int saved_tcl = ahc_inb(ahc, SAVED_TCL);
+               u_int target = TCL_TARGET(saved_tcl);
+               u_int initiator_role_id = TCL_SCSI_ID(ahc, saved_tcl);
+               char channel = TCL_CHANNEL(ahc, saved_tcl);
+               int printerror = 1;
+
+               ahc_outb(ahc, SCSISEQ,
+                        ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+               if (lastphase == P_MESGOUT) {
+                       u_int message;
+                       u_int tag;
+
+                       message = ahc->msgout_buf[ahc->msgout_index - 1];
+                       tag = SCB_LIST_NULL;
+                       switch (message) {
+                       case MSG_ABORT_TAG:
+                               tag = scb->hscb->tag;
+                               /* FALLTRHOUGH */
+                       case MSG_ABORT:
+                               sc_print_addr(scb->xs->sc_link);
+                               printf("SCB %d - Abort %s Completed.\n",
+                                      scb->hscb->tag, tag == SCB_LIST_NULL ?
+                                      "" : "Tag");
+                               ahc_abort_scbs(ahc, target, channel,
+                                              TCL_LUN(saved_tcl), tag,
+                                              ROLE_INITIATOR,
+                                              XS_DRIVER_STUFFUP);
+                               printerror = 0;
+                               break;
+                       case MSG_BUS_DEV_RESET:
+                       {
+                               struct ahc_devinfo devinfo;
+
+                               if (scb != NULL &&
+                                   (scb->xs->flags & SCSI_RESET)
+                                && ahc_match_scb(scb, target, channel,
+                                                 TCL_LUN(saved_tcl),
+                                                 SCB_LIST_NULL,
+                                                 ROLE_INITIATOR)) {
+                                       ahcsetccbstatus(scb->xs, XS_NOERROR);
+                               }
+                               ahc_compile_devinfo(&devinfo,
+                                                   initiator_role_id,
+                                                   target,
+                                                   TCL_LUN(saved_tcl),
+                                                   channel,
+                                                   ROLE_INITIATOR);
+                               ahc_handle_devreset(ahc, &devinfo,
+                                                   XS_RESET,
+                                                   "Bus Device Reset",
+                                                   /*verbose_level*/0);
+                               printerror = 0;
+                               break;
+                       }
+                       default:
+                               break;
+                       }
+               }
+               if (printerror != 0) {
+                       int i;
+
+                       if (scb != NULL) {
+                               u_int tag;
+
+                               if ((scb->hscb->control & TAG_ENB) != 0)
+                                       tag = scb->hscb->tag;
+                               else
+                                       tag = SCB_LIST_NULL;
+                               ahc_abort_scbs(ahc, target, channel,
+                                              SCB_LUN(scb), tag,
+                                              ROLE_INITIATOR,
+                                              XS_DRIVER_STUFFUP);
+                       } else {
+                               /*
+                                * We had not fully identified this connection,
+                                * so we cannot abort anything.
+                                */
+                               printf("%s: ", ahc_name(ahc));
+                       }
+                       for (i = 0; i < num_phases; i++) {
+                               if (lastphase == phase_table[i].phase)
                                        break;
                        }
-                       printf("parity error during %s phase.\n", phase);
+                       printf("Unexpected busfree %s\n"
+                              "SEQADDR == 0x%x\n",
+                              phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0)
+                               | (ahc_inb(ahc, SEQADDR1) << 8));
+               }
+               ahc_clear_msg_state(ahc);
+               ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
+               ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR);
+               ahc_outb(ahc, CLRINT, CLRSCSIINT);
+               restart_sequencer(ahc);
+       } else if ((status & SELTO) != 0) {
+               u_int scbptr;
+
+               scbptr = ahc_inb(ahc, WAITING_SCBH);
+               ahc_outb(ahc, SCBPTR, scbptr);
+               scb_index = ahc_inb(ahc, SCB_TAG);
+
+               if (scb_index < ahc->scb_data->numscbs) {
+                       scb = &ahc->scb_data->scbarray[scb_index];
+                       if ((scb->flags & SCB_ACTIVE) == 0)
+                               scb = NULL;
+               } else
+                       scb = NULL;
+
+               if (scb == NULL) {
+                       printf("%s: ahc_intr - referenced scb not "
+                              "valid during SELTO scb(%d, %d)\n",
+                              ahc_name(ahc), scbptr, scb_index);
+               } else {
+                       u_int tag;
+
+                       tag = SCB_LIST_NULL;
+                       if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0)
+                               tag = scb->hscb->tag;
+
+                       ahc_abort_scbs(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb),
+                                      SCB_LUN(scb), tag,
+                                      ROLE_INITIATOR, XS_SELTIMEOUT);
+               }
+               /* Stop the selection */
+               ahc_outb(ahc, SCSISEQ, 0);
+
+               /* No more pending messages */
+               ahc_clear_msg_state(ahc);
+
+               /*
+                * Although the driver does not care about the
+                * 'Selection in Progress' status bit, the busy
+                * LED does.  SELINGO is only cleared by a sucessful
+                * selection, so we must manually clear it to ensure
+                * the LED turns off just incase no future successful
+                * selections occur (e.g. no devices on the bus).
+                */
+               ahc_outb(ahc, CLRSINT0, CLRSELINGO);
+
+               /* Clear interrupt state */
+               ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);
+               ahc_outb(ahc, CLRINT, CLRSCSIINT);
+               restart_sequencer(ahc);
+       } else {
+               sc_print_addr(scb->xs->sc_link);
+               printf("Unknown SCSIINT. Status = 0x%x\n", status);
+               ahc_outb(ahc, CLRSINT1, status);
+               ahc_outb(ahc, CLRINT, CLRSCSIINT);
+               unpause_sequencer(ahc);
+       }
+}
+
+STATIC void
+ahc_build_transfer_msg(ahc, devinfo)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+{
+       /*
+        * We need to initiate transfer negotiations.
+        * If our current and goal settings are identical,
+        * we want to renegotiate due to a check condition.
+        */
+       struct  ahc_initiator_tinfo *tinfo;
+       struct  tmode_tstate *tstate;
+       int     dowide;
+       int     dosync;
+
+       tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+                                   devinfo->our_scsiid,
+                                   devinfo->target, &tstate);
+       dowide = tinfo->current.width != tinfo->goal.width;
+       dosync = tinfo->current.period != tinfo->goal.period;
+
+       if (!dowide && !dosync) {
+               dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT;
+               dosync = tinfo->goal.period != 0;
+       }
+
+       if (dowide) {
+               ahc_construct_wdtr(ahc, tinfo->goal.width);
+       } else if (dosync) {
+               struct  ahc_syncrate *rate;
+               u_int   period;
+               u_int   offset;
+
+               period = tinfo->goal.period;
+               rate = ahc_devlimited_syncrate(ahc, &period);
+               offset = tinfo->goal.offset;
+               ahc_validate_offset(ahc, rate, &offset,
+                                   tinfo->current.width);
+               ahc_construct_sdtr(ahc, period, offset);
+       } else {
+               panic("ahc_intr: AWAITING_MSG for negotiation, "
+                     "but no negotiation needed\n");   
+       }
+}
+
+STATIC void
+ahc_setup_initiator_msgout(ahc, devinfo, scb)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+       struct scb *scb;
+{
+       /*              
+        * To facilitate adding multiple messages together,
+        * each routine should increment the index and len
+        * variables instead of setting them explicitly.
+        */             
+       ahc->msgout_index = 0;
+       ahc->msgout_len = 0;
+
+       if ((scb->flags & SCB_DEVICE_RESET) == 0
+        && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) {
+               u_int identify_msg;
+
+               identify_msg = MSG_IDENTIFYFLAG | SCB_LUN(scb);
+               if ((scb->hscb->control & DISCENB) != 0)
+                       identify_msg |= MSG_IDENTIFY_DISCFLAG;
+               ahc->msgout_buf[ahc->msgout_index++] = identify_msg;
+               ahc->msgout_len++;
+
+               if ((scb->hscb->control & TAG_ENB) != 0) {
+                       /* XXX fvdl FreeBSD has tag action passed down */
+                       ahc->msgout_buf[ahc->msgout_index++] = MSG_SIMPLE_Q_TAG;
+                       ahc->msgout_buf[ahc->msgout_index++] = scb->hscb->tag;
+                       ahc->msgout_len += 2;
+               }
+       }
+
+       if (scb->flags & SCB_DEVICE_RESET) {
+               ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET;
+               ahc->msgout_len++;
+               
+               sc_print_addr(scb->xs->sc_link);
+               printf("Bus Device Reset Message Sent\n");
+       } else if (scb->flags & SCB_ABORT) {
+               if ((scb->hscb->control & TAG_ENB) != 0)
+                       ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG;
+               else
+                       ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT;
+               ahc->msgout_len++;
+               sc_print_addr(scb->xs->sc_link);
+               printf("Abort Message Sent\n");
+       } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0) {
+               ahc_build_transfer_msg(ahc, devinfo);
+       } else {
+               printf("ahc_intr: AWAITING_MSG for an SCB that "
+                      "does not have a waiting message");
+               panic("SCB = %d, SCB Control = %x, MSG_OUT = %x "
+                     "SCB flags = %x", scb->hscb->tag, scb->hscb->control,
+                     ahc_inb(ahc, MSG_OUT), scb->flags);
+       }
+
+       /*
+        * Clear the MK_MESSAGE flag from the SCB so we aren't
+        * asked to send this message again.
+        */
+       ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE);
+       ahc->msgout_index = 0;
+       ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+}
+
+STATIC void
+ahc_setup_target_msgin(ahc, devinfo)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+{
+       /*              
+        * To facilitate adding multiple messages together,
+        * each routine should increment the index and len
+        * variables instead of setting them explicitly.
+        */             
+       ahc->msgout_index = 0;
+       ahc->msgout_len = 0;
+
+       if ((ahc->targ_msg_req & devinfo->target_mask) != 0)
+               ahc_build_transfer_msg(ahc, devinfo);
+       else
+               panic("ahc_intr: AWAITING target message with no message");
+
+       ahc->msgout_index = 0;
+       ahc->msg_type = MSG_TYPE_TARGET_MSGIN;
+}
+
+STATIC int
+ahc_handle_msg_reject(ahc, devinfo)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+{
+       /*
+        * What we care about here is if we had an
+        * outstanding SDTR or WDTR message for this
+        * target.  If we did, this is a signal that
+        * the target is refusing negotiation.
+        */
+       struct scb *scb;
+       u_int scb_index;
+       u_int last_msg;
+       int   response = 0;
+
+       scb_index = ahc_inb(ahc, SCB_TAG);
+       scb = &ahc->scb_data->scbarray[scb_index];
+
+       /* Might be necessary */
+       last_msg = ahc_inb(ahc, LAST_MSG);
+
+       if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/FALSE)) {
+               struct ahc_initiator_tinfo *tinfo;
+               struct tmode_tstate *tstate;
+
+               /* note 8bit xfers */
+               printf("%s:%c:%d: refuses WIDE negotiation.  Using "
+                      "8bit transfers\n", ahc_name(ahc),
+                      devinfo->channel, devinfo->target);
+               ahc_set_width(ahc, devinfo,
+                             MSG_EXT_WDTR_BUS_8_BIT,
+                             AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+                             /*paused*/TRUE, /*done*/TRUE);
+               /*
+                * No need to clear the sync rate.  If the target
+                * did not accept the command, our syncrate is
+                * unaffected.  If the target started the negotiation,
+                * but rejected our response, we already cleared the
+                * sync rate before sending our WDTR.
+                */
+               tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+                                           devinfo->our_scsiid,
+                                           devinfo->target, &tstate);
+               if (tinfo->goal.period) {
+                       u_int period;
+
+                       /* Start the sync negotiation */
+                       period = tinfo->goal.period;
+                       ahc_devlimited_syncrate(ahc, &period);
+                       ahc->msgout_index = 0;
+                       ahc->msgout_len = 0;
+                       ahc_construct_sdtr(ahc, period, tinfo->goal.offset);
+                       ahc->msgout_index = 0;
+                       response = 1;
+               }
+       } else if (ahc_sent_msg(ahc, MSG_EXT_SDTR, /*full*/FALSE)) {
+               /* note asynch xfers and clear flag */
+               ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, /*period*/0,
+                                /*offset*/0,
+                                AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+                                /*paused*/TRUE,
+                                /*done*/TRUE);
+               printf("%s:%c:%d: refuses synchronous negotiation. "
+                      "Using asynchronous transfers\n",
+                      ahc_name(ahc),
+                      devinfo->channel, devinfo->target);
+       } else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) {
+               printf("%s:%c:%d: refuses tagged commands.  Performing "
+                      "non-tagged I/O\n", ahc_name(ahc),
+                      devinfo->channel, devinfo->target);
+                       
+               ahc_set_tags(ahc, devinfo, FALSE);
+
+               /*
+                * Resend the identify for this CCB as the target
+                * may believe that the selection is invalid otherwise.
+                */
+               ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL)
+                                         & ~MSG_SIMPLE_Q_TAG);
+               scb->hscb->control &= ~MSG_SIMPLE_Q_TAG;
+               ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG);
+               ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO);
+
+               /*
+                * Requeue all tagged commands for this target
+                * currently in our posession so they can be
+                * converted to untagged commands.
+                */
+               ahc_search_qinfifo(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb),
+                                  SCB_LUN(scb), /*tag*/SCB_LIST_NULL,
+                                  ROLE_INITIATOR, SCB_REQUEUE,
+                                  SEARCH_COMPLETE);
+       } else {
+               /*
+                * Otherwise, we ignore it.
+                */
+               printf("%s:%c:%d: Message reject for %x -- ignored\n",
+                      ahc_name(ahc), devinfo->channel, devinfo->target,
+                      last_msg);
+       }
+       return (response);
+}
+
+STATIC void
+ahc_clear_msg_state(ahc)
+       struct ahc_softc *ahc;
+{
+       ahc->msgout_len = 0;
+       ahc->msgin_index = 0;
+       ahc->msg_type = MSG_TYPE_NONE;
+       ahc_outb(ahc, MSG_OUT, MSG_NOOP);
+}
+
+STATIC void
+ahc_handle_message_phase(ahc, sc_link)
+       struct ahc_softc *ahc;
+       struct scsi_link *sc_link;
+{ 
+       struct  ahc_devinfo devinfo;
+       u_int   bus_phase;
+       int     end_session;
+
+       ahc_fetch_devinfo(ahc, &devinfo);
+       end_session = FALSE;
+       bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+
+reswitch:
+       switch (ahc->msg_type) {
+       case MSG_TYPE_INITIATOR_MSGOUT:
+       {
+               int lastbyte;
+               int phasemis;
+               int msgdone;
+
+               if (ahc->msgout_len == 0)
+                       panic("REQINIT interrupt with no active message");
+
+               phasemis = bus_phase != P_MESGOUT;
+               if (phasemis) {
+                       if (bus_phase == P_MESGIN) {
+                               /*
+                                * Change gears and see if
+                                * this messages is of interest to
+                                * us or should be passed back to
+                                * the sequencer.
+                                */
+                               ahc_outb(ahc, CLRSINT1, CLRATNO);
+                               ahc->send_msg_perror = FALSE;
+                               ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+                               ahc->msgin_index = 0;
+                               goto reswitch;
+                       }
+                       end_session = TRUE;
+                       break;
+               }
+
+               if (ahc->send_msg_perror) {
+                       ahc_outb(ahc, CLRSINT1, CLRATNO);
+                       ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+                       ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR);
+                       break;
+               }
+
+               msgdone = ahc->msgout_index == ahc->msgout_len;
+               if (msgdone) {
+                       /*
+                        * The target has requested a retry.
+                        * Re-assert ATN, reset our message index to
+                        * 0, and try again.
+                        */
+                       ahc->msgout_index = 0;
+                       ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO);
+               }
+
+               lastbyte = ahc->msgout_index == (ahc->msgout_len - 1);
+               if (lastbyte) {
+                       /* Last byte is signified by dropping ATN */
+                       ahc_outb(ahc, CLRSINT1, CLRATNO);
+               }
+
+               /*
+                * Clear our interrupt status and present
+                * the next byte on the bus.
+                */
+               ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+               ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
+               break;
+       }
+       case MSG_TYPE_INITIATOR_MSGIN:
+       {
+               int phasemis;
+               int message_done;
+
+               phasemis = bus_phase != P_MESGIN;
+
+               if (phasemis) {
+                       ahc->msgin_index = 0;
+                       if (bus_phase == P_MESGOUT
+                        && (ahc->send_msg_perror == TRUE
+                         || (ahc->msgout_len != 0
+                          && ahc->msgout_index == 0))) {
+                               ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+                               goto reswitch;
+                       }
+                       end_session = TRUE;
+                       break;
+               }
+
+               /* Pull the byte in without acking it */
+               ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL);
+
+               message_done = ahc_parse_msg(ahc, sc_link, &devinfo);
+
+               if (message_done) {
+                       /*
+                        * Clear our incoming message buffer in case there
+                        * is another message following this one.
+                        */
+                       ahc->msgin_index = 0;
+
+                       /*
+                        * If this message illicited a response,
+                        * assert ATN so the target takes us to the
+                        * message out phase.
+                        */
+                       if (ahc->msgout_len != 0)
+                               ahc_outb(ahc, SCSISIGO,
+                                        ahc_inb(ahc, SCSISIGO) | ATNO);
+               } else 
+                       ahc->msgin_index++;
+
+               /* Ack the byte */
+               ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+               ahc_inb(ahc, SCSIDATL);
+               break;
+       }
+       case MSG_TYPE_TARGET_MSGIN:
+       {
+               int msgdone;
+               int msgout_request;
+
+               if (ahc->msgout_len == 0)
+                       panic("Target MSGIN with no active message");
+
+               /*
+                * If we interrupted a mesgout session, the initiator
+                * will not know this until our first REQ.  So, we
+                * only honor mesgout requests after we've sent our
+                * first byte.
+                */
+               if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0
+                && ahc->msgout_index > 0)
+                       msgout_request = TRUE;
+               else
+                       msgout_request = FALSE;
+
+               if (msgout_request) {
+
+                       /*
+                        * Change gears and see if
+                        * this messages is of interest to
+                        * us or should be passed back to
+                        * the sequencer.
+                        */
+                       ahc->msg_type = MSG_TYPE_TARGET_MSGOUT;
+                       ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO);
+                       ahc->msgin_index = 0;
+                       /* Dummy read to REQ for first byte */
+                       ahc_inb(ahc, SCSIDATL);
+                       ahc_outb(ahc, SXFRCTL0,
+                                ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+                       break;
+               }
+
+               msgdone = ahc->msgout_index == ahc->msgout_len;
+               if (msgdone) {
+                       ahc_outb(ahc, SXFRCTL0,
+                                ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
+                       end_session = TRUE;
+                       break;
+               }
+
+               /*
+                * Present the next byte on the bus.
+                */
+               ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+               ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
+               break;
+       }
+       case MSG_TYPE_TARGET_MSGOUT:
+       {
+               int lastbyte;
+               int msgdone;
+
+               /*
+                * The initiator signals that this is
+                * the last byte by dropping ATN.
+                */
+               lastbyte = (ahc_inb(ahc, SCSISIGI) & ATNI) == 0;
 
+               /*
+                * Read the latched byte, but turn off SPIOEN first
+                * so that we don't inadvertantly cause a REQ for the
+                * next byte.
+                */
+               ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
+               ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL);
+               msgdone = ahc_parse_msg(ahc, sc_link, &devinfo);
+               if (msgdone == MSGLOOP_TERMINATED) {
                        /*
-                        * We've set the hardware to assert ATN if we   
-                        * get a parity error on "in" phases, so all we  
-                        * need to do is stuff the message buffer with
-                        * the appropriate message.  "In" phases have set
-                        * mesg_out to something other than MSG_NOP.
+                        * The message is *really* done in that it caused
+                        * us to go to bus free.  The sequencer has already
+                        * been reset at this point, so pull the ejection
+                        * handle.
                         */
-                       if(mesg_out != MSG_NOOP) {
-                               AHC_OUTB(ahc, MSG0, mesg_out);
-                               AHC_OUTB(ahc, MSG_LEN, 1);
-                       }
-                       else
-                               /*
-                                * Should we allow the target to make
-                                * this decision for us?
-                                */
-                               xs->error = XS_DRIVER_STUFFUP;
+                       return;
                }
-               else if (status & SELTO) {
-                       u_char waiting;
-                       u_char flags;
+               
+               ahc->msgin_index++;
+
+               /*
+                * XXX Read spec about initiator dropping ATN too soon
+                *     and use msgdone to detect it.
+                */
+               if (msgdone == MSGLOOP_MSGCOMPLETE) {
+                       ahc->msgin_index = 0;
 
-                       xs = scb->xs;
-                       xs->error = XS_SELTIMEOUT;
                        /*
-                        * Clear any pending messages for the timed out
-                        * target, and mark the target as free
+                        * If this message illicited a response, transition
+                        * to the Message in phase and send it.
                         */
-                       flags = AHC_INB(ahc, FLAGS);
-                       AHC_OUTB(ahc, MSG_LEN, 0);
-                       ahc_unbusy_target(ahc, xs->sc_link->target,
-#if defined(__FreeBSD__)
-                               ((long)xs->sc_link->fordriver & SELBUSB)
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-                               IS_SCSIBUS_B(ahc, xs->sc_link)
-#endif
-                                       ? 'B' : 'A');
-                       /* Stop the selection */
-                       AHC_OUTB(ahc, SCSISEQ, 0);
-
-                       AHC_OUTB(ahc, SCB_CONTROL, 0);
-
-                       AHC_OUTB(ahc, CLRSINT1, CLRSELTIMEO);
-
-                       AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
-
-                       /* Shift the waiting for selection queue forward */
-                       waiting = AHC_INB(ahc, WAITING_SCBH);
-                       AHC_OUTB(ahc, SCBPTR, waiting);
-                       waiting = AHC_INB(ahc, SCB_NEXT);
-                       AHC_OUTB(ahc, WAITING_SCBH, waiting);
-
-                       restart_sequencer(ahc);
-               }       
-               else if (!(status & BUSFREE)) {
-                     sc_print_addr(scb->xs->sc_link);
-                     printf("Unknown SCSIINT. Status = 0x%x\n", status);
-                     AHC_OUTB(ahc, CLRSINT1, status);
-                     unpause_sequencer(ahc, /*unpause_always*/TRUE);
-                     AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
-                     scb = NULL;
-               }
-               if(scb != NULL) {
-                   /* We want to process the command */
-                   untimeout(ahc_timeout, (caddr_t)scb);
-                   ahc_done(ahc, scb);
-               }
-       }
-       if (intstat & CMDCMPLT) {
-               int   scb_index;
-
-               do {
-                       scb_index = AHC_INB(ahc, QOUTFIFO);
-                       scb = ahc->scbarray[scb_index];
-                       if (!scb || !(scb->flags & SCB_ACTIVE)) {
-                               printf("%s: WARNING "
-                                      "no command for scb %d (cmdcmplt)\n"
-                                      "QOUTCNT == %d\n",
-                                       ahc_name(ahc), scb_index,
-                                       AHC_INB(ahc, QOUTCNT));
-                               AHC_OUTB(ahc, CLRINT, CLRCMDINT);
-                               continue;
+                       if (ahc->msgout_len != 0) {
+                               ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO);
+                               ahc_outb(ahc, SXFRCTL0,
+                                        ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+                               ahc->msg_type = MSG_TYPE_TARGET_MSGIN;
+                               ahc->msgin_index = 0;
+                               break;
                        }
-                       AHC_OUTB(ahc, CLRINT, CLRCMDINT);
-                       untimeout(ahc_timeout, (caddr_t)scb);
-                       ahc_done(ahc, scb);
+               }
 
-               } while (AHC_INB(ahc, QOUTCNT) & ahc->qcntmask);
+               if (lastbyte)
+                       end_session = TRUE;
+               else {
+                       /* Ask for the next byte. */
+                       ahc_outb(ahc, SXFRCTL0,
+                                ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+               }
 
-               ahc_run_waiting_queues(ahc);
+               break;
        }
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-       return 1;
-#endif
+       default:
+               panic("Unknown REQINIT message type");
+       }
+
+       if (end_session) {
+               ahc_clear_msg_state(ahc);
+               ahc_outb(ahc, RETURN_1, EXIT_MSG_LOOP);
+       } else
+               ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP);
 }
 
-static void
-ahc_handle_seqint(ahc, intstat)
-       struct ahc_data *ahc;
-       u_int8_t intstat;
+/*
+ * See if we sent a particular extended message to the target.
+ * If "full" is true, the target saw the full message.
+ * If "full" is false, the target saw at least the first
+ * byte of the message.
+ */
+STATIC int
+ahc_sent_msg(ahc, msgtype, full)
+       struct ahc_softc *ahc;
+       u_int msgtype;
+       int full;
 {
-       struct scb *scb;
-       u_short targ_mask;
-       u_char target = (AHC_INB(ahc, SCSIID) >> 4) & 0x0f;
-       u_char scratch_offset = target;
-       char channel = AHC_INB(ahc, SBLKCTL) & SELBUSB ? 'B': 'A';
-
-       if (channel == 'B')
-               scratch_offset += 8;
-       targ_mask = (0x01 << scratch_offset); 
+       int found;
+       int index;
 
-       switch (intstat & SEQINT_MASK) {
-       case NO_MATCH:
-               if (ahc->flags & AHC_PAGESCBS) {
-                       /* SCB Page-in request */
-                       u_char tag;
-                       u_char next;
-                       u_char disc_scb;
-                       struct scb *outscb;
-                       u_char arg_1 = AHC_INB(ahc, ARG_1);
+       found = FALSE;
+       index = 0;
 
-                       /*
-                        * We should succeed, so set this now.
-                        * If we don't, and one of the methods
-                        * we use to aquire an SCB calls ahc_done,
-                        * we may wind up in our start routine
-                        * and unpause the adapter without giving
-                        * it the correct return value, which will
-                        * cause a hang.
-                        */
-                       AHC_OUTB(ahc, RETURN_1, SCB_PAGEDIN);
+       while (index < ahc->msgout_len) {
+               if (ahc->msgout_buf[index] == MSG_EXTENDED) {
 
-                       if (arg_1 == SCB_LIST_NULL) {
-                               /* Non-tagged command */
-                               int index;
-                               
-                               index = target|(channel == 'B' ? SELBUSB : 0);
-                               scb = ahc->pagedout_ntscbs[index];
-                       } else
-                               scb = ahc->scbarray[arg_1];
+                       /* Found a candidate */
+                       if (ahc->msgout_buf[index+2] == msgtype) {
+                               u_int end_index;
 
-                       if (!(scb->flags & SCB_PAGED_OUT))
-                               panic("%s: Request to page in a non paged out "
-                                     "SCB.", ahc_name(ahc));
-                       /*
-                        * Now to pick the SCB to page out.
-                        * Either take a free SCB, an assigned SCB,
-                        * an SCB that just completed, the first
-                        * one on the disconnected SCB list, or
-                        * as a last resort a queued SCB.
-                        */
-                       if (ahc->free_scbs.stqh_first) {
-                               outscb = ahc->free_scbs.stqh_first; 
-                               STAILQ_REMOVE_HEAD(&ahc->free_scbs, links);
-                               scb->position = outscb->position;
-                               outscb->position = SCB_LIST_NULL;
-                               STAILQ_INSERT_HEAD(&ahc->page_scbs, outscb,
-                                                  links);
-                               AHC_OUTB(ahc, SCBPTR, scb->position);
-                               ahc_send_scb(ahc, scb);
-                               scb->flags &= ~SCB_PAGED_OUT;
-                               goto pagein_done;
+                               end_index = index + 1
+                                         + ahc->msgout_buf[index + 1];
+                               if (full) {
+                                       if (ahc->msgout_index > end_index)
+                                               found = TRUE;
+                               } else if (ahc->msgout_index > index)
+                                       found = TRUE;
                        }
-                       if (intstat & CMDCMPLT) {
-                               int   scb_index;
-
-                               AHC_OUTB(ahc, CLRINT, CLRCMDINT);
-                               scb_index = AHC_INB(ahc, QOUTFIFO);
-                               if (!(AHC_INB(ahc, QOUTCNT) & ahc->qcntmask))
-                                       intstat &= ~CMDCMPLT;
-
-                               outscb = ahc->scbarray[scb_index];
-                               if (!outscb || !(outscb->flags & SCB_ACTIVE)) {
-                                       printf("%s: WARNING no command for "
-                                              "scb %d (cmdcmplt)\n",
-                                              ahc_name(ahc),
-                                              scb_index);
-                                       /*
-                                        * Fall through in hopes of finding
-                                        * another SCB
-                                        */
-                               } else {
-                                       scb->position = outscb->position;
-                                       outscb->position = SCB_LIST_NULL;
-                                       AHC_OUTB(ahc, SCBPTR, scb->position);
-                                       ahc_send_scb(ahc, scb);
-                                       scb->flags &= ~SCB_PAGED_OUT;
-                                       untimeout(ahc_timeout,
-                                                 (caddr_t)outscb);
-                                       ahc_done(ahc, outscb);
-                                       goto pagein_done;
-                               }
-                       }
-                       disc_scb = AHC_INB(ahc, DISCONNECTED_SCBH);
-                       if (disc_scb != SCB_LIST_NULL) {
-                               AHC_OUTB(ahc, SCBPTR, disc_scb);
-                               tag = AHC_INB(ahc, SCB_TAG); 
-                               outscb = ahc->scbarray[tag];
-                               next = AHC_INB(ahc, SCB_NEXT);
-                               if (next != SCB_LIST_NULL) {
-                                       AHC_OUTB(ahc, SCBPTR, next);
-                                       AHC_OUTB(ahc, SCB_PREV,
-                                                SCB_LIST_NULL);
-                                       AHC_OUTB(ahc, SCBPTR, disc_scb);
-                               }
-                               AHC_OUTB(ahc, DISCONNECTED_SCBH, next);
-                               ahc_page_scb(ahc, outscb, scb);
-                       } else if (AHC_INB(ahc, QINCNT) & ahc->qcntmask) {
-                               /*
-                                * Pull one of our queued commands
-                                * as a last resort
-                                */
-                               disc_scb = AHC_INB(ahc, QINFIFO);
-                               AHC_OUTB(ahc, SCBPTR, disc_scb);
-                               tag = AHC_INB(ahc, SCB_TAG);
-                               outscb = ahc->scbarray[tag];
-                               if ((outscb->control & 0x23) != TAG_ENB) {
-                                       /*
-                                        * This is not a simple tagged command
-                                        * so its position in the queue
-                                        * matters.  Take the command at the
-                                        * end of the queue instead.
-                                        */
-                                       int i;
-                                       u_char saved_queue[AHC_SCB_MAX];
-                                       u_char queued = AHC_INB(ahc, QINCNT)
-                                                       & ahc->qcntmask;
-
-                                       /*
-                                        * Count the command we removed
-                                        * already
-                                        */
-                                       saved_queue[0] = disc_scb;
-                                       queued++;
-
-                                       /* Empty the input queue */
-                                       for (i = 1; i < queued; i++) 
-                                               saved_queue[i] = AHC_INB(ahc, QINFIFO);
+                       break;
+               } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG
+                       && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) {
 
-                                       /*
-                                        * Put everyone back but the
-                                        * last entry
-                                        */
-                                       queued--;
-                                       for (i = 0; i < queued; i++)
-                                               AHC_OUTB(ahc, QINFIFO,
-                                                        saved_queue[i]);
-
-                                       AHC_OUTB(ahc, SCBPTR,
-                                                saved_queue[queued]);
-                                       tag = AHC_INB(ahc, SCB_TAG);
-                                       outscb = ahc->scbarray[tag];
-                               }       
-                               untimeout(ahc_timeout, (caddr_t)outscb);
-                               scb->position = outscb->position;
-                               outscb->position = SCB_LIST_NULL;
-                               STAILQ_INSERT_HEAD(&ahc->waiting_scbs,
-                                                  outscb, links);
-                               outscb->flags |= SCB_WAITINGQ;
-                               ahc_send_scb(ahc, scb);
-                               scb->flags &= ~SCB_PAGED_OUT;
-                       }
-                       else {
-                               panic("Page-in request with no candidates");
-                               AHC_OUTB(ahc, RETURN_1, 0);
-                       }
-                 pagein_done:
+                       /* Skip tag type and tag id or residue param*/
+                       index += 2;
                } else {
-                       printf("%s:%c:%d: no active SCB for reconnecting "
-                              "target - issuing ABORT\n",
-                              ahc_name(ahc), channel, target);
-                       printf("SAVED_TCL == 0x%x\n",
-                              AHC_INB(ahc, SAVED_TCL));
-                       ahc_unbusy_target(ahc, target, channel);
-                       AHC_OUTB(ahc, SCB_CONTROL, 0);
-                       AHC_OUTB(ahc, CLRSINT1, CLRSELTIMEO);
-                       AHC_OUTB(ahc, RETURN_1, 0);
+                       /* Single byte message */
+                       index++;
                }
+       }
+       return (found);
+}
+
+STATIC int
+ahc_parse_msg(ahc, sc_link, devinfo)
+       struct ahc_softc *ahc;
+       struct scsi_link *sc_link;
+       struct ahc_devinfo *devinfo;
+{
+       struct  ahc_initiator_tinfo *tinfo;
+       struct  tmode_tstate *tstate;
+       int     reject;
+       int     done;
+       int     response;
+       u_int   targ_scsirate;
+
+       done = MSGLOOP_IN_PROG;
+       response = FALSE;
+       reject = FALSE;
+       tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+                                   devinfo->target, &tstate);
+       targ_scsirate = tinfo->scsirate;
+
+       /*
+        * Parse as much of the message as is availible,
+        * rejecting it if we don't support it.  When
+        * the entire message is availible and has been
+        * handled, return MSGLOOP_MSGCOMPLETE, indicating
+        * that we have parsed an entire message.
+        *
+        * In the case of extended messages, we accept the length
+        * byte outright and perform more checking once we know the
+        * extended message type.
+        */
+       switch (ahc->msgin_buf[0]) {
+       case MSG_MESSAGE_REJECT:
+               response = ahc_handle_msg_reject(ahc, devinfo);
+               /* FALLTHROUGH */
+       case MSG_NOOP:
+               done = MSGLOOP_MSGCOMPLETE;
                break;
-       case SEND_REJECT: 
+       case MSG_IGN_WIDE_RESIDUE:
        {
-               u_char rejbyte = AHC_INB(ahc, REJBYTE);
-               printf("%s:%c:%d: Warning - unknown message received from "
-                      "target (0x%x).  Rejecting\n", 
-                      ahc_name(ahc), channel, target, rejbyte);
-               break; 
-       }
-       case NO_IDENT: 
-               panic("%s:%c:%d: Target did not send an IDENTIFY message. "
-                     "SAVED_TCL == 0x%x\n",
-                     ahc_name(ahc), channel, target,
-                     AHC_INB(ahc, SAVED_TCL));
+               /* Wait for the whole message */
+               if (ahc->msgin_index >= 1) {
+                       if (ahc->msgin_buf[1] != 1
+                        || tinfo->current.width == MSG_EXT_WDTR_BUS_8_BIT) {
+                               reject = TRUE;
+                               done = MSGLOOP_MSGCOMPLETE;
+                       } else
+                               ahc_handle_ign_wide_residue(ahc, devinfo);
+               }
                break;
-       case BAD_PHASE:
-               printf("%s:%c:%d: unknown scsi bus phase.  Attempting to "
-                      "continue\n", ahc_name(ahc), channel, target);   
-               break; 
-       case EXTENDED_MSG:
+       }
+       case MSG_EXTENDED:
        {
-               u_int8_t message_length;
-               u_int8_t message_code;
-
-               message_length = AHC_INB(ahc, MSGIN_EXT_LEN);
-               message_code = AHC_INB(ahc, MSGIN_EXT_OPCODE);
-               switch(message_code) {
+               /* Wait for enough of the message to begin validation */
+               if (ahc->msgin_index < 2)
+                       break;
+               switch (ahc->msgin_buf[2]) {
                case MSG_EXT_SDTR:
                {
-                       u_int8_t period;
-                       u_int8_t offset;
-                       u_int8_t saved_offset;
-                       u_int8_t targ_scratch;
-                       u_int8_t maxoffset;
-                       u_int8_t rate;
+                       struct   ahc_syncrate *syncrate;
+                       u_int    period;
+                       u_int    offset;
+                       u_int    saved_offset;
                        
-                       if (message_length != MSG_EXT_SDTR_LEN) {
-                               AHC_OUTB(ahc, RETURN_1, SEND_REJ);
-                               ahc->sdtrpending &= ~targ_mask;
+                       if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) {
+                               reject = TRUE;
                                break;
                        }
-                       period = AHC_INB(ahc, MSGIN_EXT_BYTE0);
-                       saved_offset = AHC_INB(ahc, MSGIN_EXT_BYTE1);
-                       targ_scratch = AHC_INB(ahc, TARG_SCRATCH
-                                              + scratch_offset);
-                       if (targ_scratch & WIDEXFER)
-                               maxoffset = MAX_OFFSET_16BIT;
-                       else
-                               maxoffset = MAX_OFFSET_8BIT;
-                       offset = MIN(saved_offset, maxoffset);
-                       ahc_scsirate(ahc, &rate, &period, &offset,
-                                    channel, target);
-                       /* Preserve the WideXfer flag */
-                       targ_scratch = rate | (targ_scratch & WIDEXFER);
 
                        /*
-                        * Update both the target scratch area and the
-                        * current SCSIRATE.
+                        * Wait until we have both args before validating
+                        * and acting on this message.
+                        *
+                        * Add one to MSG_EXT_SDTR_LEN to account for
+                        * the extended message preamble.
                         */
-                       AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset,
-                                targ_scratch);
-                       AHC_OUTB(ahc, SCSIRATE, targ_scratch); 
+                       if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1))
+                               break;
+
+                       period = ahc->msgin_buf[3];
+                       saved_offset = offset = ahc->msgin_buf[4];
+                       syncrate = ahc_devlimited_syncrate(ahc, &period);
+                       ahc_validate_offset(ahc, syncrate, &offset,
+                                           targ_scsirate & WIDEXFER);
+                       ahc_set_syncrate(ahc, devinfo,
+                                        syncrate, period, offset,
+                                        AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+                                        /*paused*/TRUE, /*done*/TRUE);
 
                        /*
                         * See if we initiated Sync Negotiation
                         * and didn't have to fall down to async
                         * transfers.
                         */
-                       if ((ahc->sdtrpending & targ_mask) != 0
-                        && (saved_offset == offset)) {
-                               /*
-                                * Don't send an SDTR back to
-                                * the target
-                                */
-                               AHC_OUTB(ahc, RETURN_1, 0);
-                               ahc->needsdtr &= ~targ_mask;
-                               ahc->sdtrpending &= ~targ_mask;
+                       if (ahc_sent_msg(ahc, MSG_EXT_SDTR, /*full*/TRUE)) {
+                               /* We started it */
+                               if (saved_offset != offset) {
+                                       /* Went too low - force async */
+                                       reject = TRUE;
+                               }
                        } else {
                                /*
                                 * Send our own SDTR in reply
                                 */
-#ifdef AHC_DEBUG
-                               if(ahc_debug & AHC_SHOWMISC)
-                                       printf("Sending SDTR!!\n");
-#endif
-                               ahc_construct_sdtr(ahc, /*start_byte*/0,
-                                                  period, offset);
-                               AHC_OUTB(ahc, RETURN_1, SEND_MSG);
-
-                               /*
-                                * If we aren't starting a re-negotiation
-                                * because we had to go async in response
-                                * to a "too low" response from the target
-                                * clear the needsdtr flag for this target.
-                                */
-                               if ((ahc->sdtrpending & targ_mask) == 0)
-                                       ahc->needsdtr &= ~targ_mask;
-                               else
-                                       ahc->sdtrpending |= targ_mask;
+                               if (bootverbose)
+                                       printf("Sending SDTR!\n");
+                               ahc->msgout_index = 0;
+                               ahc->msgout_len = 0;
+                               ahc_construct_sdtr(ahc, period, offset);
+                               ahc->msgout_index = 0;
+                               response = TRUE;
                        }
+                       done = MSGLOOP_MSGCOMPLETE;
                        break;
                }
                case MSG_EXT_WDTR:
                {
-                       u_int8_t scratch, bus_width;
+                       u_int   bus_width;
+                       u_int   sending_reply;
 
-                       if (message_length != MSG_EXT_WDTR_LEN) {
-                               AHC_OUTB(ahc, RETURN_1, SEND_REJ);
-                               ahc->wdtrpending &= ~targ_mask;
+                       sending_reply = FALSE;
+                       if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) {
+                               reject = TRUE;
                                break;
                        }
 
-                       bus_width = AHC_INB(ahc, MSGIN_EXT_BYTE0);
-                       scratch = AHC_INB(ahc, TARG_SCRATCH
-                                         + scratch_offset);
+                       /*
+                        * Wait until we have our arg before validating
+                        * and acting on this message.
+                        *
+                        * Add one to MSG_EXT_WDTR_LEN to account for
+                        * the extended message preamble.
+                        */
+                       if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1))
+                               break;
 
-                       if (ahc->wdtrpending & targ_mask) {
+                       bus_width = ahc->msgin_buf[3];
+                       if (ahc_sent_msg(ahc, MSG_EXT_WDTR, /*full*/TRUE)) {
                                /*
                                 * Don't send a WDTR back to the
                                 * target, since we asked first.
                                 */
-                               AHC_OUTB(ahc, RETURN_1, 0);
-                               switch(bus_width){
-                               case BUS_8_BIT:
-                                       scratch &= 0x7f;
-                                       break;
-                               case BUS_16_BIT:
-                                       if(bootverbose)
-                                               printf("%s: target %d using "
-                                                      "16Bit transfers\n",
-                                                      ahc_name(ahc), target);
-                                       scratch |= WIDEXFER;    
-                                       break;
-                               case BUS_32_BIT:
+                               switch (bus_width){
+                               default:
                                        /*
-                                        * How can we do 32bit transfers
-                                        * on a 16bit bus?
+                                        * How can we do anything greater
+                                        * than 16bit transfers on a 16bit
+                                        * bus?
                                         */
-                                       AHC_OUTB(ahc, RETURN_1, SEND_REJ);
-                                       printf("%s: target %d requested 32Bit "
+                                       reject = TRUE;
+                                       printf("%s: target %d requested %dBit "
                                               "transfers.  Rejecting...\n",
-                                              ahc_name(ahc), target);
+                                              ahc_name(ahc), devinfo->target,
+                                              8 * (0x01 << bus_width));
+                                       /* FALLTHROUGH */
+                               case MSG_EXT_WDTR_BUS_8_BIT:
+                                       bus_width = MSG_EXT_WDTR_BUS_8_BIT;
                                        break;
-                               default:
+                               case MSG_EXT_WDTR_BUS_16_BIT:
                                        break;
                                }
                        } else {
                                /*
                                 * Send our own WDTR in reply
                                 */
-                               switch(bus_width) {
-                               case BUS_8_BIT:
-                                       scratch &= 0x7f;
-                                       break;
-                               case BUS_32_BIT:
-                               case BUS_16_BIT:
-                                       if(ahc->type & AHC_WIDE) {
-                                               /* Negotiate 16_BITS */
-                                               bus_width = BUS_16_BIT;
-                                               if(bootverbose)
-                                                       printf("%s: target %d "
-                                                              "using 16Bit "
-                                                              "transfers\n",
-                                                              ahc_name(ahc),
-                                                              target);
-                                               scratch |= WIDEXFER;    
-                                       } else
-                                               bus_width = BUS_8_BIT;
-                                       break;
+                               if (bootverbose)
+                                       printf("Sending WDTR!\n");
+                               switch (bus_width) {
                                default:
+                                       if (ahc->features & AHC_WIDE) {
+                                               /* Respond Wide */
+                                               bus_width =
+                                                   MSG_EXT_WDTR_BUS_16_BIT;
+                                               break;
+                                       }
+                                       /* FALLTHROUGH */
+                               case MSG_EXT_WDTR_BUS_8_BIT:
+                                       bus_width = MSG_EXT_WDTR_BUS_8_BIT;
                                        break;
                                }
-                               ahc_construct_wdtr(ahc, /*start_byte*/0,
-                                                  bus_width);
-                               AHC_OUTB(ahc, RETURN_1, SEND_MSG);
+                               ahc->msgout_index = 0;
+                               ahc->msgout_len = 0;
+                               ahc_construct_wdtr(ahc, bus_width);
+                               ahc->msgout_index = 0;
+                               response = TRUE;
+                               sending_reply = TRUE;
                        }
-                       
-                       ahc->needwdtr &= ~targ_mask;
-                       ahc->wdtrpending &= ~targ_mask;
-                       AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset, scratch);
-                       AHC_OUTB(ahc, SCSIRATE, scratch); 
+                       ahc_set_width(ahc, devinfo, bus_width,
+                                     AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+                                     /*paused*/TRUE, /*done*/TRUE);
+
+                       /* After a wide message, we are async */
+                       ahc_set_syncrate(ahc, devinfo,
+                                        /*syncrate*/NULL, /*period*/0,
+                                        /*offset*/0, AHC_TRANS_ACTIVE,
+                                        /*paused*/TRUE, /*done*/FALSE);
+                       if (sending_reply == FALSE && reject == FALSE) {
+
+                               if (tinfo->goal.period) {
+                                       struct  ahc_syncrate *rate;
+                                       u_int   period;
+                                       u_int   offset;
+
+                                       /* Start the sync negotiation */
+                                       period = tinfo->goal.period;
+                                       rate = ahc_devlimited_syncrate(ahc,
+                                                                      &period);
+                                       offset = tinfo->goal.offset;
+                                       ahc_validate_offset(ahc, rate, &offset,
+                                                         tinfo->current.width);
+                                       ahc->msgout_index = 0;
+                                       ahc->msgout_len = 0;
+                                       ahc_construct_sdtr(ahc, period, offset);
+                                       ahc->msgout_index = 0;
+                                       response = TRUE;
+                               }
+                       }
+                       done = MSGLOOP_MSGCOMPLETE;
                        break;
                }
                default:
                        /* Unknown extended message.  Reject it. */
-                       AHC_OUTB(ahc, RETURN_1, SEND_REJ);
-               }
-       }
-       case REJECT_MSG:
-       {
-               /*
-                * What we care about here is if we had an
-                * outstanding SDTR or WDTR message for this
-                * target.  If we did, this is a signal that
-                * the target is refusing negotiation.
-                */
-
-               u_char targ_scratch;
-
-               targ_scratch = AHC_INB(ahc, TARG_SCRATCH
-                                      + scratch_offset);
-
-               if (ahc->wdtrpending & targ_mask){
-                       /* note 8bit xfers and clear flag */
-                       targ_scratch &= 0x7f;
-                       ahc->needwdtr &= ~targ_mask;
-                       ahc->wdtrpending &= ~targ_mask;
-#if !(defined(__NetBSD__) || defined(__OpenBSD__)) || defined(DEBUG)
-                       printf("%s:%c:%d: refuses WIDE negotiation.  Using "
-                              "8bit transfers\n", ahc_name(ahc),
-                              channel, target);
-#endif
-               } else if(ahc->sdtrpending & targ_mask){
-                       /* note asynch xfers and clear flag */
-                       targ_scratch &= 0xf0;
-                       ahc->needsdtr &= ~targ_mask;
-                       ahc->sdtrpending &= ~targ_mask;
-#if !(defined(__NetBSD__) || defined(__OpenBSD__)) || defined(DEBUG)
-                       printf("%s:%c:%d: refuses synchronous negotiation. "
-                              "Using asynchronous transfers\n",
-                              ahc_name(ahc),
-                              channel, target);
-#endif
-               } else {
-                       /*
-                        * Otherwise, we ignore it.
-                        */
-#ifdef AHC_DEBUG
-                       if(ahc_debug & AHC_SHOWMISC)
-                               printf("%s:%c:%d: Message reject -- ignored\n",
-                                      ahc_name(ahc), channel, target);
-#endif
+                       reject = TRUE;
                        break;
                }
-               AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset, targ_scratch);
-               AHC_OUTB(ahc, SCSIRATE, targ_scratch);
                break;
        }
-       case BAD_STATUS:
-       {
-               int     scb_index;
-               struct  scsi_xfer *xs;
-
-               /* The sequencer will notify us when a command
-                * has an error that would be of interest to
-                * the kernel.  This allows us to leave the sequencer
-                * running in the common case of command completes
-                * without error.
-                */
-
-               scb_index = AHC_INB(ahc, SCB_TAG);
-               scb = ahc->scbarray[scb_index];
-
-               /*
-                * Set the default return value to 0 (don't
-                * send sense).  The sense code will change
-                * this if needed and this reduces code
-                * duplication.
-                */
-               AHC_OUTB(ahc, RETURN_1, 0);
-               if (!(scb && (scb->flags & SCB_ACTIVE))) {
-                       printf("%s:%c:%d: ahc_intr - referenced scb "
-                              "not valid during seqint 0x%x scb(%d)\n",
-                              ahc_name(ahc),
-                              channel, target, intstat,
-                              scb_index);
-                       goto clear;
-               }
-
-               xs = scb->xs;
-
-               scb->status = AHC_INB(ahc, SCB_TARGET_STATUS);
-
-#ifdef AHC_DEBUG
-               if((ahc_debug & AHC_SHOWSCBS)
-                  && xs->sc_link->target == DEBUGTARGET)
-                       ahc_print_scb(scb);
-#endif
-               xs->status = scb->status;
-               switch(scb->status){
-               case SCSI_OK:
-                       printf("%s: Interrupted for staus of"
-                              " 0???\n", ahc_name(ahc));
+       case MSG_BUS_DEV_RESET:
+               ahc_handle_devreset(ahc, devinfo,
+                                   XS_RESET, "Bus Device Reset Received",
+                                   /*verbose_level*/0);
+               restart_sequencer(ahc);
+               done = MSGLOOP_TERMINATED;
+               break;
+       case MSG_ABORT_TAG:
+       case MSG_ABORT:
+       case MSG_CLEAR_QUEUE:
+               /* Target mode messages */
+               if (devinfo->role != ROLE_TARGET) {
+                       reject = TRUE;
                        break;
-               case SCSI_CHECK:
-#ifdef AHC_DEBUG
-                       if(ahc_debug & AHC_SHOWSENSE)
-                       {
-
-                               sc_print_addr(xs->sc_link);
-                               printf("requests Check Status\n");
-                       }
-#endif
-
-                       if ((xs->error == XS_NOERROR)
-                           && !(scb->flags & SCB_SENSE)) {
-                               struct ahc_dma_seg *sg = scb->ahc_dma;
-                               struct scsi_sense *sc = &(scb->sense_cmd);
-#ifdef AHC_DEBUG
-                               if (ahc_debug & AHC_SHOWSENSE)
-                               {
-                                       sc_print_addr(xs->sc_link);
-                                       printf("Sending Sense\n");
-                               }
-#endif
-#if defined(__FreeBSD__)
-                               sc->op_code = REQUEST_SENSE;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-                               sc->opcode = REQUEST_SENSE;
-#endif
-                               sc->byte2 =  xs->sc_link->lun << 5;
-                               sc->length = sizeof(struct scsi_sense_data);
-                               sc->control = 0;
-                               sg->addr = KVTOPHYS(&xs->sense);
-                               sg->len = sizeof(struct scsi_sense_data);
-
-                               scb->control &= DISCENB;
-                               scb->status = 0;
-                               scb->SG_segment_count = 1;
-                               scb->SG_list_pointer = KVTOPHYS(sg);
-                               scb->data = sg->addr; 
-                               scb->datalen = sg->len;
-#ifdef AHC_BROKEN_CACHE
-                               if (ahc_broken_cache)
-                                       INVALIDATE_CACHE();
-#endif
-                               scb->cmdpointer = KVTOPHYS(sc);
-                               scb->cmdlen = sizeof(*sc);
-
-                               scb->flags |= SCB_SENSE;
-                               ahc_send_scb(ahc, scb);
-                               /*
-                                * Ensure that the target is "BUSY"
-                                * so we don't get overlapping 
-                                * commands if we happen to be doing
-                                * tagged I/O.
-                                */
-                               ahc_busy_target(ahc, target, channel);
-
-                               /*
-                                * Make us the next command to run
-                                */
-                               ahc_add_waiting_scb(ahc, scb);
-                               AHC_OUTB(ahc, RETURN_1, SEND_SENSE);
-                               break;
+               }
+#if AHC_TARGET_MODE
+               ahc_abort_scbs(ahc, devinfo->target, devinfo->channel,
+                              devinfo->lun,
+                              ahc->msgin_buf[0] == MSG_ABORT_TAG ? SCB_LIST_NULL
+                              : ahc_inb(ahc, INITIATOR_TAG),
+                               ROLE_TARGET, XS_DRIVER_STUFFUP);
+
+               tstate = ahc->enabled_targets[devinfo->our_scsiid];
+               if (tstate != NULL) {
+                       struct tmode_lstate* lstate;
+
+                       lstate = tstate->enabled_luns[devinfo->lun];
+                       if (lstate != NULL) {
+                               ahc_queue_lstate_event(ahc, lstate,
+                                                      devinfo->our_scsiid,
+                                                      ahc->msgin_buf[0],
+                                                      /*arg*/0);
+                               ahc_send_lstate_events(ahc, lstate);
                        }
-                       /*
-                        * Clear the SCB_SENSE Flag and have
-                        * the sequencer do a normal command
-                        * complete with either a "DRIVER_STUFFUP"
-                        * error or whatever other error condition
-                        * we already had.
-                        */
-                       scb->flags &= ~SCB_SENSE;
-                       if (xs->error == XS_NOERROR)
-                               xs->error = XS_DRIVER_STUFFUP;
-                       break;
-               case SCSI_BUSY:
-                       xs->error = XS_BUSY;
-                       sc_print_addr(xs->sc_link);
-                       printf("Target Busy\n");
-                       break;
-               case SCSI_QUEUE_FULL:
-                       /*
-                        * The upper level SCSI code will someday
-                        * handle this properly.
-                        */
-                       sc_print_addr(xs->sc_link);
-                       printf("Queue Full\n");
-                       scb->flags |= SCB_ASSIGNEDQ;
-                       STAILQ_INSERT_TAIL(&ahc->assigned_scbs,scb, links);
-                       AHC_OUTB(ahc, RETURN_1, SEND_SENSE);
-                       break;
-               default:
-                       sc_print_addr(xs->sc_link);
-                       printf("unexpected targ_status: %x\n", scb->status);
-                       xs->error = XS_DRIVER_STUFFUP;
-                       break;
                }
+               done = MSGLOOP_MSGCOMPLETE;
+#else
+               panic("ahc: got target mode message");
+#endif
+               break;
+       case MSG_TERM_IO_PROC:
+       default:
+               reject = TRUE;
                break;
        }
-       case RESIDUAL:
-       {
-               int scb_index;
-               struct scsi_xfer *xs;
 
-               scb_index = AHC_INB(ahc, SCB_TAG);
-               scb = ahc->scbarray[scb_index];
-               xs = scb->xs;
+       if (reject) {
                /*
-                * Don't clobber valid resid info with
-                * a resid coming from a check sense
-                * operation.
+                * Setup to reject the message.
                 */
-               if (!(scb->flags & SCB_SENSE)) {
-                       int resid_sgs;
-
-                       /*
-                        * Remainder of the SG where the transfer
-                        * stopped.
-                        */
-                       xs->resid = (AHC_INB(ahc, SCB_RESID_DCNT2)<<16) |
-                                   (AHC_INB(ahc, SCB_RESID_DCNT1)<<8)  |
-                                   AHC_INB(ahc, SCB_RESID_DCNT0);
-
-                       /*
-                        * Add up the contents of all residual
-                        * SG segments that are after the SG where
-                        * the transfer stopped.
-                        */
-                       resid_sgs = AHC_INB(ahc, SCB_RESID_SGCNT) - 1;
-                       while (resid_sgs > 0) {
-                               int sg;
+               ahc->msgout_index = 0;
+               ahc->msgout_len = 1;
+               ahc->msgout_buf[0] = MSG_MESSAGE_REJECT;
+               done = MSGLOOP_MSGCOMPLETE;
+               response = TRUE;
+       }
 
-                               sg = scb->SG_segment_count - resid_sgs;
-                               xs->resid += scb->ahc_dma[sg].len;
-                               resid_sgs--;
-                       }
+       if (done != MSGLOOP_IN_PROG && !response)
+               /* Clear the outgoing message buffer */
+               ahc->msgout_len = 0;
 
-#if defined(__FreeBSD__)
-                       xs->flags |= SCSI_RESID_VALID;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-                       /* XXX - Update to do this right */
-#endif
-#ifdef AHC_DEBUG
-                       if (ahc_debug & AHC_SHOWMISC) {
-                               sc_print_addr(xs->sc_link);
-                               printf("Handled Residual of %ld bytes\n"
-                                      ,xs->resid);
-                       }
-#endif
-               }
-               break;
-       }
-       case ABORT_TAG:
-       {
-               int   scb_index;
-               struct scsi_xfer *xs;
+       return (done);
+}
 
-               scb_index = AHC_INB(ahc, SCB_TAG);
-               scb = ahc->scbarray[scb_index];
-               xs = scb->xs;
-               /*
-                * We didn't recieve a valid tag back from
-                * the target on a reconnect.
-                */
-               sc_print_addr(xs->sc_link);
-               printf("invalid tag received -- sending ABORT_TAG\n");
-               xs->error = XS_DRIVER_STUFFUP;
-               untimeout(ahc_timeout, (caddr_t)scb);
-               ahc_done(ahc, scb);
-               break;
-       }
-       case AWAITING_MSG:
-       {
-               int   scb_index;
-               scb_index = AHC_INB(ahc, SCB_TAG);
-               scb = ahc->scbarray[scb_index];
-               /*
-                * This SCB had a zero length command, informing
-                * the sequencer that we wanted to send a special
-                * message to this target.  We only do this for
-                * BUS_DEVICE_RESET messages currently.
-                */
-               if (scb->flags & SCB_DEVICE_RESET) {
-                       AHC_OUTB(ahc, MSG0,
-                                MSG_BUS_DEV_RESET);
-                       AHC_OUTB(ahc, MSG_LEN, 1);
-                       printf("Bus Device Reset Message Sent\n");
-               } else if (scb->flags & SCB_MSGOUT_WDTR) {
-                       ahc_construct_wdtr(ahc, AHC_INB(ahc, MSG_LEN),
-                                          BUS_16_BIT);
-               } else if (scb->flags & SCB_MSGOUT_SDTR) {
-                       u_int8_t target_scratch;
-                       u_int8_t ultraenable;                   
-                       int sxfr;
-                       int i;
+STATIC void
+ahc_handle_ign_wide_residue(ahc, devinfo)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+{
+       u_int scb_index;
+       struct scb *scb;
 
-                       /* Pull the user defined setting */
-                       target_scratch = AHC_INB(ahc, TARG_SCRATCH
-                                                + scratch_offset);
-                       
-                       sxfr = target_scratch & SXFR;
-                       if (scratch_offset < 8)
-                               ultraenable = AHC_INB(ahc, ULTRA_ENB);
-                       else
-                               ultraenable = AHC_INB(ahc, ULTRA_ENB + 1);
-                       
-                       if (ultraenable & targ_mask)
-                               /* Want an ultra speed in the table */
-                               sxfr |= 0x100;
-                       
-                       for (i = 0; i < ahc_num_syncrates; i++)
-                               if (sxfr == ahc_syncrates[i].sxfr)
-                                       break;
-                                                       
-                       ahc_construct_sdtr(ahc, AHC_INB(ahc, MSG_LEN),
-                                          ahc_syncrates[i].period,
-                                          target_scratch & WIDEXFER ?
-                                          MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
-               } else  
-                       panic("ahc_intr: AWAITING_MSG for an SCB that "
-                             "does not have a waiting message");
-               break;
-       }
-       case IMMEDDONE:
-       {
-               /*
-                * Take care of device reset messages
-                */
-               u_char scbindex = AHC_INB(ahc, SCB_TAG);
-               scb = ahc->scbarray[scbindex];
-               if (scb->flags & SCB_DEVICE_RESET) {
-                       u_char targ_scratch;
-                       int found;
-                       /*
-                        * Go back to async/narrow transfers and
-                        * renegotiate.
-                        */
-                       ahc_unbusy_target(ahc, target, channel);
-                       ahc->needsdtr |= ahc->needsdtr_orig & targ_mask;
-                       ahc->needwdtr |= ahc->needwdtr_orig & targ_mask;
-                       ahc->sdtrpending &= ~targ_mask;
-                       ahc->wdtrpending &= ~targ_mask;
-                       targ_scratch = AHC_INB(ahc, TARG_SCRATCH 
-                                              + scratch_offset);
-                       targ_scratch &= SXFR;
-                       AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset,
-                                targ_scratch);
-                       found = ahc_reset_device(ahc, target,
-                                                channel, SCB_LIST_NULL, 
-                                                XS_NOERROR);
-                       sc_print_addr(scb->xs->sc_link);
-                       printf("Bus Device Reset delivered. "
-                              "%d SCBs aborted\n", found);
-                       ahc->in_timeout = FALSE;
-                       ahc_run_done_queue(ahc);
-               } else
-                       panic("ahc_intr: Immediate complete for "
-                             "unknown operation.");
-               break;
-       }
-       case DATA_OVERRUN:
-       {
+       scb_index = ahc_inb(ahc, SCB_TAG);
+       scb = &ahc->scb_data->scbarray[scb_index];
+       if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0
+        || !(scb->xs->flags & SCSI_DATA_IN)) {
                /*
-                * When the sequencer detects an overrun, it
-                * sets STCNT to 0x00ffffff and allows the
-                * target to complete its transfer in
-                * BITBUCKET mode.
+                * Ignore the message if we haven't
+                * seen an appropriate data phase yet.
                 */
-               u_char scbindex = AHC_INB(ahc, SCB_TAG);
-               u_int32_t overrun;
-               scb = ahc->scbarray[scbindex];
-               overrun = AHC_INB(ahc, STCNT0)
-                       | (AHC_INB(ahc, STCNT1) << 8)
-                       | (AHC_INB(ahc, STCNT2) << 16);
-               overrun = 0x00ffffff - overrun;
-               sc_print_addr(scb->xs->sc_link);
-               printf("data overrun of %d bytes detected."
-                      "  Forcing a retry.\n", overrun);
+       } else {
                /*
-                * Set this and it will take affect when the
-                * target does a command complete.
+                * If the residual occurred on the last
+                * transfer and the transfer request was
+                * expected to end on an odd count, do
+                * nothing.  Otherwise, subtract a byte
+                * and update the residual count accordingly.
                 */
-               scb->xs->error = XS_DRIVER_STUFFUP;
-               break;
-       }
-#if NOT_YET
-       /* XXX Fill these in later */
-       case MESG_BUFFER_BUSY:
-               break;
-       case MSGIN_PHASEMIS:
-               break;
-#endif
-       default:
-               printf("ahc_intr: seqint, "
-                      "intstat == 0x%x, scsisigi = 0x%x\n",
-                      intstat, AHC_INB(ahc, SCSISIGI));
-               break;
+               u_int resid_sgcnt;
+
+               resid_sgcnt = ahc_inb(ahc, SCB_RESID_SGCNT);
+               if (resid_sgcnt == 0
+                && ahc_inb(ahc, DATA_COUNT_ODD) == 1) {
+                       /*
+                        * If the residual occurred on the last
+                        * transfer and the transfer request was
+                        * expected to end on an odd count, do
+                        * nothing.
+                        */
+               } else {
+                       u_int data_cnt;
+                       u_int data_addr;
+                       u_int sg_index;
+
+                       data_cnt = (ahc_inb(ahc, SCB_RESID_DCNT + 2) << 16)
+                                | (ahc_inb(ahc, SCB_RESID_DCNT + 1) << 8)
+                                | (ahc_inb(ahc, SCB_RESID_DCNT));
+
+                       data_addr = (ahc_inb(ahc, SHADDR + 3) << 24)
+                                 | (ahc_inb(ahc, SHADDR + 2) << 16)
+                                 | (ahc_inb(ahc, SHADDR + 1) << 8)
+                                 | (ahc_inb(ahc, SHADDR));
+
+                       data_cnt += 1;
+                       data_addr -= 1;
+
+                       sg_index = scb->sg_count - resid_sgcnt;
+
+                       if (sg_index != 0
+                        && (scb->sg_list[sg_index].len < data_cnt)) {
+                               u_int sg_addr;
+
+                               sg_index--;
+                               data_cnt = 1;
+                               data_addr = scb->sg_list[sg_index].addr
+                                         + scb->sg_list[sg_index].len - 1;
+                               
+                               /*
+                                * The physical address base points to the
+                                * second entry as it is always used for
+                                * calculating the "next S/G pointer".
+                                */
+                               sg_addr = scb->sg_list_phys
+                                       + (sg_index* sizeof(*scb->sg_list));
+                               ahc_outb(ahc, SG_NEXT + 3, sg_addr >> 24);
+                               ahc_outb(ahc, SG_NEXT + 2, sg_addr >> 16);
+                               ahc_outb(ahc, SG_NEXT + 1, sg_addr >> 8);
+                               ahc_outb(ahc, SG_NEXT, sg_addr);
+                       }
+
+                       ahc_outb(ahc, SCB_RESID_DCNT + 2, data_cnt >> 16);
+                       ahc_outb(ahc, SCB_RESID_DCNT + 1, data_cnt >> 8);
+                       ahc_outb(ahc, SCB_RESID_DCNT, data_cnt);
+
+                       ahc_outb(ahc, SHADDR + 3, data_addr >> 24);
+                       ahc_outb(ahc, SHADDR + 2, data_addr >> 16);
+                       ahc_outb(ahc, SHADDR + 1, data_addr >> 8);
+                       ahc_outb(ahc, SHADDR, data_addr);
+               }
        }
-       
-clear:
-       /*
-        * Clear the upper byte that holds SEQINT status
-        * codes and clear the SEQINT bit.
-        */
-       AHC_OUTB(ahc, CLRINT, CLRSEQINT);
+}
+
+STATIC void
+ahc_handle_devreset(ahc, devinfo, status, message, verbose_level)
+       struct ahc_softc *ahc;
+       struct ahc_devinfo *devinfo;
+       int status;
+       char *message;
+       int verbose_level;
+{
+       int found;
 
+       found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel,
+                              ALL_LUNS, SCB_LIST_NULL, devinfo->role,
+                              status);
+       
        /*
-        *  The sequencer is paused immediately on
-        *  a SEQINT, so we should restart it when
-        *  we're done.
+        * Go back to async/narrow transfers and renegotiate.
+        * ahc_set_width and ahc_set_syncrate can cope with NULL
+        * paths.
         */
-       unpause_sequencer(ahc, /*unpause_always*/TRUE);
+       ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+                     AHC_TRANS_CUR, /*paused*/TRUE, /*done*/FALSE);
+       ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL,
+                        /*period*/0, /*offset*/0, AHC_TRANS_CUR,
+                        /*paused*/TRUE, /*done*/FALSE);
+       
+       if (message != NULL
+        && (verbose_level <= bootverbose))
+               printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc),
+                      message, devinfo->channel, devinfo->target, found);
 }
 
 /*
- * We have a scb which has been processed by the
+ * We have an scb which has been processed by the
  * adaptor, now we look to see how the operation
  * went.
  */
-static void
+STATIC void
 ahc_done(ahc, scb)
-       struct ahc_data *ahc;
+       struct ahc_softc *ahc;
        struct scb *scb;
 {
        struct scsi_xfer *xs = scb->xs;
+       struct scsi_link *sc_link = xs->sc_link;
+       int requeue = 0;
+       int target;
 
        SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_done\n"));
+       
+       LIST_REMOVE(scb, pend_links);
+
+       untimeout(ahc_timeout, (caddr_t)scb);
+
+#ifdef AHC_DEBUG
+       if (ahc_debug & AHC_SHOWCMDS) {
+               sc_print_addr(sc_link);
+               printf("ahc_done opcode %d tag %x\n", xs->cmdstore.opcode,
+                   scb->hscb->tag);
+       }
+#endif
+       
+       target = sc_link->target;
+       
+       if (xs->datalen) {
+               int op;
+       
+               if ((xs->flags & SCSI_DATA_IN) != 0)
+                       op = BUS_DMASYNC_POSTREAD;
+               else
+                       op = BUS_DMASYNC_POSTWRITE;
+               bus_dmamap_sync(ahc->sc_dmat, scb->dmamap, op);
+               bus_dmamap_unload(ahc->sc_dmat, scb->dmamap);
+       }
+
        /*
-        * Put the results of the operation
-        * into the xfer and call whoever started it
+        * Unbusy this target/channel/lun.
+        * XXX if we are holding two commands per lun, 
+        *     send the next command.
         */
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-       if (xs->error != XS_NOERROR) {
-               /* Don't override the error value. */
-       } else if (scb->flags & SCB_ABORTED) {
-               xs->error = XS_DRIVER_STUFFUP;
-       } else
-#endif
-       if(scb->flags & SCB_SENSE)
-               xs->error = XS_SENSE;
-       if(scb->flags & SCB_SENTORDEREDTAG)
-               ahc->in_timeout = FALSE;
-#if defined(__FreeBSD__)
-       if ((xs->flags & SCSI_ERR_OK) && !(xs->error == XS_SENSE)) {
-               /* All went correctly  OR errors expected */
-               xs->error = XS_NOERROR;
-       }
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
+       ahc_index_busy_tcl(ahc, scb->hscb->tcl, /*unbusy*/TRUE);
+
        /*
-        * Since NetBSD nor OpenBSD doesn't have error ignoring operation mode
-        * (SCSI_ERR_OK in FreeBSD), we don't have to care this case.
+        * If the recovery SCB completes, we have to be
+        * out of our timeout.
         */
-#endif
-       xs->flags |= ITSDONE;
-#ifdef AHC_TAGENABLE
-       if(xs->cmd->opcode == INQUIRY && xs->error == XS_NOERROR)
-       {
-               struct scsi_inquiry_data *inq_data;
-               u_short mask = 0x01 << (xs->sc_link->target |
-                               (scb->tcl & 0x08));
+       if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
+
+               struct  scb *scbp;
+
                /*
-                * Sneak a look at the results of the SCSI Inquiry
-                * command and see if we can do Tagged queing.  This
-                * should really be done by the higher level drivers.
+                * We were able to complete the command successfully,
+                * so reinstate the timeouts for all other pending
+                * commands.
                 */
-               inq_data = (struct scsi_inquiry_data *)xs->data;
-               if((inq_data->flags & SID_CmdQue) && !(ahc->tagenable & mask))
-               {
-                       printf("%s: target %d Tagged Queuing Device\n",
-                               ahc_name(ahc), xs->sc_link->target);
-                       ahc->tagenable |= mask;
-                       if(ahc->maxhscbs >= 16 || (ahc->flags & AHC_PAGESCBS)) {
-                               /* Default to 8 tags */
-                               xs->sc_link->opennings += 6;
-                       }
-                       else
-                       {
-                               /*
-                                * Default to 4 tags on whimpy
-                                * cards that don't have much SCB
-                                * space and can't page.  This prevents
-                                * a single device from hogging all
-                                * slots.  We should really have a better
-                                * way of providing fairness.
-                                */
-                               xs->sc_link->opennings += 2;
+               scbp = ahc->pending_scbs.lh_first;
+               while (scbp != NULL) {
+                       struct scsi_xfer *txs = scbp->xs;
+
+                       if (!(txs->flags & SCSI_POLL)) {
+                               timeout(ahc_timeout, scbp,
+                                   (scbp->xs->timeout * hz)/1000);
                        }
+                       scbp = LIST_NEXT(scbp, pend_links);
                }
+
+               /*
+                * Ensure that we didn't put a second instance of this
+                * SCB into the QINFIFO.
+                */
+               ahc_search_qinfifo(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb),
+                                  SCB_LUN(scb), scb->hscb->tag,
+                                  ROLE_INITIATOR, /*status*/0,
+                                  SEARCH_REMOVE);
+               if (xs->error != XS_NOERROR)
+                       ahcsetccbstatus(xs, XS_TIMEOUT);
+               sc_print_addr(xs->sc_link);
+               printf("no longer in timeout, status = %x\n", xs->status);
+       }
+
+       if (xs->error != XS_NOERROR) {
+               /* Don't clobber any existing error state */
+       } else if ((scb->flags & SCB_SENSE) != 0) {
+               /*
+                * We performed autosense retrieval.
+                *
+                * bzero the sense data before having
+                * the drive fill it.  The SCSI spec mandates
+                * that any untransfered data should be
+                * assumed to be zero.  Complete the 'bounce'
+                * of sense information through buffers accessible
+                * via bus-space by copying it into the clients
+                * csio.
+                */
+               bzero(&xs->sense, sizeof(struct scsi_sense));
+               bcopy(&ahc->scb_data->sense[scb->hscb->tag],
+                     &xs->sense, scb->sg_list->len);
+               xs->error = XS_SENSE;
+       }
+       if (scb->flags & SCB_FREEZE_QUEUE) {
+               ahc->devqueue_blocked[target]--;
+               scb->flags &= ~SCB_FREEZE_QUEUE;
+       }
+       
+       requeue = scb->flags & SCB_REQUEUE;
+       ahcfreescb(ahc, scb);
+
+       if (requeue) {
+               /*
+                * Re-insert at the front of the private queue to
+                * preserve order.
+                */
+               int s;
+
+               s = splbio();
+               /* TAILQ_INSERT_HEAD(&ahc->sc_q, xs, adapter_q); */
+               ahc_list_insert_head(ahc, xs);
+               splx(s);
+       } else {
+               xs->flags |= ITSDONE;
+               scsi_done(xs);
        }
-#endif
-       ahc_free_scb(ahc, scb, xs->flags);
-       scsi_done(xs);
 
-#if defined(__NetBSD__) || defined(__OpenBSD__)        /* XXX */
        /*
         * If there are entries in the software queue, try to
         * run the first one.  We should be more or less guaranteed
@@ -2029,9 +3521,30 @@ ahc_done(ahc, scb)
         * NOTE: ahc_scsi_cmd() relies on our calling it with
         * the first entry in the queue.
         */
-       if (ahc->sc_xxxq.lh_first != NULL)
-               (void) ahc_scsi_cmd(ahc->sc_xxxq.lh_first);
-#endif /* __NetBSD__ || __OpenBSD__ */
+       if ((xs = ahc->sc_xxxq.lh_first) != NULL)
+               (void) ahc_scsi_cmd(xs);
+}
+
+/*
+ * Determine the number of SCBs available on the controller
+ */
+int
+ahc_probe_scbs(ahc)
+       struct ahc_softc *ahc;
+{
+       int i;
+
+       for (i = 0; i < AHC_SCB_MAX; i++) {
+               ahc_outb(ahc, SCBPTR, i);
+               ahc_outb(ahc, SCB_CONTROL, i);
+               if (ahc_inb(ahc, SCB_CONTROL) != i)
+                       break;
+               ahc_outb(ahc, SCBPTR, 0);
+               if (ahc_inb(ahc, SCB_CONTROL) != 0)
+                       break;
+       }
+       
+       return (i);
 }
 
 /*
@@ -2039,435 +3552,555 @@ ahc_done(ahc, scb)
  */
 int
 ahc_init(ahc)
-       struct  ahc_data *ahc;
+       struct ahc_softc *ahc;
 {
-       u_int8_t  scsi_conf, sblkctl, i;
-       u_int16_t ultraenable = 0;
        int       max_targ = 15;
+       int       i;
+       int       term;
+       u_int     scsi_conf;
+       u_int     scsiseq_template;
+       u_int     ultraenb;
+       u_int     discenable;
+       u_int     tagenable;
+       size_t    driver_data_size;
+       u_int32_t physaddr;
+       struct scb_data *scb_data = NULL;
+
+#ifdef AHC_PRINT_SRAM
+       printf("Scratch Ram:");
+       for (i = 0x20; i < 0x5f; i++) {
+               if (((i % 8) == 0) && (i != 0)) {
+                       printf ("\n              ");
+               }
+               printf (" 0x%x", ahc_inb(ahc, i));
+       }
+       if ((ahc->features & AHC_MORE_SRAM) != 0) {
+               for (i = 0x70; i < 0x7f; i++) {
+                       if (((i % 8) == 0) && (i != 0)) {
+                               printf ("\n              ");
+                       }
+                       printf (" 0x%x", ahc_inb(ahc, i));
+               }
+       }
+       printf ("\n");
+#endif
+
+       if (ahc->scb_data == NULL) {
+               scb_data = malloc(sizeof (struct scb_data), M_DEVBUF, M_NOWAIT);
+               if (scb_data == NULL) {
+                       printf("%s: cannot malloc scb_data!\n", ahc_name(ahc));
+                       return (ENOMEM);
+               }
+               bzero(scb_data, sizeof(struct scb_data));
+               ahc->scb_data = scb_data;
+       }
        /*
         * Assume we have a board at this stage and it has been reset.
         */
+       if ((ahc->flags & AHC_USEDEFAULTS) != 0)
+               ahc->our_id = ahc->our_id_b = 7;
+       
+       /*
+        * Default to allowing initiator operations.
+        */
+       ahc->flags |= AHC_INITIATORMODE;
+       
+       /*
+        * DMA tag for our command fifos and other data in system memory
+        * the card's sequencer must be able to access.  For initiator
+        * roles, we need to allocate space for the qinfifo, qoutfifo,
+        * and untagged_scb arrays each of which are composed of 256
+        * 1 byte elements.  When providing for the target mode role,
+        * we additionally must provide space for the incoming target
+        * command fifo.
+        */
+       driver_data_size = 3 * 256 * sizeof(u_int8_t);
 
-       /* Handle the SCBPAGING option */
-#ifndef AHC_SCBPAGING_ENABLE
-       ahc->flags &= ~AHC_PAGESCBS;
-#endif
+       if (ahc_createdmamem(ahc, driver_data_size, 
+           &ahc->shared_data_dmamap, (caddr_t *)&ahc->qoutfifo,
+           &ahc->shared_data_busaddr, &ahc->shared_data_seg,
+           &ahc->shared_data_nseg, "shared data") < 0)
+               return (ENOMEM);
 
-       /* Determine channel configuration and who we are on the scsi bus. */
-       switch ( (sblkctl = AHC_INB(ahc, SBLKCTL) & 0x0a) ) {
-           case 0:
-               ahc->our_id = (AHC_INB(ahc, SCSICONF) & HSCSIID);
-               ahc->flags &= ~AHC_CHANNEL_B_PRIMARY;
-               if(ahc->type == AHC_394)
-                       printf("Channel %c, SCSI Id=%d, ", 
-                               ahc->flags & AHC_CHNLB ? 'B' : 'A',
-                               ahc->our_id);
-               else
-                       printf("Single Channel, SCSI Id=%d, ", ahc->our_id);
-               AHC_OUTB(ahc, FLAGS, SINGLE_BUS | (ahc->flags & AHC_PAGESCBS));
-               break;
-           case 2:
-               ahc->our_id = (AHC_INB(ahc, SCSICONF + 1) & HWSCSIID);
-               ahc->flags &= ~AHC_CHANNEL_B_PRIMARY;
-               if(ahc->type == AHC_394)
-                       printf("Wide Channel %c, SCSI Id=%d, ", 
-                               ahc->flags & AHC_CHNLB ? 'B' : 'A',
-                               ahc->our_id);
-               else
-                       printf("Wide Channel, SCSI Id=%d, ", ahc->our_id);
-               ahc->type |= AHC_WIDE;
-               AHC_OUTB(ahc, FLAGS, WIDE_BUS | (ahc->flags & AHC_PAGESCBS));
-               break;
-           case 8:
-               ahc->our_id = (AHC_INB(ahc, SCSICONF) & HSCSIID);
-               ahc->our_id_b = (AHC_INB(ahc, SCSICONF + 1) & HSCSIID);
-               printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, ",
-                       ahc->our_id, ahc->our_id_b);
-               ahc->type |= AHC_TWIN;
-               AHC_OUTB(ahc, FLAGS, TWIN_BUS | (ahc->flags & AHC_PAGESCBS));
-               break;
-           default:
-               printf(" Unsupported adapter type.  Ignoring\n");
-               return(-1);
-       }
+       ahc->init_level++;
 
-       /* Determine the number of SCBs */
+       /* Allocate SCB data now that sc_dmat is initialized */
+       if (ahc->scb_data->maxhscbs == 0)
+               if (ahcinitscbdata(ahc) != 0)
+                       return (ENOMEM);
 
-       {
-               AHC_OUTB(ahc, SCBPTR, 0);
-               AHC_OUTB(ahc, SCB_CONTROL, 0);
-               for(i = 1; i < AHC_SCB_MAX; i++) {
-                       AHC_OUTB(ahc, SCBPTR, i);
-                       AHC_OUTB(ahc, SCB_CONTROL, i);
-                       if(AHC_INB(ahc, SCB_CONTROL) != i)
-                               break;
-                       AHC_OUTB(ahc, SCBPTR, 0);
-                       if(AHC_INB(ahc, SCB_CONTROL) != 0)
-                               break;
-                       /* Clear the control byte. */
-                       AHC_OUTB(ahc, SCBPTR, i);
-                       AHC_OUTB(ahc, SCB_CONTROL, 0);
+       ahc->qinfifo = &ahc->qoutfifo[256];
+       ahc->untagged_scbs = &ahc->qinfifo[256];
+       /* There are no untagged SCBs active yet. */
+       for (i = 0; i < 256; i++)
+               ahc->untagged_scbs[i] = SCB_LIST_NULL;
 
-                       ahc->qcntmask |= i;     /* Update the count mask. */
-               }
+       /* All of our queues are empty */
+       for (i = 0; i < 256; i++)
+               ahc->qoutfifo[i] = SCB_LIST_NULL;
 
-               /* Ensure we clear the 0 SCB's control byte. */
-               AHC_OUTB(ahc, SCBPTR, 0);
-               AHC_OUTB(ahc, SCB_CONTROL, 0);
+       /*
+        * Allocate a tstate to house information for our
+        * initiator presence on the bus as well as the user
+        * data for any target mode initiator.
+        */
+       if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) {
+               printf("%s: unable to allocate tmode_tstate.  "
+                      "Failing attach\n", ahc_name(ahc));
+               return (-1);
+       }
 
-               ahc->qcntmask |= i;
-               ahc->maxhscbs = i;
+       if ((ahc->features & AHC_TWIN) != 0) {
+               if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) {
+                       printf("%s: unable to allocate tmode_tstate.  "
+                              "Failing attach\n", ahc_name(ahc));
+                       return (-1);
+               }
+               printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, primary %c, ",
+                      ahc->our_id, ahc->our_id_b,
+                      ahc->flags & AHC_CHANNEL_B_PRIMARY? 'B': 'A');
+       } else {
+               if ((ahc->features & AHC_WIDE) != 0) {
+                       printf("Wide ");
+               } else {
+                       printf("Single ");
+               }
+               printf("Channel %c, SCSI Id=%d, ", ahc->channel, ahc->our_id);
        }
 
-       if((ahc->maxhscbs < AHC_SCB_MAX) && (ahc->flags & AHC_PAGESCBS))
-               ahc->maxscbs = AHC_SCB_MAX;
-       else {
-               ahc->maxscbs = ahc->maxhscbs;
+       ahc_outb(ahc, SEQ_FLAGS, 0);
+
+       if (ahc->scb_data->maxhscbs < AHC_SCB_MAX) {
+               ahc->flags |= AHC_PAGESCBS;
+               printf("%d/%d SCBs\n", ahc->scb_data->maxhscbs, AHC_SCB_MAX);
+       } else {
                ahc->flags &= ~AHC_PAGESCBS;
+               printf("%d SCBs\n", ahc->scb_data->maxhscbs);
        }
 
-       printf("%d SCBs\n", ahc->maxhscbs);
-
 #ifdef AHC_DEBUG
-       if(ahc_debug & AHC_SHOWMISC) {
-               struct scb      test;
-               printf("%s: hardware scb %ld bytes; kernel scb; "
+       if (ahc_debug & AHC_SHOWMISC) {
+               printf("%s: hardware scb %d bytes; kernel scb %d bytes; "
                       "ahc_dma %d bytes\n",
                        ahc_name(ahc),
-                       (u_long)&(test.next) - (u_long)(&test),
-                       sizeof(test),
+                       sizeof(struct hardware_scb),
+                       sizeof(struct scb),
                        sizeof(struct ahc_dma_seg));
        }
 #endif /* AHC_DEBUG */
 
-       /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/
-       if(ahc->type & AHC_TWIN)
-       {
+       /* Set the SCSI Id,SXFRCTL0,SXFRCTL1, and SIMODE1, for both channels*/
+       if (ahc->features & AHC_TWIN) {
+
                /*
                 * The device is gated to channel B after a chip reset,
                 * so set those values first
                 */
-               AHC_OUTB(ahc, SCSIID, ahc->our_id_b);
-               scsi_conf = AHC_INB(ahc, SCSICONF + 1);
-               AHC_OUTB(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
-                                       | ENSTIMER|ACTNEGEN|STPWEN);
-               AHC_OUTB(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
-               if(ahc->type & AHC_ULTRA)
-                       AHC_OUTB(ahc, SXFRCTL0, DFON|SPIOEN|ULTRAEN);
+               term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0;
+               if ((ahc->features & AHC_ULTRA2) != 0)
+                       ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id_b);
                else
-                       AHC_OUTB(ahc, SXFRCTL0, DFON|SPIOEN);
-
-               if(scsi_conf & RESET_SCSI) {
-                       /* Reset the bus */
-#if (!defined(__NetBSD__) && !defined(__OpenBSD__)) || defined(DEBUG)
-                       if(bootverbose)
-                               printf("%s: Resetting Channel B\n",
-                                      ahc_name(ahc));
-#endif
-                       AHC_OUTB(ahc, SCSISEQ, SCSIRSTO);
-                       DELAY(1000);
-                       AHC_OUTB(ahc, SCSISEQ, 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|ENSTIMER|ACTNEGEN);
+               ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+               ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
 
-                       /* Ensure we don't get a RSTI interrupt from this */
-                       AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI);
-                       AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
-               }
+               if ((scsi_conf & RESET_SCSI) != 0
+                && (ahc->flags & AHC_INITIATORMODE) != 0)
+                       ahc->flags |= AHC_RESET_BUS_B;
 
                /* Select Channel A */
-               AHC_OUTB(ahc, SBLKCTL, 0);
-       }
-       AHC_OUTB(ahc, SCSIID, ahc->our_id);
-       scsi_conf = AHC_INB(ahc, SCSICONF);
-       AHC_OUTB(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
-                               | ENSTIMER|ACTNEGEN|STPWEN);
-       AHC_OUTB(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
-       if(ahc->type & AHC_ULTRA)
-               AHC_OUTB(ahc, SXFRCTL0, DFON|SPIOEN|ULTRAEN);
-       else
-               AHC_OUTB(ahc, SXFRCTL0, DFON|SPIOEN);
-
-       if(scsi_conf & RESET_SCSI) {
-               /* Reset the bus */
-#if (!defined(__NetBSD__) && !defined(__OpenBSD__)) || defined(DEBUG)
-               if(bootverbose)
-                       printf("%s: Resetting Channel A\n", ahc_name(ahc));
-#endif
-
-               AHC_OUTB(ahc, SCSISEQ, SCSIRSTO);
-               DELAY(1000);
-               AHC_OUTB(ahc, SCSISEQ, 0);
-
-               /* Ensure we don't get a RSTI interrupt from this */
-               AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI);
-               AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
+               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
+                               |ENSTIMER|ACTNEGEN);
+       ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+       ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+
+       if ((scsi_conf & RESET_SCSI) != 0
+        && (ahc->flags & AHC_INITIATORMODE) != 0)
+               ahc->flags |= AHC_RESET_BUS_A;
 
        /*
         * Look at the information that board initialization or
-        * the board bios has left us.  In the lower four bits of each
-        * target's scratch space any value other than 0 indicates
-        * that we should initiate synchronous transfers.  If it's zero,
-        * the user or the BIOS has decided to disable synchronous
-        * negotiation to that target so we don't activate the needsdtr
-        * flag.
+        * the board bios has left us.
         */
-       ahc->needsdtr_orig = 0;
-       ahc->needwdtr_orig = 0;
+       ultraenb = 0;   
+       tagenable = ALL_TARGETS_MASK;
 
        /* Grab the disconnection disable table and invert it for our needs */
-       if(ahc->flags & AHC_USEDEFAULTS) {
+       if (ahc->flags & AHC_USEDEFAULTS) {
                printf("%s: Host Adapter Bios disabled.  Using default SCSI "
                        "device parameters\n", ahc_name(ahc));
-               ahc->discenable = 0xff;
+               ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B|
+                             AHC_TERM_ENB_A|AHC_TERM_ENB_B;
+               discenable = ALL_TARGETS_MASK;
+               if ((ahc->features & AHC_ULTRA) != 0)
+                       ultraenb = ALL_TARGETS_MASK;
+       } else {
+               discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8)
+                          | ahc_inb(ahc, DISC_DSB));
+               if ((ahc->features & (AHC_ULTRA|AHC_ULTRA2)) != 0)
+                       ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8)
+                                     | ahc_inb(ahc, ULTRA_ENB);
        }
-       else
-               ahc->discenable = ~((AHC_INB(ahc, DISC_DSB + 1) << 8)
-                                  | AHC_INB(ahc, DISC_DSB));
 
-       if(!(ahc->type & (AHC_WIDE|AHC_TWIN)))
+       if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
                max_targ = 7;
 
-       for(i = 0; i <= max_targ; i++){
-               u_char target_settings;
-               if (ahc->flags & AHC_USEDEFAULTS) {
-                       target_settings = 0; /* 10MHz */
-                       ahc->needsdtr_orig |= (0x01 << i);
-                       ahc->needwdtr_orig |= (0x01 << i);
+       for (i = 0; i <= max_targ; i++) {
+               struct ahc_initiator_tinfo *tinfo;
+               struct tmode_tstate *tstate;
+               u_int our_id;
+               u_int target_id;
+               char channel;
+
+               channel = 'A';
+               our_id = ahc->our_id;
+               target_id = i;
+               if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
+                       channel = 'B';
+                       our_id = ahc->our_id_b;
+                       target_id = i % 8;
                }
-               else {
+               tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
+                                           target_id, &tstate);
+               /* Default to async narrow across the board */
+               bzero(tinfo, sizeof(*tinfo));
+               if (ahc->flags & AHC_USEDEFAULTS) {
+                       if ((ahc->features & AHC_WIDE) != 0)
+                               tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
+
+                       /*
+                        * These will be truncated when we determine the
+                        * connection type we have with the target.
+                        */
+                       tinfo->user.period = ahc_syncrates->period;
+                       tinfo->user.offset = ~0;
+               } else {
+                       u_int scsirate;
+                       u_int16_t mask;
+
                        /* Take the settings leftover in scratch RAM. */
-                       target_settings = AHC_INB(ahc, TARG_SCRATCH + i);
+                       scsirate = ahc_inb(ahc, TARG_SCSIRATE + i);
+                       mask = (0x01 << i);
+                       if ((ahc->features & AHC_ULTRA2) != 0) {
+                               u_int offset;
+                               u_int maxsync;
 
-                       if(target_settings & 0x0f){
-                               ahc->needsdtr_orig |= (0x01 << i);
-                               /*Default to asynchronous transfers(0 offset)*/
-                               target_settings &= 0xf0;
-                       }
-                       if(target_settings & 0x80){
-                               ahc->needwdtr_orig |= (0x01 << i);
-                               /*
-                                * We'll set the Wide flag when we
-                                * are successful with Wide negotiation.
-                                * Turn it off for now so we aren't
-                                * confused.
-                                */
-                               target_settings &= 0x7f;
-                       }
-                       if(ahc->type & AHC_ULTRA) {
-                               /*
-                                * Enable Ultra for any target that
-                                * has a valid ultra syncrate setting.
-                                */
-                               u_char rate = target_settings & 0x70;
-                               if(rate == 0x00 || rate == 0x10 ||
-                                  rate == 0x20 || rate == 0x40) {
-                                       if(rate == 0x40) {
-                                               /* Treat 10MHz specially */
-                                               target_settings &= ~0x70;
-                                       }
-                                       else
-                                               ultraenable |= (0x01 << i);
-                               }
+                               if ((scsirate & SOFS) == 0x0F) {
+                                       /*
+                                        * Haven't negotiated yet,
+                                        * so the format is different.
+                                        */
+                                       scsirate = (scsirate & SXFR) >> 4
+                                                | (ultraenb & mask)
+                                                 ? 0x08 : 0x0
+                                                | (scsirate & WIDEXFER);
+                                       offset = MAX_OFFSET_ULTRA2;
+                               } else
+                                       offset = ahc_inb(ahc, TARG_OFFSET + i);
+                               maxsync = AHC_SYNCRATE_ULTRA2;
+                               if ((ahc->features & AHC_DT) != 0)
+                                       maxsync = AHC_SYNCRATE_DT;
+                               tinfo->user.period =
+                                   ahc_find_period(ahc, scsirate, maxsync);
+                               if (offset == 0)
+                                       tinfo->user.period = 0;
+                               else
+                                       tinfo->user.offset = ~0;
+                       } else if ((scsirate & SOFS) != 0) {
+                               tinfo->user.period = 
+                                   ahc_find_period(ahc, scsirate,
+                                                   (ultraenb & mask)
+                                                  ? AHC_SYNCRATE_ULTRA
+                                                  : AHC_SYNCRATE_FAST);
+                               if (tinfo->user.period != 0)
+                                       tinfo->user.offset = ~0;
                        }
+                       if ((scsirate & WIDEXFER) != 0
+                        && (ahc->features & AHC_WIDE) != 0)
+                               tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
                }
-               AHC_OUTB(ahc, TARG_SCRATCH+i,target_settings);
+               tinfo->goal = tinfo->user; /* force negotiation */
+               tstate->ultraenb = ultraenb;
+               tstate->discenable = discenable;
+               tstate->tagenable = 0; /* Wait until the XPT says its okay */
        }
+       ahc->user_discenable = discenable;
+       ahc->user_tagenable = tagenable;
+
+       /*
+        * 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, SCBID_ADDR, physaddr & 0xFF);
+       ahc_outb(ahc, SCBID_ADDR + 1, (physaddr >> 8) & 0xFF);
+       ahc_outb(ahc, SCBID_ADDR + 2, (physaddr >> 16) & 0xFF);
+       ahc_outb(ahc, SCBID_ADDR + 3, (physaddr >> 24) & 0xFF);
+
+       /* Target mode incomding command fifo */
+       physaddr += 3 * 256 * sizeof(u_int8_t);
+       ahc_outb(ahc, TMODE_CMDADDR, physaddr & 0xFF);
+       ahc_outb(ahc, TMODE_CMDADDR + 1, (physaddr >> 8) & 0xFF);
+       ahc_outb(ahc, TMODE_CMDADDR + 2, (physaddr >> 16) & 0xFF);
+       ahc_outb(ahc, TMODE_CMDADDR + 3, (physaddr >> 24) & 0xFF);
+
        /*
-        * If we are not a WIDE device, forget WDTR.  This
-        * makes the driver work on some cards that don't
-        * leave these fields cleared when the BIOS is not
-        * installed.
+        * 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.
         */
-       if(!(ahc->type & AHC_WIDE))
-               ahc->needwdtr_orig = 0;
-       ahc->needsdtr = ahc->needsdtr_orig;
-       ahc->needwdtr = ahc->needwdtr_orig;
-       ahc->sdtrpending = 0;
-       ahc->wdtrpending = 0;
-       ahc->tagenable = 0;
-       ahc->orderedtag = 0;
-
-       AHC_OUTB(ahc, ULTRA_ENB, ultraenable & 0xff);
-       AHC_OUTB(ahc, ULTRA_ENB + 1, (ultraenable >> 8) & 0xff);
+       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);
 
 #ifdef AHC_DEBUG
-       /* How did we do? */
-       if(ahc_debug & AHC_SHOWMISC)
+       if (ahc_debug & AHC_SHOWMISC)
                printf("NEEDSDTR == 0x%x\nNEEDWDTR == 0x%x\n"
-                       "DISCENABLE == 0x%x\n", ahc->needsdtr, 
-                       ahc->needwdtr, ahc->discenable);
+                      "DISCENABLE == 0x%x\nULTRAENB == 0x%x\n",
+                      ahc->needsdtr_orig, ahc->needwdtr_orig,
+                      discenable, ultraenb);
 #endif
-       /*
-        * Set the number of available SCBs
-        */
-       AHC_OUTB(ahc, SCBCOUNT, ahc->maxhscbs);
 
-       /*
-        * 2's compliment of maximum tag value
-        */
-       i = ahc->maxscbs;
-       AHC_OUTB(ahc, COMP_SCBCOUNT, -i & 0xff);
+       /* Don't have any special messages to send to targets */
+       ahc_outb(ahc, TARGET_MSG_REQUEST, 0);
+       ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0);
 
        /*
-        * QCount mask to deal with broken aic7850s that
-        * sporadically get garbage in the upper bits of
-        * their QCount registers.
+        * Use the built in queue management registers
+        * if they are available.
         */
-       AHC_OUTB(ahc, QCNTMASK, ahc->qcntmask);
+       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 busy targets right now */
-       AHC_OUTB(ahc, ACTIVE_A, 0);
-       AHC_OUTB(ahc, ACTIVE_B, 0);
 
        /* We don't have any waiting selections */
-       AHC_OUTB(ahc, WAITING_SCBH, SCB_LIST_NULL);
+       ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL);
 
        /* Our disconnection list is empty too */
-       AHC_OUTB(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);
+       ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);
 
        /* Message out buffer starts empty */
-       AHC_OUTB(ahc, MSG_LEN, 0x00);
+       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_INITIATORMODE) != 0)
+               scsiseq_template |= ENRSELI;
+       ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template);
 
        /*
         * Load the Sequencer program and Enable the adapter
         * in "fast" mode.
          */
-#if (!defined(__NetBSD__) && !defined(__OpenBSD__)) || defined(DEBUG)
-       if(bootverbose)
+       if (bootverbose)
                printf("%s: Downloading Sequencer Program...",
                       ahc_name(ahc));
-#endif
 
        ahc_loadseq(ahc);
 
-#if (!defined(__NetBSD__) && !defined(__OpenBSD__)) || defined(DEBUG)
-       if(bootverbose)
-               printf("Done\n");
-#endif
-
-       AHC_OUTB(ahc, SEQCTL, FASTMODE);
-
-       unpause_sequencer(ahc, /*unpause_always*/TRUE);
-
-       /*
-        * Note that we are going and return (to probe)
-        */
-       ahc->flags |= AHC_INIT;
+       /* We have to wait until after any system dumps... */
+       shutdownhook_establish(ahc_shutdown, ahc);
        return (0);
 }
 
-static void
-ahcminphys(bp)
-        struct buf *bp;
-{
 /*
- * Even though the card can transfer up to 16megs per command
- * we are limited by the number of segments in the dma segment
- * list that we can hold.  The worst case is that all pages are
- * discontinuous physically, hense the "page per segment" limit
- * enforced here.
+ * Routines to manage a scsi_xfer into the software queue.  
+ * We overload xs->free_list to to ensure we don't run into a queue 
+ * resource shortage, and keep a pointer to the last entry around 
+ * to make insertion O(C).
  */
-        if (bp->b_bcount > ((AHC_NSEG - 1) * PAGE_SIZE)) {
-                bp->b_bcount = ((AHC_NSEG - 1) * PAGE_SIZE);
-        }
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-       minphys(bp);
-#endif
+STATIC INLINE void
+ahc_list_insert_before(ahc, xs, next_xs)
+       struct ahc_softc *ahc;
+       struct scsi_xfer *xs;
+       struct scsi_xfer *next_xs;
+{
+       LIST_INSERT_BEFORE(xs, next_xs, free_list); 
+
 }
 
-#if defined(__NetBSD__)        || defined(__OpenBSD__) /* XXX */
-/*
- * Insert a scsi_xfer into the software queue.  We overload xs->free_list
- * to to ensure we don't run into a queue resource shortage, and keep
- * a pointer to the last entry around to make insertion O(C).
- */
-static void
-ahc_xxx_enqueue(ahc, xs, infront)
-       struct ahc_data *ahc;
+STATIC INLINE void
+ahc_list_insert_head(ahc, xs)
+       struct ahc_softc *ahc;
        struct scsi_xfer *xs;
-       int infront;
 {
+       if (ahc->sc_xxxq.lh_first == NULL)
+               ahc->sc_xxxqlast = xs;
+       LIST_INSERT_HEAD(&ahc->sc_xxxq, xs, free_list);
+       return;
+}
 
-       if (infront || ahc->sc_xxxq.lh_first == NULL) {
-               if (ahc->sc_xxxq.lh_first == NULL)
-                       ahc->sc_xxxqlast = xs;
+STATIC INLINE void
+ahc_list_insert_tail(ahc, xs)
+       struct ahc_softc *ahc;
+       struct scsi_xfer *xs;
+{
+       if (ahc->sc_xxxq.lh_first == NULL){
+               ahc->sc_xxxqlast = xs;
                LIST_INSERT_HEAD(&ahc->sc_xxxq, xs, free_list);
                return;
        }
-
        LIST_INSERT_AFTER(ahc->sc_xxxqlast, xs, free_list);
        ahc->sc_xxxqlast = xs;
 }
 
-/*
- * Pull a scsi_xfer off the front of the software queue.  When we
- * pull the last one off, we need to clear the pointer to the last
- * entry.
- */
-static struct scsi_xfer *
-ahc_xxx_dequeue(ahc)
-       struct ahc_data *ahc;
-{
+STATIC INLINE void
+ahc_list_remove(ahc, xs)
+       struct ahc_softc *ahc;
        struct scsi_xfer *xs;
-
-       xs = ahc->sc_xxxq.lh_first;
+{
+       struct scsi_xfer *lxs;
+       if (xs == ahc->sc_xxxqlast) {
+               lxs = ahc->sc_xxxq.lh_first;
+               while (lxs != NULL) {
+                       if (LIST_NEXT(lxs, free_list) == ahc->sc_xxxqlast) {
+                                ahc->sc_xxxqlast = lxs;
+                               break;
+                       }
+                       lxs = LIST_NEXT(xs, free_list);
+               }
+       }
+       
        LIST_REMOVE(xs, free_list);
-
        if (ahc->sc_xxxq.lh_first == NULL)
                ahc->sc_xxxqlast = NULL;
+}
 
-       return (xs);
+STATIC INLINE struct scsi_xfer *
+ahc_list_next(ahc, xs)
+       struct ahc_softc *ahc;
+       struct scsi_xfer *xs;
+{
+       return(LIST_NEXT(xs, free_list));
 }
-#endif
 
 /*
- * start a scsi operation given the command and
- * the data address, target, and lun all of which
- * are stored in the scsi_xfer struct
+ * Pick the first xs for a non-blocked target.
  */
-static int32_t
+STATIC INLINE struct scsi_xfer *
+ahc_first_xs(struct ahc_softc *ahc)
+{
+       int target;
+       struct scsi_xfer *xs = ahc->sc_xxxq.lh_first;
+
+       if (ahc->queue_blocked)
+               return NULL;
+
+       while (xs != NULL) {
+               target = xs->sc_link->target;
+               if (ahc->devqueue_blocked[target] == 0 &&
+                   ahc_index_busy_tcl(ahc, XS_TCL(ahc, xs), FALSE) ==
+                       SCB_LIST_NULL)
+                       break;
+               xs = LIST_NEXT(xs, free_list);
+       }
+
+       return xs;
+}
+
+STATIC int32_t
 ahc_scsi_cmd(xs)
-        struct scsi_xfer *xs;
+       struct scsi_xfer *xs;
 {
-       struct  scb *scb;
-       struct  ahc_dma_seg *sg;
-       int     seg;            /* scatter gather seg being worked on */
-       unsigned long thiskv, nextkv;
-       physaddr thisphys, nextphys;
-       int     bytes_this_seg, bytes_this_page, datalen, flags;
-       struct  ahc_data *ahc;
-       u_short mask;
-       int     s;
-#if defined(__NetBSD__) || defined(__OpenBSD__)        /* XXX */
-       int     dontqueue = 0, fromqueue = 0;
-#endif
+       struct scsi_xfer *first_xs, *next_xs = NULL;
+       struct ahc_softc *ahc;
+       struct scb *scb;
+       struct hardware_scb *hscb;      
+       struct ahc_initiator_tinfo *tinfo;
+       struct tmode_tstate *tstate;
+       u_int target_id;
+       u_int our_id;
+       int s, tcl;
+       u_int16_t mask;
+       int dontqueue = 0, fromqueue = 0;
+
+       SC_DEBUG(xs->sc_link, SDEV_DB3, ("ahc_scsi_cmd\n"));
+       ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
 
-       ahc = (struct ahc_data *)xs->sc_link->adapter_softc;
-       mask = (0x01 << (xs->sc_link->target
-#if defined(__FreeBSD__)
-                               | ((u_long)xs->sc_link->fordriver & 0x08)));
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-                       | (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0) ));
-#endif
+       /* must protect the queue */
+       s = splbio();
+
+       if (xs == ahc->sc_xxxq.lh_first) {
+               /*
+                * Called from ahc_done. Calling with the first entry in
+                * the queue is really just a way of seeing where we're
+                * called from. Now, find the first eligible SCB to send,
+                * e.g. one which will be accepted immediately.
+                */
+
+               if (ahc->queue_blocked) {
+                       splx(s);
+                       return (TRY_AGAIN_LATER);
+               }
 
-       SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_scsi_cmd\n"));
+               xs = ahc_first_xs(ahc);
+               if (xs == NULL) {
+                       splx(s);
+                       return (TRY_AGAIN_LATER);
+               }
 
-#if defined(__NetBSD__) || (__OpenBSD__)       /* XXX */
-       /* must protect the queue */
-       s = splbio();
+               next_xs = ahc_list_next(ahc, xs);
+               ahc_list_remove(ahc, xs);
+               fromqueue = 1;
+               goto get_scb;
+       }
 
        /*
-        * If we're running the queue from ahc_done(), we're called
-        * with the first entry in the queue as our argument.
-        * Pull it off; if we can't run the job, it will get placed
-        * back at the front.
+        * If no new requests are accepted, just insert into the
+        * private queue to wait for our turn.
         */
-       if (xs == ahc->sc_xxxq.lh_first) {
-               xs = ahc_xxx_dequeue(ahc);
-               fromqueue = 1;
-               goto get_scb;
+       tcl = XS_TCL(ahc, xs);
+
+       if (ahc->queue_blocked ||
+           ahc->devqueue_blocked[xs->sc_link->target] ||
+           ahc_index_busy_tcl(ahc, tcl, FALSE) != SCB_LIST_NULL) {
+               if (dontqueue) {
+                       splx(s);
+                       xs->error = XS_DRIVER_STUFFUP;
+                       return TRY_AGAIN_LATER;
+               }
+               ahc_list_insert_tail(ahc, xs);
+               splx(s);
+               return SUCCESSFULLY_QUEUED;
        }
 
+       first_xs = ahc_first_xs(ahc);
+
        /* determine safety of software queueing */
        dontqueue = xs->flags & SCSI_POLL;
 
@@ -2475,7 +4108,7 @@ ahc_scsi_cmd(xs)
         * Handle situations where there's already entries in the
         * queue.
         */
-       if (ahc->sc_xxxq.lh_first != NULL) {
+       if (first_xs != NULL) {
                /*
                 * If we can't queue, we have to abort, since
                 * we have to preserve order.
@@ -2489,32 +4122,24 @@ ahc_scsi_cmd(xs)
                /*
                 * Swap with the first queue entry.
                 */
-               ahc_xxx_enqueue(ahc, xs, 0);
-               xs = ahc_xxx_dequeue(ahc);
+               ahc_list_insert_tail(ahc, xs);
+               xs = first_xs;
+               next_xs = ahc_list_next(ahc, xs);
+               ahc_list_remove(ahc, xs);
                fromqueue = 1;
+
        }
 
- get_scb:
-#endif /* __NetBSD__ || __OpenBSD__ */
+get_scb:
+
+       target_id = xs->sc_link->target;
+       our_id = SIM_SCSI_ID(ahc, xs->sc_link);
+
        /*
-        * get an scb to use. If the transfer
-        * is from a buf (possibly from interrupt time)
-        * then we can't allow it to sleep
+        * get an scb to use.
         */
-       flags = xs->flags;
-       if (flags & ITSDONE) {
-               printf("%s: Already done?", ahc_name(ahc));
-               xs->flags &= ~ITSDONE;
-       }
-       if (!(flags & INUSE)) {
-               printf("%s: Not in use?", ahc_name(ahc));
-               xs->flags |= INUSE;
-       }
-       if (!(scb = ahc_get_scb(ahc, flags))) {
-#if defined(__NetBSD__) || defined(__OpenBSD__)        /* XXX */
-               /*
-                * If we can't queue, we lose.
-                */
+       if ((scb = ahcgetscb(ahc)) == NULL) {
+
                if (dontqueue) {
                        splx(s);
                        xs->error = XS_DRIVER_STUFFUP;
@@ -2523,182 +4148,189 @@ ahc_scsi_cmd(xs)
 
                /*
                 * If we were pulled off the queue, put ourselves
-                * back in the front, otherwise tack ourselves onto
-                * the end.
+                * back to where we came from, otherwise tack ourselves
+                * onto the end.
                 */
-               ahc_xxx_enqueue(ahc, xs, fromqueue);
+               if (fromqueue && next_xs != NULL)
+                       ahc_list_insert_before(ahc, xs, next_xs);
+               else
+                       ahc_list_insert_tail(ahc, xs);
 
                splx(s);
                return (SUCCESSFULLY_QUEUED);
-#else
-               xs->error = XS_DRIVER_STUFFUP;
-               return (TRY_AGAIN_LATER);
-#endif /* __NetBSD__ || __OpenBSD__ */
        }
 
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-       /* we're done playing with the queue */
-       splx(s);
-#endif
+       tcl = XS_TCL(ahc, xs);
 
-       SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb));
+#ifdef DIAGNOSTIC
+       if (ahc_index_busy_tcl(ahc, tcl, FALSE) != SCB_LIST_NULL)
+               panic("ahc: queuing for busy target");
+#endif
+       
        scb->xs = xs;
-       if (flags & SCSI_RESET) {
-               scb->flags |= SCB_DEVICE_RESET|SCB_IMMED;
-               scb->control |= MK_MESSAGE;
-       }
+       hscb = scb->hscb;
+       hscb->tcl = tcl;
+
+       ahc_busy_tcl(ahc, scb);
+
+       splx(s);
        /*
         * Put all the arguments for the xfer in the scb
         */
 
-       if(ahc->tagenable & mask) {
-               scb->control |= TAG_ENB;
-               if(ahc->orderedtag & mask) {
-                       printf("Ordered Tag sent\n");
-                       scb->control |= 0x02;
-                       ahc->orderedtag &= ~mask;
-               }
+       mask = SCB_TARGET_MASK(scb);
+       tinfo = ahc_fetch_transinfo(ahc, SIM_CHANNEL(ahc, xs->sc_link), our_id,
+                                   target_id, &tstate);
+       if (ahc->inited_targets[target_id] == 0) {
+               struct ahc_devinfo devinfo;
+
+               s = splbio();
+               ahc_compile_devinfo(&devinfo, our_id, target_id,
+                   xs->sc_link->lun, SIM_CHANNEL(ahc, xs->sc_link),
+                   ROLE_INITIATOR);
+               ahc_update_target_msg_request(ahc, &devinfo, tinfo, TRUE,
+                   FALSE);
+               ahc->inited_targets[target_id] = 1;
+               splx(s);
        }
-       if(ahc->discenable & mask)
-               scb->control |= DISCENB;
-       if((ahc->needwdtr & mask) && !(ahc->wdtrpending & mask))
-       {
-               scb->control |= MK_MESSAGE;
-               scb->flags |= SCB_MSGOUT_WDTR;
-               ahc->wdtrpending |= mask;
+
+       hscb->scsirate = tinfo->scsirate;
+       hscb->scsioffset = tinfo->current.offset;
+       if ((tstate->ultraenb & mask) != 0)
+               hscb->control |= ULTRAENB;
+               
+       if ((tstate->discenable & mask) != 0)
+               hscb->control |= DISCENB;
+
+       if (xs->flags & SCSI_RESET) {
+               hscb->cmdpointer = NULL;
+               scb->flags |= SCB_DEVICE_RESET;
+               hscb->control |= MK_MESSAGE;
+               return ahc_execute_scb(scb, NULL, 0);
        }
-       else if((ahc->needsdtr & mask) && !(ahc->sdtrpending & mask))
-       {
-               scb->control |= MK_MESSAGE;
-               scb->flags |= SCB_MSGOUT_SDTR;
-               ahc->sdtrpending |= mask;
-       }
-       scb->tcl = ((xs->sc_link->target << 4) & 0xF0) |
-#if defined(__FreeBSD__)
-                                 ((u_long)xs->sc_link->fordriver & 0x08) |
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-                                 (IS_SCSIBUS_B(ahc,xs->sc_link)? SELBUSB : 0)|
-#endif
-                                 (xs->sc_link->lun & 0x07);
-       scb->cmdlen = xs->cmdlen;
-       scb->cmdpointer = KVTOPHYS(xs->cmd);
-       xs->resid = 0;
-       xs->status = 0;
-       if (xs->datalen) {      /* should use S/G only if not zero length */
-               scb->SG_list_pointer = KVTOPHYS(scb->ahc_dma);
-               sg = scb->ahc_dma;
-               seg = 0;
-               /*
-                * Set up the scatter gather block
-                */
-               SC_DEBUG(xs->sc_link, SDEV_DB4,
-                        ("%ld @%p:- ", xs->datalen, xs->data));
-               datalen = xs->datalen;
-               thiskv = (unsigned long) xs->data;
-               thisphys = KVTOPHYS(thiskv);
 
-               while ((datalen) && (seg < AHC_NSEG)) {
-                       bytes_this_seg = 0;
+       return ahc_setup_data(ahc, xs, scb);
+}
 
-                       /* put in the base address */
-                       sg->addr = thisphys;
+STATIC int
+ahc_execute_scb(arg, dm_segs, nsegments)
+       void *arg;
+       bus_dma_segment_t *dm_segs;
+       int nsegments;
+{
+       struct   scb *scb;
+       struct scsi_xfer *xs;
+       struct   ahc_softc *ahc;
+       int      s;
 
-                       SC_DEBUGN(xs->sc_link, SDEV_DB4, ("0x%lx", thisphys));
+       scb = (struct scb *)arg;
+       xs = scb->xs;
+       ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;
 
-                       /* do it at least once */
-                       nextphys = thisphys;
-                       while ((datalen) && (thisphys == nextphys)) {
-                               /*
-                                * This page is contiguous (physically)
-                                * with the the last, just extend the
-                                * length
-                                */
-                               /* how far to the end of the page */
-                               nextphys = (thisphys & (~(PAGE_SIZE- 1)))
-                                          + PAGE_SIZE;
-                               bytes_this_page = nextphys - thisphys;
-                               /**** or the data ****/
-                               bytes_this_page = min(bytes_this_page, datalen);
-                               bytes_this_seg += bytes_this_page;
-                               datalen -= bytes_this_page;
-
-                               /* get more ready for the next page */
-                               nextkv = thiskv;
-                               nextkv &= ~((unsigned long) PAGE_SIZE - 1);
-                               nextkv += PAGE_SIZE;
-                               if (datalen)
-                                       thisphys = KVTOPHYS(nextkv);
-                               thiskv = nextkv;
-                       }
-                       /*
-                        * next page isn't contiguous, finish the seg
-                        */
-                       SC_DEBUGN(xs->sc_link, SDEV_DB4,
-                                       ("(0x%x)", bytes_this_seg));
-                       sg->len = bytes_this_seg;
-                       sg++;
-                       seg++;
-               }
-               scb->SG_segment_count = seg;
+
+       if (nsegments != 0) {
+               struct    ahc_dma_seg *sg;
+               bus_dma_segment_t *end_seg;
+               bus_dmasync_op_t op;
+
+               end_seg = dm_segs + nsegments;
 
                /* Copy the first SG into the data pointer area */
-               scb->data = scb->ahc_dma->addr;
-               scb->datalen = scb->ahc_dma->len;
-               SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n"));
-               if (datalen) { 
-                       /* there's still data, must have run out of segs! */
-                       printf("%s: ahc_scsi_cmd: more than %d DMA segs\n",
-                               ahc_name(ahc), AHC_NSEG);
-                       xs->error = XS_DRIVER_STUFFUP;
-                       ahc_free_scb(ahc, scb, flags);
-                       return (COMPLETE);
+               scb->hscb->data = dm_segs->ds_addr;
+               scb->hscb->datalen = dm_segs->ds_len;
+
+               /* Copy the segments into our SG list */
+               sg = scb->sg_list;
+               while (dm_segs < end_seg) {
+                       sg->addr = dm_segs->ds_addr;
+                       sg->len = dm_segs->ds_len;
+                       sg++;
+                       dm_segs++;
                }
-#ifdef AHC_BROKEN_CACHE
-               if (ahc_broken_cache)
-                       INVALIDATE_CACHE();
-#endif
+
+               /* Note where to find the SG entries in bus space */
+               scb->hscb->SG_pointer = scb->sg_list_phys;
+               if ((scb->xs->flags & SCSI_DATA_IN) != 0)
+                       op = BUS_DMASYNC_PREREAD;
+               else
+                       op = BUS_DMASYNC_PREWRITE;
+               bus_dmamap_sync(ahc->sc_dmat, scb->dmamap, op);
+       } else {
+               scb->hscb->SG_pointer = 0;
+               scb->hscb->data = 0;
+               scb->hscb->datalen = 0;
        }
-       else {
-               /*
-                * No data xfer, use non S/G values
-                */
-               scb->SG_segment_count = 0;
-               scb->SG_list_pointer = 0;
-               scb->data = 0;
-               scb->datalen = 0;
+       
+       scb->sg_count = scb->hscb->SG_count = nsegments;
+
+       s = splbio();
+
+       /*
+        * Last time we need to check if this SCB needs to
+        * be aborted.
+        */
+       if (xs->flags & ITSDONE) {
+               ahc_index_busy_tcl(ahc, scb->hscb->tcl, TRUE);
+               if (nsegments != 0)
+                       bus_dmamap_unload(ahc->sc_dmat, scb->dmamap);
+               ahcfreescb(ahc, scb);
+               splx(s);
+               return (COMPLETE);
        }
 
-#ifdef AHC_DEBUG
-       if((ahc_debug & AHC_SHOWSCBS) && (xs->sc_link->target == DEBUGTARG))
-               ahc_print_scb(scb);
+#ifdef DIAGNOSTIC
+       if (scb->sg_count > 255)
+               panic("ahc bad sg_count");
 #endif
-       s = splbio();
+               
+       LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pend_links);
 
-       if( scb->position != SCB_LIST_NULL )
-       {
-               /* We already have a valid slot */
-               u_char curscb;
+       scb->flags |= SCB_ACTIVE;
 
+       if (!(xs->flags & SCSI_POLL))
+       timeout(ahc_timeout, (caddr_t)scb, 
+                   (xs->timeout * hz) / 1000);
+
+       if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
+#if 0
+               printf("Continueing Immediate Command %d:%d\n",
+                      xs->sc_link->target,
+                      xs->sc_link->lun);
+#endif
                pause_sequencer(ahc);
-               curscb = AHC_INB(ahc, SCBPTR);
-               AHC_OUTB(ahc, SCBPTR, scb->position);
-               ahc_send_scb(ahc, scb);
-               AHC_OUTB(ahc, SCBPTR, curscb);
-               AHC_OUTB(ahc, QINFIFO, scb->position);
-               unpause_sequencer(ahc, /*unpause_always*/FALSE);
-               scb->flags |= SCB_ACTIVE;
-               if (!(flags & SCSI_NOMASK)) {
-                       timeout(ahc_timeout, (caddr_t)scb,
-                               (xs->timeout * hz) / 1000);
-               }
-               SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
-       }
-       else {
-               scb->flags |= SCB_WAITINGQ;
-               STAILQ_INSERT_TAIL(&ahc->waiting_scbs, scb, links);
-               ahc_run_waiting_queues(ahc);
-       }
-       if (!(flags & SCSI_NOMASK)) {
+               if ((ahc->flags & AHC_PAGESCBS) == 0)
+                       ahc_outb(ahc, SCBPTR, scb->hscb->tag);
+               ahc_outb(ahc, SCB_TAG, scb->hscb->tag);
+               ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP);
+               unpause_sequencer(ahc);
+       } else {
+
+               ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
+
+               bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, 
+                               BUS_DMASYNC_PREWRITE);
+               
+               if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+                       ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+               } else {
+                       pause_sequencer(ahc);
+                       ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+                       unpause_sequencer(ahc);
+               }
+       }
+
+#ifdef AHC_DEBUG
+       if (ahc_debug & AHC_SHOWCMDS) {
+               printf("opcode %d tag %x len %d flags %x control %x fpos %u"
+                   " rate %x\n",
+                   xs->cmdstore.opcode, scb->hscb->tag, scb->hscb->datalen,
+                   scb->flags, scb->hscb->control, ahc->qinfifonext,
+                   scb->hscb->scsirate);
+       }
+#endif
+
+       if (!(xs->flags & SCSI_POLL)) {
                splx(s);
                return (SUCCESSFULLY_QUEUED);
        }
@@ -2713,797 +4345,1398 @@ ahc_scsi_cmd(xs)
                        ahc_timeout(scb);
                        break;
                }
-       } while (!(xs->flags & ITSDONE));  /* a non command complete intr */
-       splx(s); 
+       } while (!(xs->flags & ITSDONE));
+       splx(s);
        return (COMPLETE);
 }
 
+STATIC int
+ahc_poll(ahc, wait)
+       struct   ahc_softc *ahc;
+       int   wait;     /* in msec */
+{
+       while (--wait) {
+               DELAY(1000);
+               if (ahc_inb(ahc, INTSTAT) & INT_PEND)
+                       break;
+       }
 
-/*
- * A scb (and hence an scb entry on the board) is put onto the
- * free list.
- */
-static void
-ahc_free_scb(ahc, scb, flags)
-        struct ahc_data *ahc;
-        int     flags;
-        struct  scb *scb;
+       if (wait == 0) {
+               printf("%s: board is not responding\n", ahc_name(ahc));
+               return (EIO);
+       }
+               
+       ahc_intr((void *)ahc);
+       return (0);
+}
+
+STATIC int
+ahc_setup_data(ahc, xs, scb)
+       struct ahc_softc *ahc;
+       struct scsi_xfer *xs;
+       struct scb *scb;
+{
+       struct hardware_scb *hscb;
+       
+       hscb = scb->hscb;
+       xs->resid = xs->status = 0;
+       
+       hscb->cmdlen = xs->cmdlen;
+       bcopy(xs->cmd, hscb->cmdstore, xs->cmdlen);
+       hscb->cmdpointer = hscb->cmdstore_busaddr;
+
+       /* Only use S/G if there is a transfer */
+       if (xs->datalen) {
+               int error;
+
+               error = bus_dmamap_load(ahc->sc_dmat,
+                           scb->dmamap, xs->data,
+                           xs->datalen, NULL,
+                           (xs->flags & SCSI_NOSLEEP) ?
+                           BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
+               if (error) {
+                       ahc_index_busy_tcl(ahc, hscb->tcl, TRUE);
+                       return (TRY_AGAIN_LATER);       /* XXX fvdl */
+               }
+               error = ahc_execute_scb(scb,
+                   scb->dmamap->dm_segs,
+                   scb->dmamap->dm_nsegs);
+               return error;
+       } else {
+               return ahc_execute_scb(scb, NULL, 0);
+       }
+}
+
+STATIC void
+ahc_freeze_devq(ahc, sc_link)
+       struct ahc_softc *ahc;
+       struct scsi_link *sc_link;
 {
-       struct scb *wscb;
-       unsigned int opri;
+       int     target;
+       char    channel;
+       int     lun;
 
-       opri = splbio();
+       target = sc_link->target;
+       lun = sc_link->lun;
+       channel = SIM_CHANNEL(ahc, sc_link);
+       
+       ahc_search_qinfifo(ahc, target, channel, lun,
+                          /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN,
+                          SCB_REQUEUE, SEARCH_COMPLETE);
+}
 
-       /* Clean up for the next user */
-       scb->flags = SCB_FREE;
-       scb->control = 0;
-       scb->status = 0;
+STATIC void
+ahcallocscbs(ahc)
+       struct ahc_softc *ahc;
+{
+       struct scb_data *scb_data;
+       struct scb *next_scb;
+       struct sg_map_node *sg_map;
+       bus_addr_t physaddr;
+       struct ahc_dma_seg *segs;
+       int newcount;
+       int i;
+       int dma_flags = 0;
 
-       if(scb->position == SCB_LIST_NULL) {
-               STAILQ_INSERT_HEAD(&ahc->page_scbs, scb, links);
-               if(!scb->links.stqe_next && !ahc->free_scbs.stqh_first)
-                       /*
-                        * If there were no SCBs available, wake anybody waiting
-                        * for one to come free.
-                        */
-                       wakeup((caddr_t)&ahc->free_scbs);
+       scb_data = ahc->scb_data;
+       if (scb_data->numscbs >= AHC_SCB_MAX)
+               /* Can't allocate any more */
+               return;
+
+       next_scb = &scb_data->scbarray[scb_data->numscbs];
+
+       sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
+
+       if (sg_map == NULL)
+               return;
+       bzero(sg_map, sizeof(struct sg_map_node));
+       
+       if (ahc_createdmamem(ahc, PAGE_SIZE, &sg_map->sg_dmamap,
+           (caddr_t *)&sg_map->sg_vaddr, &sg_map->sg_physaddr,
+           &sg_map->sg_dmasegs, &sg_map->sg_nseg, "SG space") < 0) {
+               free(sg_map, M_DEVBUF);
+               return;
        }
-       /*
-        * If there are any SCBS on the waiting queue,
-        * assign the slot of this "freed" SCB to the first
-        * one.  We'll run the waiting queues after all command
-        * completes for a particular interrupt are completed
-        * or when we start another command.
-        */
-       else if((wscb = ahc->waiting_scbs.stqh_first) != NULL) {
-               STAILQ_REMOVE_HEAD(&ahc->waiting_scbs, links);
-               wscb->position = scb->position;
-               STAILQ_INSERT_TAIL(&ahc->assigned_scbs, wscb, links);
-               wscb->flags ^= SCB_WAITINGQ|SCB_ASSIGNEDQ;
-
-               /* 
-                * The "freed" SCB will need to be assigned a slot
-                * before being used, so put it in the page_scbs
-                * queue.
+       
+       SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links);
+
+       segs = sg_map->sg_vaddr;
+       physaddr = sg_map->sg_physaddr;
+
+       newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg)));
+
+       for (i = 0; scb_data->numscbs < AHC_SCB_MAX && i < newcount; i++) {
+               int error;
+
+               next_scb->sg_list = segs;
+               /*
+                * The sequencer always starts with the second entry.
+                * The first entry is embedded in the scb.
                 */
-               scb->position = SCB_LIST_NULL;
-               STAILQ_INSERT_HEAD(&ahc->page_scbs, scb, links);
-               if(!scb->links.stqe_next && !ahc->free_scbs.stqh_first)
+               next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg);
+               next_scb->flags = SCB_FREE;
+               
+               /* set up AHA-284x right. */
+               dma_flags = ((ahc->chip & AHC_VL) !=0) ? 
+                       BUS_DMA_NOWAIT|ISABUS_DMA_32BIT :
+                       BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW;
+               
+               error = bus_dmamap_create(ahc->sc_dmat,
+                                AHC_MAXTRANSFER_SIZE, AHC_NSEG, MAXBSIZE, 0,
+                                dma_flags, &next_scb->dmamap);
+               if (error !=0) 
+                       break;
+
+               next_scb->hscb = &scb_data->hscbs[scb_data->numscbs];
+               next_scb->hscb->tag = ahc->scb_data->numscbs;
+               next_scb->hscb->cmdstore_busaddr = 
+                       ahc_hscb_busaddr(ahc, next_scb->hscb->tag) + 
+                       offsetof(struct hardware_scb, cmdstore);        
+               SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, next_scb, links);
+               segs += AHC_NSEG;
+               physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg));
+               next_scb++;
+               ahc->scb_data->numscbs++;
+       }
+}
+
+#ifdef AHC_DUMP_SEQ
+STATIC void
+ahc_dumpseq(ahc)
+       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++) {
+               u_int8_t ins_bytes[4];
+
+               ahc_insb(ahc, SEQRAM, ins_bytes, 4);
+               printf("0x%08x\n", ins_bytes[0] << 24
+                                | ins_bytes[1] << 16
+                                | ins_bytes[2] << 8
+                                | ins_bytes[3]);
+       }
+}
+#endif
+
+STATIC void
+ahc_loadseq(ahc)
+       struct ahc_softc* ahc;
+{
+       struct patch *cur_patch;
+       int i;
+       int downloaded;
+       int skip_addr;
+       u_int8_t download_consts[4];
+
+       /* Setup downloadable constant table */
+#if 0
+       /* No downloaded constants are currently defined. */
+       download_consts[TMODE_NUMCMDS] = ahc->num_targetcmds;
+#endif
+
+       cur_patch = patches;
+       downloaded = 0;
+       skip_addr = 0;
+       ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
+       ahc_outb(ahc, SEQADDR0, 0);
+       ahc_outb(ahc, SEQADDR1, 0);
+
+       for (i = 0; i < sizeof(seqprog)/4; i++) {
+               if (ahc_check_patch(ahc, &cur_patch, i, &skip_addr) == 0) {
                        /*
-                        * If there were no SCBs available, wake anybody waiting
-                        * for one to come free.
+                        * Don't download this instruction as it
+                        * is in a patch that was removed.
                         */
-                       wakeup((caddr_t)&ahc->free_scbs);
+                        continue;
+               }
+               ahc_download_instr(ahc, i, download_consts);
+               downloaded++;
        }
-       else {
-               STAILQ_INSERT_HEAD(&ahc->free_scbs, scb, links);
-               if(!scb->links.stqe_next && !ahc->page_scbs.stqh_first)
-                       /*
-                        * If there were no SCBs available, wake anybody waiting
-                        * for one to come free.
+       ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE);
+       restart_sequencer(ahc);
+
+       if (bootverbose)
+               printf(" %d instructions downloaded\n", downloaded);
+}
+
+STATIC int
+ahc_check_patch(ahc, start_patch, start_instr,skip_addr)
+       struct ahc_softc *ahc;
+       struct patch **start_patch;
+       int start_instr;
+       int *skip_addr;
+{
+       struct  patch *cur_patch;
+       struct  patch *last_patch;
+       int     num_patches;
+
+       num_patches = sizeof(patches)/sizeof(struct patch);
+       last_patch = &patches[num_patches];
+       cur_patch = *start_patch;
+
+       while (cur_patch < last_patch && start_instr == cur_patch->begin) {
+
+               if (cur_patch->patch_func(ahc) == 0) {
+
+                       /* Start rejecting code */
+                       *skip_addr = start_instr + cur_patch->skip_instr;
+                       cur_patch += cur_patch->skip_patch;
+               } else {
+                       /* Accepted this patch.  Advance to the next
+                        * one and wait for our intruction pointer to
+                        * hit this point.
                         */
-                       wakeup((caddr_t)&ahc->free_scbs);
+                       cur_patch++;
+               }
        }
-#ifdef AHC_DEBUG
-       ahc->activescbs--;
-#endif
-       splx(opri);
+
+       *start_patch = cur_patch;
+       if (start_instr < *skip_addr)
+               /* Still skipping */
+               return (0);
+
+       return (1);
 }
 
-/*
- * Get a free scb, either one already assigned to a hardware slot
- * on the adapter or one that will require an SCB to be paged out before
- * use. If there are none, see if we can allocate a new SCB.  Otherwise
- * either return an error or sleep.
- */
-static struct scb *
-ahc_get_scb(ahc, flags)
-        struct ahc_data *ahc;
-        int    flags;
+STATIC void
+ahc_download_instr(ahc, instrptr, dconsts)
+       struct ahc_softc *ahc;
+       int instrptr;
+       u_int8_t *dconsts;
 {
-       unsigned opri;
-       struct scb *scbp;
+       union   ins_formats instr;
+       struct  ins_format1 *fmt1_ins;
+       struct  ins_format3 *fmt3_ins;
+       u_int   opcode;
+
+       /* Structure copy */
+       instr = *(union ins_formats*)&seqprog[instrptr * 4];
+
+       fmt1_ins = &instr.format1;
+       fmt3_ins = NULL;
+
+       /* Pull the opcode */
+       opcode = instr.format1.opcode;
+       switch (opcode) {
+       case AIC_OP_JMP:
+       case AIC_OP_JC:
+       case AIC_OP_JNC:
+       case AIC_OP_CALL:
+       case AIC_OP_JNE:
+       case AIC_OP_JNZ:
+       case AIC_OP_JE:
+       case AIC_OP_JZ:
+       {
+               struct patch *cur_patch;
+               int address_offset;
+               u_int address;
+               int skip_addr;
+               int i;
 
-       opri = splbio();
-       /*
-        * If we can and have to, sleep waiting for one to come free
-        * but only if we can't allocate a new one.
-        */
-       while (1) {
-               if((scbp = ahc->free_scbs.stqh_first)) {
-                       STAILQ_REMOVE_HEAD(&ahc->free_scbs, links);
-               }
-               else if((scbp = ahc->page_scbs.stqh_first)) {
-                       STAILQ_REMOVE_HEAD(&ahc->page_scbs, links);
-               }
-               else if(ahc->numscbs < ahc->maxscbs) {
-                       scbp = (struct scb *) malloc(sizeof(struct scb),
-                               M_TEMP, M_NOWAIT);
-                       if (scbp) {
-                               bzero(scbp, sizeof(struct scb));
-                               scbp->tag = ahc->numscbs;
-                               if( ahc->numscbs < ahc->maxhscbs )
-                                       scbp->position = ahc->numscbs;
-                               else
-                                       scbp->position = SCB_LIST_NULL;
-                               ahc->numscbs++;
-                               /*
-                                * Place in the scbarray
-                                * Never is removed.
-                                */
-                               ahc->scbarray[scbp->tag] = scbp;
-                       }
-                       else {
-                               printf("%s: Can't malloc SCB\n",
-                                      ahc_name(ahc));
+               fmt3_ins = &instr.format3;
+               address_offset = 0;
+               address = fmt3_ins->address;
+               cur_patch = patches;
+               skip_addr = 0;
+
+               for (i = 0; i < address;) {
+
+                       ahc_check_patch(ahc, &cur_patch, i, &skip_addr);
+
+                       if (skip_addr > i) {
+                               int end_addr;
+
+                               end_addr = MIN(address, skip_addr);
+                               address_offset += end_addr - i;
+                               i = skip_addr;
+                       } else {
+                               i++;
                        }
                }
-               else {
-                       if (!(flags & SCSI_NOSLEEP)) {
-                               tsleep((caddr_t)&ahc->free_scbs, PRIBIO,
-                                       "ahcscb", 0);
-                               continue;
+               address -= address_offset;
+               fmt3_ins->address = address;
+               /* FALLTHROUGH */
+       }
+       case AIC_OP_OR:
+       case AIC_OP_AND:
+       case AIC_OP_XOR:
+       case AIC_OP_ADD:
+       case AIC_OP_ADC:
+       case AIC_OP_BMOV:
+               if (fmt1_ins->parity != 0) {
+                       fmt1_ins->immediate = dconsts[fmt1_ins->immediate];
+               }
+               fmt1_ins->parity = 0;
+               /* FALLTHROUGH */
+       case AIC_OP_ROL:
+               if ((ahc->features & AHC_ULTRA2) != 0) {
+                       int i, count;
+
+                       /* Calculate odd parity for the instruction */
+                       for (i = 0, count = 0; i < 31; i++) {
+                               u_int32_t mask;
+
+                               mask = 0x01 << i;
+                               if ((instr.integer & mask) != 0)
+                                       count++;
+                       }
+                       if ((count & 0x01) == 0)
+                               instr.format1.parity = 1;
+               } else {
+                       /* Compress the instruction for older sequencers */
+                       if (fmt3_ins != NULL) {
+                               instr.integer =
+                                       fmt3_ins->immediate
+                                     | (fmt3_ins->source << 8)
+                                     | (fmt3_ins->address << 16)
+                                     | (fmt3_ins->opcode << 25);
+                       } else {
+                               instr.integer =
+                                       fmt1_ins->immediate
+                                     | (fmt1_ins->source << 8)
+                                     | (fmt1_ins->destination << 16)
+                                     | (fmt1_ins->ret << 24)
+                                     | (fmt1_ins->opcode << 25);
                        }
                }
+               ahc_outsb(ahc, SEQRAM, instr.bytes, 4);
+               break;
+       default:
+               panic("Unknown opcode encountered in seq program");
                break;
        }
-
-#ifdef AHC_DEBUG
-       if (scbp) {
-               ahc->activescbs++;
-               if((ahc_debug & AHC_SHOWSCBCNT)
-                 && (ahc->activescbs == ahc->maxhscbs))
-                       printf("%s: Max SCBs active\n", ahc_name(ahc));
-       }
-#endif
-
-       splx(opri);
-
-       return (scbp);
 }
 
-static void ahc_loadseq(ahc)
-       struct ahc_data *ahc;
+STATIC void
+ahc_set_recoveryscb(ahc, scb)
+       struct ahc_softc *ahc;
+       struct scb *scb;
 {
-        static u_char seqprog[] = {
-#if defined(__FreeBSD__)
-#               include "aic7xxx_seq.h"
-#endif
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-#              include <dev/microcode/aic7xxx/aic7xxx_seq.h>
-#endif
-       };
 
-       AHC_OUTB(ahc, SEQCTL, PERRORDIS|SEQRESET|LOADRAM);
+       if ((scb->flags & SCB_RECOVERY_SCB) == 0) {
+               struct scb *scbp;
 
-       AHC_OUTSB(ahc, SEQRAM, seqprog, sizeof(seqprog));
+               scb->flags |= SCB_RECOVERY_SCB;
 
-       do {
-               AHC_OUTB(ahc, SEQCTL, SEQRESET|FASTMODE);
-       } while((AHC_INB(ahc, SEQADDR0) != 0)
-               || (AHC_INB(ahc, SEQADDR1) != 0));
-}
+               /*
+                * Take all queued, but not sent SCBs out of the equation.
+                * Also ensure that no new CCBs are queued to us while we
+                * try to fix this problem.
+                */
+               ahc->queue_blocked = 1;
 
-/*
- * Function to poll for command completion when
- * interrupts are disabled (crash dumps)
- */
-static int
-ahc_poll(ahc, wait)
-       struct  ahc_data *ahc;
-       int     wait; /* in msec */
-{
-       while (--wait) {
-               DELAY(1000);
-               if (AHC_INB(ahc, INTSTAT) & INT_PEND)
-                       break;
-       } if (wait == 0) {
-               printf("%s: board is not responding\n", ahc_name(ahc));
-               return (EIO);
+               /*
+                * Go through all of our pending SCBs and remove
+                * any scheduled timeouts for them.  We will reschedule
+                * them after we've successfully fixed this problem.
+                */
+               scbp = ahc->pending_scbs.lh_first;
+               while (scbp != NULL) {
+                       untimeout(ahc_timeout, scbp);
+                       scbp = scbp->pend_links.le_next;
+               }
        }
-       ahc_intr((void *)ahc);
-       return (0);
 }
 
-static void
-ahc_timeout(arg)
-       void    *arg;
+STATIC void
+ahc_timeout(void *arg)
 {
-       struct  scb *scb = (struct scb *)arg;
-       struct  ahc_data *ahc;
+       struct  scb *scb;
+       struct  ahc_softc *ahc;
        int     s, found;
-       u_char  bus_state;
+       u_int   last_phase;
+       int     target;
+       int     lun;
+       int     i;
        char    channel;
 
+       scb = (struct scb *)arg; 
+       ahc = (struct ahc_softc *)scb->xs->sc_link->adapter_softc;
+
        s = splbio();
 
-       if (!(scb->flags & SCB_ACTIVE)) {
+       /*
+        * Ensure that the card doesn't do anything
+        * behind our back.  Also make sure that we
+        * didn't "just" miss an interrupt that would
+        * affect this timeout.
+        */
+       do {
+               ahc_intr(ahc);
+               pause_sequencer(ahc);
+       } while (ahc_inb(ahc, INTSTAT) & INT_PEND);
+
+       if ((scb->flags & SCB_ACTIVE) == 0) {
                /* Previous timeout took care of me already */
+               printf("Timedout SCB handled by another timeout\n");
+               unpause_sequencer(ahc);
                splx(s);
-               return;
-       }
-
-       ahc = (struct ahc_data *)scb->xs->sc_link->adapter_softc;
-
-       if (ahc->in_timeout) {
-               /*
-                * Some other SCB has started a recovery operation
-                * and is still working on cleaning things up.
-                */
-               if (scb->flags & SCB_TIMEDOUT) {
-                       /*
-                        * This SCB has been here before and is not the
-                        * recovery SCB. Cut our losses and panic.  Its
-                        * better to do this than trash a filesystem.
-                        */
-                       panic("%s: Timed-out command times out "
-                               "again\n", ahc_name(ahc));
-               }
-               else if (!(scb->flags & SCB_ABORTED))
-               {
-                       /*
-                        * This is not the SCB that started this timeout
-                        * processing.  Give this scb another lifetime so
-                        * that it can continue once we deal with the
-                        * timeout.
-                        */
-                       scb->flags |= SCB_TIMEDOUT;
-                       timeout(ahc_timeout, (caddr_t)scb, 
-                               (scb->xs->timeout * hz) / 1000);
-                       splx(s);
-                       return;
-               }
+               return;
        }
-       ahc->in_timeout = TRUE;
 
-       /*      
-        * Ensure that the card doesn't do anything
-        * behind our back.
-        */
-       pause_sequencer(ahc);
+       target = SCB_TARGET(scb);
+       channel = SCB_CHANNEL(scb);
+       lun = SCB_LUN(scb);
 
        sc_print_addr(scb->xs->sc_link);
-       printf("timed out ");
+       printf("SCB 0x%x - timed out ", scb->hscb->tag);
        /*
         * Take a snapshot of the bus state and print out
         * some information so we can track down driver bugs.
         */
-       bus_state = AHC_INB(ahc, LASTPHASE);
+       last_phase = ahc_inb(ahc, LASTPHASE);
 
-       switch(bus_state & PHASE_MASK)
-       {
-               case P_DATAOUT:
-                       printf("in dataout phase");
-                       break;
-               case P_DATAIN:
-                       printf("in datain phase");
-                       break;
-               case P_COMMAND:
-                       printf("in command phase");
-                       break;
-               case P_MESGOUT:
-                       printf("in message out phase");
-                       break;
-               case P_STATUS:
-                       printf("in status phase");
-                       break;
-               case P_MESGIN:
-                       printf("in message in phase");
-                       break;
-               default:
-                       printf("while idle, LASTPHASE == 0x%x",
-                               bus_state);
-                       /* 
-                        * We aren't in a valid phase, so assume we're
-                        * idle.
-                        */
-                       bus_state = 0;
+       for (i = 0; i < num_phases; i++) {
+               if (last_phase == phase_table[i].phase)
                        break;
        }
-
-       printf(", SCSISIGI == 0x%x\n", AHC_INB(ahc, SCSISIGI));
-
-       /* Decide our course of action */
-
-       if(scb->flags & SCB_ABORTED)
-       {
+       printf("%s", phase_table[i].phasemsg);
+  
+       printf(", SEQADDR == 0x%x\n",
+              ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
+#if 0
+       printf("SSTAT1 == 0x%x\n", ahc_inb(ahc, SSTAT1));
+       printf("SSTAT3 == 0x%x\n", ahc_inb(ahc, SSTAT3));
+       printf("SCSIPHASE == 0x%x\n", ahc_inb(ahc, SCSIPHASE));
+       printf("SCSIRATE == 0x%x\n", ahc_inb(ahc, SCSIRATE));
+       printf("SCSIOFFSET == 0x%x\n", ahc_inb(ahc, SCSIOFFSET));
+       printf("SEQ_FLAGS == 0x%x\n", ahc_inb(ahc, SEQ_FLAGS));
+       printf("SCB_DATAPTR == 0x%x\n", ahc_inb(ahc, SCB_DATAPTR)
+                                     | ahc_inb(ahc, SCB_DATAPTR + 1) << 8
+                                     | ahc_inb(ahc, SCB_DATAPTR + 2) << 16
+                                     | ahc_inb(ahc, SCB_DATAPTR + 3) << 24);
+       printf("SCB_DATACNT == 0x%x\n", ahc_inb(ahc, SCB_DATACNT)
+                                     | ahc_inb(ahc, SCB_DATACNT + 1) << 8
+                                     | ahc_inb(ahc, SCB_DATACNT + 2) << 16);
+       printf("SCB_SGCOUNT == 0x%x\n", ahc_inb(ahc, SCB_SGCOUNT));
+       printf("CCSCBCTL == 0x%x\n", ahc_inb(ahc, CCSCBCTL));
+       printf("CCSCBCNT == 0x%x\n", ahc_inb(ahc, CCSCBCNT));
+       printf("DFCNTRL == 0x%x\n", ahc_inb(ahc, DFCNTRL));
+       printf("DFSTATUS == 0x%x\n", ahc_inb(ahc, DFSTATUS));
+       printf("CCHCNT == 0x%x\n", ahc_inb(ahc, CCHCNT));
+       if (scb->sg_count > 0) {
+               for (i = 0; i < scb->sg_count; i++) {
+                       printf("sg[%d] - Addr 0x%x : Length %d\n",
+                              i,
+                              scb->sg_list[i].addr,
+                              scb->sg_list[i].len);
+               }
+       }
+#endif
+       if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) {
                /*
                 * Been down this road before.
                 * Do a full bus reset.
                 */
-               char channel = (scb->tcl & SELBUSB)
-                          ? 'B': 'A';  
-               found = ahc_reset_channel(ahc, channel, scb->tag,
-                                         XS_TIMEOUT, /*Initiate Reset*/TRUE);
-               printf("%s: Issued Channel %c Bus Reset #1. "
+bus_reset:
+               ahcsetccbstatus(scb->xs, XS_TIMEOUT);
+               found = ahc_reset_channel(ahc, channel, /*Initiate Reset*/TRUE);
+               printf("%s: Issued Channel %c Bus Reset. "
                       "%d SCBs aborted\n", ahc_name(ahc), channel, found);
-               ahc->in_timeout = FALSE;
-       }
-       else if(scb->control & TAG_ENB) {
-               /*
-                * We could be starving this command
-                * try sending an ordered tag command
-                * to the target we come from.
-                */
-               scb->flags |= SCB_ABORTED|SCB_SENTORDEREDTAG;
-               ahc->orderedtag |= 0xFF;
-               timeout(ahc_timeout, (caddr_t)scb, (5 * hz));
-               unpause_sequencer(ahc, /*unpause_always*/FALSE);
-               printf("Ordered Tag queued\n");
-               goto done;
-       }
-       else {
+       } else {
                /*
-                * Send a Bus Device Reset Message:
-                * The target that is holding up the bus may not
+                * If we are a target, transition to bus free and report
+                * the timeout.
+                * 
+                * The target/initiator that is holding up the bus may not
                 * be the same as the one that triggered this timeout
                 * (different commands have different timeout lengths).
-                * It is also impossible to get a message to a target
-                * if we are in a "frozen" data transfer phase.  Our
-                * strategy here is to queue a bus device reset message
-                * to the timed out target if it is disconnected.
-                * Otherwise, if we have an active target we stuff the
-                * message buffer with a bus device reset message and
-                * assert ATN in the hopes that the target will let go
-                * of the bus and finally disconnect.  If this fails,
-                * we'll get another timeout 2 seconds later which will
-                * cause a bus reset.
+                * If the bus is idle and we are actiing as the initiator
+                * for this request, queue a BDR message to the timed out
+                * target.  Otherwise, if the timed out transaction is
+                * active:
+                *   Initiator transaction:
+                *      Stuff the message buffer with a BDR message and assert
+                *      ATN in the hopes that the target will let go of the bus
+                *      and go to the mesgout phase.  If this fails, we'll
+                *      get another timeout 2 seconds later which will attempt
+                *      a bus reset.
                 *
-                * XXX If the SCB is paged out, we simply reset the
-                *     bus.  We should probably queue a new command
-                *     instead.
+                *   Target transaction:
+                *      Transition to BUS FREE and report the error.
+                *      It's good to be the target!
                 */
+               u_int active_scb_index;
 
-               /* Test to see if scb is disconnected */
-               if( !(scb->flags & SCB_PAGED_OUT ) ){
-                       u_char active_scb;
-                       struct scb *active_scbp;
+               active_scb_index = ahc_inb(ahc, SCB_TAG);
 
-                       active_scb = AHC_INB(ahc, SCBPTR);
-                       active_scbp = ahc->scbarray[AHC_INB(ahc, SCB_TAG)];
-                       AHC_OUTB(ahc, SCBPTR, scb->position);
+               if (last_phase != P_BUSFREE 
+                 && (active_scb_index < ahc->scb_data->numscbs)) {
+                       struct scb *active_scb;
+
+                       /*
+                        * If the active SCB is not from our device,
+                        * assume that another device is hogging the bus
+                        * and wait for it's timeout to expire before
+                        * taking additional action.
+                        */ 
+                       active_scb = &ahc->scb_data->scbarray[active_scb_index];
+                       if (active_scb->hscb->tcl != scb->hscb->tcl) {
+                               u_int   newtimeout;
 
-                       if(AHC_INB(ahc, SCB_CONTROL) & DISCONNECTED) {
-                               if(ahc->flags & AHC_PAGESCBS) {
-                                       /*
-                                        * Pull this SCB out of the 
-                                        * disconnected list.
-                                        */
-                                       u_char prev = AHC_INB(ahc, SCB_PREV);
-                                       u_char next = AHC_INB(ahc, SCB_NEXT);
-                                       if(prev == SCB_LIST_NULL) {
-                                               /* At the head */
-                                               AHC_OUTB(ahc, DISCONNECTED_SCBH,
-                                                    next );
-                                       }
-                                       else {
-                                               AHC_OUTB(ahc, SCBPTR, prev);
-                                               AHC_OUTB(ahc, SCB_NEXT, next);
-                                               if(next != SCB_LIST_NULL) {
-                                                       AHC_OUTB(ahc, SCBPTR,
-                                                            next);
-                                                       AHC_OUTB(ahc, SCB_PREV,
-                                                            prev);
-                                               }
-                                               AHC_OUTB(ahc, SCBPTR,
-                                                    scb->position);
-                                       }
-                               }
-                               scb->flags |= SCB_DEVICE_RESET|SCB_ABORTED;
-                               scb->control &= DISCENB;
-                               scb->control |= MK_MESSAGE;
-                               scb->cmdlen = 0;
-                               scb->SG_segment_count = 0;
-                               scb->SG_list_pointer = 0;
-                               scb->data = 0;
-                               scb->datalen = 0;
-                               ahc_send_scb(ahc, scb);
-                               ahc_add_waiting_scb(ahc, scb);
-                               timeout(ahc_timeout, (caddr_t)scb, (2 * hz));
                                sc_print_addr(scb->xs->sc_link);
-                               printf("BUS DEVICE RESET message queued.\n");
-                               AHC_OUTB(ahc, SCBPTR, active_scb);
-                               unpause_sequencer(ahc, /*unpause_always*/FALSE);
-                               goto done;
+                               printf("Other SCB Timeout%s",
+                                      (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0
+                                      ? " again\n" : "\n");
+                               scb->flags |= SCB_OTHERTCL_TIMEOUT;
+                               newtimeout = MAX(active_scb->xs->timeout,
+                                                scb->xs->timeout);
+                               timeout(ahc_timeout, scb,
+                                           (newtimeout * hz) / 1000);
+                               splx(s);
+                               return;
+                       } 
+
+                       /* It's us */
+                       if ((scb->hscb->control & TARGET_SCB) != 0) {
+
+                               /*
+                                * Send back any queued up transactions
+                                * and properly record the error condition.
+                                */
+                               ahc_freeze_devq(ahc, scb->xs->sc_link);
+                               ahcsetccbstatus(scb->xs, XS_TIMEOUT);
+                               ahc_freeze_ccb(scb);
+                               ahc_done(ahc, scb);
+
+                               /* Will clear us from the bus */
+                               restart_sequencer(ahc);
+                               return;
+                       } 
+
+                       ahc_set_recoveryscb(ahc, active_scb);
+                       ahc_outb(ahc, MSG_OUT, MSG_BUS_DEV_RESET);
+                       ahc_outb(ahc, SCSISIGO, last_phase|ATNO);
+                       sc_print_addr(active_scb->xs->sc_link);
+                       printf("BDR message in message buffer\n");
+                       active_scb->flags |=  SCB_DEVICE_RESET;
+                           timeout(ahc_timeout, (caddr_t)active_scb, 2 * hz);
+               } else {
+                       int      disconnected;
+
+                       /* XXX Shouldn't panic.  Just punt instead */
+                       if ((scb->hscb->control & TARGET_SCB) != 0)
+                               panic("Timed-out target SCB but bus idle");
+
+                       if (last_phase != P_BUSFREE
+                        && (ahc_inb(ahc, SSTAT0) & TARGET) != 0) {
+                               /* XXX What happened to the SCB? */
+                               /* Hung target selection.  Goto busfree */
+                               printf("%s: Hung target selection\n",
+                                      ahc_name(ahc));
+                               restart_sequencer(ahc);
+                               return;
+                       }
+
+                       if (ahc_search_qinfifo(ahc, target, channel, lun,
+                                              scb->hscb->tag, ROLE_INITIATOR,
+                                              /*status*/0, SEARCH_COUNT) > 0) {
+                               disconnected = FALSE;
+                       } else {
+                               disconnected = TRUE;
                        }
-                       /* Is the active SCB really active? */
-                       else if((active_scbp->flags & SCB_ACTIVE) && bus_state){
-                               AHC_OUTB(ahc, MSG_LEN, 1);
-                               AHC_OUTB(ahc, MSG0, MSG_BUS_DEV_RESET);
-                               AHC_OUTB(ahc, SCSISIGO, bus_state|ATNO);
-                               sc_print_addr(active_scbp->xs->sc_link);
-                               printf("asserted ATN - device reset in "
-                                      "message buffer\n");
-                               active_scbp->flags |=   SCB_DEVICE_RESET
-                                                     | SCB_ABORTED;
-                               if(active_scbp != scb) {
-                                       untimeout(ahc_timeout, 
-                                                 (caddr_t)active_scbp);
-                                       /* Give scb a new lease on life */
-                                       timeout(ahc_timeout, (caddr_t)scb, 
-                                               (scb->xs->timeout * hz) / 1000);
+
+                       if (disconnected) {
+                               u_int active_scb;
+
+                               ahc_set_recoveryscb(ahc, scb);
+                               /*
+                                * Simply set the MK_MESSAGE control bit.
+                                */
+                               scb->hscb->control |= MK_MESSAGE;
+                               scb->flags |= SCB_QUEUED_MSG
+                                          |  SCB_DEVICE_RESET;
+
+                               /*
+                                * Mark the cached copy of this SCB in the
+                                * disconnected list too, so that a reconnect
+                                * at this point causes a BDR or abort.
+                                */
+                               active_scb = ahc_inb(ahc, SCBPTR);
+                               if (ahc_search_disc_list(ahc, target,
+                                                        channel, lun,
+                                                        scb->hscb->tag,
+                                                        /*stop_on_first*/TRUE,
+                                                        /*remove*/FALSE,
+                                                        /*save_state*/FALSE)) {
+                                       u_int scb_control;
+
+                                       scb_control = ahc_inb(ahc, SCB_CONTROL);
+                                       scb_control |= MK_MESSAGE;
+                                       ahc_outb(ahc, SCB_CONTROL, scb_control);
                                }
-                               timeout(ahc_timeout, (caddr_t)active_scbp, 
-                                       (2 * hz));
-                               AHC_OUTB(ahc, SCBPTR, active_scb);
-                               unpause_sequencer(ahc, /*unpause_always*/FALSE);
-                               goto done;
+                               ahc_outb(ahc, SCBPTR, active_scb);
+                               ahc_index_busy_tcl(ahc, scb->hscb->tcl,
+                                                  /*unbusy*/TRUE);
+
+                               /*
+                                * Actually re-queue this SCB in case we can
+                                * select the device before it reconnects.
+                                * Clear out any entries in the QINFIFO first
+                                * so we are the next SCB for this target
+                                * to run.
+                                */
+                               ahc_search_qinfifo(ahc, SCB_TARGET(scb),
+                                                  channel, SCB_LUN(scb),
+                                                  SCB_LIST_NULL,
+                                                  ROLE_INITIATOR,
+                                                  SCB_REQUEUE,
+                                                  SEARCH_COMPLETE);
+                               sc_print_addr(scb->xs->sc_link);
+                               printf("Queuing a BDR SCB\n");
+                               ahc->qinfifo[ahc->qinfifonext++] =
+                                   scb->hscb->tag;
+                               if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+                                       ahc_outb(ahc, HNSCB_QOFF,
+                                                ahc->qinfifonext);
+                               } else {
+                                       ahc_outb(ahc, KERNEL_QINPOS,
+                                                ahc->qinfifonext);
+                               }
+                               timeout(ahc_timeout, (caddr_t)scb, 2 * hz);
+                               unpause_sequencer(ahc);
+                       } else {
+                               /* Go "immediatly" to the bus reset */
+                               /* This shouldn't happen */
+                               ahc_set_recoveryscb(ahc, scb);
+                               sc_print_addr(scb->xs->sc_link);
+                               printf("SCB %d: Immediate reset.  "
+                                       "Flags = 0x%x\n", scb->hscb->tag,
+                                       scb->flags);
+                               goto bus_reset;
                        }
                }
-               /*
-                * No active target or a paged out SCB.
-                * Try resetting the bus.
-                */
-               channel = (scb->tcl & SELBUSB) ? 'B': 'A';      
-               found = ahc_reset_channel(ahc, channel, scb->tag, 
-                                         XS_TIMEOUT,
-                                         /*Initiate Reset*/TRUE);
-               printf("%s: Issued Channel %c Bus Reset #2. "
-                       "%d SCBs aborted\n", ahc_name(ahc), channel,
-                       found);
-               ahc->in_timeout = FALSE;
-       }
-done:
+       }
        splx(s);
 }
 
-
-/*
- * The device at the given target/channel has been reset.  Abort 
- * all active and queued scbs for that target/channel. 
- */
-static int
-ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
-       struct ahc_data *ahc;
+STATIC int
+ahc_search_qinfifo(ahc, target, channel, lun, tag, role, status, action)
+       struct ahc_softc *ahc;
        int target;
        char channel;
-       u_char timedout_scb;
-       u_int32_t xs_error;
+       int lun;
+       u_int tag;
+       role_t role;
+       u_int32_t status;
+       ahc_search_action action;
 {
-        struct scb *scbp;
-       u_char active_scb;
-       int i = 0;
-       int found = 0;
+       struct   scb *scbp;
+       u_int8_t qinpos;
+       u_int8_t qintail;
+       int      found;
 
-       /* restore this when we're done */
-       active_scb = AHC_INB(ahc, SCBPTR);
+       qinpos = ahc_inb(ahc, QINPOS);
+       qintail = ahc->qinfifonext;
+       found = 0;
 
        /*
-        * Search the QINFIFO.
+        * Start with an empty queue.  Entries that are not chosen
+        * for removal will be re-added to the queue as we go.
         */
-       {
-               u_char saved_queue[AHC_SCB_MAX];
-               u_char queued = AHC_INB(ahc, QINCNT) & ahc->qcntmask;
-
-               for (i = 0; i < (queued - found); i++) {
-                       saved_queue[i] = AHC_INB(ahc, QINFIFO);
-                       AHC_OUTB(ahc, SCBPTR, saved_queue[i]);
-                       scbp = ahc->scbarray[AHC_INB(ahc, SCB_TAG)];
-                       if (ahc_match_scb (scbp, target, channel)){
-                               /*
-                                * We found an scb that needs to be aborted.
-                                */
-                               scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
-                               scbp->xs->error |= xs_error;
-                               if(scbp->position != timedout_scb)
-                                       untimeout(ahc_timeout, (caddr_t)scbp);
-                               AHC_OUTB(ahc, SCB_CONTROL, 0);
-                               i--;
-                               found++;
+       ahc->qinfifonext = qinpos;
+       bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, 
+                       BUS_DMASYNC_POSTREAD);
+
+       while (qinpos != qintail) {
+               scbp = &ahc->scb_data->scbarray[ahc->qinfifo[qinpos]];
+               if (ahc_match_scb(scbp, target, channel, lun, tag, role)) {
+                       /*
+                        * We found an scb that needs to be removed.
+                        */
+                       switch (action) {
+                       case SEARCH_COMPLETE:
+                               if (!(scbp->xs->flags & ITSDONE)) {
+                                       scbp->flags |= status;
+                                       scbp->xs->error = XS_NOERROR;
+                               }
+                               ahc_freeze_ccb(scbp);
+                               ahc_done(ahc, scbp);
+                               break;
+                       case SEARCH_COUNT:
+                               ahc->qinfifo[ahc->qinfifonext++] =
+                                   scbp->hscb->tag;
+                               break;
+                       case SEARCH_REMOVE:
+                               break;
                        }
+                       found++;
+               } else {
+                       ahc->qinfifo[ahc->qinfifonext++] = scbp->hscb->tag;
                }
-               /* Now put the saved scbs back. */
-               for (queued = 0; queued < i; queued++) {
-                       AHC_OUTB(ahc, QINFIFO, saved_queue[queued]);
-               }
+               qinpos++;
+       }
+       bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, 
+                       BUS_DMASYNC_PREWRITE);
+       
+       if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+               ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+       } else {
+               ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
        }
 
+       return (found);
+}
+
+/*
+ * Abort all SCBs that match the given description (target/channel/lun/tag),
+ * setting their status to the passed in status if the status has not already
+ * been modified from CAM_REQ_INPROG.  This routine assumes that the sequencer
+ * is paused before it is called.
+ */
+STATIC int
+ahc_abort_scbs(ahc, target, channel, lun, tag, role, status)
+       struct ahc_softc *ahc;
+       int target;
+       char channel;
+       int lun;
+       u_int tag;
+       role_t role;
+       u_int32_t status;
+{
+       struct  scb *scbp;
+       u_int   active_scb;
+       int     i;
+       int     found;
+
+       /* restore this when we're done */
+       active_scb = ahc_inb(ahc, SCBPTR);
+
+       found = ahc_search_qinfifo(ahc, target, channel, lun, SCB_LIST_NULL,
+                                  role, SCB_REQUEUE, SEARCH_COMPLETE);
+
        /*
         * Search waiting for selection list.
         */
        {
-               u_char next, prev;
-
-               next = AHC_INB(ahc, WAITING_SCBH);  /* Start at head of list. */
+               u_int8_t next, prev;
+                /* Start at head of list. */
+               next = ahc_inb(ahc, WAITING_SCBH);
                prev = SCB_LIST_NULL;
 
                while (next != SCB_LIST_NULL) {
-                       AHC_OUTB(ahc, SCBPTR, next);
-                       scbp = ahc->scbarray[AHC_INB(ahc, SCB_TAG)];
-                       /*
-                        * Select the SCB.
-                        */
-                       if (ahc_match_scb(scbp, target, channel)) {
-                               next = ahc_abort_wscb(ahc, scbp, prev,
-                                               timedout_scb, xs_error);
-                               found++;
+                       u_int8_t scb_index;
+
+                       ahc_outb(ahc, SCBPTR, next);
+                       scb_index = ahc_inb(ahc, SCB_TAG);
+                       if (scb_index >= ahc->scb_data->numscbs) {
+                               panic("Waiting List inconsistency. "
+                                     "SCB index == %d, yet numscbs == %d.",
+                                     scb_index, ahc->scb_data->numscbs);
                        }
-                       else {
+                       scbp = &ahc->scb_data->scbarray[scb_index];
+                       if (ahc_match_scb(scbp, target, channel,
+                                         lun, SCB_LIST_NULL, role)) {
+
+                               next = ahc_abort_wscb(ahc, next, prev);
+                       } else {
+                               
                                prev = next;
-                               next = AHC_INB(ahc, SCB_NEXT);
+                               next = ahc_inb(ahc, SCB_NEXT);
                        }
                }
        }
        /*
-        * Go through the entire SCB array now and look for 
-        * commands for this target that are active.  These
-        * are other (most likely tagged) commands that 
-        * were disconnected when the reset occured.
+        * Go through the disconnected list and remove any entries we
+        * have queued for completion, 0'ing their control byte too.
+        * We save the active SCB and restore it ourselves, so there
+        * is no reason for this search to restore it too.
         */
-       for(i = 0; i < ahc->numscbs; i++) {
-               scbp = ahc->scbarray[i];
-               if((scbp->flags & SCB_ACTIVE)
-                 && ahc_match_scb(scbp, target, channel)) {
-                       /* Ensure the target is "free" */
-                       ahc_unbusy_target(ahc, target, channel);
-                       if( !(scbp->flags & SCB_PAGED_OUT) )
-                       {
-                               AHC_OUTB(ahc, SCBPTR, scbp->position);
-                               AHC_OUTB(ahc, SCB_CONTROL, 0);
+       ahc_search_disc_list(ahc, target, channel, lun, tag,
+                            /*stop_on_first*/FALSE, /*remove*/TRUE,
+                            /*save_state*/FALSE);
+
+       /*
+        * Go through the hardware SCB array looking for commands that
+        * were active but not on any list.
+        */
+       for(i = 0; i < ahc->scb_data->maxhscbs; i++) {
+               u_int scbid;
+
+               ahc_outb(ahc, SCBPTR, i);
+               scbid = ahc_inb(ahc, SCB_TAG);
+               scbp = &ahc->scb_data->scbarray[scbid];
+               if (scbid < ahc->scb_data->numscbs && 
+                        ahc_match_scb(scbp, target, channel, lun, tag, role))
+                               ahc_add_curscb_to_free_list(ahc);
+       }
+
+       /*
+        * Go through the pending CCB list and look for
+        * commands for this target that are still active.
+        * These are other tagged commands that were
+        * disconnected when the reset occured.
+        */
+       {
+               struct scb *scb;
+
+               scb = ahc->pending_scbs.lh_first;
+               while (scb != NULL) {
+                       scbp = scb;
+                       scb = scb->pend_links.le_next;
+                       if (ahc_match_scb(scbp, target, channel,
+                                         lun, tag, role)) {
+                               if (!(scbp->xs->flags & ITSDONE))
+                                       ahcsetccbstatus(scbp->xs, status);
+                               ahc_freeze_ccb(scbp);
+                               ahc_done(ahc, scbp);
+                               found++;
                        }
-                       scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
-                       scbp->xs->error |= xs_error;
-                       if(scbp->tag != timedout_scb)
-                               untimeout(ahc_timeout, (caddr_t)scbp);
-                       found++;
                }
-       }                       
-       AHC_OUTB(ahc, SCBPTR, active_scb);
+       }
+       ahc_outb(ahc, SCBPTR, active_scb);
        return found;
 }
 
+STATIC int
+ahc_search_disc_list(ahc, target, channel, lun, tag, stop_on_first, 
+                    remove, save_state)
+       struct ahc_softc *ahc;
+       int target;
+       char channel;
+       int lun;
+       u_int tag;
+       int stop_on_first;
+       int remove;
+       int save_state;
+{
+       struct  scb *scbp;
+       u_int   next;
+       u_int   prev;
+       u_int   count;
+       u_int   active_scb;
+
+       count = 0;
+       next = ahc_inb(ahc, DISCONNECTED_SCBH);
+       prev = SCB_LIST_NULL;
+
+       if (save_state) {
+       /* restore this when we're done */
+       active_scb = ahc_inb(ahc, SCBPTR);
+       } else
+               /* Silence compiler */
+               active_scb = SCB_LIST_NULL;
+
+       while (next != SCB_LIST_NULL) {
+               u_int scb_index;
+
+               ahc_outb(ahc, SCBPTR, next);
+               scb_index = ahc_inb(ahc, SCB_TAG);
+               if (scb_index >= ahc->scb_data->numscbs) {
+                       panic("Disconnected List inconsistency. "
+                             "SCB index == %d, yet numscbs == %d.",
+                             scb_index, ahc->scb_data->numscbs);
+               }
+               scbp = &ahc->scb_data->scbarray[scb_index];
+               if (ahc_match_scb(scbp, target, channel, lun,
+                                 tag, ROLE_INITIATOR)) {
+                       count++;
+                       if (remove) {
+                               next =
+                                   ahc_rem_scb_from_disc_list(ahc, prev, next);
+                       } else {
+                               prev = next;
+                               next = ahc_inb(ahc, SCB_NEXT);
+                       }
+                       if (stop_on_first)
+                               break;
+               } else {
+                       prev = next;
+                       next = ahc_inb(ahc, SCB_NEXT);
+               }
+       }
+       if (save_state)
+       ahc_outb(ahc, SCBPTR, active_scb);
+       return (count);
+}
+
+STATIC u_int
+ahc_rem_scb_from_disc_list(ahc, prev, scbptr)
+       struct ahc_softc *ahc;
+       u_int prev;
+       u_int scbptr;
+{
+       u_int next;
+
+       ahc_outb(ahc, SCBPTR, scbptr);
+       next = ahc_inb(ahc, SCB_NEXT);
+
+       ahc_outb(ahc, SCB_CONTROL, 0);
+
+       ahc_add_curscb_to_free_list(ahc);
+
+       if (prev != SCB_LIST_NULL) {
+               ahc_outb(ahc, SCBPTR, prev);
+               ahc_outb(ahc, SCB_NEXT, next);
+       } else
+               ahc_outb(ahc, DISCONNECTED_SCBH, next);
+
+       return (next);
+}
+
+STATIC void
+ahc_add_curscb_to_free_list(ahc)
+       struct ahc_softc *ahc;
+{
+       /* Invalidate the tag so that ahc_find_scb doesn't think it's active */
+       ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL);
+
+       ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH));
+       ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR));
+}
+
 /*
  * Manipulate the waiting for selection list and return the
  * scb that follows the one that we remove.
  */
-static u_char
-ahc_abort_wscb (ahc, scbp, prev, timedout_scb, xs_error)
-       struct ahc_data *ahc;
-        struct scb *scbp;
-       u_char prev;
-       u_char timedout_scb;
-       u_int32_t xs_error;
+STATIC u_int
+ahc_abort_wscb(ahc, scbpos, prev)
+       struct ahc_softc *ahc;
+       u_int scbpos;
+        u_int prev;
 {       
-       u_char curscbp, next;
-       int target = ((scbp->tcl >> 4) & 0x0f);
-       char channel = (scbp->tcl & SELBUSB) ? 'B' : 'A';
+       u_int curscb, next;
+
        /*
         * Select the SCB we want to abort and
         * pull the next pointer out of it.
         */
-       curscbp = AHC_INB(ahc, SCBPTR);
-       AHC_OUTB(ahc, SCBPTR, scbp->position);
-       next = AHC_INB(ahc, SCB_NEXT);
+       curscb = ahc_inb(ahc, SCBPTR);
+       ahc_outb(ahc, SCBPTR, scbpos);
+       next = ahc_inb(ahc, SCB_NEXT);
 
        /* Clear the necessary fields */
-       AHC_OUTB(ahc, SCB_CONTROL, 0);
-       AHC_OUTB(ahc, SCB_NEXT, SCB_LIST_NULL);
-       ahc_unbusy_target(ahc, target, channel);
+       ahc_outb(ahc, SCB_CONTROL, 0);
+
+       ahc_add_curscb_to_free_list(ahc);
 
        /* update the waiting list */
-       if( prev == SCB_LIST_NULL ) 
+       if (prev == SCB_LIST_NULL) {
                /* First in the list */
-               AHC_OUTB(ahc, WAITING_SCBH, next); 
-       else {
+               ahc_outb(ahc, WAITING_SCBH, next); 
+
+               /*
+                * Ensure we aren't attempting to perform
+                * selection for this entry.
+                */
+               ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
+       } else {
                /*
                 * Select the scb that pointed to us 
                 * and update its next pointer.
                 */
-               AHC_OUTB(ahc, SCBPTR, prev);
-               AHC_OUTB(ahc, SCB_NEXT, next);
+               ahc_outb(ahc, SCBPTR, prev);
+               ahc_outb(ahc, SCB_NEXT, next);
        }
+
        /*
-        * Point us back at the original scb position
-        * and inform the SCSI system that the command
-        * has been aborted.
+        * Point us back at the original scb position.
         */
-       AHC_OUTB(ahc, SCBPTR, curscbp);
-       scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
-       scbp->xs->error |= xs_error;
-       if(scbp->tag != timedout_scb)
-               untimeout(ahc_timeout, (caddr_t)scbp);
+       ahc_outb(ahc, SCBPTR, curscb);
        return next;
 }
 
-static void
-ahc_busy_target(ahc, target, channel)
-       struct ahc_data *ahc;
-       u_char target;
-       char   channel;
+STATIC void
+ahc_clear_intstat(ahc)
+       struct ahc_softc *ahc;
 {
-       u_char active;
-       u_long active_port = ACTIVE_A;
-
-       if(target > 0x07 || channel == 'B') {
-               /* 
-                * targets on the Second channel or
-                * above id 7 store info in byte two 
-                * of HA_ACTIVE
-                */
-               active_port++;
-       }
-       active = AHC_INB(ahc, active_port);
-       active |= (0x01 << (target & 0x07));
-       AHC_OUTB(ahc, active_port, active);
+       /* Clear any interrupt conditions this may have caused */
+       ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO);
+       ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI
+                               |CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG|
+                               CLRREQINIT);
+       ahc_outb(ahc, CLRINT, CLRSCSIINT);
 }
 
-static void
-ahc_unbusy_target(ahc, target, channel)
-       struct ahc_data *ahc;
-       u_char target;
-       char   channel;
+STATIC void
+ahc_reset_current_bus(ahc)
+       struct ahc_softc *ahc;
 {
-       u_char active;
-       u_long active_port = ACTIVE_A;
+       u_int8_t scsiseq;
 
-       if(target > 0x07 || channel == 'B') {
-               /* 
-                * targets on the Second channel or
-                * above id 7 store info in byte two 
-                * of HA_ACTIVE
-                */
-               active_port++;
-       }
-       active = AHC_INB(ahc, active_port);
-       active &= ~(0x01 << (target & 0x07));
-       AHC_OUTB(ahc, active_port, active);
-}
+       ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST);
+       scsiseq = ahc_inb(ahc, SCSISEQ);
+       ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO);
+       DELAY(AHC_BUSRESET_DELAY);
+       /* Turn off the bus reset */
+       ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO);
 
-static void
-ahc_reset_current_bus(ahc)
-       struct ahc_data *ahc;
-{
-       AHC_OUTB(ahc, SCSISEQ, SCSIRSTO);
-       DELAY(1000);
-       AHC_OUTB(ahc, SCSISEQ, 0);
+       ahc_clear_intstat(ahc);
+
+       /* Re-enable reset interrupts */
+       ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENSCSIRST);
 }
 
-static int
-ahc_reset_channel(ahc, channel, timedout_scb, xs_error, initiate_reset)
-       struct ahc_data *ahc;
-       char   channel;
-       u_char timedout_scb;
-       u_int32_t xs_error;
-       u_char initiate_reset;
+STATIC int
+ahc_reset_channel(ahc, channel, initiate_reset)
+       struct ahc_softc *ahc;
+       char channel;
+       int initiate_reset;
 {
-       u_char sblkctl;
-       char cur_channel;
-       u_long offset, offset_max;
-       int found;
+       u_int   initiator, target, max_scsiid;
+       u_int   sblkctl;
+       u_int   our_id;
+       int     found;
+       int     restart_needed;
+       char    cur_channel;
+
+       ahc->pending_device = NULL;
+
+       pause_sequencer(ahc);
 
        /*
-        * Clean up all the state information for the
-        * pending transactions on this bus.
+        * Run our command complete fifos to ensure that we perform
+        * completion processing on any commands that 'completed'
+        * before the reset occurred.
         */
-       found = ahc_reset_device(ahc, ALL_TARGETS, channel, 
-                                timedout_scb, xs_error);
-       if(channel == 'B'){
-               ahc->needsdtr |= (ahc->needsdtr_orig & 0xff00);
-               ahc->sdtrpending &= 0x00ff;
-               AHC_OUTB(ahc, ACTIVE_B, 0);
-               offset = TARG_SCRATCH + 8;
-               offset_max = TARG_SCRATCH + 16;
-       }
-       else if (ahc->type & AHC_WIDE){
-               ahc->needsdtr = ahc->needsdtr_orig;
-               ahc->needwdtr = ahc->needwdtr_orig;
-               ahc->sdtrpending = 0;
-               ahc->wdtrpending = 0;
-               AHC_OUTB(ahc, ACTIVE_A, 0);
-               AHC_OUTB(ahc, ACTIVE_B, 0);
-               offset = TARG_SCRATCH;
-               offset_max = TARG_SCRATCH + 16;
-       }
-       else{
-               ahc->needsdtr |= (ahc->needsdtr_orig & 0x00ff);
-               ahc->sdtrpending &= 0xff00;
-               AHC_OUTB(ahc, ACTIVE_A, 0);
-               offset = TARG_SCRATCH;
-               offset_max = TARG_SCRATCH + 8;
-       }
-       for(;offset < offset_max;offset++) {
+       ahc_run_qoutfifo(ahc);
+
+       /*
+        * Reset the bus if we are initiating this reset
+        */
+       sblkctl = ahc_inb(ahc, SBLKCTL);
+       cur_channel = 'A';
+       if ((ahc->features & AHC_TWIN) != 0
+        && ((sblkctl & SELBUSB) != 0))
+           cur_channel = 'B';
+       if (cur_channel != channel) {
+               /* Case 1: Command for another bus is active
+                * Stealthily reset the other bus without
+                * upsetting the current bus.
+                */
+               ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB);
+               ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
+               ahc_outb(ahc, SCSISEQ,
+                        ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+               if (initiate_reset)
+                       ahc_reset_current_bus(ahc);
+               ahc_clear_intstat(ahc);
+               ahc_outb(ahc, SBLKCTL, sblkctl);
+               restart_needed = FALSE;
+       } else {
+               /* Case 2: A command from this bus is active or we're idle */
+               ahc_clear_msg_state(ahc);
+               ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
+               ahc_outb(ahc, SCSISEQ,
+                        ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+               if (initiate_reset)
+                       ahc_reset_current_bus(ahc);
+               ahc_clear_intstat(ahc);
+
                /*
-                * Revert to async/narrow transfers
-                * until we renegotiate.
+                * Since we are going to restart the sequencer, avoid
+                * a race in the sequencer that could cause corruption
+                * of our Q pointers by starting over from index 0.
                 */
-               u_char targ_scratch;
+               ahc->qoutfifonext = 0;
+               if ((ahc->features & AHC_QUEUE_REGS) != 0)
+                       ahc_outb(ahc, SDSCB_QOFF, 0);
+               else
+                       ahc_outb(ahc, QOUTPOS, 0);
+               restart_needed = TRUE;
+       }
 
-               targ_scratch = AHC_INB(ahc, offset);
-               targ_scratch &= SXFR;
-               AHC_OUTB(ahc, offset, targ_scratch);
+       /*
+        * Clean up all the state information for the
+        * pending transactions on this bus.
+        */
+       found = ahc_abort_scbs(ahc, ALL_TARGETS, channel,
+                              ALL_LUNS, SCB_LIST_NULL,
+                              ROLE_UNKNOWN, XS_RESET);
+       if (channel == 'B') {
+               our_id = ahc->our_id_b;
+       } else {
+               our_id = ahc->our_id;
        }
 
+       max_scsiid = (ahc->features & AHC_WIDE) ? 15 : 7;
+       
        /*
-        * Reset the bus if we are initiating this reset and
-        * restart/unpause the sequencer
+        * Revert to async/narrow transfers until we renegotiate.
         */
-       /* Case 1: Command for another bus is active */
-       sblkctl = AHC_INB(ahc, SBLKCTL);
-       cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
-       if(cur_channel != channel)
-       {
-               /*
-                * Stealthily reset the other bus
-                * without upsetting the current bus
-                */
-               AHC_OUTB(ahc, SBLKCTL, sblkctl ^ SELBUSB);
-               if( initiate_reset )
-               {
-                       ahc_reset_current_bus(ahc);
+       for (target = 0; target <= max_scsiid; target++) {
+
+               if (ahc->enabled_targets[target] == NULL)
+                       continue;
+               for (initiator = 0; initiator <= max_scsiid; initiator++) {
+                       struct ahc_devinfo devinfo;
+
+                       ahc_compile_devinfo(&devinfo, target, initiator,
+                                           ALL_LUNS,
+                                           channel, ROLE_UNKNOWN);
+                       ahc_set_width(ahc, &devinfo,
+                                     MSG_EXT_WDTR_BUS_8_BIT,
+                                     AHC_TRANS_CUR,
+                                     /*paused*/TRUE,
+                                     /*done*/FALSE);
+                       ahc_set_syncrate(ahc, &devinfo,
+                                        /*syncrate*/NULL, /*period*/0,
+                                        /*offset*/0, AHC_TRANS_CUR,
+                                        /*paused*/TRUE,
+                                        /*done*/FALSE);
                }
-               AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI|CLRSELTIMEO);
-               AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
-               AHC_OUTB(ahc, SBLKCTL, sblkctl);
-               unpause_sequencer(ahc, /*unpause_always*/TRUE);
        }
-       /* Case 2: A command from this bus is active or we're idle */ 
-       else {
-               if( initiate_reset )
-               {
-                       ahc_reset_current_bus(ahc);
-               }
-               AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI|CLRSELTIMEO);
-               AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
+
+       if (restart_needed)
                restart_sequencer(ahc);
-       }
-       ahc_run_done_queue(ahc);
+       else
+               unpause_sequencer(ahc);
        return found;
 }
 
-void
-ahc_run_done_queue(ahc)
-       struct ahc_data *ahc;
+STATIC int
+ahc_match_scb(scb, target, channel, lun, role, tag)
+       struct scb *scb;
+       int target;
+       char channel;
+       int lun;
+       role_t role;
+       u_int tag;
 {
-       int i;
-       struct scb *scbp;
-       
-       for(i = 0; i < ahc->numscbs; i++) {
-               scbp = ahc->scbarray[i];
-               if(scbp->flags & SCB_QUEUED_FOR_DONE) 
-                       ahc_done(ahc, scbp);
-       }
+       int targ = SCB_TARGET(scb);
+       char chan = SCB_CHANNEL(scb);
+       int slun = SCB_LUN(scb);
+       int match;
+
+       match = ((chan == channel) || (channel == ALL_CHANNELS));
+       if (match != 0)
+               match = ((targ == target) || (target == ALL_TARGETS));
+       if (match != 0)
+               match = ((lun == slun) || (lun == ALL_LUNS));
+       return match;
 }
-       
-static int
-ahc_match_scb (scb, target, channel)
-        struct scb *scb;
-        int target;
-       char channel;
+
+STATIC void
+ahc_construct_sdtr(ahc, period, offset)
+       struct ahc_softc *ahc;
+       u_int period;
+       u_int offset;
 {
-       int targ = (scb->tcl >> 4) & 0x0f;
-       char chan = (scb->tcl & SELBUSB) ? 'B' : 'A';
+       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
+       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN;
+       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR;
+       ahc->msgout_buf[ahc->msgout_index++] = period;
+       ahc->msgout_buf[ahc->msgout_index++] = offset;
+       ahc->msgout_len += 5;
+}
 
-       if (target == ALL_TARGETS) 
-               return (chan == channel);
-       else
-               return ((chan == channel) && (targ == target));
+STATIC void
+ahc_construct_wdtr(ahc, bus_width)
+       struct ahc_softc *ahc;
+       u_int bus_width;
+{
+       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
+       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR_LEN;
+       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR;
+       ahc->msgout_buf[ahc->msgout_index++] = bus_width;
+       ahc->msgout_len += 4;
 }
 
+STATIC void
+ahc_calc_residual(scb)
+       struct scb *scb;
+{
+       struct  hardware_scb *hscb;
+
+       hscb = scb->hscb;
+
+       /*
+        * If the disconnected flag is still set, this is bogus
+        * residual information left over from a sequencer
+        * pagin/pageout, so ignore this case.
+        */
+       if ((scb->hscb->control & DISCONNECTED) == 0) {
+               u_int32_t resid;
+               int       resid_sgs;
+               int       sg;
+               
+               /*
+                * Remainder of the SG where the transfer
+                * stopped.
+                */
+               resid = (hscb->residual_data_count[2] << 16)
+                     | (hscb->residual_data_count[1] <<8)
+                     | (hscb->residual_data_count[0]);
+
+               /*
+                * Add up the contents of all residual
+                * SG segments that are after the SG where
+                * the transfer stopped.
+                */
+               resid_sgs = scb->hscb->residual_SG_count - 1/*current*/;
+               sg = scb->sg_count - resid_sgs;
+               while (resid_sgs > 0) {
+
+                       resid += scb->sg_list[sg].len;
+                       sg++;
+                       resid_sgs--;
+               }
+               scb->xs->resid = resid;
+       }
+
+       /*
+        * Clean out the residual information in this SCB for its
+        * next consumer.
+        */
+       hscb->residual_SG_count = 0;
+
+#ifdef AHC_DEBUG
+       if (ahc_debug & AHC_SHOWMISC) {
+               sc_print_addr(scb->xs->sc_link);
+               printf("Handled Residual of %ld bytes\n" ,scb->xs->resid);
+       }
+#endif
+}
 
-static void
-ahc_construct_sdtr(ahc, start_byte, period, offset)
-       struct ahc_data *ahc;
-       int start_byte;
-       u_int8_t period;
-       u_int8_t offset;
+STATIC void
+ahc_update_pending_syncrates(ahc)
+       struct ahc_softc *ahc;
 {
-       AHC_OUTB(ahc, MSG0 + start_byte, MSG_EXTENDED);
-       AHC_OUTB(ahc, MSG1 + start_byte, MSG_EXT_SDTR_LEN);
-       AHC_OUTB(ahc, MSG2 + start_byte, MSG_EXT_SDTR);
-       AHC_OUTB(ahc, MSG3 + start_byte, period);
-       AHC_OUTB(ahc, MSG4 + start_byte, offset);
-       AHC_OUTB(ahc, MSG_LEN, start_byte + 5);
+       struct  scb *scb;
+       int     pending_scb_count;
+       int     i;
+       u_int   saved_scbptr;
+
+       /*
+        * Traverse the pending SCB list and ensure that all of the
+        * SCBs there have the proper settings.
+        */
+       scb = LIST_FIRST(&ahc->pending_scbs);
+       pending_scb_count = 0;
+       while (scb != NULL) {
+               struct ahc_devinfo devinfo;
+               struct scsi_xfer *xs;
+               struct scb *pending_scb;
+               struct hardware_scb *pending_hscb;
+               struct ahc_initiator_tinfo *tinfo;
+               struct tmode_tstate *tstate;
+               u_int  our_id, remote_id;
+               
+               xs = scb->xs;
+               pending_scb = scb;
+               pending_hscb = pending_scb->hscb;
+               our_id = SCB_IS_SCSIBUS_B(pending_scb)
+                      ? ahc->our_id_b : ahc->our_id;
+               remote_id = xs->sc_link->target;
+               ahc_compile_devinfo(&devinfo, our_id, remote_id,
+                                   SCB_LUN(pending_scb),
+                                   SCB_CHANNEL(pending_scb),
+                                   ROLE_UNKNOWN);
+               tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
+                                           our_id, remote_id, &tstate);
+               pending_hscb->control &= ~ULTRAENB;
+               if ((tstate->ultraenb & devinfo.target_mask) != 0)
+                       pending_hscb->control |= ULTRAENB;
+               pending_hscb->scsirate = tinfo->scsirate;
+               pending_hscb->scsioffset = tinfo->current.offset;
+               pending_scb_count++;
+               scb = LIST_NEXT(scb, pend_links);
+       }
+
+       if (pending_scb_count == 0)
+               return;
+
+       saved_scbptr = ahc_inb(ahc, SCBPTR);
+       /* Ensure that the hscbs down on the card match the new information */
+       for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+               u_int scb_tag;
+
+               ahc_outb(ahc, SCBPTR, i);
+               scb_tag = ahc_inb(ahc, SCB_TAG);
+               if (scb_tag != SCB_LIST_NULL) {
+                       struct  ahc_devinfo devinfo;
+                       struct  scb *pending_scb;
+                       struct scsi_xfer *xs;
+                       struct  hardware_scb *pending_hscb;
+                       struct  ahc_initiator_tinfo *tinfo;
+                       struct  tmode_tstate *tstate;
+                       u_int   our_id, remote_id;
+                       u_int   control;
+
+                       pending_scb = &ahc->scb_data->scbarray[scb_tag];
+                       if (pending_scb->flags == SCB_FREE)
+                               continue;
+                       pending_hscb = pending_scb->hscb;
+                       xs = pending_scb->xs;
+                       our_id = SCB_IS_SCSIBUS_B(pending_scb)
+                              ? ahc->our_id_b : ahc->our_id;
+                       remote_id = xs->sc_link->target;
+                       ahc_compile_devinfo(&devinfo, our_id, remote_id,
+                                           SCB_LUN(pending_scb),
+                                           SCB_CHANNEL(pending_scb),
+                                           ROLE_UNKNOWN);
+                       tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
+                                                   our_id, remote_id, &tstate);
+                       control = ahc_inb(ahc, SCB_CONTROL);
+                       control &= ~ULTRAENB;
+                       if ((tstate->ultraenb & devinfo.target_mask) != 0)
+                               control |= ULTRAENB;
+                       ahc_outb(ahc, SCB_CONTROL, control);
+                       ahc_outb(ahc, SCB_SCSIRATE, tinfo->scsirate);
+                       ahc_outb(ahc, SCB_SCSIOFFSET, tinfo->current.offset);
+               }
+       }
+       ahc_outb(ahc, SCBPTR, saved_scbptr);
 }
 
-static void
-ahc_construct_wdtr(ahc, start_byte, bus_width)
-       struct ahc_data *ahc;
-       int start_byte;
-       u_int8_t bus_width;
+STATIC void
+ahc_shutdown(void *arg)
 {
-       AHC_OUTB(ahc, MSG0 + start_byte, MSG_EXTENDED);
-       AHC_OUTB(ahc, MSG1 + start_byte, MSG_EXT_WDTR_LEN);
-       AHC_OUTB(ahc, MSG2 + start_byte, MSG_EXT_WDTR);
-       AHC_OUTB(ahc, MSG3 + start_byte, bus_width);
-       AHC_OUTB(ahc, MSG_LEN, start_byte + 4);
+       struct  ahc_softc *ahc;
+       int     i;
+       u_int   sxfrctl1_a, sxfrctl1_b;
+
+       ahc = (struct ahc_softc *)arg;
+
+       pause_sequencer(ahc);
+
+       /*
+        * Preserve the value of the SXFRCTL1 register for all channels.
+        * It contains settings that affect termination and we don't want
+        * to disturb the integrity of the bus during shutdown in case
+        * we are in a multi-initiator setup.
+        */
+       sxfrctl1_b = 0;
+       if ((ahc->features & AHC_TWIN) != 0) {
+               u_int sblkctl;
+
+               sblkctl = ahc_inb(ahc, SBLKCTL);
+               ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB);
+               sxfrctl1_b = ahc_inb(ahc, SXFRCTL1);
+               ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB);
+       }
+
+       sxfrctl1_a = ahc_inb(ahc, SXFRCTL1);
+
+       /* This will reset most registers to 0, but not all */
+       ahc_reset(ahc);
+
+       if ((ahc->features & AHC_TWIN) != 0) {
+               u_int sblkctl;
+
+               sblkctl = ahc_inb(ahc, SBLKCTL);
+               ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB);
+               ahc_outb(ahc, SXFRCTL1, sxfrctl1_b);
+               ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB);
+       }
+       ahc_outb(ahc, SXFRCTL1, sxfrctl1_a);
+
+       ahc_outb(ahc, SCSISEQ, 0);
+       ahc_outb(ahc, SXFRCTL0, 0);
+       ahc_outb(ahc, DSPCISTATUS, 0);
+
+       for (i = TARG_SCSIRATE; i < HA_274_BIOSCTRL; i++)
+               ahc_outb(ahc, i, 0);
 }
index 8f97514..7dde5dd 100644 (file)
-/*     $OpenBSD: aic7xxxreg.h,v 1.5 1997/04/10 22:52:19 deraadt Exp $  */
-/*     $NetBSD: aic7xxxreg.h,v 1.4 1996/10/08 03:04:04 gibbs Exp $     */
 /*
- * Aic7xxx register and scratch ram definitions.
- *
- * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
+ * DO NOT EDIT - This file is automatically generated.
+ */
+
+#define        SCSISEQ                         0x00
+#define                TEMODE                  0x80
+#define                SCSIRSTO                0x01
+
+#define        SXFRCTL0                        0x01
+#define                DFON                    0x80
+#define                DFPEXP                  0x40
+#define                FAST20                  0x20
+#define                CLRSTCNT                0x10
+#define                SPIOEN                  0x08
+#define                SCAMEN                  0x04
+#define                CLRCHN                  0x02
+
+#define        SXFRCTL1                        0x02
+#define                BITBUCKET               0x80
+#define                SWRAPEN                 0x40
+#define                STIMESEL                0x18
+#define                ENSTIMER                0x04
+#define                ACTNEGEN                0x02
+#define                STPWEN                  0x01
+
+#define        SCSISIGO                        0x03
+#define                CDO                     0x80
+#define                IOO                     0x40
+#define                MSGO                    0x20
+#define                ATNO                    0x10
+#define                SELO                    0x08
+#define                BSYO                    0x04
+#define                REQO                    0x02
+#define                ACKO                    0x01
+
+#define        SCSISIGI                        0x03
+#define                ATNI                    0x10
+#define                SELI                    0x08
+#define                BSYI                    0x04
+#define                REQI                    0x02
+#define                ACKI                    0x01
+
+#define        SCSIRATE                        0x04
+#define                WIDEXFER                0x80
+#define                SXFR                    0x70
+#define                ENABLE_CRC              0x40
+#define                SINGLE_EDGE             0x10
+#define                SOFS                    0x0f
+#define                SXFR_ULTRA2             0x0f
+
+#define        SCSIID                          0x05
+#define        SCSIOFFSET                      0x05
+#define                SOFS_ULTRA2             0x7f
+
+#define        SCSIDATL                        0x06
+
+#define        SCSIDATH                        0x07
+
+#define        STCNT                           0x08
+
+#define        OPTIONMODE                      0x08
+#define                AUTORATEEN              0x80
+#define                AUTOACKEN               0x40
+#define                ATNMGMNTEN              0x20
+#define                BUSFREEREV              0x10
+#define                EXPPHASEDIS             0x08
+#define                SCSIDATL_IMGEN          0x04
+#define                OPTIONMODE_DEFAULTS     0x03
+#define                AUTO_MSGOUT_DE          0x02
+#define                DIS_MSGIN_DUALEDGE      0x01
+
+#define        TARGCRCCNT                      0x0a
+
+#define        CLRSINT0                        0x0b
+#define                CLRSELDO                0x40
+#define                CLRSELDI                0x20
+#define                CLRSELINGO              0x10
+#define                CLRSWRAP                0x08
+#define                CLRSPIORDY              0x02
+
+#define        SSTAT0                          0x0b
+#define                TARGET                  0x80
+#define                SELDO                   0x40
+#define                SELDI                   0x20
+#define                SELINGO                 0x10
+#define                IOERR                   0x08
+#define                SWRAP                   0x08
+#define                SDONE                   0x04
+#define                SPIORDY                 0x02
+#define                DMADONE                 0x01
+
+#define        CLRSINT1                        0x0c
+#define                CLRSELTIMEO             0x80
+#define                CLRATNO                 0x40
+#define                CLRSCSIRSTI             0x20
+#define                CLRBUSFREE              0x08
+#define                CLRSCSIPERR             0x04
+#define                CLRPHASECHG             0x02
+#define                CLRREQINIT              0x01
+
+#define        SSTAT1                          0x0c
+#define                SELTO                   0x80
+#define                ATNTARG                 0x40
+#define                SCSIRSTI                0x20
+#define                PHASEMIS                0x10
+#define                BUSFREE                 0x08
+#define                SCSIPERR                0x04
+#define                PHASECHG                0x02
+#define                REQINIT                 0x01
+
+#define        SSTAT2                          0x0d
+#define                OVERRUN                 0x80
+#define                SFCNT                   0x1f
+#define                EXP_ACTIVE              0x10
+
+#define        SSTAT3                          0x0e
+#define                SCSICNT                 0xf0
+#define                OFFCNT                  0x0f
+
+#define        SCSIID_ULTRA2                   0x0f
+#define                OID                     0x0f
+
+#define        SIMODE0                         0x10
+#define                ENSELDO                 0x40
+#define                ENSELDI                 0x20
+#define                ENSELINGO               0x10
+#define                ENIOERR                 0x08
+#define                ENSWRAP                 0x08
+#define                ENSDONE                 0x04
+#define                ENSPIORDY               0x02
+#define                ENDMADONE               0x01
+
+#define        SIMODE1                         0x11
+#define                ENSELTIMO               0x80
+#define                ENATNTARG               0x40
+#define                ENSCSIRST               0x20
+#define                ENPHASEMIS              0x10
+#define                ENBUSFREE               0x08
+#define                ENSCSIPERR              0x04
+#define                ENPHASECHG              0x02
+#define                ENREQINIT               0x01
+
+#define        SCSIBUSL                        0x12
+
+#define        SCSIBUSH                        0x13
+
+#define        SHADDR                          0x14
+
+#define        SELTIMER                        0x18
+#define        TARGIDIN                        0x18
+#define                STAGE6                  0x20
+#define                STAGE5                  0x10
+#define                STAGE4                  0x08
+#define                STAGE3                  0x04
+#define                STAGE2                  0x02
+#define                STAGE1                  0x01
+
+#define        SELID                           0x19
+#define                SELID_MASK              0xf0
+#define                ONEBIT                  0x08
+
+#define        SCAMCTL                         0x1a
+#define                ENSCAMSELO              0x80
+#define                CLRSCAMSELID            0x40
+#define                ALTSTIM                 0x20
+#define                DFLTTID                 0x10
+#define                SCAMLVL                 0x03
+
+#define        TARGID                          0x1b
+
+#define        SPIOCAP                         0x1b
+#define                SOFT1                   0x80
+#define                SOFT0                   0x40
+#define                SOFTCMDEN               0x20
+#define                HAS_BRDCTL              0x10
+#define                SEEPROM                 0x08
+#define                EEPROM                  0x04
+#define                ROM                     0x02
+#define                SSPIOCPS                0x01
+
+#define        BRDCTL                          0x1d
+#define                BRDDAT7                 0x80
+#define                BRDDAT6                 0x40
+#define                BRDDAT5                 0x20
+#define                BRDDAT4                 0x10
+#define                BRDSTB                  0x10
+#define                BRDCS                   0x08
+#define                BRDDAT3                 0x08
+#define                BRDDAT2                 0x04
+#define                BRDRW                   0x04
+#define                BRDRW_ULTRA2            0x02
+#define                BRDCTL1                 0x02
+#define                BRDCTL0                 0x01
+#define                BRDSTB_ULTRA2           0x01
+
+#define        SEECTL                          0x1e
+#define                EXTARBACK               0x80
+#define                EXTARBREQ               0x40
+#define                SEEMS                   0x20
+#define                SEERDY                  0x10
+#define                SEECS                   0x08
+#define                SEECK                   0x04
+#define                SEEDO                   0x02
+#define                SEEDI                   0x01
+
+#define        SBLKCTL                         0x1f
+#define                DIAGLEDEN               0x80
+#define                DIAGLEDON               0x40
+#define                AUTOFLUSHDIS            0x20
+#define                ENAB40                  0x08
+#define                ENAB20                  0x04
+#define                SELWIDE                 0x02
+#define                XCVR                    0x01
+
+#define        SRAM_BASE                       0x20
+
+#define        TARG_SCSIRATE                   0x20
+#define        CMDSIZE_TABLE                   0x20
+
+#define        ULTRA_ENB                       0x30
+
+#define        DISC_DSB                        0x32
+
+#define        MSG_OUT                         0x34
+
+#define        DMAPARAMS                       0x35
+#define                PRELOADEN               0x80
+#define                WIDEODD                 0x40
+#define                SCSIEN                  0x20
+#define                SDMAENACK               0x10
+#define                SDMAEN                  0x10
+#define                HDMAEN                  0x08
+#define                HDMAENACK               0x08
+#define                DIRECTION               0x04
+#define                FIFOFLUSH               0x02
+#define                FIFORESET               0x01
+
+#define        SEQ_FLAGS                       0x36
+#define                IDENTIFY_SEEN           0x80
+#define                SCBPTR_VALID            0x40
+#define                DPHASE                  0x20
+#define                TARG_CMD_PENDING        0x10
+#define                CMDPHASE_PENDING        0x08
+#define                DPHASE_PENDING          0x04
+#define                SPHASE_PENDING          0x02
+#define                NO_DISCONNECT           0x01
+
+#define        SAVED_TCL                       0x37
+
+#define        SG_COUNT                        0x38
+
+#define        SG_NEXT                         0x39
+
+#define        LASTPHASE                       0x3d
+#define                P_MESGIN                0xe0
+#define                PHASE_MASK              0xe0
+#define                P_STATUS                0xc0
+#define                P_MESGOUT               0xa0
+#define                P_COMMAND               0x80
+#define                CDI                     0x80
+#define                IOI                     0x40
+#define                P_DATAIN                0x40
+#define                MSGI                    0x20
+#define                P_BUSFREE               0x01
+#define                P_DATAOUT               0x00
 
-/*
- * This header is shared by the sequencer code and the kernel level driver.
- *
- * All page numbers refer to the Adaptec AIC-7770 Data Book available from
- * Adaptec's Technical Documents Department 1-800-934-2766
- */
+#define        WAITING_SCBH                    0x3e
 
-/*
- * SCSI Sequence Control (p. 3-11).
- * Each bit, when set starts a specific SCSI sequence on the bus
- */
-#define SCSISEQ                        0x000
-#define                TEMODEO         0x80
-#define                ENSELO          0x40
-#define                ENSELI          0x20
-#define                ENRSELI         0x10
-#define                ENAUTOATNO      0x08
-#define                ENAUTOATNI      0x04
-#define                ENAUTOATNP      0x02
-#define                SCSIRSTO        0x01
+#define        DISCONNECTED_SCBH               0x3f
 
-/*
- * SCSI Transfer Control 0 Register (pp. 3-13).
- * Controls the SCSI module data path.
- */
-#define        SXFRCTL0                0x001
-#define                DFON            0x80
-#define                DFPEXP          0x40
-#define                ULTRAEN         0x20
-#define                CLRSTCNT        0x10
-#define                SPIOEN          0x08
-#define                SCAMEN          0x04
-#define                CLRCHN          0x02
-/*  UNUSED                     0x01 */
+#define        FREE_SCBH                       0x40
 
-/*
- * SCSI Transfer Control 1 Register (pp. 3-14,15).
- * Controls the SCSI module data path.
- */
-#define        SXFRCTL1                0x002
-#define                BITBUCKET       0x80
-#define                SWRAPEN         0x40
-#define                ENSPCHK         0x20
-#define                STIMESEL        0x18
-#define                ENSTIMER        0x04
-#define                ACTNEGEN        0x02
-#define                STPWEN          0x01    /* Powered Termination */
+#define        HSCB_ADDR                       0x41
 
-/*
- * SCSI Control Signal Read Register (p. 3-15).
- * Reads the actual state of the SCSI bus pins
- */
-#define SCSISIGI               0x003
-#define                CDI             0x80
-#define                IOI             0x40
-#define                MSGI            0x20
-#define                ATNI            0x10
-#define                SELI            0x08
-#define                BSYI            0x04
-#define                REQI            0x02
-#define                ACKI            0x01
+#define        SCBID_ADDR                      0x45
 
-/*
- * Possible phases in SCSISIGI
- */
-#define                PHASE_MASK      0xe0
-#define                P_DATAOUT       0x00
-#define                P_DATAIN        0x40
-#define                P_COMMAND       0x80
-#define                P_MESGOUT       0xa0
-#define                P_STATUS        0xc0
-#define                P_MESGIN        0xe0
-/*
- * SCSI Control Signal Write Register (p. 3-16).
- * Writing to this register modifies the control signals on the bus.  Only
- * those signals that are allowed in the current mode (Initiator/Target) are
- * asserted.
- */
-#define SCSISIGO               0x003
-#define                CDO             0x80
-#define                IOO             0x40
-#define                MSGO            0x20
-#define                ATNO            0x10
-#define                SELO            0x08
-#define                BSYO            0x04
-#define                REQO            0x02
-#define                ACKO            0x01
-
-/* 
- * SCSI Rate Control (p. 3-17).
- * Contents of this register determine the Synchronous SCSI data transfer
- * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
- * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
- * greater than 0 enables synchronous transfers.
- */
-#define SCSIRATE               0x004
-#define                WIDEXFER        0x80            /* Wide transfer control */
-#define                SXFR            0x70            /* Sync transfer rate */
-#define                SOFS            0x0f            /* Sync offset */
+#define        TMODE_CMDADDR                   0x49
 
-/*
- * SCSI ID (p. 3-18).
- * Contains the ID of the board and the current target on the
- * selected channel.
- */
-#define SCSIID                 0x005
-#define                TID             0xf0            /* Target ID mask */
-#define                OID             0x0f            /* Our ID mask */
+#define        KERNEL_QINPOS                   0x4d
 
-/*
- * SCSI Latched Data (p. 3-19).
- * Read/Write latches used to transfer data on the SCSI bus during
- * Automatic or Manual PIO mode.  SCSIDATH can be used for the
- * upper byte of a 16bit wide asynchronous data phase transfer.
- */
-#define SCSIDATL               0x006
-#define SCSIDATH               0x007
+#define        QINPOS                          0x4e
 
-/*
- * SCSI Transfer Count (pp. 3-19,20)
- * These registers count down the number of bytes transferred
- * across the SCSI bus.  The counter is decremented only once
- * the data has been safely transferred.  SDONE in SSTAT0 is
- * set when STCNT goes to 0
- */ 
-#define STCNT                  0x008
-#define STCNT0                 0x008
-#define STCNT1                 0x009
-#define STCNT2                 0x00a
+#define        QOUTPOS                         0x4f
 
-/*
- * Clear SCSI Interrupt 0 (p. 3-20)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
- */
-#define        CLRSINT0                0x00b
-#define                CLRSELDO        0x40
-#define                CLRSELDI        0x20
-#define                CLRSELINGO      0x10
-#define                CLRSWRAP        0x08
-/*  UNUSED                     0x04 */
-#define                CLRSPIORDY      0x02
-/*  UNUSED                     0x01 */
+#define        KERNEL_TQINPOS                  0x50
 
-/*
- * SCSI Status 0 (p. 3-21)
- * Contains one set of SCSI Interrupt codes
- * These are most likely of interest to the sequencer
- */
-#define SSTAT0                 0x00b
-#define                TARGET          0x80            /* Board acting as target */
-#define                SELDO           0x40            /* Selection Done */
-#define                SELDI           0x20            /* Board has been selected */
-#define                SELINGO         0x10            /* Selection In Progress */
-#define                SWRAP           0x08            /* 24bit counter wrap */
-#define                SDONE           0x04            /* STCNT = 0x000000 */
-#define                SPIORDY         0x02            /* SCSI PIO Ready */
-#define                DMADONE         0x01            /* DMA transfer completed */
+#define        TQINPOS                         0x51
 
-/*
- * Clear SCSI Interrupt 1 (p. 3-23)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
- */
-#define CLRSINT1               0x00c
-#define                CLRSELTIMEO     0x80
-#define                CLRATNO         0x40
-#define                CLRSCSIRSTI     0x20
-/*  UNUSED                     0x10 */
-#define                CLRBUSFREE      0x08
-#define                CLRSCSIPERR     0x04
-#define                CLRPHASECHG     0x02
-#define                CLRREQINIT      0x01
+#define        ARG_1                           0x52
+#define        RETURN_1                        0x52
+#define                SEND_MSG                0x80
+#define                SEND_SENSE              0x40
+#define                SEND_REJ                0x20
+#define                MSGOUT_PHASEMIS         0x10
+#define                EXIT_MSG_LOOP           0x08
+#define                CONT_MSG_LOOP           0x04
+#define                CONT_TARG_SESSION       0x02
 
-/*
- * SCSI Status 1 (p. 3-24)
- */
-#define SSTAT1                 0x00c
-#define                SELTO           0x80
-#define                ATNTARG         0x40
-#define                SCSIRSTI        0x20
-#define                PHASEMIS        0x10
-#define                BUSFREE         0x08
-#define                SCSIPERR        0x04
-#define                PHASECHG        0x02
-#define                REQINIT         0x01
+#define        ARG_2                           0x53
+#define        RETURN_2                        0x53
 
-/*
- * SCSI Interrupt Mode 1 (pp. 3-28,29)
- * Setting any bit will enable the corresponding function
- * in SIMODE1 to interrupt via the IRQ pin.
- */
-#define        SIMODE1                 0x011
-#define                ENSELTIMO       0x80
-#define                ENATNTARG       0x40
-#define                ENSCSIRST       0x20
-#define                ENPHASEMIS      0x10
-#define                ENBUSFREE       0x08
-#define                ENSCSIPERR      0x04
-#define                ENPHASECHG      0x02
-#define                ENREQINIT       0x01
+#define        LAST_MSG                        0x54
 
-/*
- * SCSI Data Bus (High) (p. 3-29)
- * This register reads data on the SCSI Data bus directly.
- */
-#define        SCSIBUSL                0x012
-#define        SCSIBUSH                0x013
+#define        PREFETCH_CNT                    0x55
 
-/*
- * SCSI/Host Address (p. 3-30)
- * These registers hold the host address for the byte about to be
- * transfered on the SCSI bus.  They are counted up in the same
- * manner as STCNT is counted down.  SHADDR should always be used
- * to determine the address of the last byte transfered since HADDR
- * can be skewed by write-ahead.
- */
-#define        SHADDR                  0x014
-#define        SHADDR0                 0x014
-#define        SHADDR1                 0x015
-#define        SHADDR2                 0x016
-#define        SHADDR3                 0x017
+#define        TARGET_MSG_REQUEST              0x56
 
-/*
- * Selection/Reselection ID (p. 3-31)
- * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
- * device did not set its own ID.
- */
-#define SELID                  0x019
-#define                SELID_MASK      0xf0
-#define                ONEBIT          0x08
-/*  UNUSED                     0x07 */
+#define        SCSISEQ_TEMPLATE                0x58
+#define                ENSELO                  0x40
+#define                ENSELI                  0x20
+#define                ENRSELI                 0x10
+#define                ENAUTOATNO              0x08
+#define                ENAUTOATNI              0x04
+#define                ENAUTOATNP              0x02
 
-/*
- * SCSI Block Control (p. 3-32)
- * Controls Bus type and channel selection.  In a twin channel configuration
- * addresses 0x00-0x1e are gated to the appropriate channel based on this
- * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
- * on a wide bus.
- */
-#define SBLKCTL                        0x01f
-#define                DIAGLEDEN       0x80    /* Aic78X0 only */
-#define                DIAGLEDON       0x40    /* Aic78X0 only */
-#define                AUTOFLUSHDIS    0x20
-/*  UNUSED                     0x10 */
-#define                SELBUS_MASK     0x0a
-#define                SELBUSB         0x08
-/*  UNUSED                     0x04 */
-#define                SELWIDE         0x02
-/*  UNUSED                     0x01 */
-#define                SELNARROW       0x00
+#define        DATA_COUNT_ODD                  0x59
 
-/*
- * Sequencer Control (p. 3-33)
- * Error detection mode and speed configuration
- */
-#define SEQCTL                 0x060
-#define                PERRORDIS       0x80
-#define                PAUSEDIS        0x40
-#define                FAILDIS         0x20
-#define        FASTMODE        0x10
-#define                BRKADRINTEN     0x08
-#define                STEP            0x04
-#define                SEQRESET        0x02
-#define                LOADRAM         0x01
+#define        SCSICONF                        0x5a
+#define                TERM_ENB                0x80
+#define                RESET_SCSI              0x40
+#define                ENSPCHK                 0x20
+#define                HWSCSIID                0x0f
+#define                HSCSIID                 0x07
 
-/*
- * Sequencer RAM Data (p. 3-34)
- * Single byte window into the Scratch Ram area starting at the address
- * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
- * four bytes in sucessesion.  The SEQADDRs will increment after the most
- * significant byte is written
- */
-#define SEQRAM                 0x061
+#define        INITIATOR_TAG                   0x5a
 
-/*
- * Sequencer Address Registers (p. 3-35)
- * Only the first bit of SEQADDR1 holds addressing information
- */
-#define SEQADDR0               0x062
-#define SEQADDR1               0x063
-#define        SEQADDR1_MASK   0x01
+#define        HOSTCONF                        0x5d
 
-/*
- * Accumulator
- * We cheat by passing arguments in the Accumulator up to the kernel driver
- */
-#define ACCUM                  0x064
+#define        HA_274_BIOSCTRL                 0x5f
+#define                BIOSMODE                0x30
+#define                BIOSDISABLED            0x30
+#define                CHANNEL_B_PRIMARY       0x08
 
-#define SINDEX                 0x065
-#define DINDEX                 0x066
-#define ALLZEROS               0x06a
-#define NONE                   0x06a
-#define SINDIR                 0x06c
-#define DINDIR                 0x06d
-#define FUNCTION1              0x06e
+#define        SEQCTL                          0x60
+#define                PERRORDIS               0x80
+#define                PAUSEDIS                0x40
+#define                FAILDIS                 0x20
+#define                FASTMODE                0x10
+#define                BRKADRINTEN             0x08
+#define                STEP                    0x04
+#define                SEQRESET                0x02
+#define                LOADRAM                 0x01
 
-/*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transferred across the host bus.
- */
-#define HADDR                  0x088
-#define HADDR0                 0x088
-#define HADDR1                 0x089
-#define HADDR2                 0x08a
-#define HADDR3                 0x08b
-
-#define HCNT                   0x08c
-#define HCNT0                  0x08c
-#define HCNT1                  0x08d
-#define HCNT2                  0x08e
-/*
- * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
- */
-#define SCBPTR                 0x090
+#define        SEQRAM                          0x61
 
-/*
- * Board Control (p. 3-43)
- */
-#define BCTL                   0x084
-/*   RSVD                      0xf0 */
-#define                ACE             0x08    /* Support for external processors */
-/*   RSVD                      0x06 */
-#define                ENABLE          0x01
+#define        SEQADDR0                        0x62
 
-/*
- * On the aic78X0 chips, Board Control is replaced by the DSCommand
- * register (p. 4-64)
- */
-#define        DSCOMMAND               0x084
-#define                CACHETHEN       0x80    /* Cache Threshold enable */
-#define                DPARCKEN        0x40    /* Data Parity Check Enable */
-#define                MPARCKEN        0x20    /* Memory Parity Check Enable */
-#define                EXTREQLCK       0x10    /* External Request Lock */
+#define        SEQADDR1                        0x63
+#define                SEQADDR1_MASK           0x01
 
-/*
- * Bus On/Off Time (p. 3-44)
- */
-#define BUSTIME                        0x085
-#define                BOFF            0xf0
-#define                BON             0x0f
+#define        ACCUM                           0x64
 
-/*
- * Bus Speed (p. 3-45)
- */
-#define        BUSSPD                  0x086
-#define                DFTHRSH         0xc0
-#define                STBOFF          0x38
-#define                STBON           0x07
-#define                DFTHRSH_100     0xc0
+#define        SINDEX                          0x65
 
-/*
- * Host Control (p. 3-47) R/W
- * Overall host control of the device.
- */
-#define HCNTRL                 0x087
-/*    UNUSED                   0x80 */
-#define                POWRDN          0x40
-/*    UNUSED                   0x20 */
-#define                SWINT           0x10
-#define                IRQMS           0x08
-#define                PAUSE           0x04
-#define                INTEN           0x02
-#define                CHIPRST         0x01
-#define                CHIPRSTACK      0x01
+#define        DINDEX                          0x66
 
-/*
- * Interrupt Status (p. 3-50)
- * Status for system interrupts
- */
-#define INTSTAT                        0x091
-#define                SEQINT_MASK     0xf1            /* SEQINT Status Codes */
-#define                        BAD_PHASE       0x01    /* unknown scsi bus phase */
-#define                        SEND_REJECT     0x11    /* sending a message reject */
-#define                        NO_IDENT        0x21    /* no IDENTIFY after reconnect*/
-#define                        NO_MATCH        0x31    /* no cmd match for reconnect */
-#define                        EXTENDED_MSG    0x41    /* Extended message received */
-#define                        REJECT_MSG      0x61    /* Reject message received */
-#define                        BAD_STATUS      0x71    /* Bad status from target */
-#define                        RESIDUAL        0x81    /* Residual byte count != 0 */
-#define                        ABORT_TAG       0x91    /* Sent an ABORT_TAG message */
-#define                        AWAITING_MSG    0xa1    /*
-                                                * Kernel requested to specify
-                                                 * a message to this target
-                                                 * (command was null), so tell
-                                                 * it that it can fill the
-                                                 * message buffer.
-                                                 */
-#define                        IMMEDDONE       0xb1    /*
-                                                * An immediate command has
-                                                * completed
-                                                */
-#define                        MSG_BUFFER_BUSY 0xc1    /*
-                                                * Sequencer wants to use the
-                                                * message buffer, but it
-                                                * already contains a message
-                                                */
-#define                        MSGIN_PHASEMIS  0xd1    /*
-                                                * Target changed phase on us
-                                                * when we were expecting
-                                                * another msgin byte.
-                                                */
-#define                        DATA_OVERRUN    0xe1    /*
-                                                * Target attempted to write
-                                                * beyond the bounds of its
-                                                * command.
-                                                */
-#define        BRKADRINT 0x08
-#define                SCSIINT   0x04
-#define                CMDCMPLT  0x02
-#define                SEQINT    0x01
-#define                INT_PEND  (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
+#define        ALLONES                         0x69
 
-/*
- * Hard Error (p. 3-53)
- * Reporting of catastrophic errors.  You usually cannot recover from
- * these without a full board reset.
- */
-#define ERROR                  0x092
-/*    UNUSED                   0xf0 */
-#define                PARERR          0x08
-#define                ILLOPCODE       0x04
-#define                ILLSADDR        0x02
-#define                ILLHADDR        0x01
+#define        ALLZEROS                        0x6a
 
-/*
- * Clear Interrupt Status (p. 3-52)
- */
-#define CLRINT                 0x092
-#define                CLRBRKADRINT    0x08
-#define                CLRSCSIINT      0x04
-#define                CLRCMDINT       0x02
-#define                CLRSEQINT       0x01
-
-#define        DFCNTRL                 0x093
-#define                WIDEODD         0x40
-#define                SCSIEN          0x20
-#define                SDMAEN          0x10
-#define                SDMAENACK       0x10
-#define                HDMAEN          0x08
-#define                HDMAENACK       0x08
-#define                DIRECTION       0x04
-#define                FIFOFLUSH       0x02
-#define                FIFORESET       0x01
-
-#define        DFSTATUS                0x094
-#define                HDONE           0x08
-#define                FIFOEMP         0x01
-
-#define        DFDAT                   0x099
+#define        NONE                            0x6a
 
-/*
- * SCB Auto Increment (p. 3-59)
- * Byte offset into the SCB Array and an optional bit to allow auto
- * incrementing of the address during download and upload operations
- */
-#define SCBCNT                 0x09a
-#define                SCBAUTO         0x80
-#define                SCBCNT_MASK     0x1f
+#define        FLAGS                           0x6b
+#define                ZERO                    0x02
+#define                CARRY                   0x01
 
-/*
- * Queue In FIFO (p. 3-60)
- * Input queue for queued SCBs (commands that the seqencer has yet to start)
- */
-#define QINFIFO                        0x09b
+#define        SINDIR                          0x6c
 
-/*
- * Queue In Count (p. 3-60)
- * Number of queued SCBs
- */
-#define QINCNT                 0x09c
+#define        DINDIR                          0x6d
 
-/*
- * Queue Out FIFO (p. 3-61)
- * Queue of SCBs that have completed and await the host
- */
-#define QOUTFIFO               0x09d
+#define        FUNCTION1                       0x6e
 
-/*
- * Queue Out Count (p. 3-61)
- * Number of queued SCBs in the Out FIFO
- */
-#define QOUTCNT                        0x09e
+#define        STACK                           0x6f
 
-/*
- * SCB Definition (p. 5-4)
- * The two reserved bytes at SCBARRAY+1[23] are expected to be set to
- * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
- * whether or not to DMA an SCB from host ram. This flag prevents the
- * "re-fetching" of transactions that are requeued because the target is
- * busy with another command. We also use bits 6 & 7 to indicate whether
- * or not to initiate SDTR or WDTR repectively when starting this command.
- */
-#define SCBARRAY               0x0a0
-#define        SCB_CONTROL             0x0a0
-#define                MK_MESSAGE      0x80
-#define                DISCENB         0x40
-#define                TAG_ENB         0x20
-#define                DISCONNECTED    0x04
-#define                SCB_TAG_TYPE    0x03
-#define        SCB_TCL                 0x0a1
-#define        SCB_TARGET_STATUS       0x0a2
-#define        SCB_SGCOUNT             0x0a3
-#define        SCB_SGPTR               0x0a4
-#define                SCB_SGPTR0      0x0a4
-#define                SCB_SGPTR1      0x0a5
-#define                SCB_SGPTR2      0x0a6
-#define                SCB_SGPTR3      0x0a7
-#define        SCB_RESID_SGCNT         0x0a8
-#define SCB_RESID_DCNT         0x0a9
-#define                SCB_RESID_DCNT0 0x0a9
-#define                SCB_RESID_DCNT1 0x0aa
-#define                SCB_RESID_DCNT2 0x0ab
-#define SCB_DATAPTR            0x0ac
-#define                SCB_DATAPTR0    0x0ac
-#define                SCB_DATAPTR1    0x0ad
-#define                SCB_DATAPTR2    0x0ae
-#define                SCB_DATAPTR3    0x0af
-#define        SCB_DATACNT             0x0b0
-#define                SCB_DATACNT0    0x0b0
-#define                SCB_DATACNT1    0x0b1
-#define                SCB_DATACNT2    0x0b2
-/* UNUSED - QUAD PADDING       0x0b3 */
-#define SCB_CMDPTR             0x0b4
-#define                SCB_CMDPTR0     0x0b4
-#define                SCB_CMDPTR1     0x0b5
-#define                SCB_CMDPTR2     0x0b6
-#define                SCB_CMDPTR3     0x0b7
-#define        SCB_CMDLEN              0x0b8
-#define SCB_TAG                        0x0b9
-#define        SCB_NEXT                0x0ba
-#define        SCB_PREV                0x0bb
-
-#ifdef __linux__
-#define        SG_SIZEOF               0x0c            /* sizeof(struct scatterlist) */
-#else
-#define        SG_SIZEOF               0x08            /* sizeof(struct ahc_dma) */
-#endif
-
-/* --------------------- AHA-2840-only definitions -------------------- */
-
-#define        SEECTL_2840             0x0c0
-/*     UNUSED                  0xf8 */
-#define                CS_2840         0x04
-#define                CK_2840         0x02
-#define                DO_2840         0x01
-
-#define        STATUS_2840             0x0c1
-#define                EEPROM_TF       0x80
-#define                BIOS_SEL        0x60
-#define                ADSEL           0x1e
-#define                DI_2840         0x01
-
-/* --------------------- AIC-7870-only definitions -------------------- */
-
-#define DSPCISTATUS            0x086
+#define        TARG_OFFSET                     0x70
 
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device.  In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device.  When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM.  When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.  
- *
- * After successful arbitration for the memory port, the SEECS bit of 
- * the SEECTL register is connected to the chip select.  The SEECK, 
- * SEEDO, and SEEDI are connected to the clock, data out, and data in 
- * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
- * gives us an 800 nsec timer.  After a write to the SEECTL register, 
- * the SEERDY goes high 800 nsec later.  The one exception to this is 
- * when we first request access to the memory port.  The SEERDY goes 
- * high to signify that access has been granted and, for this case, has 
- * no implied timing.
- *
- * See 93cx6.c for detailed information on the protocol necessary to 
- * read the serial EEPROM.
- */
-#define SEECTL                 0x01e
-#define                EXTARBACK       0x80
-#define                EXTARBREQ       0x40
-#define                SEEMS           0x20
-#define                SEERDY          0x10
-#define                SEECS           0x08
-#define                SEECK           0x04
-#define                SEEDO           0x02
-#define                SEEDI           0x01
-
-/* ---------------------- Scratch RAM Offsets ------------------------- */
-/* These offsets are either to values that are initialized by the board's
- * BIOS or are specified by the sequencer code.
- *
- * The host adapter card (at least the BIOS) uses 20-2f for SCSI
- * device information, 32-33 and 5a-5f as well. As it turns out, the
- * BIOS trashes 20-2f, writing the synchronous negotiation results
- * on top of the BIOS values, so we re-use those for our per-target
- * scratchspace (actually a value that can be copied directly into
- * SCSIRATE).  The kernel driver will enable synchronous negotiation
- * for all targets that have a value other than 0 in the lower four
- * bits of the target scratch space.  This should work regardless of
- * whether the bios has been installed.
- */
+#define        BCTL                            0x84
+#define                ACE                     0x08
+#define                ENABLE                  0x01
 
-/*
- * 1 byte per target starting at this address for configuration values
- */
-#define TARG_SCRATCH           0x020
+#define        DSCOMMAND0                      0x84
+#define                CACHETHEN               0x80
+#define                DPARCKEN                0x40
+#define                MPARCKEN                0x20
+#define                EXTREQLCK               0x10
+#define                INTSCBRAMSEL            0x08
+#define                RAMPS                   0x04
+#define                USCBSIZE32              0x02
+#define                CIOPARCKEN              0x01
+
+#define        BUSTIME                         0x85
+#define                BOFF                    0xf0
+#define                BON                     0x0f
 
-/*
- * The sequencer will stick the first byte of any rejected message here so
- * we can see what is getting thrown away.  Extended messages put the
- * extended message type in REJBYTE_EXT.
- */
-#define REJBYTE                        0x030
-#define REJBYTE_EXT            0x031
+#define        BUSSPD                          0x86
+#define                DFTHRSH                 0xc0
+#define                STBOFF                  0x38
+#define                STBON                   0x07
 
-/*
- * Bit vector of targets that have disconnection disabled.
- */
-#define        DISC_DSB                0x032
-#define                DISC_DSB_A      0x032
-#define                DISC_DSB_B      0x033
+#define        HS_MAILBOX                      0x86
+#define                HOST_MAILBOX            0xf0
+#define                SEQ_MAILBOX             0x0f
+
+#define        DSPCISTATUS                     0x86
+#define                DFTHRSH_100             0xc0
+
+#define        HCNTRL                          0x87
+#define                POWRDN                  0x40
+#define                SWINT                   0x10
+#define                IRQMS                   0x08
+#define                PAUSE                   0x04
+#define                INTEN                   0x02
+#define                CHIPRST                 0x01
+#define                CHIPRSTACK              0x01
+
+#define        HADDR                           0x88
+
+#define        HCNT                            0x8c
+
+#define        SCBPTR                          0x90
+
+#define        INTSTAT                         0x91
+#define                SEQINT_MASK             0xf1
+#define                DATA_OVERRUN            0xf1
+#define                MSGIN_PHASEMIS          0xe1
+#define                TRACEPOINT              0xd1
+#define                PERR_DETECTED           0xb1
+#define                HOST_MSG_LOOP           0xa1
+#define                TRACE_POINT             0x91
+#define                RESIDUAL                0x81
+#define                BAD_STATUS              0x71
+#define                UPDATE_TMSG_REQ         0x61
+#define                NO_MATCH                0x31
+#define                NO_IDENT                0x21
+#define                SEND_REJECT             0x11
+#define                INT_PEND                0x0f
+#define                BRKADRINT               0x08
+#define                SCSIINT                 0x04
+#define                CMDCMPLT                0x02
+#define                BAD_PHASE               0x01
+#define                SEQINT                  0x01
 
-/*
- * Length of pending message
- */
-#define MSG_LEN                        0x034
-
-/* We reserve 8bytes to store outgoing messages */
-#define MSG0                   0x035
-#define                COMP_MSG0       0xcb      /* 2's complement of MSG0 */
-#define MSG1                   0x036
-#define MSG2                   0x037
-#define MSG3                   0x038
-#define MSG4                   0x039
-#define MSG5                   0x03a
-#define MSG6                   0x03b
-#define MSG7                   0x03c
+#define        CLRINT                          0x92
+#define                CLRPARERR               0x10
+#define                CLRBRKADRINT            0x08
+#define                CLRSCSIINT              0x04
+#define                CLRCMDINT               0x02
+#define                CLRSEQINT               0x01
 
-/*
- * These are offsets into the card's scratch ram.  Some of the values are
- * specified in the AHA2742 technical reference manual and are initialized
- * by the BIOS at boot time.
- */
-#define LASTPHASE              0x03d
-#define ARG_1                  0x03e
-#define RETURN_1               0x03f
-#define                SEND_MSG        0x80
-#define                SEND_SENSE      0x40
-#define                SEND_REJ        0x20
-#define                SCB_PAGEDIN     0x10
-
-#define SIGSTATE               0x040
-
-#define DMAPARAMS              0x041   /* Parameters for DMA Logic */
-
-#define        SG_COUNT                0x042
-#define        SG_NEXT                 0x043   /* working value of SG pointer */
-#define                SG_NEXT0        0x043
-#define                SG_NEXT1        0x044
-#define                SG_NEXT2        0x045
-#define                SG_NEXT3        0x046
-
-#define        SCBCOUNT                0x047   /*
-                                        * Number of SCBs supported by
-                                        * this card.
-                                        */
-#define        COMP_SCBCOUNT           0x048   /*
-                                        * Two's complement of SCBCOUNT
-                                        */
-#define QCNTMASK               0x049   /*
-                                        * Mask of bits to test against
-                                        * when looking at the Queue Count
-                                        * registers.  Works around a bug
-                                        * on aic7850 chips. 
-                                        */
-#define FLAGS                  0x04a
-#define                SINGLE_BUS      0x00
-#define                TWIN_BUS        0x01
-#define                WIDE_BUS        0x02
-#define                PAGESCBS        0x04
-#define                DPHASE          0x10
-#define                SELECTED        0x20
-#define                IDENTIFY_SEEN   0x40
-#define                RESELECTED      0x80
-
-#define        SAVED_TCL               0x04b   /*
-                                        * Temporary storage for the
-                                        * target/channel/lun of a
-                                        * reconnecting target
-                                        */
-#define        ACTIVE_A                0x04c
-#define        ACTIVE_B                0x04d
-#define WAITING_SCBH           0x04e   /*
-                                        * head of list of SCBs awaiting
-                                        * selection
-                                        */
-#define DISCONNECTED_SCBH      0x04f   /*
-                                        * head of list of SCBs that are
-                                        * disconnected.  Used for SCB
-                                        * paging.
-                                        */
-#define                SCB_LIST_NULL   0xff
-
-#define SAVED_LINKPTR          0x050
-#define SAVED_SCBPTR           0x051
-#define ULTRA_ENB              0x052
-#define ULTRA_ENB_B            0x053
-
-#define MSGIN_EXT_LEN          0x054
-#define MSGIN_EXT_OPCODE       0x055
-#define MSGIN_EXT_BYTE0                0x056
-#define MSGIN_EXT_BYTE1                0x057
-#define        MSGIN_EXT_LASTBYTE      0x058   /*
-                                        * We don't use this location, but
-                                        * continue to store bytes until
-                                        * we reach this address (avoids
-                                        * a more complicated compare).
-                                        * So, we can store at most 2
-                                        * bytes for now.
-                                        */
-
-#define SCSICONF               0x05a
-#define                RESET_SCSI      0x40
-
-#define HOSTCONF               0x05d
-
-#define HA_274_BIOSCTRL                0x05f
-#define BIOSMODE               0x30
-#define BIOSDISABLED           0x30
-#define CHANNEL_B_PRIMARY      0x08
-
-/* WDTR Message values */
-#define        BUS_8_BIT               0x00
-#define BUS_16_BIT             0x01
-#define BUS_32_BIT             0x02
-
-#define MAX_OFFSET_8BIT                0x0f
-#define MAX_OFFSET_16BIT       0x08
+#define        ERROR                           0x92
+#define                CIOPARERR               0x80
+#define                PCIERRSTAT              0x40
+#define                MPARERR                 0x20
+#define                DPARERR                 0x10
+#define                SQPARERR                0x08
+#define                ILLOPCODE               0x04
+#define                ILLSADDR                0x02
+#define                ILLHADDR                0x01
+
+#define        DFCNTRL                         0x93
+
+#define        DFSTATUS                        0x94
+#define                PRELOAD_AVAIL           0x80
+#define                DWORDEMP                0x20
+#define                MREQPEND                0x10
+#define                HDONE                   0x08
+#define                DFTHRESH                0x04
+#define                FIFOFULL                0x02
+#define                FIFOEMP                 0x01
+
+#define        DFWADDR                         0x95
+
+#define        DFRADDR                         0x97
+
+#define        DFDAT                           0x99
+
+#define        SCBCNT                          0x9a
+#define                SCBAUTO                 0x80
+#define                SCBCNT_MASK             0x1f
+
+#define        QINFIFO                         0x9b
+
+#define        QINCNT                          0x9c
+
+#define        QOUTFIFO                        0x9d
+
+#define        CRCCONTROL1                     0x9d
+#define                CRCONSEEN               0x80
+#define                CRCVALCHKEN             0x40
+#define                CRCENDCHKEN             0x20
+#define                CRCREQCHKEN             0x10
+#define                TARGCRCENDEN            0x08
+#define                TARGCRCCNTEN            0x04
+
+#define        QOUTCNT                         0x9e
+
+#define        SCSIPHASE                       0x9e
+#define                STATUS_PHASE            0x20
+#define                COMMAND_PHASE           0x10
+#define                MSG_IN_PHASE            0x08
+#define                MSG_OUT_PHASE           0x04
+#define                DATA_IN_PHASE           0x02
+#define                DATA_OUT_PHASE          0x01
+
+#define        SFUNCT                          0x9f
+#define                ALT_MODE                0x80
+
+#define        SCB_CONTROL                     0xa0
+#define                TARGET_SCB              0x80
+#define                DISCENB                 0x40
+#define                TAG_ENB                 0x20
+#define                MK_MESSAGE              0x10
+#define                ULTRAENB                0x08
+#define                DISCONNECTED            0x04
+#define                SCB_TAG_TYPE            0x03
+
+#define        SCB_BASE                        0xa0
+
+#define        SCB_TCL                         0xa1
+#define                TID                     0xf0
+#define                SELBUSB                 0x08
+#define                LID                     0x07
+
+#define        SCB_TARGET_STATUS               0xa2
+
+#define        SCB_SGCOUNT                     0xa3
+
+#define        SCB_SGPTR                       0xa4
+
+#define        SCB_RESID_SGCNT                 0xa8
+
+#define        SCB_RESID_DCNT                  0xa9
+
+#define        SCB_DATAPTR                     0xac
+
+#define        SCB_DATACNT                     0xb0
+
+#define        SCB_CMDPTR                      0xb4
+#define        SCB_TARGET_PHASES               0xb4
+#define                TARGET_DATA_IN          0x01
+
+#define        SCB_CMDLEN                      0xb8
+#define        SCB_INITIATOR_TAG               0xb8
+
+#define        SCB_TAG                         0xb9
+
+#define        SCB_NEXT                        0xba
+
+#define        SCB_SCSIRATE                    0xbb
+
+#define        SCB_SCSIOFFSET                  0xbc
+
+#define        SCB_SPARE                       0xbd
+
+#define        SCB_CMDSTORE                    0xc0
+
+#define        SEECTL_2840                     0xc0
+#define                CS_2840                 0x04
+#define                CK_2840                 0x02
+#define                DO_2840                 0x01
+
+#define        STATUS_2840                     0xc1
+#define                EEPROM_TF               0x80
+#define                BIOS_SEL                0x60
+#define                ADSEL                   0x1e
+#define                DI_2840                 0x01
+
+#define        SCB_CMDSTORE_BUSADDR            0xd0
+
+#define        SCB_64BYTE_SPARE                0xd4
+
+#define        CCHADDR                         0xe0
+
+#define        CCHCNT                          0xe8
+
+#define        CCSGRAM                         0xe9
+
+#define        CCSGADDR                        0xea
+
+#define        CCSGCTL                         0xeb
+#define                CCSGDONE                0x80
+#define                CCSGEN                  0x08
+#define                FLAG                    0x02
+#define                CCSGRESET               0x01
+
+#define        CCSCBRAM                        0xec
+
+#define        CCSCBADDR                       0xed
+
+#define        CCSCBCTL                        0xee
+#define                CCSCBDONE               0x80
+#define                ARRDONE                 0x40
+#define                CCARREN                 0x10
+#define                CCSCBEN                 0x08
+#define                CCSCBDIR                0x04
+#define                CCSCBRESET              0x01
+
+#define        CCSCBCNT                        0xef
+
+#define        SCBBADDR                        0xf0
+
+#define        CCSCBPTR                        0xf1
+
+#define        HNSCB_QOFF                      0xf4
+
+#define        SNSCB_QOFF                      0xf6
+
+#define        SDSCB_QOFF                      0xf8
+
+#define        QOFF_CTLSTA                     0xfa
+#define                SCB_AVAIL               0x40
+#define                SNSCB_ROLLOVER          0x20
+#define                SDSCB_ROLLOVER          0x10
+#define                SCB_QSIZE               0x07
+#define                SCB_QSIZE_256           0x06
+
+#define        DFF_THRSH                       0xfb
+#define                WR_DFTHRSH              0x70
+#define                WR_DFTHRSH_MAX          0x70
+#define                WR_DFTHRSH_90           0x60
+#define                WR_DFTHRSH_85           0x50
+#define                WR_DFTHRSH_75           0x40
+#define                WR_DFTHRSH_63           0x30
+#define                WR_DFTHRSH_50           0x20
+#define                WR_DFTHRSH_25           0x10
+#define                RD_DFTHRSH_MAX          0x07
+#define                RD_DFTHRSH              0x07
+#define                RD_DFTHRSH_90           0x06
+#define                RD_DFTHRSH_85           0x05
+#define                RD_DFTHRSH_75           0x04
+#define                RD_DFTHRSH_63           0x03
+#define                RD_DFTHRSH_50           0x02
+#define                RD_DFTHRSH_25           0x01
+#define                RD_DFTHRSH_MIN          0x00
+#define                WR_DFTHRSH_MIN          0x00
+
+#define        SG_CACHEPTR                     0xfc
+#define                SG_USER_DATA            0xfc
+#define                LAST_SEG                0x02
+#define                LAST_SEG_DONE           0x01
+
+
+#define        CMD_GROUP_CODE_SHIFT    0x05
+#define        BUS_8_BIT       0x00
+#define        QOUTFIFO_OFFSET 0x00
+#define        CCSGRAM_MAXSEGS 0x10
+#define        SCB_64BYTE_SIZE 0x30
+#define        STATUS_QUEUE_FULL       0x28
+#define        STATUS_BUSY     0x08
+#define        TQINFIFO_UPDATE_CNT     0x20
+#define        TCL_TARGET_SHIFT        0x04
+#define        MAX_OFFSET_8BIT 0x0f
+#define        BUS_16_BIT      0x01
+#define        QINFIFO_OFFSET  0x01
+#define        SCB_32BYTE_SIZE 0x1c
+#define        HOST_MAILBOX_SHIFT      0x04
+#define        MAX_OFFSET_ULTRA2       0x7f
+#define        MAX_OFFSET_16BIT        0x08
+#define        UNTAGGEDSCB_OFFSET      0x02
+#define        TARGET_CMD_CMPLT        0xfe
+#define        SCB_LIST_NULL   0xff
+#define        SG_SIZEOF       0x08
+#define        SEQ_MAILBOX_SHIFT       0x00
+#define        HOST_MSG        0xff
+#define        BUS_32_BIT      0x02
+#define        CCSGADDR_MAX    0x80
+
+
+/* Downloaded Constant Definitions */
index d2c4c50..ae51091 100644 (file)
@@ -1,25 +1,23 @@
-/*     $OpenBSD: aic7xxxvar.h,v 1.10 1997/04/10 22:52:20 deraadt Exp $ */
-/*     $NetBSD: aic7xxxvar.h,v 1.10 1996/10/21 22:34:09 thorpej Exp $  */
 /*
  * Interface to the generic driver for the aic7xxx based adaptec
  * SCSI controllers.  This is used to implement product specific
  * probe and attach routines.
  *
- * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
+ * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000 Justin T. Gibbs.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.15 2000/01/07 23:08:18 gibbs Exp $
+ * $OpenBSD: aic7xxxvar.h,v 1.11 2000/03/22 02:48:47 smurph Exp $
  */
 
-#ifndef _AIC7XXX_H_
-#define _AIC7XXX_H_
+#ifndef _AIC7XXXVAR_H_
+#define _AIC7XXXVAR_H_
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
 
-#if defined(__FreeBSD__)
-#include "ahc.h"                /* for NAHC from config */
+#ifndef TRUE
+#define TRUE 1
 #endif
 
-#if defined(__NetBSD__) || defined(__OpenBSD__)
 /*
  * convert FreeBSD's <sys/queue.h> symbols to NetBSD's
  */
        SIMPLEQ_REMOVE_HEAD(head, (head)->sqh_first, field)
 #define        stqh_first              sqh_first
 #define        stqe_next               sqe_next
-#endif
 
-#if defined(__FreeBSD__)
-#define        AHC_INB(ahc, port)      \
-       inb((ahc)->baseport+(port))
-#define        AHC_INSB(ahc, port, valp, size) \
-       insb((ahc)->baseport+(port), valp, size)
-#define        AHC_OUTB(ahc, port, val)        \
-       outb((ahc)->baseport+(port), val)
-#define        AHC_OUTSB(ahc, port, valp, size)        \
-       outsb((ahc)->baseport+(port), valp, size)
-#define        AHC_OUTSL(ahc, port, valp, size)        \
-       outsl((ahc)->baseport+(port), valp, size)
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-#define        AHC_INB(ahc, port)      \
-       bus_space_read_1((ahc)->sc_iot, (ahc)->sc_ioh, port)
-#define        AHC_INSB(ahc, port, valp, size) \
-       bus_space_read_multi_1((ahc)->sc_iot, (ahc)->sc_ioh, port, (u_int8_t *) valp, size)
-#define        AHC_OUTB(ahc, port, val)        \
-       bus_space_write_1((ahc)->sc_iot, (ahc)->sc_ioh, port, val)
-#define        AHC_OUTSB(ahc, port, valp, size)        \
-       bus_space_write_multi_1((ahc)->sc_iot, (ahc)->sc_ioh, port, (u_int8_t *) valp, size)
-#define        AHC_OUTSL(ahc, port, valp, size)        \
-       bus_space_write_multi_4((ahc)->sc_iot, (ahc)->sc_ioh, port, (u_int32_t *) valp, size)
-#endif
+/*
+ * The maximum transfer per S/G segment.
+ */
+#define AHC_MAXTRANSFER_SIZE    0x00ffffff     /* limited by 24bit counter */
 
-#define        AHC_NSEG        256     /* number of dma segments supported */
+/*
+ * The number of dma segments supported.  The current implementation limits
+ * us to 255 S/G entries (this may change to be unlimited at some point).
+ * To reduce the driver's memory consumption, we further limit the number
+ * supported to be sufficient to handle the largest mapping supported by
+ * the kernel, MAXPHYS.  Assuming the transfer is as fragmented as possible
+ * and unaligned, this turns out to be the number of paged sized transfers
+ * in MAXPHYS plus an extra element to handle any unaligned residual.
+ */
+#define AHC_NSEG (MIN(btoc(MAXPHYS) + 1, 255))
 
 #define AHC_SCB_MAX    255     /*
                                 * Up to 255 SCBs on some types of aic7xxx
                                 * aic7850 has only 3.
                                 */
 
-
-typedef u_int32_t physaddr;
-#if defined(__FreeBSD__)
-extern u_long ahc_unit;
-#endif
+#define AHC_TMODE_CMDS 256    /*
+                               * Ring Buffer of incoming target commands.
+                               * We allocate 256 to simplify the logic
+                               * in the sequencer by using the natural
+                               * wrap point of an 8bit counter.
+                               */
 
 struct ahc_dma_seg {
-       physaddr        addr;
+       u_int32_t       addr;
        u_int32_t       len;
 };
 
 typedef enum {
-       AHC_NONE        = 0x000,
-       AHC_ULTRA       = 0x001,        /* Supports 20MHz Transfers */
-       AHC_WIDE        = 0x002,        /* Wide Channel */
-       AHC_TWIN        = 0x008,        /* Twin Channel */
-       AHC_AIC7770     = 0x010,
-       AHC_AIC7850     = 0x020,
-       AHC_AIC7860     = 0x021,        /* ULTRA version of the aic7850 */
-       AHC_AIC7870     = 0x040,
-       AHC_AIC7880     = 0x041,
-       AHC_AIC78X0     = 0x060,        /* PCI Based Controller */
-       AHC_274         = 0x110,        /* EISA Based Controller */
-       AHC_284         = 0x210,        /* VL/ISA Based Controller */
-       AHC_294AU       = 0x421,        /* aic7860 based '2940' */
-       AHC_294         = 0x440,        /* PCI Based Controller */
-       AHC_294U        = 0x441,        /* ULTRA PCI Based Controller */
-       AHC_394         = 0x840,        /* Twin Channel PCI Controller */
-       AHC_394U        = 0x841,        /* Twin, ULTRA Channel PCI Controller */
-}ahc_type;
+       AHC_NONE        = 0x0000,
+       AHC_CHIPID_MASK = 0x00FF,
+       AHC_AIC7770     = 0x0001,
+       AHC_AIC7850     = 0x0002,
+       AHC_AIC7855     = 0x0003,
+       AHC_AIC7859     = 0x0004,
+       AHC_AIC7860     = 0x0005,
+       AHC_AIC7870     = 0x0006,
+       AHC_AIC7880     = 0x0007,
+       AHC_AIC7890     = 0x0008,
+       AHC_AIC7892     = 0x0009,
+       AHC_AIC7895     = 0x000a,
+       AHC_AIC7896     = 0x000b,
+       AHC_AIC7899     = 0x000c,
+       AHC_VL          = 0x0100,       /* Bus type VL */
+       AHC_EISA        = 0x0200,       /* Bus type EISA */
+       AHC_PCI         = 0x0400,       /* Bus type PCI */
+       AHC_BUS_MASK    = 0x0F00
+} ahc_chip;
+
+extern char *ahc_chip_names[];
 
 typedef enum {
-       AHC_FNONE               = 0x00,
-       AHC_INIT                = 0x01,
-       AHC_RUNNING             = 0x02,
-       AHC_PAGESCBS            = 0x04, /* Enable SCB paging */
-       AHC_CHANNEL_B_PRIMARY   = 0x08, /*
+       AHC_FENONE      = 0x0000,
+       AHC_ULTRA       = 0x0001,       /* Supports 20MHz Transfers */
+       AHC_ULTRA2      = 0x0002,       /* Supports 40MHz Transfers */
+       AHC_WIDE        = 0x0004,       /* Wide Channel */
+       AHC_TWIN        = 0x0008,       /* Twin Channel */
+       AHC_MORE_SRAM   = 0x0010,       /* 80 bytes instead of 64 */
+       AHC_CMD_CHAN    = 0x0020,       /* Has a Command DMA Channel */
+       AHC_QUEUE_REGS  = 0x0040,       /* Has Queue management registers */
+       AHC_SG_PRELOAD  = 0x0080,       /* Can perform auto-SG preload */
+       AHC_SPIOCAP     = 0x0100,       /* Has a Serial Port I/O Cap Register */
+       AHC_MULTI_TID   = 0x0200,       /* Has bitmask of TIDs for select-in */
+       AHC_HS_MAILBOX  = 0x0400,       /* Has HS_MAILBOX register */
+       AHC_DT          = 0x0800,       /* Double Transition transfers */
+       AHC_NEW_TERMCTL = 0x1000,
+       AHC_MULTI_FUNC  = 0x2000,       /* Multi-Function Twin Channel Device */
+       AHC_TARG_DMABUG = 0x4000,       /* WideOdd Data-In bug in TMODE */
+       AHC_AIC7770_FE  = AHC_TARG_DMABUG,
+       AHC_AIC7850_FE  = AHC_TARG_DMABUG|AHC_SPIOCAP,
+       AHC_AIC7855_FE  = AHC_AIC7850_FE,
+       AHC_AIC7859_FE  = AHC_AIC7850_FE|AHC_ULTRA,
+       AHC_AIC7860_FE  = AHC_AIC7859_FE,
+       AHC_AIC7870_FE  = AHC_TARG_DMABUG,
+       AHC_AIC7880_FE  = AHC_TARG_DMABUG|AHC_ULTRA,
+       AHC_AIC7890_FE  = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|AHC_QUEUE_REGS
+                         |AHC_SG_PRELOAD|AHC_MULTI_TID|AHC_HS_MAILBOX
+                         |AHC_NEW_TERMCTL,
+       AHC_AIC7892_FE  = AHC_AIC7890_FE|AHC_DT,
+       AHC_AIC7895_FE  = AHC_AIC7880_FE|AHC_MORE_SRAM
+                         |AHC_CMD_CHAN|AHC_MULTI_FUNC,
+       AHC_AIC7895C_FE = AHC_AIC7895_FE|AHC_MULTI_TID,
+       AHC_AIC7896_FE  = AHC_AIC7890_FE|AHC_MULTI_FUNC,
+       AHC_AIC7899_FE  = AHC_AIC7892_FE|AHC_MULTI_FUNC
+} ahc_feature;
+
+typedef enum {
+       AHC_FNONE               = 0x000,
+       AHC_PAGESCBS            = 0x001,/* Enable SCB paging */
+       AHC_CHANNEL_B_PRIMARY   = 0x002,/*
                                         * On twin channel adapters, probe
                                         * channel B first since it is the
                                         * primary bus.
                                         */
-       AHC_USEDEFAULTS         = 0x10, /*
+       AHC_USEDEFAULTS         = 0x004,/*
                                         * For cards without an seeprom
                                         * or a BIOS to initialize the chip's
                                         * SRAM, we use the default target
                                         * settings.
                                         */
-       AHC_CHNLB               = 0x20, /* 
-                                        * Second controller on 3940 
-                                        * Also encodes the offset in the
-                                        * SEEPROM for CHNLB info (32)
-                                        */
-}ahc_flag;
+       AHC_SHARED_SRAM         = 0x010,
+       AHC_LARGE_SEEPROM       = 0x020,/* Uses C56_66 not C46 */
+       AHC_RESET_BUS_A         = 0x040,
+       AHC_RESET_BUS_B         = 0x080,
+       AHC_EXTENDED_TRANS_A    = 0x100,
+       AHC_EXTENDED_TRANS_B    = 0x200,
+       AHC_TERM_ENB_A          = 0x400,
+       AHC_TERM_ENB_B          = 0x800,
+       AHC_INITIATORMODE       = 0x1000,/*
+                                         * Allow initiator operations on
+                                         * this controller.
+                                         */
+       AHC_TARGETMODE          = 0x2000,/*
+                                         * Allow target operations on this
+                                         * controller.
+                                         */
+       AHC_NEWEEPROM_FMT       = 0x4000,
+       AHC_RESOURCE_SHORTAGE   = 0x8000,
+       AHC_TQINFIFO_BLOCKED    = 0x10000,/* Blocked waiting for ATIOs */
+       AHC_INT50_SPEEDFLEX     = 0x20000,/*
+                                          * Internal 50pin connector
+                                          * sits behind an aic3860
+                                          */
+} ahc_flag;
 
 typedef enum {
        SCB_FREE                = 0x0000,
-       SCB_ACTIVE              = 0x0001,
-       SCB_ABORTED             = 0x0002,
+       SCB_OTHERTCL_TIMEOUT    = 0x0002,/*
+                                         * Another device was active
+                                         * during the first timeout for
+                                         * this SCB so we gave ourselves
+                                         * an additional timeout period
+                                         * in case it was hogging the
+                                         * bus.
+                                         */
        SCB_DEVICE_RESET        = 0x0004,
-       SCB_IMMED               = 0x0008,
-       SCB_SENSE               = 0x0010,
-       SCB_TIMEDOUT            = 0x0020,
-       SCB_QUEUED_FOR_DONE     = 0x0040,
-       SCB_PAGED_OUT           = 0x0080,
-       SCB_WAITINGQ            = 0x0100,
-       SCB_ASSIGNEDQ           = 0x0200,
-       SCB_SENTORDEREDTAG      = 0x0400,
-       SCB_MSGOUT_SDTR         = 0x0800,
-       SCB_MSGOUT_WDTR         = 0x1000
-}scb_flag;
+       SCB_SENSE               = 0x0008,
+       SCB_FREEZE_QUEUE        = 0x0010,
+       SCB_REQUEUE             = 0x0020,
+       SCB_RECOVERY_SCB        = 0x0040,
+       SCB_ABORT               = 0x1000,
+       SCB_QUEUED_MSG          = 0x2000,
+       SCB_ACTIVE              = 0x4000,
+       SCB_TARGET_IMMEDIATE    = 0x8000
+} scb_flag;
 
 /*
- * The driver keeps up to MAX_SCB scb structures per card in memory.  Only the
- * first 28 bytes of the structure need to be transfered to the card during
- * normal operation.  The fields starting at byte 28 are used for kernel level
- * bookkeeping.  
+ * The driver keeps up to MAX_SCB scb structures per card in memory.  The SCB
+ * consists of a "hardware SCB" mirroring the fields availible on the card
+ * and additional information the kernel stores for each transaction.
  */
-struct scb {
-/* ------------    Begin hardware supported fields    ---------------- */
-/*0*/   u_char control;
-/*1*/  u_char tcl;             /* 4/1/3 bits */
-/*2*/  u_char status;
-/*3*/  u_char SG_segment_count;
-/*4*/  physaddr SG_list_pointer;
-/*8*/  u_char residual_SG_segment_count;
-/*9*/  u_char residual_data_count[3];
-/*12*/ physaddr data;
-/*16*/  u_int32_t datalen;             /* Really only three bits, but its
+struct hardware_scb {
+/*0*/   u_int8_t  control;
+/*1*/  u_int8_t  tcl;          /* 4/1/3 bits */
+/*2*/  u_int8_t  status;
+/*3*/  u_int8_t  SG_count;
+/*4*/  u_int32_t SG_pointer;
+/*8*/  u_int8_t  residual_SG_count;
+/*9*/  u_int8_t  residual_data_count[3];
+/*12*/ u_int32_t data;
+/*16*/ u_int32_t datalen;              /* Really only three bytes, but its
                                         * faster to treat it as a long on
                                         * a quad boundary.
                                         */
-/*20*/ physaddr cmdpointer;
-/*24*/ u_char cmdlen;
-/*25*/ u_char tag;                     /* Index into our kernel SCB array.
+/*20*/ u_int32_t cmdpointer;
+/*24*/ u_int8_t  cmdlen;
+/*25*/ u_int8_t  tag;                  /* Index into our kernel SCB array.
                                         * Also used as the tag for tagged I/O
                                         */
-#define SCB_PIO_TRANSFER_SIZE  26      /* amount we need to upload/download
-                                        * via PIO to initialize a transaction.
-                                        */
-/*26*/ u_char next;                    /* Used for threading SCBs in the
+/*26*/ u_int8_t  next;                 /* Used for threading SCBs in the
                                         * "Waiting for Selection" and
                                         * "Disconnected SCB" lists down
                                         * in the sequencer.
                                         */
-/*27*/ u_char prev;
-/*-----------------end of hardware supported fields----------------*/
-       STAILQ_ENTRY(scb)       links;  /* for chaining */
+/*27*/ u_int8_t  scsirate;             /* Value for SCSIRATE register */
+/*28*/ u_int8_t  scsioffset;           /* Value for SCSIOFFSET register */
+/*29*/ u_int8_t  spare[3];             /*
+                                        * Spare space available on
+                                        * all controller types.
+                                        */
+/*32*/ u_int8_t  cmdstore[16];         /*
+                                        * CDB storage for controllers
+                                        * supporting 64 byte SCBs.
+                                        */
+/*48*/ u_int32_t cmdstore_busaddr;     /*
+                                        * Address of command store for
+                                        * 32byte SCB adapters
+                                        */
+/*48*/ u_int8_t  spare_64[12];         /*
+                                        * Pad to 64 bytes.
+                                        */
+};
+
+struct scb {
+       struct  hardware_scb    *hscb;
+       SLIST_ENTRY(scb)         links;  /* for chaining */
+       LIST_ENTRY(scb)  pend_links;     /* for pending scbs*/
        struct scsi_xfer *xs;   /* the scsi_xfer for this cmd */
-       scb_flag flags;
-       u_char  position;       /* Position in card's scbarray */
-       struct ahc_dma_seg ahc_dma[AHC_NSEG];
-       struct scsi_sense sense_cmd;    /* SCSI command block */
+       scb_flag                 flags;
+       bus_dmamap_t             dmamap;
+       struct  ahc_dma_seg     *sg_list;
+       bus_addr_t               sg_list_phys;
+       u_int                    sg_count;/* How full ahc_dma_seg is */
+};
+
+/*
+ * Connection desciptor for select-in requests in target mode.
+ * The first byte is the connecting target, followed by identify
+ * message and optional tag information, terminated by 0xFF.  The
+ * remainder is the command to execute.  The cmd_valid byte is on
+ * an 8 byte boundary to simplify setting it on aic7880 hardware
+ * which only has limited direct access to the DMA FIFO.
+ */
+struct target_cmd {
+       u_int8_t initiator_channel;
+       u_int8_t targ_id;       /* Target ID we were selected at */
+       u_int8_t identify;      /* Identify message */
+       u_int8_t bytes[21];
+       u_int8_t cmd_valid;
+       u_int8_t pad[7];
+};
+
+/*
+ * Number of events we can buffer up if we run out
+ * of immediate notify ccbs.
+ */
+#define AHC_TMODE_EVENT_BUFFER_SIZE 8
+struct ahc_tmode_event {
+       u_int8_t initiator_id;
+       u_int8_t event_type;    /* MSG type or EVENT_TYPE_BUS_RESET */
+#define        EVENT_TYPE_BUS_RESET 0xFF
+       u_int8_t event_arg;
+};
+
+/*
+ * Per lun target mode state including accept TIO CCB
+ * and immediate notify CCB pools.
+ */
+struct tmode_lstate {
+       u_int8_t not_yet;
+};
+
+#define AHC_TRANS_CUR          0x01    /* Modify current neogtiation status */
+#define AHC_TRANS_ACTIVE       0x03    /* Assume this is the active target */
+#define AHC_TRANS_GOAL         0x04    /* Modify negotiation goal */
+#define AHC_TRANS_USER         0x08    /* Modify user negotiation settings */
+
+struct ahc_transinfo {
+       u_int8_t width;
+       u_int8_t period;
+       u_int8_t offset;
+       u_int8_t ppr_flags;
+};
+
+struct ahc_initiator_tinfo {
+       u_int8_t scsirate;
+       struct ahc_transinfo current;
+       struct ahc_transinfo goal;
+       struct ahc_transinfo user;
+};
+
+/*
+ * Per target mode enabled target state.  Esentially just an array of
+ * pointers to lun target state as well as sync/wide negotiation information
+ * for each initiator<->target mapping (including the mapping for when we
+ * are the initiator).
+ */
+struct tmode_tstate {
+       struct ahc_initiator_tinfo      transinfo[16];
+
+       /*
+        * Per initiator state bitmasks.
+        */
+       u_int16_t                ultraenb;      /* Using ultra sync rate  */
+       u_int16_t                discenable;    /* Disconnection allowed  */
+       u_int16_t                tagenable;     /* Tagged Queuing allowed */
 };
 
-struct ahc_data {
-#if defined(__FreeBSD__)
-       int     unit;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#define ALL_TARGETS -1
+#define ALL_LUNS -1
+
+/*
+ * Define the format of the aic7XXX SEEPROM registers (16 bits).
+ */
+
+struct seeprom_config {
+/*
+ * SCSI ID Configuration Flags
+ */
+       u_int16_t device_flags[16];     /* words 0-15 */
+#define                CFXFER          0x0007  /* synchronous transfer rate */
+#define                CFSYNCH         0x0008  /* enable synchronous transfer */
+#define                CFDISC          0x0010  /* enable disconnection */
+#define                CFWIDEB         0x0020  /* wide bus device */
+#define                CFSYNCHISULTRA  0x0040  /* CFSYNCH is an ultra offset (2940AU)*/
+#define                CFSYNCSINGLE    0x0080  /* Single-Transition signalling */
+#define                CFSTART         0x0100  /* send start unit SCSI command */
+#define                CFINCBIOS       0x0200  /* include in BIOS scan */
+#define                CFRNFOUND       0x0400  /* report even if not found */
+#define                CFMULTILUN      0x0800  /* Probe multiple luns in BIOS scan */
+#define                CFWBCACHEENB    0x4000  /* Enable W-Behind Cache on disks */
+#define                CFWBCACHENOP    0xc000  /* Don't touch W-Behind Cache */
+
+/*
+ * BIOS Control Bits
+ */
+       u_int16_t bios_control;         /* word 16 */
+#define                CFSUPREM        0x0001  /* support all removeable drives */
+#define                CFSUPREMB       0x0002  /* support removeable boot drives */
+#define                CFBIOSEN        0x0004  /* BIOS enabled */
+/*             UNUSED          0x0008  */
+#define                CFSM2DRV        0x0010  /* support more than two drives */
+#define                CF284XEXTEND    0x0020  /* extended translation (284x cards) */ 
+/*             UNUSED          0x0040  */
+#define                CFEXTEND        0x0080  /* extended translation enabled */
+/*             UNUSED          0xff00  */
+
+/*
+ * Host Adapter Control Bits
+ */
+       u_int16_t adapter_control;      /* word 17 */   
+#define                CFAUTOTERM      0x0001  /* Perform Auto termination */
+#define                CFULTRAEN       0x0002  /* Ultra SCSI speed enable */
+#define                CF284XSELTO     0x0003  /* Selection timeout (284x cards) */
+#define                CF284XFIFO      0x000C  /* FIFO Threshold (284x cards) */
+#define                CFSTERM         0x0004  /* SCSI low byte termination */
+#define                CFWSTERM        0x0008  /* SCSI high byte termination */
+#define                CFSPARITY       0x0010  /* SCSI parity */
+#define                CF284XSTERM     0x0020  /* SCSI low byte term (284x cards) */   
+#define                CFRESETB        0x0040  /* reset SCSI bus at boot */
+#define                CFCHNLBPRIMARY  0x0100  /* aic7895 probe B channel first */
+#define                CFSEAUTOTERM    0x0400  /* aic7890 Perform SE Auto Termination*/
+#define                CFLVDSTERM      0x0800  /* aic7890 LVD Termination */
+/*             UNUSED          0xf280  */
+
+/*
+ * Bus Release, Host Adapter ID
+ */
+       u_int16_t brtime_id;            /* word 18 */
+#define                CFSCSIID        0x000f  /* host adapter SCSI ID */
+/*             UNUSED          0x00f0  */
+#define                CFBRTIME        0xff00  /* bus release time */
+
+/*
+ * Maximum targets
+ */
+       u_int16_t max_targets;          /* word 19 */   
+#define                CFMAXTARG       0x00ff  /* maximum targets */
+/*             UNUSED          0xff00  */
+       u_int16_t res_1[11];            /* words 20-30 */
+       u_int16_t checksum;             /* word 31 */
+};
+
+struct ahc_syncrate {
+       int sxfr_u2;
+       int sxfr;
+       /* Rates in Ultra mode have bit 8 of sxfr set */
+#define                ULTRA_SXFR 0x100
+#define                ST_SXFR    0x010
+       u_int8_t period; /* Period to send to SCSI target */
+       char *rate;
+};
+
+typedef enum {
+       MSG_TYPE_NONE                   = 0x00,
+       MSG_TYPE_INITIATOR_MSGOUT       = 0x01,
+       MSG_TYPE_INITIATOR_MSGIN        = 0x02,
+       MSG_TYPE_TARGET_MSGOUT          = 0x03,
+       MSG_TYPE_TARGET_MSGIN           = 0x04
+} ahc_msg_type;
+
+struct sg_map_node {
+       bus_dmamap_t             sg_dmamap;
+       bus_addr_t               sg_physaddr;
+       bus_dma_segment_t        sg_dmasegs;
+       int                      sg_nseg;
+       struct ahc_dma_seg*      sg_vaddr;
+       SLIST_ENTRY(sg_map_node) links;
+};
+       
+struct scb_data {
+       struct  hardware_scb    *hscbs;     /* Array of hardware SCBs */
+       struct  scb *scbarray;              /* Array of kernel SCBs */
+       SLIST_HEAD(, scb) free_scbs;    /*
+                                        * Pool of SCBs ready to be assigned
+                                        * commands to execute.
+                                        */
+       struct  scsi_sense_data *sense; /* Per SCB sense data */
+
+       /*
+        * "Bus" addresses of our data structures.
+        */
+       bus_dmamap_t     hscb_dmamap;
+       bus_addr_t       hscb_busaddr;
+       bus_dma_segment_t hscb_seg;
+       int               hscb_nseg;
+       int               hscb_size;
+
+       bus_dmamap_t     sense_dmamap;
+       bus_addr_t       sense_busaddr;
+       bus_dma_segment_t sense_seg;
+       int               sense_nseg;
+       int               sense_size;
+
+       SLIST_HEAD(, sg_map_node) sg_maps;
+       u_int8_t        numscbs;
+       u_int8_t        maxhscbs;       /* Number of SCBs on the card */
+       u_int8_t        init_level;     /*
+                                        * How far we've initialized
+                                        * this structure.
+                                        */
+};
+
+struct ahc_softc {
        struct device sc_dev;
        void    *sc_ih;
        bus_space_tag_t sc_iot;
        bus_space_handle_t sc_ioh;
+       bus_dma_tag_t           sc_dmat;
+       bus_dmamap_t            sc_dmamap_fifo; /* maps the FIFOs */
+       bus_dma_tag_t            buffer_dmat;   /* dmat for buffer I/O */
+       struct scb_data         *scb_data;
+       void    *pci_data;                      /* for pci config read/write */
+       int     (*pci_intr_func) __P((struct ahc_softc *));     /* for pci error interrupts  */
        LIST_HEAD(, scsi_xfer) sc_xxxq; /* XXX software request queue */
        struct scsi_xfer *sc_xxxqlast;  /* last entry in queue */
-#endif
-       ahc_type type;
-       ahc_flag flags;
-#if defined(__FreeBSD__)
-       u_long  baseport;
-#endif
-       struct  scb *scbarray[AHC_SCB_MAX]; /* Mirror boards scbarray */
-       struct  scb *pagedout_ntscbs[16];/* 
-                                         * Paged out, non-tagged scbs
-                                         * indexed by target.
-                                         */
-       STAILQ_HEAD(, scb) free_scbs;   /*
-                                        * SCBs assigned to free slots
-                                        * on the card. (no paging required)
-                                        */
-       STAILQ_HEAD(, scb) page_scbs;   /*
-                                        * SCBs that will require paging
-                                        * before use (no assigned slot)
-                                        */
-       STAILQ_HEAD(, scb) waiting_scbs;/*
-                                        * SCBs waiting to be paged in
-                                        * and started.
-                                        */
-       STAILQ_HEAD(, scb)assigned_scbs;/*
-                                        * SCBs that were waiting but have
-                                        * now been assigned a slot by
-                                        * ahc_free_scb.
-                                        */
+       
+       int                     queue_blocked;
+       u_int16_t               devqueue_blocked[16];
+       u_int8_t                inited_targets[16];
+
+       /*
+        * SCBs that have been send to the controller
+        */
+       LIST_HEAD(, scb)         pending_scbs;
+
+       /*
+        * Target mode related state kept on a per enabled lun basis.
+        * Targets that are not enabled will have null entries.
+        * As an initiator, we keep one target entry for our initiator
+        * ID to store our sync/wide transfer settings.
+        */
+       struct tmode_tstate*     enabled_targets[16];
+
+       /*
+        * The black hole device responsible for handling requests for
+        * disabled luns on enabled targets.
+        */
+       struct tmode_lstate*     black_hole;
+
+       /*
+        * Device instance currently on the bus awaiting a continue TIO
+        * for a command that was not given the disconnect priveledge.
+        */
+       struct tmode_lstate*     pending_device;
+
+       /*
+        * Card characteristics
+        */
+       ahc_chip                 chip;
+       ahc_feature              features;
+       ahc_flag                 flags;
+
+       /* Values to store in the SEQCTL register for pause and unpause */
+       u_int8_t                 unpause;
+       u_int8_t                 pause;
+
+       /* Command Queues */
+       u_int8_t                 qoutfifonext;
+       u_int8_t                 qinfifonext;
+       u_int8_t                *qoutfifo;
+       u_int8_t                *qinfifo;
+
+       /*
+        * 256 byte array storing the SCBID of outstanding
+        * untagged SCBs indexed by TCL.
+        */     
+       u_int8_t                 *untagged_scbs;
+
+       /*
+        * Hooks into the XPT.
+        */
        struct  scsi_link sc_link;
        struct  scsi_link sc_link_b;    /* Second bus for Twin channel cards */
-       u_short needsdtr_orig;          /* Targets we initiate sync neg with */
-       u_short needwdtr_orig;          /* Targets we initiate wide neg with */
-       u_short needsdtr;               /* Current list of negotiated targets */
-       u_short needwdtr;               /* Current list of negotiated targets */
-       u_short sdtrpending;            /* Pending SDTR to these targets */
-       u_short wdtrpending;            /* Pending WDTR to these targets */
-       u_short tagenable;              /* Targets that can handle tagqueing */
-       u_short orderedtag;             /* Targets to use ordered tag on */
-       u_short discenable;             /* Targets allowed to disconnect */
-       u_char  our_id;                 /* our scsi id */
-       u_char  our_id_b;               /* B channel scsi id */
-       u_char  numscbs;
-       u_char  activescbs;
-       u_char  maxhscbs;               /* Number of SCBs on the card */
-       u_char  maxscbs;                /*
-                                        * Max SCBs we allocate total including
-                                        * any that will force us to page SCBs
-                                        */
-       u_char  qcntmask;
-       u_char  unpause;
-       u_char  pause;
-       u_char  in_timeout;
+
+       int                      unit;
+
+       /* Channel Names ('A', 'B', etc.) */
+       char                     channel;
+       char                     channel_b;
+
+       /* Initiator Bus ID */
+       u_int8_t                 our_id;
+       u_int8_t                 our_id_b;
+
+       /* Targets that need negotiation messages */
+       u_int16_t                targ_msg_req;
+
+       /*
+        * Target incoming command FIFO.
+        */
+       struct target_cmd       *targetcmds;
+       u_int8_t                 tqinfifonext;
+
+       /*
+        * Incoming and outgoing message handling.
+        */
+       u_int8_t                 send_msg_perror;
+       ahc_msg_type             msg_type;
+       u_int8_t                 msgout_buf[8]; /* Message we are sending */
+       u_int8_t                 msgin_buf[8];  /* Message we are receiving */
+       u_int                    msgout_len;    /* Length of message to send */
+       u_int                    msgout_index;  /* Current index in msgout */
+       u_int                    msgin_index;   /* Current index in msgin */
+
+       void                    *ih;
+       bus_dmamap_t             shared_data_dmamap;
+       bus_addr_t               shared_data_busaddr;
+       bus_dma_segment_t        shared_data_seg;
+       int                      shared_data_nseg;
+       int                      shared_data_size;
+
+       /* Number of enabled target mode device on this card */
+       u_int                    enabled_luns;
+
+       /* Initialization level of this data structure */
+       u_int                    init_level;
+
+       u_int16_t                user_discenable;/* Disconnection allowed  */
+       u_int16_t                user_tagenable; /* Tagged Queuing allowed */
+
 };
 
 /* #define AHC_DEBUG */
@@ -280,28 +620,36 @@ struct ahc_data {
 extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */
 #endif
 
-#if defined(__FreeBSD__)
-
-char *ahc_name __P((struct ahc_data *ahc));
-
-void ahc_reset __P((u_long iobase));
-struct ahc_data *ahc_alloc __P((int unit, u_long io_base, ahc_type type, ahc_flag flags));
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-
 #define        ahc_name(ahc)   (ahc)->sc_dev.dv_xname
 
-void   ahc_reset __P((char *devname, bus_space_tag_t iot,
-           bus_space_handle_t ioh));
-void   ahc_construct __P((struct ahc_data *ahc, bus_space_tag_t iot,
-           bus_space_handle_t ioh, ahc_type type, ahc_flag flags));
-#endif
-void   ahc_free __P((struct ahc_data *));
-int    ahc_init __P((struct ahc_data *));
-int    ahc_attach __P((struct ahc_data *));
-#if defined(__FreeBSD__)
-void   ahc_intr __P((void *arg));
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
+void   ahc_construct __P((struct ahc_softc *ahc, bus_space_tag_t iot,
+               bus_space_handle_t ioh, ahc_chip chip, ahc_flag flags, 
+               ahc_feature features, u_char channel));
+int   ahc_probe_scbs __P((struct ahc_softc *ahc));
+void   ahc_free __P((struct ahc_softc *));
+int    ahc_init __P((struct ahc_softc *));
+int    ahc_attach __P((struct ahc_softc *));
 int    ahc_intr __P((void *arg));
-#endif
+int    ahc_reset __P((struct ahc_softc *ahc));
+void  ahc_xxx_reset __P((char *devname, bus_space_tag_t iot, bus_space_handle_t ioh));
+#define ahc_isa_reset ahc_xxx_reset
+#define ahc_eisa_reset ahc_xxx_reset
+
+#define        AHC_INB(ahc, port)      \
+       bus_space_read_1((ahc)->sc_iot, (ahc)->sc_ioh, port)
+#define        AHC_INSB(ahc, port, valp, size) \
+       bus_space_read_multi_1((ahc)->sc_iot, (ahc)->sc_ioh, port, (u_int8_t *) valp, size)
+#define        AHC_OUTB(ahc, port, val)        \
+       bus_space_write_1((ahc)->sc_iot, (ahc)->sc_ioh, port, val)
+#define        AHC_OUTSB(ahc, port, valp, size)        \
+       bus_space_write_multi_1((ahc)->sc_iot, (ahc)->sc_ioh, port, (u_int8_t *) valp, size)
+#define        AHC_OUTSL(ahc, port, valp, size)        \
+       bus_space_write_multi_4((ahc)->sc_iot, (ahc)->sc_ioh, port, (u_int32_t *) valp, size)
+
+#define ahc_inb AHC_INB
+#define ahc_insb AHC_INSB
+#define ahc_outb AHC_OUTB
+#define ahc_outsb AHC_OUTSB
+#define ahc_outsl AHC_OUTSL
 
-#endif  /* _AIC7XXX_H_ */
+#endif  /* _AIC7XXXVAR_H_ */