Merge remote-tracking branch 'mkp-scsi/4.5/scsi-queue' into misc
authorJames Bottomley <James.Bottomley@HansenPartnership.com>
Thu, 14 Jan 2016 00:29:30 +0000 (16:29 -0800)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Thu, 14 Jan 2016 00:29:30 +0000 (16:29 -0800)
26 files changed:
drivers/scsi/3w-xxxx.c
drivers/scsi/Kconfig
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/arm/cumana_1.c
drivers/scsi/arm/oak.c
drivers/scsi/atari_NCR5380.c
drivers/scsi/atari_scsi.c
drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
drivers/scsi/dmx3191d.c
drivers/scsi/dtc.c
drivers/scsi/dtc.h
drivers/scsi/g_NCR5380.c
drivers/scsi/g_NCR5380.h
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
drivers/scsi/imm.c
drivers/scsi/ipr.c
drivers/scsi/mac_scsi.c
drivers/scsi/megaraid/megaraid_mm.c
drivers/scsi/pas16.c
drivers/scsi/pas16.h
drivers/scsi/scsi_devinfo.c
drivers/scsi/storvsc_drv.c
drivers/scsi/sun3_scsi.c
drivers/scsi/t128.c
drivers/scsi/t128.h

index 2940bd7..25aba16 100644 (file)
@@ -1045,6 +1045,9 @@ static int tw_chrdev_open(struct inode *inode, struct file *file)
 static const struct file_operations tw_fops = {
        .owner          = THIS_MODULE,
        .unlocked_ioctl = tw_chrdev_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = tw_chrdev_ioctl,
+#endif
        .open           = tw_chrdev_open,
        .release        = NULL,
        .llseek         = noop_llseek,
index c1fe0d2..23d862d 100644 (file)
@@ -1620,23 +1620,6 @@ config ATARI_SCSI
          ST-DMA, replacing ACSI).  It does NOT support other schemes, like
          in the Hades (without DMA).
 
-config ATARI_SCSI_TOSHIBA_DELAY
-       bool "Long delays for Toshiba CD-ROMs"
-       depends on ATARI_SCSI
-       help
-         This option increases the delay after a SCSI arbitration to
-         accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to
-         use a Toshiba CD-ROM drive; otherwise, the option is not needed and
-         would impact performance a bit, so say N.
-
-config ATARI_SCSI_RESET_BOOT
-       bool "Reset SCSI-devices at boottime"
-       depends on ATARI_SCSI
-       help
-         Reset the devices on your Atari whenever it boots.  This makes the
-         boot process fractionally longer but may assist recovery from errors
-         that leave the devices with SCSI operations partway completed.
-
 config MAC_SCSI
        tristate "Macintosh NCR5380 SCSI"
        depends on MAC && SCSI=y
index a777e5c..d728672 100644 (file)
@@ -1,17 +1,17 @@
-/* 
+/*
  * NCR 5380 generic driver routines.  These should make it *trivial*
- *      to implement 5380 SCSI drivers under Linux with a non-trantor
- *      architecture.
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
  *
- *      Note that these routines also work with NR53c400 family chips.
+ * Note that these routines also work with NR53c400 family chips.
  *
  * Copyright 1993, Drew Eckhardt
- *      Visionary Computing 
- *      (Unix and Linux consulting and custom programming)
- *      drew@colorado.edu
- *      +1 (303) 666-5836
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
  *
- * For more information, please consult 
+ * For more information, please consult
  *
  * NCR 5380 Family
  * SCSI Protocol Controller
  */
 
 /*
- * Revision 1.10 1998/9/2      Alan Cox
- *                             (alan@lxorguk.ukuu.org.uk)
- * Fixed up the timer lockups reported so far. Things still suck. Looking 
- * forward to 2.3 and per device request queues. Then it'll be possible to
- * SMP thread this beast and improve life no end.
- * Revision 1.9  1997/7/27     Ronald van Cuijlenborg
- *                             (ronald.van.cuijlenborg@tip.nl or nutty@dds.nl)
- * (hopefully) fixed and enhanced USLEEP
- * added support for DTC3181E card (for Mustek scanner)
- *
-
- * Revision 1.8                        Ingmar Baumgart
- *                             (ingmar@gonzo.schwaben.de)
- * added support for NCR53C400a card
- *
-
- * Revision 1.7  1996/3/2       Ray Van Tassle (rayvt@comm.mot.com)
- * added proc_info
- * added support needed for DTC 3180/3280
- * fixed a couple of bugs
- *
-
- * Revision 1.5  1994/01/19  09:14:57  drew
- * Fixed udelay() hack that was being used on DATAOUT phases
- * instead of a proper wait for the final handshake.
- *
- * Revision 1.4  1994/01/19  06:44:25  drew
- * *** empty log message ***
- *
- * Revision 1.3  1994/01/19  05:24:40  drew
- * Added support for TCR LAST_BYTE_SENT bit.
- *
- * Revision 1.2  1994/01/15  06:14:11  drew
- * REAL DMA support, bug fixes.
- *
- * Revision 1.1  1994/01/15  06:00:54  drew
- * Initial revision
- *
+ * With contributions from Ray Van Tassle, Ingmar Baumgart,
+ * Ronald van Cuijlenborg, Alan Cox and others.
  */
 
 /*
- * Further development / testing that should be done : 
+ * Further development / testing that should be done :
  * 1.  Cleanup the NCR5380_transfer_dma function and DMA operation complete
- *     code so that everything does the same thing that's done at the 
- *     end of a pseudo-DMA read operation.
+ * code so that everything does the same thing that's done at the
+ * end of a pseudo-DMA read operation.
  *
  * 2.  Fix REAL_DMA (interrupt driven, polled works fine) -
- *     basically, transfer size needs to be reduced by one 
- *     and the last byte read as is done with PSEUDO_DMA.
- * 
- * 4.  Test SCSI-II tagged queueing (I have no devices which support 
- *      tagged queueing)
- *
- * 5.  Test linked command handling code after Eric is ready with 
- *      the high level code.
+ * basically, transfer size needs to be reduced by one
+ * and the last byte read as is done with PSEUDO_DMA.
+ *
+ * 4.  Test SCSI-II tagged queueing (I have no devices which support
+ * tagged queueing)
  */
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_transport_spi.h>
-
-#if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x,y) {printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
-#define REMOVE(w,x,y,z) {printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); }
-#else
-#define LIST(x,y)
-#define REMOVE(w,x,y,z)
-#endif
 
 #ifndef notyet
-#undef LINKED
 #undef REAL_DMA
 #endif
 
-#ifdef REAL_DMA_POLL
-#undef READ_OVERRUNS
-#define READ_OVERRUNS
-#endif
-
 #ifdef BOARD_REQUIRES_NO_DELAY
 #define io_recovery_delay(x)
 #else
 /*
  * Design
  *
- * This is a generic 5380 driver.  To use it on a different platform, 
+ * This is a generic 5380 driver.  To use it on a different platform,
  * one simply writes appropriate system specific macros (ie, data
- * transfer - some PC's will use the I/O bus, 68K's must use 
+ * transfer - some PC's will use the I/O bus, 68K's must use
  * memory mapped) and drops this file in their 'C' wrapper.
  *
- * (Note from hch:  unfortunately it was not enough for the different
- * m68k folks and instead of improving this driver they copied it
- * and hacked it up for their needs.  As a consequence they lost
- * most updates to this driver.  Maybe someone will fix all these
- * drivers to use a common core one day..)
- *
- * As far as command queueing, two queues are maintained for 
+ * As far as command queueing, two queues are maintained for
  * each 5380 in the system - commands that haven't been issued yet,
- * and commands that are currently executing.  This means that an 
- * unlimited number of commands may be queued, letting 
- * more commands propagate from the higher driver levels giving higher 
- * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported, 
- * allowing multiple commands to propagate all the way to a SCSI-II device 
+ * and commands that are currently executing.  This means that an
+ * unlimited number of commands may be queued, letting
+ * more commands propagate from the higher driver levels giving higher
+ * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported,
+ * allowing multiple commands to propagate all the way to a SCSI-II device
  * while a command is already executing.
  *
  *
- * Issues specific to the NCR5380 : 
- *
- * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 
- * piece of hardware that requires you to sit in a loop polling for 
- * the REQ signal as long as you are connected.  Some devices are 
- * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 
- * while doing long seek operations.
- * 
- * The workaround for this is to keep track of devices that have
- * disconnected.  If the device hasn't disconnected, for commands that
- * should disconnect, we do something like 
+ * Issues specific to the NCR5380 :
  *
- * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- * 
- * Some tweaking of N and M needs to be done.  An algorithm based 
- * on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these 
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+ * piece of hardware that requires you to sit in a loop polling for
+ * the REQ signal as long as you are connected.  Some devices are
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
+ * while doing long seek operations. [...] These
  * broken devices are the exception rather than the rule and I'd rather
  * spend my time optimizing for the normal case.
  *
  * which is started from a workqueue for each NCR5380 host in the
  * system.  It attempts to establish I_T_L or I_T_L_Q nexuses by
  * removing the commands from the issue queue and calling
- * NCR5380_select() if a nexus is not established. 
+ * NCR5380_select() if a nexus is not established.
  *
  * Once a nexus is established, the NCR5380_information_transfer()
  * phase goes through the various phases as instructed by the target.
  * if the target goes into MSG IN and sends a DISCONNECT message,
  * the command structure is placed into the per instance disconnected
- * queue, and NCR5380_main tries to find more work.  If the target is 
+ * queue, and NCR5380_main tries to find more work.  If the target is
  * idle for too long, the system will try to sleep.
  *
  * If a command has disconnected, eventually an interrupt will trigger,
  * calling NCR5380_intr()  which will in turn call NCR5380_reselect
  * to reestablish a nexus.  This will run main if necessary.
  *
- * On command termination, the done function will be called as 
+ * On command termination, the done function will be called as
  * appropriate.
  *
- * SCSI pointers are maintained in the SCp field of SCSI command 
+ * SCSI pointers are maintained in the SCp field of SCSI command
  * structures, being initialized after the command is connected
  * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
  * Note that in violation of the standard, an implicit SAVE POINTERS operation
 /*
  * Using this file :
  * This file a skeleton Linux SCSI driver for the NCR 5380 series
- * of chips.  To use it, you write an architecture specific functions 
+ * of chips.  To use it, you write an architecture specific functions
  * and macros and include this file in your driver.
  *
- * These macros control options : 
- * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be 
- *      defined.
- * 
+ * These macros control options :
+ * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be
+ * defined.
+ *
  * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- *      for commands that return with a CHECK CONDITION status. 
+ * for commands that return with a CHECK CONDITION status.
  *
  * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
- *      transceivers. 
+ * transceivers.
  *
  * DONT_USE_INTR - if defined, never use interrupts, even if we probe or
- *      override-configure an IRQ.
- *
- * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
- *      bytes at a time.  Since interrupts are disabled by default during
- *      these transfers, we might need this to give reasonable interrupt
- *      service time if the transfer size gets too large.
- *
- * LINKED - if defined, linked commands are supported.
+ * override-configure an IRQ.
  *
  * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
  *
  * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
  *
  * REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't
- *      rely on phase mismatch and EOP interrupts to determine end 
- *      of phase.
- *
- * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
- *          only really want to use this if you're having a problem with
- *          dropped characters during high speed communications, and even
- *          then, you're going to be better off twiddling with transfersize
- *          in the high level code.
- *
- * Defaults for these will be provided although the user may want to adjust 
- * these to allocate CPU resources to the SCSI driver or "real" code.
- * 
- * USLEEP_SLEEP - amount of time, in jiffies, to sleep
- *
- * USLEEP_POLL - amount of time, in jiffies, to poll
+ * rely on phase mismatch and EOP interrupts to determine end
+ * of phase.
  *
  * These macros MUST be defined :
- * NCR5380_local_declare() - declare any local variables needed for your
- *      transfer routines.
  *
- * NCR5380_setup(instance) - initialize any local variables needed from a given
- *      instance of the host adapter for NCR5380_{read,write,pread,pwrite}
- * 
  * NCR5380_read(register)  - read from the specified register
  *
- * NCR5380_write(register, value) - write to the specific register 
+ * NCR5380_write(register, value) - write to the specific register
  *
- * NCR5380_implementation_fields  - additional fields needed for this 
- *      specific implementation of the NCR5380
+ * NCR5380_implementation_fields  - additional fields needed for this
+ * specific implementation of the NCR5380
  *
  * Either real DMA *or* pseudo DMA may be implemented
- * REAL functions : 
+ * REAL functions :
  * NCR5380_REAL_DMA should be defined if real DMA is to be used.
- * Note that the DMA setup functions should return the number of bytes 
- *      that they were able to program the controller for.
+ * Note that the DMA setup functions should return the number of bytes
+ * that they were able to program the controller for.
  *
- * Also note that generic i386/PC versions of these macros are 
- *      available as NCR5380_i386_dma_write_setup,
- *      NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ * Also note that generic i386/PC versions of these macros are
+ * available as NCR5380_i386_dma_write_setup,
+ * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
  *
  * NCR5380_dma_write_setup(instance, src, count) - initialize
  * NCR5380_dma_read_setup(instance, dst, count) - initialize
  * NCR5380_pread(instance, dst, count);
  *
  * The generic driver is initialized by calling NCR5380_init(instance),
- * after setting the appropriate host specific fields and ID.  If the 
+ * after setting the appropriate host specific fields and ID.  If the
  * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
  * possible) function may be used.
  */
 
-static int do_abort(struct Scsi_Host *host);
-static void do_reset(struct Scsi_Host *host);
+static int do_abort(struct Scsi_Host *);
+static void do_reset(struct Scsi_Host *);
 
-/*
- *     initialize_SCp          -       init the scsi pointer field
- *     @cmd: command block to set up
+/**
+ * initialize_SCp - init the scsi pointer field
+ * @cmd: command block to set up
  *
- *     Set up the internal fields in the SCSI command.
+ * Set up the internal fields in the SCSI command.
  */
 
 static inline void initialize_SCp(struct scsi_cmnd *cmd)
 {
-       /* 
-        * Initialize the Scsi Pointer field so that all of the commands in the 
+       /*
+        * Initialize the Scsi Pointer field so that all of the commands in the
         * various queues are valid.
         */
 
@@ -295,120 +198,123 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
                cmd->SCp.ptr = NULL;
                cmd->SCp.this_residual = 0;
        }
+
+       cmd->SCp.Status = 0;
+       cmd->SCp.Message = 0;
 }
 
 /**
- *     NCR5380_poll_politely   -       wait for NCR5380 status bits
- *     @instance: controller to poll
- *     @reg: 5380 register to poll
- *     @bit: Bitmask to check
- *     @val: Value required to exit
- *
- *     Polls the NCR5380 in a reasonably efficient manner waiting for
- *     an event to occur, after a short quick poll we begin giving the
- *     CPU back in non IRQ contexts
- *
- *     Returns the value of the register or a negative error code.
+ * NCR5380_poll_politely2 - wait for two chip register values
+ * @instance: controller to poll
+ * @reg1: 5380 register to poll
+ * @bit1: Bitmask to check
+ * @val1: Expected value
+ * @reg2: Second 5380 register to poll
+ * @bit2: Second bitmask to check
+ * @val2: Second expected value
+ * @wait: Time-out in jiffies
+ *
+ * Polls the chip in a reasonably efficient manner waiting for an
+ * event to occur. After a short quick poll we begin to yield the CPU
+ * (if possible). In irq contexts the time-out is arbitrarily limited.
+ * Callers may hold locks as long as they are held in irq mode.
+ *
+ * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT.
  */
-static int NCR5380_poll_politely(struct Scsi_Host *instance, int reg, int bit, int val, int t)
+
+static int NCR5380_poll_politely2(struct Scsi_Host *instance,
+                                  int reg1, int bit1, int val1,
+                                  int reg2, int bit2, int val2, int wait)
 {
-       NCR5380_local_declare();
-       int n = 500;            /* At about 8uS a cycle for the cpu access */
-       unsigned long end = jiffies + t;
-       int r;
-       
-       NCR5380_setup(instance);
-
-       while( n-- > 0)
-       {
-               r = NCR5380_read(reg);
-               if((r & bit) == val)
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       unsigned long deadline = jiffies + wait;
+       unsigned long n;
+
+       /* Busy-wait for up to 10 ms */
+       n = min(10000U, jiffies_to_usecs(wait));
+       n *= hostdata->accesses_per_ms;
+       n /= 2000;
+       do {
+               if ((NCR5380_read(reg1) & bit1) == val1)
+                       return 0;
+               if ((NCR5380_read(reg2) & bit2) == val2)
                        return 0;
                cpu_relax();
-       }
-       
-       /* t time yet ? */
-       while(time_before(jiffies, end))
-       {
-               r = NCR5380_read(reg);
-               if((r & bit) == val)
+       } while (n--);
+
+       if (irqs_disabled() || in_interrupt())
+               return -ETIMEDOUT;
+
+       /* Repeatedly sleep for 1 ms until deadline */
+       while (time_is_after_jiffies(deadline)) {
+               schedule_timeout_uninterruptible(1);
+               if ((NCR5380_read(reg1) & bit1) == val1)
+                       return 0;
+               if ((NCR5380_read(reg2) & bit2) == val2)
                        return 0;
-               if(!in_interrupt())
-                       cond_resched();
-               else
-                       cpu_relax();
        }
+
        return -ETIMEDOUT;
 }
 
-static struct {
-       unsigned char value;
-       const char *name;
-} phases[] __maybe_unused = {
-       {PHASE_DATAOUT, "DATAOUT"}, 
-       {PHASE_DATAIN, "DATAIN"}, 
-       {PHASE_CMDOUT, "CMDOUT"}, 
-       {PHASE_STATIN, "STATIN"}, 
-       {PHASE_MSGOUT, "MSGOUT"}, 
-       {PHASE_MSGIN, "MSGIN"}, 
-       {PHASE_UNKNOWN, "UNKNOWN"}
-};
+static inline int NCR5380_poll_politely(struct Scsi_Host *instance,
+                                        int reg, int bit, int val, int wait)
+{
+       return NCR5380_poll_politely2(instance, reg, bit, val,
+                                               reg, bit, val, wait);
+}
 
 #if NDEBUG
 static struct {
        unsigned char mask;
        const char *name;
-} signals[] = { 
-       {SR_DBP, "PARITY"}, 
-       {SR_RST, "RST"}, 
-       {SR_BSY, "BSY"}, 
-       {SR_REQ, "REQ"}, 
-       {SR_MSG, "MSG"}, 
-       {SR_CD, "CD"}, 
-       {SR_IO, "IO"}, 
-       {SR_SEL, "SEL"}, 
+} signals[] = {
+       {SR_DBP, "PARITY"},
+       {SR_RST, "RST"},
+       {SR_BSY, "BSY"},
+       {SR_REQ, "REQ"},
+       {SR_MSG, "MSG"},
+       {SR_CD, "CD"},
+       {SR_IO, "IO"},
+       {SR_SEL, "SEL"},
        {0, NULL}
-}, 
+},
 basrs[] = {
-       {BASR_ATN, "ATN"}, 
-       {BASR_ACK, "ACK"}, 
+       {BASR_ATN, "ATN"},
+       {BASR_ACK, "ACK"},
        {0, NULL}
-}, 
-icrs[] = { 
-       {ICR_ASSERT_RST, "ASSERT RST"}, 
-       {ICR_ASSERT_ACK, "ASSERT ACK"}, 
-       {ICR_ASSERT_BSY, "ASSERT BSY"}, 
-       {ICR_ASSERT_SEL, "ASSERT SEL"}, 
-       {ICR_ASSERT_ATN, "ASSERT ATN"}, 
-       {ICR_ASSERT_DATA, "ASSERT DATA"}, 
+},
+icrs[] = {
+       {ICR_ASSERT_RST, "ASSERT RST"},
+       {ICR_ASSERT_ACK, "ASSERT ACK"},
+       {ICR_ASSERT_BSY, "ASSERT BSY"},
+       {ICR_ASSERT_SEL, "ASSERT SEL"},
+       {ICR_ASSERT_ATN, "ASSERT ATN"},
+       {ICR_ASSERT_DATA, "ASSERT DATA"},
        {0, NULL}
-}, 
-mrs[] = { 
-       {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, 
-       {MR_TARGET, "MODE TARGET"}, 
-       {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, 
-       {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, 
-       {MR_MONITOR_BSY, "MODE MONITOR BSY"}, 
-       {MR_DMA_MODE, "MODE DMA"}, 
-       {MR_ARBITRATE, "MODE ARBITRATION"}, 
+},
+mrs[] = {
+       {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"},
+       {MR_TARGET, "MODE TARGET"},
+       {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"},
+       {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"},
+       {MR_ENABLE_EOP_INTR, "MODE EOP INTR"},
+       {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+       {MR_DMA_MODE, "MODE DMA"},
+       {MR_ARBITRATE, "MODE ARBITRATION"},
        {0, NULL}
 };
 
 /**
- *     NCR5380_print   -       print scsi bus signals
- *     @instance:      adapter state to dump
- *
- *     Print the SCSI bus signals for debugging purposes
+ * NCR5380_print - print scsi bus signals
+ * @instance: adapter state to dump
  *
- *     Locks: caller holds hostdata lock (not essential)
+ * Print the SCSI bus signals for debugging purposes
  */
 
 static void NCR5380_print(struct Scsi_Host *instance)
 {
-       NCR5380_local_declare();
        unsigned char status, data, basr, mr, icr, i;
-       NCR5380_setup(instance);
 
        data = NCR5380_read(CURRENT_SCSI_DATA_REG);
        status = NCR5380_read(STATUS_REG);
@@ -435,117 +341,56 @@ static void NCR5380_print(struct Scsi_Host *instance)
        printk("\n");
 }
 
+static struct {
+       unsigned char value;
+       const char *name;
+} phases[] = {
+       {PHASE_DATAOUT, "DATAOUT"},
+       {PHASE_DATAIN, "DATAIN"},
+       {PHASE_CMDOUT, "CMDOUT"},
+       {PHASE_STATIN, "STATIN"},
+       {PHASE_MSGOUT, "MSGOUT"},
+       {PHASE_MSGIN, "MSGIN"},
+       {PHASE_UNKNOWN, "UNKNOWN"}
+};
 
-/* 
- *     NCR5380_print_phase     -       show SCSI phase
- *     @instance: adapter to dump
- *
- *     Print the current SCSI phase for debugging purposes
+/**
+ * NCR5380_print_phase - show SCSI phase
+ * @instance: adapter to dump
  *
- *     Locks: none
+ * Print the current SCSI phase for debugging purposes
  */
 
 static void NCR5380_print_phase(struct Scsi_Host *instance)
 {
-       NCR5380_local_declare();
        unsigned char status;
        int i;
-       NCR5380_setup(instance);
 
        status = NCR5380_read(STATUS_REG);
        if (!(status & SR_REQ))
-               printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no);
+               shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n");
        else {
-               for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
-               printk("scsi%d : phase %s\n", instance->host_no, phases[i].name);
+               for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+                    (phases[i].value != (status & PHASE_MASK)); ++i)
+                       ;
+               shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name);
        }
 }
 #endif
 
-/*
- * These need tweaking, and would probably work best as per-device 
- * flags initialized differently for disk, tape, cd, etc devices.
- * People with broken devices are free to experiment as to what gives
- * the best results for them.
- *
- * USLEEP_SLEEP should be a minimum seek time.
- *
- * USLEEP_POLL should be a maximum rotational latency.
- */
-#ifndef USLEEP_SLEEP
-/* 20 ms (reasonable hard disk speed) */
-#define USLEEP_SLEEP msecs_to_jiffies(20)
-#endif
-/* 300 RPM (floppy speed) */
-#ifndef USLEEP_POLL
-#define USLEEP_POLL msecs_to_jiffies(200)
-#endif
-#ifndef USLEEP_WAITLONG
-/* RvC: (reasonable time to wait on select error) */
-#define USLEEP_WAITLONG USLEEP_SLEEP
-#endif
-
-/* 
- * Function : int should_disconnect (unsigned char cmd)
- *
- * Purpose : decide whether a command would normally disconnect or 
- *      not, since if it won't disconnect we should go to sleep.
- *
- * Input : cmd - opcode of SCSI command
- *
- * Returns : DISCONNECT_LONG if we should disconnect for a really long 
- *      time (ie always, sleep, look for REQ active, sleep), 
- *      DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal
- *      time-to-data delay, DISCONNECT_NONE if this command would return
- *      immediately.
- *
- *      Future sleep algorithms based on time to data can exploit 
- *      something like this so they can differentiate between "normal" 
- *      (ie, read, write, seek) and unusual commands (ie, * format).
- *
- * Note : We don't deal with commands that handle an immediate disconnect,
- *        
- */
 
-static int should_disconnect(unsigned char cmd)
-{
-       switch (cmd) {
-       case READ_6:
-       case WRITE_6:
-       case SEEK_6:
-       case READ_10:
-       case WRITE_10:
-       case SEEK_10:
-               return DISCONNECT_TIME_TO_DATA;
-       case FORMAT_UNIT:
-       case SEARCH_HIGH:
-       case SEARCH_LOW:
-       case SEARCH_EQUAL:
-               return DISCONNECT_LONG;
-       default:
-               return DISCONNECT_NONE;
-       }
-}
-
-static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout)
-{
-       hostdata->time_expires = jiffies + timeout;
-       schedule_delayed_work(&hostdata->coroutine, timeout);
-}
-
-
-static int probe_irq __initdata = 0;
+static int probe_irq __initdata;
 
 /**
- *     probe_intr      -       helper for IRQ autoprobe
- *     @irq: interrupt number
- *     @dev_id: unused
- *     @regs: unused
+ * probe_intr  -       helper for IRQ autoprobe
+ * @irq: interrupt number
+ * @dev_id: unused
+ * @regs: unused
  *
- *     Set a flag to indicate the IRQ in question was received. This is
- *     used by the IRQ probe code.
+ * Set a flag to indicate the IRQ in question was received. This is
+ * used by the IRQ probe code.
  */
+
 static irqreturn_t __init probe_intr(int irq, void *dev_id)
 {
        probe_irq = irq;
@@ -553,24 +398,20 @@ static irqreturn_t __init probe_intr(int irq, void *dev_id)
 }
 
 /**
- *     NCR5380_probe_irq       -       find the IRQ of an NCR5380
- *     @instance: NCR5380 controller
- *     @possible: bitmask of ISA IRQ lines
- *
- *     Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ
- *     and then looking to see what interrupt actually turned up.
+ * NCR5380_probe_irq   -       find the IRQ of an NCR5380
+ * @instance: NCR5380 controller
+ * @possible: bitmask of ISA IRQ lines
  *
- *     Locks: none, irqs must be enabled on entry
+ * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ
+ * and then looking to see what interrupt actually turned up.
  */
 
 static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
                                                int possible)
 {
-       NCR5380_local_declare();
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned long timeout;
        int trying_irqs, i, mask;
-       NCR5380_setup(instance);
 
        for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1)
                if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
@@ -581,7 +422,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
 
        /*
         * A interrupt is triggered whenever BSY = false, SEL = true
-        * and a bit set in the SELECT_ENABLE_REG is asserted on the 
+        * and a bit set in the SELECT_ENABLE_REG is asserted on the
         * SCSI bus.
         *
         * Note that the bus is only driven when the phase control signals
@@ -596,7 +437,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
 
        while (probe_irq == NO_IRQ && time_before(jiffies, timeout))
                schedule_timeout_uninterruptible(1);
-       
+
        NCR5380_write(SELECT_ENABLE_REG, 0);
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
@@ -608,12 +449,10 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
 }
 
 /**
- *     NCR58380_info - report driver and host information
- *     @instance: relevant scsi host instance
- *
- *     For use as the host template info() handler.
+ * NCR58380_info - report driver and host information
+ * @instance: relevant scsi host instance
  *
- *     Locks: none
+ * For use as the host template info() handler.
  */
 
 static const char *NCR5380_info(struct Scsi_Host *instance)
@@ -633,20 +472,14 @@ static void prepare_info(struct Scsi_Host *instance)
                 "can_queue %d, cmd_per_lun %d, "
                 "sg_tablesize %d, this_id %d, "
                 "flags { %s%s%s}, "
-#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
-                "USLEEP_POLL %lu, USLEEP_WAITLONG %lu, "
-#endif
                 "options { %s} ",
                 instance->hostt->name, instance->io_port, instance->n_io_port,
                 instance->base, instance->irq,
                 instance->can_queue, instance->cmd_per_lun,
                 instance->sg_tablesize, instance->this_id,
-                hostdata->flags & FLAG_NCR53C400     ? "NCR53C400 "     : "",
-                hostdata->flags & FLAG_DTC3181E      ? "DTC3181E "      : "",
+                hostdata->flags & FLAG_NO_DMA_FIXUP  ? "NO_DMA_FIXUP "  : "",
                 hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "",
-#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
-                USLEEP_POLL, USLEEP_WAITLONG,
-#endif
+                hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY "  : "",
 #ifdef AUTOPROBE_IRQ
                 "AUTOPROBE_IRQ "
 #endif
@@ -664,47 +497,11 @@ static void prepare_info(struct Scsi_Host *instance)
 #endif
 #ifdef PSEUDO_DMA
                 "PSEUDO_DMA "
-#endif
-#ifdef UNSAFE
-                "UNSAFE "
-#endif
-#ifdef NCR53C400
-                "NCR53C400 "
 #endif
                 "");
 }
 
-/**
- *     NCR5380_print_status    -       dump controller info
- *     @instance: controller to dump
- *
- *     Print commands in the various queues, called from NCR5380_abort 
- *     and NCR5380_debug to aid debugging.
- *
- *     Locks: called functions disable irqs
- */
-
-static void NCR5380_print_status(struct Scsi_Host *instance)
-{
-       NCR5380_dprint(NDEBUG_ANY, instance);
-       NCR5380_dprint_phase(NDEBUG_ANY, instance);
-}
-
 #ifdef PSEUDO_DMA
-/******************************************/
-/*
- * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
- *
- * *buffer: I/O buffer
- * **start: if inout == FALSE pointer into buffer where user read should start
- * offset: current offset
- * length: length of buffer
- * hostno: Scsi_Host host_no
- * inout: TRUE - user is writing; FALSE - user is reading
- *
- * Return the number of bytes read from or written
- */
-
 static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
        char *buffer, int length)
 {
@@ -714,104 +511,41 @@ static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
        hostdata->spin_max_w = 0;
        return 0;
 }
-#endif
-
-static
-void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m);
-static
-void lprint_command(unsigned char *cmd, struct seq_file *m);
-static
-void lprint_opcode(int opcode, struct seq_file *m);
 
 static int __maybe_unused NCR5380_show_info(struct seq_file *m,
-       struct Scsi_Host *instance)
+                                            struct Scsi_Host *instance)
 {
-       struct NCR5380_hostdata *hostdata;
-       struct scsi_cmnd *ptr;
-
-       hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
 
-#ifdef PSEUDO_DMA
        seq_printf(m, "Highwater I/O busy spin counts: write %d, read %d\n",
                hostdata->spin_max_w, hostdata->spin_max_r);
-#endif
-       spin_lock_irq(instance->host_lock);
-       if (!hostdata->connected)
-               seq_printf(m, "scsi%d: no currently connected command\n", instance->host_no);
-       else
-               lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
-       seq_printf(m, "scsi%d: issue_queue\n", instance->host_no);
-       for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
-               lprint_Scsi_Cmnd(ptr, m);
-
-       seq_printf(m, "scsi%d: disconnected_queue\n", instance->host_no);
-       for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
-               lprint_Scsi_Cmnd(ptr, m);
-       spin_unlock_irq(instance->host_lock);
        return 0;
 }
-
-static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
-{
-       seq_printf(m, "scsi%d : destination target %d, lun %llu\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun);
-       seq_puts(m, "        command = ");
-       lprint_command(cmd->cmnd, m);
-}
-
-static void lprint_command(unsigned char *command, struct seq_file *m)
-{
-       int i, s;
-       lprint_opcode(command[0], m);
-       for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
-               seq_printf(m, "%02x ", command[i]);
-       seq_putc(m, '\n');
-}
-
-static void lprint_opcode(int opcode, struct seq_file *m)
-{
-       seq_printf(m, "%2d (0x%02x)", opcode, opcode);
-}
-
+#endif
 
 /**
- *     NCR5380_init    -       initialise an NCR5380
- *     @instance: adapter to configure
- *     @flags: control flags
+ * NCR5380_init - initialise an NCR5380
+ * @instance: adapter to configure
+ * @flags: control flags
  *
- *     Initializes *instance and corresponding 5380 chip,
- *      with flags OR'd into the initial flags value.
+ * Initializes *instance and corresponding 5380 chip,
+ * with flags OR'd into the initial flags value.
  *
- *     Notes : I assume that the host, hostno, and id bits have been
- *      set correctly.  I don't care about the irq and other fields. 
+ * Notes : I assume that the host, hostno, and id bits have been
+ * set correctly. I don't care about the irq and other fields.
  *
- *     Returns 0 for success
- *
- *     Locks: interrupts must be enabled when we are called 
+ * Returns 0 for success
  */
 
 static int NCR5380_init(struct Scsi_Host *instance, int flags)
 {
-       NCR5380_local_declare();
-       int i, pass;
-       unsigned long timeout;
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-
-       if(in_interrupt())
-               printk(KERN_ERR "NCR5380_init called with interrupts off!\n");
-       /* 
-        * On NCR53C400 boards, NCR5380 registers are mapped 8 past 
-        * the base address.
-        */
-
-#ifdef NCR53C400
-       if (flags & FLAG_NCR53C400)
-               instance->NCR5380_instance_name += NCR53C400_address_adjust;
-#endif
-
-       NCR5380_setup(instance);
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       int i;
+       unsigned long deadline;
 
-       hostdata->aborted = 0;
+       hostdata->host = instance;
        hostdata->id_mask = 1 << instance->this_id;
+       hostdata->id_higher_mask = 0;
        for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
                if (i > hostdata->id_mask)
                        hostdata->id_higher_mask |= i;
@@ -820,21 +554,21 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
 #ifdef REAL_DMA
        hostdata->dmalen = 0;
 #endif
-       hostdata->targets_present = 0;
+       spin_lock_init(&hostdata->lock);
        hostdata->connected = NULL;
-       hostdata->issue_queue = NULL;
-       hostdata->disconnected_queue = NULL;
-       
-       INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main);
-       
-       /* The CHECK code seems to break the 53C400. Will check it later maybe */
-       if (flags & FLAG_NCR53C400)
-               hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags;
-       else
-               hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags;
+       hostdata->sensing = NULL;
+       INIT_LIST_HEAD(&hostdata->autosense);
+       INIT_LIST_HEAD(&hostdata->unissued);
+       INIT_LIST_HEAD(&hostdata->disconnected);
 
-       hostdata->host = instance;
-       hostdata->time_expires = 0;
+       hostdata->flags = flags;
+
+       INIT_WORK(&hostdata->main_task, NCR5380_main);
+       hostdata->work_q = alloc_workqueue("ncr5380_%d",
+                               WQ_UNBOUND | WQ_MEM_RECLAIM,
+                               1, instance->host_no);
+       if (!hostdata->work_q)
+               return -ENOMEM;
 
        prepare_info(instance);
 
@@ -843,43 +577,69 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
        NCR5380_write(TARGET_COMMAND_REG, 0);
        NCR5380_write(SELECT_ENABLE_REG, 0);
 
-#ifdef NCR53C400
-       if (hostdata->flags & FLAG_NCR53C400) {
-               NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
-       }
-#endif
+       /* Calibrate register polling loop */
+       i = 0;
+       deadline = jiffies + 1;
+       do {
+               cpu_relax();
+       } while (time_is_after_jiffies(deadline));
+       deadline += msecs_to_jiffies(256);
+       do {
+               NCR5380_read(STATUS_REG);
+               ++i;
+               cpu_relax();
+       } while (time_is_after_jiffies(deadline));
+       hostdata->accesses_per_ms = i / 256;
 
-       /* 
-        * Detect and correct bus wedge problems.
-        *
-        * If the system crashed, it may have crashed in a state 
-        * where a SCSI command was still executing, and the 
-        * SCSI bus is not in a BUS FREE STATE.
-        *
-        * If this is the case, we'll try to abort the currently
-        * established nexus which we know nothing about, and that
-        * failing, do a hard reset of the SCSI bus 
-        */
+       return 0;
+}
+
+/**
+ * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems.
+ * @instance: adapter to check
+ *
+ * If the system crashed, it may have crashed with a connected target and
+ * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the
+ * currently established nexus, which we know nothing about. Failing that
+ * do a bus reset.
+ *
+ * Note that a bus reset will cause the chip to assert IRQ.
+ *
+ * Returns 0 if successful, otherwise -ENXIO.
+ */
+
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       int pass;
 
        for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
                switch (pass) {
                case 1:
                case 3:
                case 5:
-                       printk(KERN_INFO "scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no);
-                       timeout = jiffies + 5 * HZ;
-                       NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, 0, 5*HZ);
+                       shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n");
+                       NCR5380_poll_politely(instance,
+                                             STATUS_REG, SR_BSY, 0, 5 * HZ);
                        break;
                case 2:
-                       printk(KERN_WARNING "scsi%d: bus busy, attempting abort\n", instance->host_no);
+                       shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
                        do_abort(instance);
                        break;
                case 4:
-                       printk(KERN_WARNING "scsi%d: bus busy, attempting reset\n", instance->host_no);
+                       shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
                        do_reset(instance);
+                       /* Wait after a reset; the SCSI standard calls for
+                        * 250ms, we wait 500ms to be on the safe side.
+                        * But some Toshiba CD-ROMs need ten times that.
+                        */
+                       if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+                               msleep(2500);
+                       else
+                               msleep(500);
                        break;
                case 6:
-                       printk(KERN_ERR "scsi%d: bus locked solid or invalid override\n", instance->host_no);
+                       shost_printk(KERN_ERR, instance, "bus locked solid\n");
                        return -ENXIO;
                }
        }
@@ -887,450 +647,513 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
 }
 
 /**
- *     NCR5380_exit    -       remove an NCR5380
- *     @instance: adapter to remove
+ * NCR5380_exit - remove an NCR5380
+ * @instance: adapter to remove
+ *
+ * Assumes that no more work can be queued (e.g. by NCR5380_intr).
  */
 
 static void NCR5380_exit(struct Scsi_Host *instance)
 {
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
 
-       cancel_delayed_work_sync(&hostdata->coroutine);
+       cancel_work_sync(&hostdata->main_task);
+       destroy_workqueue(hostdata->work_q);
 }
 
 /**
- *     NCR5380_queue_command           -       queue a command
- *     @cmd: SCSI command
- *     @done: completion handler
- *
- *      cmd is added to the per instance issue_queue, with minor 
- *      twiddling done to the host specific fields of cmd.  If the 
- *      main coroutine is not running, it is restarted.
+ * complete_cmd - finish processing a command and return it to the SCSI ML
+ * @instance: the host instance
+ * @cmd: command to complete
+ */
+
+static void complete_cmd(struct Scsi_Host *instance,
+                         struct scsi_cmnd *cmd)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+       dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd);
+
+       if (hostdata->sensing == cmd) {
+               /* Autosense processing ends here */
+               if ((cmd->result & 0xff) != SAM_STAT_GOOD) {
+                       scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+                       set_host_byte(cmd, DID_ERROR);
+               } else
+                       scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+               hostdata->sensing = NULL;
+       }
+
+       hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
+
+       cmd->scsi_done(cmd);
+}
+
+/**
+ * NCR5380_queue_command - queue a command
+ * @instance: the relevant SCSI adapter
+ * @cmd: SCSI command
  *
- *     Locks: host lock taken by caller
+ * cmd is added to the per-instance issue queue, with minor
+ * twiddling done to the host specific fields of cmd.  If the
+ * main coroutine is not running, it is restarted.
  */
 
-static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *))
+static int NCR5380_queue_command(struct Scsi_Host *instance,
+                                 struct scsi_cmnd *cmd)
 {
-       struct Scsi_Host *instance = cmd->device->host;
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-       struct scsi_cmnd *tmp;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+       unsigned long flags;
 
 #if (NDEBUG & NDEBUG_NO_WRITE)
        switch (cmd->cmnd[0]) {
        case WRITE_6:
        case WRITE_10:
-               printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no);
+               shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n");
                cmd->result = (DID_ERROR << 16);
-               done(cmd);
+               cmd->scsi_done(cmd);
                return 0;
        }
-#endif                         /* (NDEBUG & NDEBUG_NO_WRITE) */
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
 
-       /* 
-        * We use the host_scribble field as a pointer to the next command  
-        * in a queue 
-        */
-
-       cmd->host_scribble = NULL;
-       cmd->scsi_done = done;
        cmd->result = 0;
 
-       /* 
-        * Insert the cmd into the issue queue. Note that REQUEST SENSE 
+       spin_lock_irqsave(&hostdata->lock, flags);
+
+       /*
+        * Insert the cmd into the issue queue. Note that REQUEST SENSE
         * commands are added to the head of the queue since any command will
-        * clear the contingent allegiance condition that exists and the 
+        * clear the contingent allegiance condition that exists and the
         * sense data is only guaranteed to be valid while the condition exists.
         */
 
-       if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
-               LIST(cmd, hostdata->issue_queue);
-               cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
-               hostdata->issue_queue = cmd;
-       } else {
-               for (tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (struct scsi_cmnd *) tmp->host_scribble);
-               LIST(cmd, tmp);
-               tmp->host_scribble = (unsigned char *) cmd;
-       }
-       dprintk(NDEBUG_QUEUES, "scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+       if (cmd->cmnd[0] == REQUEST_SENSE)
+               list_add(&ncmd->list, &hostdata->unissued);
+       else
+               list_add_tail(&ncmd->list, &hostdata->unissued);
+
+       spin_unlock_irqrestore(&hostdata->lock, flags);
+
+       dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n",
+                cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
 
-       /* Run the coroutine if it isn't already running. */
        /* Kick off command processing */
-       schedule_delayed_work(&hostdata->coroutine, 0);
+       queue_work(hostdata->work_q, &hostdata->main_task);
        return 0;
 }
 
-static DEF_SCSI_QCMD(NCR5380_queue_command)
+/**
+ * dequeue_next_cmd - dequeue a command for processing
+ * @instance: the scsi host instance
+ *
+ * Priority is given to commands on the autosense queue. These commands
+ * need autosense because of a CHECK CONDITION result.
+ *
+ * Returns a command pointer if a command is found for a target that is
+ * not already busy. Otherwise returns NULL.
+ */
+
+static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       struct NCR5380_cmd *ncmd;
+       struct scsi_cmnd *cmd;
+
+       if (list_empty(&hostdata->autosense)) {
+               list_for_each_entry(ncmd, &hostdata->unissued, list) {
+                       cmd = NCR5380_to_scmd(ncmd);
+                       dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
+                                cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun);
+
+                       if (!(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))) {
+                               list_del(&ncmd->list);
+                               dsprintk(NDEBUG_QUEUES, instance,
+                                        "dequeue: removed %p from issue queue\n", cmd);
+                               return cmd;
+                       }
+               }
+       } else {
+               /* Autosense processing begins here */
+               ncmd = list_first_entry(&hostdata->autosense,
+                                       struct NCR5380_cmd, list);
+               list_del(&ncmd->list);
+               cmd = NCR5380_to_scmd(ncmd);
+               dsprintk(NDEBUG_QUEUES, instance,
+                        "dequeue: removed %p from autosense queue\n", cmd);
+               scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+               hostdata->sensing = cmd;
+               return cmd;
+       }
+       return NULL;
+}
+
+static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+
+       if (hostdata->sensing) {
+               scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+               list_add(&ncmd->list, &hostdata->autosense);
+               hostdata->sensing = NULL;
+       } else
+               list_add(&ncmd->list, &hostdata->unissued);
+}
 
 /**
- *     NCR5380_main    -       NCR state machines
- *
- *     NCR5380_main is a coroutine that runs as long as more work can 
- *      be done on the NCR5380 host adapters in a system.  Both 
- *      NCR5380_queue_command() and NCR5380_intr() will try to start it 
- *      in case it is not running.
- * 
- *     Locks: called as its own thread with no locks held. Takes the
- *     host lock and called routines may take the isa dma lock.
+ * NCR5380_main - NCR state machines
+ *
+ * NCR5380_main is a coroutine that runs as long as more work can
+ * be done on the NCR5380 host adapters in a system.  Both
+ * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * in case it is not running.
  */
 
 static void NCR5380_main(struct work_struct *work)
 {
        struct NCR5380_hostdata *hostdata =
-               container_of(work, struct NCR5380_hostdata, coroutine.work);
+               container_of(work, struct NCR5380_hostdata, main_task);
        struct Scsi_Host *instance = hostdata->host;
-       struct scsi_cmnd *tmp, *prev;
+       struct scsi_cmnd *cmd;
        int done;
-       
-       spin_lock_irq(instance->host_lock);
+
        do {
-               /* Lock held here */
                done = 1;
-               if (!hostdata->connected && !hostdata->selecting) {
-                       dprintk(NDEBUG_MAIN, "scsi%d : not connected\n", instance->host_no);
-                       /*
-                        * Search through the issue_queue for a command destined
-                        * for a target that's not busy.
-                        */
-                       for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
-                       {
-                               if (prev != tmp)
-                                   dprintk(NDEBUG_LISTS, "MAIN tmp=%p   target=%d   busy=%d lun=%llu\n", tmp, tmp->device->id, hostdata->busy[tmp->device->id], tmp->device->lun);
-                               /*  When we find one, remove it from the issue queue. */
-                               if (!(hostdata->busy[tmp->device->id] &
-                                     (1 << (u8)(tmp->device->lun & 0xff)))) {
-                                       if (prev) {
-                                               REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
-                                               prev->host_scribble = tmp->host_scribble;
-                                       } else {
-                                               REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble);
-                                               hostdata->issue_queue = (struct scsi_cmnd *) tmp->host_scribble;
-                                       }
-                                       tmp->host_scribble = NULL;
 
-                                       /* 
-                                        * Attempt to establish an I_T_L nexus here. 
-                                        * On success, instance->hostdata->connected is set.
-                                        * On failure, we must add the command back to the
-                                        *   issue queue so we can keep trying. 
-                                        */
-                                       dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, "scsi%d : main() : command for target %d lun %llu removed from issue_queue\n", instance->host_no, tmp->device->id, tmp->device->lun);
-       
-                                       /*
-                                        * A successful selection is defined as one that 
-                                        * leaves us with the command connected and 
-                                        * in hostdata->connected, OR has terminated the
-                                        * command.
-                                        *
-                                        * With successful commands, we fall through
-                                        * and see if we can do an information transfer,
-                                        * with failures we will restart.
-                                        */
-                                       hostdata->selecting = NULL;
-                                       /* RvC: have to preset this to indicate a new command is being performed */
+               spin_lock_irq(&hostdata->lock);
+               while (!hostdata->connected &&
+                      (cmd = dequeue_next_cmd(instance))) {
 
-                                       /*
-                                        * REQUEST SENSE commands are issued without tagged
-                                        * queueing, even on SCSI-II devices because the
-                                        * contingent allegiance condition exists for the
-                                        * entire unit.
-                                        */
+                       dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
 
-                                       if (!NCR5380_select(instance, tmp)) {
-                                               break;
-                                       } else {
-                                               LIST(tmp, hostdata->issue_queue);
-                                               tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
-                                               hostdata->issue_queue = tmp;
-                                               done = 0;
-                                               dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, "scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no);
-                                       }
-                                       /* lock held here still */
-                               }       /* if target/lun is not busy */
-                       }       /* for */
-                       /* exited locked */
-               }       /* if (!hostdata->connected) */
-               if (hostdata->selecting) {
-                       tmp = (struct scsi_cmnd *) hostdata->selecting;
-                       /* Selection will drop and retake the lock */
-                       if (!NCR5380_select(instance, tmp)) {
-                               /* Ok ?? */
+                       /*
+                        * Attempt to establish an I_T_L nexus here.
+                        * On success, instance->hostdata->connected is set.
+                        * On failure, we must add the command back to the
+                        * issue queue so we can keep trying.
+                        */
+                       /*
+                        * REQUEST SENSE commands are issued without tagged
+                        * queueing, even on SCSI-II devices because the
+                        * contingent allegiance condition exists for the
+                        * entire unit.
+                        */
+
+                       cmd = NCR5380_select(instance, cmd);
+                       if (!cmd) {
+                               dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
                        } else {
-                               /* RvC: device failed, so we wait a long time
-                                  this is needed for Mustek scanners, that
-                                  do not respond to commands immediately
-                                  after a scan */
-                               printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->device->id);
-                               LIST(tmp, hostdata->issue_queue);
-                               tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
-                               hostdata->issue_queue = tmp;
-                               NCR5380_set_timer(hostdata, USLEEP_WAITLONG);
+                               dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
+                                        "main: select failed, returning %p to queue\n", cmd);
+                               requeue_cmd(instance, cmd);
                        }
-               }       /* if hostdata->selecting */
+               }
                if (hostdata->connected
 #ifdef REAL_DMA
                    && !hostdata->dmalen
 #endif
-                   && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))
                    ) {
-                       dprintk(NDEBUG_MAIN, "scsi%d : main() : performing information transfer\n", instance->host_no);
+                       dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n");
                        NCR5380_information_transfer(instance);
-                       dprintk(NDEBUG_MAIN, "scsi%d : main() : done set false\n", instance->host_no);
                        done = 0;
-               } else
-                       break;
+               }
+               spin_unlock_irq(&hostdata->lock);
+               if (!done)
+                       cond_resched();
        } while (!done);
-       
-       spin_unlock_irq(instance->host_lock);
 }
 
 #ifndef DONT_USE_INTR
 
 /**
- *     NCR5380_intr    -       generic NCR5380 irq handler
- *     @irq: interrupt number
- *     @dev_id: device info
- *
- *     Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
- *      from the disconnected queue, and restarting NCR5380_main() 
- *      as required.
- *
- *     Locks: takes the needed instance locks
+ * NCR5380_intr - generic NCR5380 irq handler
+ * @irq: interrupt number
+ * @dev_id: device info
+ *
+ * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ * from the disconnected queue, and restarting NCR5380_main()
+ * as required.
+ *
+ * The chip can assert IRQ in any of six different conditions. The IRQ flag
+ * is then cleared by reading the Reset Parity/Interrupt Register (RPIR).
+ * Three of these six conditions are latched in the Bus and Status Register:
+ * - End of DMA (cleared by ending DMA Mode)
+ * - Parity error (cleared by reading RPIR)
+ * - Loss of BSY (cleared by reading RPIR)
+ * Two conditions have flag bits that are not latched:
+ * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode)
+ * - Bus reset (non-maskable)
+ * The remaining condition has no flag bit at all:
+ * - Selection/reselection
+ *
+ * Hence, establishing the cause(s) of any interrupt is partly guesswork.
+ * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor
+ * claimed that "the design of the [DP8490] interrupt logic ensures
+ * interrupts will not be lost (they can be on the DP5380)."
+ * The L5380/53C80 datasheet from LOGIC Devices has more details.
+ *
+ * Checking for bus reset by reading RST is futile because of interrupt
+ * latency, but a bus reset will reset chip logic. Checking for parity error
+ * is unnecessary because that interrupt is never enabled. A Loss of BSY
+ * condition will clear DMA Mode. We can tell when this occurs because the
+ * the Busy Monitor interrupt is enabled together with DMA Mode.
  */
 
-static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
+static irqreturn_t NCR5380_intr(int irq, void *dev_id)
 {
-       NCR5380_local_declare();
        struct Scsi_Host *instance = dev_id;
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-       int done;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       int handled = 0;
        unsigned char basr;
        unsigned long flags;
 
-       dprintk(NDEBUG_INTR, "scsi : NCR5380 irq %d triggered\n",
-               instance->irq);
+       spin_lock_irqsave(&hostdata->lock, flags);
+
+       basr = NCR5380_read(BUS_AND_STATUS_REG);
+       if (basr & BASR_IRQ) {
+               unsigned char mr = NCR5380_read(MODE_REG);
+               unsigned char sr = NCR5380_read(STATUS_REG);
+
+               dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n",
+                        irq, basr, sr, mr);
 
-       do {
-               done = 1;
-               spin_lock_irqsave(instance->host_lock, flags);
-               /* Look for pending interrupts */
-               NCR5380_setup(instance);
-               basr = NCR5380_read(BUS_AND_STATUS_REG);
-               /* XXX dispatch to appropriate routine if found and done=0 */
-               if (basr & BASR_IRQ) {
-                       NCR5380_dprint(NDEBUG_INTR, instance);
-                       if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
-                               done = 0;
-                               dprintk(NDEBUG_INTR, "scsi%d : SEL interrupt\n", instance->host_no);
-                               NCR5380_reselect(instance);
-                               (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-                       } else if (basr & BASR_PARITY_ERROR) {
-                               dprintk(NDEBUG_INTR, "scsi%d : PARITY interrupt\n", instance->host_no);
-                               (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-                       } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
-                               dprintk(NDEBUG_INTR, "scsi%d : RESET interrupt\n", instance->host_no);
-                               (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-                       } else {
 #if defined(REAL_DMA)
-                               /*
-                                * We should only get PHASE MISMATCH and EOP interrupts
-                                * if we have DMA enabled, so do a sanity check based on
-                                * the current setting of the MODE register.
-                                */
+               if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) {
+                       /* Probably End of DMA, Phase Mismatch or Loss of BSY.
+                        * We ack IRQ after clearing Mode Register. Workarounds
+                        * for End of DMA errata need to happen in DMA Mode.
+                        */
 
-                               if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) {
-                                       int transferred;
+                       dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n");
 
-                                       if (!hostdata->connected)
-                                               panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno);
+                       int transferred;
 
-                                       transferred = (hostdata->dmalen - NCR5380_dma_residual(instance));
-                                       hostdata->connected->SCp.this_residual -= transferred;
-                                       hostdata->connected->SCp.ptr += transferred;
-                                       hostdata->dmalen = 0;
+                       if (!hostdata->connected)
+                               panic("scsi%d : DMA interrupt with no connected cmd\n",
+                                     instance->hostno);
 
-                                       (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-                                                       
-                                       /* FIXME: we need to poll briefly then defer a workqueue task ! */
-                                       NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2*HZ);
+                       transferred = hostdata->dmalen - NCR5380_dma_residual(instance);
+                       hostdata->connected->SCp.this_residual -= transferred;
+                       hostdata->connected->SCp.ptr += transferred;
+                       hostdata->dmalen = 0;
 
-                                       NCR5380_write(MODE_REG, MR_BASE);
-                                       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                               }
-#else
-                               dprintk(NDEBUG_INTR, "scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
-                               (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-#endif
+                       /* FIXME: we need to poll briefly then defer a workqueue task ! */
+                       NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2 * HZ);
+
+                       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+                       NCR5380_write(MODE_REG, MR_BASE);
+                       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+               } else
+#endif /* REAL_DMA */
+               if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) &&
+                   (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) {
+                       /* Probably reselected */
+                       NCR5380_write(SELECT_ENABLE_REG, 0);
+                       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+                       dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n");
+
+                       if (!hostdata->connected) {
+                               NCR5380_reselect(instance);
+                               queue_work(hostdata->work_q, &hostdata->main_task);
                        }
-               }       /* if BASR_IRQ */
-               spin_unlock_irqrestore(instance->host_lock, flags);
-               if(!done)
-                       schedule_delayed_work(&hostdata->coroutine, 0);
-       } while (!done);
-       return IRQ_HANDLED;
+                       if (!hostdata->connected)
+                               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+               } else {
+                       /* Probably Bus Reset */
+                       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+                       dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n");
+               }
+               handled = 1;
+       } else {
+               shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n");
+       }
+
+       spin_unlock_irqrestore(&hostdata->lock, flags);
+
+       return IRQ_RETVAL(handled);
 }
 
-#endif 
+#endif
 
-/* 
+/*
  * Function : int NCR5380_select(struct Scsi_Host *instance,
- *                               struct scsi_cmnd *cmd)
+ * struct scsi_cmnd *cmd)
  *
  * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- *      including ARBITRATION, SELECTION, and initial message out for 
- *      IDENTIFY and queue messages. 
- *
- * Inputs : instance - instantiation of the 5380 driver on which this 
- *      target lives, cmd - SCSI command to execute.
- * 
- * Returns : -1 if selection could not execute for some reason,
- *      0 if selection succeeded or failed because the target 
- *      did not respond.
- *
- * Side effects : 
- *      If bus busy, arbitration failed, etc, NCR5380_select() will exit 
- *              with registers as they should have been on entry - ie
- *              SELECT_ENABLE will be set appropriately, the NCR5380
- *              will cease to drive any SCSI bus signals.
- *
- *      If successful : I_T_L or I_T_L_Q nexus will be established, 
- *              instance->connected will be set to cmd.  
- *              SELECT interrupt will be disabled.
- *
- *      If failed (no target) : cmd->scsi_done() will be called, and the 
- *              cmd->result host byte set to DID_BAD_TARGET.
- *
- *     Locks: caller holds hostdata lock in IRQ mode
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this
+ * target lives, cmd - SCSI command to execute.
+ *
+ * Returns cmd if selection failed but should be retried,
+ * NULL if selection failed and should not be retried, or
+ * NULL if selection succeeded (hostdata->connected == cmd).
+ *
+ * Side effects :
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
+ *
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
+ *
+ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
  */
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+
+static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
+                                        struct scsi_cmnd *cmd)
 {
-       NCR5380_local_declare();
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char tmp[3], phase;
        unsigned char *data;
        int len;
-       unsigned long timeout;
-       unsigned char value;
        int err;
-       NCR5380_setup(instance);
-
-       if (hostdata->selecting)
-               goto part2;
-
-       hostdata->restart_select = 0;
 
        NCR5380_dprint(NDEBUG_ARBITRATION, instance);
-       dprintk(NDEBUG_ARBITRATION, "scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id);
+       dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
+                instance->this_id);
+
+       /*
+        * Arbitration and selection phases are slow and involve dropping the
+        * lock, so we have to watch out for EH. An exception handler may
+        * change 'selecting' to NULL. This function will then return NULL
+        * so that the caller will forget about 'cmd'. (During information
+        * transfer phases, EH may change 'connected' to NULL.)
+        */
+       hostdata->selecting = cmd;
 
-       /* 
-        * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
+       /*
+        * Set the phase bits to 0, otherwise the NCR5380 won't drive the
         * data bus during SELECTION.
         */
 
        NCR5380_write(TARGET_COMMAND_REG, 0);
 
-       /* 
+       /*
         * Start arbitration.
         */
 
        NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
        NCR5380_write(MODE_REG, MR_ARBITRATE);
 
+       /* The chip now waits for BUS FREE phase. Then after the 800 ns
+        * Bus Free Delay, arbitration will begin.
+        */
 
-       /* We can be relaxed here, interrupts are on, we are
-          in workqueue context, the birds are singing in the trees */
-       spin_unlock_irq(instance->host_lock);
-       err = NCR5380_poll_politely(instance, INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, ICR_ARBITRATION_PROGRESS, 5*HZ);
-       spin_lock_irq(instance->host_lock);
+       spin_unlock_irq(&hostdata->lock);
+       err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0,
+                       INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS,
+                                              ICR_ARBITRATION_PROGRESS, HZ);
+       spin_lock_irq(&hostdata->lock);
+       if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) {
+               /* Reselection interrupt */
+               goto out;
+       }
        if (err < 0) {
-               printk(KERN_DEBUG "scsi: arbitration timeout at %d\n", __LINE__);
                NCR5380_write(MODE_REG, MR_BASE);
-               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-               goto failed;
+               shost_printk(KERN_ERR, instance,
+                            "select: arbitration timeout\n");
+               goto out;
        }
+       spin_unlock_irq(&hostdata->lock);
 
-       dprintk(NDEBUG_ARBITRATION, "scsi%d : arbitration complete\n", instance->host_no);
-
-       /* 
-        * The arbitration delay is 2.2us, but this is a minimum and there is 
-        * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
-        * the integral nature of udelay().
-        *
-        */
-
+       /* The SCSI-2 arbitration delay is 2.4 us */
        udelay(3);
 
        /* Check for lost arbitration */
-       if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
-               NCR5380_write(MODE_REG, MR_BASE);
-               dprintk(NDEBUG_ARBITRATION, "scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no);
-               goto failed;
-       }
-       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
-
-       if (!(hostdata->flags & FLAG_DTC3181E) &&
-           /* RvC: DTC3181E has some trouble with this
-            *      so we simply removed it. Seems to work with
-            *      only Mustek scanner attached
-            */
+       if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+           (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
            (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
                NCR5380_write(MODE_REG, MR_BASE);
-               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-               dprintk(NDEBUG_ARBITRATION, "scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no);
-               goto failed;
+               dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n");
+               spin_lock_irq(&hostdata->lock);
+               goto out;
        }
-       /* 
-        * Again, bus clear + bus settle time is 1.2us, however, this is 
+
+       /* After/during arbitration, BSY should be asserted.
+        * IBM DPES-31080 Version S31Q works now
+        * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman)
+        */
+       NCR5380_write(INITIATOR_COMMAND_REG,
+                     ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
+
+       /*
+        * Again, bus clear + bus settle time is 1.2us, however, this is
         * a minimum so we'll udelay ceil(1.2)
         */
 
-       udelay(2);
+       if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+               udelay(15);
+       else
+               udelay(2);
+
+       spin_lock_irq(&hostdata->lock);
+
+       /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */
+       if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
+               goto out;
 
-       dprintk(NDEBUG_ARBITRATION, "scsi%d : won arbitration\n", instance->host_no);
+       if (!hostdata->selecting) {
+               NCR5380_write(MODE_REG, MR_BASE);
+               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+               goto out;
+       }
 
-       /* 
-        * Now that we have won arbitration, start Selection process, asserting 
+       dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n");
+
+       /*
+        * Now that we have won arbitration, start Selection process, asserting
         * the host and target ID's on the SCSI bus.
         */
 
-       NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << scmd_id(cmd))));
+       NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd)));
 
-       /* 
+       /*
         * Raise ATN while SEL is true before BSY goes false from arbitration,
         * since this is the only way to guarantee that we'll get a MESSAGE OUT
         * phase immediately after selection.
         */
 
-       NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY |
+                     ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL);
        NCR5380_write(MODE_REG, MR_BASE);
 
-       /* 
+       /*
         * Reselect interrupts must be turned off prior to the dropping of BSY,
         * otherwise we will trigger an interrupt.
         */
        NCR5380_write(SELECT_ENABLE_REG, 0);
 
+       spin_unlock_irq(&hostdata->lock);
+
        /*
-        * The initiator shall then wait at least two deskew delays and release 
+        * The initiator shall then wait at least two deskew delays and release
         * the BSY signal.
         */
-       udelay(1);              /* wingel -- wait two bus deskew delay >2*45ns */
+       udelay(1);        /* wingel -- wait two bus deskew delay >2*45ns */
 
        /* Reset BSY */
-       NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
+                     ICR_ASSERT_ATN | ICR_ASSERT_SEL);
 
-       /* 
+       /*
         * Something weird happens when we cease to drive BSY - looks
-        * like the board/chip is letting us do another read before the 
+        * like the board/chip is letting us do another read before the
         * appropriate propagation delay has expired, and we're confusing
         * a BSY signal from ourselves as the target's response to SELECTION.
         *
         * A small delay (the 'C++' frontend breaks the pipeline with an
         * unnecessary jump, making it work on my 386-33/Trantor T128, the
-        * tighter 'C' code breaks and requires this) solves the problem - 
-        * the 1 us delay is arbitrary, and only used because this delay will 
-        * be the same on other platforms and since it works here, it should 
+        * tighter 'C' code breaks and requires this) solves the problem -
+        * the 1 us delay is arbitrary, and only used because this delay will
+        * be the same on other platforms and since it works here, it should
         * work there.
         *
         * wingel suggests that this could be due to failing to wait
@@ -1339,50 +1162,43 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
 
        udelay(1);
 
-       dprintk(NDEBUG_SELECTION, "scsi%d : selecting target %d\n", instance->host_no, scmd_id(cmd));
+       dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd));
 
-       /* 
-        * The SCSI specification calls for a 250 ms timeout for the actual 
+       /*
+        * The SCSI specification calls for a 250 ms timeout for the actual
         * selection.
         */
 
-       timeout = jiffies + msecs_to_jiffies(250);
+       err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY,
+                                   msecs_to_jiffies(250));
 
-       /* 
-        * XXX very interesting - we're seeing a bounce where the BSY we 
-        * asserted is being reflected / still asserted (propagation delay?)
-        * and it's detecting as true.  Sigh.
-        */
-
-       hostdata->select_time = 0;      /* we count the clock ticks at which we polled */
-       hostdata->selecting = cmd;
-
-part2:
-       /* RvC: here we enter after a sleeping period, or immediately after
-          execution of part 1
-          we poll only once ech clock tick */
-       value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO);
-
-       if (!value && (hostdata->select_time < HZ/4)) {
-               /* RvC: we still must wait for a device response */
-               hostdata->select_time++;        /* after 25 ticks the device has failed */
-               NCR5380_set_timer(hostdata, 1);
-               return 0;       /* RvC: we return here with hostdata->selecting set,
-                                  to go to sleep */
-       }
-
-       hostdata->selecting = NULL;/* clear this pointer, because we passed the
-                                          waiting period */
        if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+               spin_lock_irq(&hostdata->lock);
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                NCR5380_reselect(instance);
-               printk("scsi%d : reselection after won arbitration?\n", instance->host_no);
+               if (!hostdata->connected)
+                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+               shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
+               goto out;
+       }
+
+       if (err < 0) {
+               spin_lock_irq(&hostdata->lock);
+               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-               return -1;
+               /* Can't touch cmd if it has been reclaimed by the scsi ML */
+               if (hostdata->selecting) {
+                       cmd->result = DID_BAD_TARGET << 16;
+                       complete_cmd(instance, cmd);
+                       dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n");
+                       cmd = NULL;
+               }
+               goto out;
        }
-       /* 
-        * No less than two deskew delays after the initiator detects the 
-        * BSY signal is true, it shall release the SEL signal and may 
+
+       /*
+        * No less than two deskew delays after the initiator detects the
+        * BSY signal is true, it shall release the SEL signal and may
         * change the DATA BUS.                                     -wingel
         */
 
@@ -1390,53 +1206,38 @@ part2:
 
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
 
-       if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
-               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-               if (hostdata->targets_present & (1 << scmd_id(cmd))) {
-                       printk(KERN_DEBUG "scsi%d : weirdness\n", instance->host_no);
-                       if (hostdata->restart_select)
-                               printk(KERN_DEBUG "\trestart select\n");
-                       NCR5380_dprint(NDEBUG_SELECTION, instance);
-                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-                       return -1;
-               }
-               cmd->result = DID_BAD_TARGET << 16;
-               cmd->scsi_done(cmd);
-               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-               dprintk(NDEBUG_SELECTION, "scsi%d : target did not respond within 250ms\n", instance->host_no);
-               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-               return 0;
-       }
-       hostdata->targets_present |= (1 << scmd_id(cmd));
-
        /*
-        * Since we followed the SCSI spec, and raised ATN while SEL 
+        * Since we followed the SCSI spec, and raised ATN while SEL
         * was true but before BSY was false during selection, the information
         * transfer phase should be a MESSAGE OUT phase so that we can send the
         * IDENTIFY message.
-        * 
+        *
         * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
         * message (2 bytes) with a tag ID that we increment with every command
         * until it wraps back to 0.
         *
         * XXX - it turns out that there are some broken SCSI-II devices,
-        *       which claim to support tagged queuing but fail when more than
-        *       some number of commands are issued at once.
+        * which claim to support tagged queuing but fail when more than
+        * some number of commands are issued at once.
         */
 
        /* Wait for start of REQ/ACK handshake */
 
-       spin_unlock_irq(instance->host_lock);
        err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
-       spin_lock_irq(instance->host_lock);
-       
-       if(err) {
-               printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__);
+       spin_lock_irq(&hostdata->lock);
+       if (err < 0) {
+               shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
+               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-               goto failed;
+               goto out;
+       }
+       if (!hostdata->selecting) {
+               do_abort(instance);
+               goto out;
        }
 
-       dprintk(NDEBUG_SELECTION, "scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id);
+       dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n",
+                scmd_id(cmd));
        tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun);
 
        len = 1;
@@ -1446,104 +1247,82 @@ part2:
        data = tmp;
        phase = PHASE_MSGOUT;
        NCR5380_transfer_pio(instance, &phase, &len, &data);
-       dprintk(NDEBUG_SELECTION, "scsi%d : nexus established.\n", instance->host_no);
+       dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n");
        /* XXX need to handle errors here */
+
        hostdata->connected = cmd;
-       hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF));
+       hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun;
 
        initialize_SCp(cmd);
 
-       return 0;
-
-       /* Selection failed */
-failed:
-       return -1;
+       cmd = NULL;
 
+out:
+       if (!hostdata->selecting)
+               return NULL;
+       hostdata->selecting = NULL;
+       return cmd;
 }
 
-/* 
- * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 
- *      unsigned char *phase, int *count, unsigned char **data)
+/*
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
  *
  * Purpose : transfers data in given phase using polled I/O
  *
- * Inputs : instance - instance of driver, *phase - pointer to 
- *      what phase is expected, *count - pointer to number of 
- *      bytes to transfer, **data - pointer to data pointer.
- * 
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+ *
  * Returns : -1 when different phase is entered without transferring
- *      maximum number of bytes, 0 if all bytes or transferred or exit
- *      is in same phase.
+ * maximum number of bytes, 0 if all bytes are transferred or exit
+ * is in same phase.
  *
- *      Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
  *
  * XXX Note : handling for bus free may be useful.
  */
 
 /*
- * Note : this code is not as quick as it could be, however it 
+ * Note : this code is not as quick as it could be, however it
  * IS 100% reliable, and for the actual data transfer where speed
  * counts, we will always do a pseudo DMA or DMA transfer.
  */
 
-static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
-       NCR5380_local_declare();
+static int NCR5380_transfer_pio(struct Scsi_Host *instance,
+                               unsigned char *phase, int *count,
+                               unsigned char **data)
+{
        unsigned char p = *phase, tmp;
        int c = *count;
        unsigned char *d = *data;
-       /*
-        *      RvC: some administrative data to process polling time
-        */
-       int break_allowed = 0;
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-       NCR5380_setup(instance);
-
-       if (!(p & SR_IO))
-               dprintk(NDEBUG_PIO, "scsi%d : pio write %d bytes\n", instance->host_no, c);
-       else
-               dprintk(NDEBUG_PIO, "scsi%d : pio read %d bytes\n", instance->host_no, c);
 
-       /* 
-        * The NCR5380 chip will only drive the SCSI bus when the 
+       /*
+        * The NCR5380 chip will only drive the SCSI bus when the
         * phase specified in the appropriate bits of the TARGET COMMAND
         * REGISTER match the STATUS REGISTER
         */
 
-        NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
-
-       /* RvC: don't know if this is necessary, but other SCSI I/O is short
-        *      so breaks are not necessary there
-        */
-       if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) {
-               break_allowed = 1;
-       }
-       do {
-               /* 
-                * Wait for assertion of REQ, after which the phase bits will be 
-                * valid 
-                */
+       NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
 
-               /* RvC: we simply poll once, after that we stop temporarily
-                *      and let the device buffer fill up
-                *      if breaking is not allowed, we keep polling as long as needed
+       do {
+               /*
+                * Wait for assertion of REQ, after which the phase bits will be
+                * valid
                 */
 
-               /* FIXME */
-               while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed);
-               if (!(tmp & SR_REQ)) {
-                       /* timeout condition */
-                       NCR5380_set_timer(hostdata, USLEEP_SLEEP);
+               if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0)
                        break;
-               }
 
-               dprintk(NDEBUG_HANDSHAKE, "scsi%d : REQ detected\n", instance->host_no);
+               dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n");
 
                /* Check for phase mismatch */
-               if ((tmp & PHASE_MASK) != p) {
-                       dprintk(NDEBUG_HANDSHAKE, "scsi%d : phase mismatch\n", instance->host_no);
-                       NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance);
+               if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) {
+                       dsprintk(NDEBUG_PIO, instance, "phase mismatch\n");
+                       NCR5380_dprint_phase(NDEBUG_PIO, instance);
                        break;
                }
+
                /* Do actual transfer from SCSI bus to / from memory */
                if (!(p & SR_IO))
                        NCR5380_write(OUTPUT_DATA_REG, *d);
@@ -1552,7 +1331,7 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
 
                ++d;
 
-               /* 
+               /*
                 * The SCSI standard suggests that in MSGOUT phase, the initiator
                 * should drop ATN on the last byte of the message phase
                 * after REQ has been asserted for the handshake but before
@@ -1563,29 +1342,34 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
                        if (!((p & SR_MSG) && c > 1)) {
                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
                                NCR5380_dprint(NDEBUG_PIO, instance);
-                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+                                             ICR_ASSERT_DATA | ICR_ASSERT_ACK);
                        } else {
-                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+                                             ICR_ASSERT_DATA | ICR_ASSERT_ATN);
                                NCR5380_dprint(NDEBUG_PIO, instance);
-                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+                                             ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
                        }
                } else {
                        NCR5380_dprint(NDEBUG_PIO, instance);
                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
                }
 
-               /* FIXME - if this fails bus reset ?? */
-               NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 5*HZ);
-               dprintk(NDEBUG_HANDSHAKE, "scsi%d : req false, handshake complete\n", instance->host_no);
+               if (NCR5380_poll_politely(instance,
+                                         STATUS_REG, SR_REQ, 0, 5 * HZ) < 0)
+                       break;
+
+               dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n");
 
 /*
- * We have several special cases to consider during REQ/ACK handshaking : 
- * 1.  We were in MSGOUT phase, and we are on the last byte of the 
- *      message.  ATN must be dropped as ACK is dropped.
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1.  We were in MSGOUT phase, and we are on the last byte of the
+ * message.  ATN must be dropped as ACK is dropped.
  *
- * 2.  We are in a MSGIN phase, and we are on the last byte of the  
- *      message.  We must exit with ACK asserted, so that the calling
- *      code may raise ATN before dropping ACK to reject the message.
+ * 2.  We are in a MSGIN phase, and we are on the last byte of the
+ * message.  We must exit with ACK asserted, so that the calling
+ * code may raise ATN before dropping ACK to reject the message.
  *
  * 3.  ACK and ATN are clear and the target may proceed as normal.
  */
@@ -1597,12 +1381,16 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
                }
        } while (--c);
 
-       dprintk(NDEBUG_PIO, "scsi%d : residual %d\n", instance->host_no, c);
+       dsprintk(NDEBUG_PIO, instance, "residual %d\n", c);
 
        *count = c;
        *data = d;
        tmp = NCR5380_read(STATUS_REG);
-       if (tmp & SR_REQ)
+       /* The phase read from the bus is valid if either REQ is (already)
+        * asserted or if ACK hasn't been released yet. The latter applies if
+        * we're in MSG IN, DATA IN or STATUS and all bytes have been received.
+        */
+       if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0))
                *phase = tmp & PHASE_MASK;
        else
                *phase = PHASE_UNKNOWN;
@@ -1614,79 +1402,80 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
 }
 
 /**
- *     do_reset        -       issue a reset command
- *     @host: adapter to reset
+ * do_reset - issue a reset command
+ * @instance: adapter to reset
  *
- *     Issue a reset sequence to the NCR5380 and try and get the bus
- *     back into sane shape.
+ * Issue a reset sequence to the NCR5380 and try and get the bus
+ * back into sane shape.
  *
- *     Locks: caller holds queue lock
+ * This clears the reset interrupt flag because there may be no handler for
+ * it. When the driver is initialized, the NCR5380_intr() handler has not yet
+ * been installed. And when in EH we may have released the ST DMA interrupt.
  */
-static void do_reset(struct Scsi_Host *host) {
-       NCR5380_local_declare();
-       NCR5380_setup(host);
 
-       NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
+static void do_reset(struct Scsi_Host *instance)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       NCR5380_write(TARGET_COMMAND_REG,
+                     PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
-       udelay(25);
+       udelay(50);
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+       (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+       local_irq_restore(flags);
 }
 
-/*
- * Function : do_abort (Scsi_Host *host)
- * 
- * Purpose : abort the currently established nexus.  Should only be 
- *      called from a routine which can drop into a 
- * 
- * Returns : 0 on success, -1 on failure.
- *
- * Locks: queue lock held by caller
- *     FIXME: sort this out and get new_eh running
+/**
+ * do_abort - abort the currently established nexus by going to
+ * MESSAGE OUT phase and sending an ABORT message.
+ * @instance: relevant scsi host instance
+ *
+ * Returns 0 on success, -1 on failure.
  */
 
-static int do_abort(struct Scsi_Host *host) {
-       NCR5380_local_declare();
+static int do_abort(struct Scsi_Host *instance)
+{
        unsigned char *msgptr, phase, tmp;
        int len;
        int rc;
-       NCR5380_setup(host);
-
 
        /* Request message out phase */
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
 
-       /* 
-        * Wait for the target to indicate a valid phase by asserting 
-        * REQ.  Once this happens, we'll have either a MSGOUT phase 
-        * and can immediately send the ABORT message, or we'll have some 
+       /*
+        * Wait for the target to indicate a valid phase by asserting
+        * REQ.  Once this happens, we'll have either a MSGOUT phase
+        * and can immediately send the ABORT message, or we'll have some
         * other phase and will have to source/sink data.
-        * 
+        *
         * We really don't care what value was on the bus or what value
         * the target sees, so we just handshake.
         */
 
-       rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, SR_REQ, 60 * HZ);
-       
-       if(rc < 0)
-               return -1;
+       rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ);
+       if (rc < 0)
+               goto timeout;
+
+       tmp = NCR5380_read(STATUS_REG) & PHASE_MASK;
 
-       tmp = (unsigned char)rc;
-       
        NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
 
-       if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
-               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
-               rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, 0, 3*HZ);
+       if (tmp != PHASE_MSGOUT) {
+               NCR5380_write(INITIATOR_COMMAND_REG,
+                             ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+               rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ);
+               if (rc < 0)
+                       goto timeout;
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-               if(rc == -1)
-                       return -1;
        }
+
        tmp = ABORT;
        msgptr = &tmp;
        len = 1;
        phase = PHASE_MSGOUT;
-       NCR5380_transfer_pio(host, &phase, &len, &msgptr);
+       NCR5380_transfer_pio(instance, &phase, &len, &msgptr);
 
        /*
         * If we got here, and the command completed successfully,
@@ -1694,32 +1483,37 @@ static int do_abort(struct Scsi_Host *host) {
         */
 
        return len ? -1 : 0;
+
+timeout:
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+       return -1;
 }
 
 #if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)
-/* 
- * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
- *      unsigned char *phase, int *count, unsigned char **data)
+/*
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
  *
  * Purpose : transfers data in given phase using either real
- *      or pseudo DMA.
+ * or pseudo DMA.
  *
- * Inputs : instance - instance of driver, *phase - pointer to 
- *      what phase is expected, *count - pointer to number of 
- *      bytes to transfer, **data - pointer to data pointer.
- * 
- * Returns : -1 when different phase is entered without transferring
- *      maximum number of bytes, 0 if all bytes or transferred or exit
- *      is in same phase.
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
  *
- *      Also, *phase, *count, *data are modified in place.
+ * Returns : -1 when different phase is entered without transferring
+ * maximum number of bytes, 0 if all bytes or transferred or exit
+ * is in same phase.
  *
- *     Locks: io_request lock held by caller
+ * Also, *phase, *count, *data are modified in place.
  */
 
 
-static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
-       NCR5380_local_declare();
+static int NCR5380_transfer_dma(struct Scsi_Host *instance,
+                               unsigned char *phase, int *count,
+                               unsigned char **data)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        register int c = *count;
        register unsigned char p = *phase;
        register unsigned char *d = *data;
@@ -1730,54 +1524,47 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
        unsigned char saved_data = 0, overrun = 0, residue;
 #endif
 
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-
-       NCR5380_setup(instance);
-
        if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
                *phase = tmp;
                return -1;
        }
 #if defined(REAL_DMA) || defined(REAL_DMA_POLL)
-#ifdef READ_OVERRUNS
        if (p & SR_IO) {
-               c -= 2;
+               if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS))
+                       c -= 2;
        }
-#endif
-       dprintk(NDEBUG_DMA, "scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
        hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c);
+
+       dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
+                (p & SR_IO) ? "receive" : "send", c, *data);
 #endif
 
        NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
 
 #ifdef REAL_DMA
-       NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+       NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+                               MR_ENABLE_EOP_INTR);
 #elif defined(REAL_DMA_POLL)
-       NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+       NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY);
 #else
        /*
         * Note : on my sample board, watch-dog timeouts occurred when interrupts
-        * were not disabled for the duration of a single DMA transfer, from 
+        * were not disabled for the duration of a single DMA transfer, from
         * before the setting of DMA mode to after transfer of the last byte.
         */
 
-#if defined(PSEUDO_DMA) && defined(UNSAFE)
-       spin_unlock_irq(instance->host_lock);
-#endif
-       /* KLL May need eop and parity in 53c400 */
-       if (hostdata->flags & FLAG_NCR53C400)
-               NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE |
-                               MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR |
-                               MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+       if (hostdata->flags & FLAG_NO_DMA_FIXUP)
+               NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+                                       MR_ENABLE_EOP_INTR);
        else
-               NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+               NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY);
 #endif                         /* def REAL_DMA */
 
        dprintk(NDEBUG_DMA, "scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG));
 
-       /* 
-        *      On the PAS16 at least I/O recovery delays are not needed here.
-        *      Everyone else seems to want them.
+       /*
+        * On the PAS16 at least I/O recovery delays are not needed here.
+        * Everyone else seems to want them.
         */
 
        if (p & SR_IO) {
@@ -1797,49 +1584,49 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
        } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER)));
 
 /*
-   At this point, either we've completed DMA, or we have a phase mismatch,
-   or we've unexpectedly lost BUSY (which is a real error).
-
-   For write DMAs, we want to wait until the last byte has been
-   transferred out over the bus before we turn off DMA mode.  Alas, there
-   seems to be no terribly good way of doing this on a 5380 under all
-   conditions.  For non-scatter-gather operations, we can wait until REQ
-   and ACK both go false, or until a phase mismatch occurs.  Gather-writes
-   are nastier, since the device will be expecting more data than we
-   are prepared to send it, and REQ will remain asserted.  On a 53C8[01] we
-   could test LAST BIT SENT to assure transfer (I imagine this is precisely
-   why this signal was added to the newer chips) but on the older 538[01]
-   this signal does not exist.  The workaround for this lack is a watchdog;
-   we bail out of the wait-loop after a modest amount of wait-time if
-   the usual exit conditions are not met.  Not a terribly clean or
-   correct solution :-%
-
-   Reads are equally tricky due to a nasty characteristic of the NCR5380.
-   If the chip is in DMA mode for an READ, it will respond to a target's
-   REQ by latching the SCSI data into the INPUT DATA register and asserting
-   ACK, even if it has _already_ been notified by the DMA controller that
-   the current DMA transfer has completed!  If the NCR5380 is then taken
-   out of DMA mode, this already-acknowledged byte is lost.
-
-   This is not a problem for "one DMA transfer per command" reads, because
-   the situation will never arise... either all of the data is DMA'ed
-   properly, or the target switches to MESSAGE IN phase to signal a
-   disconnection (either operation bringing the DMA to a clean halt).
-   However, in order to handle scatter-reads, we must work around the
-   problem.  The chosen fix is to DMA N-2 bytes, then check for the
-   condition before taking the NCR5380 out of DMA mode.  One or two extra
-   bytes are transferred via PIO as necessary to fill out the original
-   request.
+ * At this point, either we've completed DMA, or we have a phase mismatch,
+ * or we've unexpectedly lost BUSY (which is a real error).
+ *
+ * For DMA sends, we want to wait until the last byte has been
+ * transferred out over the bus before we turn off DMA mode.  Alas, there
+ * seems to be no terribly good way of doing this on a 5380 under all
+ * conditions.  For non-scatter-gather operations, we can wait until REQ
+ * and ACK both go false, or until a phase mismatch occurs.  Gather-sends
+ * are nastier, since the device will be expecting more data than we
+ * are prepared to send it, and REQ will remain asserted.  On a 53C8[01] we
+ * could test Last Byte Sent to assure transfer (I imagine this is precisely
+ * why this signal was added to the newer chips) but on the older 538[01]
+ * this signal does not exist.  The workaround for this lack is a watchdog;
+ * we bail out of the wait-loop after a modest amount of wait-time if
+ * the usual exit conditions are not met.  Not a terribly clean or
+ * correct solution :-%
+ *
+ * DMA receive is equally tricky due to a nasty characteristic of the NCR5380.
+ * If the chip is in DMA receive mode, it will respond to a target's
+ * REQ by latching the SCSI data into the INPUT DATA register and asserting
+ * ACK, even if it has _already_ been notified by the DMA controller that
+ * the current DMA transfer has completed!  If the NCR5380 is then taken
+ * out of DMA mode, this already-acknowledged byte is lost. This is
+ * not a problem for "one DMA transfer per READ command", because
+ * the situation will never arise... either all of the data is DMA'ed
+ * properly, or the target switches to MESSAGE IN phase to signal a
+ * disconnection (either operation bringing the DMA to a clean halt).
+ * However, in order to handle scatter-receive, we must work around the
+ * problem.  The chosen fix is to DMA N-2 bytes, then check for the
+ * condition before taking the NCR5380 out of DMA mode.  One or two extra
+ * bytes are transferred via PIO as necessary to fill out the original
+ * request.
  */
 
        if (p & SR_IO) {
-#ifdef READ_OVERRUNS
-               udelay(10);
-               if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) {
-                       saved_data = NCR5380_read(INPUT_DATA_REGISTER);
-                       overrun = 1;
+               if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS)) {
+                       udelay(10);
+                       if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) ==
+                           (BASR_PHASE_MATCH | BASR_ACK)) {
+                               saved_data = NCR5380_read(INPUT_DATA_REGISTER);
+                               overrun = 1;
+                       }
                }
-#endif
        } else {
                int limit = 100;
                while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) {
@@ -1850,7 +1637,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
                }
        }
 
-       dprintk(NDEBUG_DMA, "scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG));
+       dsprintk(NDEBUG_DMA, "polled DMA transfer complete, basr 0x%02x, sr 0x%02x\n",
+                tmp, NCR5380_read(STATUS_REG));
 
        NCR5380_write(MODE_REG, MR_BASE);
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -1861,8 +1649,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
        *data += c;
        *phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
 
-#ifdef READ_OVERRUNS
-       if (*phase == p && (p & SR_IO) && residue == 0) {
+       if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS) &&
+           *phase == p && (p & SR_IO) && residue == 0) {
                if (overrun) {
                        dprintk(NDEBUG_DMA, "Got an input overrun, using saved byte\n");
                        **data = saved_data;
@@ -1877,7 +1665,6 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
                NCR5380_transfer_pio(instance, phase, &cnt, data);
                *count -= toPIO - cnt;
        }
-#endif
 
        dprintk(NDEBUG_DMA, "Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count));
        return 0;
@@ -1886,95 +1673,64 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
        return 0;
 #else                          /* defined(REAL_DMA_POLL) */
        if (p & SR_IO) {
-#ifdef DMA_WORKS_RIGHT
-               foo = NCR5380_pread(instance, d, c);
-#else
-               int diff = 1;
-               if (hostdata->flags & FLAG_NCR53C400) {
-                       diff = 0;
-               }
-               if (!(foo = NCR5380_pread(instance, d, c - diff))) {
+               foo = NCR5380_pread(instance, d,
+                       hostdata->flags & FLAG_NO_DMA_FIXUP ? c : c - 1);
+               if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) {
                        /*
-                        * We can't disable DMA mode after successfully transferring 
+                        * We can't disable DMA mode after successfully transferring
                         * what we plan to be the last byte, since that would open up
-                        * a race condition where if the target asserted REQ before 
+                        * a race condition where if the target asserted REQ before
                         * we got the DMA mode reset, the NCR5380 would have latched
                         * an additional byte into the INPUT DATA register and we'd
                         * have dropped it.
-                        * 
-                        * The workaround was to transfer one fewer bytes than we 
-                        * intended to with the pseudo-DMA read function, wait for 
+                        *
+                        * The workaround was to transfer one fewer bytes than we
+                        * intended to with the pseudo-DMA read function, wait for
                         * the chip to latch the last byte, read it, and then disable
                         * pseudo-DMA mode.
-                        * 
+                        *
                         * After REQ is asserted, the NCR5380 asserts DRQ and ACK.
                         * REQ is deasserted when ACK is asserted, and not reasserted
                         * until ACK goes false.  Since the NCR5380 won't lower ACK
                         * until DACK is asserted, which won't happen unless we twiddle
-                        * the DMA port or we take the NCR5380 out of DMA mode, we 
-                        * can guarantee that we won't handshake another extra 
+                        * the DMA port or we take the NCR5380 out of DMA mode, we
+                        * can guarantee that we won't handshake another extra
                         * byte.
                         */
 
-                       if (!(hostdata->flags & FLAG_NCR53C400)) {
-                               while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
-                               /* Wait for clean handshake */
-                               while (NCR5380_read(STATUS_REG) & SR_REQ);
-                               d[c - 1] = NCR5380_read(INPUT_DATA_REG);
+                       if (NCR5380_poll_politely(instance, BUS_AND_STATUS_REG,
+                                                 BASR_DRQ, BASR_DRQ, HZ) < 0) {
+                               foo = -1;
+                               shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n");
                        }
+                       if (NCR5380_poll_politely(instance, STATUS_REG,
+                                                 SR_REQ, 0, HZ) < 0) {
+                               foo = -1;
+                               shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n");
+                       }
+                       d[c - 1] = NCR5380_read(INPUT_DATA_REG);
                }
-#endif
        } else {
-#ifdef DMA_WORKS_RIGHT
                foo = NCR5380_pwrite(instance, d, c);
-#else
-               int timeout;
-               dprintk(NDEBUG_C400_PWRITE, "About to pwrite %d bytes\n", c);
-               if (!(foo = NCR5380_pwrite(instance, d, c))) {
+               if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) {
                        /*
-                        * Wait for the last byte to be sent.  If REQ is being asserted for 
-                        * the byte we're interested, we'll ACK it and it will go false.  
+                        * Wait for the last byte to be sent.  If REQ is being asserted for
+                        * the byte we're interested, we'll ACK it and it will go false.
                         */
-                       if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) {
-                               timeout = 20000;
-                               while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH));
-
-                               if (!timeout)
-                                       dprintk(NDEBUG_LAST_BYTE_SENT, "scsi%d : timed out on last byte\n", instance->host_no);
-
-                               if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) {
-                                       hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT;
-                                       if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) {
-                                               hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;
-                                               dprintk(NDEBUG_LAST_BYTE_SENT, "scsi%d : last byte sent works\n", instance->host_no);
-                                       }
-                               }
-                       } else {
-                               dprintk(NDEBUG_C400_PWRITE, "Waiting for LASTBYTE\n");
-                               while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));
-                               dprintk(NDEBUG_C400_PWRITE, "Got LASTBYTE\n");
+                       if (NCR5380_poll_politely2(instance,
+                            BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ,
+                            BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) {
+                               foo = -1;
+                               shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n");
                        }
                }
-#endif
        }
        NCR5380_write(MODE_REG, MR_BASE);
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
-       if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) {
-               dprintk(NDEBUG_C400_PWRITE, "53C400w: Checking for IRQ\n");
-               if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) {
-                       dprintk(NDEBUG_C400_PWRITE, "53C400w:    got it, reading reset interrupt reg\n");
-                       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-               } else {
-                       printk("53C400w:    IRQ NOT THERE!\n");
-               }
-       }
+       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
        *data = d + c;
        *count = 0;
        *phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
-#if defined(PSEUDO_DMA) && defined(UNSAFE)
-       spin_lock_irq(instance->host_lock);
-#endif                         /* defined(REAL_DMA_POLL) */
        return foo;
 #endif                         /* def REAL_DMA */
 }
@@ -1983,25 +1739,23 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
 /*
  * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
  *
- * Purpose : run through the various SCSI phases and do as the target 
- *      directs us to.  Operates on the currently connected command, 
- *      instance->connected.
+ * Purpose : run through the various SCSI phases and do as the target
+ * directs us to.  Operates on the currently connected command,
+ * instance->connected.
  *
  * Inputs : instance, instance for which we are doing commands
  *
- * Side effects : SCSI things happen, the disconnected queue will be 
- *      modified if a command disconnects, *instance->connected will
- *      change.
+ * Side effects : SCSI things happen, the disconnected queue will be
+ * modified if a command disconnects, *instance->connected will
+ * change.
  *
- * XXX Note : we need to watch for bus free or a reset condition here 
- *      to recover from an unexpected bus free condition.
- *
- * Locks: io_request_lock held by caller in IRQ mode
+ * XXX Note : we need to watch for bus free or a reset condition here
+ * to recover from an unexpected bus free condition.
  */
 
-static void NCR5380_information_transfer(struct Scsi_Host *instance) {
-       NCR5380_local_declare();
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+static void NCR5380_information_transfer(struct Scsi_Host *instance)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char msgout = NOP;
        int sink = 0;
        int len;
@@ -2010,13 +1764,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
 #endif
        unsigned char *data;
        unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
-       struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
-       /* RvC: we need to set the end of the polling time */
-       unsigned long poll_time = jiffies + USLEEP_POLL;
+       struct scsi_cmnd *cmd;
 
-       NCR5380_setup(instance);
+       while ((cmd = hostdata->connected)) {
+               struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
 
-       while (1) {
                tmp = NCR5380_read(STATUS_REG);
                /* We only have a valid SCSI phase when REQ is asserted */
                if (tmp & SR_REQ) {
@@ -2028,24 +1780,28 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                        if (sink && (phase != PHASE_MSGOUT)) {
                                NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
 
-                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
-                               while (NCR5380_read(STATUS_REG) & SR_REQ);
-                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+                                             ICR_ASSERT_ACK);
+                               while (NCR5380_read(STATUS_REG) & SR_REQ)
+                                       ;
+                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+                                             ICR_ASSERT_ATN);
                                sink = 0;
                                continue;
                        }
+
                        switch (phase) {
-                       case PHASE_DATAIN:
                        case PHASE_DATAOUT:
 #if (NDEBUG & NDEBUG_NO_DATAOUT)
-                               printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no);
+                               shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n");
                                sink = 1;
                                do_abort(instance);
                                cmd->result = DID_ERROR << 16;
-                               cmd->scsi_done(cmd);
+                               complete_cmd(instance, cmd);
                                return;
 #endif
-                               /* 
+                       case PHASE_DATAIN:
+                               /*
                                 * If there is no room left in the current buffer in the
                                 * scatter-gather list, move onto the next one.
                                 */
@@ -2055,10 +1811,13 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                        --cmd->SCp.buffers_residual;
                                        cmd->SCp.this_residual = cmd->SCp.buffer->length;
                                        cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
-                                       dprintk(NDEBUG_INFORMATION, "scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual);
+                                       dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n",
+                                                cmd->SCp.this_residual,
+                                                cmd->SCp.buffers_residual);
                                }
+
                                /*
-                                * The preferred transfer method is going to be 
+                                * The preferred transfer method is going to be
                                 * PSEUDO-DMA for systems that are strictly PIO,
                                 * since we can let the hardware do the handshaking.
                                 *
@@ -2068,50 +1827,39 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                 */
 
 #if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
-                               /* KLL
-                                * PSEUDO_DMA is defined here. If this is the g_NCR5380
-                                * driver then it will always be defined, so the
-                                * FLAG_NO_PSEUDO_DMA is used to inhibit PDMA in the base
-                                * NCR5380 case.  I think this is a fairly clean solution.
-                                * We supplement these 2 if's with the flag.
-                                */
-#ifdef NCR5380_dma_xfer_len
-                               if (!cmd->device->borken && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
-#else
-                               transfersize = cmd->transfersize;
-
-#ifdef LIMIT_TRANSFERSIZE      /* If we have problems with interrupt service */
-                               if (transfersize > 512)
-                                       transfersize = 512;
-#endif                         /* LIMIT_TRANSFERSIZE */
-
-                               if (!cmd->device->borken && transfersize && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) {
-                                       /* Limit transfers to 32K, for xx400 & xx406
-                                        * pseudoDMA that transfers in 128 bytes blocks. */
-                                       if (transfersize > 32 * 1024)
-                                               transfersize = 32 * 1024;
-#endif
+                               transfersize = 0;
+                               if (!cmd->device->borken &&
+                                   !(hostdata->flags & FLAG_NO_PSEUDO_DMA))
+                                       transfersize = NCR5380_dma_xfer_len(instance, cmd, phase);
+
+                               if (transfersize) {
                                        len = transfersize;
-                                       if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) {
+                                       if (NCR5380_transfer_dma(instance, &phase,
+                                           &len, (unsigned char **)&cmd->SCp.ptr)) {
                                                /*
-                                                * If the watchdog timer fires, all future accesses to this
-                                                * device will use the polled-IO.
+                                                * If the watchdog timer fires, all future
+                                                * accesses to this device will use the
+                                                * polled-IO.
                                                 */
                                                scmd_printk(KERN_INFO, cmd,
-                                                           "switching to slow handshake\n");
+                                                       "switching to slow handshake\n");
                                                cmd->device->borken = 1;
-                                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
                                                sink = 1;
                                                do_abort(instance);
                                                cmd->result = DID_ERROR << 16;
-                                               cmd->scsi_done(cmd);
+                                               complete_cmd(instance, cmd);
                                                /* XXX - need to source or sink data here, as appropriate */
                                        } else
                                                cmd->SCp.this_residual -= transfersize - len;
                                } else
 #endif                         /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */
-                                       NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **)
-                                                            &cmd->SCp.ptr);
+                               {
+                                       spin_unlock_irq(&hostdata->lock);
+                                       NCR5380_transfer_pio(instance, &phase,
+                                                            (int *)&cmd->SCp.this_residual,
+                                                            (unsigned char **)&cmd->SCp.ptr);
+                                       spin_lock_irq(&hostdata->lock);
+                               }
                                break;
                        case PHASE_MSGIN:
                                len = 1;
@@ -2120,101 +1868,42 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                cmd->SCp.Message = tmp;
 
                                switch (tmp) {
-                                       /*
-                                        * Linking lets us reduce the time required to get the 
-                                        * next command out to the device, hopefully this will
-                                        * mean we don't waste another revolution due to the delays
-                                        * required by ARBITRATION and another SELECTION.
-                                        *
-                                        * In the current implementation proposal, low level drivers
-                                        * merely have to start the next command, pointed to by 
-                                        * next_link, done() is called as with unlinked commands.
-                                        */
-#ifdef LINKED
-                               case LINKED_CMD_COMPLETE:
-                               case LINKED_FLG_CMD_COMPLETE:
-                                       /* Accept message by clearing ACK */
-                                       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                                       dprintk(NDEBUG_LINKED, "scsi%d : target %d lun %llu linked command complete.\n", instance->host_no, cmd->device->id, cmd->device->lun);
-                                       /* 
-                                        * Sanity check : A linked command should only terminate with
-                                        * one of these messages if there are more linked commands
-                                        * available.
-                                        */
-                                       if (!cmd->next_link) {
-                                           printk("scsi%d : target %d lun %llu linked command complete, no next_link\n" instance->host_no, cmd->device->id, cmd->device->lun);
-                                               sink = 1;
-                                               do_abort(instance);
-                                               return;
-                                       }
-                                       initialize_SCp(cmd->next_link);
-                                       /* The next command is still part of this process */
-                                       cmd->next_link->tag = cmd->tag;
-                                       cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-                                       dprintk(NDEBUG_LINKED, "scsi%d : target %d lun %llu linked request done, calling scsi_done().\n", instance->host_no, cmd->device->id, cmd->device->lun);
-                                       cmd->scsi_done(cmd);
-                                       cmd = hostdata->connected;
-                                       break;
-#endif                         /* def LINKED */
                                case ABORT:
                                case COMMAND_COMPLETE:
                                        /* Accept message by clearing ACK */
                                        sink = 1;
                                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                                       hostdata->connected = NULL;
-                                       dprintk(NDEBUG_QUEUES, "scsi%d : command for target %d, lun %llu completed\n", instance->host_no, cmd->device->id, cmd->device->lun);
-                                       hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xFF));
-
-                                       /* 
-                                        * I'm not sure what the correct thing to do here is : 
-                                        * 
-                                        * If the command that just executed is NOT a request 
-                                        * sense, the obvious thing to do is to set the result
-                                        * code to the values of the stored parameters.
-                                        * 
-                                        * If it was a REQUEST SENSE command, we need some way 
-                                        * to differentiate between the failure code of the original
-                                        * and the failure code of the REQUEST sense - the obvious
-                                        * case is success, where we fall through and leave the result
-                                        * code unchanged.
-                                        * 
-                                        * The non-obvious place is where the REQUEST SENSE failed 
-                                        */
-
-                                       if (cmd->cmnd[0] != REQUEST_SENSE)
-                                               cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-                                       else if (status_byte(cmd->SCp.Status) != GOOD)
-                                               cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-
-                                       if ((cmd->cmnd[0] == REQUEST_SENSE) &&
-                                               hostdata->ses.cmd_len) {
-                                               scsi_eh_restore_cmnd(cmd, &hostdata->ses);
-                                               hostdata->ses.cmd_len = 0 ;
-                                       }
+                                       dsprintk(NDEBUG_QUEUES, instance,
+                                                "COMMAND COMPLETE %p target %d lun %llu\n",
+                                                cmd, scmd_id(cmd), cmd->device->lun);
 
-                                       if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
-                                               scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
-
-                                               dprintk(NDEBUG_AUTOSENSE, "scsi%d : performing request sense\n", instance->host_no);
+                                       hostdata->connected = NULL;
 
-                                               LIST(cmd, hostdata->issue_queue);
-                                               cmd->host_scribble = (unsigned char *)
-                                                   hostdata->issue_queue;
-                                               hostdata->issue_queue = (struct scsi_cmnd *) cmd;
-                                               dprintk(NDEBUG_QUEUES, "scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no);
-                                       } else {
-                                               cmd->scsi_done(cmd);
+                                       cmd->result &= ~0xffff;
+                                       cmd->result |= cmd->SCp.Status;
+                                       cmd->result |= cmd->SCp.Message << 8;
+
+                                       if (cmd->cmnd[0] == REQUEST_SENSE)
+                                               complete_cmd(instance, cmd);
+                                       else {
+                                               if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION ||
+                                                   cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) {
+                                                       dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n",
+                                                                cmd);
+                                                       list_add_tail(&ncmd->list,
+                                                                     &hostdata->autosense);
+                                               } else
+                                                       complete_cmd(instance, cmd);
                                        }
 
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-                                       /* 
-                                        * Restore phase bits to 0 so an interrupted selection, 
+                                       /*
+                                        * Restore phase bits to 0 so an interrupted selection,
                                         * arbitration can resume.
                                         */
                                        NCR5380_write(TARGET_COMMAND_REG, 0);
 
-                                       while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
-                                               barrier();
+                                       /* Enable reselect interrupts */
+                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                                        return;
                                case MESSAGE_REJECT:
                                        /* Accept message by clearing ACK */
@@ -2229,38 +1918,33 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                        default:
                                                break;
                                        }
-                               case DISCONNECT:{
-                                               /* Accept message by clearing ACK */
-                                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                                               cmd->device->disconnect = 1;
-                                               LIST(cmd, hostdata->disconnected_queue);
-                                               cmd->host_scribble = (unsigned char *)
-                                                   hostdata->disconnected_queue;
-                                               hostdata->connected = NULL;
-                                               hostdata->disconnected_queue = cmd;
-                                               dprintk(NDEBUG_QUEUES, "scsi%d : command for target %d lun %llu was moved from connected to" "  the disconnected_queue\n", instance->host_no, cmd->device->id, cmd->device->lun);
-                                               /* 
-                                                * Restore phase bits to 0 so an interrupted selection, 
-                                                * arbitration can resume.
-                                                */
-                                               NCR5380_write(TARGET_COMMAND_REG, 0);
-
-                                               /* Enable reselect interrupts */
-                                               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-                                               /* Wait for bus free to avoid nasty timeouts - FIXME timeout !*/
-                                               /* NCR538_poll_politely(instance, STATUS_REG, SR_BSY, 0, 30 * HZ); */
-                                               while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
-                                                       barrier();
-                                               return;
-                                       }
-                                       /* 
+                                       break;
+                               case DISCONNECT:
+                                       /* Accept message by clearing ACK */
+                                       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+                                       hostdata->connected = NULL;
+                                       list_add(&ncmd->list, &hostdata->disconnected);
+                                       dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES,
+                                                instance, "connected command %p for target %d lun %llu moved to disconnected queue\n",
+                                                cmd, scmd_id(cmd), cmd->device->lun);
+
+                                       /*
+                                        * Restore phase bits to 0 so an interrupted selection,
+                                        * arbitration can resume.
+                                        */
+                                       NCR5380_write(TARGET_COMMAND_REG, 0);
+
+                                       /* Enable reselect interrupts */
+                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+                                       return;
+                                       /*
                                         * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
-                                        * operation, in violation of the SCSI spec so we can safely 
+                                        * operation, in violation of the SCSI spec so we can safely
                                         * ignore SAVE/RESTORE pointers calls.
                                         *
-                                        * Unfortunately, some disks violate the SCSI spec and 
+                                        * Unfortunately, some disks violate the SCSI spec and
                                         * don't issue the required SAVE_POINTERS message before
-                                        * disconnecting, and we have to break spec to remain 
+                                        * disconnecting, and we have to break spec to remain
                                         * compatible.
                                         */
                                case SAVE_POINTERS:
@@ -2269,31 +1953,28 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                                        break;
                                case EXTENDED_MESSAGE:
-/* 
- * Extended messages are sent in the following format :
- * Byte         
- * 0            EXTENDED_MESSAGE == 1
- * 1            length (includes one byte for code, doesn't 
- *              include first two bytes)
- * 2            code
- * 3..length+1  arguments
- *
- * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since spi_print_msg() wants the whole thing.  
- */
+                                       /*
+                                        * Start the message buffer with the EXTENDED_MESSAGE
+                                        * byte, since spi_print_msg() wants the whole thing.
+                                        */
                                        extended_msg[0] = EXTENDED_MESSAGE;
                                        /* Accept first byte by clearing ACK */
                                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                                       dprintk(NDEBUG_EXTENDED, "scsi%d : receiving extended message\n", instance->host_no);
+
+                                       spin_unlock_irq(&hostdata->lock);
+
+                                       dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n");
 
                                        len = 2;
                                        data = extended_msg + 1;
                                        phase = PHASE_MSGIN;
                                        NCR5380_transfer_pio(instance, &phase, &len, &data);
+                                       dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n",
+                                                (int)extended_msg[1],
+                                                (int)extended_msg[2]);
 
-                                       dprintk(NDEBUG_EXTENDED, "scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2]);
-
-                                       if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) {
+                                       if (!len && extended_msg[1] > 0 &&
+                                           extended_msg[1] <= sizeof(extended_msg) - 2) {
                                                /* Accept third byte by clearing ACK */
                                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                                                len = extended_msg[1] - 1;
@@ -2301,7 +1982,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                                phase = PHASE_MSGIN;
 
                                                NCR5380_transfer_pio(instance, &phase, &len, &data);
-                                               dprintk(NDEBUG_EXTENDED, "scsi%d : message received, residual %d\n", instance->host_no, len);
+                                               dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n",
+                                                        len);
 
                                                switch (extended_msg[2]) {
                                                case EXTENDED_SDTR:
@@ -2311,34 +1993,42 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                                        tmp = 0;
                                                }
                                        } else if (len) {
-                                               printk("scsi%d: error receiving extended message\n", instance->host_no);
+                                               shost_printk(KERN_ERR, instance, "error receiving extended message\n");
                                                tmp = 0;
                                        } else {
-                                               printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]);
+                                               shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n",
+                                                            extended_msg[2], extended_msg[1]);
                                                tmp = 0;
                                        }
+
+                                       spin_lock_irq(&hostdata->lock);
+                                       if (!hostdata->connected)
+                                               return;
+
                                        /* Fall through to reject message */
 
-                                       /* 
-                                        * If we get something weird that we aren't expecting, 
+                                       /*
+                                        * If we get something weird that we aren't expecting,
                                         * reject it.
                                         */
                                default:
                                        if (!tmp) {
-                                               printk("scsi%d: rejecting message ", instance->host_no);
+                                               shost_printk(KERN_ERR, instance, "rejecting message ");
                                                spi_print_msg(extended_msg);
                                                printk("\n");
                                        } else if (tmp != EXTENDED_MESSAGE)
                                                scmd_printk(KERN_INFO, cmd,
-                                                       "rejecting unknown message %02x\n",tmp);
+                                                           "rejecting unknown message %02x\n",
+                                                           tmp);
                                        else
                                                scmd_printk(KERN_INFO, cmd,
-                                                       "rejecting unknown extended message code %02x, length %d\n", extended_msg[1], extended_msg[0]);
+                                                           "rejecting unknown extended message code %02x, length %d\n",
+                                                           extended_msg[1], extended_msg[0]);
 
                                        msgout = MESSAGE_REJECT;
                                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
                                        break;
-                               }       /* switch (tmp) */
+                               } /* switch (tmp) */
                                break;
                        case PHASE_MSGOUT:
                                len = 1;
@@ -2346,10 +2036,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                hostdata->last_message = msgout;
                                NCR5380_transfer_pio(instance, &phase, &len, &data);
                                if (msgout == ABORT) {
-                                       hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xFF));
                                        hostdata->connected = NULL;
                                        cmd->result = DID_ERROR << 16;
-                                       cmd->scsi_done(cmd);
+                                       complete_cmd(instance, cmd);
                                        NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                                        return;
                                }
@@ -2358,17 +2047,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                        case PHASE_CMDOUT:
                                len = cmd->cmd_len;
                                data = cmd->cmnd;
-                               /* 
-                                * XXX for performance reasons, on machines with a 
-                                * PSEUDO-DMA architecture we should probably 
-                                * use the dma transfer function.  
+                               /*
+                                * XXX for performance reasons, on machines with a
+                                * PSEUDO-DMA architecture we should probably
+                                * use the dma transfer function.
                                 */
                                NCR5380_transfer_pio(instance, &phase, &len, &data);
-                               if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) {
-                                       NCR5380_set_timer(hostdata, USLEEP_SLEEP);
-                                       dprintk(NDEBUG_USLEEP, "scsi%d : issued command, sleeping until %lu\n", instance->host_no, hostdata->time_expires);
-                                       return;
-                               }
                                break;
                        case PHASE_STATIN:
                                len = 1;
@@ -2377,46 +2061,37 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
                                cmd->SCp.Status = tmp;
                                break;
                        default:
-                               printk("scsi%d : unknown phase\n", instance->host_no);
+                               shost_printk(KERN_ERR, instance, "unknown phase\n");
                                NCR5380_dprint(NDEBUG_ANY, instance);
-                       }       /* switch(phase) */
-               }               /* if (tmp * SR_REQ) */
-               else {
-                       /* RvC: go to sleep if polling time expired
-                        */
-                       if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) {
-                               NCR5380_set_timer(hostdata, USLEEP_SLEEP);
-                               dprintk(NDEBUG_USLEEP, "scsi%d : poll timed out, sleeping until %lu\n", instance->host_no, hostdata->time_expires);
-                               return;
-                       }
+                       } /* switch(phase) */
+               } else {
+                       spin_unlock_irq(&hostdata->lock);
+                       NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+                       spin_lock_irq(&hostdata->lock);
                }
-       }                       /* while (1) */
+       }
 }
 
 /*
  * Function : void NCR5380_reselect (struct Scsi_Host *instance)
  *
- * Purpose : does reselection, initializing the instance->connected 
- *      field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
- *      nexus has been reestablished,
- *      
- * Inputs : instance - this instance of the NCR5380.
+ * Purpose : does reselection, initializing the instance->connected
+ * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
  *
- * Locks: io_request_lock held by caller if IRQ driven
+ * Inputs : instance - this instance of the NCR5380.
  */
 
-static void NCR5380_reselect(struct Scsi_Host *instance) {
-       NCR5380_local_declare();
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
-        instance->hostdata;
+static void NCR5380_reselect(struct Scsi_Host *instance)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char target_mask;
        unsigned char lun, phase;
        int len;
        unsigned char msg[3];
        unsigned char *data;
-       struct scsi_cmnd *tmp = NULL, *prev;
-       int abort = 0;
-       NCR5380_setup(instance);
+       struct NCR5380_cmd *ncmd;
+       struct scsi_cmnd *tmp;
 
        /*
         * Disable arbitration, etc. since the host adapter obviously
@@ -2424,12 +2099,12 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
         */
 
        NCR5380_write(MODE_REG, MR_BASE);
-       hostdata->restart_select = 1;
 
        target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
-       dprintk(NDEBUG_SELECTION, "scsi%d : reselect\n", instance->host_no);
 
-       /* 
+       dsprintk(NDEBUG_RESELECTION, instance, "reselect\n");
+
+       /*
         * At this point, we have detected that our SCSI ID is on the bus,
         * SEL is true and BSY was false for at least one bus settle delay
         * (400 ns).
@@ -2439,103 +2114,110 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
         */
 
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-
-       /* FIXME: timeout too long, must fail to workqueue */   
-       if(NCR5380_poll_politely(instance, STATUS_REG, SR_SEL, 0, 2*HZ)<0)
-               abort = 1;
-               
+       if (NCR5380_poll_politely(instance,
+                                 STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
+               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+               return;
+       }
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
        /*
         * Wait for target to go into MSGIN.
-        * FIXME: timeout needed and fail to work queeu
         */
 
-       if(NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 2*HZ))
-               abort = 1;
+       if (NCR5380_poll_politely(instance,
+                                 STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
+               do_abort(instance);
+               return;
+       }
 
        len = 1;
        data = msg;
        phase = PHASE_MSGIN;
        NCR5380_transfer_pio(instance, &phase, &len, &data);
 
+       if (len) {
+               do_abort(instance);
+               return;
+       }
+
        if (!(msg[0] & 0x80)) {
-               printk(KERN_ERR "scsi%d : expecting IDENTIFY message, got ", instance->host_no);
+               shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
                spi_print_msg(msg);
-               abort = 1;
-       } else {
-               /* Accept message by clearing ACK */
-               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-               lun = (msg[0] & 0x07);
+               printk("\n");
+               do_abort(instance);
+               return;
+       }
+       lun = msg[0] & 0x07;
 
-               /* 
-                * We need to add code for SCSI-II to track which devices have
-                * I_T_L_Q nexuses established, and which have simple I_T_L
-                * nexuses so we can chose to do additional data transfer.
-                */
+       /*
+        * We need to add code for SCSI-II to track which devices have
+        * I_T_L_Q nexuses established, and which have simple I_T_L
+        * nexuses so we can chose to do additional data transfer.
+        */
 
-               /* 
-                * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
-                * just reestablished, and remove it from the disconnected queue.
-                */
+       /*
+        * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we
+        * just reestablished, and remove it from the disconnected queue.
+        */
 
+       tmp = NULL;
+       list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+               struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
 
-               for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
-                       if ((target_mask == (1 << tmp->device->id)) && (lun == (u8)tmp->device->lun)
-                           ) {
-                               if (prev) {
-                                       REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
-                                       prev->host_scribble = tmp->host_scribble;
-                               } else {
-                                       REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble);
-                                       hostdata->disconnected_queue = (struct scsi_cmnd *) tmp->host_scribble;
-                               }
-                               tmp->host_scribble = NULL;
-                               break;
-                       }
-               if (!tmp) {
-                       printk(KERN_ERR "scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun);
-                       /* 
-                        * Since we have an established nexus that we can't do anything with,
-                        * we must abort it.  
-                        */
-                       abort = 1;
+               if (target_mask == (1 << scmd_id(cmd)) &&
+                   lun == (u8)cmd->device->lun) {
+                       list_del(&ncmd->list);
+                       tmp = cmd;
+                       break;
                }
        }
 
-       if (abort) {
-               do_abort(instance);
+       if (tmp) {
+               dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance,
+                        "reselect: removed %p from disconnected queue\n", tmp);
        } else {
-               hostdata->connected = tmp;
-               dprintk(NDEBUG_RESELECTION, "scsi%d : nexus established, target = %d, lun = %llu, tag = %d\n", instance->host_no, tmp->device->id, tmp->device->lun, tmp->tag);
+               shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
+                            target_mask, lun);
+               /*
+                * Since we have an established nexus that we can't do anything
+                * with, we must abort it.
+                */
+               do_abort(instance);
+               return;
        }
+
+       /* Accept message by clearing ACK */
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+       hostdata->connected = tmp;
+       dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu, tag %d\n",
+                scmd_id(tmp), tmp->device->lun, tmp->tag);
 }
 
 /*
  * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
  *
  * Purpose : called by interrupt handler when DMA finishes or a phase
- *      mismatch occurs (which would finish the DMA transfer).  
+ * mismatch occurs (which would finish the DMA transfer).
  *
  * Inputs : instance - this instance of the NCR5380.
  *
  * Returns : pointer to the scsi_cmnd structure for which the I_T_L
- *      nexus has been reestablished, on failure NULL is returned.
+ * nexus has been reestablished, on failure NULL is returned.
  */
 
 #ifdef REAL_DMA
 static void NCR5380_dma_complete(NCR5380_instance * instance) {
-       NCR5380_local_declare();
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        int transferred;
-       NCR5380_setup(instance);
 
        /*
         * XXX this might not be right.
         *
         * Wait for final byte to transfer, ie wait for ACK to go false.
         *
-        * We should use the Last Byte Sent bit, unfortunately this is 
+        * We should use the Last Byte Sent bit, unfortunately this is
         * not available on the 5380/5381 (only the various CMOS chips)
         *
         * FIXME: timeout, and need to handle long timeout/irq case
@@ -2543,7 +2225,6 @@ static void NCR5380_dma_complete(NCR5380_instance * instance) {
 
        NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, BASR_ACK, 0, 5*HZ);
 
-       NCR5380_write(MODE_REG, MR_BASE);
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
        /*
@@ -2560,190 +2241,251 @@ static void NCR5380_dma_complete(NCR5380_instance * instance) {
 }
 #endif                         /* def REAL_DMA */
 
-/*
- * Function : int NCR5380_abort (struct scsi_cmnd *cmd)
- *
- * Purpose : abort a command
- *
- * Inputs : cmd - the scsi_cmnd to abort, code - code to set the
- *      host byte of the result field to, if zero DID_ABORTED is
- *      used.
- *
- * Returns : SUCCESS - success, FAILED on failure.
- *
- *     XXX - there is no way to abort the command that is currently
- *     connected, you have to wait for it to complete.  If this is
- *     a problem, we could implement longjmp() / setjmp(), setjmp()
- *     called where the loop started in NCR5380_main().
- *
- * Locks: host lock taken by caller
+/**
+ * list_find_cmd - test for presence of a command in a linked list
+ * @haystack: list of commands
+ * @needle: command to search for
  */
 
-static int NCR5380_abort(struct scsi_cmnd *cmd)
+static bool list_find_cmd(struct list_head *haystack,
+                          struct scsi_cmnd *needle)
 {
-       NCR5380_local_declare();
-       struct Scsi_Host *instance = cmd->device->host;
-       struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-       struct scsi_cmnd *tmp, **prev;
+       struct NCR5380_cmd *ncmd;
 
-       scmd_printk(KERN_WARNING, cmd, "aborting command\n");
+       list_for_each_entry(ncmd, haystack, list)
+               if (NCR5380_to_scmd(ncmd) == needle)
+                       return true;
+       return false;
+}
 
-       NCR5380_print_status(instance);
+/**
+ * list_remove_cmd - remove a command from linked list
+ * @haystack: list of commands
+ * @needle: command to remove
+ */
 
-       NCR5380_setup(instance);
+static bool list_del_cmd(struct list_head *haystack,
+                         struct scsi_cmnd *needle)
+{
+       if (list_find_cmd(haystack, needle)) {
+               struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle);
 
-       dprintk(NDEBUG_ABORT, "scsi%d : abort called\n", instance->host_no);
-       dprintk(NDEBUG_ABORT, "        basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG));
+               list_del(&ncmd->list);
+               return true;
+       }
+       return false;
+}
 
-#if 0
-/*
- * Case 1 : If the command is the currently executing command, 
- * we'll set the aborted flag and return control so that 
- * information transfer routine can exit cleanly.
+/**
+ * NCR5380_abort - scsi host eh_abort_handler() method
+ * @cmd: the command to be aborted
+ *
+ * Try to abort a given command by removing it from queues and/or sending
+ * the target an abort message. This may not succeed in causing a target
+ * to abort the command. Nonetheless, the low-level driver must forget about
+ * the command because the mid-layer reclaims it and it may be re-issued.
+ *
+ * The normal path taken by a command is as follows. For EH we trace this
+ * same path to locate and abort the command.
+ *
+ * unissued -> selecting -> [unissued -> selecting ->]... connected ->
+ * [disconnected -> connected ->]...
+ * [autosense -> connected ->] done
+ *
+ * If cmd is unissued then just remove it.
+ * If cmd is disconnected, try to select the target.
+ * If cmd is connected, try to send an abort message.
+ * If cmd is waiting for autosense, give it a chance to complete but check
+ * that it isn't left connected.
+ * If cmd was not found at all then presumably it has already been completed,
+ * in which case return SUCCESS to try to avoid further EH measures.
+ * If the command has not completed yet, we must not fail to find it.
  */
 
-       if (hostdata->connected == cmd) {
-               dprintk(NDEBUG_ABORT, "scsi%d : aborting connected command\n", instance->host_no);
-               hostdata->aborted = 1;
-/*
- * We should perform BSY checking, and make sure we haven't slipped
- * into BUS FREE.
- */
+static int NCR5380_abort(struct scsi_cmnd *cmd)
+{
+       struct Scsi_Host *instance = cmd->device->host;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       unsigned long flags;
+       int result = SUCCESS;
 
-               NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN);
-/* 
- * Since we can't change phases until we've completed the current 
- * handshake, we have to source or sink a byte of data if the current
- * phase is not MSGOUT.
- */
+       spin_lock_irqsave(&hostdata->lock, flags);
 
-/* 
- * Return control to the executing NCR drive so we can clear the
- * aborted flag and get back into our main loop.
- */
+#if (NDEBUG & NDEBUG_ANY)
+       scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+       NCR5380_dprint(NDEBUG_ANY, instance);
+       NCR5380_dprint_phase(NDEBUG_ANY, instance);
 
-               return SUCCESS;
+       if (list_del_cmd(&hostdata->unissued, cmd)) {
+               dsprintk(NDEBUG_ABORT, instance,
+                        "abort: removed %p from issue queue\n", cmd);
+               cmd->result = DID_ABORT << 16;
+               cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
        }
-#endif
 
-/* 
- * Case 2 : If the command hasn't been issued yet, we simply remove it 
- *          from the issue queue.
- */
-       dprintk(NDEBUG_ABORT, "scsi%d : abort going into loop.\n", instance->host_no);
-       for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue), tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
-               if (cmd == tmp) {
-                       REMOVE(5, *prev, tmp, tmp->host_scribble);
-                       (*prev) = (struct scsi_cmnd *) tmp->host_scribble;
-                       tmp->host_scribble = NULL;
-                       tmp->result = DID_ABORT << 16;
-                       dprintk(NDEBUG_ABORT, "scsi%d : abort removed command from issue queue.\n", instance->host_no);
-                       tmp->scsi_done(tmp);
-                       return SUCCESS;
+       if (hostdata->selecting == cmd) {
+               dsprintk(NDEBUG_ABORT, instance,
+                        "abort: cmd %p == selecting\n", cmd);
+               hostdata->selecting = NULL;
+               cmd->result = DID_ABORT << 16;
+               complete_cmd(instance, cmd);
+               goto out;
+       }
+
+       if (list_del_cmd(&hostdata->disconnected, cmd)) {
+               dsprintk(NDEBUG_ABORT, instance,
+                        "abort: removed %p from disconnected list\n", cmd);
+               cmd->result = DID_ERROR << 16;
+               if (!hostdata->connected)
+                       NCR5380_select(instance, cmd);
+               if (hostdata->connected != cmd) {
+                       complete_cmd(instance, cmd);
+                       result = FAILED;
+                       goto out;
+               }
+       }
+
+       if (hostdata->connected == cmd) {
+               dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+               hostdata->connected = NULL;
+               if (do_abort(instance)) {
+                       set_host_byte(cmd, DID_ERROR);
+                       complete_cmd(instance, cmd);
+                       result = FAILED;
+                       goto out;
                }
-#if (NDEBUG  & NDEBUG_ABORT)
-       /* KLL */
-               else if (prev == tmp)
-                       printk(KERN_ERR "scsi%d : LOOP\n", instance->host_no);
+               set_host_byte(cmd, DID_ABORT);
+#ifdef REAL_DMA
+               hostdata->dma_len = 0;
 #endif
+               if (cmd->cmnd[0] == REQUEST_SENSE)
+                       complete_cmd(instance, cmd);
+               else {
+                       struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
 
-/* 
- * Case 3 : If any commands are connected, we're going to fail the abort
- *          and let the high level SCSI driver retry at a later time or 
- *          issue a reset.
- *
- *          Timeouts, and therefore aborted commands, will be highly unlikely
- *          and handling them cleanly in this situation would make the common
- *          case of noresets less efficient, and would pollute our code.  So,
- *          we fail.
- */
+                       /* Perform autosense for this command */
+                       list_add(&ncmd->list, &hostdata->autosense);
+               }
+       }
 
-       if (hostdata->connected) {
-               dprintk(NDEBUG_ABORT, "scsi%d : abort failed, command connected.\n", instance->host_no);
-               return FAILED;
+       if (list_find_cmd(&hostdata->autosense, cmd)) {
+               dsprintk(NDEBUG_ABORT, instance,
+                        "abort: found %p on sense queue\n", cmd);
+               spin_unlock_irqrestore(&hostdata->lock, flags);
+               queue_work(hostdata->work_q, &hostdata->main_task);
+               msleep(1000);
+               spin_lock_irqsave(&hostdata->lock, flags);
+               if (list_del_cmd(&hostdata->autosense, cmd)) {
+                       dsprintk(NDEBUG_ABORT, instance,
+                                "abort: removed %p from sense queue\n", cmd);
+                       set_host_byte(cmd, DID_ABORT);
+                       complete_cmd(instance, cmd);
+                       goto out;
+               }
        }
-/*
- * Case 4: If the command is currently disconnected from the bus, and 
- *      there are no connected commands, we reconnect the I_T_L or 
- *      I_T_L_Q nexus associated with it, go into message out, and send 
- *      an abort message.
- *
- * This case is especially ugly. In order to reestablish the nexus, we
- * need to call NCR5380_select().  The easiest way to implement this 
- * function was to abort if the bus was busy, and let the interrupt
- * handler triggered on the SEL for reselect take care of lost arbitrations
- * where necessary, meaning interrupts need to be enabled.
- *
- * When interrupts are enabled, the queues may change - so we 
- * can't remove it from the disconnected queue before selecting it
- * because that could cause a failure in hashing the nexus if that 
- * device reselected.
- * 
- * Since the queues may change, we can't use the pointers from when we
- * first locate it.
- *
- * So, we must first locate the command, and if NCR5380_select()
- * succeeds, then issue the abort, relocate the command and remove
- * it from the disconnected queue.
- */
 
-       for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; tmp = (struct scsi_cmnd *) tmp->host_scribble)
-               if (cmd == tmp) {
-                       dprintk(NDEBUG_ABORT, "scsi%d : aborting disconnected command.\n", instance->host_no);
+       if (hostdata->connected == cmd) {
+               dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+               hostdata->connected = NULL;
+               if (do_abort(instance)) {
+                       set_host_byte(cmd, DID_ERROR);
+                       complete_cmd(instance, cmd);
+                       result = FAILED;
+                       goto out;
+               }
+               set_host_byte(cmd, DID_ABORT);
+#ifdef REAL_DMA
+               hostdata->dma_len = 0;
+#endif
+               complete_cmd(instance, cmd);
+       }
 
-                       if (NCR5380_select(instance, cmd))
-                               return FAILED;
-                       dprintk(NDEBUG_ABORT, "scsi%d : nexus reestablished.\n", instance->host_no);
+out:
+       if (result == FAILED)
+               dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd);
+       else
+               dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd);
 
-                       do_abort(instance);
+       queue_work(hostdata->work_q, &hostdata->main_task);
+       spin_unlock_irqrestore(&hostdata->lock, flags);
 
-                       for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue), tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
-                               if (cmd == tmp) {
-                                       REMOVE(5, *prev, tmp, tmp->host_scribble);
-                                       *prev = (struct scsi_cmnd *) tmp->host_scribble;
-                                       tmp->host_scribble = NULL;
-                                       tmp->result = DID_ABORT << 16;
-                                       tmp->scsi_done(tmp);
-                                       return SUCCESS;
-                               }
-               }
-/*
- * Case 5 : If we reached this point, the command was not found in any of 
- *          the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
-       printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n"
-                       "         before abortion\n", instance->host_no);
-       return FAILED;
+       return result;
 }
 
 
-/* 
- * Function : int NCR5380_bus_reset (struct scsi_cmnd *cmd)
- * 
- * Purpose : reset the SCSI bus.
- *
- * Returns : SUCCESS
+/**
+ * NCR5380_bus_reset - reset the SCSI bus
+ * @cmd: SCSI command undergoing EH
  *
- * Locks: host lock taken by caller
+ * Returns SUCCESS
  */
 
 static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
 {
        struct Scsi_Host *instance = cmd->device->host;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       int i;
+       unsigned long flags;
+       struct NCR5380_cmd *ncmd;
 
-       NCR5380_local_declare();
-       NCR5380_setup(instance);
-       NCR5380_print_status(instance);
+       spin_lock_irqsave(&hostdata->lock, flags);
+
+#if (NDEBUG & NDEBUG_ANY)
+       scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+       NCR5380_dprint(NDEBUG_ANY, instance);
+       NCR5380_dprint_phase(NDEBUG_ANY, instance);
 
-       spin_lock_irq(instance->host_lock);
        do_reset(instance);
-       spin_unlock_irq(instance->host_lock);
+
+       /* reset NCR registers */
+       NCR5380_write(MODE_REG, MR_BASE);
+       NCR5380_write(TARGET_COMMAND_REG, 0);
+       NCR5380_write(SELECT_ENABLE_REG, 0);
+
+       /* After the reset, there are no more connected or disconnected commands
+        * and no busy units; so clear the low-level status here to avoid
+        * conflicts when the mid-level code tries to wake up the affected
+        * commands!
+        */
+
+       hostdata->selecting = NULL;
+
+       list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+               struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+               set_host_byte(cmd, DID_RESET);
+               cmd->scsi_done(cmd);
+       }
+
+       list_for_each_entry(ncmd, &hostdata->autosense, list) {
+               struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+               set_host_byte(cmd, DID_RESET);
+               cmd->scsi_done(cmd);
+       }
+
+       if (hostdata->connected) {
+               set_host_byte(hostdata->connected, DID_RESET);
+               complete_cmd(instance, hostdata->connected);
+               hostdata->connected = NULL;
+       }
+
+       if (hostdata->sensing) {
+               set_host_byte(hostdata->connected, DID_RESET);
+               complete_cmd(instance, hostdata->sensing);
+               hostdata->sensing = NULL;
+       }
+
+       for (i = 0; i < 8; ++i)
+               hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+       hostdata->dma_len = 0;
+#endif
+
+       queue_work(hostdata->work_q, &hostdata->main_task);
+       spin_unlock_irqrestore(&hostdata->lock, flags);
 
        return SUCCESS;
 }
index 162112d..a792886 100644 (file)
 #ifndef NCR5380_H
 #define NCR5380_H
 
+#include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_eh.h>
+#include <scsi/scsi_transport_spi.h>
 
 #define NDEBUG_ARBITRATION     0x1
 #define NDEBUG_AUTOSENSE       0x2
 /* Write any value to this register to start an ini mode DMA receive */
 #define START_DMA_INITIATOR_RECEIVE_REG 7      /* wo */
 
-#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8    /* rw */
-
+/* NCR 53C400(A) Control Status Register bits: */
 #define CSR_RESET              0x80    /* wo  Resets 53c400 */
 #define CSR_53C80_REG          0x80    /* ro  5380 registers busy */
 #define CSR_TRANS_DIR          0x40    /* rw  Data transfer direction */
 #define CSR_BASE CSR_53C80_INTR
 #endif
 
-/* Number of 128-byte blocks to be transferred */
-#define C400_BLOCK_COUNTER_REG   NCR53C400_register_offset-7   /* rw */
-
-/* Resume transfer after disconnect */
-#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6   /* wo */
-
-/* Access to host buffer stack */
-#define C400_HOST_BUFFER         NCR53C400_register_offset-4   /* rw */
-
-
 /* Note : PHASE_* macros are based on the values of the STATUS register */
 #define PHASE_MASK     (SR_MSG | SR_CD | SR_IO)
 
 
 #define PHASE_SR_TO_TCR(phase) ((phase) >> 2)
 
-/*
- * The internal should_disconnect() function returns these based on the 
- * expected length of a disconnect if a device supports disconnect/
- * reconnect.
- */
-
-#define DISCONNECT_NONE                0
-#define DISCONNECT_TIME_TO_DATA        1
-#define DISCONNECT_LONG                2
-
 /* 
  * "Special" value for the (unsigned char) command tag, to indicate
  * I_T_L nexus instead of I_T_L_Q.
 #define NO_IRQ         0
 #endif
 
-#define FLAG_HAS_LAST_BYTE_SENT                1       /* NCR53c81 or better */
-#define FLAG_CHECK_LAST_BYTE_SENT      2       /* Only test once */
-#define FLAG_NCR53C400                 4       /* NCR53c400 */
+#define FLAG_NO_DMA_FIXUP              1       /* No DMA errata workarounds */
 #define FLAG_NO_PSEUDO_DMA             8       /* Inhibit DMA */
-#define FLAG_DTC3181E                  16      /* DTC3181E */
 #define FLAG_LATE_DMA_SETUP            32      /* Setup NCR before DMA H/W */
 #define FLAG_TAGGED_QUEUING            64      /* as X3T9.2 spelled it */
-
-#ifndef ASM
+#define FLAG_TOSHIBA_DELAY             128     /* Allow for borken CD-ROMs */
 
 #ifdef SUPPORT_TAGS
 struct tag_alloc {
@@ -258,33 +238,24 @@ struct NCR5380_hostdata {
        NCR5380_implementation_fields;          /* implementation specific */
        struct Scsi_Host *host;                 /* Host backpointer */
        unsigned char id_mask, id_higher_mask;  /* 1 << id, all bits greater */
-       unsigned char targets_present;          /* targets we have connected
-                                                  to, so we can call a select
-                                                  failure a retryable condition */
-       volatile unsigned char busy[8];         /* index = target, bit = lun */
+       unsigned char busy[8];                  /* index = target, bit = lun */
 #if defined(REAL_DMA) || defined(REAL_DMA_POLL)
-       volatile int dma_len;                   /* requested length of DMA */
+       int dma_len;                            /* requested length of DMA */
 #endif
-       volatile unsigned char last_message;    /* last message OUT */
-       volatile struct scsi_cmnd *connected;   /* currently connected command */
-       volatile struct scsi_cmnd *issue_queue; /* waiting to be issued */
-       volatile struct scsi_cmnd *disconnected_queue;  /* waiting for reconnect */
-       volatile int restart_select;            /* we have disconnected,
-                                                  used to restart 
-                                                  NCR5380_select() */
-       volatile unsigned aborted:1;            /* flag, says aborted */
+       unsigned char last_message;             /* last message OUT */
+       struct scsi_cmnd *connected;            /* currently connected cmnd */
+       struct scsi_cmnd *selecting;            /* cmnd to be connected */
+       struct list_head unissued;              /* waiting to be issued */
+       struct list_head autosense;             /* priority issue queue */
+       struct list_head disconnected;          /* waiting for reconnect */
+       spinlock_t lock;                        /* protects this struct */
        int flags;
-       unsigned long time_expires;             /* in jiffies, set prior to sleeping */
-       int select_time;                        /* timer in select for target response */
-       volatile struct scsi_cmnd *selecting;
-       struct delayed_work coroutine;          /* our co-routine */
        struct scsi_eh_save ses;
+       struct scsi_cmnd *sensing;
        char info[256];
        int read_overruns;                /* number of bytes to cut from a
                                           * transfer to handle chip overruns */
-       int retain_dma_intr;
        struct work_struct main_task;
-       volatile int main_running;
 #ifdef SUPPORT_TAGS
        struct tag_alloc TagAlloc[8][8];        /* 8 targets and 8 LUNs */
 #endif
@@ -292,10 +263,23 @@ struct NCR5380_hostdata {
        unsigned spin_max_r;
        unsigned spin_max_w;
 #endif
+       struct workqueue_struct *work_q;
+       unsigned long accesses_per_ms;  /* chip register accesses per ms */
 };
 
 #ifdef __KERNEL__
 
+struct NCR5380_cmd {
+       struct list_head list;
+};
+
+#define NCR5380_CMD_SIZE               (sizeof(struct NCR5380_cmd))
+
+static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr)
+{
+       return ((struct scsi_cmnd *)ncmd_ptr) - 1;
+}
+
 #ifndef NDEBUG
 #define NDEBUG (0)
 #endif
@@ -304,6 +288,11 @@ struct NCR5380_hostdata {
        do { if ((NDEBUG) & (flg)) \
                printk(KERN_DEBUG fmt, ## __VA_ARGS__); } while (0)
 
+#define dsprintk(flg, host, fmt, ...) \
+       do { if ((NDEBUG) & (flg)) \
+               shost_printk(KERN_DEBUG, host, fmt, ## __VA_ARGS__); \
+       } while (0)
+
 #if NDEBUG
 #define NCR5380_dprint(flg, arg) \
        do { if ((NDEBUG) & (flg)) NCR5380_print(arg); } while (0)
@@ -320,6 +309,7 @@ static void NCR5380_print(struct Scsi_Host *instance);
 static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible);
 #endif
 static int NCR5380_init(struct Scsi_Host *instance, int flags);
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *);
 static void NCR5380_exit(struct Scsi_Host *instance);
 static void NCR5380_information_transfer(struct Scsi_Host *instance);
 #ifndef DONT_USE_INTR
@@ -328,7 +318,7 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id);
 static void NCR5380_main(struct work_struct *work);
 static const char *NCR5380_info(struct Scsi_Host *instance);
 static void NCR5380_reselect(struct Scsi_Host *instance);
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd);
+static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *);
 #if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
 static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
 #endif
@@ -443,5 +433,4 @@ static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance)
 #endif                         /* defined(i386) || defined(__alpha__) */
 #endif                         /* defined(REAL_DMA)  */
 #endif                         /* __KERNEL__ */
-#endif                         /* ndef ASM */
 #endif                         /* NCR5380_H */
index d28d6c0..221f18c 100644 (file)
@@ -4,9 +4,7 @@
  * Copyright 1995-2002, Russell King
  */
 #include <linux/module.h>
-#include <linux/signal.h>
 #include <linux/ioport.h>
-#include <linux/delay.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
 
 
 #include <scsi/scsi_host.h>
 
-#include <scsi/scsicam.h>
-
 #define PSEUDO_DMA
 
 #define priv(host)                     ((struct NCR5380_hostdata *)(host)->hostdata)
-#define NCR5380_local_declare()                struct Scsi_Host *_instance
-#define NCR5380_setup(instance)                _instance = instance
-#define NCR5380_read(reg)              cumanascsi_read(_instance, reg)
-#define NCR5380_write(reg, value)      cumanascsi_write(_instance, reg, value)
+#define NCR5380_read(reg)              cumanascsi_read(instance, reg)
+#define NCR5380_write(reg, value)      cumanascsi_write(instance, reg, value)
+
+#define NCR5380_dma_xfer_len(instance, cmd, phase)     (cmd->transfersize)
+
 #define NCR5380_intr                   cumanascsi_intr
 #define NCR5380_queue_command          cumanascsi_queue_command
 #define NCR5380_info                   cumanascsi_info
@@ -211,6 +208,8 @@ static struct scsi_host_template cumanascsi_template = {
        .cmd_per_lun            = 2,
        .use_clustering         = DISABLE_CLUSTERING,
        .proc_name              = "CumanaSCSI-1",
+       .cmd_size               = NCR5380_CMD_SIZE,
+       .max_sectors            = 128,
 };
 
 static int cumanascsi1_probe(struct expansion_card *ec,
@@ -240,23 +239,21 @@ static int cumanascsi1_probe(struct expansion_card *ec,
 
        host->irq = ec->irq;
 
-       NCR5380_init(host, 0);
+       ret = NCR5380_init(host, 0);
+       if (ret)
+               goto out_unmap;
+
+       NCR5380_maybe_reset_bus(host);
 
         priv(host)->ctrl = 0;
         writeb(0, priv(host)->base + CTRL);
 
-       host->n_io_port = 255;
-       if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
-               ret = -EBUSY;
-               goto out_unmap;
-       }
-
        ret = request_irq(host->irq, cumanascsi_intr, 0,
                          "CumanaSCSI-1", host);
        if (ret) {
                printk("scsi%d: IRQ%d not free: %d\n",
                    host->host_no, host->irq, ret);
-               goto out_unmap;
+               goto out_exit;
        }
 
        ret = scsi_add_host(host, &ec->dev);
@@ -268,6 +265,8 @@ static int cumanascsi1_probe(struct expansion_card *ec,
 
  out_free_irq:
        free_irq(host->irq, host);
+ out_exit:
+       NCR5380_exit(host);
  out_unmap:
        iounmap(priv(host)->base);
        iounmap(priv(host)->dma);
index 7c6fa14..1fab1d1 100644 (file)
@@ -5,9 +5,7 @@
  */
 
 #include <linux/module.h>
-#include <linux/signal.h>
 #include <linux/ioport.h>
-#include <linux/delay.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
 
 #define DONT_USE_INTR
 
 #define priv(host)                     ((struct NCR5380_hostdata *)(host)->hostdata)
-#define NCR5380_local_declare()                void __iomem *_base
-#define NCR5380_setup(host)            _base = priv(host)->base
 
-#define NCR5380_read(reg)              readb(_base + ((reg) << 2))
-#define NCR5380_write(reg, value)      writeb(value, _base + ((reg) << 2))
+#define NCR5380_read(reg) \
+       readb(priv(instance)->base + ((reg) << 2))
+#define NCR5380_write(reg, value) \
+       writeb(value, priv(instance)->base + ((reg) << 2))
+
+#define NCR5380_dma_xfer_len(instance, cmd, phase)     (cmd->transfersize)
+
 #define NCR5380_queue_command          oakscsi_queue_command
 #define NCR5380_info                   oakscsi_info
-#define NCR5380_show_info              oakscsi_show_info
 
 #define NCR5380_implementation_fields  \
        void __iomem *base
@@ -103,7 +103,6 @@ printk("reading %p len %d\n", addr, len);
 
 static struct scsi_host_template oakscsi_template = {
        .module                 = THIS_MODULE,
-       .show_info              = oakscsi_show_info,
        .name                   = "Oak 16-bit SCSI",
        .info                   = oakscsi_info,
        .queuecommand           = oakscsi_queue_command,
@@ -115,6 +114,8 @@ static struct scsi_host_template oakscsi_template = {
        .cmd_per_lun            = 2,
        .use_clustering         = DISABLE_CLUSTERING,
        .proc_name              = "oakscsi",
+       .cmd_size               = NCR5380_CMD_SIZE,
+       .max_sectors            = 128,
 };
 
 static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
@@ -142,15 +143,21 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
        host->irq = NO_IRQ;
        host->n_io_port = 255;
 
-       NCR5380_init(host, 0);
+       ret = NCR5380_init(host, 0);
+       if (ret)
+               goto out_unmap;
+
+       NCR5380_maybe_reset_bus(host);
 
        ret = scsi_add_host(host, &ec->dev);
        if (ret)
-               goto out_unmap;
+               goto out_exit;
 
        scsi_scan_host(host);
        goto out;
 
+ out_exit:
+       NCR5380_exit(host);
  out_unmap:
        iounmap(priv(host)->base);
  unreg:
index db87ece..e654786 100644 (file)
@@ -1,15 +1,15 @@
 /*
  * NCR 5380 generic driver routines.  These should make it *trivial*
- *     to implement 5380 SCSI drivers under Linux with a non-trantor
- *     architecture.
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
  *
- *     Note that these routines also work with NR53c400 family chips.
+ * Note that these routines also work with NR53c400 family chips.
  *
  * Copyright 1993, Drew Eckhardt
- *     Visionary Computing
- *     (Unix and Linux consulting and custom programming)
- *     drew@colorado.edu
- *     +1 (303) 666-5836
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
  *
  * For more information, please consult
  *
  * 1+ (800) 334-5454
  */
 
-/*
- * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
- * this file, too:
- *
- *  - Some of the debug statements were incorrect (undefined variables and the
- *    like). I fixed that.
- *
- *  - In information_transfer(), I think a #ifdef was wrong. Looking at the
- *    possible DMA transfer size should also happen for REAL_DMA. I added this
- *    in the #if statement.
- *
- *  - When using real DMA, information_transfer() should return in a DATAOUT
- *    phase after starting the DMA. It has nothing more to do.
- *
- *  - The interrupt service routine should run main after end of DMA, too (not
- *    only after RESELECTION interrupts). Additionally, it should _not_ test
- *    for more interrupts after running main, since a DMA process may have
- *    been started and interrupts are turned on now. The new int could happen
- *    inside the execution of NCR5380_intr(), leading to recursive
- *    calls.
- *
- *  - I've added a function merge_contiguous_buffers() that tries to
- *    merge scatter-gather buffers that are located at contiguous
- *    physical addresses and can be processed with the same DMA setup.
- *    Since most scatter-gather operations work on a page (4K) of
- *    4 buffers (1K), in more than 90% of all cases three interrupts and
- *    DMA setup actions are saved.
- *
- * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
- *    and USLEEP, because these were messing up readability and will never be
- *    needed for Atari SCSI.
- *
- * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
- *   stuff), and 'main' is executed in a bottom half if awoken by an
- *   interrupt.
- *
- * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
- *   constructs. In my eyes, this made the source rather unreadable, so I
- *   finally replaced that by the *_PRINTK() macros.
- *
- */
-
-/*
- * Further development / testing that should be done :
- * 1.  Test linked command handling code after Eric is ready with
- *     the high level code.
- */
+/* Ported to Atari by Roman Hodek and others. */
 
 /* Adapted for the sun3 by Sam Creasey. */
 
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_transport_spi.h>
-
-#if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x, y)                                             \
-       do {                                                    \
-               printk("LINE:%d   Adding %p to %p\n",           \
-                      __LINE__, (void*)(x), (void*)(y));       \
-               if ((x) == (y))                                 \
-                       udelay(5);                              \
-       } while (0)
-#define REMOVE(w, x, y, z)                                     \
-       do {                                                    \
-               printk("LINE:%d   Removing: %p->%p  %p->%p \n", \
-                      __LINE__, (void*)(w), (void*)(x),        \
-                      (void*)(y), (void*)(z));                 \
-               if ((x) == (y))                                 \
-                       udelay(5);                              \
-       } while (0)
-#else
-#define LIST(x,y)
-#define REMOVE(w,x,y,z)
-#endif
-
-#ifndef notyet
-#undef LINKED
-#endif
-
 /*
  * Design
  *
  * piece of hardware that requires you to sit in a loop polling for
  * the REQ signal as long as you are connected.  Some devices are
  * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
- * while doing long seek operations.
- *
- * The workaround for this is to keep track of devices that have
- * disconnected.  If the device hasn't disconnected, for commands that
- * should disconnect, we do something like
- *
- * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- *
- * Some tweaking of N and M needs to be done.  An algorithm based
- * on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these
+ * while doing long seek operations. [...] These
  * broken devices are the exception rather than the rule and I'd rather
  * spend my time optimizing for the normal case.
  *
  *
  * These macros control options :
  * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- *     for commands that return with a CHECK CONDITION status.
+ * for commands that return with a CHECK CONDITION status.
  *
  * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
- *     transceivers.
- *
- * LINKED - if defined, linked commands are supported.
+ * transceivers.
  *
  * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
  *
  * NCR5380_write(register, value) - write to the specific register
  *
  * NCR5380_implementation_fields  - additional fields needed for this
- *      specific implementation of the NCR5380
+ * specific implementation of the NCR5380
  *
  * Either real DMA *or* pseudo DMA may be implemented
  * REAL functions :
  * NCR5380_REAL_DMA should be defined if real DMA is to be used.
  * Note that the DMA setup functions should return the number of bytes
- *     that they were able to program the controller for.
+ * that they were able to program the controller for.
  *
  * Also note that generic i386/PC versions of these macros are
- *     available as NCR5380_i386_dma_write_setup,
- *     NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ * available as NCR5380_i386_dma_write_setup,
+ * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
  *
  * NCR5380_dma_write_setup(instance, src, count) - initialize
  * NCR5380_dma_read_setup(instance, dst, count) - initialize
  * possible) function may be used.
  */
 
-/* Macros ease life... :-) */
-#define        SETUP_HOSTDATA(in)                              \
-    struct NCR5380_hostdata *hostdata =                        \
-       (struct NCR5380_hostdata *)(in)->hostdata
-#define        HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
-
-#define        NEXT(cmd)               ((struct scsi_cmnd *)(cmd)->host_scribble)
-#define        SET_NEXT(cmd,next)      ((cmd)->host_scribble = (void *)(next))
-#define        NEXTADDR(cmd)           ((struct scsi_cmnd **)&(cmd)->host_scribble)
-
-#define        HOSTNO          instance->host_no
-#define        H_NO(cmd)       (cmd)->device->host->host_no
+static int do_abort(struct Scsi_Host *);
+static void do_reset(struct Scsi_Host *);
 
 #ifdef SUPPORT_TAGS
 
  * cannot know it in advance :-( We just see a QUEUE_FULL status being
  * returned. So, in this case, the driver internal queue size assumption is
  * reduced to the number of active tags if QUEUE_FULL is returned by the
- * target. The command is returned to the mid-level, but with status changed
- * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
- * correctly.
+ * target.
  *
  * We're also not allowed running tagged commands as long as an untagged
  * command is active. And REQUEST SENSE commands after a contingent allegiance
@@ -304,7 +206,8 @@ static void __init init_tags(struct NCR5380_hostdata *hostdata)
 static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
 {
        u8 lun = cmd->device->lun;
-       SETUP_HOSTDATA(cmd->device->host);
+       struct Scsi_Host *instance = cmd->device->host;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
 
        if (hostdata->busy[cmd->device->id] & (1 << lun))
                return 1;
@@ -314,8 +217,8 @@ static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
                return 0;
        if (hostdata->TagAlloc[scmd_id(cmd)][lun].nr_allocated >=
            hostdata->TagAlloc[scmd_id(cmd)][lun].queue_size) {
-               dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d: no free tags\n",
-                          H_NO(cmd), cmd->device->id, lun);
+               dsprintk(NDEBUG_TAGS, instance, "target %d lun %d: no free tags\n",
+                        scmd_id(cmd), lun);
                return 1;
        }
        return 0;
@@ -330,7 +233,8 @@ static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
 static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
 {
        u8 lun = cmd->device->lun;
-       SETUP_HOSTDATA(cmd->device->host);
+       struct Scsi_Host *instance = cmd->device->host;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
 
        /* If we or the target don't support tagged queuing, allocate the LUN for
         * an untagged command.
@@ -340,18 +244,16 @@ static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
            !cmd->device->tagged_supported) {
                cmd->tag = TAG_NONE;
                hostdata->busy[cmd->device->id] |= (1 << lun);
-               dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d now allocated by untagged "
-                          "command\n", H_NO(cmd), cmd->device->id, lun);
+               dsprintk(NDEBUG_TAGS, instance, "target %d lun %d now allocated by untagged command\n",
+                        scmd_id(cmd), lun);
        } else {
                struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
 
                cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS);
                set_bit(cmd->tag, ta->allocated);
                ta->nr_allocated++;
-               dprintk(NDEBUG_TAGS, "scsi%d: using tag %d for target %d lun %d "
-                          "(now %d tags in use)\n",
-                          H_NO(cmd), cmd->tag, cmd->device->id,
-                          lun, ta->nr_allocated);
+               dsprintk(NDEBUG_TAGS, instance, "using tag %d for target %d lun %d (%d tags allocated)\n",
+                        cmd->tag, scmd_id(cmd), lun, ta->nr_allocated);
        }
 }
 
@@ -363,21 +265,22 @@ static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
 static void cmd_free_tag(struct scsi_cmnd *cmd)
 {
        u8 lun = cmd->device->lun;
-       SETUP_HOSTDATA(cmd->device->host);
+       struct Scsi_Host *instance = cmd->device->host;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
 
        if (cmd->tag == TAG_NONE) {
                hostdata->busy[cmd->device->id] &= ~(1 << lun);
-               dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d untagged cmd finished\n",
-                          H_NO(cmd), cmd->device->id, lun);
+               dsprintk(NDEBUG_TAGS, instance, "target %d lun %d untagged cmd freed\n",
+                        scmd_id(cmd), lun);
        } else if (cmd->tag >= MAX_TAGS) {
-               printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
-                      H_NO(cmd), cmd->tag);
+               shost_printk(KERN_NOTICE, instance,
+                            "trying to free bad tag %d!\n", cmd->tag);
        } else {
                struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
                clear_bit(cmd->tag, ta->allocated);
                ta->nr_allocated--;
-               dprintk(NDEBUG_TAGS, "scsi%d: freed tag %d for target %d lun %d\n",
-                          H_NO(cmd), cmd->tag, cmd->device->id, lun);
+               dsprintk(NDEBUG_TAGS, instance, "freed tag %d for target %d lun %d\n",
+                        cmd->tag, scmd_id(cmd), lun);
        }
 }
 
@@ -401,17 +304,15 @@ static void free_all_tags(struct NCR5380_hostdata *hostdata)
 
 #endif /* SUPPORT_TAGS */
 
-
-/*
- * Function: void merge_contiguous_buffers( struct scsi_cmnd *cmd )
- *
- * Purpose: Try to merge several scatter-gather requests into one DMA
- *    transfer. This is possible if the scatter buffers lie on
- *    physical contiguous addresses.
- *
- * Parameters: struct scsi_cmnd *cmd
- *    The command to work on. The first scatter buffer's data are
- *    assumed to be already transferred into ptr/this_residual.
+/**
+ * merge_contiguous_buffers - coalesce scatter-gather list entries
+ * @cmd: command requesting IO
+ *
+ * Try to merge several scatter-gather buffers into one DMA transfer.
+ * This is possible if the scatter buffers lie on physically
+ * contiguous addresses. The first scatter-gather buffer's data are
+ * assumed to be already transferred into cmd->SCp.this_residual.
+ * Every buffer merged avoids an interrupt and a DMA setup operation.
  */
 
 static void merge_contiguous_buffers(struct scsi_cmnd *cmd)
@@ -463,9 +364,7 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
                cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
                cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
                cmd->SCp.this_residual = cmd->SCp.buffer->length;
-               /* ++roman: Try to merge some scatter-buffers if they are at
-                * contiguous physical addresses.
-                */
+
                merge_contiguous_buffers(cmd);
        } else {
                cmd->SCp.buffer = NULL;
@@ -473,31 +372,110 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
                cmd->SCp.ptr = NULL;
                cmd->SCp.this_residual = 0;
        }
+
+       cmd->SCp.Status = 0;
+       cmd->SCp.Message = 0;
+}
+
+/**
+ * NCR5380_poll_politely2 - wait for two chip register values
+ * @instance: controller to poll
+ * @reg1: 5380 register to poll
+ * @bit1: Bitmask to check
+ * @val1: Expected value
+ * @reg2: Second 5380 register to poll
+ * @bit2: Second bitmask to check
+ * @val2: Second expected value
+ * @wait: Time-out in jiffies
+ *
+ * Polls the chip in a reasonably efficient manner waiting for an
+ * event to occur. After a short quick poll we begin to yield the CPU
+ * (if possible). In irq contexts the time-out is arbitrarily limited.
+ * Callers may hold locks as long as they are held in irq mode.
+ *
+ * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT.
+ */
+
+static int NCR5380_poll_politely2(struct Scsi_Host *instance,
+                                  int reg1, int bit1, int val1,
+                                  int reg2, int bit2, int val2, int wait)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       unsigned long deadline = jiffies + wait;
+       unsigned long n;
+
+       /* Busy-wait for up to 10 ms */
+       n = min(10000U, jiffies_to_usecs(wait));
+       n *= hostdata->accesses_per_ms;
+       n /= 2000;
+       do {
+               if ((NCR5380_read(reg1) & bit1) == val1)
+                       return 0;
+               if ((NCR5380_read(reg2) & bit2) == val2)
+                       return 0;
+               cpu_relax();
+       } while (n--);
+
+       if (irqs_disabled() || in_interrupt())
+               return -ETIMEDOUT;
+
+       /* Repeatedly sleep for 1 ms until deadline */
+       while (time_is_after_jiffies(deadline)) {
+               schedule_timeout_uninterruptible(1);
+               if ((NCR5380_read(reg1) & bit1) == val1)
+                       return 0;
+               if ((NCR5380_read(reg2) & bit2) == val2)
+                       return 0;
+       }
+
+       return -ETIMEDOUT;
 }
 
-#include <linux/delay.h>
+static inline int NCR5380_poll_politely(struct Scsi_Host *instance,
+                                        int reg, int bit, int val, int wait)
+{
+       return NCR5380_poll_politely2(instance, reg, bit, val,
+                                               reg, bit, val, wait);
+}
 
 #if NDEBUG
 static struct {
        unsigned char mask;
        const char *name;
 } signals[] = {
-       { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
-       { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD,  "CD" }, { SR_IO, "IO" },
-       { SR_SEL, "SEL" }, {0, NULL}
-}, basrs[] = {
-       {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}
-}, icrs[] = {
-       {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
-       {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
-       {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+       {SR_DBP, "PARITY"},
+       {SR_RST, "RST"},
+       {SR_BSY, "BSY"},
+       {SR_REQ, "REQ"},
+       {SR_MSG, "MSG"},
+       {SR_CD, "CD"},
+       {SR_IO, "IO"},
+       {SR_SEL, "SEL"},
        {0, NULL}
-}, mrs[] = {
-       {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
-       {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
-       "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+},
+basrs[] = {
+       {BASR_ATN, "ATN"},
+       {BASR_ACK, "ACK"},
+       {0, NULL}
+},
+icrs[] = {
+       {ICR_ASSERT_RST, "ASSERT RST"},
+       {ICR_ASSERT_ACK, "ASSERT ACK"},
+       {ICR_ASSERT_BSY, "ASSERT BSY"},
+       {ICR_ASSERT_SEL, "ASSERT SEL"},
+       {ICR_ASSERT_ATN, "ASSERT ATN"},
+       {ICR_ASSERT_DATA, "ASSERT DATA"},
+       {0, NULL}
+},
+mrs[] = {
+       {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"},
+       {MR_TARGET, "MODE TARGET"},
+       {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"},
+       {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"},
+       {MR_ENABLE_EOP_INTR, "MODE EOP INTR"},
        {MR_MONITOR_BSY, "MODE MONITOR BSY"},
-       {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+       {MR_DMA_MODE, "MODE DMA"},
+       {MR_ARBITRATE, "MODE ARBITRATION"},
        {0, NULL}
 };
 
@@ -511,15 +489,13 @@ static struct {
 static void NCR5380_print(struct Scsi_Host *instance)
 {
        unsigned char status, data, basr, mr, icr, i;
-       unsigned long flags;
 
-       local_irq_save(flags);
        data = NCR5380_read(CURRENT_SCSI_DATA_REG);
        status = NCR5380_read(STATUS_REG);
        mr = NCR5380_read(MODE_REG);
        icr = NCR5380_read(INITIATOR_COMMAND_REG);
        basr = NCR5380_read(BUS_AND_STATUS_REG);
-       local_irq_restore(flags);
+
        printk("STATUS_REG: %02x ", status);
        for (i = 0; signals[i].mask; ++i)
                if (status & signals[i].mask)
@@ -543,8 +519,12 @@ static struct {
        unsigned char value;
        const char *name;
 } phases[] = {
-       {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
-       {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+       {PHASE_DATAOUT, "DATAOUT"},
+       {PHASE_DATAIN, "DATAIN"},
+       {PHASE_CMDOUT, "CMDOUT"},
+       {PHASE_STATIN, "STATIN"},
+       {PHASE_MSGOUT, "MSGOUT"},
+       {PHASE_MSGIN, "MSGIN"},
        {PHASE_UNKNOWN, "UNKNOWN"}
 };
 
@@ -553,8 +533,6 @@ static struct {
  * @instance: adapter to dump
  *
  * Print the current SCSI phase for debugging purposes
- *
- * Locks: none
  */
 
 static void NCR5380_print_phase(struct Scsi_Host *instance)
@@ -564,54 +542,21 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
 
        status = NCR5380_read(STATUS_REG);
        if (!(status & SR_REQ))
-               printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+               shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n");
        else {
                for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
                     (phases[i].value != (status & PHASE_MASK)); ++i)
                        ;
-               printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+               shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name);
        }
 }
-
 #endif
 
-/*
- * ++roman: New scheme of calling NCR5380_main()
- *
- * If we're not in an interrupt, we can call our main directly, it cannot be
- * already running. Else, we queue it on a task queue, if not 'main_running'
- * tells us that a lower level is already executing it. This way,
- * 'main_running' needs not be protected in a special way.
- *
- * queue_main() is a utility function for putting our main onto the task
- * queue, if main_running is false. It should be called only from a
- * interrupt or bottom half.
- */
-
-#include <linux/gfp.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-
-static inline void queue_main(struct NCR5380_hostdata *hostdata)
-{
-       if (!hostdata->main_running) {
-               /* If in interrupt and NCR5380_main() not already running,
-                  queue it on the 'immediate' task queue, to be processed
-                  immediately after the current interrupt processing has
-                  finished. */
-               schedule_work(&hostdata->main_task);
-       }
-       /* else: nothing to do: the running NCR5380_main() will pick up
-          any newly queued command. */
-}
-
 /**
  * NCR58380_info - report driver and host information
  * @instance: relevant scsi host instance
  *
  * For use as the host template info() handler.
- *
- * Locks: none
  */
 
 static const char *NCR5380_info(struct Scsi_Host *instance)
@@ -630,13 +575,14 @@ static void prepare_info(struct Scsi_Host *instance)
                 "base 0x%lx, irq %d, "
                 "can_queue %d, cmd_per_lun %d, "
                 "sg_tablesize %d, this_id %d, "
-                "flags { %s}, "
+                "flags { %s%s}, "
                 "options { %s} ",
                 instance->hostt->name, instance->io_port, instance->n_io_port,
                 instance->base, instance->irq,
                 instance->can_queue, instance->cmd_per_lun,
                 instance->sg_tablesize, instance->this_id,
                 hostdata->flags & FLAG_TAGGED_QUEUING ? "TAGGED_QUEUING " : "",
+                hostdata->flags & FLAG_TOSHIBA_DELAY  ? "TOSHIBA_DELAY "  : "",
 #ifdef DIFFERENTIAL
                 "DIFFERENTIAL "
 #endif
@@ -652,102 +598,6 @@ static void prepare_info(struct Scsi_Host *instance)
                 "");
 }
 
-/**
- * NCR5380_print_status - dump controller info
- * @instance: controller to dump
- *
- * Print commands in the various queues, called from NCR5380_abort
- * to aid debugging.
- */
-
-static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd)
-{
-       int i, s;
-       unsigned char *command;
-       printk("scsi%d: destination target %d, lun %llu\n",
-               H_NO(cmd), cmd->device->id, cmd->device->lun);
-       printk(KERN_CONT "        command = ");
-       command = cmd->cmnd;
-       printk(KERN_CONT "%2d (0x%02x)", command[0], command[0]);
-       for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
-               printk(KERN_CONT " %02x", command[i]);
-       printk("\n");
-}
-
-static void NCR5380_print_status(struct Scsi_Host *instance)
-{
-       struct NCR5380_hostdata *hostdata;
-       struct scsi_cmnd *ptr;
-       unsigned long flags;
-
-       NCR5380_dprint(NDEBUG_ANY, instance);
-       NCR5380_dprint_phase(NDEBUG_ANY, instance);
-
-       hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
-       local_irq_save(flags);
-       printk("NCR5380: coroutine is%s running.\n",
-               hostdata->main_running ? "" : "n't");
-       if (!hostdata->connected)
-               printk("scsi%d: no currently connected command\n", HOSTNO);
-       else
-               lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected);
-       printk("scsi%d: issue_queue\n", HOSTNO);
-       for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
-               lprint_Scsi_Cmnd(ptr);
-
-       printk("scsi%d: disconnected_queue\n", HOSTNO);
-       for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
-            ptr = NEXT(ptr))
-               lprint_Scsi_Cmnd(ptr);
-
-       local_irq_restore(flags);
-       printk("\n");
-}
-
-static void show_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
-{
-       int i, s;
-       unsigned char *command;
-       seq_printf(m, "scsi%d: destination target %d, lun %llu\n",
-               H_NO(cmd), cmd->device->id, cmd->device->lun);
-       seq_puts(m, "        command = ");
-       command = cmd->cmnd;
-       seq_printf(m, "%2d (0x%02x)", command[0], command[0]);
-       for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
-               seq_printf(m, " %02x", command[i]);
-       seq_putc(m, '\n');
-}
-
-static int __maybe_unused NCR5380_show_info(struct seq_file *m,
-                                            struct Scsi_Host *instance)
-{
-       struct NCR5380_hostdata *hostdata;
-       struct scsi_cmnd *ptr;
-       unsigned long flags;
-
-       hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
-       local_irq_save(flags);
-       seq_printf(m, "NCR5380: coroutine is%s running.\n",
-               hostdata->main_running ? "" : "n't");
-       if (!hostdata->connected)
-               seq_printf(m, "scsi%d: no currently connected command\n", HOSTNO);
-       else
-               show_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
-       seq_printf(m, "scsi%d: issue_queue\n", HOSTNO);
-       for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
-               show_Scsi_Cmnd(ptr, m);
-
-       seq_printf(m, "scsi%d: disconnected_queue\n", HOSTNO);
-       for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
-            ptr = NEXT(ptr))
-               show_Scsi_Cmnd(ptr, m);
-
-       local_irq_restore(flags);
-       return 0;
-}
-
 /**
  * NCR5380_init - initialise an NCR5380
  * @instance: adapter to configure
@@ -764,11 +614,11 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m,
 
 static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
 {
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        int i;
-       SETUP_HOSTDATA(instance);
+       unsigned long deadline;
 
        hostdata->host = instance;
-       hostdata->aborted = 0;
        hostdata->id_mask = 1 << instance->this_id;
        hostdata->id_higher_mask = 0;
        for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
@@ -782,13 +632,21 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
 #if defined (REAL_DMA)
        hostdata->dma_len = 0;
 #endif
-       hostdata->targets_present = 0;
+       spin_lock_init(&hostdata->lock);
        hostdata->connected = NULL;
-       hostdata->issue_queue = NULL;
-       hostdata->disconnected_queue = NULL;
+       hostdata->sensing = NULL;
+       INIT_LIST_HEAD(&hostdata->autosense);
+       INIT_LIST_HEAD(&hostdata->unissued);
+       INIT_LIST_HEAD(&hostdata->disconnected);
+
        hostdata->flags = flags;
 
        INIT_WORK(&hostdata->main_task, NCR5380_main);
+       hostdata->work_q = alloc_workqueue("ncr5380_%d",
+                               WQ_UNBOUND | WQ_MEM_RECLAIM,
+                               1, instance->host_no);
+       if (!hostdata->work_q)
+               return -ENOMEM;
 
        prepare_info(instance);
 
@@ -797,6 +655,72 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
        NCR5380_write(TARGET_COMMAND_REG, 0);
        NCR5380_write(SELECT_ENABLE_REG, 0);
 
+       /* Calibrate register polling loop */
+       i = 0;
+       deadline = jiffies + 1;
+       do {
+               cpu_relax();
+       } while (time_is_after_jiffies(deadline));
+       deadline += msecs_to_jiffies(256);
+       do {
+               NCR5380_read(STATUS_REG);
+               ++i;
+               cpu_relax();
+       } while (time_is_after_jiffies(deadline));
+       hostdata->accesses_per_ms = i / 256;
+
+       return 0;
+}
+
+/**
+ * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems.
+ * @instance: adapter to check
+ *
+ * If the system crashed, it may have crashed with a connected target and
+ * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the
+ * currently established nexus, which we know nothing about. Failing that
+ * do a bus reset.
+ *
+ * Note that a bus reset will cause the chip to assert IRQ.
+ *
+ * Returns 0 if successful, otherwise -ENXIO.
+ */
+
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       int pass;
+
+       for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
+               switch (pass) {
+               case 1:
+               case 3:
+               case 5:
+                       shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n");
+                       NCR5380_poll_politely(instance,
+                                             STATUS_REG, SR_BSY, 0, 5 * HZ);
+                       break;
+               case 2:
+                       shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
+                       do_abort(instance);
+                       break;
+               case 4:
+                       shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
+                       do_reset(instance);
+                       /* Wait after a reset; the SCSI standard calls for
+                        * 250ms, we wait 500ms to be on the safe side.
+                        * But some Toshiba CD-ROMs need ten times that.
+                        */
+                       if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+                               msleep(2500);
+                       else
+                               msleep(500);
+                       break;
+               case 6:
+                       shost_printk(KERN_ERR, instance, "bus locked solid\n");
+                       return -ENXIO;
+               }
+       }
        return 0;
 }
 
@@ -812,6 +736,38 @@ static void NCR5380_exit(struct Scsi_Host *instance)
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
 
        cancel_work_sync(&hostdata->main_task);
+       destroy_workqueue(hostdata->work_q);
+}
+
+/**
+ * complete_cmd - finish processing a command and return it to the SCSI ML
+ * @instance: the host instance
+ * @cmd: command to complete
+ */
+
+static void complete_cmd(struct Scsi_Host *instance,
+                         struct scsi_cmnd *cmd)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+       dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd);
+
+       if (hostdata->sensing == cmd) {
+               /* Autosense processing ends here */
+               if ((cmd->result & 0xff) != SAM_STAT_GOOD) {
+                       scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+                       set_host_byte(cmd, DID_ERROR);
+               } else
+                       scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+               hostdata->sensing = NULL;
+       }
+
+#ifdef SUPPORT_TAGS
+       cmd_free_tag(cmd);
+#else
+       hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
+#endif
+       cmd->scsi_done(cmd);
 }
 
 /**
@@ -819,7 +775,7 @@ static void NCR5380_exit(struct Scsi_Host *instance)
  * @instance: the relevant SCSI adapter
  * @cmd: SCSI command
  *
- * cmd is added to the per instance issue_queue, with minor
+ * cmd is added to the per-instance issue queue, with minor
  * twiddling done to the host specific fields of cmd.  If the
  * main coroutine is not running, it is restarted.
  */
@@ -828,44 +784,23 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
                                  struct scsi_cmnd *cmd)
 {
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
-       struct scsi_cmnd *tmp;
+       struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
        unsigned long flags;
 
 #if (NDEBUG & NDEBUG_NO_WRITE)
        switch (cmd->cmnd[0]) {
        case WRITE_6:
        case WRITE_10:
-               printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
-                      H_NO(cmd));
+               shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n");
                cmd->result = (DID_ERROR << 16);
                cmd->scsi_done(cmd);
                return 0;
        }
 #endif /* (NDEBUG & NDEBUG_NO_WRITE) */
 
-       /*
-        * We use the host_scribble field as a pointer to the next command
-        * in a queue
-        */
-
-       SET_NEXT(cmd, NULL);
        cmd->result = 0;
 
        /*
-        * Insert the cmd into the issue queue. Note that REQUEST SENSE
-        * commands are added to the head of the queue since any command will
-        * clear the contingent allegiance condition that exists and the
-        * sense data is only guaranteed to be valid while the condition exists.
-        */
-
-       /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
-        * Otherwise a running NCR5380_main may steal the lock.
-        * Lock before actually inserting due to fairness reasons explained in
-        * atari_scsi.c. If we insert first, then it's impossible for this driver
-        * to release the lock.
-        * Stop timer for this command while waiting for the lock, or timeouts
-        * may happen (and they really do), and it's no good if the command doesn't
-        * appear in any of the queues.
         * ++roman: Just disabling the NCR interrupt isn't sufficient here,
         * because also a timer int can trigger an abort or reset, which would
         * alter queues and touch the lock.
@@ -873,7 +808,7 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
        if (!NCR5380_acquire_dma_irq(instance))
                return SCSI_MLQUEUE_HOST_BUSY;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&hostdata->lock, flags);
 
        /*
         * Insert the cmd into the issue queue. Note that REQUEST SENSE
@@ -882,33 +817,18 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
         * sense data is only guaranteed to be valid while the condition exists.
         */
 
-       if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
-               LIST(cmd, hostdata->issue_queue);
-               SET_NEXT(cmd, hostdata->issue_queue);
-               hostdata->issue_queue = cmd;
-       } else {
-               for (tmp = (struct scsi_cmnd *)hostdata->issue_queue;
-                    NEXT(tmp); tmp = NEXT(tmp))
-                       ;
-               LIST(cmd, tmp);
-               SET_NEXT(tmp, cmd);
-       }
-       local_irq_restore(flags);
+       if (cmd->cmnd[0] == REQUEST_SENSE)
+               list_add(&ncmd->list, &hostdata->unissued);
+       else
+               list_add_tail(&ncmd->list, &hostdata->unissued);
 
-       dprintk(NDEBUG_QUEUES, "scsi%d: command added to %s of queue\n", H_NO(cmd),
-                 (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+       spin_unlock_irqrestore(&hostdata->lock, flags);
 
-       /* If queue_command() is called from an interrupt (real one or bottom
-        * half), we let queue_main() do the job of taking care about main. If it
-        * is already running, this is a no-op, else main will be queued.
-        *
-        * If we're not in an interrupt, we can call NCR5380_main()
-        * unconditionally, because it cannot be already running.
-        */
-       if (in_interrupt() || irqs_disabled())
-               queue_main(hostdata);
-       else
-               NCR5380_main(&hostdata->main_task);
+       dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n",
+                cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+       /* Kick off command processing */
+       queue_work(hostdata->work_q, &hostdata->main_task);
        return 0;
 }
 
@@ -917,13 +837,78 @@ static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
 
        /* Caller does the locking needed to set & test these data atomically */
-       if (!hostdata->disconnected_queue &&
-           !hostdata->issue_queue &&
+       if (list_empty(&hostdata->disconnected) &&
+           list_empty(&hostdata->unissued) &&
+           list_empty(&hostdata->autosense) &&
            !hostdata->connected &&
-           !hostdata->retain_dma_intr)
+           !hostdata->selecting)
                NCR5380_release_dma_irq(instance);
 }
 
+/**
+ * dequeue_next_cmd - dequeue a command for processing
+ * @instance: the scsi host instance
+ *
+ * Priority is given to commands on the autosense queue. These commands
+ * need autosense because of a CHECK CONDITION result.
+ *
+ * Returns a command pointer if a command is found for a target that is
+ * not already busy. Otherwise returns NULL.
+ */
+
+static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       struct NCR5380_cmd *ncmd;
+       struct scsi_cmnd *cmd;
+
+       if (list_empty(&hostdata->autosense)) {
+               list_for_each_entry(ncmd, &hostdata->unissued, list) {
+                       cmd = NCR5380_to_scmd(ncmd);
+                       dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
+                                cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun);
+
+                       if (
+#ifdef SUPPORT_TAGS
+                           !is_lun_busy(cmd, 1)
+#else
+                           !(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))
+#endif
+                       ) {
+                               list_del(&ncmd->list);
+                               dsprintk(NDEBUG_QUEUES, instance,
+                                        "dequeue: removed %p from issue queue\n", cmd);
+                               return cmd;
+                       }
+               }
+       } else {
+               /* Autosense processing begins here */
+               ncmd = list_first_entry(&hostdata->autosense,
+                                       struct NCR5380_cmd, list);
+               list_del(&ncmd->list);
+               cmd = NCR5380_to_scmd(ncmd);
+               dsprintk(NDEBUG_QUEUES, instance,
+                        "dequeue: removed %p from autosense queue\n", cmd);
+               scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+               hostdata->sensing = cmd;
+               return cmd;
+       }
+       return NULL;
+}
+
+static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+
+       if (hostdata->sensing) {
+               scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+               list_add(&ncmd->list, &hostdata->autosense);
+               hostdata->sensing = NULL;
+       } else
+               list_add(&ncmd->list, &hostdata->unissued);
+}
+
 /**
  * NCR5380_main - NCR state machines
  *
@@ -931,8 +916,6 @@ static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
  * be done on the NCR5380 host adapters in a system.  Both
  * NCR5380_queue_command() and NCR5380_intr() will try to start it
  * in case it is not running.
- *
- * Locks: called as its own thread with no locks held.
  */
 
 static void NCR5380_main(struct work_struct *work)
@@ -940,154 +923,69 @@ static void NCR5380_main(struct work_struct *work)
        struct NCR5380_hostdata *hostdata =
                container_of(work, struct NCR5380_hostdata, main_task);
        struct Scsi_Host *instance = hostdata->host;
-       struct scsi_cmnd *tmp, *prev;
+       struct scsi_cmnd *cmd;
        int done;
-       unsigned long flags;
 
        /*
-        * We run (with interrupts disabled) until we're sure that none of
-        * the host adapters have anything that can be done, at which point
-        * we set main_running to 0 and exit.
-        *
-        * Interrupts are enabled before doing various other internal
-        * instructions, after we've decided that we need to run through
-        * the loop again.
-        *
-        * this should prevent any race conditions.
-        *
         * ++roman: Just disabling the NCR interrupt isn't sufficient here,
         * because also a timer int can trigger an abort or reset, which can
         * alter queues and touch the Falcon lock.
         */
 
-       /* Tell int handlers main() is now already executing.  Note that
-          no races are possible here. If an int comes in before
-          'main_running' is set here, and queues/executes main via the
-          task queue, it doesn't do any harm, just this instance of main
-          won't find any work left to do. */
-       if (hostdata->main_running)
-               return;
-       hostdata->main_running = 1;
-
-       local_save_flags(flags);
        do {
-               local_irq_disable();    /* Freeze request queues */
                done = 1;
 
-               if (!hostdata->connected) {
-                       dprintk(NDEBUG_MAIN, "scsi%d: not connected\n", HOSTNO);
-                       /*
-                        * Search through the issue_queue for a command destined
-                        * for a target that's not busy.
-                        */
-#if (NDEBUG & NDEBUG_LISTS)
-                       for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL;
-                            tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
-                               ;
-                       /*printk("%p  ", tmp);*/
-                       if ((tmp == prev) && tmp)
-                               printk(" LOOP\n");
-                       /* else printk("\n"); */
-#endif
-                       for (tmp = (struct scsi_cmnd *) hostdata->issue_queue,
-                            prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) {
-                               u8 lun = tmp->device->lun;
-
-                               dprintk(NDEBUG_LISTS,
-                                       "MAIN tmp=%p target=%d busy=%d lun=%d\n",
-                                       tmp, scmd_id(tmp), hostdata->busy[scmd_id(tmp)],
-                                       lun);
-                               /*  When we find one, remove it from the issue queue. */
-                               /* ++guenther: possible race with Falcon locking */
-                               if (
-#ifdef SUPPORT_TAGS
-                                   !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
-#else
-                                   !(hostdata->busy[tmp->device->id] & (1 << lun))
-#endif
-                                   ) {
-                                       /* ++guenther: just to be sure, this must be atomic */
-                                       local_irq_disable();
-                                       if (prev) {
-                                               REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
-                                               SET_NEXT(prev, NEXT(tmp));
-                                       } else {
-                                               REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
-                                               hostdata->issue_queue = NEXT(tmp);
-                                       }
-                                       SET_NEXT(tmp, NULL);
-                                       hostdata->retain_dma_intr++;
+               spin_lock_irq(&hostdata->lock);
+               while (!hostdata->connected &&
+                      (cmd = dequeue_next_cmd(instance))) {
 
-                                       /* reenable interrupts after finding one */
-                                       local_irq_restore(flags);
+                       dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
 
-                                       /*
-                                        * Attempt to establish an I_T_L nexus here.
-                                        * On success, instance->hostdata->connected is set.
-                                        * On failure, we must add the command back to the
-                                        *   issue queue so we can keep trying.
-                                        */
-                                       dprintk(NDEBUG_MAIN, "scsi%d: main(): command for target %d "
-                                                   "lun %d removed from issue_queue\n",
-                                                   HOSTNO, tmp->device->id, lun);
-                                       /*
-                                        * REQUEST SENSE commands are issued without tagged
-                                        * queueing, even on SCSI-II devices because the
-                                        * contingent allegiance condition exists for the
-                                        * entire unit.
-                                        */
-                                       /* ++roman: ...and the standard also requires that
-                                        * REQUEST SENSE command are untagged.
-                                        */
+                       /*
+                        * Attempt to establish an I_T_L nexus here.
+                        * On success, instance->hostdata->connected is set.
+                        * On failure, we must add the command back to the
+                        * issue queue so we can keep trying.
+                        */
+                       /*
+                        * REQUEST SENSE commands are issued without tagged
+                        * queueing, even on SCSI-II devices because the
+                        * contingent allegiance condition exists for the
+                        * entire unit.
+                        */
+                       /* ++roman: ...and the standard also requires that
+                        * REQUEST SENSE command are untagged.
+                        */
 
 #ifdef SUPPORT_TAGS
-                                       cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
+                       cmd_get_tag(cmd, cmd->cmnd[0] != REQUEST_SENSE);
 #endif
-                                       if (!NCR5380_select(instance, tmp)) {
-                                               local_irq_disable();
-                                               hostdata->retain_dma_intr--;
-                                               /* release if target did not response! */
-                                               maybe_release_dma_irq(instance);
-                                               local_irq_restore(flags);
-                                               break;
-                                       } else {
-                                               local_irq_disable();
-                                               LIST(tmp, hostdata->issue_queue);
-                                               SET_NEXT(tmp, hostdata->issue_queue);
-                                               hostdata->issue_queue = tmp;
+                       cmd = NCR5380_select(instance, cmd);
+                       if (!cmd) {
+                               dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
+                               maybe_release_dma_irq(instance);
+                       } else {
+                               dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
+                                        "main: select failed, returning %p to queue\n", cmd);
+                               requeue_cmd(instance, cmd);
 #ifdef SUPPORT_TAGS
-                                               cmd_free_tag(tmp);
+                               cmd_free_tag(cmd);
 #endif
-                                               hostdata->retain_dma_intr--;
-                                               local_irq_restore(flags);
-                                               dprintk(NDEBUG_MAIN, "scsi%d: main(): select() failed, "
-                                                           "returned to issue_queue\n", HOSTNO);
-                                               if (hostdata->connected)
-                                                       break;
-                                       }
-                               } /* if target/lun/target queue is not busy */
-                       } /* for issue_queue */
-               } /* if (!hostdata->connected) */
-
+                       }
+               }
                if (hostdata->connected
 #ifdef REAL_DMA
                    && !hostdata->dma_len
 #endif
                    ) {
-                       local_irq_restore(flags);
-                       dprintk(NDEBUG_MAIN, "scsi%d: main: performing information transfer\n",
-                                   HOSTNO);
+                       dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n");
                        NCR5380_information_transfer(instance);
-                       dprintk(NDEBUG_MAIN, "scsi%d: main: done set false\n", HOSTNO);
                        done = 0;
                }
+               spin_unlock_irq(&hostdata->lock);
+               if (!done)
+                       cond_resched();
        } while (!done);
-
-       /* Better allow ints _after_ 'main_running' has been cleared, else
-          an interrupt could believe we'll pick up the work it left for
-          us, but we won't see it anymore here... */
-       hostdata->main_running = 0;
-       local_irq_restore(flags);
 }
 
 
@@ -1096,27 +994,20 @@ static void NCR5380_main(struct work_struct *work)
  * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
  *
  * Purpose : Called by interrupt handler when DMA finishes or a phase
- *     mismatch occurs (which would finish the DMA transfer).
+ * mismatch occurs (which would finish the DMA transfer).
  *
  * Inputs : instance - this instance of the NCR5380.
- *
  */
 
 static void NCR5380_dma_complete(struct Scsi_Host *instance)
 {
-       SETUP_HOSTDATA(instance);
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        int transferred;
        unsigned char **data;
-       volatile int *count;
+       int *count;
        int saved_data = 0, overrun = 0;
        unsigned char p;
 
-       if (!hostdata->connected) {
-               printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
-                      "no connected cmd\n", HOSTNO);
-               return;
-       }
-
        if (hostdata->read_overruns) {
                p = hostdata->connected->SCp.phase;
                if (p & SR_IO) {
@@ -1126,15 +1017,11 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
                            (BASR_PHASE_MATCH|BASR_ACK)) {
                                saved_data = NCR5380_read(INPUT_DATA_REG);
                                overrun = 1;
-                               dprintk(NDEBUG_DMA, "scsi%d: read overrun handled\n", HOSTNO);
+                               dsprintk(NDEBUG_DMA, instance, "read overrun handled\n");
                        }
                }
        }
 
-       dprintk(NDEBUG_DMA, "scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
-                  HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
-                  NCR5380_read(STATUS_REG));
-
 #if defined(CONFIG_SUN3)
        if ((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) {
                pr_err("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n",
@@ -1153,9 +1040,9 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
        }
 #endif
 
-       (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
        NCR5380_write(MODE_REG, MR_BASE);
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 
        transferred = hostdata->dma_len - NCR5380_dma_residual(instance);
        hostdata->dma_len = 0;
@@ -1194,140 +1081,160 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
  * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
  * from the disconnected queue, and restarting NCR5380_main()
  * as required.
+ *
+ * The chip can assert IRQ in any of six different conditions. The IRQ flag
+ * is then cleared by reading the Reset Parity/Interrupt Register (RPIR).
+ * Three of these six conditions are latched in the Bus and Status Register:
+ * - End of DMA (cleared by ending DMA Mode)
+ * - Parity error (cleared by reading RPIR)
+ * - Loss of BSY (cleared by reading RPIR)
+ * Two conditions have flag bits that are not latched:
+ * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode)
+ * - Bus reset (non-maskable)
+ * The remaining condition has no flag bit at all:
+ * - Selection/reselection
+ *
+ * Hence, establishing the cause(s) of any interrupt is partly guesswork.
+ * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor
+ * claimed that "the design of the [DP8490] interrupt logic ensures
+ * interrupts will not be lost (they can be on the DP5380)."
+ * The L5380/53C80 datasheet from LOGIC Devices has more details.
+ *
+ * Checking for bus reset by reading RST is futile because of interrupt
+ * latency, but a bus reset will reset chip logic. Checking for parity error
+ * is unnecessary because that interrupt is never enabled. A Loss of BSY
+ * condition will clear DMA Mode. We can tell when this occurs because the
+ * the Busy Monitor interrupt is enabled together with DMA Mode.
  */
 
 static irqreturn_t NCR5380_intr(int irq, void *dev_id)
 {
        struct Scsi_Host *instance = dev_id;
-       int done = 1, handled = 0;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       int handled = 0;
        unsigned char basr;
+       unsigned long flags;
 
-       dprintk(NDEBUG_INTR, "scsi%d: NCR5380 irq triggered\n", HOSTNO);
+       spin_lock_irqsave(&hostdata->lock, flags);
 
-       /* Look for pending interrupts */
        basr = NCR5380_read(BUS_AND_STATUS_REG);
-       dprintk(NDEBUG_INTR, "scsi%d: BASR=%02x\n", HOSTNO, basr);
-       /* dispatch to appropriate routine if found and done=0 */
        if (basr & BASR_IRQ) {
-               NCR5380_dprint(NDEBUG_INTR, instance);
-               if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
-                       done = 0;
-                       dprintk(NDEBUG_INTR, "scsi%d: SEL interrupt\n", HOSTNO);
-                       NCR5380_reselect(instance);
-                       (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-               } else if (basr & BASR_PARITY_ERROR) {
-                       dprintk(NDEBUG_INTR, "scsi%d: PARITY interrupt\n", HOSTNO);
-                       (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-               } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
-                       dprintk(NDEBUG_INTR, "scsi%d: RESET interrupt\n", HOSTNO);
-                       (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-               } else {
-                       /*
-                        * The rest of the interrupt conditions can occur only during a
-                        * DMA transfer
-                        */
+               unsigned char mr = NCR5380_read(MODE_REG);
+               unsigned char sr = NCR5380_read(STATUS_REG);
+
+               dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n",
+                        irq, basr, sr, mr);
 
 #if defined(REAL_DMA)
-                       /*
-                        * We should only get PHASE MISMATCH and EOP interrupts if we have
-                        * DMA enabled, so do a sanity check based on the current setting
-                        * of the MODE register.
+               if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) {
+                       /* Probably End of DMA, Phase Mismatch or Loss of BSY.
+                        * We ack IRQ after clearing Mode Register. Workarounds
+                        * for End of DMA errata need to happen in DMA Mode.
                         */
 
-                       if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
-                           ((basr & BASR_END_DMA_TRANSFER) ||
-                            !(basr & BASR_PHASE_MATCH))) {
+                       dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n");
 
-                               dprintk(NDEBUG_INTR, "scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
-                               NCR5380_dma_complete( instance );
-                               done = 0;
-                       } else
+                       if (hostdata->connected) {
+                               NCR5380_dma_complete(instance);
+                               queue_work(hostdata->work_q, &hostdata->main_task);
+                       } else {
+                               NCR5380_write(MODE_REG, MR_BASE);
+                               NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+                       }
+               } else
 #endif /* REAL_DMA */
-                       {
-/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
-                               if (basr & BASR_PHASE_MATCH)
-                                       dprintk(NDEBUG_INTR, "scsi%d: unknown interrupt, "
-                                              "BASR 0x%x, MR 0x%x, SR 0x%x\n",
-                                              HOSTNO, basr, NCR5380_read(MODE_REG),
-                                              NCR5380_read(STATUS_REG));
-                               (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+               if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) &&
+                   (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) {
+                       /* Probably reselected */
+                       NCR5380_write(SELECT_ENABLE_REG, 0);
+                       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+                       dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n");
+
+                       if (!hostdata->connected) {
+                               NCR5380_reselect(instance);
+                               queue_work(hostdata->work_q, &hostdata->main_task);
+                       }
+                       if (!hostdata->connected)
+                               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+               } else {
+                       /* Probably Bus Reset */
+                       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+                       dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n");
 #ifdef SUN3_SCSI_VME
-                               dregs->csr |= CSR_DMA_ENABLE;
+                       dregs->csr |= CSR_DMA_ENABLE;
 #endif
-                       }
-               } /* if !(SELECTION || PARITY) */
+               }
                handled = 1;
-       } /* BASR & IRQ */ else {
-               printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
-                      "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
-                      NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
-               (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+       } else {
+               shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n");
 #ifdef SUN3_SCSI_VME
                dregs->csr |= CSR_DMA_ENABLE;
 #endif
        }
 
-       if (!done) {
-               dprintk(NDEBUG_INTR, "scsi%d: in int routine, calling main\n", HOSTNO);
-               /* Put a call to NCR5380_main() on the queue... */
-               queue_main(shost_priv(instance));
-       }
+       spin_unlock_irqrestore(&hostdata->lock, flags);
+
        return IRQ_RETVAL(handled);
 }
 
 /*
  * Function : int NCR5380_select(struct Scsi_Host *instance,
- *                               struct scsi_cmnd *cmd)
+ * struct scsi_cmnd *cmd)
  *
  * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- *     including ARBITRATION, SELECTION, and initial message out for
- *     IDENTIFY and queue messages.
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
  *
  * Inputs : instance - instantiation of the 5380 driver on which this
- *     target lives, cmd - SCSI command to execute.
+ * target lives, cmd - SCSI command to execute.
  *
- * Returns : -1 if selection could not execute for some reason,
- *     0 if selection succeeded or failed because the target
- *     did not respond.
+ * Returns cmd if selection failed but should be retried,
+ * NULL if selection failed and should not be retried, or
+ * NULL if selection succeeded (hostdata->connected == cmd).
  *
  * Side effects :
- *     If bus busy, arbitration failed, etc, NCR5380_select() will exit
- *             with registers as they should have been on entry - ie
- *             SELECT_ENABLE will be set appropriately, the NCR5380
- *             will cease to drive any SCSI bus signals.
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
  *
- *     If successful : I_T_L or I_T_L_Q nexus will be established,
- *             instance->connected will be set to cmd.
- *             SELECT interrupt will be disabled.
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
  *
- *     If failed (no target) : cmd->scsi_done() will be called, and the
- *             cmd->result host byte set to DID_BAD_TARGET.
+ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
  */
 
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
+                                        struct scsi_cmnd *cmd)
 {
-       SETUP_HOSTDATA(instance);
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char tmp[3], phase;
        unsigned char *data;
        int len;
-       unsigned long timeout;
-       unsigned long flags;
+       int err;
 
-       hostdata->restart_select = 0;
        NCR5380_dprint(NDEBUG_ARBITRATION, instance);
-       dprintk(NDEBUG_ARBITRATION, "scsi%d: starting arbitration, id = %d\n", HOSTNO,
-                  instance->this_id);
+       dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
+                instance->this_id);
+
+       /*
+        * Arbitration and selection phases are slow and involve dropping the
+        * lock, so we have to watch out for EH. An exception handler may
+        * change 'selecting' to NULL. This function will then return NULL
+        * so that the caller will forget about 'cmd'. (During information
+        * transfer phases, EH may change 'connected' to NULL.)
+        */
+       hostdata->selecting = cmd;
 
        /*
         * Set the phase bits to 0, otherwise the NCR5380 won't drive the
         * data bus during SELECTION.
         */
 
-       local_irq_save(flags);
-       if (hostdata->connected) {
-               local_irq_restore(flags);
-               return -1;
-       }
        NCR5380_write(TARGET_COMMAND_REG, 0);
 
        /*
@@ -1337,96 +1244,77 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
        NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
        NCR5380_write(MODE_REG, MR_ARBITRATE);
 
-       local_irq_restore(flags);
-
-       /* Wait for arbitration logic to complete */
-#if defined(NCR_TIMEOUT)
-       {
-               unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+       /* The chip now waits for BUS FREE phase. Then after the 800 ns
+        * Bus Free Delay, arbitration will begin.
+        */
 
-               while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
-                      time_before(jiffies, timeout) && !hostdata->connected)
-                       ;
-               if (time_after_eq(jiffies, timeout)) {
-                       printk("scsi : arbitration timeout at %d\n", __LINE__);
-                       NCR5380_write(MODE_REG, MR_BASE);
-                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-                       return -1;
-               }
+       spin_unlock_irq(&hostdata->lock);
+       err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0,
+                       INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS,
+                                              ICR_ARBITRATION_PROGRESS, HZ);
+       spin_lock_irq(&hostdata->lock);
+       if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) {
+               /* Reselection interrupt */
+               goto out;
        }
-#else /* NCR_TIMEOUT */
-       while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
-              !hostdata->connected)
-               ;
-#endif
-
-       dprintk(NDEBUG_ARBITRATION, "scsi%d: arbitration complete\n", HOSTNO);
-
-       if (hostdata->connected) {
+       if (err < 0) {
                NCR5380_write(MODE_REG, MR_BASE);
-               return -1;
+               shost_printk(KERN_ERR, instance,
+                            "select: arbitration timeout\n");
+               goto out;
        }
-       /*
-        * The arbitration delay is 2.2us, but this is a minimum and there is
-        * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
-        * the integral nature of udelay().
-        *
-        */
+       spin_unlock_irq(&hostdata->lock);
 
+       /* The SCSI-2 arbitration delay is 2.4 us */
        udelay(3);
 
        /* Check for lost arbitration */
        if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
            (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
-           (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
-           hostdata->connected) {
+           (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
                NCR5380_write(MODE_REG, MR_BASE);
-               dprintk(NDEBUG_ARBITRATION, "scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
-                          HOSTNO);
-               return -1;
+               dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n");
+               spin_lock_irq(&hostdata->lock);
+               goto out;
        }
 
-       /* after/during arbitration, BSY should be asserted.
-          IBM DPES-31080 Version S31Q works now */
-       /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+       /* After/during arbitration, BSY should be asserted.
+        * IBM DPES-31080 Version S31Q works now
+        * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman)
+        */
        NCR5380_write(INITIATOR_COMMAND_REG,
                      ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
 
-       if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
-           hostdata->connected) {
-               NCR5380_write(MODE_REG, MR_BASE);
-               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-               dprintk(NDEBUG_ARBITRATION, "scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
-                          HOSTNO);
-               return -1;
-       }
-
        /*
         * Again, bus clear + bus settle time is 1.2us, however, this is
         * a minimum so we'll udelay ceil(1.2)
         */
 
-#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
-       /* ++roman: But some targets (see above :-) seem to need a bit more... */
-       udelay(15);
-#else
-       udelay(2);
-#endif
+       if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+               udelay(15);
+       else
+               udelay(2);
 
-       if (hostdata->connected) {
+       spin_lock_irq(&hostdata->lock);
+
+       /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */
+       if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
+               goto out;
+
+       if (!hostdata->selecting) {
                NCR5380_write(MODE_REG, MR_BASE);
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-               return -1;
+               goto out;
        }
 
-       dprintk(NDEBUG_ARBITRATION, "scsi%d: won arbitration\n", HOSTNO);
+       dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n");
 
        /*
         * Now that we have won arbitration, start Selection process, asserting
         * the host and target ID's on the SCSI bus.
         */
 
-       NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+       NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd)));
 
        /*
         * Raise ATN while SEL is true before BSY goes false from arbitration,
@@ -1434,22 +1322,18 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
         * phase immediately after selection.
         */
 
-       NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
-                     ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY |
+                     ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL);
        NCR5380_write(MODE_REG, MR_BASE);
 
        /*
         * Reselect interrupts must be turned off prior to the dropping of BSY,
         * otherwise we will trigger an interrupt.
         */
-
-       if (hostdata->connected) {
-               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-               return -1;
-       }
-
        NCR5380_write(SELECT_ENABLE_REG, 0);
 
+       spin_unlock_irq(&hostdata->lock);
+
        /*
         * The initiator shall then wait at least two deskew delays and release
         * the BSY signal.
@@ -1457,8 +1341,8 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
        udelay(1);        /* wingel -- wait two bus deskew delay >2*45ns */
 
        /* Reset BSY */
-       NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
-                     ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
+                     ICR_ASSERT_ATN | ICR_ASSERT_SEL);
 
        /*
         * Something weird happens when we cease to drive BSY - looks
@@ -1479,45 +1363,39 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
 
        udelay(1);
 
-       dprintk(NDEBUG_SELECTION, "scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
+       dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd));
 
        /*
         * The SCSI specification calls for a 250 ms timeout for the actual
         * selection.
         */
 
-       timeout = jiffies + msecs_to_jiffies(250);
-
-       /*
-        * XXX very interesting - we're seeing a bounce where the BSY we
-        * asserted is being reflected / still asserted (propagation delay?)
-        * and it's detecting as true.  Sigh.
-        */
-
-#if 0
-       /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
-        * IO while SEL is true. But again, there are some disks out the in the
-        * world that do that nevertheless. (Somebody claimed that this announces
-        * reselection capability of the target.) So we better skip that test and
-        * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
-        */
-
-       while (time_before(jiffies, timeout) &&
-              !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO)))
-               ;
+       err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY,
+                                   msecs_to_jiffies(250));
 
        if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+               spin_lock_irq(&hostdata->lock);
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                NCR5380_reselect(instance);
-               printk(KERN_ERR "scsi%d: reselection after won arbitration?\n",
-                      HOSTNO);
+               if (!hostdata->connected)
+                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+               shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
+               goto out;
+       }
+
+       if (err < 0) {
+               spin_lock_irq(&hostdata->lock);
+               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-               return -1;
+               /* Can't touch cmd if it has been reclaimed by the scsi ML */
+               if (hostdata->selecting) {
+                       cmd->result = DID_BAD_TARGET << 16;
+                       complete_cmd(instance, cmd);
+                       dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n");
+                       cmd = NULL;
+               }
+               goto out;
        }
-#else
-       while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY))
-               ;
-#endif
 
        /*
         * No less than two deskew delays after the initiator detects the
@@ -1525,32 +1403,9 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
         * change the DATA BUS.                                     -wingel
         */
 
-       udelay(1);
-
-       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-
-       if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
-               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-               if (hostdata->targets_present & (1 << cmd->device->id)) {
-                       printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
-                       if (hostdata->restart_select)
-                               printk(KERN_NOTICE "\trestart select\n");
-                       NCR5380_dprint(NDEBUG_ANY, instance);
-                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-                       return -1;
-               }
-               cmd->result = DID_BAD_TARGET << 16;
-#ifdef SUPPORT_TAGS
-               cmd_free_tag(cmd);
-#endif
-               cmd->scsi_done(cmd);
-               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-               dprintk(NDEBUG_SELECTION, "scsi%d: target did not respond within 250ms\n", HOSTNO);
-               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-               return 0;
-       }
-
-       hostdata->targets_present |= (1 << cmd->device->id);
+       udelay(1);
+
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
 
        /*
         * Since we followed the SCSI spec, and raised ATN while SEL
@@ -1563,16 +1418,27 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
         * until it wraps back to 0.
         *
         * XXX - it turns out that there are some broken SCSI-II devices,
-        *           which claim to support tagged queuing but fail when more than
-        *           some number of commands are issued at once.
+        * which claim to support tagged queuing but fail when more than
+        * some number of commands are issued at once.
         */
 
        /* Wait for start of REQ/ACK handshake */
-       while (!(NCR5380_read(STATUS_REG) & SR_REQ))
-               ;
 
-       dprintk(NDEBUG_SELECTION, "scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
-                  HOSTNO, cmd->device->id);
+       err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+       spin_lock_irq(&hostdata->lock);
+       if (err < 0) {
+               shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
+               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+               NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+               goto out;
+       }
+       if (!hostdata->selecting) {
+               do_abort(instance);
+               goto out;
+       }
+
+       dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n",
+                scmd_id(cmd));
        tmp[0] = IDENTIFY(1, cmd->device->lun);
 
 #ifdef SUPPORT_TAGS
@@ -1591,11 +1457,12 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
        data = tmp;
        phase = PHASE_MSGOUT;
        NCR5380_transfer_pio(instance, &phase, &len, &data);
-       dprintk(NDEBUG_SELECTION, "scsi%d: nexus established.\n", HOSTNO);
+       dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n");
        /* XXX need to handle errors here */
+
        hostdata->connected = cmd;
 #ifndef SUPPORT_TAGS
-       hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+       hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun;
 #endif
 #ifdef SUN3_SCSI_VME
        dregs->csr |= CSR_INTR;
@@ -1603,24 +1470,30 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
 
        initialize_SCp(cmd);
 
-       return 0;
+       cmd = NULL;
+
+out:
+       if (!hostdata->selecting)
+               return NULL;
+       hostdata->selecting = NULL;
+       return cmd;
 }
 
 /*
  * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
- *      unsigned char *phase, int *count, unsigned char **data)
+ * unsigned char *phase, int *count, unsigned char **data)
  *
  * Purpose : transfers data in given phase using polled I/O
  *
  * Inputs : instance - instance of driver, *phase - pointer to
- *     what phase is expected, *count - pointer to number of
- *     bytes to transfer, **data - pointer to data pointer.
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
  *
  * Returns : -1 when different phase is entered without transferring
- *     maximum number of bytes, 0 if all bytes are transferred or exit
- *     is in same phase.
+ * maximum number of bytes, 0 if all bytes are transferred or exit
+ * is in same phase.
  *
- *     Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
  *
  * XXX Note : handling for bus free may be useful.
  */
@@ -1635,9 +1508,9 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
                                unsigned char *phase, int *count,
                                unsigned char **data)
 {
-       register unsigned char p = *phase, tmp;
-       register int c = *count;
-       register unsigned char *d = *data;
+       unsigned char p = *phase, tmp;
+       int c = *count;
+       unsigned char *d = *data;
 
        /*
         * The NCR5380 chip will only drive the SCSI bus when the
@@ -1652,14 +1525,15 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
                 * Wait for assertion of REQ, after which the phase bits will be
                 * valid
                 */
-               while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
-                       ;
 
-               dprintk(NDEBUG_HANDSHAKE, "scsi%d: REQ detected\n", HOSTNO);
+               if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0)
+                       break;
+
+               dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n");
 
                /* Check for phase mismatch */
-               if ((tmp & PHASE_MASK) != p) {
-                       dprintk(NDEBUG_PIO, "scsi%d: phase mismatch\n", HOSTNO);
+               if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) {
+                       dsprintk(NDEBUG_PIO, instance, "phase mismatch\n");
                        NCR5380_dprint_phase(NDEBUG_PIO, instance);
                        break;
                }
@@ -1684,35 +1558,36 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
                                NCR5380_dprint(NDEBUG_PIO, instance);
                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-                                             ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+                                             ICR_ASSERT_DATA | ICR_ASSERT_ACK);
                        } else {
                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-                                             ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+                                             ICR_ASSERT_DATA | ICR_ASSERT_ATN);
                                NCR5380_dprint(NDEBUG_PIO, instance);
                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-                                             ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+                                             ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
                        }
                } else {
                        NCR5380_dprint(NDEBUG_PIO, instance);
                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
                }
 
-               while (NCR5380_read(STATUS_REG) & SR_REQ)
-                       ;
+               if (NCR5380_poll_politely(instance,
+                                         STATUS_REG, SR_REQ, 0, 5 * HZ) < 0)
+                       break;
 
-               dprintk(NDEBUG_HANDSHAKE, "scsi%d: req false, handshake complete\n", HOSTNO);
+               dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n");
 
-               /*
               * We have several special cases to consider during REQ/ACK handshaking :
               * 1.  We were in MSGOUT phase, and we are on the last byte of the
               *      message.  ATN must be dropped as ACK is dropped.
               *
               * 2.  We are in a MSGIN phase, and we are on the last byte of the
               *      message.  We must exit with ACK asserted, so that the calling
               *      code may raise ATN before dropping ACK to reject the message.
               *
               * 3.  ACK and ATN are clear and the target may proceed as normal.
               */
+/*
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1.  We were in MSGOUT phase, and we are on the last byte of the
* message.  ATN must be dropped as ACK is dropped.
+ *
+ * 2.  We are in a MSGIN phase, and we are on the last byte of the
* message.  We must exit with ACK asserted, so that the calling
* code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3.  ACK and ATN are clear and the target may proceed as normal.
+ */
                if (!(p == PHASE_MSGIN && c == 1)) {
                        if (p == PHASE_MSGOUT && c > 1)
                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
@@ -1721,16 +1596,16 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
                }
        } while (--c);
 
-       dprintk(NDEBUG_PIO, "scsi%d: residual %d\n", HOSTNO, c);
+       dsprintk(NDEBUG_PIO, instance, "residual %d\n", c);
 
        *count = c;
        *data = d;
        tmp = NCR5380_read(STATUS_REG);
        /* The phase read from the bus is valid if either REQ is (already)
-        * asserted or if ACK hasn't been released yet. The latter is the case if
-        * we're in MSGIN and all wanted bytes have been received.
+        * asserted or if ACK hasn't been released yet. The latter applies if
+        * we're in MSG IN, DATA IN or STATUS and all bytes have been received.
         */
-       if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+       if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0))
                *phase = tmp & PHASE_MASK;
        else
                *phase = PHASE_UNKNOWN;
@@ -1741,19 +1616,45 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
                return -1;
 }
 
-/*
- * Function : do_abort (Scsi_Host *host)
+/**
+ * do_reset - issue a reset command
+ * @instance: adapter to reset
+ *
+ * Issue a reset sequence to the NCR5380 and try and get the bus
+ * back into sane shape.
  *
- * Purpose : abort the currently established nexus.  Should only be
- *     called from a routine which can drop into a
+ * This clears the reset interrupt flag because there may be no handler for
+ * it. When the driver is initialized, the NCR5380_intr() handler has not yet
+ * been installed. And when in EH we may have released the ST DMA interrupt.
+ */
+
+static void do_reset(struct Scsi_Host *instance)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       NCR5380_write(TARGET_COMMAND_REG,
+                     PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+       udelay(50);
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+       (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+       local_irq_restore(flags);
+}
+
+/**
+ * do_abort - abort the currently established nexus by going to
+ * MESSAGE OUT phase and sending an ABORT message.
+ * @instance: relevant scsi host instance
  *
- * Returns 0 on success, -1 on failure.
+ * Returns 0 on success, -1 on failure.
  */
 
 static int do_abort(struct Scsi_Host *instance)
 {
-       unsigned char tmp, *msgptr, phase;
+       unsigned char *msgptr, phase, tmp;
        int len;
+       int rc;
 
        /* Request message out phase */
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
@@ -1768,16 +1669,20 @@ static int do_abort(struct Scsi_Host *instance)
         * the target sees, so we just handshake.
         */
 
-       while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
-               ;
+       rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ);
+       if (rc < 0)
+               goto timeout;
+
+       tmp = NCR5380_read(STATUS_REG) & PHASE_MASK;
 
        NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
 
-       if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
-               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
-                             ICR_ASSERT_ACK);
-               while (NCR5380_read(STATUS_REG) & SR_REQ)
-                       ;
+       if (tmp != PHASE_MSGOUT) {
+               NCR5380_write(INITIATOR_COMMAND_REG,
+                             ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+               rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ);
+               if (rc < 0)
+                       goto timeout;
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
        }
 
@@ -1793,26 +1698,29 @@ static int do_abort(struct Scsi_Host *instance)
         */
 
        return len ? -1 : 0;
+
+timeout:
+       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+       return -1;
 }
 
 #if defined(REAL_DMA)
 /*
  * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
- *      unsigned char *phase, int *count, unsigned char **data)
+ * unsigned char *phase, int *count, unsigned char **data)
  *
  * Purpose : transfers data in given phase using either real
- *     or pseudo DMA.
+ * or pseudo DMA.
  *
  * Inputs : instance - instance of driver, *phase - pointer to
- *     what phase is expected, *count - pointer to number of
- *     bytes to transfer, **data - pointer to data pointer.
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
  *
  * Returns : -1 when different phase is entered without transferring
- *     maximum number of bytes, 0 if all bytes or transferred or exit
- *     is in same phase.
- *
- *     Also, *phase, *count, *data are modified in place.
+ * maximum number of bytes, 0 if all bytes or transferred or exit
+ * is in same phase.
  *
+ * Also, *phase, *count, *data are modified in place.
  */
 
 
@@ -1820,10 +1728,9 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
                                unsigned char *phase, int *count,
                                unsigned char **data)
 {
-       SETUP_HOSTDATA(instance);
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        register int c = *count;
        register unsigned char p = *phase;
-       unsigned long flags;
 
 #if defined(CONFIG_SUN3)
        /* sanity check */
@@ -1834,29 +1741,22 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
        }
        hostdata->dma_len = c;
 
-       dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n",
-               instance->host_no, (p & SR_IO) ? "reading" : "writing",
-               c, (p & SR_IO) ? "to" : "from", *data);
+       dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
+                (p & SR_IO) ? "receive" : "send", c, *data);
 
        /* netbsd turns off ints here, why not be safe and do it too */
-       local_irq_save(flags);
 
        /* send start chain */
        sun3scsi_dma_start(c, *data);
 
+       NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+       NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+                               MR_ENABLE_EOP_INTR);
        if (p & SR_IO) {
-               NCR5380_write(TARGET_COMMAND_REG, 1);
-               NCR5380_read(RESET_PARITY_INTERRUPT_REG);
                NCR5380_write(INITIATOR_COMMAND_REG, 0);
-               NCR5380_write(MODE_REG,
-                             (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
                NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
        } else {
-               NCR5380_write(TARGET_COMMAND_REG, 0);
-               NCR5380_read(RESET_PARITY_INTERRUPT_REG);
                NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA);
-               NCR5380_write(MODE_REG,
-                             (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
                NCR5380_write(START_DMA_SEND_REG, 0);
        }
 
@@ -1864,8 +1764,6 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
        dregs->csr |= CSR_DMA_ENABLE;
 #endif
 
-       local_irq_restore(flags);
-
        sun3_dma_active = 1;
 
 #else /* !defined(CONFIG_SUN3) */
@@ -1880,25 +1778,20 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
        if (hostdata->read_overruns && (p & SR_IO))
                c -= hostdata->read_overruns;
 
-       dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n",
-                  HOSTNO, (p & SR_IO) ? "reading" : "writing",
-                  c, (p & SR_IO) ? "to" : "from", d);
+       dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
+                (p & SR_IO) ? "receive" : "send", c, d);
 
        NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
-
-#ifdef REAL_DMA
-       NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
-#endif /* def REAL_DMA  */
+       NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+                               MR_ENABLE_EOP_INTR);
 
        if (!(hostdata->flags & FLAG_LATE_DMA_SETUP)) {
                /* On the Medusa, it is a must to initialize the DMA before
                 * starting the NCR. This is also the cleaner way for the TT.
                 */
-               local_irq_save(flags);
                hostdata->dma_len = (p & SR_IO) ?
                        NCR5380_dma_read_setup(instance, d, c) :
                        NCR5380_dma_write_setup(instance, d, c);
-               local_irq_restore(flags);
        }
 
        if (p & SR_IO)
@@ -1912,11 +1805,9 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
                /* On the Falcon, the DMA setup must be done after the last */
                /* NCR access, else the DMA setup gets trashed!
                 */
-               local_irq_save(flags);
                hostdata->dma_len = (p & SR_IO) ?
                        NCR5380_dma_read_setup(instance, d, c) :
                        NCR5380_dma_write_setup(instance, d, c);
-               local_irq_restore(flags);
        }
 #endif /* !defined(CONFIG_SUN3) */
 
@@ -1928,23 +1819,22 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
  * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
  *
  * Purpose : run through the various SCSI phases and do as the target
- *     directs us to.  Operates on the currently connected command,
- *     instance->connected.
+ * directs us to.  Operates on the currently connected command,
+ * instance->connected.
  *
  * Inputs : instance, instance for which we are doing commands
  *
  * Side effects : SCSI things happen, the disconnected queue will be
- *     modified if a command disconnects, *instance->connected will
- *     change.
+ * modified if a command disconnects, *instance->connected will
+ * change.
  *
  * XXX Note : we need to watch for bus free or a reset condition here
- *     to recover from an unexpected bus free condition.
+ * to recover from an unexpected bus free condition.
  */
 
 static void NCR5380_information_transfer(struct Scsi_Host *instance)
 {
-       SETUP_HOSTDATA(instance);
-       unsigned long flags;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char msgout = NOP;
        int sink = 0;
        int len;
@@ -1953,13 +1843,15 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
 #endif
        unsigned char *data;
        unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
-       struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
+       struct scsi_cmnd *cmd;
 
 #ifdef SUN3_SCSI_VME
        dregs->csr |= CSR_INTR;
 #endif
 
-       while (1) {
+       while ((cmd = hostdata->connected)) {
+               struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+
                tmp = NCR5380_read(STATUS_REG);
                /* We only have a valid SCSI phase when REQ is asserted */
                if (tmp & SR_REQ) {
@@ -1984,7 +1876,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                /* this command setup for dma yet? */
                                if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != cmd)) {
                                        if (cmd->request->cmd_type == REQ_TYPE_FS) {
-                                               sun3scsi_dma_setup(d, count,
+                                               sun3scsi_dma_setup(instance, d, count,
                                                                   rq_data_dir(cmd->request));
                                                sun3_dma_setup_done = cmd;
                                        }
@@ -2000,11 +1892,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
 
                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
-                                             ICR_ASSERT_ACK);
+                                             ICR_ASSERT_ACK);
                                while (NCR5380_read(STATUS_REG) & SR_REQ)
                                        ;
                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-                                             ICR_ASSERT_ATN);
+                                             ICR_ASSERT_ATN);
                                sink = 0;
                                continue;
                        }
@@ -2012,12 +1904,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                        switch (phase) {
                        case PHASE_DATAOUT:
 #if (NDEBUG & NDEBUG_NO_DATAOUT)
-                               printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
-                                      "aborted\n", HOSTNO);
+                               shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n");
                                sink = 1;
                                do_abort(instance);
                                cmd->result = DID_ERROR << 16;
-                               cmd->scsi_done(cmd);
+                               complete_cmd(instance, cmd);
                                return;
 #endif
                        case PHASE_DATAIN:
@@ -2031,13 +1922,10 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                        --cmd->SCp.buffers_residual;
                                        cmd->SCp.this_residual = cmd->SCp.buffer->length;
                                        cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
-                                       /* ++roman: Try to merge some scatter-buffers if
-                                        * they are at contiguous physical addresses.
-                                        */
                                        merge_contiguous_buffers(cmd);
-                                       dprintk(NDEBUG_INFORMATION, "scsi%d: %d bytes and %d buffers left\n",
-                                                  HOSTNO, cmd->SCp.this_residual,
-                                                  cmd->SCp.buffers_residual);
+                                       dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n",
+                                                cmd->SCp.this_residual,
+                                                cmd->SCp.buffers_residual);
                                }
 
                                /*
@@ -2051,16 +1939,18 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                 */
 
                                /* ++roman: I suggest, this should be
-                                *   #if def(REAL_DMA)
+                                * #if def(REAL_DMA)
                                 * instead of leaving REAL_DMA out.
                                 */
 
 #if defined(REAL_DMA)
-                               if (
 #if !defined(CONFIG_SUN3)
-                                   !cmd->device->borken &&
+                               transfersize = 0;
+                               if (!cmd->device->borken)
 #endif
-                                   (transfersize = NCR5380_dma_xfer_len(instance, cmd, phase)) >= DMA_MIN_SIZE) {
+                                       transfersize = NCR5380_dma_xfer_len(instance, cmd, phase);
+
+                               if (transfersize >= DMA_MIN_SIZE) {
                                        len = transfersize;
                                        cmd->SCp.phase = phase;
                                        if (NCR5380_transfer_dma(instance, &phase,
@@ -2068,16 +1958,15 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                /*
                                                 * If the watchdog timer fires, all future
                                                 * accesses to this device will use the
-                                                * polled-IO. */
+                                                * polled-IO.
+                                                */
                                                scmd_printk(KERN_INFO, cmd,
                                                        "switching to slow handshake\n");
                                                cmd->device->borken = 1;
-                                               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-                                                       ICR_ASSERT_ATN);
                                                sink = 1;
                                                do_abort(instance);
                                                cmd->result = DID_ERROR << 16;
-                                               cmd->scsi_done(cmd);
+                                               complete_cmd(instance, cmd);
                                                /* XXX - need to source or sink data here, as appropriate */
                                        } else {
 #ifdef REAL_DMA
@@ -2093,9 +1982,13 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                        }
                                } else
 #endif /* defined(REAL_DMA) */
+                               {
+                                       spin_unlock_irq(&hostdata->lock);
                                        NCR5380_transfer_pio(instance, &phase,
-                                                            (int *)&cmd->SCp.this_residual,
-                                                            (unsigned char **)&cmd->SCp.ptr);
+                                                            (int *)&cmd->SCp.this_residual,
+                                                            (unsigned char **)&cmd->SCp.ptr);
+                                       spin_lock_irq(&hostdata->lock);
+                               }
 #if defined(CONFIG_SUN3) && defined(REAL_DMA)
                                /* if we had intended to dma that command clear it */
                                if (sun3_dma_setup_done == cmd)
@@ -2105,162 +1998,64 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                        case PHASE_MSGIN:
                                len = 1;
                                data = &tmp;
-                               NCR5380_write(SELECT_ENABLE_REG, 0);    /* disable reselects */
                                NCR5380_transfer_pio(instance, &phase, &len, &data);
                                cmd->SCp.Message = tmp;
 
                                switch (tmp) {
-                               /*
-                                * Linking lets us reduce the time required to get the
-                                * next command out to the device, hopefully this will
-                                * mean we don't waste another revolution due to the delays
-                                * required by ARBITRATION and another SELECTION.
-                                *
-                                * In the current implementation proposal, low level drivers
-                                * merely have to start the next command, pointed to by
-                                * next_link, done() is called as with unlinked commands.
-                                */
-#ifdef LINKED
-                               case LINKED_CMD_COMPLETE:
-                               case LINKED_FLG_CMD_COMPLETE:
-                                       /* Accept message by clearing ACK */
-                                       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
-                                       dprintk(NDEBUG_LINKED, "scsi%d: target %d lun %llu linked command "
-                                                  "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
-
-                                       /* Enable reselect interrupts */
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-                                       /*
-                                        * Sanity check : A linked command should only terminate
-                                        * with one of these messages if there are more linked
-                                        * commands available.
-                                        */
-
-                                       if (!cmd->next_link) {
-                                                printk(KERN_NOTICE "scsi%d: target %d lun %llu "
-                                                       "linked command complete, no next_link\n",
-                                                       HOSTNO, cmd->device->id, cmd->device->lun);
-                                               sink = 1;
-                                               do_abort(instance);
-                                               return;
-                                       }
-
-                                       initialize_SCp(cmd->next_link);
-                                       /* The next command is still part of this process; copy it
-                                        * and don't free it! */
-                                       cmd->next_link->tag = cmd->tag;
-                                       cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-                                       dprintk(NDEBUG_LINKED, "scsi%d: target %d lun %llu linked request "
-                                                  "done, calling scsi_done().\n",
-                                                  HOSTNO, cmd->device->id, cmd->device->lun);
-                                       cmd->scsi_done(cmd);
-                                       cmd = hostdata->connected;
-                                       break;
-#endif /* def LINKED */
                                case ABORT:
                                case COMMAND_COMPLETE:
                                        /* Accept message by clearing ACK */
                                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                                       dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d, lun %llu "
-                                                 "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+                                       dsprintk(NDEBUG_QUEUES, instance,
+                                                "COMMAND COMPLETE %p target %d lun %llu\n",
+                                                cmd, scmd_id(cmd), cmd->device->lun);
 
-                                       local_irq_save(flags);
-                                       hostdata->retain_dma_intr++;
                                        hostdata->connected = NULL;
 #ifdef SUPPORT_TAGS
                                        cmd_free_tag(cmd);
                                        if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
-                                               /* Turn a QUEUE FULL status into BUSY, I think the
-                                                * mid level cannot handle QUEUE FULL :-( (The
-                                                * command is retried after BUSY). Also update our
-                                                * queue size to the number of currently issued
-                                                * commands now.
-                                                */
-                                               /* ++Andreas: the mid level code knows about
-                                                  QUEUE_FULL now. */
-                                               struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][cmd->device->lun];
-                                               dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %llu returned "
-                                                          "QUEUE_FULL after %d commands\n",
-                                                          HOSTNO, cmd->device->id, cmd->device->lun,
-                                                          ta->nr_allocated);
+                                               u8 lun = cmd->device->lun;
+                                               struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
+
+                                               dsprintk(NDEBUG_TAGS, instance,
+                                                        "QUEUE_FULL %p target %d lun %d nr_allocated %d\n",
+                                                        cmd, scmd_id(cmd), lun, ta->nr_allocated);
                                                if (ta->queue_size > ta->nr_allocated)
-                                                       ta->nr_allocated = ta->queue_size;
+                                                       ta->queue_size = ta->nr_allocated;
                                        }
-#else
-                                       hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
-                                       /* Enable reselect interrupts */
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
-                                       /*
-                                        * I'm not sure what the correct thing to do here is :
-                                        *
-                                        * If the command that just executed is NOT a request
-                                        * sense, the obvious thing to do is to set the result
-                                        * code to the values of the stored parameters.
-                                        *
-                                        * If it was a REQUEST SENSE command, we need some way to
-                                        * differentiate between the failure code of the original
-                                        * and the failure code of the REQUEST sense - the obvious
-                                        * case is success, where we fall through and leave the
-                                        * result code unchanged.
-                                        *
-                                        * The non-obvious place is where the REQUEST SENSE failed
-                                        */
-
-                                       if (cmd->cmnd[0] != REQUEST_SENSE)
-                                               cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-                                       else if (status_byte(cmd->SCp.Status) != GOOD)
-                                               cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-
-                                       if ((cmd->cmnd[0] == REQUEST_SENSE) &&
-                                               hostdata->ses.cmd_len) {
-                                               scsi_eh_restore_cmnd(cmd, &hostdata->ses);
-                                               hostdata->ses.cmd_len = 0 ;
-                                       }
-
-                                       if ((cmd->cmnd[0] != REQUEST_SENSE) &&
-                                           (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
-                                               scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
 
-                                               dprintk(NDEBUG_AUTOSENSE, "scsi%d: performing request sense\n", HOSTNO);
-
-                                               LIST(cmd,hostdata->issue_queue);
-                                               SET_NEXT(cmd, hostdata->issue_queue);
-                                               hostdata->issue_queue = (struct scsi_cmnd *) cmd;
-                                               dprintk(NDEBUG_QUEUES, "scsi%d: REQUEST SENSE added to head of "
-                                                         "issue queue\n", H_NO(cmd));
-                                       } else {
-                                               cmd->scsi_done(cmd);
+                                       cmd->result &= ~0xffff;
+                                       cmd->result |= cmd->SCp.Status;
+                                       cmd->result |= cmd->SCp.Message << 8;
+
+                                       if (cmd->cmnd[0] == REQUEST_SENSE)
+                                               complete_cmd(instance, cmd);
+                                       else {
+                                               if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION ||
+                                                   cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) {
+                                                       dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n",
+                                                                cmd);
+                                                       list_add_tail(&ncmd->list,
+                                                                     &hostdata->autosense);
+                                               } else
+                                                       complete_cmd(instance, cmd);
                                        }
 
-                                       local_irq_restore(flags);
-
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                                        /*
                                         * Restore phase bits to 0 so an interrupted selection,
                                         * arbitration can resume.
                                         */
                                        NCR5380_write(TARGET_COMMAND_REG, 0);
 
-                                       while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
-                                               barrier();
+                                       /* Enable reselect interrupts */
+                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 
-                                       local_irq_save(flags);
-                                       hostdata->retain_dma_intr--;
-                                       /* ++roman: For Falcon SCSI, release the lock on the
-                                        * ST-DMA here if no other commands are waiting on the
-                                        * disconnected queue.
-                                        */
                                        maybe_release_dma_irq(instance);
-                                       local_irq_restore(flags);
                                        return;
                                case MESSAGE_REJECT:
                                        /* Accept message by clearing ACK */
                                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                                       /* Enable reselect interrupts */
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                                        switch (hostdata->last_message) {
                                        case HEAD_OF_QUEUE_TAG:
                                        case ORDERED_QUEUE_TAG:
@@ -2274,27 +2069,20 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                cmd->device->tagged_supported = 0;
                                                hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
                                                cmd->tag = TAG_NONE;
-                                               dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %llu rejected "
-                                                          "QUEUE_TAG message; tagged queuing "
-                                                          "disabled\n",
-                                                          HOSTNO, cmd->device->id, cmd->device->lun);
+                                               dsprintk(NDEBUG_TAGS, instance, "target %d lun %llu rejected QUEUE_TAG message; tagged queuing disabled\n",
+                                                        scmd_id(cmd), cmd->device->lun);
                                                break;
                                        }
                                        break;
                                case DISCONNECT:
                                        /* Accept message by clearing ACK */
                                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                                       local_irq_save(flags);
-                                       cmd->device->disconnect = 1;
-                                       LIST(cmd,hostdata->disconnected_queue);
-                                       SET_NEXT(cmd, hostdata->disconnected_queue);
                                        hostdata->connected = NULL;
-                                       hostdata->disconnected_queue = cmd;
-                                       local_irq_restore(flags);
-                                       dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d lun %llu was "
-                                                 "moved from connected to the "
-                                                 "disconnected_queue\n", HOSTNO,
-                                                 cmd->device->id, cmd->device->lun);
+                                       list_add(&ncmd->list, &hostdata->disconnected);
+                                       dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES,
+                                                instance, "connected command %p for target %d lun %llu moved to disconnected queue\n",
+                                                cmd, scmd_id(cmd), cmd->device->lun);
+
                                        /*
                                         * Restore phase bits to 0 so an interrupted selection,
                                         * arbitration can resume.
@@ -2303,9 +2091,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
 
                                        /* Enable reselect interrupts */
                                        NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-                                       /* Wait for bus free to avoid nasty timeouts */
-                                       while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
-                                               barrier();
 #ifdef SUN3_SCSI_VME
                                        dregs->csr |= CSR_DMA_ENABLE;
 #endif
@@ -2324,37 +2109,30 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                case RESTORE_POINTERS:
                                        /* Accept message by clearing ACK */
                                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-                                       /* Enable reselect interrupts */
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                                        break;
                                case EXTENDED_MESSAGE:
                                        /*
-                                        * Extended messages are sent in the following format :
-                                        * Byte
-                                        * 0            EXTENDED_MESSAGE == 1
-                                        * 1            length (includes one byte for code, doesn't
-                                        *              include first two bytes)
-                                        * 2            code
-                                        * 3..length+1  arguments
-                                        *
-                                        * Start the extended message buffer with the EXTENDED_MESSAGE
+                                        * Start the message buffer with the EXTENDED_MESSAGE
                                         * byte, since spi_print_msg() wants the whole thing.
                                         */
                                        extended_msg[0] = EXTENDED_MESSAGE;
                                        /* Accept first byte by clearing ACK */
                                        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
-                                       dprintk(NDEBUG_EXTENDED, "scsi%d: receiving extended message\n", HOSTNO);
+                                       spin_unlock_irq(&hostdata->lock);
+
+                                       dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n");
 
                                        len = 2;
                                        data = extended_msg + 1;
                                        phase = PHASE_MSGIN;
                                        NCR5380_transfer_pio(instance, &phase, &len, &data);
-                                       dprintk(NDEBUG_EXTENDED, "scsi%d: length=%d, code=0x%02x\n", HOSTNO,
-                                                  (int)extended_msg[1], (int)extended_msg[2]);
+                                       dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n",
+                                                (int)extended_msg[1],
+                                                (int)extended_msg[2]);
 
-                                       if (!len && extended_msg[1] <=
-                                           (sizeof(extended_msg) - 1)) {
+                                       if (!len && extended_msg[1] > 0 &&
+                                           extended_msg[1] <= sizeof(extended_msg) - 2) {
                                                /* Accept third byte by clearing ACK */
                                                NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
                                                len = extended_msg[1] - 1;
@@ -2362,8 +2140,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                phase = PHASE_MSGIN;
 
                                                NCR5380_transfer_pio(instance, &phase, &len, &data);
-                                               dprintk(NDEBUG_EXTENDED, "scsi%d: message received, residual %d\n",
-                                                          HOSTNO, len);
+                                               dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n",
+                                                        len);
 
                                                switch (extended_msg[2]) {
                                                case EXTENDED_SDTR:
@@ -2373,15 +2151,18 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                                        tmp = 0;
                                                }
                                        } else if (len) {
-                                               printk(KERN_NOTICE "scsi%d: error receiving "
-                                                      "extended message\n", HOSTNO);
+                                               shost_printk(KERN_ERR, instance, "error receiving extended message\n");
                                                tmp = 0;
                                        } else {
-                                               printk(KERN_NOTICE "scsi%d: extended message "
-                                                          "code %02x length %d is too long\n",
-                                                          HOSTNO, extended_msg[2], extended_msg[1]);
+                                               shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n",
+                                                            extended_msg[2], extended_msg[1]);
                                                tmp = 0;
                                        }
+
+                                       spin_lock_irq(&hostdata->lock);
+                                       if (!hostdata->connected)
+                                               return;
+
                                        /* Fall through to reject message */
 
                                        /*
@@ -2390,8 +2171,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                         */
                                default:
                                        if (!tmp) {
-                                               printk(KERN_INFO "scsi%d: rejecting message ",
-                                                      instance->host_no);
+                                               shost_printk(KERN_ERR, instance, "rejecting message ");
                                                spi_print_msg(extended_msg);
                                                printk("\n");
                                        } else if (tmp != EXTENDED_MESSAGE)
@@ -2414,18 +2194,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                hostdata->last_message = msgout;
                                NCR5380_transfer_pio(instance, &phase, &len, &data);
                                if (msgout == ABORT) {
-                                       local_irq_save(flags);
-#ifdef SUPPORT_TAGS
-                                       cmd_free_tag(cmd);
-#else
-                                       hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
                                        hostdata->connected = NULL;
                                        cmd->result = DID_ERROR << 16;
-                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+                                       complete_cmd(instance, cmd);
                                        maybe_release_dma_irq(instance);
-                                       local_irq_restore(flags);
-                                       cmd->scsi_done(cmd);
+                                       NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                                        return;
                                }
                                msgout = NOP;
@@ -2447,22 +2220,25 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
                                cmd->SCp.Status = tmp;
                                break;
                        default:
-                               printk("scsi%d: unknown phase\n", HOSTNO);
+                               shost_printk(KERN_ERR, instance, "unknown phase\n");
                                NCR5380_dprint(NDEBUG_ANY, instance);
                        } /* switch(phase) */
-               } /* if (tmp * SR_REQ) */
-       } /* while (1) */
+               } else {
+                       spin_unlock_irq(&hostdata->lock);
+                       NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+                       spin_lock_irq(&hostdata->lock);
+               }
+       }
 }
 
 /*
  * Function : void NCR5380_reselect (struct Scsi_Host *instance)
  *
  * Purpose : does reselection, initializing the instance->connected
- *     field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
- *     nexus has been reestablished,
+ * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
  *
  * Inputs : instance - this instance of the NCR5380.
- *
  */
 
 
@@ -2471,7 +2247,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
 
 static void NCR5380_reselect(struct Scsi_Host *instance)
 {
-       SETUP_HOSTDATA(instance);
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char target_mask;
        unsigned char lun;
 #ifdef SUPPORT_TAGS
@@ -2480,7 +2256,8 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
        unsigned char msg[3];
        int __maybe_unused len;
        unsigned char __maybe_unused *data, __maybe_unused phase;
-       struct scsi_cmnd *tmp = NULL, *prev;
+       struct NCR5380_cmd *ncmd;
+       struct scsi_cmnd *tmp;
 
        /*
         * Disable arbitration, etc. since the host adapter obviously
@@ -2488,11 +2265,10 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
         */
 
        NCR5380_write(MODE_REG, MR_BASE);
-       hostdata->restart_select = 1;
 
        target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
 
-       dprintk(NDEBUG_RESELECTION, "scsi%d: reselect\n", HOSTNO);
+       dsprintk(NDEBUG_RESELECTION, instance, "reselect\n");
 
        /*
         * At this point, we have detected that our SCSI ID is on the bus,
@@ -2504,17 +2280,22 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
         */
 
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-
-       while (NCR5380_read(STATUS_REG) & SR_SEL)
-               ;
+       if (NCR5380_poll_politely(instance,
+                                 STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
+               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+               return;
+       }
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
        /*
         * Wait for target to go into MSGIN.
         */
 
-       while (!(NCR5380_read(STATUS_REG) & SR_REQ))
-               ;
+       if (NCR5380_poll_politely(instance,
+                                 STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
+               do_abort(instance);
+               return;
+       }
 
 #if defined(CONFIG_SUN3) && defined(REAL_DMA)
        /* acknowledge toggle to MSGIN */
@@ -2527,15 +2308,21 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
        data = msg;
        phase = PHASE_MSGIN;
        NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+       if (len) {
+               do_abort(instance);
+               return;
+       }
 #endif
 
        if (!(msg[0] & 0x80)) {
-               printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+               shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
                spi_print_msg(msg);
+               printk("\n");
                do_abort(instance);
                return;
        }
-       lun = (msg[0] & 0x07);
+       lun = msg[0] & 0x07;
 
 #if defined(SUPPORT_TAGS) && !defined(CONFIG_SUN3)
        /* If the phase is still MSGIN, the target wants to send some more
@@ -2551,8 +2338,8 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
                if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
                    msg[1] == SIMPLE_QUEUE_TAG)
                        tag = msg[2];
-               dprintk(NDEBUG_TAGS, "scsi%d: target mask %02x, lun %d sent tag %d at "
-                          "reselection\n", HOSTNO, target_mask, lun, tag);
+               dsprintk(NDEBUG_TAGS, instance, "reselect: target mask %02x, lun %d sent tag %d\n",
+                        target_mask, lun, tag);
        }
 #endif
 
@@ -2561,36 +2348,34 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
         * just reestablished, and remove it from the disconnected queue.
         */
 
-       for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL;
-            tmp; prev = tmp, tmp = NEXT(tmp)) {
-               if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+       tmp = NULL;
+       list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+               struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+               if (target_mask == (1 << scmd_id(cmd)) &&
+                   lun == (u8)cmd->device->lun
 #ifdef SUPPORT_TAGS
-                   && (tag == tmp->tag)
+                   && (tag == cmd->tag)
 #endif
                    ) {
-                       if (prev) {
-                               REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
-                               SET_NEXT(prev, NEXT(tmp));
-                       } else {
-                               REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
-                               hostdata->disconnected_queue = NEXT(tmp);
-                       }
-                       SET_NEXT(tmp, NULL);
+                       list_del(&ncmd->list);
+                       tmp = cmd;
                        break;
                }
        }
 
-       if (!tmp) {
-               printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
-#ifdef SUPPORT_TAGS
-                      "tag %d "
-#endif
-                      "not in disconnected_queue.\n",
-                      HOSTNO, target_mask, lun
+       if (tmp) {
+               dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance,
+                        "reselect: removed %p from disconnected queue\n", tmp);
+       } else {
+
 #ifdef SUPPORT_TAGS
-                      , tag
+               shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d tag %d not in disconnected queue.\n",
+                            target_mask, lun, tag);
+#else
+               shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
+                            target_mask, lun);
 #endif
-                       );
                /*
                 * Since we have an established nexus that we can't do anything
                 * with, we must abort it.
@@ -2614,7 +2399,8 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
                }
                /* setup this command for dma if not already */
                if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != tmp)) {
-                       sun3scsi_dma_setup(d, count, rq_data_dir(tmp->request));
+                       sun3scsi_dma_setup(instance, d, count,
+                                          rq_data_dir(tmp->request));
                        sun3_dma_setup_done = tmp;
                }
        }
@@ -2639,235 +2425,196 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
                if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
                    msg[1] == SIMPLE_QUEUE_TAG)
                        tag = msg[2];
-               dprintk(NDEBUG_TAGS, "scsi%d: target mask %02x, lun %d sent tag %d at reselection\n"
-                       HOSTNO, target_mask, lun, tag);
+               dsprintk(NDEBUG_TAGS, instance, "reselect: target mask %02x, lun %d sent tag %d\n"
+                        target_mask, lun, tag);
        }
 #endif
 
        hostdata->connected = tmp;
-       dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n",
-                  HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
+       dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu, tag %d\n",
+                scmd_id(tmp), tmp->device->lun, tmp->tag);
 }
 
 
-/*
- * Function : int NCR5380_abort (struct scsi_cmnd *cmd)
- *
- * Purpose : abort a command
- *
- * Inputs : cmd - the scsi_cmnd to abort, code - code to set the
- *     host byte of the result field to, if zero DID_ABORTED is
- *     used.
- *
- * Returns : SUCCESS - success, FAILED on failure.
- *
- * XXX - there is no way to abort the command that is currently
- *      connected, you have to wait for it to complete.  If this is
- *      a problem, we could implement longjmp() / setjmp(), setjmp()
- *      called where the loop started in NCR5380_main().
+/**
+ * list_find_cmd - test for presence of a command in a linked list
+ * @haystack: list of commands
+ * @needle: command to search for
  */
 
-static
-int NCR5380_abort(struct scsi_cmnd *cmd)
+static bool list_find_cmd(struct list_head *haystack,
+                          struct scsi_cmnd *needle)
 {
-       struct Scsi_Host *instance = cmd->device->host;
-       SETUP_HOSTDATA(instance);
-       struct scsi_cmnd *tmp, **prev;
-       unsigned long flags;
+       struct NCR5380_cmd *ncmd;
 
-       scmd_printk(KERN_NOTICE, cmd, "aborting command\n");
+       list_for_each_entry(ncmd, haystack, list)
+               if (NCR5380_to_scmd(ncmd) == needle)
+                       return true;
+       return false;
+}
 
-       NCR5380_print_status(instance);
+/**
+ * list_remove_cmd - remove a command from linked list
+ * @haystack: list of commands
+ * @needle: command to remove
+ */
 
-       local_irq_save(flags);
+static bool list_del_cmd(struct list_head *haystack,
+                         struct scsi_cmnd *needle)
+{
+       if (list_find_cmd(haystack, needle)) {
+               struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle);
 
-       dprintk(NDEBUG_ABORT, "scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
-                   NCR5380_read(BUS_AND_STATUS_REG),
-                   NCR5380_read(STATUS_REG));
+               list_del(&ncmd->list);
+               return true;
+       }
+       return false;
+}
 
-#if 1
-       /*
-        * Case 1 : If the command is the currently executing command,
-        * we'll set the aborted flag and return control so that
-        * information transfer routine can exit cleanly.
-        */
+/**
+ * NCR5380_abort - scsi host eh_abort_handler() method
+ * @cmd: the command to be aborted
+ *
+ * Try to abort a given command by removing it from queues and/or sending
+ * the target an abort message. This may not succeed in causing a target
+ * to abort the command. Nonetheless, the low-level driver must forget about
+ * the command because the mid-layer reclaims it and it may be re-issued.
+ *
+ * The normal path taken by a command is as follows. For EH we trace this
+ * same path to locate and abort the command.
+ *
+ * unissued -> selecting -> [unissued -> selecting ->]... connected ->
+ * [disconnected -> connected ->]...
+ * [autosense -> connected ->] done
+ *
+ * If cmd is unissued then just remove it.
+ * If cmd is disconnected, try to select the target.
+ * If cmd is connected, try to send an abort message.
+ * If cmd is waiting for autosense, give it a chance to complete but check
+ * that it isn't left connected.
+ * If cmd was not found at all then presumably it has already been completed,
+ * in which case return SUCCESS to try to avoid further EH measures.
+ * If the command has not completed yet, we must not fail to find it.
+ */
 
-       if (hostdata->connected == cmd) {
+static int NCR5380_abort(struct scsi_cmnd *cmd)
+{
+       struct Scsi_Host *instance = cmd->device->host;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       unsigned long flags;
+       int result = SUCCESS;
 
-               dprintk(NDEBUG_ABORT, "scsi%d: aborting connected command\n", HOSTNO);
-               /*
-                * We should perform BSY checking, and make sure we haven't slipped
-                * into BUS FREE.
-                */
+       spin_lock_irqsave(&hostdata->lock, flags);
 
-               /*      NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
-               /*
-                * Since we can't change phases until we've completed the current
-                * handshake, we have to source or sink a byte of data if the current
-                * phase is not MSGOUT.
-                */
+#if (NDEBUG & NDEBUG_ANY)
+       scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+       NCR5380_dprint(NDEBUG_ANY, instance);
+       NCR5380_dprint_phase(NDEBUG_ANY, instance);
 
-               /*
-                * Return control to the executing NCR drive so we can clear the
-                * aborted flag and get back into our main loop.
-                */
+       if (list_del_cmd(&hostdata->unissued, cmd)) {
+               dsprintk(NDEBUG_ABORT, instance,
+                        "abort: removed %p from issue queue\n", cmd);
+               cmd->result = DID_ABORT << 16;
+               cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
+       }
 
-               if (do_abort(instance) == 0) {
-                       hostdata->aborted = 1;
-                       hostdata->connected = NULL;
-                       cmd->result = DID_ABORT << 16;
-#ifdef SUPPORT_TAGS
-                       cmd_free_tag(cmd);
-#else
-                       hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
-                       maybe_release_dma_irq(instance);
-                       local_irq_restore(flags);
-                       cmd->scsi_done(cmd);
-                       return SUCCESS;
-               } else {
-                       local_irq_restore(flags);
-                       printk("scsi%d: abort of connected command failed!\n", HOSTNO);
-                       return FAILED;
-               }
+       if (hostdata->selecting == cmd) {
+               dsprintk(NDEBUG_ABORT, instance,
+                        "abort: cmd %p == selecting\n", cmd);
+               hostdata->selecting = NULL;
+               cmd->result = DID_ABORT << 16;
+               complete_cmd(instance, cmd);
+               goto out;
        }
-#endif
 
-       /*
-        * Case 2 : If the command hasn't been issued yet, we simply remove it
-        *          from the issue queue.
-        */
-       for (prev = (struct scsi_cmnd **)&(hostdata->issue_queue),
-            tmp = (struct scsi_cmnd *)hostdata->issue_queue;
-            tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
-               if (cmd == tmp) {
-                       REMOVE(5, *prev, tmp, NEXT(tmp));
-                       (*prev) = NEXT(tmp);
-                       SET_NEXT(tmp, NULL);
-                       tmp->result = DID_ABORT << 16;
-                       maybe_release_dma_irq(instance);
-                       local_irq_restore(flags);
-                       dprintk(NDEBUG_ABORT, "scsi%d: abort removed command from issue queue.\n",
-                                   HOSTNO);
-                       /* Tagged queuing note: no tag to free here, hasn't been assigned
-                        * yet... */
-                       tmp->scsi_done(tmp);
-                       return SUCCESS;
+       if (list_del_cmd(&hostdata->disconnected, cmd)) {
+               dsprintk(NDEBUG_ABORT, instance,
+                        "abort: removed %p from disconnected list\n", cmd);
+               cmd->result = DID_ERROR << 16;
+               if (!hostdata->connected)
+                       NCR5380_select(instance, cmd);
+               if (hostdata->connected != cmd) {
+                       complete_cmd(instance, cmd);
+                       result = FAILED;
+                       goto out;
                }
        }
 
-       /*
-        * Case 3 : If any commands are connected, we're going to fail the abort
-        *          and let the high level SCSI driver retry at a later time or
-        *          issue a reset.
-        *
-        *          Timeouts, and therefore aborted commands, will be highly unlikely
-        *          and handling them cleanly in this situation would make the common
-        *          case of noresets less efficient, and would pollute our code.  So,
-        *          we fail.
-        */
+       if (hostdata->connected == cmd) {
+               dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+               hostdata->connected = NULL;
+               if (do_abort(instance)) {
+                       set_host_byte(cmd, DID_ERROR);
+                       complete_cmd(instance, cmd);
+                       result = FAILED;
+                       goto out;
+               }
+               set_host_byte(cmd, DID_ABORT);
+#ifdef REAL_DMA
+               hostdata->dma_len = 0;
+#endif
+               if (cmd->cmnd[0] == REQUEST_SENSE)
+                       complete_cmd(instance, cmd);
+               else {
+                       struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
 
-       if (hostdata->connected) {
-               local_irq_restore(flags);
-               dprintk(NDEBUG_ABORT, "scsi%d: abort failed, command connected.\n", HOSTNO);
-               return FAILED;
+                       /* Perform autosense for this command */
+                       list_add(&ncmd->list, &hostdata->autosense);
+               }
        }
 
-       /*
-        * Case 4: If the command is currently disconnected from the bus, and
-        *      there are no connected commands, we reconnect the I_T_L or
-        *      I_T_L_Q nexus associated with it, go into message out, and send
-        *      an abort message.
-        *
-        * This case is especially ugly. In order to reestablish the nexus, we
-        * need to call NCR5380_select().  The easiest way to implement this
-        * function was to abort if the bus was busy, and let the interrupt
-        * handler triggered on the SEL for reselect take care of lost arbitrations
-        * where necessary, meaning interrupts need to be enabled.
-        *
-        * When interrupts are enabled, the queues may change - so we
-        * can't remove it from the disconnected queue before selecting it
-        * because that could cause a failure in hashing the nexus if that
-        * device reselected.
-        *
-        * Since the queues may change, we can't use the pointers from when we
-        * first locate it.
-        *
-        * So, we must first locate the command, and if NCR5380_select()
-        * succeeds, then issue the abort, relocate the command and remove
-        * it from the disconnected queue.
-        */
-
-       for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp;
-            tmp = NEXT(tmp)) {
-               if (cmd == tmp) {
-                       local_irq_restore(flags);
-                       dprintk(NDEBUG_ABORT, "scsi%d: aborting disconnected command.\n", HOSTNO);
-
-                       if (NCR5380_select(instance, cmd))
-                               return FAILED;
-
-                       dprintk(NDEBUG_ABORT, "scsi%d: nexus reestablished.\n", HOSTNO);
-
-                       do_abort(instance);
-
-                       local_irq_save(flags);
-                       for (prev = (struct scsi_cmnd **)&(hostdata->disconnected_queue),
-                            tmp = (struct scsi_cmnd *)hostdata->disconnected_queue;
-                            tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
-                               if (cmd == tmp) {
-                                       REMOVE(5, *prev, tmp, NEXT(tmp));
-                                       *prev = NEXT(tmp);
-                                       SET_NEXT(tmp, NULL);
-                                       tmp->result = DID_ABORT << 16;
-                                       /* We must unlock the tag/LUN immediately here, since the
-                                        * target goes to BUS FREE and doesn't send us another
-                                        * message (COMMAND_COMPLETE or the like)
-                                        */
-#ifdef SUPPORT_TAGS
-                                       cmd_free_tag(tmp);
-#else
-                                       hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
-                                       maybe_release_dma_irq(instance);
-                                       local_irq_restore(flags);
-                                       tmp->scsi_done(tmp);
-                                       return SUCCESS;
-                               }
-                       }
+       if (list_find_cmd(&hostdata->autosense, cmd)) {
+               dsprintk(NDEBUG_ABORT, instance,
+                        "abort: found %p on sense queue\n", cmd);
+               spin_unlock_irqrestore(&hostdata->lock, flags);
+               queue_work(hostdata->work_q, &hostdata->main_task);
+               msleep(1000);
+               spin_lock_irqsave(&hostdata->lock, flags);
+               if (list_del_cmd(&hostdata->autosense, cmd)) {
+                       dsprintk(NDEBUG_ABORT, instance,
+                                "abort: removed %p from sense queue\n", cmd);
+                       set_host_byte(cmd, DID_ABORT);
+                       complete_cmd(instance, cmd);
+                       goto out;
                }
        }
 
-       /* Maybe it is sufficient just to release the ST-DMA lock... (if
-        * possible at all) At least, we should check if the lock could be
-        * released after the abort, in case it is kept due to some bug.
-        */
-       maybe_release_dma_irq(instance);
-       local_irq_restore(flags);
+       if (hostdata->connected == cmd) {
+               dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+               hostdata->connected = NULL;
+               if (do_abort(instance)) {
+                       set_host_byte(cmd, DID_ERROR);
+                       complete_cmd(instance, cmd);
+                       result = FAILED;
+                       goto out;
+               }
+               set_host_byte(cmd, DID_ABORT);
+#ifdef REAL_DMA
+               hostdata->dma_len = 0;
+#endif
+               complete_cmd(instance, cmd);
+       }
 
-       /*
-        * Case 5 : If we reached this point, the command was not found in any of
-        *          the queues.
-        *
-        * We probably reached this point because of an unlikely race condition
-        * between the command completing successfully and the abortion code,
-        * so we won't panic, but we will notify the user in case something really
-        * broke.
-        */
+out:
+       if (result == FAILED)
+               dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd);
+       else
+               dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd);
 
-       printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO);
+       queue_work(hostdata->work_q, &hostdata->main_task);
+       maybe_release_dma_irq(instance);
+       spin_unlock_irqrestore(&hostdata->lock, flags);
 
-       return FAILED;
+       return result;
 }
 
 
-/*
- * Function : int NCR5380_reset (struct scsi_cmnd *cmd)
- *
- * Purpose : reset the SCSI bus.
- *
- * Returns : SUCCESS or FAILURE
+/**
+ * NCR5380_bus_reset - reset the SCSI bus
+ * @cmd: SCSI command undergoing EH
  *
+ * Returns SUCCESS
  */
 
 static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
@@ -2876,23 +2623,22 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
        int i;
        unsigned long flags;
+       struct NCR5380_cmd *ncmd;
 
-       NCR5380_print_status(instance);
+       spin_lock_irqsave(&hostdata->lock, flags);
+
+#if (NDEBUG & NDEBUG_ANY)
+       scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+       NCR5380_dprint(NDEBUG_ANY, instance);
+       NCR5380_dprint_phase(NDEBUG_ANY, instance);
+
+       do_reset(instance);
 
-       /* get in phase */
-       NCR5380_write(TARGET_COMMAND_REG,
-                     PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
-       /* assert RST */
-       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
-       udelay(40);
        /* reset NCR registers */
-       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
        NCR5380_write(MODE_REG, MR_BASE);
        NCR5380_write(TARGET_COMMAND_REG, 0);
        NCR5380_write(SELECT_ENABLE_REG, 0);
-       /* ++roman: reset interrupt condition! otherwise no interrupts don't get
-        * through anymore ... */
-       (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 
        /* After the reset, there are no more connected or disconnected commands
         * and no busy units; so clear the low-level status here to avoid
@@ -2900,17 +2646,34 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
         * commands!
         */
 
-       if (hostdata->issue_queue)
-               dprintk(NDEBUG_ABORT, "scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
-       if (hostdata->connected)
-               dprintk(NDEBUG_ABORT, "scsi%d: reset aborted a connected command\n", H_NO(cmd));
-       if (hostdata->disconnected_queue)
-               dprintk(NDEBUG_ABORT, "scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+       hostdata->selecting = NULL;
+
+       list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+               struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+               set_host_byte(cmd, DID_RESET);
+               cmd->scsi_done(cmd);
+       }
+
+       list_for_each_entry(ncmd, &hostdata->autosense, list) {
+               struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+               set_host_byte(cmd, DID_RESET);
+               cmd->scsi_done(cmd);
+       }
+
+       if (hostdata->connected) {
+               set_host_byte(hostdata->connected, DID_RESET);
+               complete_cmd(instance, hostdata->connected);
+               hostdata->connected = NULL;
+       }
+
+       if (hostdata->sensing) {
+               set_host_byte(hostdata->connected, DID_RESET);
+               complete_cmd(instance, hostdata->sensing);
+               hostdata->sensing = NULL;
+       }
 
-       local_irq_save(flags);
-       hostdata->issue_queue = NULL;
-       hostdata->connected = NULL;
-       hostdata->disconnected_queue = NULL;
 #ifdef SUPPORT_TAGS
        free_all_tags(hostdata);
 #endif
@@ -2920,8 +2683,9 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
        hostdata->dma_len = 0;
 #endif
 
+       queue_work(hostdata->work_q, &hostdata->main_task);
        maybe_release_dma_irq(instance);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&hostdata->lock, flags);
 
        return SUCCESS;
 }
index 5ede3da..78d1b29 100644 (file)
@@ -66,7 +66,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/delay.h>
 #include <linux/blkdev.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -98,7 +97,6 @@
 
 #define NCR5380_queue_command           atari_scsi_queue_command
 #define NCR5380_abort                   atari_scsi_abort
-#define NCR5380_show_info               atari_scsi_show_info
 #define NCR5380_info                    atari_scsi_info
 
 #define NCR5380_dma_read_setup(instance, data, count) \
@@ -161,23 +159,10 @@ static inline unsigned long SCSI_DMA_GETADR(void)
        return adr;
 }
 
-#define HOSTDATA_DMALEN                (((struct NCR5380_hostdata *) \
-                               (atari_scsi_host->hostdata))->dma_len)
-
-/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
- * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
- * need ten times the standard value... */
-#ifndef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
-#define        AFTER_RESET_DELAY       (HZ/2)
-#else
-#define        AFTER_RESET_DELAY       (5*HZ/2)
-#endif
-
 #ifdef REAL_DMA
 static void atari_scsi_fetch_restbytes(void);
 #endif
 
-static struct Scsi_Host *atari_scsi_host;
 static unsigned char (*atari_scsi_reg_read)(unsigned char reg);
 static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value);
 
@@ -208,12 +193,12 @@ static int setup_cmd_per_lun = -1;
 module_param(setup_cmd_per_lun, int, 0);
 static int setup_sg_tablesize = -1;
 module_param(setup_sg_tablesize, int, 0);
-#ifdef SUPPORT_TAGS
 static int setup_use_tagged_queuing = -1;
 module_param(setup_use_tagged_queuing, int, 0);
-#endif
 static int setup_hostid = -1;
 module_param(setup_hostid, int, 0);
+static int setup_toshiba_delay = -1;
+module_param(setup_toshiba_delay, int, 0);
 
 
 #if defined(REAL_DMA)
@@ -273,15 +258,17 @@ static void scsi_dma_buserr(int irq, void *dummy)
 #endif
 
 
-static irqreturn_t scsi_tt_intr(int irq, void *dummy)
+static irqreturn_t scsi_tt_intr(int irq, void *dev)
 {
 #ifdef REAL_DMA
+       struct Scsi_Host *instance = dev;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        int dma_stat;
 
        dma_stat = tt_scsi_dma.dma_ctrl;
 
-       dprintk(NDEBUG_INTR, "scsi%d: NCR5380 interrupt, DMA status = %02x\n",
-                  atari_scsi_host->host_no, dma_stat & 0xff);
+       dsprintk(NDEBUG_INTR, instance, "NCR5380 interrupt, DMA status = %02x\n",
+                dma_stat & 0xff);
 
        /* Look if it was the DMA that has interrupted: First possibility
         * is that a bus error occurred...
@@ -304,7 +291,8 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy)
         * data reg!
         */
        if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
-               atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
+               atari_dma_residual = hostdata->dma_len -
+                       (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
 
                dprintk(NDEBUG_DMA, "SCSI DMA: There are %ld residual bytes.\n",
                           atari_dma_residual);
@@ -356,15 +344,17 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy)
 
 #endif /* REAL_DMA */
 
-       NCR5380_intr(irq, dummy);
+       NCR5380_intr(irq, dev);
 
        return IRQ_HANDLED;
 }
 
 
-static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
+static irqreturn_t scsi_falcon_intr(int irq, void *dev)
 {
 #ifdef REAL_DMA
+       struct Scsi_Host *instance = dev;
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        int dma_stat;
 
        /* Turn off DMA and select sector counter register before
@@ -399,7 +389,7 @@ static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
                        printk(KERN_ERR "SCSI DMA error: %ld bytes lost in "
                               "ST-DMA fifo\n", transferred & 15);
 
-               atari_dma_residual = HOSTDATA_DMALEN - transferred;
+               atari_dma_residual = hostdata->dma_len - transferred;
                dprintk(NDEBUG_DMA, "SCSI DMA: There are %ld residual bytes.\n",
                           atari_dma_residual);
        } else
@@ -411,13 +401,14 @@ static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
                 * data to the original destination address.
                 */
                memcpy(atari_dma_orig_addr, phys_to_virt(atari_dma_startaddr),
-                      HOSTDATA_DMALEN - atari_dma_residual);
+                      hostdata->dma_len - atari_dma_residual);
                atari_dma_orig_addr = NULL;
        }
 
 #endif /* REAL_DMA */
 
-       NCR5380_intr(irq, dummy);
+       NCR5380_intr(irq, dev);
+
        return IRQ_HANDLED;
 }
 
@@ -488,7 +479,7 @@ static int __init atari_scsi_setup(char *str)
         * Defaults depend on TT or Falcon, determined at run time.
         * Negative values mean don't change.
         */
-       int ints[6];
+       int ints[8];
 
        get_options(str, ARRAY_SIZE(ints), ints);
 
@@ -504,10 +495,11 @@ static int __init atari_scsi_setup(char *str)
                setup_sg_tablesize = ints[3];
        if (ints[0] >= 4)
                setup_hostid = ints[4];
-#ifdef SUPPORT_TAGS
        if (ints[0] >= 5)
                setup_use_tagged_queuing = ints[5];
-#endif
+       /* ints[6] (use_pdma) is ignored */
+       if (ints[0] >= 7)
+               setup_toshiba_delay = ints[7];
 
        return 1;
 }
@@ -516,38 +508,6 @@ __setup("atascsi=", atari_scsi_setup);
 #endif /* !MODULE */
 
 
-#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
-static void __init atari_scsi_reset_boot(void)
-{
-       unsigned long end;
-
-       /*
-        * Do a SCSI reset to clean up the bus during initialization. No messing
-        * with the queues, interrupts, or locks necessary here.
-        */
-
-       printk("Atari SCSI: resetting the SCSI bus...");
-
-       /* get in phase */
-       NCR5380_write(TARGET_COMMAND_REG,
-                     PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
-
-       /* assert RST */
-       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
-       /* The min. reset hold time is 25us, so 40us should be enough */
-       udelay(50);
-       /* reset RST and interrupt */
-       NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-
-       end = jiffies + AFTER_RESET_DELAY;
-       while (time_before(jiffies, end))
-               barrier();
-
-       printk(" done\n");
-}
-#endif
-
 #if defined(REAL_DMA)
 
 static unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance,
@@ -815,14 +775,14 @@ static int atari_scsi_bus_reset(struct scsi_cmnd *cmd)
 static struct scsi_host_template atari_scsi_template = {
        .module                 = THIS_MODULE,
        .proc_name              = DRV_MODULE_NAME,
-       .show_info              = atari_scsi_show_info,
        .name                   = "Atari native SCSI",
        .info                   = atari_scsi_info,
        .queuecommand           = atari_scsi_queue_command,
        .eh_abort_handler       = atari_scsi_abort,
        .eh_bus_reset_handler   = atari_scsi_bus_reset,
        .this_id                = 7,
-       .use_clustering         = DISABLE_CLUSTERING
+       .use_clustering         = DISABLE_CLUSTERING,
+       .cmd_size               = NCR5380_CMD_SIZE,
 };
 
 static int __init atari_scsi_probe(struct platform_device *pdev)
@@ -880,7 +840,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
        } else {
                /* Test if a host id is set in the NVRam */
                if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
-                       unsigned char b = nvram_read_byte(14);
+                       unsigned char b = nvram_read_byte(16);
 
                        /* Arbitration enabled? (for TOS)
                         * If yes, use configured host ID
@@ -915,21 +875,18 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
                error = -ENOMEM;
                goto fail_alloc;
        }
-       atari_scsi_host = instance;
-
-#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
-       atari_scsi_reset_boot();
-#endif
 
        instance->irq = irq->start;
 
        host_flags |= IS_A_TT() ? 0 : FLAG_LATE_DMA_SETUP;
-
 #ifdef SUPPORT_TAGS
        host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
 #endif
+       host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
 
-       NCR5380_init(instance, host_flags);
+       error = NCR5380_init(instance, host_flags);
+       if (error)
+               goto fail_init;
 
        if (IS_A_TT()) {
                error = request_irq(instance->irq, scsi_tt_intr, 0,
@@ -975,6 +932,8 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
 #endif
        }
 
+       NCR5380_maybe_reset_bus(instance);
+
        error = scsi_add_host(instance, NULL);
        if (error)
                goto fail_host;
@@ -989,6 +948,7 @@ fail_host:
                free_irq(instance->irq, instance);
 fail_irq:
        NCR5380_exit(instance);
+fail_init:
        scsi_host_put(instance);
 fail_alloc:
        if (atari_dma_buffer)
index 0e2bee9..e22a268 100644 (file)
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(cxgb3i_snd_win, "TCP send window in bytes (default=128KB)");
 
 static int cxgb3i_rx_credit_thres = 10 * 1024;
 module_param(cxgb3i_rx_credit_thres, int, 0644);
-MODULE_PARM_DESC(rx_credit_thres,
+MODULE_PARM_DESC(cxgb3i_rx_credit_thres,
                 "RX credits return threshold in bytes (default=10KB)");
 
 static unsigned int cxgb3i_max_connect = 8 * 1024;
index 3e08812..6c14e68 100644 (file)
 
 #define DONT_USE_INTR
 
-#define NCR5380_read(reg)              inb(port + reg)
-#define NCR5380_write(reg, value)      outb(value, port + reg)
+#define NCR5380_read(reg)              inb(instance->io_port + reg)
+#define NCR5380_write(reg, value)      outb(value, instance->io_port + reg)
 
 #define NCR5380_implementation_fields  /* none */
-#define NCR5380_local_declare()                unsigned int port
-#define NCR5380_setup(instance)                port = instance->io_port
-
-/*
- * Includes needed for NCR5380.[ch] (XXX: Move them to NCR5380.h)
- */
-#include <linux/delay.h>
 
 #include "NCR5380.h"
 #include "NCR5380.c"
@@ -56,6 +49,7 @@
 
 
 static struct scsi_host_template dmx3191d_driver_template = {
+       .module                 = THIS_MODULE,
        .proc_name              = DMX3191D_DRIVER_NAME,
        .name                   = "Domex DMX3191D",
        .info                   = NCR5380_info,
@@ -67,6 +61,8 @@ static struct scsi_host_template dmx3191d_driver_template = {
        .sg_tablesize           = SG_ALL,
        .cmd_per_lun            = 2,
        .use_clustering         = DISABLE_CLUSTERING,
+       .cmd_size               = NCR5380_CMD_SIZE,
+       .max_sectors            = 128,
 };
 
 static int dmx3191d_probe_one(struct pci_dev *pdev,
@@ -97,17 +93,25 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
         */
        shost->irq = NO_IRQ;
 
-       NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
+       error = NCR5380_init(shost, FLAG_NO_PSEUDO_DMA);
+       if (error)
+               goto out_host_put;
+
+       NCR5380_maybe_reset_bus(shost);
 
        pci_set_drvdata(pdev, shost);
 
        error = scsi_add_host(shost, &pdev->dev);
        if (error)
-               goto out_release_region;
+               goto out_exit;
 
        scsi_scan_host(shost);
        return 0;
 
+out_exit:
+       NCR5380_exit(shost);
+out_host_put:
+       scsi_host_put(shost);
  out_release_region:
        release_region(io, DMX3191D_REGION_LEN);
  out_disable_device:
@@ -119,15 +123,14 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
 static void dmx3191d_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       unsigned long io = shost->io_port;
 
        scsi_remove_host(shost);
 
        NCR5380_exit(shost);
-
-       release_region(shost->io_port, DMX3191D_REGION_LEN);
-       pci_disable_device(pdev);
-
        scsi_host_put(shost);
+       release_region(io, DMX3191D_REGION_LEN);
+       pci_disable_device(pdev);
 }
 
 static struct pci_device_id dmx3191d_pci_tbl[] = {
index 4c74c7b..6c736b0 100644 (file)
@@ -1,9 +1,5 @@
-
 #define PSEUDO_DMA
 #define DONT_USE_INTR
-#define UNSAFE                 /* Leave interrupts enabled during pseudo-dma I/O */
-#define DMA_WORKS_RIGHT
-
 
 /*
  * DTC 3180/3280 driver, by
 
 
 #include <linux/module.h>
-#include <linux/signal.h>
 #include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <scsi/scsi_host.h>
+
 #include "dtc.h"
 #define AUTOPROBE_IRQ
 #include "NCR5380.h"
@@ -150,7 +144,7 @@ static const struct signature {
 
 static int __init dtc_setup(char *str)
 {
-       static int commandline_current = 0;
+       static int commandline_current;
        int i;
        int ints[10];
 
@@ -188,7 +182,7 @@ __setup("dtc=", dtc_setup);
 
 static int __init dtc_detect(struct scsi_host_template * tpnt)
 {
-       static int current_override = 0, current_base = 0;
+       static int current_override, current_base;
        struct Scsi_Host *instance;
        unsigned int addr;
        void __iomem *base;
@@ -205,9 +199,8 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
                                addr = 0;
                } else
                        for (; !addr && (current_base < NO_BASES); ++current_base) {
-#if (DTCDEBUG & DTCDEBUG_INIT)
-                               printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address);
-#endif
+                               dprintk(NDEBUG_INIT, "dtc: probing address 0x%08x\n",
+                                       (unsigned int)bases[current_base].address);
                                if (bases[current_base].noauto)
                                        continue;
                                base = ioremap(bases[current_base].address, 0x2000);
@@ -216,18 +209,14 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
                                for (sig = 0; sig < NO_SIGNATURES; ++sig) {
                                        if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
                                                addr = bases[current_base].address;
-#if (DTCDEBUG & DTCDEBUG_INIT)
-                                               printk(KERN_DEBUG "scsi-dtc : detected board.\n");
-#endif
+                                               dprintk(NDEBUG_INIT, "dtc: detected board\n");
                                                goto found;
                                        }
                                }
                                iounmap(base);
                        }
 
-#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
-               printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr);
-#endif
+               dprintk(NDEBUG_INIT, "dtc: addr = 0x%08x\n", addr);
 
                if (!addr)
                        break;
@@ -235,12 +224,15 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
 found:
                instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
                if (instance == NULL)
-                       break;
+                       goto out_unmap;
 
                instance->base = addr;
                ((struct NCR5380_hostdata *)(instance)->hostdata)->base = base;
 
-               NCR5380_init(instance, 0);
+               if (NCR5380_init(instance, FLAG_NO_DMA_FIXUP))
+                       goto out_unregister;
+
+               NCR5380_maybe_reset_bus(instance);
 
                NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);  /* Enable int's */
                if (overrides[current_override].irq != IRQ_AUTO)
@@ -271,14 +263,19 @@ found:
                        printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
                instance->irq = NO_IRQ;
 #endif
-#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
-               printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+               dprintk(NDEBUG_INIT, "scsi%d : irq = %d\n",
+                       instance->host_no, instance->irq);
 
                ++current_override;
                ++count;
        }
        return count;
+
+out_unregister:
+       scsi_unregister(instance);
+out_unmap:
+       iounmap(base);
+       return count;
 }
 
 /*
@@ -331,12 +328,8 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
        unsigned char *d = dst;
        int i;                  /* For counting time spent in the poll-loop */
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
-       NCR5380_local_declare();
-       NCR5380_setup(instance);
 
        i = 0;
-       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-       NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
        if (instance->irq == NO_IRQ)
                NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
        else
@@ -348,7 +341,7 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
                while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
                        ++i;
                rtrc(3);
-               memcpy_fromio(d, base + DTC_DATA_BUF, 128);
+               memcpy_fromio(d, hostdata->base + DTC_DATA_BUF, 128);
                d += 128;
                len -= 128;
                rtrc(7);
@@ -358,9 +351,7 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
        rtrc(4);
        while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
                ++i;
-       NCR5380_write(MODE_REG, 0);     /* Clear the operating mode */
        rtrc(0);
-       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
        if (i > hostdata->spin_max_r)
                hostdata->spin_max_r = i;
        return (0);
@@ -383,12 +374,7 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
 {
        int i;
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
-       NCR5380_local_declare();
-       NCR5380_setup(instance);
 
-       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-       NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
-       /* set direction (write) */
        if (instance->irq == NO_IRQ)
                NCR5380_write(DTC_CONTROL_REG, 0);
        else
@@ -400,7 +386,7 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
                while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
                        ++i;
                rtrc(3);
-               memcpy_toio(base + DTC_DATA_BUF, src, 128);
+               memcpy_toio(hostdata->base + DTC_DATA_BUF, src, 128);
                src += 128;
                len -= 128;
        }
@@ -413,47 +399,60 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
                ++i;
        rtrc(7);
        /* Check for parity error here. fixme. */
-       NCR5380_write(MODE_REG, 0);     /* Clear the operating mode */
        rtrc(0);
        if (i > hostdata->spin_max_w)
                hostdata->spin_max_w = i;
        return (0);
 }
 
+static int dtc_dma_xfer_len(struct scsi_cmnd *cmd)
+{
+       int transfersize = cmd->transfersize;
+
+       /* Limit transfers to 32K, for xx400 & xx406
+        * pseudoDMA that transfers in 128 bytes blocks.
+        */
+       if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
+           !(cmd->SCp.this_residual % transfersize))
+               transfersize = 32 * 1024;
+
+       return transfersize;
+}
+
 MODULE_LICENSE("GPL");
 
 #include "NCR5380.c"
 
 static int dtc_release(struct Scsi_Host *shost)
 {
-       NCR5380_local_declare();
-       NCR5380_setup(shost);
+       struct NCR5380_hostdata *hostdata = shost_priv(shost);
+
        if (shost->irq != NO_IRQ)
                free_irq(shost->irq, shost);
        NCR5380_exit(shost);
-       if (shost->io_port && shost->n_io_port)
-               release_region(shost->io_port, shost->n_io_port);
        scsi_unregister(shost);
-       iounmap(base);
+       iounmap(hostdata->base);
        return 0;
 }
 
 static struct scsi_host_template driver_template = {
-       .name                           = "DTC 3180/3280 ",
-       .detect                         = dtc_detect,
-       .release                        = dtc_release,
-       .proc_name                      = "dtc3x80",
-       .show_info                      = dtc_show_info,
-       .write_info                     = dtc_write_info,
-       .info                           = dtc_info,
-       .queuecommand                   = dtc_queue_command,
-       .eh_abort_handler               = dtc_abort,
-       .eh_bus_reset_handler           = dtc_bus_reset,
-       .bios_param                     = dtc_biosparam,
-       .can_queue                      = CAN_QUEUE,
-       .this_id                        = 7,
-       .sg_tablesize                   = SG_ALL,
-       .cmd_per_lun                    = CMD_PER_LUN,
-       .use_clustering                 = DISABLE_CLUSTERING,
+       .name                   = "DTC 3180/3280",
+       .detect                 = dtc_detect,
+       .release                = dtc_release,
+       .proc_name              = "dtc3x80",
+       .show_info              = dtc_show_info,
+       .write_info             = dtc_write_info,
+       .info                   = dtc_info,
+       .queuecommand           = dtc_queue_command,
+       .eh_abort_handler       = dtc_abort,
+       .eh_bus_reset_handler   = dtc_bus_reset,
+       .bios_param             = dtc_biosparam,
+       .can_queue              = 32,
+       .this_id                = 7,
+       .sg_tablesize           = SG_ALL,
+       .cmd_per_lun            = 2,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .cmd_size               = NCR5380_CMD_SIZE,
+       .max_sectors            = 128,
 };
 #include "scsi_module.c"
index 78a2332..56732cb 100644 (file)
 #ifndef DTC3280_H
 #define DTC3280_H
 
-#define DTCDEBUG 0
-#define DTCDEBUG_INIT  0x1
-#define DTCDEBUG_TRANSFER 0x2
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 32 
-#endif
-
 #define NCR5380_implementation_fields \
     void __iomem *base
 
-#define NCR5380_local_declare() \
-    void __iomem *base
-
-#define NCR5380_setup(instance) \
-    base = ((struct NCR5380_hostdata *)(instance)->hostdata)->base
+#define DTC_address(reg) \
+       (((struct NCR5380_hostdata *)shost_priv(instance))->base + DTC_5380_OFFSET + reg)
 
-#define DTC_address(reg) (base + DTC_5380_OFFSET + reg)
-
-#define dbNCR5380_read(reg)                                              \
-    (rval=readb(DTC_address(reg)), \
-     (((unsigned char) printk("DTC : read register %d at addr %p is: %02x\n"\
-    , (reg), DTC_address(reg), rval)), rval ) )
-
-#define dbNCR5380_write(reg, value) do {                                  \
-    printk("DTC : write %02x to register %d at address %p\n",         \
-            (value), (reg), DTC_address(reg));     \
-    writeb(value, DTC_address(reg));} while(0)
-
-
-#if !(DTCDEBUG & DTCDEBUG_TRANSFER) 
 #define NCR5380_read(reg) (readb(DTC_address(reg)))
 #define NCR5380_write(reg, value) (writeb(value, DTC_address(reg)))
-#else
-#define NCR5380_read(reg) (readb(DTC_address(reg)))
-#define xNCR5380_read(reg)                                             \
-    (((unsigned char) printk("DTC : read register %d at address %p\n"\
-    , (reg), DTC_address(reg))), readb(DTC_address(reg)))
 
-#define NCR5380_write(reg, value) do {                                 \
-    printk("DTC : write %02x to register %d at address %p\n",  \
-           (value), (reg), DTC_address(reg));  \
-    writeb(value, DTC_address(reg));} while(0)
-#endif
+#define NCR5380_dma_xfer_len(instance, cmd, phase) \
+        dtc_dma_xfer_len(cmd)
 
 #define NCR5380_intr                   dtc_intr
 #define NCR5380_queue_command          dtc_queue_command
index f8d2478..90091e6 100644 (file)
  *     
  */
 
-/* settings for DTC3181E card with only Mustek scanner attached */
-#define USLEEP_POLL    msecs_to_jiffies(10)
-#define USLEEP_SLEEP   msecs_to_jiffies(200)
-#define USLEEP_WAITLONG        msecs_to_jiffies(5000)
-
 #define AUTOPROBE_IRQ
 
 #ifdef CONFIG_SCSI_GENERIC_NCR53C400
-#define NCR53C400_PSEUDO_DMA 1
 #define PSEUDO_DMA
-#define NCR53C400
 #endif
 
 #include <asm/io.h>
-#include <linux/signal.h>
 #include <linux/blkdev.h>
+#include <linux/module.h>
 #include <scsi/scsi_host.h>
 #include "g_NCR5380.h"
 #include "NCR5380.h"
-#include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/isapnp.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
 
-#define NCR_NOT_SET 0
-static int ncr_irq = NCR_NOT_SET;
-static int ncr_dma = NCR_NOT_SET;
-static int ncr_addr = NCR_NOT_SET;
-static int ncr_5380 = NCR_NOT_SET;
-static int ncr_53c400 = NCR_NOT_SET;
-static int ncr_53c400a = NCR_NOT_SET;
-static int dtc_3181e = NCR_NOT_SET;
+static int ncr_irq;
+static int ncr_dma;
+static int ncr_addr;
+static int ncr_5380;
+static int ncr_53c400;
+static int ncr_53c400a;
+static int dtc_3181e;
+static int hp_c2502;
 
 static struct override {
        NCR5380_map_type NCR5380_map_name;
@@ -121,7 +112,7 @@ static struct override {
 
 static void __init internal_setup(int board, char *str, int *ints)
 {
-       static int commandline_current = 0;
+       static int commandline_current;
        switch (board) {
        case BOARD_NCR5380:
                if (ints[0] != 2 && ints[0] != 3) {
@@ -235,6 +226,30 @@ static int __init do_DTC3181E_setup(char *str)
 
 #endif
 
+#ifndef SCSI_G_NCR5380_MEM
+/*
+ * Configure I/O address of 53C400A or DTC436 by writing magic numbers
+ * to ports 0x779 and 0x379.
+ */
+static void magic_configure(int idx, u8 irq, u8 magic[])
+{
+       u8 cfg = 0;
+
+       outb(magic[0], 0x779);
+       outb(magic[1], 0x379);
+       outb(magic[2], 0x379);
+       outb(magic[3], 0x379);
+       outb(magic[4], 0x379);
+
+       /* allowed IRQs for HP C2502 */
+       if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7)
+               irq = 0;
+       if (idx >= 0 && idx <= 7)
+               cfg = 0x80 | idx | (irq << 4);
+       outb(cfg, 0x379);
+}
+#endif
+
 /**
  *     generic_NCR5380_detect  -       look for NCR5380 controllers
  *     @tpnt: the scsi template
@@ -243,19 +258,18 @@ static int __init do_DTC3181E_setup(char *str)
  *     and DTC436(ISAPnP) controllers. If overrides have been set we use
  *     them.
  *
- *     The caller supplied NCR5380_init function is invoked from here, before
- *     the interrupt line is taken.
- *
  *     Locks: none
  */
 
 static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
 {
-       static int current_override = 0;
+       static int current_override;
        int count;
        unsigned int *ports;
+       u8 *magic = NULL;
 #ifndef SCSI_G_NCR5380_MEM
        int i;
+       int port_idx = -1;
        unsigned long region_size = 16;
 #endif
        static unsigned int __initdata ncr_53c400a_ports[] = {
@@ -264,27 +278,36 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
        static unsigned int __initdata dtc_3181e_ports[] = {
                0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
        };
-       int flags = 0;
+       static u8 ncr_53c400a_magic[] __initdata = {    /* 53C400A & DTC436 */
+               0x59, 0xb9, 0xc5, 0xae, 0xa6
+       };
+       static u8 hp_c2502_magic[] __initdata = {       /* HP C2502 */
+               0x0f, 0x22, 0xf0, 0x20, 0x80
+       };
+       int flags;
        struct Scsi_Host *instance;
+       struct NCR5380_hostdata *hostdata;
 #ifdef SCSI_G_NCR5380_MEM
        unsigned long base;
        void __iomem *iomem;
 #endif
 
-       if (ncr_irq != NCR_NOT_SET)
+       if (ncr_irq)
                overrides[0].irq = ncr_irq;
-       if (ncr_dma != NCR_NOT_SET)
+       if (ncr_dma)
                overrides[0].dma = ncr_dma;
-       if (ncr_addr != NCR_NOT_SET)
+       if (ncr_addr)
                overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr;
-       if (ncr_5380 != NCR_NOT_SET)
+       if (ncr_5380)
                overrides[0].board = BOARD_NCR5380;
-       else if (ncr_53c400 != NCR_NOT_SET)
+       else if (ncr_53c400)
                overrides[0].board = BOARD_NCR53C400;
-       else if (ncr_53c400a != NCR_NOT_SET)
+       else if (ncr_53c400a)
                overrides[0].board = BOARD_NCR53C400A;
-       else if (dtc_3181e != NCR_NOT_SET)
+       else if (dtc_3181e)
                overrides[0].board = BOARD_DTC3181E;
+       else if (hp_c2502)
+               overrides[0].board = BOARD_HP_C2502;
 #ifndef SCSI_G_NCR5380_MEM
        if (!current_override && isapnp_present()) {
                struct pnp_dev *dev = NULL;
@@ -318,41 +341,45 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
                }
        }
 #endif
-       tpnt->proc_name = "g_NCR5380";
 
        for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
                if (!(overrides[current_override].NCR5380_map_name))
                        continue;
 
                ports = NULL;
+               flags = 0;
                switch (overrides[current_override].board) {
                case BOARD_NCR5380:
                        flags = FLAG_NO_PSEUDO_DMA;
                        break;
                case BOARD_NCR53C400:
-                       flags = FLAG_NCR53C400;
+#ifdef PSEUDO_DMA
+                       flags = FLAG_NO_DMA_FIXUP;
+#endif
                        break;
                case BOARD_NCR53C400A:
-                       flags = FLAG_NO_PSEUDO_DMA;
+                       flags = FLAG_NO_DMA_FIXUP;
+                       ports = ncr_53c400a_ports;
+                       magic = ncr_53c400a_magic;
+                       break;
+               case BOARD_HP_C2502:
+                       flags = FLAG_NO_DMA_FIXUP;
                        ports = ncr_53c400a_ports;
+                       magic = hp_c2502_magic;
                        break;
                case BOARD_DTC3181E:
-                       flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E;
+                       flags = FLAG_NO_DMA_FIXUP;
                        ports = dtc_3181e_ports;
+                       magic = ncr_53c400a_magic;
                        break;
                }
 
 #ifndef SCSI_G_NCR5380_MEM
-               if (ports) {
+               if (ports && magic) {
                        /* wakeup sequence for the NCR53C400A and DTC3181E */
 
                        /* Disable the adapter and look for a free io port */
-                       outb(0x59, 0x779);
-                       outb(0xb9, 0x379);
-                       outb(0xc5, 0x379);
-                       outb(0xae, 0x379);
-                       outb(0xa6, 0x379);
-                       outb(0x00, 0x379);
+                       magic_configure(-1, 0, magic);
 
                        if (overrides[current_override].NCR5380_map_name != PORT_AUTO)
                                for (i = 0; ports[i]; i++) {
@@ -371,17 +398,12 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
                                }
                        if (ports[i]) {
                                /* At this point we have our region reserved */
-                               outb(0x59, 0x779);
-                               outb(0xb9, 0x379);
-                               outb(0xc5, 0x379);
-                               outb(0xae, 0x379);
-                               outb(0xa6, 0x379);
-                               outb(0x80 | i, 0x379);  /* set io port to be used */
+                               magic_configure(i, 0, magic); /* no IRQ yet */
                                outb(0xc0, ports[i] + 9);
                                if (inb(ports[i] + 9) != 0x80)
                                        continue;
-                               else
-                                       overrides[current_override].NCR5380_map_name = ports[i];
+                               overrides[current_override].NCR5380_map_name = ports[i];
+                               port_idx = i;
                        } else
                                continue;
                }
@@ -403,24 +425,65 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
                }
 #endif
                instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
-               if (instance == NULL) {
-#ifndef SCSI_G_NCR5380_MEM
-                       release_region(overrides[current_override].NCR5380_map_name, region_size);
-#else
-                       iounmap(iomem);
-                       release_mem_region(base, NCR5380_region_size);
-#endif
-                       continue;
-               }
+               if (instance == NULL)
+                       goto out_release;
+               hostdata = shost_priv(instance);
 
-               instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
 #ifndef SCSI_G_NCR5380_MEM
+               instance->io_port = overrides[current_override].NCR5380_map_name;
                instance->n_io_port = region_size;
+               hostdata->io_width = 1; /* 8-bit PDMA by default */
+
+               /*
+                * On NCR53C400 boards, NCR5380 registers are mapped 8 past
+                * the base address.
+                */
+               switch (overrides[current_override].board) {
+               case BOARD_NCR53C400:
+                       instance->io_port += 8;
+                       hostdata->c400_ctl_status = 0;
+                       hostdata->c400_blk_cnt = 1;
+                       hostdata->c400_host_buf = 4;
+                       break;
+               case BOARD_DTC3181E:
+                       hostdata->io_width = 2; /* 16-bit PDMA */
+                       /* fall through */
+               case BOARD_NCR53C400A:
+               case BOARD_HP_C2502:
+                       hostdata->c400_ctl_status = 9;
+                       hostdata->c400_blk_cnt = 10;
+                       hostdata->c400_host_buf = 8;
+                       break;
+               }
 #else
-               ((struct NCR5380_hostdata *)instance->hostdata)->iomem = iomem;
+               instance->base = overrides[current_override].NCR5380_map_name;
+               hostdata->iomem = iomem;
+               switch (overrides[current_override].board) {
+               case BOARD_NCR53C400:
+                       hostdata->c400_ctl_status = 0x100;
+                       hostdata->c400_blk_cnt = 0x101;
+                       hostdata->c400_host_buf = 0x104;
+                       break;
+               case BOARD_DTC3181E:
+               case BOARD_NCR53C400A:
+               case BOARD_HP_C2502:
+                       pr_err(DRV_MODULE_NAME ": unknown register offsets\n");
+                       goto out_unregister;
+               }
 #endif
 
-               NCR5380_init(instance, flags);
+               if (NCR5380_init(instance, flags))
+                       goto out_unregister;
+
+               switch (overrides[current_override].board) {
+               case BOARD_NCR53C400:
+               case BOARD_DTC3181E:
+               case BOARD_NCR53C400A:
+               case BOARD_HP_C2502:
+                       NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
+               }
+
+               NCR5380_maybe_reset_bus(instance);
 
                if (overrides[current_override].irq != IRQ_AUTO)
                        instance->irq = overrides[current_override].irq;
@@ -431,12 +494,18 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
                if (instance->irq == 255)
                        instance->irq = NO_IRQ;
 
-               if (instance->irq != NO_IRQ)
+               if (instance->irq != NO_IRQ) {
+#ifndef SCSI_G_NCR5380_MEM
+                       /* set IRQ for HP C2502 */
+                       if (overrides[current_override].board == BOARD_HP_C2502)
+                               magic_configure(port_idx, instance->irq, magic);
+#endif
                        if (request_irq(instance->irq, generic_NCR5380_intr,
                                        0, "NCR5380", instance)) {
                                printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
                                instance->irq = NO_IRQ;
                        }
+               }
 
                if (instance->irq == NO_IRQ) {
                        printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
@@ -447,6 +516,17 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
                ++count;
        }
        return count;
+
+out_unregister:
+       scsi_unregister(instance);
+out_release:
+#ifndef SCSI_G_NCR5380_MEM
+       release_region(overrides[current_override].NCR5380_map_name, region_size);
+#else
+       iounmap(iomem);
+       release_mem_region(base, NCR5380_region_size);
+#endif
+       return count;
 }
 
 /**
@@ -460,21 +540,15 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
  
 static int generic_NCR5380_release_resources(struct Scsi_Host *instance)
 {
-       NCR5380_local_declare();
-       NCR5380_setup(instance);
-       
        if (instance->irq != NO_IRQ)
                free_irq(instance->irq, instance);
        NCR5380_exit(instance);
-
 #ifndef SCSI_G_NCR5380_MEM
-       release_region(instance->NCR5380_instance_name, instance->n_io_port);
+       release_region(instance->io_port, instance->n_io_port);
 #else
        iounmap(((struct NCR5380_hostdata *)instance->hostdata)->iomem);
-       release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size);
+       release_mem_region(instance->base, NCR5380_region_size);
 #endif
-
-
        return 0;
 }
 
@@ -507,7 +581,7 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
 }
 #endif
 
-#ifdef NCR53C400_PSEUDO_DMA
+#ifdef PSEUDO_DMA
 
 /**
  *     NCR5380_pread           -       pseudo DMA read
@@ -521,75 +595,68 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
  
 static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
 {
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        int blocks = len / 128;
        int start = 0;
-       int bl;
-
-       NCR5380_local_declare();
-       NCR5380_setup(instance);
 
-       NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
-       NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+       NCR5380_write(hostdata->c400_ctl_status, CSR_BASE | CSR_TRANS_DIR);
+       NCR5380_write(hostdata->c400_blk_cnt, blocks);
        while (1) {
-               if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+               if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
                        break;
-               }
-               if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+               if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
                        printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
                        return -1;
                }
-               while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY);
+               while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
+                       ; /* FIXME - no timeout */
 
 #ifndef SCSI_G_NCR5380_MEM
-               {
-                       int i;
-                       for (i = 0; i < 128; i++)
-                               dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
-               }
+               if (hostdata->io_width == 2)
+                       insw(instance->io_port + hostdata->c400_host_buf,
+                                                       dst + start, 64);
+               else
+                       insb(instance->io_port + hostdata->c400_host_buf,
+                                                       dst + start, 128);
 #else
                /* implies SCSI_G_NCR5380_MEM */
-               memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128);
+               memcpy_fromio(dst + start,
+                             hostdata->iomem + NCR53C400_host_buffer, 128);
 #endif
                start += 128;
                blocks--;
        }
 
        if (blocks) {
-               while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-               {
-                       // FIXME - no timeout
-               }
+               while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
+                       ; /* FIXME - no timeout */
 
 #ifndef SCSI_G_NCR5380_MEM
-               {
-                       int i;  
-                       for (i = 0; i < 128; i++)
-                               dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
-               }
+               if (hostdata->io_width == 2)
+                       insw(instance->io_port + hostdata->c400_host_buf,
+                                                       dst + start, 64);
+               else
+                       insb(instance->io_port + hostdata->c400_host_buf,
+                                                       dst + start, 128);
 #else
                /* implies SCSI_G_NCR5380_MEM */
-               memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128);
+               memcpy_fromio(dst + start,
+                             hostdata->iomem + NCR53C400_host_buffer, 128);
 #endif
                start += 128;
                blocks--;
        }
 
-       if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+       if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ))
                printk("53C400r: no 53C80 gated irq after transfer");
 
-#if 0
-       /*
-        *      DON'T DO THIS - THEY NEVER ARRIVE!
-        */
-       printk("53C400r: Waiting for 53C80 registers\n");
-       while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
+       /* wait for 53C80 registers to be available */
+       while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG))
                ;
-#endif
+
        if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
                printk(KERN_ERR "53C400r: no end dma signal\n");
                
-       NCR5380_write(MODE_REG, MR_BASE);
-       NCR5380_read(RESET_PARITY_INTERRUPT_REG);
        return 0;
 }
 
@@ -605,89 +672,91 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
 
 static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
 {
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
        int blocks = len / 128;
        int start = 0;
-       int bl;
-       int i;
 
-       NCR5380_local_declare();
-       NCR5380_setup(instance);
-
-       NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
-       NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+       NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
+       NCR5380_write(hostdata->c400_blk_cnt, blocks);
        while (1) {
-               if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+               if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
                        printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
                        return -1;
                }
 
-               if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+               if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
                        break;
-               }
-               while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+               while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
                        ; // FIXME - timeout
 #ifndef SCSI_G_NCR5380_MEM
-               {
-                       for (i = 0; i < 128; i++)
-                               NCR5380_write(C400_HOST_BUFFER, src[start + i]);
-               }
+               if (hostdata->io_width == 2)
+                       outsw(instance->io_port + hostdata->c400_host_buf,
+                                                       src + start, 64);
+               else
+                       outsb(instance->io_port + hostdata->c400_host_buf,
+                                                       src + start, 128);
 #else
                /* implies SCSI_G_NCR5380_MEM */
-               memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128);
+               memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
+                           src + start, 128);
 #endif
                start += 128;
                blocks--;
        }
        if (blocks) {
-               while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+               while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
                        ; // FIXME - no timeout
 
 #ifndef SCSI_G_NCR5380_MEM
-               {
-                       for (i = 0; i < 128; i++)
-                               NCR5380_write(C400_HOST_BUFFER, src[start + i]);
-               }
+               if (hostdata->io_width == 2)
+                       outsw(instance->io_port + hostdata->c400_host_buf,
+                                                       src + start, 64);
+               else
+                       outsb(instance->io_port + hostdata->c400_host_buf,
+                                                       src + start, 128);
 #else
                /* implies SCSI_G_NCR5380_MEM */
-               memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128);
+               memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
+                           src + start, 128);
 #endif
                start += 128;
                blocks--;
        }
 
-#if 0
-       printk("53C400w: waiting for registers to be available\n");
-       THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG);
-       printk("53C400w: Got em\n");
-#endif
-
-       /* Let's wait for this instead - could be ugly */
-       /* All documentation says to check for this. Maybe my hardware is too
-        * fast. Waiting for it seems to work fine! KLL
-        */
-       while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
-               ;       // FIXME - no timeout
-
-       /*
-        * I know. i is certainly != 0 here but the loop is new. See previous
-        * comment.
-        */
-       if (i) {
-               if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
-                       printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i);
-       } else
-               printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n");
+       /* wait for 53C80 registers to be available */
+       while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
+               udelay(4); /* DTC436 chip hangs without this */
+               /* FIXME - no timeout */
+       }
 
-#if 0
        if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
                printk(KERN_ERR "53C400w: no end dma signal\n");
        }
-#endif
+
        while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
                ;       // TIMEOUT
        return 0;
 }
-#endif                         /* PSEUDO_DMA */
+
+static int generic_NCR5380_dma_xfer_len(struct scsi_cmnd *cmd)
+{
+       int transfersize = cmd->transfersize;
+
+       /* Limit transfers to 32K, for xx400 & xx406
+        * pseudoDMA that transfers in 128 bytes blocks.
+        */
+       if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
+           !(cmd->SCp.this_residual % transfersize))
+               transfersize = 32 * 1024;
+
+       /* 53C400 datasheet: non-modulo-128-byte transfers should use PIO */
+       if (transfersize % 128)
+               transfersize = 0;
+
+       return transfersize;
+}
+
+#endif /* PSEUDO_DMA */
 
 /*
  *     Include the NCR5380 core code that we build our driver around   
@@ -696,22 +765,24 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
 #include "NCR5380.c"
 
 static struct scsi_host_template driver_template = {
-       .show_info              = generic_NCR5380_show_info,
-       .name                   = "Generic NCR5380/NCR53C400 SCSI",
-       .detect                 = generic_NCR5380_detect,
-       .release                = generic_NCR5380_release_resources,
-       .info                   = generic_NCR5380_info,
-       .queuecommand           = generic_NCR5380_queue_command,
+       .proc_name              = DRV_MODULE_NAME,
+       .name                   = "Generic NCR5380/NCR53C400 SCSI",
+       .detect                 = generic_NCR5380_detect,
+       .release                = generic_NCR5380_release_resources,
+       .info                   = generic_NCR5380_info,
+       .queuecommand           = generic_NCR5380_queue_command,
        .eh_abort_handler       = generic_NCR5380_abort,
        .eh_bus_reset_handler   = generic_NCR5380_bus_reset,
-       .bios_param             = NCR5380_BIOSPARAM,
-       .can_queue              = CAN_QUEUE,
-        .this_id               = 7,
-        .sg_tablesize          = SG_ALL,
-       .cmd_per_lun            = CMD_PER_LUN,
-        .use_clustering                = DISABLE_CLUSTERING,
+       .bios_param             = NCR5380_BIOSPARAM,
+       .can_queue              = 16,
+       .this_id                = 7,
+       .sg_tablesize           = SG_ALL,
+       .cmd_per_lun            = 2,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .cmd_size               = NCR5380_CMD_SIZE,
+       .max_sectors            = 128,
 };
-#include <linux/module.h>
+
 #include "scsi_module.c"
 
 module_param(ncr_irq, int, 0);
@@ -721,6 +792,7 @@ module_param(ncr_5380, int, 0);
 module_param(ncr_53c400, int, 0);
 module_param(ncr_53c400a, int, 0);
 module_param(dtc_3181e, int, 0);
+module_param(hp_c2502, int, 0);
 MODULE_LICENSE("GPL");
 
 #if !defined(SCSI_G_NCR5380_MEM) && defined(MODULE)
index bea1a3b..6f3d2ac 100644 (file)
 #ifndef GENERIC_NCR5380_H
 #define GENERIC_NCR5380_H
 
-#ifdef NCR53C400
+#ifdef CONFIG_SCSI_GENERIC_NCR53C400
 #define BIOSPARAM
 #define NCR5380_BIOSPARAM generic_NCR5380_biosparam
 #else
 #define NCR5380_BIOSPARAM NULL
 #endif
 
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 16
-#endif
-
 #define __STRVAL(x) #x
 #define STRVAL(x) __STRVAL(x)
 
 #ifndef SCSI_G_NCR5380_MEM
+#define DRV_MODULE_NAME "g_NCR5380"
 
-#define NCR5380_map_config port
 #define NCR5380_map_type int
 #define NCR5380_map_name port
-#define NCR5380_instance_name io_port
-#define NCR53C400_register_offset 0
-#define NCR53C400_address_adjust 8
 
-#ifdef NCR53C400
+#ifdef CONFIG_SCSI_GENERIC_NCR53C400
 #define NCR5380_region_size 16
 #else
 #define NCR5380_region_size 8
 #endif
 
-#define NCR5380_read(reg) (inb(NCR5380_map_name + (reg)))
-#define NCR5380_write(reg, value) (outb((value), (NCR5380_map_name + (reg))))
+#define NCR5380_read(reg) \
+       inb(instance->io_port + (reg))
+#define NCR5380_write(reg, value) \
+       outb(value, instance->io_port + (reg))
 
 #define NCR5380_implementation_fields \
-    NCR5380_map_type NCR5380_map_name
-
-#define NCR5380_local_declare() \
-    register NCR5380_implementation_fields
-
-#define NCR5380_setup(instance) \
-    NCR5380_map_name = (NCR5380_map_type)((instance)->NCR5380_instance_name)
+       int c400_ctl_status; \
+       int c400_blk_cnt; \
+       int c400_host_buf; \
+       int io_width;
 
 #else 
 /* therefore SCSI_G_NCR5380_MEM */
+#define DRV_MODULE_NAME "g_NCR5380_mmio"
 
-#define NCR5380_map_config memory
 #define NCR5380_map_type unsigned long
 #define NCR5380_map_name base
-#define NCR5380_instance_name base
-#define NCR53C400_register_offset 0x108
-#define NCR53C400_address_adjust 0
 #define NCR53C400_mem_base 0x3880
 #define NCR53C400_host_buffer 0x3900
 #define NCR5380_region_size 0x3a00
 
-#define NCR5380_read(reg) readb(iomem + NCR53C400_mem_base + (reg))
-#define NCR5380_write(reg, value) writeb(value, iomem + NCR53C400_mem_base + (reg))
+#define NCR5380_read(reg) \
+       readb(((struct NCR5380_hostdata *)shost_priv(instance))->iomem + \
+             NCR53C400_mem_base + (reg))
+#define NCR5380_write(reg, value) \
+       writeb(value, ((struct NCR5380_hostdata *)shost_priv(instance))->iomem + \
+              NCR53C400_mem_base + (reg))
 
 #define NCR5380_implementation_fields \
-    NCR5380_map_type NCR5380_map_name; \
-    void __iomem *iomem;
-
-#define NCR5380_local_declare() \
-    register void __iomem *iomem
-
-#define NCR5380_setup(instance) \
-    iomem = (((struct NCR5380_hostdata *)(instance)->hostdata)->iomem)
+       void __iomem *iomem; \
+       int c400_ctl_status; \
+       int c400_blk_cnt; \
+       int c400_host_buf;
 
 #endif
 
+#define NCR5380_dma_xfer_len(instance, cmd, phase) \
+        generic_NCR5380_dma_xfer_len(cmd)
+
 #define NCR5380_intr generic_NCR5380_intr
 #define NCR5380_queue_command generic_NCR5380_queue_command
 #define NCR5380_abort generic_NCR5380_abort
 #define BOARD_NCR53C400        1
 #define BOARD_NCR53C400A 2
 #define BOARD_DTC3181E 3
+#define BOARD_HP_C2502 4
 
-#endif /* ndef ASM */
 #endif /* GENERIC_NCR5380_H */
 
index d543811..057fdeb 100644 (file)
 /* ITCT header */
 /* qw0 */
 #define ITCT_HDR_DEV_TYPE_OFF          0
-#define ITCT_HDR_DEV_TYPE_MSK          (0x3 << ITCT_HDR_DEV_TYPE_OFF)
+#define ITCT_HDR_DEV_TYPE_MSK          (0x3ULL << ITCT_HDR_DEV_TYPE_OFF)
 #define ITCT_HDR_VALID_OFF             2
-#define ITCT_HDR_VALID_MSK             (0x1 << ITCT_HDR_VALID_OFF)
-#define ITCT_HDR_BREAK_REPLY_ENA_OFF   3
-#define ITCT_HDR_BREAK_REPLY_ENA_MSK   (0x1 << ITCT_HDR_BREAK_REPLY_ENA_OFF)
+#define ITCT_HDR_VALID_MSK             (0x1ULL << ITCT_HDR_VALID_OFF)
 #define ITCT_HDR_AWT_CONTROL_OFF       4
-#define ITCT_HDR_AWT_CONTROL_MSK       (0x1 << ITCT_HDR_AWT_CONTROL_OFF)
+#define ITCT_HDR_AWT_CONTROL_MSK       (0x1ULL << ITCT_HDR_AWT_CONTROL_OFF)
 #define ITCT_HDR_MAX_CONN_RATE_OFF     5
-#define ITCT_HDR_MAX_CONN_RATE_MSK     (0xf << ITCT_HDR_MAX_CONN_RATE_OFF)
+#define ITCT_HDR_MAX_CONN_RATE_MSK     (0xfULL << ITCT_HDR_MAX_CONN_RATE_OFF)
 #define ITCT_HDR_VALID_LINK_NUM_OFF    9
-#define ITCT_HDR_VALID_LINK_NUM_MSK    (0xf << ITCT_HDR_VALID_LINK_NUM_OFF)
+#define ITCT_HDR_VALID_LINK_NUM_MSK    (0xfULL << ITCT_HDR_VALID_LINK_NUM_OFF)
 #define ITCT_HDR_PORT_ID_OFF           13
-#define ITCT_HDR_PORT_ID_MSK           (0x7 << ITCT_HDR_PORT_ID_OFF)
+#define ITCT_HDR_PORT_ID_MSK           (0x7ULL << ITCT_HDR_PORT_ID_OFF)
 #define ITCT_HDR_SMP_TIMEOUT_OFF       16
-#define ITCT_HDR_SMP_TIMEOUT_MSK       (0xffff << ITCT_HDR_SMP_TIMEOUT_OFF)
-#define ITCT_HDR_MAX_BURST_BYTES_OFF   16
-#define ITCT_HDR_MAX_BURST_BYTES_MSK   (0xffffffff << \
-                                       ITCT_MAX_BURST_BYTES_OFF)
+#define ITCT_HDR_SMP_TIMEOUT_MSK       (0xffffULL << ITCT_HDR_SMP_TIMEOUT_OFF)
 /* qw1 */
 #define ITCT_HDR_MAX_SAS_ADDR_OFF      0
 #define ITCT_HDR_MAX_SAS_ADDR_MSK      (0xffffffffffffffff << \
                                        ITCT_HDR_MAX_SAS_ADDR_OFF)
 /* qw2 */
 #define ITCT_HDR_IT_NEXUS_LOSS_TL_OFF  0
-#define ITCT_HDR_IT_NEXUS_LOSS_TL_MSK  (0xffff << \
+#define ITCT_HDR_IT_NEXUS_LOSS_TL_MSK  (0xffffULL << \
                                        ITCT_HDR_IT_NEXUS_LOSS_TL_OFF)
 #define ITCT_HDR_BUS_INACTIVE_TL_OFF   16
-#define ITCT_HDR_BUS_INACTIVE_TL_MSK   (0xffff << \
+#define ITCT_HDR_BUS_INACTIVE_TL_MSK   (0xffffULL << \
                                        ITCT_HDR_BUS_INACTIVE_TL_OFF)
 #define ITCT_HDR_MAX_CONN_TL_OFF       32
-#define ITCT_HDR_MAX_CONN_TL_MSK       (0xffff << \
+#define ITCT_HDR_MAX_CONN_TL_MSK       (0xffffULL << \
                                        ITCT_HDR_MAX_CONN_TL_OFF)
 #define ITCT_HDR_REJ_OPEN_TL_OFF       48
-#define ITCT_HDR_REJ_OPEN_TL_MSK       (0xffff << \
-                                       ITCT_REJ_OPEN_TL_OFF)
+#define ITCT_HDR_REJ_OPEN_TL_MSK       (0xffffULL << \
+                                       ITCT_HDR_REJ_OPEN_TL_OFF)
 
 /* Err record header */
 #define ERR_HDR_DMA_TX_ERR_TYPE_OFF    0
@@ -533,10 +528,10 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
        itct->sas_addr = __swab64(itct->sas_addr);
 
        /* qw2 */
-       itct->qw2 = cpu_to_le64((500 < ITCT_HDR_IT_NEXUS_LOSS_TL_OFF) |
-                               (0xff00 < ITCT_HDR_BUS_INACTIVE_TL_OFF) |
-                               (0xff00 < ITCT_HDR_MAX_CONN_TL_OFF) |
-                               (0xff00 < ITCT_HDR_REJ_OPEN_TL_OFF));
+       itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_IT_NEXUS_LOSS_TL_OFF) |
+                               (0xff00ULL << ITCT_HDR_BUS_INACTIVE_TL_OFF) |
+                               (0xff00ULL << ITCT_HDR_MAX_CONN_TL_OFF) |
+                               (0xff00ULL << ITCT_HDR_REJ_OPEN_TL_OFF));
 }
 
 static void free_device_v1_hw(struct hisi_hba *hisi_hba,
@@ -544,7 +539,8 @@ static void free_device_v1_hw(struct hisi_hba *hisi_hba,
 {
        u64 dev_id = sas_dev->device_id;
        struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
-       u32 qw0, reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
+       u64 qw0;
+       u32 reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
 
        reg_val |= CFG_AGING_TIME_ITCT_REL_MSK;
        hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
index 4e1a632..f8b88fa 100644 (file)
@@ -43,6 +43,7 @@ typedef struct {
        unsigned dp:1;          /* Data phase present           */
        unsigned rd:1;          /* Read data in data phase      */
        unsigned wanted:1;      /* Parport sharing busy flag    */
+       unsigned int dev_no;    /* Device number                */
        wait_queue_head_t *waiting;
        struct Scsi_Host *host;
        struct list_head list;
@@ -1120,15 +1121,40 @@ static struct scsi_host_template imm_template = {
 
 static LIST_HEAD(imm_hosts);
 
+/*
+ * Finds the first available device number that can be alloted to the
+ * new imm device and returns the address of the previous node so that
+ * we can add to the tail and have a list in the ascending order.
+ */
+
+static inline imm_struct *find_parent(void)
+{
+       imm_struct *dev, *par = NULL;
+       unsigned int cnt = 0;
+
+       if (list_empty(&imm_hosts))
+               return NULL;
+
+       list_for_each_entry(dev, &imm_hosts, list) {
+               if (dev->dev_no != cnt)
+                       return par;
+               cnt++;
+               par = dev;
+       }
+
+       return par;
+}
+
 static int __imm_attach(struct parport *pb)
 {
        struct Scsi_Host *host;
-       imm_struct *dev;
+       imm_struct *dev, *temp;
        DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
        DEFINE_WAIT(wait);
        int ports;
        int modes, ppb;
        int err = -ENOMEM;
+       struct pardev_cb imm_cb;
 
        init_waitqueue_head(&waiting);
 
@@ -1141,9 +1167,15 @@ static int __imm_attach(struct parport *pb)
        dev->mode = IMM_AUTODETECT;
        INIT_LIST_HEAD(&dev->list);
 
-       dev->dev = parport_register_device(pb, "imm", NULL, imm_wakeup,
-                                               NULL, 0, dev);
+       temp = find_parent();
+       if (temp)
+               dev->dev_no = temp->dev_no + 1;
+
+       memset(&imm_cb, 0, sizeof(imm_cb));
+       imm_cb.private = dev;
+       imm_cb.wakeup = imm_wakeup;
 
+       dev->dev = parport_register_dev_model(pb, "imm", &imm_cb, dev->dev_no);
        if (!dev->dev)
                goto out;
 
@@ -1207,7 +1239,10 @@ static int __imm_attach(struct parport *pb)
        host->unique_id = pb->number;
        *(imm_struct **)&host->hostdata = dev;
        dev->host = host;
-       list_add_tail(&dev->list, &imm_hosts);
+       if (!temp)
+               list_add_tail(&dev->list, &imm_hosts);
+       else
+               list_add_tail(&dev->list, &temp->list);
        err = scsi_add_host(host, NULL);
        if (err)
                goto out2;
@@ -1245,9 +1280,10 @@ static void imm_detach(struct parport *pb)
 }
 
 static struct parport_driver imm_driver = {
-       .name   = "imm",
-       .attach = imm_attach,
-       .detach = imm_detach,
+       .name           = "imm",
+       .match_port     = imm_attach,
+       .detach         = imm_detach,
+       .devmodel       = true,
 };
 
 static int __init imm_driver_init(void)
index 536cd5a..1c3759b 100644 (file)
@@ -4003,13 +4003,12 @@ static ssize_t ipr_store_update_fw(struct device *dev,
        struct ipr_sglist *sglist;
        char fname[100];
        char *src;
-       int len, result, dnld_size;
+       int result, dnld_size;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       len = snprintf(fname, 99, "%s", buf);
-       fname[len-1] = '\0';
+       snprintf(fname, sizeof(fname), "%s", buf);
 
        if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
                dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);
index d64a769..bb23813 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #define PSEUDO_DMA
 
 #define NCR5380_implementation_fields   unsigned char *pdma_base
-#define NCR5380_local_declare()         struct Scsi_Host *_instance
-#define NCR5380_setup(instance)         _instance = instance
 
-#define NCR5380_read(reg)               macscsi_read(_instance, reg)
-#define NCR5380_write(reg, value)       macscsi_write(_instance, reg, value)
+#define NCR5380_read(reg)               macscsi_read(instance, reg)
+#define NCR5380_write(reg, value)       macscsi_write(instance, reg, value)
 
 #define NCR5380_pread                   macscsi_pread
 #define NCR5380_pwrite                  macscsi_pwrite
+#define NCR5380_dma_xfer_len(instance, cmd, phase)     (cmd->transfersize)
 
 #define NCR5380_intr                    macscsi_intr
 #define NCR5380_queue_command           macscsi_queue_command
@@ -51,8 +49,6 @@
 
 #include "NCR5380.h"
 
-#define RESET_BOOT
-
 static int setup_can_queue = -1;
 module_param(setup_can_queue, int, 0);
 static int setup_cmd_per_lun = -1;
@@ -65,17 +61,8 @@ static int setup_use_tagged_queuing = -1;
 module_param(setup_use_tagged_queuing, int, 0);
 static int setup_hostid = -1;
 module_param(setup_hostid, int, 0);
-
-/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
- * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
- * need ten times the standard value... */
-#define TOSHIBA_DELAY
-
-#ifdef TOSHIBA_DELAY
-#define        AFTER_RESET_DELAY       (5*HZ/2)
-#else
-#define        AFTER_RESET_DELAY       (HZ/2)
-#endif
+static int setup_toshiba_delay = -1;
+module_param(setup_toshiba_delay, int, 0);
 
 /*
  * NCR 5380 register access functions
@@ -94,12 +81,12 @@ static inline void macscsi_write(struct Scsi_Host *instance, int reg, int value)
 #ifndef MODULE
 static int __init mac_scsi_setup(char *str)
 {
-       int ints[7];
+       int ints[8];
 
        (void)get_options(str, ARRAY_SIZE(ints), ints);
 
-       if (ints[0] < 1 || ints[0] > 6) {
-               pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>]]]]]\n");
+       if (ints[0] < 1) {
+               pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");
                return 0;
        }
        if (ints[0] >= 1)
@@ -114,50 +101,14 @@ static int __init mac_scsi_setup(char *str)
                setup_use_tagged_queuing = ints[5];
        if (ints[0] >= 6)
                setup_use_pdma = ints[6];
+       if (ints[0] >= 7)
+               setup_toshiba_delay = ints[7];
        return 1;
 }
 
 __setup("mac5380=", mac_scsi_setup);
 #endif /* !MODULE */
 
-#ifdef RESET_BOOT
-/*
- * Our 'bus reset on boot' function
- */
-
-static void mac_scsi_reset_boot(struct Scsi_Host *instance)
-{
-       unsigned long end;
-
-       NCR5380_local_declare();
-       NCR5380_setup(instance);
-       
-       /*
-        * Do a SCSI reset to clean up the bus during initialization. No messing
-        * with the queues, interrupts, or locks necessary here.
-        */
-
-       printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
-
-       /* get in phase */
-       NCR5380_write( TARGET_COMMAND_REG,
-                     PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
-
-       /* assert RST */
-       NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
-       /* The min. reset hold time is 25us, so 40us should be enough */
-       udelay( 50 );
-       /* reset RST and interrupt */
-       NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
-       NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
-       for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
-               barrier();
-
-       printk(KERN_INFO " done\n" );
-}
-#endif
-
 #ifdef PSEUDO_DMA
 /* 
    Pseudo-DMA: (Ove Edlund)
@@ -235,9 +186,6 @@ static int macscsi_pread(struct Scsi_Host *instance,
        unsigned char *d;
        unsigned char *s;
 
-       NCR5380_local_declare();
-       NCR5380_setup(instance);
-
        s = hostdata->pdma_base + (INPUT_DATA_REG << 4);
        d = dst;
 
@@ -329,9 +277,6 @@ static int macscsi_pwrite(struct Scsi_Host *instance,
        unsigned char *s;
        unsigned char *d;
 
-       NCR5380_local_declare();
-       NCR5380_setup(instance);
-
        s = src;
        d = hostdata->pdma_base + (OUTPUT_DATA_REG << 4);
 
@@ -364,20 +309,22 @@ static int macscsi_pwrite(struct Scsi_Host *instance,
 #define PFX                     DRV_MODULE_NAME ": "
 
 static struct scsi_host_template mac_scsi_template = {
-       .module                         = THIS_MODULE,
-       .proc_name                      = DRV_MODULE_NAME,
-       .show_info                      = macscsi_show_info,
-       .write_info                     = macscsi_write_info,
-       .name                           = "Macintosh NCR5380 SCSI",
-       .info                           = macscsi_info,
-       .queuecommand                   = macscsi_queue_command,
-       .eh_abort_handler               = macscsi_abort,
-       .eh_bus_reset_handler           = macscsi_bus_reset,
-       .can_queue                      = 16,
-       .this_id                        = 7,
-       .sg_tablesize                   = SG_ALL,
-       .cmd_per_lun                    = 2,
-       .use_clustering                 = DISABLE_CLUSTERING
+       .module                 = THIS_MODULE,
+       .proc_name              = DRV_MODULE_NAME,
+       .show_info              = macscsi_show_info,
+       .write_info             = macscsi_write_info,
+       .name                   = "Macintosh NCR5380 SCSI",
+       .info                   = macscsi_info,
+       .queuecommand           = macscsi_queue_command,
+       .eh_abort_handler       = macscsi_abort,
+       .eh_bus_reset_handler   = macscsi_bus_reset,
+       .can_queue              = 16,
+       .this_id                = 7,
+       .sg_tablesize           = SG_ALL,
+       .cmd_per_lun            = 2,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .cmd_size               = NCR5380_CMD_SIZE,
+       .max_sectors            = 128,
 };
 
 static int __init mac_scsi_probe(struct platform_device *pdev)
@@ -432,15 +379,14 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
        } else
                host_flags |= FLAG_NO_PSEUDO_DMA;
 
-#ifdef RESET_BOOT
-       mac_scsi_reset_boot(instance);
-#endif
-
 #ifdef SUPPORT_TAGS
        host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
 #endif
+       host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
 
-       NCR5380_init(instance, host_flags);
+       error = NCR5380_init(instance, host_flags);
+       if (error)
+               goto fail_init;
 
        if (instance->irq != NO_IRQ) {
                error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
@@ -449,6 +395,8 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
                        goto fail_irq;
        }
 
+       NCR5380_maybe_reset_bus(instance);
+
        error = scsi_add_host(instance, NULL);
        if (error)
                goto fail_host;
@@ -463,6 +411,7 @@ fail_host:
                free_irq(instance->irq, instance);
 fail_irq:
        NCR5380_exit(instance);
+fail_init:
        scsi_host_put(instance);
        return error;
 }
index a706927..4cf9ed9 100644 (file)
@@ -179,8 +179,12 @@ mraid_mm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 
        /*
         * The following call will block till a kioc is available
+        * or return NULL if the list head is empty for the pointer
+        * of type mraid_mmapt passed to mraid_mm_alloc_kioc
         */
        kioc = mraid_mm_alloc_kioc(adp);
+       if (!kioc)
+               return -ENXIO;
 
        /*
         * User sent the old mimd_t ioctl packet. Convert it to uioc_t.
index e81eadd..512037e 100644 (file)
@@ -1,6 +1,4 @@
 #define PSEUDO_DMA
-#define UNSAFE  /* Not unsafe for PAS16 -- use it */
-#define PDEBUG 0
 
 /*
  * This driver adapted from Drew Eckhardt's Trantor T128 driver
  
 #include <linux/module.h>
 
-#include <linux/signal.h>
-#include <linux/proc_fs.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/blkdev.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/stat.h>
 #include <linux/init.h>
 
 #include <scsi/scsi_host.h>
@@ -87,8 +81,8 @@
 #include "NCR5380.h"
 
 
-static unsigned short pas16_addr = 0;
-static int pas16_irq = 0;
+static unsigned short pas16_addr;
+static int pas16_irq;
  
 
 static const int scsi_irq_translate[] =
@@ -146,22 +140,6 @@ static const unsigned short  pas16_offset[ 8 ] =
                    * START_DMA_INITIATOR_RECEIVE_REG wo
                    */
     };
-/*----------------------------------------------------------------*/
-/* the following will set the monitor border color (useful to find
- where something crashed or gets stuck at */
-/* 1 = blue
- 2 = green
- 3 = cyan
- 4 = red
- 5 = magenta
- 6 = yellow
- 7 = white
-*/
-#if 1
-#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
-#else
-#define rtrc(i) {}
-#endif
 
 
 /*
@@ -205,7 +183,7 @@ static void __init
        outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET );   /* Reset TC */
        outb( 0x01, io_port + WAIT_STATE );   /* 1 Wait state */
 
-       NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+       inb(io_port + pas16_offset[RESET_PARITY_INTERRUPT_REG]);
 
        /* Set the SCSI interrupt pointer without mucking up the sound
         * interrupt pointer in the same byte.
@@ -280,13 +258,13 @@ static int __init
      * put in an additional test to try to weed them out.
      */
 
-    outb( 0x01, io_port + WAIT_STATE );        /* 1 Wait state */
-    NCR5380_write( MODE_REG, 0x20 );           /* Is it really SCSI? */
-    if( NCR5380_read( MODE_REG ) != 0x20 )     /* Write to a reg.    */
-       return 0;                               /* and try to read    */
-    NCR5380_write( MODE_REG, 0x00 );           /* it back.           */
-    if( NCR5380_read( MODE_REG ) != 0x00 )
-       return 0;
+       outb(0x01, io_port + WAIT_STATE);             /* 1 Wait state */
+       outb(0x20, io_port + pas16_offset[MODE_REG]); /* Is it really SCSI? */
+       if (inb(io_port + pas16_offset[MODE_REG]) != 0x20) /* Write to a reg. */
+               return 0;                                  /* and try to read */
+       outb(0x00, io_port + pas16_offset[MODE_REG]);      /* it back. */
+       if (inb(io_port + pas16_offset[MODE_REG]) != 0x00)
+               return 0;
 
     return 1;
 }
@@ -305,7 +283,7 @@ static int __init
 
 static int __init pas16_setup(char *str)
 {
-    static int commandline_current = 0;
+       static int commandline_current;
     int i;
     int ints[10];
 
@@ -344,8 +322,8 @@ __setup("pas16=", pas16_setup);
 
 static int __init pas16_detect(struct scsi_host_template *tpnt)
 {
-    static int current_override = 0;
-    static unsigned short current_base = 0;
+       static int current_override;
+       static unsigned short current_base;
     struct Scsi_Host *instance;
     unsigned short io_port;
     int  count;
@@ -377,34 +355,32 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
        }
        else
            for (; !io_port && (current_base < NO_BASES); ++current_base) {
-#if (PDEBUG & PDEBUG_INIT)
-    printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port);
-#endif
+               dprintk(NDEBUG_INIT, "pas16: probing io_port 0x%04x\n",
+                       (unsigned int)bases[current_base].io_port);
                if ( !bases[current_base].noauto &&
                     pas16_hw_detect( current_base ) ){
                        io_port = bases[current_base].io_port;
                        init_board( io_port, default_irqs[ current_base ], 0 ); 
-#if (PDEBUG & PDEBUG_INIT)
-                       printk("scsi-pas16 : detected board.\n");
-#endif
+                       dprintk(NDEBUG_INIT, "pas16: detected board\n");
                }
     }
 
-
-#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
-       printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port);
-#endif
+       dprintk(NDEBUG_INIT, "pas16: io_port = 0x%04x\n",
+               (unsigned int)io_port);
 
        if (!io_port)
            break;
 
        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
        if(instance == NULL)
-               break;
+               goto out;
                
        instance->io_port = io_port;
 
-       NCR5380_init(instance, 0);
+       if (NCR5380_init(instance, 0))
+               goto out_unregister;
+
+       NCR5380_maybe_reset_bus(instance);
 
        if (overrides[current_override].irq != IRQ_AUTO)
            instance->irq = overrides[current_override].irq;
@@ -431,14 +407,18 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
            outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
        }
 
-#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
-       printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+       dprintk(NDEBUG_INIT, "scsi%d : irq = %d\n",
+               instance->host_no, instance->irq);
 
        ++current_override;
        ++count;
     }
     return count;
+
+out_unregister:
+       scsi_unregister(instance);
+out:
+       return count;
 }
 
 /*
@@ -561,29 +541,29 @@ static int pas16_release(struct Scsi_Host *shost)
        if (shost->irq != NO_IRQ)
                free_irq(shost->irq, shost);
        NCR5380_exit(shost);
-       if (shost->io_port && shost->n_io_port)
-               release_region(shost->io_port, shost->n_io_port);
        scsi_unregister(shost);
        return 0;
 }
 
 static struct scsi_host_template driver_template = {
-       .name           = "Pro Audio Spectrum-16 SCSI",
-       .detect         = pas16_detect,
-       .release        = pas16_release,
-       .proc_name      = "pas16",
-       .show_info      = pas16_show_info,
-       .write_info     = pas16_write_info,
-       .info           = pas16_info,
-       .queuecommand   = pas16_queue_command,
-       .eh_abort_handler = pas16_abort,
-       .eh_bus_reset_handler = pas16_bus_reset,
-       .bios_param     = pas16_biosparam, 
-       .can_queue      = CAN_QUEUE,
-       .this_id        = 7,
-       .sg_tablesize   = SG_ALL,
-       .cmd_per_lun    = CMD_PER_LUN,
-       .use_clustering = DISABLE_CLUSTERING,
+       .name                   = "Pro Audio Spectrum-16 SCSI",
+       .detect                 = pas16_detect,
+       .release                = pas16_release,
+       .proc_name              = "pas16",
+       .show_info              = pas16_show_info,
+       .write_info             = pas16_write_info,
+       .info                   = pas16_info,
+       .queuecommand           = pas16_queue_command,
+       .eh_abort_handler       = pas16_abort,
+       .eh_bus_reset_handler   = pas16_bus_reset,
+       .bios_param             = pas16_biosparam,
+       .can_queue              = 32,
+       .this_id                = 7,
+       .sg_tablesize           = SG_ALL,
+       .cmd_per_lun            = 2,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .cmd_size               = NCR5380_CMD_SIZE,
+       .max_sectors            = 128,
 };
 #include "scsi_module.c"
 
index c6109c8..d375277 100644 (file)
@@ -24,9 +24,6 @@
 #ifndef PAS16_H
 #define PAS16_H
 
-#define PDEBUG_INIT    0x1
-#define PDEBUG_TRANSFER 0x2
-
 #define PAS16_DEFAULT_BASE_1  0x388
 #define PAS16_DEFAULT_BASE_2  0x384
 #define PAS16_DEFAULT_BASE_3  0x38c
 #define OPERATION_MODE_1 0xec03
 #define IO_CONFIG_3 0xf002
 
+#define NCR5380_implementation_fields /* none */
 
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 32 
-#endif
-
-#define NCR5380_implementation_fields \
-    volatile unsigned short io_port
-
-#define NCR5380_local_declare() \
-    volatile unsigned short io_port
+#define PAS16_io_port(reg) (instance->io_port + pas16_offset[(reg)])
 
-#define NCR5380_setup(instance) \
-    io_port = (instance)->io_port
-
-#define PAS16_io_port(reg) ( io_port + pas16_offset[(reg)] )
-
-#if !(PDEBUG & PDEBUG_TRANSFER) 
 #define NCR5380_read(reg) ( inb(PAS16_io_port(reg)) )
 #define NCR5380_write(reg, value) ( outb((value),PAS16_io_port(reg)) )
-#else
-#define NCR5380_read(reg)                                              \
-    (((unsigned char) printk("scsi%d : read register %d at io_port %04x\n"\
-    , instance->hostno, (reg), PAS16_io_port(reg))), inb( PAS16_io_port(reg)) )
-
-#define NCR5380_write(reg, value)                                      \
-    (printk("scsi%d : write %02x to register %d at io_port %04x\n",    \
-           instance->hostno, (value), (reg), PAS16_io_port(reg)),      \
-    outb( (value),PAS16_io_port(reg) ) )
-
-#endif
 
+#define NCR5380_dma_xfer_len(instance, cmd, phase)     (cmd->transfersize)
 
 #define NCR5380_intr pas16_intr
-#define do_NCR5380_intr do_pas16_intr
 #define NCR5380_queue_command pas16_queue_command
 #define NCR5380_abort pas16_abort
 #define NCR5380_bus_reset pas16_bus_reset
    
 #define PAS16_IRQS 0xd4a8 
 
-#endif /* ndef ASM */
 #endif /* PAS16_H */
index 2c1160c..47b9d13 100644 (file)
@@ -227,6 +227,7 @@ static struct {
        {"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC},
        {"Promise", "", NULL, BLIST_SPARSELUN},
        {"QNAP", "iSCSI Storage", NULL, BLIST_MAX_1024},
+       {"SYNOLOGY", "iSCSI Storage", NULL, BLIST_MAX_1024},
        {"QUANTUM", "XP34301", "1071", BLIST_NOTQ},
        {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
        {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
index 41c115c..55627d0 100644 (file)
@@ -390,7 +390,7 @@ module_param(storvsc_ringbuffer_size, int, S_IRUGO);
 MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
 
 module_param(storvsc_vcpus_per_sub_channel, int, S_IRUGO);
-MODULE_PARM_DESC(vcpus_per_sub_channel, "Ratio of VCPUs to subchannels");
+MODULE_PARM_DESC(storvsc_vcpus_per_sub_channel, "Ratio of VCPUs to subchannels");
 /*
  * Timeout in seconds for all devices managed by this driver.
  */
index 22a4283..b9de487 100644 (file)
 #define NCR5380_queue_command           sun3scsi_queue_command
 #define NCR5380_bus_reset               sun3scsi_bus_reset
 #define NCR5380_abort                   sun3scsi_abort
-#define NCR5380_show_info               sun3scsi_show_info
 #define NCR5380_info                    sun3scsi_info
 
 #define NCR5380_dma_read_setup(instance, data, count) \
-        sun3scsi_dma_setup(data, count, 0)
+        sun3scsi_dma_setup(instance, data, count, 0)
 #define NCR5380_dma_write_setup(instance, data, count) \
-        sun3scsi_dma_setup(data, count, 1)
+        sun3scsi_dma_setup(instance, data, count, 1)
 #define NCR5380_dma_residual(instance) \
         sun3scsi_dma_residual(instance)
 #define NCR5380_dma_xfer_len(instance, cmd, phase) \
@@ -86,10 +85,6 @@ module_param(setup_use_tagged_queuing, int, 0);
 static int setup_hostid = -1;
 module_param(setup_hostid, int, 0);
 
-/* #define RESET_BOOT */
-
-#define        AFTER_RESET_DELAY       (HZ/2)
-
 /* ms to wait after hitting dma regs */
 #define SUN3_DMA_DELAY 10
 
@@ -100,11 +95,10 @@ static struct scsi_cmnd *sun3_dma_setup_done;
 static unsigned char *sun3_scsi_regp;
 static volatile struct sun3_dma_regs *dregs;
 static struct sun3_udc_regs *udc_regs;
-static unsigned char *sun3_dma_orig_addr = NULL;
-static unsigned long sun3_dma_orig_count = 0;
-static int sun3_dma_active = 0;
-static unsigned long last_residual = 0;
-static struct Scsi_Host *default_instance;
+static unsigned char *sun3_dma_orig_addr;
+static unsigned long sun3_dma_orig_count;
+static int sun3_dma_active;
+static unsigned long last_residual;
 
 /*
  * NCR 5380 register access functions
@@ -144,50 +138,12 @@ static inline void sun3_udc_write(unsigned short val, unsigned char reg)
 }
 #endif
 
-#ifdef RESET_BOOT
-static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
-{
-       unsigned long end;
-       
-       /*
-        * Do a SCSI reset to clean up the bus during initialization. No
-        * messing with the queues, interrupts, or locks necessary here.
-        */
-
-       printk( "Sun3 SCSI: resetting the SCSI bus..." );
-
-       /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
-//             sun3_disable_irq( IRQ_SUN3_SCSI );
-
-       /* get in phase */
-       NCR5380_write( TARGET_COMMAND_REG,
-                     PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
-
-       /* assert RST */
-       NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
-
-       /* The min. reset hold time is 25us, so 40us should be enough */
-       udelay( 50 );
-
-       /* reset RST and interrupt */
-       NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
-       NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
-       for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
-               barrier();
-
-       /* switch on SCSI IRQ again */
-//             sun3_enable_irq( IRQ_SUN3_SCSI );
-
-       printk( " done\n" );
-}
-#endif
-
 // safe bits for the CSR
 #define CSR_GOOD 0x060f
 
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
+static irqreturn_t scsi_sun3_intr(int irq, void *dev)
 {
+       struct Scsi_Host *instance = dev;
        unsigned short csr = dregs->csr;
        int handled = 0;
 
@@ -196,46 +152,24 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
 #endif
 
        if(csr & ~CSR_GOOD) {
-               if(csr & CSR_DMA_BUSERR) {
-                       printk("scsi%d: bus error in dma\n", default_instance->host_no);
-               }
-
-               if(csr & CSR_DMA_CONFLICT) {
-                       printk("scsi%d: dma conflict\n", default_instance->host_no);
-               }
+               if (csr & CSR_DMA_BUSERR)
+                       shost_printk(KERN_ERR, instance, "bus error in DMA\n");
+               if (csr & CSR_DMA_CONFLICT)
+                       shost_printk(KERN_ERR, instance, "DMA conflict\n");
                handled = 1;
        }
 
        if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
-               NCR5380_intr(irq, dummy);
+               NCR5380_intr(irq, dev);
                handled = 1;
        }
 
        return IRQ_RETVAL(handled);
 }
 
-/*
- * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; 
- * reentering NCR5380_print_status seems to have ugly side effects
- */
-
-/* this doesn't seem to get used at all -- sam */
-#if 0
-void sun3_sun3_debug (void)
-{
-       unsigned long flags;
-
-       if (default_instance) {
-                       local_irq_save(flags);
-                       NCR5380_print_status(default_instance);
-                       local_irq_restore(flags);
-       }
-}
-#endif
-
-
 /* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
-static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
+static unsigned long sun3scsi_dma_setup(struct Scsi_Host *instance,
+                                void *data, unsigned long count, int write_flag)
 {
        void *addr;
 
@@ -287,10 +221,9 @@ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int wri
        dregs->csr |= CSR_FIFO;
        
        if(dregs->fifo_count != count) { 
-               printk("scsi%d: fifo_mismatch %04x not %04x\n",
-                      default_instance->host_no, dregs->fifo_count,
-                      (unsigned int) count);
-               NCR5380_dprint(NDEBUG_DMA, default_instance);
+               shost_printk(KERN_ERR, instance, "FIFO mismatch %04x not %04x\n",
+                            dregs->fifo_count, (unsigned int) count);
+               NCR5380_dprint(NDEBUG_DMA, instance);
        }
 
        /* setup udc */
@@ -325,21 +258,6 @@ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int wri
 
 }
 
-#ifndef SUN3_SCSI_VME
-static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance)
-{
-       unsigned short resid;
-
-       dregs->udc_addr = 0x32; 
-       udelay(SUN3_DMA_DELAY);
-       resid = dregs->udc_data;
-       udelay(SUN3_DMA_DELAY);
-       resid *= 2;
-
-       return (unsigned long) resid;
-}
-#endif
-
 static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
 {
        return last_residual;
@@ -437,7 +355,10 @@ static int sun3scsi_dma_finish(int write_flag)
                }
        }
 
-       count = sun3scsi_dma_count(default_instance);
+       dregs->udc_addr = 0x32;
+       udelay(SUN3_DMA_DELAY);
+       count = 2 * dregs->udc_data;
+       udelay(SUN3_DMA_DELAY);
 
        fifo = dregs->fifo_count;
        last_residual = fifo;
@@ -502,17 +423,17 @@ static int sun3scsi_dma_finish(int write_flag)
 static struct scsi_host_template sun3_scsi_template = {
        .module                 = THIS_MODULE,
        .proc_name              = DRV_MODULE_NAME,
-       .show_info              = sun3scsi_show_info,
        .name                   = SUN3_SCSI_NAME,
        .info                   = sun3scsi_info,
        .queuecommand           = sun3scsi_queue_command,
-       .eh_abort_handler       = sun3scsi_abort,
-       .eh_bus_reset_handler   = sun3scsi_bus_reset,
+       .eh_abort_handler       = sun3scsi_abort,
+       .eh_bus_reset_handler   = sun3scsi_bus_reset,
        .can_queue              = 16,
        .this_id                = 7,
        .sg_tablesize           = SG_NONE,
        .cmd_per_lun            = 2,
-       .use_clustering         = DISABLE_CLUSTERING
+       .use_clustering         = DISABLE_CLUSTERING,
+       .cmd_size               = NCR5380_CMD_SIZE,
 };
 
 static int __init sun3_scsi_probe(struct platform_device *pdev)
@@ -591,7 +512,6 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
                error = -ENOMEM;
                goto fail_alloc;
        }
-       default_instance = instance;
 
        instance->io_port = (unsigned long)ioaddr;
        instance->irq = irq->start;
@@ -600,7 +520,9 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
        host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
 #endif
 
-       NCR5380_init(instance, host_flags);
+       error = NCR5380_init(instance, host_flags);
+       if (error)
+               goto fail_init;
 
        error = request_irq(instance->irq, scsi_sun3_intr, 0,
                            "NCR5380", instance);
@@ -631,9 +553,7 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
        dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
 #endif
 
-#ifdef RESET_BOOT
-       sun3_scsi_reset_boot(instance);
-#endif
+       NCR5380_maybe_reset_bus(instance);
 
        error = scsi_add_host(instance, NULL);
        if (error)
@@ -649,6 +569,7 @@ fail_host:
                free_irq(instance->irq, instance);
 fail_irq:
        NCR5380_exit(instance);
+fail_init:
        scsi_host_put(instance);
 fail_alloc:
        if (udc_regs)
index 87828ac..4615fda 100644 (file)
  * 15 9-11
  */
  
-#include <linux/signal.h>
 #include <linux/io.h>
 #include <linux/blkdev.h>
 #include <linux/interrupt.h>
-#include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/delay.h>
 
 #include <scsi/scsi_host.h>
 #include "t128.h"
@@ -126,7 +123,7 @@ static struct signature {
 
 static int __init t128_setup(char *str)
 {
-    static int commandline_current = 0;
+       static int commandline_current;
     int i;
     int ints[10];
 
@@ -165,7 +162,7 @@ __setup("t128=", t128_setup);
 
 static int __init t128_detect(struct scsi_host_template *tpnt)
 {
-    static int current_override = 0, current_base = 0;
+       static int current_override, current_base;
     struct Scsi_Host *instance;
     unsigned long base;
     void __iomem *p;
@@ -182,9 +179,8 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
                base = 0;
        } else 
            for (; !base && (current_base < NO_BASES); ++current_base) {
-#if (TDEBUG & TDEBUG_INIT)
-    printk("scsi-t128 : probing address %08x\n", bases[current_base].address);
-#endif
+               dprintk(NDEBUG_INIT, "t128: probing address 0x%08x\n",
+                       bases[current_base].address);
                if (bases[current_base].noauto)
                        continue;
                p = ioremap(bases[current_base].address, 0x2000);
@@ -195,17 +191,13 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
                                        signatures[sig].string,
                                        strlen(signatures[sig].string))) {
                        base = bases[current_base].address;
-#if (TDEBUG & TDEBUG_INIT)
-                       printk("scsi-t128 : detected board.\n");
-#endif
+                       dprintk(NDEBUG_INIT, "t128: detected board\n");
                        goto found;
                    }
                iounmap(p);
            }
 
-#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
-       printk("scsi-t128 : base = %08x\n", (unsigned int) base);
-#endif
+       dprintk(NDEBUG_INIT, "t128: base = 0x%08x\n", (unsigned int)base);
 
        if (!base)
            break;
@@ -213,12 +205,15 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
 found:
        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
        if(instance == NULL)
-               break;
-               
+               goto out_unmap;
+
        instance->base = base;
        ((struct NCR5380_hostdata *)instance->hostdata)->base = p;
 
-       NCR5380_init(instance, 0);
+       if (NCR5380_init(instance, 0))
+               goto out_unregister;
+
+       NCR5380_maybe_reset_bus(instance);
 
        if (overrides[current_override].irq != IRQ_AUTO)
            instance->irq = overrides[current_override].irq;
@@ -242,27 +237,30 @@ found:
            printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
        }
 
-#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
-       printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+       dprintk(NDEBUG_INIT, "scsi%d: irq = %d\n",
+               instance->host_no, instance->irq);
 
        ++current_override;
        ++count;
     }
     return count;
+
+out_unregister:
+       scsi_unregister(instance);
+out_unmap:
+       iounmap(p);
+       return count;
 }
 
 static int t128_release(struct Scsi_Host *shost)
 {
-       NCR5380_local_declare();
-       NCR5380_setup(shost);
+       struct NCR5380_hostdata *hostdata = shost_priv(shost);
+
        if (shost->irq != NO_IRQ)
                free_irq(shost->irq, shost);
        NCR5380_exit(shost);
-       if (shost->io_port && shost->n_io_port)
-               release_region(shost->io_port, shost->n_io_port);
        scsi_unregister(shost);
-       iounmap(base);
+       iounmap(hostdata->base);
        return 0;
 }
 
@@ -308,14 +306,14 @@ static int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev,
  *     timeout.
  */
 
-static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
-    int len) {
-    NCR5380_local_declare();
-    void __iomem *reg;
+static inline int
+NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       void __iomem *reg, *base = hostdata->base;
     unsigned char *d = dst;
     register int i = len;
 
-    NCR5380_setup(instance);
     reg = base + T_DATA_REG_OFFSET;
 
 #if 0
@@ -354,14 +352,14 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
  *     timeout.
  */
 
-static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
-    int len) {
-    NCR5380_local_declare();
-    void __iomem *reg;
+static inline int
+NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
+{
+       struct NCR5380_hostdata *hostdata = shost_priv(instance);
+       void __iomem *reg, *base = hostdata->base;
     unsigned char *s = src;
     register int i = len;
 
-    NCR5380_setup(instance);
     reg = base + T_DATA_REG_OFFSET;
 
 #if 0
@@ -392,21 +390,23 @@ MODULE_LICENSE("GPL");
 #include "NCR5380.c"
 
 static struct scsi_host_template driver_template = {
-       .name           = "Trantor T128/T128F/T228",
-       .detect         = t128_detect,
-       .release        = t128_release,
-       .proc_name      = "t128",
-       .show_info      = t128_show_info,
-       .write_info     = t128_write_info,
-       .info           = t128_info,
-       .queuecommand   = t128_queue_command,
-       .eh_abort_handler = t128_abort,
-       .eh_bus_reset_handler    = t128_bus_reset,
-       .bios_param     = t128_biosparam,
-       .can_queue      = CAN_QUEUE,
-        .this_id        = 7,
-       .sg_tablesize   = SG_ALL,
-       .cmd_per_lun    = CMD_PER_LUN,
-       .use_clustering = DISABLE_CLUSTERING,
+       .name                   = "Trantor T128/T128F/T228",
+       .detect                 = t128_detect,
+       .release                = t128_release,
+       .proc_name              = "t128",
+       .show_info              = t128_show_info,
+       .write_info             = t128_write_info,
+       .info                   = t128_info,
+       .queuecommand           = t128_queue_command,
+       .eh_abort_handler       = t128_abort,
+       .eh_bus_reset_handler   = t128_bus_reset,
+       .bios_param             = t128_biosparam,
+       .can_queue              = 32,
+       .this_id                = 7,
+       .sg_tablesize           = SG_ALL,
+       .cmd_per_lun            = 2,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .cmd_size               = NCR5380_CMD_SIZE,
+       .max_sectors            = 128,
 };
 #include "scsi_module.c"
index 2c73714..dd16d85 100644 (file)
 #ifndef T128_H
 #define T128_H
 
-#define TDEBUG         0
-#define TDEBUG_INIT    0x1
-#define TDEBUG_TRANSFER 0x2
-
 /*
  * The trantor boards are memory mapped. They use an NCR5380 or
  * equivalent (my sample board had part second sourced from ZILOG).
 
 #define T_DATA_REG_OFFSET      0x1e00  /* rw 512 bytes long */
 
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 32
-#endif
-
 #define NCR5380_implementation_fields \
     void __iomem *base
 
-#define NCR5380_local_declare() \
-    void __iomem *base
-
-#define NCR5380_setup(instance) \
-    base = ((struct NCR5380_hostdata *)(instance->hostdata))->base
+#define T128_address(reg) \
+       (((struct NCR5380_hostdata *)shost_priv(instance))->base + T_5380_OFFSET + ((reg) * 0x20))
 
-#define T128_address(reg) (base + T_5380_OFFSET + ((reg) * 0x20))
-
-#if !(TDEBUG & TDEBUG_TRANSFER)
 #define NCR5380_read(reg) readb(T128_address(reg))
 #define NCR5380_write(reg, value) writeb((value),(T128_address(reg)))
-#else
-#define NCR5380_read(reg)                                              \
-    (((unsigned char) printk("scsi%d : read register %d at address %08x\n"\
-    , instance->hostno, (reg), T128_address(reg))), readb(T128_address(reg)))
-
-#define NCR5380_write(reg, value) {                                    \
-    printk("scsi%d : write %02x to register %d at address %08x\n",     \
-           instance->hostno, (value), (reg), T128_address(reg));       \
-    writeb((value), (T128_address(reg)));                              \
-}
-#endif
+
+#define NCR5380_dma_xfer_len(instance, cmd, phase)     (cmd->transfersize)
 
 #define NCR5380_intr t128_intr
-#define do_NCR5380_intr do_t128_intr
 #define NCR5380_queue_command t128_queue_command
 #define NCR5380_abort t128_abort
 #define NCR5380_bus_reset t128_bus_reset
 
 #define T128_IRQS 0xc4a8
 
-#endif /* ndef ASM */
 #endif /* T128_H */