Index: linux/Documentation/Configure.help
diff -c linux/Documentation/Configure.help:1.1.1.3 linux/Documentation/Configure.help:1.4
*** linux/Documentation/Configure.help:1.1.1.3	Wed May 28 07:57:28 1997
--- linux/Documentation/Configure.help	Wed May 28 08:37:09 1997
***************
*** 1576,1581 ****
--- 1576,1595 ----
    understand if you say Y here; it will enlarge your kernel by about
    12KB. If in doubt, say Y.
  
+ SCSI logging facility
+ CONFIG_SCSI_LOGGING
+   This turns on a logging facility that can be used to debug a number
+   of problems.  Normally no logging output will appear, but you can
+   enable logging with a shell command like: 
+   'echo "scsi log token [level]" > /proc/scsi/scsi'
+   There are a number of things that can be used for 'token', and this
+   allows you to select the types of information you want, and the level
+   allows you to select the level of verbosity.  If you say 'N' here,
+   it may be harder to track down some types of scsi problems.  If
+   you say 'Y' here your kernel will be somewhat larger, but there
+   should be no noticable performance impact as long as you have logging
+   turned off.
+ 
  AdvanSys SCSI support
  CONFIG_SCSI_ADVANSYS
    This is a driver for all SCSI host adapters manufactured by
***************
*** 2127,2132 ****
--- 2141,2155 ----
  CONFIG_SCSI_PPA_EPP_TIME
    This is the "reset time period", a delay time.  Too low a value may
    cause all sorts of mid-level SCSI problems.
+ 
+ SCSI Debug host simulator.
+ CONFIG_SCSI_DEBUG
+   This is a host adapter simulator that can be programmed to simulate a
+   large number of conditions that could occur on a real bus.  The advantage
+   is that many hard to reproduce problems can be tested in a controlled
+   environment where there is reduced risk of losing important data.
+   This is primarily of use to people trying to debug the middle and upper
+   layers of the scsi subsystem.
  
  Network device support?
  CONFIG_NETDEVICES
Index: linux/drivers/scsi/53c7,8xx.h
diff -c linux/drivers/scsi/53c7,8xx.h:1.1.1.2 linux/drivers/scsi/53c7,8xx.h:1.3
*** linux/drivers/scsi/53c7,8xx.h:1.1.1.2	Sun May 18 19:35:31 1997
--- linux/drivers/scsi/53c7,8xx.h	Sun May 18 20:19:55 1997
***************
*** 66,131 ****
  #define NCR53c7xx_release NULL
  #endif
  
! #ifdef LINUX_1_2
! #define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
! 	NULL, /* info */ NULL, /* command, deprecated */ NULL, 		\
! 	NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset,	\
! 	NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
! 	/* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, 		\
! 	/* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
! #else
! #define NCR53c7xx {NULL, NULL, NULL, NULL, \
!         "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
!         NULL, /* info */ NULL, /* command, deprecated */ NULL,		\
! 	NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset,	\
! 	NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
! 	/* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, 		\
! 	/* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
! #endif
  
  #endif /* defined(HOSTS_C) || defined(MODULE) */ 
  
  #ifndef HOSTS_C
- #ifdef LINUX_1_2
- /*
-  * Change virtual addresses to physical addresses and vv.
-  * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
-  * make the kernel segment mapped at 0, we need to do translation
-  * on the i386 as well)
-  */
- extern inline unsigned long virt_to_phys(volatile void * address)
- {       
- 	return (unsigned long) address;
- }       
- 
- extern inline void * phys_to_virt(unsigned long address)
- {
- 	return (void *) address;      
- }
- 
- /*
-  * IO bus memory addresses are also 1:1 with the physical address
-  */
- #define virt_to_bus virt_to_phys
- #define bus_to_virt phys_to_virt
- 
- /*
-  * readX/writeX() are used to access memory mapped devices. On some
-  * architectures the memory mapped IO stuff needs to be accessed
-  * differently. On the x86 architecture, we just read/write the
-  * memory location directly.
-  */
- #define readb(addr) (*(volatile unsigned char *) (addr))
- #define readw(addr) (*(volatile unsigned short *) (addr))
- #define readl(addr) (*(volatile unsigned int *) (addr))
- 
- #define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
- #define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
- #define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
- 
- #define mb()
- 
- #endif /* def LINUX_1_2 */
  
  /* Register addresses, ordered numerically */
  
--- 66,87 ----
  #define NCR53c7xx_release NULL
  #endif
  
! #define NCR53c7xx {					\
!           name:           "NCR53c{7,8}xx (rel 17)",	\
! 	  detect:         NCR53c7xx_detect,		\
! 	  queuecommand:   NCR53c7xx_queue_command,	\
! 	  abort:          NCR53c7xx_abort,		\
! 	  reset:          NCR53c7xx_reset,		\
! 	  bios_param:     scsicam_bios_param,		\
! 	  can_queue:      24,				\
! 	  this_id:        7,				\
! 	  sg_tablesize:   127,				\
! 	  cmd_per_lun:    3,				\
! 	  use_clustering: DISABLE_CLUSTERING} 
  
  #endif /* defined(HOSTS_C) || defined(MODULE) */ 
  
  #ifndef HOSTS_C
  
  /* Register addresses, ordered numerically */
  
Index: linux/drivers/scsi/AM53C974.c
diff -c linux/drivers/scsi/AM53C974.c:1.1.1.1 linux/drivers/scsi/AM53C974.c:1.2
*** linux/drivers/scsi/AM53C974.c:1.1.1.1	Sun May 18 19:18:13 1997
--- linux/drivers/scsi/AM53C974.c	Sun May 18 19:27:01 1997
***************
*** 2543,2594 ****
  * Inputs : cmd -- which command within the command block was responsible for the reset
  * 
  * Returns : status (SCSI_ABORT_SUCCESS)
  **************************************************************************/
! int AM53C974_reset(Scsi_Cmnd *cmd)
  {
! AM53C974_local_declare();
! int                      i;
! struct Scsi_Host         *instance = cmd->host;
! struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata;
! AM53C974_setio(instance);
! 
! cli();
! DEB(printk("AM53C974_reset called; "));
! 
! printk("AM53C974_reset called\n");
! AM53C974_print(instance);
! AM53C974_keywait();
! 
  /* do hard reset */
! AM53C974_write_8(CMDREG, CMDREG_RDEV);
! AM53C974_write_8(CMDREG, CMDREG_NOP);
! hostdata->msgout[0] = NOP;
! for (i = 0; i < 8; i++) {
!     hostdata->busy[i] = 0;
!     hostdata->sync_per[i] = DEF_STP;
!     hostdata->sync_off[i] = 0;
!     hostdata->sync_neg[i] = 0; }
! hostdata->last_message[0] = NOP;
! hostdata->sel_cmd = NULL;
! hostdata->connected = NULL;
! hostdata->issue_queue = NULL;
! hostdata->disconnected_queue = NULL;
! hostdata->in_reset = 0;
! hostdata->aborted = 0;
! hostdata->selecting = 0;
! hostdata->disconnecting = 0;
! hostdata->dma_busy = 0;
! 
  /* reset bus */
! AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); /* disable interrupt upon SCSI RESET */
! AM53C974_write_8(CMDREG, CMDREG_RBUS);     /* reset SCSI bus */
! udelay(40);
! AM53C974_config_after_reset(instance);
! 
! sti();
! cmd->result = DID_RESET << 16;
! cmd->scsi_done(cmd);
! return SCSI_ABORT_SUCCESS;
  }
  
  
--- 2543,2596 ----
  * Inputs : cmd -- which command within the command block was responsible for the reset
  * 
  * Returns : status (SCSI_ABORT_SUCCESS)
+ * 
+ * FIXME(eric) the reset_flags are ignored.
  **************************************************************************/
! int AM53C974_reset(Scsi_Cmnd *cmd, unsigned int reset_flags)
  {
!     AM53C974_local_declare();
!     int                      i;
!     struct Scsi_Host         *instance = cmd->host;
!     struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata;
!     AM53C974_setio(instance);
!     
!     cli();
!     DEB(printk("AM53C974_reset called; "));
!     
!     printk("AM53C974_reset called\n");
!     AM53C974_print(instance);
!     AM53C974_keywait();
!     
  /* do hard reset */
!     AM53C974_write_8(CMDREG, CMDREG_RDEV);
!     AM53C974_write_8(CMDREG, CMDREG_NOP);
!     hostdata->msgout[0] = NOP;
!     for (i = 0; i < 8; i++) {
! 	hostdata->busy[i] = 0;
! 	hostdata->sync_per[i] = DEF_STP;
! 	hostdata->sync_off[i] = 0;
! 	hostdata->sync_neg[i] = 0; }
!     hostdata->last_message[0] = NOP;
!     hostdata->sel_cmd = NULL;
!     hostdata->connected = NULL;
!     hostdata->issue_queue = NULL;
!     hostdata->disconnected_queue = NULL;
!     hostdata->in_reset = 0;
!     hostdata->aborted = 0;
!     hostdata->selecting = 0;
!     hostdata->disconnecting = 0;
!     hostdata->dma_busy = 0;
!     
  /* reset bus */
!     AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); /* disable interrupt upon SCSI RESET */
!     AM53C974_write_8(CMDREG, CMDREG_RBUS);     /* reset SCSI bus */
!     udelay(40);
!     AM53C974_config_after_reset(instance);
!     
!     sti();
!     cmd->result = DID_RESET << 16;
!     cmd->scsi_done(cmd);
!     return SCSI_ABORT_SUCCESS;
  }
  
  
Index: linux/drivers/scsi/AM53C974.h
diff -c linux/drivers/scsi/AM53C974.h:1.1.1.1 linux/drivers/scsi/AM53C974.h:1.2
*** linux/drivers/scsi/AM53C974.h:1.1.1.1	Sun May 18 19:18:13 1997
--- linux/drivers/scsi/AM53C974.h	Sun May 18 19:27:01 1997
***************
*** 52,80 ****
  
  extern struct proc_dir_entry proc_scsi_am53c974;
  
! #define AM53C974 { \
!     NULL,              		/* pointer to next in list                      */  \
!     NULL,			/* struct module *module			*/  \
!     &proc_scsi_am53c974,        /* struct proc_dir_entry *proc_dir              */ \
!     NULL,                       /* int (*proc_info)(char *, char **, off_t, int, int, int); */ \
!     "AM53C974",        		/* name                                         */  \
!     AM53C974_detect,   		/* int (* detect)(struct SHT *)                 */  \
!     AM53C974_release,		/* int (*release)(struct Scsi_Host *)           */  \
!     AM53C974_info,     		/* const char *(* info)(struct Scsi_Host *)     */  \
!     AM53C974_command,  		/* int (* command)(Scsi_Cmnd *)                 */  \
!     AM53C974_queue_command,	/* int (* queuecommand)(Scsi_Cmnd *,                \
!                                            void (*done)(Scsi_Cmnd *))           */  \
!     AM53C974_abort,    		/* int (* abort)(Scsi_Cmnd *)                   */  \
!     AM53C974_reset,    		/* int (* reset)(Scsi_Cmnd *)                   */  \
!     NULL,                 	/* int (* slave_attach)(int, int)               */  \
!     scsicam_bios_param,		/* int (* bios_param)(Disk *, int, int[])       */  \
!     12,                 	/* can_queue                                    */  \
!     -1,                         /* this_id                                      */  \
!     SG_ALL,            		/* sg_tablesize                                 */  \
!     1,                 		/* cmd_per_lun                                  */  \
!     0,                 		/* present, i.e. how many adapters of this kind */  \
!     0,                 		/* unchecked_isa_dma                            */  \
!     DISABLE_CLUSTERING 		/* use_clustering                               */  \
      }
  
  void AM53C974_setup(char *str, int *ints);
--- 52,73 ----
  
  extern struct proc_dir_entry proc_scsi_am53c974;
  
! #define AM53C974 {				  \
!     proc_dir:       &proc_scsi_am53c974,          \
!     name:           "AM53C974",        		  \
!     detect:         AM53C974_detect,   		  \
!     release:        AM53C974_release,		  \
!     info:           AM53C974_info,     		  \
!     command:        AM53C974_command,  		  \
!     queuecommand:   AM53C974_queue_command,	  \
!     abort:          AM53C974_abort,    		  \
!     reset:          AM53C974_reset,    		  \
!     bios_param:     scsicam_bios_param,		  \
!     can_queue:      12,                 	  \
!     this_id:        -1,                           \
!     sg_tablesize:   SG_ALL,            		  \
!     cmd_per_lun:    1,                 		  \
!     use_clustering: DISABLE_CLUSTERING 		  \
      }
  
  void AM53C974_setup(char *str, int *ints);
***************
*** 85,91 ****
  int AM53C974_command(Scsi_Cmnd *SCpnt);
  int AM53C974_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
  int AM53C974_abort(Scsi_Cmnd *cmd);
! int AM53C974_reset (Scsi_Cmnd *cmd);
  
  #endif /* AM53C974_H */
  
--- 78,84 ----
  int AM53C974_command(Scsi_Cmnd *SCpnt);
  int AM53C974_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
  int AM53C974_abort(Scsi_Cmnd *cmd);
! int AM53C974_reset (Scsi_Cmnd *cmd, unsigned int);
  
  #endif /* AM53C974_H */
  
Index: linux/drivers/scsi/BusLogic.h
diff -c linux/drivers/scsi/BusLogic.h:1.1.1.1 linux/drivers/scsi/BusLogic.h:1.2
*** linux/drivers/scsi/BusLogic.h:1.1.1.1	Sun May 18 19:18:14 1997
--- linux/drivers/scsi/BusLogic.h	Sun May 18 19:27:02 1997
***************
*** 64,90 ****
  */
  
  #define BUSLOGIC							 \
!   { NULL,				/* Next			     */	 \
!     NULL,				/* Usage Count Pointer	     */	 \
!     &BusLogic_ProcDirectoryEntry,	/* /proc Directory Entry     */	 \
!     BusLogic_ProcDirectoryInfo,		/* /proc Info Function	     */	 \
!     "BusLogic",				/* Driver Name		     */	 \
!     BusLogic_DetectHostAdapter,		/* Detect Host Adapter	     */	 \
!     BusLogic_ReleaseHostAdapter,	/* Release Host Adapter	     */	 \
!     BusLogic_DriverInfo,		/* Driver Info Function	     */	 \
!     NULL,				/* Command Function	     */	 \
!     BusLogic_QueueCommand,		/* Queue Command Function    */	 \
!     BusLogic_AbortCommand,		/* Abort Command Function    */	 \
!     BusLogic_ResetCommand,		/* Reset Command Function    */	 \
!     NULL,				/* Slave Attach Function     */	 \
!     BusLogic_BIOSDiskParameters,	/* BIOS Disk Parameters	     */	 \
!     0,					/* Can Queue		     */	 \
!     0,					/* This ID		     */	 \
!     0,					/* Scatter/Gather Table Size */	 \
!     0,					/* SCSI Commands per LUN     */	 \
!     0,					/* Present		     */	 \
!     1,					/* Default Unchecked ISA DMA */	 \
!     ENABLE_CLUSTERING }			/* Enable Clustering	     */
  
  
  /*
--- 64,81 ----
  */
  
  #define BUSLOGIC							 \
!   { proc_dir:          &BusLogic_ProcDirectoryEntry,	/* /proc Directory Entry     */	 \
!     proc_info:         BusLogic_ProcDirectoryInfo,	/* /proc Info Function	     */	 \
!     name:              "BusLogic",			/* Driver Name		     */	 \
!     detect:            BusLogic_DetectHostAdapter,	/* Detect Host Adapter	     */	 \
!     release:           BusLogic_ReleaseHostAdapter,	/* Release Host Adapter	     */	 \
!     info:              BusLogic_DriverInfo,		/* Driver Info Function	     */	 \
!     queuecommand:      BusLogic_QueueCommand,		/* Queue Command Function    */	 \
!     abort:             BusLogic_AbortCommand,		/* Abort Command Function    */	 \
!     reset:             BusLogic_ResetCommand,		/* Reset Command Function    */	 \
!     bios_param:        BusLogic_BIOSDiskParameters,	/* BIOS Disk Parameters	     */	 \
!     unchecked_isa_dma: 1,				/* Default Unchecked ISA DMA */	 \
!     use_clustering:    ENABLE_CLUSTERING }		/* Enable Clustering	     */
  
  
  /*
Index: linux/drivers/scsi/Config.in
diff -c linux/drivers/scsi/Config.in:1.1.1.2 linux/drivers/scsi/Config.in:1.3
*** linux/drivers/scsi/Config.in:1.1.1.2	Sun May 18 19:35:34 1997
--- linux/drivers/scsi/Config.in	Sun May 18 20:19:56 1997
***************
*** 13,18 ****
--- 13,19 ----
  bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
  
  bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+ bool 'SCSI logging facility' CONFIG_SCSI_LOGGING
  
  mainmenu_option next_comment
  comment 'SCSI low-level drivers'
***************
*** 96,100 ****
      int  '  maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
    fi
  dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
! #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
  endmenu
--- 97,112 ----
      int  '  maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
    fi
  dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
! 
! #
! # Note - this is a very special 'host' adapter that simulates the presence of some disks.
! # It can come in very handy for troubleshooting.  Anyone else is welcome to use it - all
! # you do is hack it to simulate the condition you want to test for, and then use it.
! #
! # The actual configuration in any kernel release could change at any time as I hack it to
! # simulate various conditions that I am testing.
! #
! if [ "`whoami`" = "eric" ]; then
!   dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
! fi
  endmenu
Index: linux/drivers/scsi/Makefile
diff -c linux/drivers/scsi/Makefile:1.1.1.3 linux/drivers/scsi/Makefile:1.4
*** linux/drivers/scsi/Makefile:1.1.1.3	Wed May 28 07:54:05 1997
--- linux/drivers/scsi/Makefile	Wed May 28 08:37:27 1997
***************
*** 36,42 ****
    SCSI=scsi.o
    ifeq ($(CONFIG_MODULES),y)
      O_TARGET := scsi_n_syms.o
!     O_OBJS   := scsi.o
      OX_OBJS  := scsi_syms.o
      SCSI     := $(O_TARGET)
    endif
--- 36,42 ----
    SCSI=scsi.o
    ifeq ($(CONFIG_MODULES),y)
      O_TARGET := scsi_n_syms.o
!     O_OBJS   := scsi.o scsi_error.o scsi_obsolete.o
      OX_OBJS  := scsi_syms.o
      SCSI     := $(O_TARGET)
    endif
***************
*** 456,463 ****
  	$(CC) $(CFLAGS) -c ncr53c8xx.c
  
  scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
! 		scsicam.o scsi_proc.o
! 	$(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
  
  sr_mod.o: sr.o sr_ioctl.o $(SR_VENDOR)
  	$(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o $(SR_VENDOR)
--- 456,464 ----
  	$(CC) $(CFLAGS) -c ncr53c8xx.c
  
  scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
! 		scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o
! 	$(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o \
! 		constants.o scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o
  
  sr_mod.o: sr.o sr_ioctl.o $(SR_VENDOR)
  	$(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o $(SR_VENDOR)
Index: linux/drivers/scsi/NCR53c406a.h
diff -c linux/drivers/scsi/NCR53c406a.h:1.1.1.1 linux/drivers/scsi/NCR53c406a.h:1.2
*** linux/drivers/scsi/NCR53c406a.h:1.1.1.1	Sun May 18 19:18:13 1997
--- linux/drivers/scsi/NCR53c406a.h	Sun May 18 19:27:03 1997
***************
*** 26,52 ****
   * Use SG_NONE if DMA mode is enabled!
   */
  #define NCR53c406a { \
!      NULL			/* next */, \
!      NULL			/* usage count */, \
!      &proc_scsi_NCR53c406a      /* proc_dir */, \
!      NULL			/* proc_info */, \
!      "NCR53c406a"		/* name */, \
!      NCR53c406a_detect		/* detect */, \
!      NULL			/* release */, \
!      NCR53c406a_info		/* info */, \
!      NCR53c406a_command		/* command */, \
!      NCR53c406a_queue		/* queuecommand */, \
!      NCR53c406a_abort		/* abort */, \
!      NCR53c406a_reset		/* reset */, \
!      NULL			/* slave_attach */, \
!      NCR53c406a_biosparm	/* biosparm */, \
!      1				/* can_queue */, \
!      7				/* SCSI ID of the chip */, \
!      32				/*SG_ALL*/ /*SG_NONE*/, \
!      1				/* commands per lun */, \
!      0				/* number of boards in system */, \
!      1				/* unchecked_isa_dma */, \
!      ENABLE_CLUSTERING \
  }
  
  extern struct proc_dir_entry proc_scsi_NCR53c406a;
--- 26,46 ----
   * Use SG_NONE if DMA mode is enabled!
   */
  #define NCR53c406a { \
!      proc_dir:          &proc_scsi_NCR53c406a   /* proc_dir */,         \
!      name:              "NCR53c406a"		/* name */,             \
!      detect:            NCR53c406a_detect	/* detect */,           \
!      info:              NCR53c406a_info		/* info */,             \
!      command:           NCR53c406a_command	/* command */,          \
!      queuecommand:      NCR53c406a_queue	/* queuecommand */,     \
!      abort:             NCR53c406a_abort	/* abort */,            \
!      reset:             NCR53c406a_reset	/* reset */,            \
!      bios_param:        NCR53c406a_biosparm	/* biosparm */,         \
!      can_queue:         1			/* can_queue */,        \
!      this_id:           7			/* SCSI ID of the chip */, \
!      sg_tablesize:      32			/*SG_ALL*/ /*SG_NONE*/, \
!      cmd_per_lun:       1			/* commands per lun */, \
!      unchecked_isa_dma: 1			/* unchecked_isa_dma */, \
!      use_clustering:    ENABLE_CLUSTERING                               \
  }
  
  extern struct proc_dir_entry proc_scsi_NCR53c406a;
Index: linux/drivers/scsi/a2091.h
diff -c linux/drivers/scsi/a2091.h:1.1.1.1 linux/drivers/scsi/a2091.h:1.2
*** linux/drivers/scsi/a2091.h:1.1.1.1	Sun May 18 19:18:14 1997
--- linux/drivers/scsi/a2091.h	Sun May 18 19:27:03 1997
***************
*** 33,59 ****
  
  extern struct proc_dir_entry proc_scsi_a2091;
  
! #define A2091_SCSI {  /* next */                NULL,            \
! 		      /* module */         NULL,	         \
! 		      /* proc_dir_entry */      &proc_scsi_a2091, \
! 		      /* proc_info */           NULL,            \
! 		      /* name */                "Commodore A2091/A590 SCSI", \
! 		      /* detect */              a2091_detect,    \
! 		      /* release */             a2091_release,   \
! 		      /* info */                NULL,	         \
! 		      /* command */             NULL,            \
! 		      /* queuecommand */        wd33c93_queuecommand, \
! 		      /* abort */               wd33c93_abort,   \
! 		      /* reset */               wd33c93_reset,   \
! 		      /* slave_attach */        NULL,            \
! 		      /* bios_param */          NULL, 	         \
! 		      /* can_queue */           CAN_QUEUE,       \
! 		      /* this_id */             7,               \
! 		      /* sg_tablesize */        SG_ALL,          \
! 		      /* cmd_per_lun */	        CMD_PER_LUN,     \
! 		      /* present */             0,               \
! 		      /* unchecked_isa_dma */   0,               \
! 		      /* use_clustering */      DISABLE_CLUSTERING }
  #else
  
  /*
--- 33,50 ----
  
  extern struct proc_dir_entry proc_scsi_a2091;
  
! #define A2091_SCSI {  proc_dir:		   &proc_scsi_a2091, \
! 		      name:                "Commodore A2091/A590 SCSI", \
! 		      detect:              a2091_detect,    \
! 		      release:             a2091_release,   \
! 		      queuecommand:        wd33c93_queuecommand, \
! 		      abort:               wd33c93_abort,   \
! 		      reset:               wd33c93_reset,   \
! 		      can_queue:           CAN_QUEUE,       \
! 		      this_id:             7,               \
! 		      sg_tablesize:        SG_ALL,          \
! 		      cmd_per_lun:	   CMD_PER_LUN,     \
! 		      use_clustering:      DISABLE_CLUSTERING }
  #else
  
  /*
Index: linux/drivers/scsi/a3000.h
diff -c linux/drivers/scsi/a3000.h:1.1.1.1 linux/drivers/scsi/a3000.h:1.2
*** linux/drivers/scsi/a3000.h:1.1.1.1	Sun May 18 19:18:15 1997
--- linux/drivers/scsi/a3000.h	Sun May 18 19:27:04 1997
***************
*** 33,59 ****
  
  extern struct proc_dir_entry proc_scsi_a3000;
  
! #define A3000_SCSI {  /* next */                NULL,            \
! 		      /* module */         NULL,	         \
! 		      /* proc_dir_entry */      &proc_scsi_a3000, \
! 		      /* proc_info */           NULL,            \
! 		      /* name */                "Amiga 3000 built-in SCSI", \
! 		      /* detect */              a3000_detect,    \
! 		      /* release */             a3000_release,   \
! 		      /* info */                NULL,	         \
! 		      /* command */             NULL,            \
! 		      /* queuecommand */        wd33c93_queuecommand, \
! 		      /* abort */               wd33c93_abort,   \
! 		      /* reset */               wd33c93_reset,   \
! 		      /* slave_attach */        NULL,            \
! 		      /* bios_param */          NULL, 	         \
! 		      /* can_queue */           CAN_QUEUE,       \
! 		      /* this_id */             7,               \
! 		      /* sg_tablesize */        SG_ALL,          \
! 		      /* cmd_per_lun */	        CMD_PER_LUN,     \
! 		      /* present */             0,               \
! 		      /* unchecked_isa_dma */   0,               \
! 		      /* use_clustering */      ENABLE_CLUSTERING }
  #else
  
  /*
--- 33,51 ----
  
  extern struct proc_dir_entry proc_scsi_a3000;
  
! #define A3000_SCSI {  proc_dir:		   &proc_scsi_a3000,		\
! 		      proc_info:           NULL,			\
! 		      name:                "Amiga 3000 built-in SCSI",	\
! 		      detect:              a3000_detect,		\
! 		      release:             a3000_release,		\
! 		      queuecommand:        wd33c93_queuecommand,	\
! 		      abort:               wd33c93_abort,		\
! 		      reset:               wd33c93_reset,		\
! 		      can_queue:           CAN_QUEUE,			\
! 		      this_id:             7,				\
! 		      sg_tablesize:        SG_ALL,			\
! 		      cmd_per_lun:	   CMD_PER_LUN,			\
! 		      use_clustering:      ENABLE_CLUSTERING }
  #else
  
  /*
Index: linux/drivers/scsi/advansys.c
diff -c linux/drivers/scsi/advansys.c:1.1.1.1 linux/drivers/scsi/advansys.c:1.2
*** linux/drivers/scsi/advansys.c:1.1.1.1	Sun May 18 19:18:12 1997
--- linux/drivers/scsi/advansys.c	Sun May 18 19:27:06 1997
***************
*** 3367,3377 ****
  
  #ifdef MODULE
  			/*
  			 * Following v1.3.89, 'cmd_per_lun' is no longer needed
  			 * and should be set to zero. But because of a bug introduced
  			 * in v1.3.89 if the driver is compiled as a module and
  			 * 'cmd_per_lun' is zero, the Mid-Level SCSI function
! 			 * 'allocate_device' will panic. To allow the driver to
  			 * work as a module in these kernels set 'cmd_per_lun' to 1.
  			 */
  			shp->cmd_per_lun = 1;
--- 3367,3382 ----
  
  #ifdef MODULE
  			/*
+ 			 * FIXME(eric) - this is completely bogus.  We need to
+ 			 * figure out what exactly the real problem is and deal
+ 			 * with it.
+ 			 */
+ 			/*
  			 * Following v1.3.89, 'cmd_per_lun' is no longer needed
  			 * and should be set to zero. But because of a bug introduced
  			 * in v1.3.89 if the driver is compiled as a module and
  			 * 'cmd_per_lun' is zero, the Mid-Level SCSI function
! 			 * 'scsi_allocate_device' will panic. To allow the driver to
  			 * work as a module in these kernels set 'cmd_per_lun' to 1.
  			 */
  			shp->cmd_per_lun = 1;
***************
*** 6608,6617 ****
--- 6613,6628 ----
  		(unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no,
  		(unsigned) s->last_reset);
  
+ #ifdef ERIC_neverdef /* { */
+ 	/*
+ 	 * This information is private to the mid-layer scsi and the
+ 	 * the low-level drivers shouldn't even be aware that it is there.
+ 	 */
  	printk(
  " host_wait %x, host_queue %x, hostt %x, block %x,\n",
  		(unsigned) s->host_wait, (unsigned) s->host_queue,
  		(unsigned) s->hostt, (unsigned) s->block);
+ #endif /* ERIC_neverdef */ /* } */
  
  	printk(
  " wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n",
Index: linux/drivers/scsi/advansys.h
diff -c linux/drivers/scsi/advansys.h:1.1.1.1 linux/drivers/scsi/advansys.h:1.2
*** linux/drivers/scsi/advansys.h:1.1.1.1	Sun May 18 19:18:14 1997
--- linux/drivers/scsi/advansys.h	Sun May 18 19:27:08 1997
***************
*** 35,52 ****
  int advansys_command(Scsi_Cmnd *);
  int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
  int advansys_abort(Scsi_Cmnd *);
- #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
- int advansys_reset(Scsi_Cmnd *);
- #else /* version >= v1.3.89 */
  int advansys_reset(Scsi_Cmnd *, unsigned int);
- #endif /* version >= v1.3.89 */
- #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
- int advansys_biosparam(Disk *, int, int[]);
- #else /* version >= v1.3.0 */
  int advansys_biosparam(Disk *, kdev_t, int[]);
  extern struct proc_dir_entry proc_scsi_advansys;
  int advansys_proc_info(char *, char **, off_t, int, int, int);
- #endif /* version >= v1.3.0 */
  
  /* init/main.c setup function */
  void advansys_setup(char *, int *);
--- 35,44 ----
***************
*** 54,139 ****
  /*
   * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h.
   */
- #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
  #define ADVANSYS { \
! 	NULL,					/* struct SHT *next */ \
! 	NULL,					/* struct module *module */ \
! 	"advansys",				/* char *name */ \
! 	advansys_detect,		/* int (*detect)(struct SHT *) */ \
! 	advansys_release,		/* int (*release)(struct Scsi_Host *) */ \
! 	advansys_info,			/* const char *(*info)(struct Scsi_Host *) */ \
! 	advansys_command, 		/* int (*command)(Scsi_Cmnd *) */ \
! 	advansys_queuecommand, \
! 			/* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
! 	advansys_abort,			/* int (*abort)(Scsi_Cmnd *) */ \
! 	advansys_reset,			/* int (*reset)(Scsi_Cmnd *) */ \
! 	NULL,					/* int (*slave_attach)(int, int) */ \
! 	advansys_biosparam,		/* int (* bios_param)(Disk *, int, int []) */ \
! 	/* \
! 	 * The following fields are set per adapter in advansys_detect(). \
! 	 */ \
! 	0,						/* int can_queue */ \
! 	0,						/* int this_id */ \
! 	0,						/* short unsigned int sg_tablesize */ \
! 	0,						/* short cmd_per_lun */ \
! 	0,						/* unsigned char present */	\
! 	/* \
  	 * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
  	 * must be set. The flag will be cleared in advansys_detect for non-ISA \
  	 * adapters. Refer to the comment in scsi_module.c for more information. \
! 	 */ \
! 	1,						/* unsigned unchecked_isa_dma:1 */ \
! 	/* \
  	 * All adapters controlled by this driver are capable of large \
  	 * scatter-gather lists. According to the mid-level SCSI documentation \
  	 * this obviates any performance gain provided by setting \
  	 * 'use_clustering'. But empirically while CPU utilization is increased \
  	 * by enabling clustering, I/O throughput increases as well. \
! 	 */ \
! 	ENABLE_CLUSTERING,		/* unsigned use_clustering:1 */ \
  }
- #else /* version >= v1.3.0 */
- #define ADVANSYS { \
- 	NULL,					/* struct SHT *next */ \
- 	NULL,					/* struct module *module */ \
- 	&proc_scsi_advansys,	/* struct proc_dir_entry *proc_dir */ \
- 	advansys_proc_info,	\
- 			/* int (*proc_info)(char *, char **, off_t, int, int, int) */ \
- 	"advansys",				/* const char *name */ \
- 	advansys_detect,		/* int (*detect)(struct SHT *) */ \
- 	advansys_release,		/* int (*release)(struct Scsi_Host *) */ \
- 	advansys_info,			/* const char *(*info)(struct Scsi_Host *) */ \
- 	advansys_command, 		/* int (*command)(Scsi_Cmnd *) */ \
- 	advansys_queuecommand, \
- 			/* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
- 	advansys_abort,			/* int (*abort)(Scsi_Cmnd *) */ \
- 	advansys_reset, \
- 		/* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \
- 		/* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \
- 	NULL,					/* int (*slave_attach)(int, int) */ \
- 	advansys_biosparam,		/* int (* bios_param)(Disk *, kdev_t, int []) */ \
- 	/* \
- 	 * The following fields are set per adapter in advansys_detect(). \
- 	 */ \
- 	0,						/* int can_queue */ \
- 	0,						/* int this_id */ \
- 	0,						/* short unsigned int sg_tablesize */ \
- 	0,						/* short cmd_per_lun */ \
- 	0,						/* unsigned char present */	\
- 	/* \
- 	 * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
- 	 * must be set. The flag will be cleared in advansys_detect for non-ISA \
- 	 * adapters. Refer to the comment in scsi_module.c for more information. \
- 	 */ \
- 	1,						/* unsigned unchecked_isa_dma:1 */ \
- 	/* \
- 	 * All adapters controlled by this driver are capable of large \
- 	 * scatter-gather lists. According to the mid-level SCSI documentation \
- 	 * this obviates any performance gain provided by setting \
- 	 * 'use_clustering'. But empirically while CPU utilization is increased \
- 	 * by enabling clustering, I/O throughput increases as well. \
- 	 */ \
- 	ENABLE_CLUSTERING,		/* unsigned use_clustering:1 */ \
- }
- #endif /* version >= v1.3.0 */
  #endif /* _ADVANSYS_H */
--- 46,76 ----
  /*
   * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h.
   */
  #define ADVANSYS { \
! 			proc_dir:     &proc_scsi_advansys,	 \
! 			proc_info:    advansys_proc_info,	 \
! 			name:         "advansys",		 \
! 			detect:       advansys_detect,		 \
! 			release:      advansys_release,	         \
! 			info:         advansys_info,		 \
! 			command:      advansys_command, 	 \
! 			queuecommand: advansys_queuecommand,     \
! 			abort:        advansys_abort,		 \
! 			reset:        advansys_reset,		 \
! 			bios_param:    advansys_biosparam,	 \
! 	/*							 \
  	 * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
  	 * must be set. The flag will be cleared in advansys_detect for non-ISA \
  	 * adapters. Refer to the comment in scsi_module.c for more information. \
! 	 */							 \
! 			unchecked_isa_dma: 1,			 \
! 	/*							 \
  	 * All adapters controlled by this driver are capable of large \
  	 * scatter-gather lists. According to the mid-level SCSI documentation \
  	 * this obviates any performance gain provided by setting \
  	 * 'use_clustering'. But empirically while CPU utilization is increased \
  	 * by enabling clustering, I/O throughput increases as well. \
! 	 */							 \
! 			use_clustering: ENABLE_CLUSTERING,	 \
  }
  #endif /* _ADVANSYS_H */
Index: linux/drivers/scsi/aha152x.h
diff -c linux/drivers/scsi/aha152x.h:1.1.1.1 linux/drivers/scsi/aha152x.h:1.2
*** linux/drivers/scsi/aha152x.h:1.1.1.1	Sun May 18 19:18:09 1997
--- linux/drivers/scsi/aha152x.h	Sun May 18 19:27:08 1997
***************
*** 28,54 ****
  extern struct proc_dir_entry proc_scsi_aha152x;
  
  /* Initial value of Scsi_Host entry */
! #define AHA152X { /* next */               0, \
!                   /* module */             0, \
!                   /* proc_dir */           &proc_scsi_aha152x, \
!                   /* proc_info */          aha152x_proc_info, \
!                   /* name */               AHA152X_REVID, \
!                   /* detect */             aha152x_detect, \
!                   /* release */            0, \
!                   /* info */               0, \
!                   /* command */		       aha152x_command, \
!                   /* queuecommand */       aha152x_queue, \
!                   /* abort */              aha152x_abort, \
!                   /* reset */              aha152x_reset, \
!                   /* slave_attach */       0, \
!                   /* bios_param */         aha152x_biosparam, \
!                   /* can_queue */          1, \
!                   /* this_id */            7, \
!                   /* sg_tablesize */       SG_ALL, \
!                   /* cmd_per_lun */        1, \
!                   /* present */            0, \
!                   /* unchecked_isa_dma */  0, \
!                   /* use_clustering */     DISABLE_CLUSTERING }
  #endif
  
  
--- 28,50 ----
  extern struct proc_dir_entry proc_scsi_aha152x;
  
  /* Initial value of Scsi_Host entry */
! #define AHA152X { proc_dir:           &proc_scsi_aha152x, \
!                   proc_info:          aha152x_proc_info,  \
!                   name:               AHA152X_REVID,	  \
!                   detect:             aha152x_detect,	  \
!                   command:	      aha152x_command,	  \
!                   queuecommand:       aha152x_queue,	  \
!                   abort:              aha152x_abort,	  \
!                   reset:              aha152x_reset,	  \
!                   slave_attach:       0,		  \
!                   bios_param:         aha152x_biosparam,  \
!                   can_queue:          1,		  \
!                   this_id:            7,		  \
!                   sg_tablesize:       SG_ALL,		  \
!                   cmd_per_lun:        1,		  \
!                   present:            0,		  \
!                   unchecked_isa_dma:  0,		  \
!                   use_clustering:     DISABLE_CLUSTERING }
  #endif
  
  
Index: linux/drivers/scsi/aha1542.c
diff -c linux/drivers/scsi/aha1542.c:1.1.1.1 linux/drivers/scsi/aha1542.c:1.4
*** linux/drivers/scsi/aha1542.c:1.1.1.1	Sun May 18 19:18:07 1997
--- linux/drivers/scsi/aha1542.c	Wed Jun  4 08:58:18 1997
***************
*** 1117,1128 ****
    return 0;
  }
  
- /* The abort command does not leave the device in a clean state where
-    it is available to be used again.  Until this gets worked out, we will
-    leave it commented out.  */
- 
  int aha1542_abort(Scsi_Cmnd * SCpnt)
  {
  #if 0
    unchar ahacmd = CMD_START_SCSI;
    unsigned long flags;
--- 1117,1380 ----
    return 0;
  }
  
  int aha1542_abort(Scsi_Cmnd * SCpnt)
  {
+     
+     /*
+      * The abort command does not leave the device in a clean state where
+      *  it is available to be used again.  Until this gets worked out, we
+      * will leave it commented out.  
+      */
+ 
+     printk("aha1542.c: Unable to abort command for target %d\n", 
+ 	   SCpnt->target);
+     return FAILED;
+ }
+ 
+ /*
+  * This is a device reset.  This is handled by sending a special command
+  * to the device.
+  */
+ int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
+ {
+     unsigned long flags;
+     struct mailbox * mb;
+     unchar target = SCpnt->target;
+     unchar lun = SCpnt->lun;
+     int mbo;
+     struct ccb  *ccb;
+     unchar ahacmd = CMD_START_SCSI;
+ 
+     ccb = HOSTDATA(SCpnt->host)->ccb;
+     mb = HOSTDATA(SCpnt->host)->mb;
+ 
+     save_flags(flags);
+     cli();
+     mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
+     if (mbo >= AHA1542_MAILBOXES) mbo = 0;
+     
+     do{
+ 	if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
+ 	    break;
+ 	mbo++;
+ 	if (mbo >= AHA1542_MAILBOXES) mbo = 0;
+     } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
+     
+     if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
+ 	panic("Unable to find empty mailbox for aha1542.\n");
+     
+     HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt;  /* This will effectively
+ 						   prevent someone else from
+ 						   screwing with this cdb. */
+ 	    
+     HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;    
+     restore_flags(flags);
+     
+     any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason*/
+ 
+     memset(&ccb[mbo], 0, sizeof(struct ccb));
+     
+     ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
+ 
+     ccb[mbo].idlun = (target&7)<<5 | (lun & 7); /*SCSI Target Id*/
+ 
+     ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+     ccb[mbo].commlinkid = 0;
+     
+     /* 
+      * Now tell the 1542 to flush all pending commands for this 
+      * target 
+      */
+     aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+ 
+     printk("aha1542.c: Trying device reset for target %d\n", SCpnt->target);
+ 
+     return SUCCESS;
+ 	    
+ 
+ #ifdef ERIC_neverdef
+     /* 
+      * With the 1542 we apparently never get an interrupt to
+      * acknowledge a device reset being sent.  Then again, Leonard
+      * says we are doing this wrong in the first place...
+      *
+      * Take a wait and see attitude.  If we get spurious interrupts,
+      * then the device reset is doing something sane and useful, and
+      * we will wait for the interrupt to post completion.
+      */
+     printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+     
+     /*
+      * Free the command block for all commands running on this 
+      * target... 
+      */
+     for(i=0; i< AHA1542_MAILBOXES; i++)
+     {
+ 	if(HOSTDATA(SCpnt->host)->SCint[i] &&
+ 	   HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target)
+ 	{
+ 	    Scsi_Cmnd * SCtmp;
+ 	    SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+ 	    if (SCtmp->host_scribble) 
+ 	    {
+ 		scsi_free(SCtmp->host_scribble, 512);
+ 	    }
+ 	    
+ 	    HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ 	    HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ 	}
+     }
+     return SUCCESS;
+ 
+     return FAILED;
+ #endif /* ERIC_neverdef */
+ }
+ 
+ int aha1542_bus_reset(Scsi_Cmnd * SCpnt)
+ {
+     int i;
+ 
+     /* 
+      * This does a scsi reset for all devices on the bus.
+      * In principle, we could also reset the 1542 - should
+      * we do this?  Try this first, and we can add that later
+      * if it turns out to be useful.
+      */
+     outb(SCRST, CONTROL(SCpnt->host->io_port));
+ 
+     /*
+      * Wait for the thing to settle down a bit.  Unfortunately
+      * this is going to basically lock up the machine while we
+      * wait for this to complete.  To be 100% correct, we need to
+      * check for timeout, and if we are doing something like this
+      * we are pretty desperate anyways.
+      */
+     scsi_sleep(4*HZ);
+ 
+     WAIT(STATUS(SCpnt->host->io_port), 
+ 	 STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+     
+     /*
+      * Now try to pick up the pieces.  For all pending commands,
+      * free any internal data structures, and basically clear things
+      * out.  We do not try and restart any commands or anything - 
+      * the strategy handler takes care of that crap.
+      */
+     printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+ 
+     for(i=0; i< AHA1542_MAILBOXES; i++)
+     {
+ 	if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
+ 	{
+ 	    Scsi_Cmnd * SCtmp;
+ 	    SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+ 
+     
+ 	    if( SCtmp->device->soft_reset )
+ 	    {
+ 		/*
+ 		 * If this device implements the soft reset option,
+ 		 * then it is still holding onto the command, and
+ 		 * may yet complete it.  In this case, we don't
+ 		 * flush the data.
+ 		 */
+ 		continue;
+ 	    }
+ 
+ 	    if (SCtmp->host_scribble) 
+ 	    {
+ 		scsi_free(SCtmp->host_scribble, 512);
+ 	    }
+ 	    
+ 	    HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ 	    HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ 	}
+     }
+ 
+     return SUCCESS;
+ 
+ fail:
+     return FAILED;
+ }
+ 
+ int aha1542_host_reset(Scsi_Cmnd * SCpnt)
+ {
+     int i;
+ 
+     /* 
+      * This does a scsi reset for all devices on the bus.
+      * In principle, we could also reset the 1542 - should
+      * we do this?  Try this first, and we can add that later
+      * if it turns out to be useful.
+      */
+     outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
+ 
+     /*
+      * Wait for the thing to settle down a bit.  Unfortunately
+      * this is going to basically lock up the machine while we
+      * wait for this to complete.  To be 100% correct, we need to
+      * check for timeout, and if we are doing something like this
+      * we are pretty desperate anyways.
+      */
+     scsi_sleep(4*HZ);
+ 
+     WAIT(STATUS(SCpnt->host->io_port), 
+ 	 STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+     
+     /*
+      * We need to do this too before the 1542 can interact with
+      * us again.
+      */
+     setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+     
+     /*
+      * Now try to pick up the pieces.  For all pending commands,
+      * free any internal data structures, and basically clear things
+      * out.  We do not try and restart any commands or anything - 
+      * the strategy handler takes care of that crap.
+      */
+     printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+     
+     for(i=0; i< AHA1542_MAILBOXES; i++)
+     {
+ 	if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
+ 	{
+ 	    Scsi_Cmnd * SCtmp;
+ 	    SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+ 
+ 	    if( SCtmp->device->soft_reset )
+ 	    {
+ 		/*
+ 		 * If this device implements the soft reset option,
+ 		 * then it is still holding onto the command, and
+ 		 * may yet complete it.  In this case, we don't
+ 		 * flush the data.
+ 		 */
+ 		continue;
+ 	    }
+ 
+ 	    if (SCtmp->host_scribble) 
+ 	    {
+ 		scsi_free(SCtmp->host_scribble, 512);
+ 	    }
+ 	    
+ 	    HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ 	    HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ 	}
+     }
+ 
+     return SUCCESS;
+ 
+ fail:
+     return FAILED;
+ }
+ 
+ /*
+  * These are the old error handling routines.  They are only temporarily
+  * here while we play with the new error handling code.
+  */
+ int aha1542_old_abort(Scsi_Cmnd * SCpnt)
+ {
  #if 0
    unchar ahacmd = CMD_START_SCSI;
    unsigned long flags;
***************
*** 1194,1200 ****
     For a first go, we assume that the 1542 notifies us with all of the
     pending commands (it does implement soft reset, after all). */
  
! int aha1542_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
  {
      unchar ahacmd = CMD_START_SCSI;
      int i;
--- 1446,1452 ----
     For a first go, we assume that the 1542 notifies us with all of the
     pending commands (it does implement soft reset, after all). */
  
! int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
  {
      unchar ahacmd = CMD_START_SCSI;
      int i;
Index: linux/drivers/scsi/aha1542.h
diff -c linux/drivers/scsi/aha1542.h:1.1.1.1 linux/drivers/scsi/aha1542.h:1.4
*** linux/drivers/scsi/aha1542.h:1.1.1.1	Sun May 18 19:18:07 1997
--- linux/drivers/scsi/aha1542.h	Wed Jun  4 08:58:18 1997
***************
*** 133,140 ****
  int aha1542_detect(Scsi_Host_Template *);
  int aha1542_command(Scsi_Cmnd *);
  int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
! int aha1542_abort(Scsi_Cmnd *);
! int aha1542_reset(Scsi_Cmnd *, unsigned int);
  int aha1542_biosparam(Disk *, kdev_t, int*);
  
  #define AHA1542_MAILBOXES 8
--- 133,140 ----
  int aha1542_detect(Scsi_Host_Template *);
  int aha1542_command(Scsi_Cmnd *);
  int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
! extern int aha1542_old_abort(Scsi_Cmnd * SCpnt);
! int aha1542_old_reset(Scsi_Cmnd *, unsigned int);
  int aha1542_biosparam(Disk *, kdev_t, int*);
  
  #define AHA1542_MAILBOXES 8
***************
*** 147,171 ****
  
  extern struct proc_dir_entry proc_scsi_aha1542;
  
! #define AHA1542 {  NULL, NULL,				\
!                      &proc_scsi_aha1542,/* proc_dir_entry */ \
! 		     NULL,		                \
! 		     "Adaptec 1542", 			\
! 		     aha1542_detect,			\
! 		     NULL,				\
! 		     NULL,	 			\
! 		     aha1542_command,			\
! 		     aha1542_queuecommand,		\
! 		     aha1542_abort,			\
! 		     aha1542_reset,			\
! 		     NULL,				\
! 		     aha1542_biosparam,                 \
! 		     AHA1542_MAILBOXES, 		\
! 		     7, 				\
! 		     AHA1542_SCATTER, 			\
! 		     AHA1542_CMDLUN, 			\
! 		     0, 				\
! 		     1, 				\
! 		     ENABLE_CLUSTERING}
  
  #endif
--- 147,170 ----
  
  extern struct proc_dir_entry proc_scsi_aha1542;
  
! #define AHA1542 {    proc_dir:			&proc_scsi_aha1542,	\
! 		     name:			"Adaptec 1542", 	\
! 		     detect:			aha1542_detect,		\
! 		     command:			aha1542_command,	\
! 		     queuecommand:		aha1542_queuecommand,	\
!                      abort:		        aha1542_old_abort,	\
!                      reset:			aha1542_old_reset,	\
! 		     eh_abort_handler:		aha1542_abort,		\
! 		     eh_device_reset_handler:	aha1542_dev_reset,	\
! 		     eh_bus_reset_handler:	aha1542_bus_reset,	\
! 		     eh_host_reset_handler:	aha1542_host_reset,	\
! 		     bios_param:		aha1542_biosparam,      \
! 		     can_queue:			AHA1542_MAILBOXES, 	\
! 		     this_id:			7, 			\
! 		     sg_tablesize:		AHA1542_SCATTER, 	\
! 		     cmd_per_lun:		AHA1542_CMDLUN, 	\
! 		     unchecked_isa_dma:		1, 			\
! 		     use_clustering:		ENABLE_CLUSTERING,	\
! 		     use_new_eh_code:		1}
  
  #endif
Index: linux/drivers/scsi/aha1740.h
diff -c linux/drivers/scsi/aha1740.h:1.1.1.1 linux/drivers/scsi/aha1740.h:1.2
*** linux/drivers/scsi/aha1740.h:1.1.1.1	Sun May 18 19:18:07 1997
--- linux/drivers/scsi/aha1740.h	Sun May 18 19:27:09 1997
***************
*** 172,196 ****
  
  extern struct proc_dir_entry proc_scsi_aha1740;
  
! #define AHA1740 {NULL,	NULL,				\
!                    &proc_scsi_aha1740,			\
! 		   aha1740_proc_info,	                \
! 		   "Adaptec 174x (EISA)",		\
! 		   aha1740_detect,			\
! 		   NULL,				\
! 		   NULL, 				\
! 		   aha1740_command,			\
! 		   aha1740_queuecommand,		\
! 		   aha1740_abort,			\
! 		   aha1740_reset,			\
! 		   NULL,				\
! 		   aha1740_biosparam,                   \
! 		   AHA1740_ECBS, 			\
! 		   7, 					\
! 		   AHA1740_SCATTER, 			\
! 		   AHA1740_CMDLUN, 			\
! 		   0, 					\
! 		   0, 					\
! 		   ENABLE_CLUSTERING}
  
  #endif
--- 172,190 ----
  
  extern struct proc_dir_entry proc_scsi_aha1740;
  
! #define AHA1740 {  proc_dir:       &proc_scsi_aha1740,			\
! 		   proc_info:      aha1740_proc_info,	                \
! 		   name:           "Adaptec 174x (EISA)",		\
! 		   detect:         aha1740_detect,			\
! 		   command:        aha1740_command,			\
! 		   queuecommand:   aha1740_queuecommand,		\
! 		   abort:          aha1740_abort,			\
! 		   reset:          aha1740_reset,			\
! 		   bios_param:     aha1740_biosparam,                   \
! 		   can_queue:      AHA1740_ECBS, 			\
! 		   this_id:        7, 					\
! 		   sg_tablesize:   AHA1740_SCATTER, 			\
! 		   cmd_per_lun:    AHA1740_CMDLUN, 			\
! 		   use_clustering: ENABLE_CLUSTERING}
  
  #endif
Index: linux/drivers/scsi/aic7xxx.h
diff -c linux/drivers/scsi/aic7xxx.h:1.1.1.1 linux/drivers/scsi/aic7xxx.h:1.4
*** linux/drivers/scsi/aic7xxx.h:1.1.1.1	Sun May 18 19:18:11 1997
--- linux/drivers/scsi/aic7xxx.h	Thu Jun  5 23:30:39 1997
***************
*** 30,56 ****
   * to do with card config are filled in after the card is detected.
   */
  #define AIC7XXX	{						\
! 	NULL,							\
! 	NULL,							\
! 	NULL,							\
! 	aic7xxx_proc_info,					\
! 	NULL,							\
! 	aic7xxx_detect,						\
! 	NULL,							\
! 	aic7xxx_info,						\
! 	NULL,							\
! 	aic7xxx_queue,						\
! 	aic7xxx_abort,						\
! 	aic7xxx_reset,						\
! 	NULL,							\
! 	aic7xxx_biosparam,					\
! 	-1,			/* max simultaneous cmds      */\
! 	-1,			/* scsi id of host adapter    */\
! 	SG_ALL,			/* max scatter-gather cmds    */\
! 	2,			/* cmds per lun (linked cmds) */\
! 	0,			/* number of 7xxx's present   */\
! 	0,			/* no memory DMA restrictions */\
! 	ENABLE_CLUSTERING					\
  }
  
  extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
--- 30,48 ----
   * to do with card config are filled in after the card is detected.
   */
  #define AIC7XXX	{						\
! 	proc_info:       aic7xxx_proc_info,					\
! 	detect:          aic7xxx_detect,					\
! 	info:            aic7xxx_info,						\
! 	queuecommand:    aic7xxx_queue,						\
! 	abort:           aic7xxx_abort,						\
! 	reset:           aic7xxx_reset,						\
! 	bios_param:      aic7xxx_biosparam,					\
! 	can_queue:       -1,			/* max simultaneous cmds      */\
! 	this_id:         -1,			/* scsi id of host adapter    */\
! 	sg_tablesize:    SG_ALL,		/* max scatter-gather cmds    */\
! 	cmd_per_lun:     2,			/* cmds per lun (linked cmds) */\
! 	use_clustering:  ENABLE_CLUSTERING,					\
! 	use_new_eh_code: 0			/* Enable new error code */	\
  }
  
  extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
Index: linux/drivers/scsi/atari_scsi.h
diff -c linux/drivers/scsi/atari_scsi.h:1.1.1.1 linux/drivers/scsi/atari_scsi.h:1.2
*** linux/drivers/scsi/atari_scsi.h:1.1.1.1	Sun May 18 19:18:14 1997
--- linux/drivers/scsi/atari_scsi.h	Sun May 18 19:27:10 1997
***************
*** 53,77 ****
  
  #if defined (HOSTS_C) || defined (MODULE)
  
! #define ATARI_SCSI { NULL, NULL, NULL,				\
!   atari_scsi_proc_info,						\
!   "Atari native SCSI",						\
!   atari_scsi_detect,						\
!   atari_scsi_release,						\
!   atari_scsi_info,						\
!   /* command */ NULL,						\
!   atari_scsi_queue_command,					\
!   atari_scsi_abort,						\
!   atari_scsi_reset,						\
!   /* slave_attach */	NULL,					\
!   /* bios_param */	NULL,					\
!   /* can queue */	0, /* initialized at run-time */	\
!   /* host_id */		0, /* initialized at run-time */	\
!   /* scatter gather */	0, /* initialized at run-time */	\
!   /* cmd per lun */	0, /* initialized at run-time */	\
!   /* present */		0,					\
!   /* unchecked ISA DMA */ 0,					\
!   /* use_clustering */	DISABLE_CLUSTERING }
  
  #endif
  
--- 53,71 ----
  
  #if defined (HOSTS_C) || defined (MODULE)
  
! #define ATARI_SCSI {    proc_info:         atari_scsi_proc_info,	\
! 			name:              "Atari native SCSI",		\
! 			detect:            atari_scsi_detect,		\
! 			release:           atari_scsi_release,		\
! 			info:              atari_scsi_info,		\
! 			queuecommand:      atari_scsi_queue_command,	\
! 			abort:             atari_scsi_abort,		\
! 			reset:             atari_scsi_reset,		\
! 			can_queue:         0, /* initialized at run-time */	\
! 			this_id:           0, /* initialized at run-time */	\
! 			sg_tablesize:      0, /* initialized at run-time */	\
! 			cmd_per_lun:       0, /* initialized at run-time */	\
! 			use_clustering:	   DISABLE_CLUSTERING }
  
  #endif
  
Index: linux/drivers/scsi/constants.c
diff -c linux/drivers/scsi/constants.c:1.1.1.1 linux/drivers/scsi/constants.c:1.2
*** linux/drivers/scsi/constants.c:1.1.1.1	Sun May 18 19:18:09 1997
--- linux/drivers/scsi/constants.c	Sun May 18 19:27:10 1997
***************
*** 3,13 ****
   * etc.
   */
  
- /*
-  * Don't import our own symbols, as this would severely mess up our
-  * symbol tables.
-  */
- #define _SCSI_SYMS_VER_
  #define __NO_VERSION__
  #include <linux/module.h>
  
--- 3,8 ----
Index: linux/drivers/scsi/dc390.h
diff -c linux/drivers/scsi/dc390.h:1.1.1.1 linux/drivers/scsi/dc390.h:1.2
*** linux/drivers/scsi/dc390.h:1.1.1.1	Sun May 18 19:35:54 1997
--- linux/drivers/scsi/dc390.h	Mon May 19 22:39:36 1997
***************
*** 63,91 ****
  
  #ifdef	VERSION_2_0_0
  
! #define DC390_T    {			\
! 	NULL,	/* *next */		\
! 	NULL,	/* *usage_count */	\
! 	&proc_scsi_tmscsim,	/* *proc_dir */ 	\
! 	tmscsim_proc_info,	/* (*proc_info)() */	\
! 	"Tekram DC390(T) V1.10 Dec-05-1996",  /* *name */ \
! 	DC390_detect,			\
! 	DC390_release,	/* (*release)() */	\
! 	NULL,	/* *(*info)() */	\
! 	NULL,	/* (*command)() */	\
! 	DC390_queue_command,	\
! 	DC390_abort,		\
! 	DC390_reset,		\
! 	NULL, /* slave attach */\
! 	DC390_bios_param,	\
! 	10,/* can queue(-1) */	\
! 	7, /* id(-1) */ 	\
! 	SG_ALL, 		\
! 	2, /* cmd per lun(2) */ \
! 	0, /* present */	\
! 	0, /* unchecked isa dma */ \
! 	DISABLE_CLUSTERING	\
! 	}
  #endif
  
  
--- 63,84 ----
  
  #ifdef	VERSION_2_0_0
  
! #define DC390_T    {			          \
!    proc_dir:       &proc_scsi_tmscsim,            \
!    proc_info:      tmscsim_proc_info
!    name:           "Tekram DC390(T) V1.10 Dec-05-1996",\
!    detect:         DC390_detect,   		  \
!    release:        DC390_release,		  \
!    queuecommand:   DC390_queue_command,	          \
!    abort:          DC390_abort,    		  \
!    reset:          DC390_reset,    		  \
!    bios_param:     DC390_bios_param,		  \
!    can_queue:      10,                 	          \
!    this_id:        7,                             \
!    sg_tablesize:   SG_ALL,            		  \
!    cmd_per_lun:    2,                 		  \
!    use_clustering: DISABLE_CLUSTERING 		  \
!    }
  #endif
  
  
Index: linux/drivers/scsi/dtc.h
diff -c linux/drivers/scsi/dtc.h:1.1.1.1 linux/drivers/scsi/dtc.h:1.2
*** linux/drivers/scsi/dtc.h:1.1.1.1	Sun May 18 19:18:15 1997
--- linux/drivers/scsi/dtc.h	Sun May 18 19:27:10 1997
***************
*** 57,69 ****
  
  #if defined(HOSTS_C) || defined(MODULE)
  
! #define DTC3x80 {NULL, NULL, NULL, NULL, \
! 	"DTC 3180/3280 ", dtc_detect, NULL,  \
! 	NULL,							\
! 	NULL, dtc_queue_command, dtc_abort, dtc_reset, NULL, 	\
! 	dtc_biosparam, 						\
! 	/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,			\
! 	/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
  
  #endif
  
--- 57,74 ----
  
  #if defined(HOSTS_C) || defined(MODULE)
  
! #define DTC3x80 {				\
! 	name:           "DTC 3180/3280 ",	\
! 	detect:         dtc_detect,		\
! 	queuecommand:   dtc_queue_command,	\
! 	abort:          dtc_abort,		\
! 	reset:          dtc_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}
  
  #endif
  
Index: linux/drivers/scsi/eata.h
diff -c linux/drivers/scsi/eata.h:1.1.1.2 linux/drivers/scsi/eata.h:1.3
*** linux/drivers/scsi/eata.h:1.1.1.2	Wed May 28 07:54:19 1997
--- linux/drivers/scsi/eata.h	Wed May 28 08:37:28 1997
***************
*** 15,41 ****
  #define EATA_VERSION "3.10.00"
  
  
! #define EATA {                                                 \
! 		NULL, /* Ptr for modules */                    \
! 		NULL, /* usage count for modules */	       \
! 		NULL,                                          \
! 		NULL,                                          \
! 		"EATA/DMA 2.0x rev. " EATA_VERSION " ",        \
! 		eata2x_detect,				       \
! 		eata2x_release,          		       \
! 		NULL,					       \
! 		NULL,    			       	       \
! 		eata2x_queuecommand,			       \
! 		eata2x_abort,				       \
! 		eata2x_reset,				       \
! 		NULL,					       \
! 		scsicam_bios_param,   			       \
! 		0,   /* can_queue, reset by detect */          \
! 		7,   /* this_id, reset by detect */            \
! 		0,   /* sg_tablesize, reset by detect */       \
! 		0,   /* cmd_per_lun, reset by detect */        \
! 		0,   /* number of boards present */            \
! 		1,   /* unchecked isa dma, reset by detect */  \
! 		ENABLE_CLUSTERING                              \
  		}
  #endif
--- 15,30 ----
  #define EATA_VERSION "3.10.00"
  
  
! #define EATA {									\
! 		name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",      \
! 		detect:            eata2x_detect,				\
! 		release:           eata2x_release,          		        \
! 		queuecommand:      eata2x_queuecommand,			        \
! 		abort:             eata2x_abort,				\
! 		reset:             eata2x_reset,				\
! 		bios_param:        scsicam_bios_param,   			\
! 		this_id:           7,   /* this_id, reset by detect */          \
! 		unchecked_isa_dma: 1,   /* unchecked isa dma, reset by detect */\
! 		use_clustering:    ENABLE_CLUSTERING                            \
  		}
  #endif
Index: linux/drivers/scsi/eata_dma.h
diff -c linux/drivers/scsi/eata_dma.h:1.1.1.1 linux/drivers/scsi/eata_dma.h:1.2
*** linux/drivers/scsi/eata_dma.h:1.1.1.1	Sun May 18 19:18:12 1997
--- linux/drivers/scsi/eata_dma.h	Sun May 18 19:27:11 1997
***************
*** 84,109 ****
  
  #include <scsi/scsicam.h>
  
! #define EATA_DMA {                   \
!         NULL, NULL,                  \
!         NULL,               /* proc_dir_entry */ \
!         eata_proc_info,     /* procinfo       */ \
!         "EATA (Extended Attachment) HBA driver", \
!         eata_detect,                 \
!         eata_release,                \
! 	NULL, NULL,                  \
! 	eata_queue,                  \
! 	eata_abort,                  \
! 	eata_reset,                  \
! 	NULL,   /* Slave attach */   \
! 	scsicam_bios_param,          \
! 	0,      /* Canqueue     */   \
! 	0,      /* this_id      */   \
! 	0,      /* sg_tablesize */   \
! 	0,      /* cmd_per_lun  */   \
! 	0,      /* present      */   \
! 	1,      /* True if ISA  */   \
! 	ENABLE_CLUSTERING }
  
  
  #endif /* _EATA_DMA_H */
--- 84,100 ----
  
  #include <scsi/scsicam.h>
  
! #define EATA_DMA {                                      \
!         proc_info:         eata_proc_info,     /* procinfo       */ \
!         name:              "EATA (Extended Attachment) HBA driver", \
!         detect:            eata_detect,                 \
!         release:           eata_release,                \
! 	queuecommand:      eata_queue,                  \
! 	abort:             eata_abort,                  \
! 	reset:             eata_reset,                  \
! 	bios_param:        scsicam_bios_param,          \
! 	unchecked_isa_dma: 1,      /* True if ISA  */   \
! 	use_clustering:    ENABLE_CLUSTERING }
  
  
  #endif /* _EATA_DMA_H */
Index: linux/drivers/scsi/eata_pio.h
diff -c linux/drivers/scsi/eata_pio.h:1.1.1.1 linux/drivers/scsi/eata_pio.h:1.2
*** linux/drivers/scsi/eata_pio.h:1.1.1.1	Sun May 18 19:18:12 1997
--- linux/drivers/scsi/eata_pio.h	Sun May 18 19:27:11 1997
***************
*** 74,99 ****
  #endif
  
  
! #define EATA_PIO {	         \
!     NULL, NULL,                  \
!     NULL,               /* proc_dir_entry */ \
!     eata_pio_proc_info, /* procinfo	  */ \
!     "EATA (Extended Attachment) PIO driver", \
!     eata_pio_detect,		 \
!     eata_pio_release,		 \
!     NULL, NULL,			 \
!     eata_pio_queue,		 \
!     eata_pio_abort,		 \
!     eata_pio_reset,		 \
!     NULL,   /* Slave attach */	 \
!     scsicam_bios_param,		 \
!     0,	    /* Canqueue	    */	 \
!     0,	    /* this_id	    */	 \
!     0,	    /* sg_tablesize */	 \
!     0,	    /* cmd_per_lun  */	 \
!     0,	    /* present	    */	 \
!     1,	    /* True if ISA  */	 \
!     ENABLE_CLUSTERING }
  
  #endif /* _EATA_PIO_H */
  
--- 74,90 ----
  #endif
  
  
! #define EATA_PIO {						\
!     proc_info:         eata_pio_proc_info, /* procinfo	  */	\
!     name:              "EATA (Extended Attachment) PIO driver",	\
!     detect:            eata_pio_detect,				\
!     release:           eata_pio_release,			\
!     queuecommand:      eata_pio_queue,				\
!     abort:             eata_pio_abort,				\
!     reset:             eata_pio_reset,				\
!     bios_param:        scsicam_bios_param,			\
!     unchecked_isa_dma: 1,	    /* True if ISA  */		\
!     use_clustering:    ENABLE_CLUSTERING }
  
  #endif /* _EATA_PIO_H */
  
Index: linux/drivers/scsi/esp.h
diff -c linux/drivers/scsi/esp.h:1.1.1.1 linux/drivers/scsi/esp.h:1.2
*** linux/drivers/scsi/esp.h:1.1.1.1	Sun May 18 19:18:14 1997
--- linux/drivers/scsi/esp.h	Sun May 18 19:27:12 1997
***************
*** 395,422 ****
  
  extern struct proc_dir_entry proc_scsi_esp;
  
! #define SCSI_SPARC_ESP {                                                               \
! /* struct SHT *next */                                         NULL,                   \
! /* struct module *module */                                    NULL,                   \
! /* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
! /* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,         \
! /* const char *name */                                         "Sun ESP 100/100a/200", \
! /* int detect(struct SHT *) */                                 esp_detect,             \
! /* int release(struct Scsi_Host *) */                          NULL,                   \
! /* const char *info(struct Scsi_Host *) */                     esp_info,               \
! /* int command(Scsi_Cmnd *) */                                 esp_command,            \
! /* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue,              \
! /* int abort(Scsi_Cmnd *) */                                   esp_abort,              \
! /* int reset(Scsi_Cmnd *, int) */                              esp_reset,              \
! /* int slave_attach(int, int) */                               NULL,                   \
! /* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
! /* int can_queue */                                            7,                      \
! /* int this_id */                                              7,                      \
! /* short unsigned int sg_tablesize */                          SG_ALL,                 \
! /* short cmd_per_lun */                                        1,                      \
! /* unsigned char present */                                    0,                      \
! /* unsigned unchecked_isa_dma:1 */                             0,                      \
! /* unsigned use_clustering:1 */                                DISABLE_CLUSTERING, }
  
  /* For our interrupt engine. */
  #define for_each_esp(esp) \
--- 395,415 ----
  
  extern struct proc_dir_entry proc_scsi_esp;
  
! #define SCSI_SPARC_ESP {                                        \
! 		proc_dir:       &proc_scsi_esp,			\
! 		proc_info:      &esp_proc_info,			\
! 		name:           "Sun ESP 100/100a/200",		\
! 		detect:         esp_detect,			\
! 		info:           esp_info,			\
! 		command:        esp_command,			\
! 		queuecommand:   esp_queue,			\
! 		abort:          esp_abort,			\
! 		reset:          esp_reset,			\
! 		can_queue:      7,				\
! 		this_id:        7,				\
! 		sg_tablesize:   SG_ALL,				\
! 		cmd_per_lun:    1,				\
! 		use_clustering: DISABLE_CLUSTERING, }
  
  /* For our interrupt engine. */
  #define for_each_esp(esp) \
Index: linux/drivers/scsi/fdomain.h
diff -c linux/drivers/scsi/fdomain.h:1.1.1.1 linux/drivers/scsi/fdomain.h:1.2
*** linux/drivers/scsi/fdomain.h:1.1.1.1	Sun May 18 19:18:10 1997
--- linux/drivers/scsi/fdomain.h	Sun May 18 19:27:12 1997
***************
*** 37,61 ****
  
  extern struct proc_dir_entry proc_scsi_fdomain;
  
! #define FDOMAIN_16X0 { NULL,                             \
! 		       NULL,                             \
! 		       NULL,		                 \
! 		       fdomain_16x0_proc_info,           \
! 		       NULL,		                 \
! 		       fdomain_16x0_detect,              \
! 		       NULL,				 \
! 		       fdomain_16x0_info,                \
! 		       fdomain_16x0_command,             \
! 		       fdomain_16x0_queue,               \
! 		       fdomain_16x0_abort,               \
! 		       fdomain_16x0_reset,               \
! 		       NULL,                             \
! 		       fdomain_16x0_biosparam,           \
! 		       1, 				 \
! 		       6, 				 \
! 		       64, 				 \
! 		       1, 				 \
! 		       0, 				 \
! 		       0, 				 \
! 		       DISABLE_CLUSTERING }
  #endif
--- 37,53 ----
  
  extern struct proc_dir_entry proc_scsi_fdomain;
  
! #define FDOMAIN_16X0 { proc_info:      fdomain_16x0_proc_info,           \
! 		       detect:         fdomain_16x0_detect,              \
! 		       info:           fdomain_16x0_info,                \
! 		       command:        fdomain_16x0_command,             \
! 		       queuecommand:   fdomain_16x0_queue,               \
! 		       abort:          fdomain_16x0_abort,               \
! 		       reset:          fdomain_16x0_reset,               \
! 		       bios_param:     fdomain_16x0_biosparam,           \
! 		       can_queue:      1, 				 \
! 		       this_id:        6, 				 \
! 		       sg_tablesize:   64, 				 \
! 		       cmd_per_lun:    1, 				 \
! 		       use_clustering: DISABLE_CLUSTERING }
  #endif
Index: linux/drivers/scsi/g_NCR5380.c
diff -c linux/drivers/scsi/g_NCR5380.c:1.1.1.1 linux/drivers/scsi/g_NCR5380.c:1.2
*** linux/drivers/scsi/g_NCR5380.c:1.1.1.1	Sun May 18 19:18:10 1997
--- linux/drivers/scsi/g_NCR5380.c	Wed Jun  4 08:58:19 1997
***************
*** 617,623 ****
      unsigned char status;
      int i;
      struct Scsi_Host *scsi_ptr;
! 	Scsi_Device *dev;
      Scsi_Cmnd *ptr;
      struct NCR5380_hostdata *hostdata;
      extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
--- 617,623 ----
      unsigned char status;
      int i;
      struct Scsi_Host *scsi_ptr;
!     Scsi_Device *dev;
      Scsi_Cmnd *ptr;
      struct NCR5380_hostdata *hostdata;
      extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
Index: linux/drivers/scsi/g_NCR5380.h
diff -c linux/drivers/scsi/g_NCR5380.h:1.1.1.1 linux/drivers/scsi/g_NCR5380.h:1.2
*** linux/drivers/scsi/g_NCR5380.h:1.1.1.1	Sun May 18 19:18:10 1997
--- linux/drivers/scsi/g_NCR5380.h	Sun May 18 19:27:12 1997
***************
*** 72,87 ****
  
  #if defined(HOSTS_C) || defined(MODULE)
  
! #define GENERIC_NCR5380 {NULL, NULL, NULL, 	 			\
! 	generic_NCR5380_proc_info,					\
! 	"Generic NCR5380/NCR53C400 Scsi Driver", 			\
! 	generic_NCR5380_detect, generic_NCR5380_release_resources,	\
! 	(void *)generic_NCR5380_info, NULL,				\
! 	generic_NCR5380_queue_command, generic_NCR5380_abort, 		\
! 	generic_NCR5380_reset, NULL,					\
! 	NCR5380_BIOSPARAM,						\
! 	/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,			\
! 	/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
  
  #endif
  
--- 72,92 ----
  
  #if defined(HOSTS_C) || defined(MODULE)
  
! #define GENERIC_NCR5380 {						\
! 	proc_info:      generic_NCR5380_proc_info,			\
! 	name:           "Generic NCR5380/NCR53C400 Scsi Driver",	\
! 	detect:         generic_NCR5380_detect,				\
! 	release:        generic_NCR5380_release_resources,		\
! 	info:           (void *)generic_NCR5380_info,			\
! 	queuecommand:   generic_NCR5380_queue_command,			\
! 	abort:          generic_NCR5380_abort,				\
! 	reset:          generic_NCR5380_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}
  
  #endif
  
Index: linux/drivers/scsi/gvp11.h
diff -c linux/drivers/scsi/gvp11.h:1.1.1.1 linux/drivers/scsi/gvp11.h:1.2
*** linux/drivers/scsi/gvp11.h:1.1.1.1	Sun May 18 19:18:15 1997
--- linux/drivers/scsi/gvp11.h	Sun May 18 19:27:13 1997
***************
*** 34,60 ****
  
  extern struct proc_dir_entry proc_scsi_gvp11;
  
! #define GVP11_SCSI {  /* next */                NULL,            \
! 		      /* module */              NULL,	         \
!                       /* proc_dir_entry */      &proc_scsi_gvp11, \
! 		      /* proc_info */           NULL,            \
! 		      /* name */                "GVP Series II SCSI", \
! 		      /* detect */              gvp11_detect,    \
! 		      /* release */             gvp11_release,   \
! 		      /* info */                NULL,	         \
! 		      /* command */             NULL,            \
! 		      /* queuecommand */        wd33c93_queuecommand, \
! 		      /* abort */               wd33c93_abort,   \
! 		      /* reset */               wd33c93_reset,   \
! 		      /* slave_attach */        NULL,            \
! 		      /* bios_param */          NULL, 	         \
! 		      /* can_queue */           CAN_QUEUE,       \
! 		      /* this_id */             7,               \
! 		      /* sg_tablesize */        SG_ALL,          \
! 		      /* cmd_per_lun */	        CMD_PER_LUN,     \
! 		      /* present */             0,               \
! 		      /* unchecked_isa_dma */   0,               \
! 		      /* use_clustering */      DISABLE_CLUSTERING }
  #else
  
  /*
--- 34,51 ----
  
  extern struct proc_dir_entry proc_scsi_gvp11;
  
! #define GVP11_SCSI {  proc_dir:		   &proc_scsi_gvp11, \
! 		      name:                "GVP Series II SCSI", \
! 		      detect:              gvp11_detect,    \
! 		      release:             gvp11_release,   \
! 		      queuecommand:        wd33c93_queuecommand, \
! 		      abort:               wd33c93_abort,   \
! 		      reset:               wd33c93_reset,   \
! 		      can_queue:           CAN_QUEUE,       \
! 		      this_id:             7,               \
! 		      sg_tablesize:        SG_ALL,          \
! 		      cmd_per_lun:	   CMD_PER_LUN,     \
! 		      use_clustering:      DISABLE_CLUSTERING }
  #else
  
  /*
Index: linux/drivers/scsi/hosts.c
diff -c linux/drivers/scsi/hosts.c:1.1.1.3 linux/drivers/scsi/hosts.c:1.5
*** linux/drivers/scsi/hosts.c:1.1.1.3	Wed May 28 07:54:06 1997
--- linux/drivers/scsi/hosts.c	Wed May 28 08:37:29 1997
***************
*** 16,26 ****
   *  hosts currently present in the system.
   */
  
- /*
-  * Don't import our own symbols, as this would severely mess up our
-  * symbol tables.
-  */
- #define _SCSI_SYMS_VER_
  #define __NO_VERSION__
  #include <linux/module.h>
  
--- 16,21 ----
***************
*** 32,37 ****
--- 27,36 ----
  #include <linux/proc_fs.h>
  #include <linux/init.h>
  
+ #define __KERNEL_SYSCALLS__
+ 
+ #include <linux/unistd.h>
+ 
  #include "scsi.h"
  
  #ifndef NULL
***************
*** 389,395 ****
--- 388,396 ----
      struct Scsi_Host * retval, *shpnt;
      retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
  						  (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
+     atomic_set(&retval->host_active,0);
      retval->host_busy = 0;
+     retval->host_failed = 0;
      retval->block = NULL;
      retval->wish_block = 0;
      if(j > 0xffff) panic("Too many extra bytes requested\n");
***************
*** 412,417 ****
--- 413,422 ----
      retval->io_port = 0;
      retval->hostt = tpnt;
      retval->next = NULL;
+     retval->in_recovery = 0;
+     retval->ehandler = NULL;    /* Initial value until the thing starts up. */
+     retval->eh_notify   = NULL;    /* Who we notify when we exit. */
+ 
  #ifdef DEBUG
      printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
  #endif
***************
*** 498,503 ****
--- 503,517 ----
  	    name = shpnt->hostt->name;
  	printk ("scsi%d : %s\n", /* And print a little message */
  		shpnt->host_no, name);
+ 
+         /*
+          * Now start the error recovery thread for the host.
+          */
+         if( shpnt->hostt->use_new_eh_code )
+         {
+             kernel_thread((int (*)(void *))scsi_error_handler, 
+                           (void *) shpnt, 0);
+         }
      }
      
      printk ("scsi : %d host%s.\n", next_scsi_host,
Index: linux/drivers/scsi/hosts.h
diff -c linux/drivers/scsi/hosts.h:1.1.1.1 linux/drivers/scsi/hosts.h:1.3
*** linux/drivers/scsi/hosts.h:1.1.1.1	Sun May 18 19:18:08 1997
--- linux/drivers/scsi/hosts.h	Wed May 28 08:37:29 1997
***************
*** 127,136 ****
--- 127,160 ----
       * # and exit result when the command is complete.
       * Host number is the POSITION IN THE hosts array of THIS
       * host adapter.
+      *
+      * The done() function must only be called after QueueCommand() 
+      * has returned.
       */
      int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
  
      /*
+      * This is an error handling strategy routine.  You don't need to
+      * define one of these if you don't want to - there is a default
+      * routine that is present that should work in most cases.  For those
+      * driver authors that have the inclination and ability to write their
+      * own strategy routine, this is where it is specified.  Note - the
+      * strategy routine is *ALWAYS* run in the context of the kernel eh
+      * thread.  Thus you are guaranteed to *NOT* be in an interrupt handler
+      * when you execute this, and you are also guaranteed to *NOT* have any
+      * other commands being queued while you are in the strategy routine.
+      * When you return from this function, operations return to normal.
+      *
+      * See scsi_error.c scsi_unjam_host for additional comments about what
+      * this function should and should not be attempting to do.
+      */
+      int (*eh_strategy_handler)(struct Scsi_Host *);
+      int (*eh_abort_handler)(Scsi_Cmnd *);
+      int (*eh_device_reset_handler)(Scsi_Cmnd *);
+      int (*eh_bus_reset_handler)(Scsi_Cmnd *);
+      int (*eh_host_reset_handler)(Scsi_Cmnd *);
+ 
+     /*
       * Since the mid level driver handles time outs, etc, we want to
       * be able to abort the current command.  Abort returns 0 if the
       * abortion was successful.	 The field SCpnt->abort reason
***************
*** 143,148 ****
--- 167,175 ----
       *
       * Note that the scsi driver should "clean up" after itself,
       * resetting the bus, etc.	if necessary.
+      *
+      * NOTE - this interface is depreciated, and will go away.  Use
+      * the eh_ routines instead.
       */
      int (* abort)(Scsi_Cmnd *);
  
***************
*** 155,160 ****
--- 182,190 ----
       * the first place.	 Some hosts do not implement a reset function,
       * and these hosts must call scsi_request_sense(SCpnt) to keep
       * the command alive.
+      *
+      * NOTE - this interface is depreciated, and will go away.  Use
+      * the eh_ routines instead.
       */
      int (* reset)(Scsi_Cmnd *, unsigned int);
  
***************
*** 227,232 ****
--- 257,269 ----
       */
      unsigned use_clustering:1;
  
+     /*
+      * True if this driver uses the new error handling code.  This flag is
+      * really only temporary until all of the other drivers get converted
+      * to use the new error handling code.
+      */
+     unsigned use_new_eh_code:1;
+ 
  } Scsi_Host_Template;
  
  /*
***************
*** 240,253 ****
  
  struct Scsi_Host
  {
!     struct Scsi_Host * next;
      unsigned short extra_bytes;
!     volatile unsigned char host_busy;
!     char host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
      unsigned long last_reset;
!     struct wait_queue *host_wait;
!     Scsi_Cmnd *host_queue;
!     Scsi_Host_Template * hostt;
  
      /*
       *	These three parameters can be used to allow for wide scsi,
--- 277,308 ----
  
  struct Scsi_Host
  {
! /* private: */
!     /*
!      * This information is private to the scsi mid-layer.  Wrapping it in a
!      * struct private is a way of marking it in a sort of C++ type of way.
!      */
!     struct Scsi_Host      * next;
!     Scsi_Device           * host_queue;
!     struct task_struct    * ehandler;  /* Error recovery thread. */
!     struct semaphore      * eh_wait;   /* The error recovery thread waits on
!                                           this. */
!     struct semaphore      * eh_notify; /* wait for eh to begin */
!     struct semaphore      * eh_action; /* Wait for specific actions on the
!                                           host. */
!     unsigned int            eh_active:1; /* Indicates the eh thread is awake and active if
!                                           this is true. */
!     struct wait_queue     * host_wait;
!     Scsi_Host_Template    * hostt;
!     atomic_t                host_active; /* commands checked out */
!     volatile unsigned short host_busy;   /* commands actually active on low-level */
!     volatile unsigned short host_failed; /* commands that failed. */
!     
! /* public: */
      unsigned short extra_bytes;
!     unsigned short host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
      unsigned long last_reset;
! 
  
      /*
       *	These three parameters can be used to allow for wide scsi,
***************
*** 292,297 ****
--- 347,354 ----
      int can_queue;
      short cmd_per_lun;
      short unsigned int sg_tablesize;
+ 
+     unsigned in_recovery:1;
      unsigned unchecked_isa_dma:1;
      unsigned use_clustering:1;
      /*
Index: linux/drivers/scsi/ibmmca.h
diff -c linux/drivers/scsi/ibmmca.h:1.1.1.1 linux/drivers/scsi/ibmmca.h:1.2
*** linux/drivers/scsi/ibmmca.h:1.1.1.1	Sun May 18 19:18:16 1997
--- linux/drivers/scsi/ibmmca.h	Sun May 18 19:27:14 1997
***************
*** 19,46 ****
  extern struct proc_dir_entry proc_scsi_ibmmca;
  
  /*initialization for Scsi_host_template type */
! #define IBMMCA {                                      \
!           NULL,                 /*next*/              \
!           NULL,                 /*module*/	      \
!           &proc_scsi_ibmmca,    /*proc_dir*/          \
!           NULL,                 /*proc info fn*/      \
!           "IBMMCA",             /*name*/              \
!           ibmmca_detect,        /*detect fn*/         \
!           ibmmca_release,       /*release fn*/        \
!           NULL,                 /*info fn*/           \
!           ibmmca_command,       /*command fn*/        \
!           ibmmca_queuecommand,  /*queuecommand fn*/   \
!           ibmmca_abort,         /*abort fn*/          \
!           ibmmca_reset,         /*reset fn*/          \
!           NULL,                 /*slave_attach fn*/   \
!           ibmmca_biosparam,     /*bios fn*/           \
!           16,                   /*can_queue*/         \
!           7,                    /*set by detect*/     \
!           16,                   /*sg_tablesize*/      \
!           1,                    /*cmd_per_lun*/       \
!           0,                    /*present*/           \
!           0,                    /*unchecked_isa_dma*/ \
!           ENABLE_CLUSTERING     /*use_clustering*/    \
          }
  
  #endif /* _IBMMCA_H */
--- 19,39 ----
  extern struct proc_dir_entry proc_scsi_ibmmca;
  
  /*initialization for Scsi_host_template type */
! #define IBMMCA {						      \
!           proc_dir:       &proc_scsi_ibmmca,    /*proc_dir*/          \
!           name:           "IBMMCA",             /*name*/              \
!           detect:         ibmmca_detect,        /*detect fn*/         \
!           release:        ibmmca_release,       /*release fn*/        \
!           command:        ibmmca_command,       /*command fn*/        \
!           queuecommand:   ibmmca_queuecommand,  /*queuecommand fn*/   \
!           abort:          ibmmca_abort,         /*abort fn*/          \
!           reset:          ibmmca_reset,         /*reset fn*/          \
!           bios_param:     ibmmca_biosparam,     /*bios fn*/           \
!           can_queue:      16,                   /*can_queue*/         \
!           this_id:        7,                    /*set by detect*/     \
!           sg_tablesize:   16,                   /*sg_tablesize*/      \
!           cmd_per_lun:    1,                    /*cmd_per_lun*/       \
!           use_clustering: ENABLE_CLUSTERING     /*use_clustering*/    \
          }
  
  #endif /* _IBMMCA_H */
Index: linux/drivers/scsi/ide-scsi.h
diff -c linux/drivers/scsi/ide-scsi.h:1.1.1.1 linux/drivers/scsi/ide-scsi.h:1.2
*** linux/drivers/scsi/ide-scsi.h:1.1.1.1	Sun May 18 19:18:16 1997
--- linux/drivers/scsi/ide-scsi.h	Sun May 18 19:27:14 1997
***************
*** 14,41 ****
  extern int idescsi_abort (Scsi_Cmnd *cmd);
  extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
  
! #define IDESCSI								\
! {	NULL,			/* next		*/			\
! 	NULL,			/* module	*/			\
! 	NULL,			/* proc_dir	*/			\
! 	NULL,			/* proc_info	*/			\
! 	"idescsi",		/* name		*/			\
! 	idescsi_detect,		/* detect	*/			\
! 	idescsi_release,	/* release	*/			\
! 	idescsi_info,		/* info		*/			\
! 	NULL,			/* command	*/			\
! 	idescsi_queue,		/* queuecommand */			\
! 	idescsi_abort,		/* abort	*/			\
! 	idescsi_reset,		/* reset	*/			\
! 	NULL,			/* slave_attach	*/			\
! 	NULL,			/* bios_param	*/			\
! 	10,			/* can_queue	*/			\
! 	-1,			/* this_id	*/			\
! 	256,			/* sg_tablesize	*/			\
! 	5,			/* cmd_per_lun	*/			\
! 	0,			/* present	*/			\
! 	0,			/* isa_dma	*/			\
! 	DISABLE_CLUSTERING	/* clustering	*/			\
  }
  
  #endif /* IDESCSI_H */
--- 14,32 ----
  extern int idescsi_abort (Scsi_Cmnd *cmd);
  extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
  
! #define IDESCSI  {								\
! 	name:            "idescsi",		/* name		*/		\
! 	detect:          idescsi_detect,	/* detect	*/		\
! 	release:         idescsi_release,	/* release	*/		\
! 	info:            idescsi_info,		/* info		*/		\
! 	queuecommand:    idescsi_queue,		/* queuecommand */		\
! 	abort:           idescsi_abort,		/* abort	*/		\
! 	reset:           idescsi_reset,		/* reset	*/		\
! 	can_queue:       10,			/* can_queue	*/		\
! 	this_id:         -1,			/* this_id	*/		\
! 	sg_tablesize:    256,			/* sg_tablesize	*/		\
! 	cmd_per_lun:     5,			/* cmd_per_lun	*/		\
! 	use_clustering:  DISABLE_CLUSTERING	/* clustering	*/		\
  }
  
  #endif /* IDESCSI_H */
Index: linux/drivers/scsi/in2000.h
diff -c linux/drivers/scsi/in2000.h:1.1.1.1 linux/drivers/scsi/in2000.h:1.3
*** linux/drivers/scsi/in2000.h:1.1.1.1	Sun May 18 19:18:11 1997
--- linux/drivers/scsi/in2000.h	Thu Jun  5 23:30:39 1997
***************
*** 39,65 ****
  #define IN2000_CPL      2
  #define IN2000_HOST_ID  7
  
! #define IN2000 {  NULL,                /* link pointer for modules */ \
!                   NULL,                /* module pointer for modules */ \
!                   &proc_scsi_in2000,   /* pointer to /proc/scsi directory entry */ \
!                   in2000_proc_info,    /* pointer to proc info function */ \
!                   "Always IN2000",     /* device name */ \
!                   in2000_detect,       /* returns number of in2000's found */ \
!                   NULL,                /* optional unload function for modules */ \
!                   NULL,                /* optional misc info function */ \
!                   NULL,                /* send scsi command, wait for completion */ \
!                   in2000_queuecommand, /* queue scsi command, don't wait */ \
!                   in2000_abort,        /* abort current command */ \
!                   in2000_reset,        /* reset scsi bus */ \
!                   NULL,                /* slave_attach - unused */ \
!                   in2000_biosparam,    /* figures out BIOS parameters for lilo, etc */ \
!                   IN2000_CAN_Q,        /* max commands we can queue up */ \
!                   IN2000_HOST_ID,      /* host-adapter scsi id */ \
!                   IN2000_SG,           /* scatter-gather table size */ \
!                   IN2000_CPL,          /* commands per lun */ \
!                   0,                   /* board counter */ \
!                   0,                   /* unchecked dma */ \
!                   DISABLE_CLUSTERING \
                 }
  
  
--- 39,58 ----
  #define IN2000_CPL      2
  #define IN2000_HOST_ID  7
  
! #define IN2000 {  proc_dir:        &proc_scsi_in2000,   /* pointer to /proc/scsi directory entry */ \
!                   proc_info:       in2000_proc_info,    /* pointer to proc info function */ \
!                   name:            "Always IN2000",     /* device name */ \
!                   detect:          in2000_detect,       /* returns number of in2000's found */ \
!                   queuecommand:    in2000_queuecommand, /* queue scsi command, don't wait */ \
!                   abort:           in2000_abort,        /* abort current command */ \
!                   reset:           in2000_reset,        /* reset scsi bus */ \
!                   bios_param:      in2000_biosparam,    /* figures out BIOS parameters for lilo, etc */ \
!                   can_queue:       IN2000_CAN_Q,        /* max commands we can queue up */ \
!                   this_id:         IN2000_HOST_ID,      /* host-adapter scsi id */ \
!                   sg_tablesize:    IN2000_SG,           /* scatter-gather table size */ \
!                   cmd_per_lun:     IN2000_CPL,          /* commands per lun */ \
!                   use_clustering:  DISABLE_CLUSTERING, \
! 		  use_new_eh_code: 1			/* Enable new error code */ \
                 }
  
  
Index: linux/drivers/scsi/ncr53c8xx.h
diff -c linux/drivers/scsi/ncr53c8xx.h:1.1.1.2 linux/drivers/scsi/ncr53c8xx.h:1.3
*** linux/drivers/scsi/ncr53c8xx.h:1.1.1.2	Sun May 18 19:35:49 1997
--- linux/drivers/scsi/ncr53c8xx.h	Sun May 18 20:19:58 1997
***************
*** 275,301 ****
  #define ncr53c8xx_release NULL
  #endif
  
! #if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
! 
! #define NCR53C8XX {NULL,NULL,NULL,NULL,SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect,\
!     	ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, 		\
! 	ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset,	\
!         NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\
! 	/* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN, 		\
!         /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
! 
! 
! #else
! 
! 
! #define NCR53C8XX {NULL, NULL, SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect,\
!     	ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, 		\
! 	ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset,	\
!         NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\
! 	/* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN, 		\
!         /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
! 
! #endif /* LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) */
  
  #endif /* defined(HOSTS_C) || defined(MODULE) */ 
  
--- 275,293 ----
  #define ncr53c8xx_release NULL
  #endif
  
! #define NCR53C8XX {     name:           SCSI_NCR_DRIVER_NAME,	\
! 			detect:         ncr53c8xx_detect,	\
! 			release:        ncr53c8xx_release,	\
! 			queuecommand:   ncr53c8xx_queue_command,\
! 			abort:          ncr53c8xx_abort,	\
! 			reset:          ncr53c8xx_reset,	\
! 			bios_param:     scsicam_bios_param,	\
! 			can_queue:      SCSI_NCR_CAN_QUEUE,	\
! 			this_id:        7,			\
! 			sg_tablesize:   SCSI_NCR_SG_TABLESIZE,	\
! 			cmd_per_lun:    SCSI_NCR_CMD_PER_LUN,	\
! 			use_clustering: DISABLE_CLUSTERING} 
!   
  
  #endif /* defined(HOSTS_C) || defined(MODULE) */ 
  
Index: linux/drivers/scsi/pas16.h
diff -c linux/drivers/scsi/pas16.h:1.1.1.1 linux/drivers/scsi/pas16.h:1.2
*** linux/drivers/scsi/pas16.h:1.1.1.1	Sun May 18 19:18:10 1997
--- linux/drivers/scsi/pas16.h	Sun May 18 19:27:15 1997
***************
*** 142,154 ****
  
  #if defined(HOSTS_C) || defined(MODULE)
  
! #define MV_PAS16 {NULL, NULL, NULL, NULL, \
! 	"Pro Audio Spectrum-16 SCSI", 		\
! 	pas16_detect, NULL, NULL,					\
! 	NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL, 	\
! 	pas16_biosparam, 						\
! 	/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,			\
! 	/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
  
  #endif
  #ifndef HOSTS_C
--- 142,159 ----
  
  #if defined(HOSTS_C) || defined(MODULE)
  
! #define MV_PAS16 {					\
! 	name:           "Pro Audio Spectrum-16 SCSI", 	\
! 	detect:         pas16_detect, 			\
! 	queuecommand:   pas16_queue_command,		\
! 	abort:          pas16_abort,			\
! 	reset:          pas16_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}
  
  #endif
  #ifndef HOSTS_C
Index: linux/drivers/scsi/ppa.h
diff -c linux/drivers/scsi/ppa.h:1.1.1.1 linux/drivers/scsi/ppa.h:1.2
*** linux/drivers/scsi/ppa.h:1.1.1.1	Sun May 18 19:18:14 1997
--- linux/drivers/scsi/ppa.h	Sun May 18 19:27:15 1997
***************
*** 65,90 ****
  {PROC_SCSI_PPA, 3, "ppa", S_IFDIR | S_IRUGO | S_IXUGO, 2};
  #endif /* !PPA_CODE => hosts.c */
  
! #define PPA {	/* next */	 	0, \
! 		/* usage_count */	0, \
! 		/* proc_dir */		&proc_scsi_ppa, \
! 		/* proc_info */		ppa_proc_info, \
! 		/* name */		"Iomega ZIP/JAZ Traveller", \
! 		/* detect */		ppa_detect, \
! 		/* release */		ppa_release, \
! 		/* info */		0, \
! 		/* command */		ppa_command, \
! 		/* queuecommand */	ppa_queuecommand, \
! 		/* abort */		ppa_abort, \
! 		/* reset */		ppa_reset, \
! 		/* slave_attach */	0, \
! 		/* bios_param */	ppa_biosparam, \
! 		/* can_queue */		0, \
! 		/* this_id */		PPA_INITIATOR, \
! 		/* sg_tablesize */	SG_ALL, \
! 		/* cmd_per_lun */	1, \
! 		/* present */		0, \
! 		/* unchecked_isa_dma */	0, \
! 		/* use_clustering */	ENABLE_CLUSTERING \
  }
  #endif				/* _PPA_H */
--- 65,83 ----
  {PROC_SCSI_PPA, 3, "ppa", S_IFDIR | S_IRUGO | S_IXUGO, 2};
  #endif /* !PPA_CODE => hosts.c */
  
! #define PPA {	proc_dir:		&proc_scsi_ppa,			\
! 		proc_info:		ppa_proc_info,			\
! 		name:			"Iomega ZIP/JAZ Traveller",	\
! 		detect:			ppa_detect,			\
! 		release:		ppa_release,			\
! 		command:		ppa_command,			\
! 		queuecommand:		ppa_queuecommand,		\
! 		abort:			ppa_abort,			\
! 		reset:			ppa_reset,			\
! 		bios_param:		ppa_biosparam,			\
! 		this_id:		PPA_INITIATOR,			\
! 		sg_tablesize:		SG_ALL,				\
! 		cmd_per_lun:		1,				\
! 		use_clustering:		ENABLE_CLUSTERING		\
  }
  #endif				/* _PPA_H */
Index: linux/drivers/scsi/qlogicfas.h
diff -c linux/drivers/scsi/qlogicfas.h:1.1.1.1 linux/drivers/scsi/qlogicfas.h:1.2
*** linux/drivers/scsi/qlogicfas.h:1.1.1.1	Sun May 18 19:18:16 1997
--- linux/drivers/scsi/qlogicfas.h	Sun May 18 19:27:17 1997
***************
*** 14,40 ****
  #endif
  
  #define QLOGICFAS {		\
! 	NULL,			\
! 	NULL,			\
! 	NULL,			\
! 	NULL,		        \
! 	NULL,			\
! 	qlogicfas_detect,	\
! 	NULL,			\
! 	qlogicfas_info,		\
! 	qlogicfas_command, 	\
! 	qlogicfas_queuecommand,	\
! 	qlogicfas_abort,	\
! 	qlogicfas_reset,	\
! 	NULL,			\
! 	qlogicfas_biosparam,	\
! 	0,			\
! 	-1,			\
! 	SG_ALL,			\
! 	1,			\
! 	0,			\
! 	0,			\
! 	DISABLE_CLUSTERING	\
  }
  
  #endif /* _QLOGICFAS_H */
--- 14,31 ----
  #endif
  
  #define QLOGICFAS {		\
! 	detect:         qlogicfas_detect,	\
! 	info:           qlogicfas_info,		\
! 	command:        qlogicfas_command, 	\
! 	queuecommand:   qlogicfas_queuecommand,	\
! 	abort:          qlogicfas_abort,	\
! 	reset:          qlogicfas_reset,	\
! 	bios_param:     qlogicfas_biosparam,	\
! 	can_queue:      0,			\
! 	this_id:        -1,			\
! 	sg_tablesize:   SG_ALL,			\
! 	cmd_per_lun:    1,			\
! 	use_clustering: DISABLE_CLUSTERING	\
  }
  
  #endif /* _QLOGICFAS_H */
Index: linux/drivers/scsi/qlogicisp.h
diff -c linux/drivers/scsi/qlogicisp.h:1.1.1.1 linux/drivers/scsi/qlogicisp.h:1.2
*** linux/drivers/scsi/qlogicisp.h:1.1.1.1	Sun May 18 19:18:15 1997
--- linux/drivers/scsi/qlogicisp.h	Sun May 18 19:27:17 1997
***************
*** 73,99 ****
  extern struct proc_dir_entry proc_scsi_isp1020;
  
  #define QLOGICISP {							   \
! 	/* next */		NULL,					   \
! 	/* module */		NULL,					   \
! 	/* proc dir */		NULL,					   \
! 	/* procfs info */	NULL,					   \
! 	/* name */		NULL,					   \
! 	/* detect */		isp1020_detect,				   \
! 	/* release */		isp1020_release,			   \
! 	/* info */		isp1020_info,				   \
! 	/* command */		NULL,					   \
! 	/* queuecommand */	isp1020_queuecommand,			   \
! 	/* abort */		isp1020_abort,				   \
! 	/* reset */		isp1020_reset,				   \
! 	/* slave_attach */	NULL,					   \
! 	/* bios_param */	isp1020_biosparam,			   \
! 	/* can_queue */		QLOGICISP_REQ_QUEUE_LEN,		   \
! 	/* this_id */		-1,					   \
! 	/* sg_tablesize */	QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
! 	/* cmd_per_lun */	1,					   \
! 	/* present */		0,					   \
! 	/* unchecked_isa_dma */	0,					   \
! 	/* use_clustering */	DISABLE_CLUSTERING			   \
  }
  
  #endif /* _QLOGICISP_H */
--- 73,92 ----
  extern struct proc_dir_entry proc_scsi_isp1020;
  
  #define QLOGICISP {							   \
! 	detect:			isp1020_detect,				   \
! 	release:		isp1020_release,			   \
! 	info:			isp1020_info,				   \
! 	queuecommand:		isp1020_queuecommand,			   \
! 	abort:			isp1020_abort,				   \
! 	reset:			isp1020_reset,				   \
! 	bios_param:		isp1020_biosparam,			   \
! 	can_queue:		QLOGICISP_REQ_QUEUE_LEN,		   \
! 	this_id:		-1,					   \
! 	sg_tablesize:		QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
! 	cmd_per_lun:		1,					   \
! 	present:		0,					   \
! 	unchecked_isa_dma:	0,					   \
! 	use_clustering:		DISABLE_CLUSTERING			   \
  }
  
  #endif /* _QLOGICISP_H */
Index: linux/drivers/scsi/qlogicpti.h
diff -c linux/drivers/scsi/qlogicpti.h:1.1.1.1 linux/drivers/scsi/qlogicpti.h:1.2
*** linux/drivers/scsi/qlogicpti.h:1.1.1.1	Sun May 18 19:18:16 1997
--- linux/drivers/scsi/qlogicpti.h	Sun May 18 19:27:17 1997
***************
*** 717,744 ****
  #define HCCTRL_B1ENAB           0x0008      /* Breakpoint 1 enable              */
  #define HCCTRL_B0ENAB           0x0004      /* Breakpoint 0 enable              */
  
! #define QLOGICPTI {							   \
! 	/* next */		NULL,					   \
! 	/* module */		NULL,					   \
! 	/* proc dir */		NULL,					   \
! 	/* procfs info */	NULL,					   \
! 	/* name */		NULL,					   \
! 	/* detect */		qlogicpti_detect,			   \
! 	/* release */		qlogicpti_release,			   \
! 	/* info */		qlogicpti_info,				   \
! 	/* command */		NULL,					   \
! 	/* queuecommand */	qlogicpti_queuecommand,			   \
! 	/* abort */		qlogicpti_abort,			   \
! 	/* reset */		qlogicpti_reset,			   \
! 	/* slave_attach */	NULL,					   \
! 	/* bios_param */	NULL,			   		   \
! 	/* can_queue */		QLOGICISP_REQ_QUEUE_LEN,		   \
! 	/* this_id */		7,					   \
! 	/* sg_tablesize */	QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
! 	/* cmd_per_lun */	1,					   \
! 	/* present */		0,					   \
! 	/* unchecked_isa_dma */	0,					   \
! 	/* use_clustering */	DISABLE_CLUSTERING			   \
  }
  
  /* For our interrupt engine. */
--- 717,734 ----
  #define HCCTRL_B1ENAB           0x0008      /* Breakpoint 1 enable              */
  #define HCCTRL_B0ENAB           0x0004      /* Breakpoint 0 enable              */
  
! #define QLOGICPTI {						   \
! 	detect:		qlogicpti_detect,			   \
! 	release:	qlogicpti_release,			   \
! 	info:		qlogicpti_info,				   \
! 	queuecommand:	qlogicpti_queuecommand,			   \
! 	abort:		qlogicpti_abort,			   \
! 	reset:		qlogicpti_reset,			   \
! 	can_queue:	QLOGICISP_REQ_QUEUE_LEN,		   \
! 	this_id:	7,					   \
! 	sg_tablesize:	QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
! 	cmd_per_lun:	1,					   \
! 	use_clustering:	DISABLE_CLUSTERING			   \
  }
  
  /* For our interrupt engine. */
Index: linux/drivers/scsi/scsi.c
diff -c linux/drivers/scsi/scsi.c:1.1.1.1 linux/drivers/scsi/scsi.c:1.7
*** linux/drivers/scsi/scsi.c:1.1.1.1	Sun May 18 19:18:08 1997
--- linux/drivers/scsi/scsi.c	Thu Jun  5 23:30:40 1997
***************
*** 13,19 ****
   *      Tommy Thorn <tthorn>
   *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
   *
!  *  Modified by Eric Youngdale eric@aib.com to
   *  add scatter-gather, multiple outstanding request, and other
   *  enhancements.
   *
--- 13,19 ----
   *      Tommy Thorn <tthorn>
   *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
   *
!  *  Modified by Eric Youngdale eric@andante.jic.com.com or ericy@gnu.ai.mit.edu to
   *  add scatter-gather, multiple outstanding request, and other
   *  enhancements.
   *
***************
*** 29,40 ****
   *  Leonard N. Zubkoff <lnz@dandelion.com>
   */
  
- /*
-  * Don't import our own symbols, as this would severely mess up our
-  * symbol tables.
-  */
- #define _SCSI_SYMS_VER_
- 
  #include <linux/config.h>
  #include <linux/module.h>
  
--- 29,34 ----
***************
*** 50,55 ****
--- 44,53 ----
  #include <linux/delay.h>
  #include <linux/init.h>
  
+ #define __KERNEL_SYSCALLS__
+ 
+ #include <linux/unistd.h>
+ 
  #include <asm/system.h>
  #include <asm/irq.h>
  #include <asm/dma.h>
***************
*** 68,77 ****
  static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
  */
  
! 
! /* Command groups 3 and 4 are reserved and should never be used.  */
! const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };
! 
  #define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
  
  /*
--- 66,74 ----
  static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
  */
  
! /*
!  * Definitions and constants.
!  */
  #define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
  
  /*
***************
*** 89,115 ****
  # error You lose.
  #endif
  
! static void scsi_done (Scsi_Cmnd *SCpnt);
! int update_timeout (Scsi_Cmnd *, int);
! static void print_inquiry(unsigned char *data);
! static void scsi_times_out (Scsi_Cmnd * SCpnt);
! static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
!                  int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
!                  struct Scsi_Host *shpnt, char * scsi_result);
! void scsi_build_commandblocks(Scsi_Device * SDpnt);
  
  static FreeSectorBitmap * dma_malloc_freelist = NULL;
! static int scsi_need_isa_bounce_buffers;
! static unsigned int dma_sectors = 0;
! unsigned int dma_free_sectors = 0;
! unsigned int need_isa_buffer = 0;
! static unsigned char ** dma_malloc_pages = NULL;
  
- static int time_start;
- static int time_elapsed;
  static volatile struct Scsi_Host * host_active = NULL;
! #define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
! 			  || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
  
  const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
  {
--- 86,157 ----
  # error You lose.
  #endif
  
! #define MAX_SCSI_DEVICE_CODE 10
! 
! #ifdef DEBUG
!     #define SCSI_TIMEOUT (5*HZ)
! #else
!     #define SCSI_TIMEOUT (2*HZ)
! #endif
! 
! #define MIN_RESET_DELAY (2*HZ)
! 
! /* Do not call reset on error if we just did a reset within 15 sec. */
! #define MIN_RESET_PERIOD (15*HZ)
! 
! /* The following devices are known not to tolerate a lun != 0 scan for
!  * one reason or another.  Some will respond to all luns, others will
!  * lock up.
!  */
! 
! #define BLIST_NOLUN     0x01
! #define BLIST_FORCELUN  0x02
! #define BLIST_BORKEN    0x04
! #define BLIST_KEY       0x08
! #define BLIST_SINGLELUN 0x10
! #define BLIST_NOTQ	0x20
! #define BLIST_SPARSELUN 0x40
  
+ /*
+  * Data declarations.
+  */
+ Scsi_Device             * scsi_devices = NULL;
+ unsigned long             scsi_pid = 0;
+ Scsi_Cmnd               * last_cmnd = NULL;
+ /* Command groups 3 and 4 are reserved and should never be used.  */
+ const unsigned char       scsi_command_size[8] = { 6, 10, 10, 12, 
+                                                    12, 12, 10, 10 };
+ static unsigned long      serial_number = 0;
+ static Scsi_Cmnd        * scsi_bh_queue_head = NULL;
  static FreeSectorBitmap * dma_malloc_freelist = NULL;
! static int                need_isa_bounce_buffers;
! static unsigned int       dma_sectors = 0;
! unsigned int              scsi_dma_free_sectors = 0;
! unsigned int              scsi_need_isa_buffer = 0;
! static unsigned char   ** dma_malloc_pages = NULL;
! 
! /*
!  * Note - the initial logging level can be set here to log events at boot time.
!  * After the system is up, you may enable logging via the /proc interface.
!  */
! unsigned int              scsi_logging_level = 0;
  
  static volatile struct Scsi_Host * host_active = NULL;
! 
! #if CONFIG_PROC_FS
! /* 
!  * This is the pointer to the /proc/scsi code.
!  * It is only initialized to !=0 if the scsi code is present
!  */
! struct proc_dir_entry proc_scsi_scsi = {
!     PROC_SCSI_SCSI, 4, "scsi",
!     S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
!     NULL,
!     NULL, NULL,
!     NULL, NULL, NULL
! };
! #endif
! 
  
  const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
  {
***************
*** 125,216 ****
      "Communications   "
  };
  
! 
! /*
!  * global variables :
!  * scsi_devices an array of these specifying the address for each
!  * (host, id, LUN)
   */
- 
- Scsi_Device * scsi_devices = NULL;
- 
- /* Process ID of SCSI commands */
- unsigned long scsi_pid = 0;
- 
- static unsigned long serial_number = 0;
- 
- static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
  static void resize_dma_pool(void);
  
! /* This variable is merely a hook so that we can debug the kernel with gdb. */
! Scsi_Cmnd * last_cmnd = NULL;
! 
! /* This is the pointer to the /proc/scsi code.
!  * It is only initialized to !=0 if the scsi code is present
   */
  #if CONFIG_PROC_FS
  extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start,
  				      off_t offset, int length, int inout);
  extern int dispatch_scsi_info(int ino, char *buffer, char **start,
  			      off_t offset, int length, int inout);
- 
- struct proc_dir_entry proc_scsi_scsi = {
-     PROC_SCSI_SCSI, 4, "scsi",
-     S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
-     NULL,
-     NULL, NULL,
-     NULL, NULL, NULL
- };
  #endif
  
  /*
   *  This is the number  of clock ticks we should wait before we time out
   *  and abort the command.  This is for  where the scsi.c module generates
   *  the command, not where it originates from a higher level, in which
   *  case the timeout is specified there.
   *
-  *  ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
-  *  respectively.
   */
  
- #ifdef DEBUG_TIMEOUT
- static void scsi_dump_status(void);
- #endif
- 
- 
- #ifdef DEBUG
-     #define SCSI_TIMEOUT (5*HZ)
- #else
-     #define SCSI_TIMEOUT (2*HZ)
- #endif
- 
- #ifdef DEBUG
-     #define SENSE_TIMEOUT SCSI_TIMEOUT
-     #define ABORT_TIMEOUT SCSI_TIMEOUT
-     #define RESET_TIMEOUT SCSI_TIMEOUT
- #else
-     #define SENSE_TIMEOUT (5*HZ/10)
-     #define RESET_TIMEOUT (5*HZ/10)
-     #define ABORT_TIMEOUT (5*HZ/10)
- #endif
- 
- #define MIN_RESET_DELAY (2*HZ)
- 
- /* Do not call reset on error if we just did a reset within 15 sec. */
- #define MIN_RESET_PERIOD (15*HZ)
- 
- /* The following devices are known not to tolerate a lun != 0 scan for
-  * one reason or another.  Some will respond to all luns, others will
-  * lock up.
-  */
  
- #define BLIST_NOLUN     0x01
- #define BLIST_FORCELUN  0x02
- #define BLIST_BORKEN    0x04
- #define BLIST_KEY       0x08
- #define BLIST_SINGLELUN 0x10
- #define BLIST_NOTQ	0x20
- #define BLIST_SPARSELUN 0x40
  
  struct dev_info{
      const char * vendor;
--- 167,212 ----
      "Communications   "
  };
  
! /* 
!  * Function prototypes.
   */
  static void resize_dma_pool(void);
+ static void print_inquiry(unsigned char *data);
+ extern void scsi_times_out (Scsi_Cmnd * SCpnt);
+ static int  scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
+                  int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
+                  struct Scsi_Host *shpnt, char * scsi_result);
+ void        scsi_build_commandblocks(Scsi_Device * SDpnt);
  
! /*
!  * These are the interface to the old error handling code.  It should go away
!  * someday soon.
   */
+ extern void scsi_old_done (Scsi_Cmnd *SCpnt);
+ extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
+ 
  #if CONFIG_PROC_FS
  extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start,
  				      off_t offset, int length, int inout);
  extern int dispatch_scsi_info(int ino, char *buffer, char **start,
  			      off_t offset, int length, int inout);
  #endif
  
+ #define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
+ 			  || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
+ 
+ static void scsi_dump_status(int level);
+ 
+ 
  /*
   *  This is the number  of clock ticks we should wait before we time out
   *  and abort the command.  This is for  where the scsi.c module generates
   *  the command, not where it originates from a higher level, in which
   *  case the timeout is specified there.
   *
   */
  
  
  
  struct dev_info{
      const char * vendor;
***************
*** 310,316 ****
      return 0;
  }
  
! void scsi_make_blocked_list(void)  {
      int block_count = 0, index;
      unsigned long flags;
      struct Scsi_Host * sh[128], * shpnt;
--- 306,336 ----
      return 0;
  }
  
! /*
!  * Function:    scsi_make_blocked_list
!  *
!  * Purpose:     Build linked list of hosts that require blocking.
!  *
!  * Arguments:   None.
!  *
!  * Returns:     Nothing
!  *
!  * Notes:       Blocking is sort of a hack that is used to prevent more than one
!  *              host adapter from being active at one time.  This is used in cases
!  *              where the ISA bus becomes unreliable if you have more than one
!  *              host adapter really pumping data through.
!  *
!  *              We spent a lot of time examining the problem, and I *believe* that
!  *              the problem is bus related as opposed to being a driver bug.
!  *
!  *              The blocked list is used as part of the synchronization object
!  *              that we use to ensure that only one host is active at one time.
!  *              I (ERY) would like to make this go away someday, but this would
!  *              require that we have a recursive mutex object.
!  */
! void 
! scsi_make_blocked_list(void)  
! {
      int block_count = 0, index;
      unsigned long flags;
      struct Scsi_Host * sh[128], * shpnt;
***************
*** 372,393 ****
  static void scan_scsis_done (Scsi_Cmnd * SCpnt)
  {
  
! #ifdef DEBUG
!     printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
! #endif
      SCpnt->request.rq_status = RQ_SCSI_DONE;
  
      if (SCpnt->request.sem != NULL)
  	up(SCpnt->request.sem);
  }
  
  #ifdef CONFIG_SCSI_MULTI_LUN
  static int max_scsi_luns = 8;
  #else
  static int max_scsi_luns = 1;
  #endif
  
! void scsi_luns_setup(char *str, int *ints) {
      if (ints[0] != 1)
  	printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
      else
--- 392,422 ----
  static void scan_scsis_done (Scsi_Cmnd * SCpnt)
  {
  
!     SCSI_LOG_MLCOMPLETE(1,printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result));
      SCpnt->request.rq_status = RQ_SCSI_DONE;
  
      if (SCpnt->request.sem != NULL)
  	up(SCpnt->request.sem);
  }
  
+ void scsi_logging_setup(char *str, int *ints) 
+ {
+     if (ints[0] != 1) {
+ 	printk("scsi_logging_setup : usage scsi_logging_level=n "
+                "(n should be 0 or non-zero)\n");
+     } else {
+ 	scsi_logging_level = (ints[1])? ~0 : 0;
+     }
+ }
+ 
  #ifdef CONFIG_SCSI_MULTI_LUN
  static int max_scsi_luns = 8;
  #else
  static int max_scsi_luns = 1;
  #endif
  
! void scsi_luns_setup(char *str, int *ints) 
! {
      if (ints[0] != 1)
  	printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
      else
***************
*** 401,437 ****
   *  lun address of all sequential devices to the tape driver, all random
   *  devices to the disk driver.
   */
! static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
!                  unchar hchannel, unchar hid, unchar hlun)
! {
!   int dev, lun, channel;
!   unsigned char scsi_result0[256];
!   unsigned char *scsi_result;
!   Scsi_Device *SDpnt;
!   int max_dev_lun, sparse_lun;
!   Scsi_Cmnd *SCpnt;
  
    SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
-   SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
    memset (SCpnt, 0, sizeof (Scsi_Cmnd));
  
  
    /* Make sure we have something that is valid for DMA purposes */
    scsi_result = ( ( !shpnt->unchecked_isa_dma )
                   ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
  
!   if (scsi_result == NULL) {
!     printk ("Unable to obtain scsi_result buffer\n");
!     goto leave;
    }
  
!   /* We must chain ourself in the host_queue, so commands can time out */
!   if(shpnt->host_queue)
!       shpnt->host_queue->prev = SCpnt;
!   SCpnt->next = shpnt->host_queue;
!   SCpnt->prev = NULL;
!   shpnt->host_queue = SCpnt;
  
  
    if (hardcoded == 1) {
      Scsi_Device *oldSDpnt=SDpnt;
--- 430,501 ----
   *  lun address of all sequential devices to the tape driver, all random
   *  devices to the disk driver.
   */
! static void scan_scsis (struct Scsi_Host *shpnt, 
!                         unchar hardcoded,
!                         unchar hchannel, 
!                         unchar hid, 
!                         unchar hlun)
! {
!   int             channel;
!   int             dev;
!   int             lun;
!   int             max_dev_lun;
!   Scsi_Cmnd     * SCpnt;
!   unsigned char * scsi_result;
!   unsigned char   scsi_result0[256];
!   Scsi_Device   * SDpnt;
!   Scsi_Device   * SDtail;
!   int             sparse_lun;
  
    SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
    memset (SCpnt, 0, sizeof (Scsi_Cmnd));
  
+   SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
+   memset (SDpnt, 0, sizeof (Scsi_Device));
+ 
  
    /* Make sure we have something that is valid for DMA purposes */
    scsi_result = ( ( !shpnt->unchecked_isa_dma )
                   ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
  
!   if (scsi_result == NULL) 
!   {
!       printk ("Unable to obtain scsi_result buffer\n");
!       goto leave;
    }
  
!   /*
!    * We must chain ourself in the host_queue, so commands can time out 
!    */
!   SCpnt->next = NULL;
!   SDpnt->device_queue = SCpnt;
!   SDpnt->host = shpnt;
!   SDpnt->online = TRUE;
! 
!   /*
!    * Next, hook the device to the host in question.
!    */
!   SDpnt->prev = NULL;
!   SDpnt->next = shpnt->host_queue;
!   if( shpnt->host_queue != NULL )
!   {
!       SDtail = shpnt->host_queue;
!       while( SDtail->next != NULL )
!           SDtail = SDtail->next;
! 
!       SDtail->next = SDpnt;
!       SDpnt->prev = SDtail;
!   }
!   else
!   {
!       shpnt->host_queue = SDpnt;
!   }
  
+   /*
+    * We need to increment the counter for this one device so we can track when
+    * things are quiet.
+    */
+   atomic_inc(&shpnt->host_active); 
  
    if (hardcoded == 1) {
      Scsi_Device *oldSDpnt=SDpnt;
***************
*** 489,508 ****
      }                           /* for channel ends */
    } 				/* if/else hardcoded */
  
    leave:
  
    {/* Unchain SCpnt from host_queue */
!     Scsi_Cmnd *prev, *next, *hqptr;
!     for(hqptr = shpnt->host_queue; hqptr != SCpnt; hqptr = hqptr->next) ;
!     if(hqptr) {
!       prev = hqptr->prev;
!       next = hqptr->next;
!       if(prev)
!      	prev->next = next;
!       else
!      	shpnt->host_queue = next;
!       if(next) next->prev = prev;
!     }
    }
  
       /* Last device block does not exist.  Free memory. */
--- 553,582 ----
      }                           /* for channel ends */
    } 				/* if/else hardcoded */
  
+   /*
+    * We need to decrement the counter for this one device
+    * so we know when everything is quiet.
+    */
+   atomic_dec(&shpnt->host_active); 
+ 
    leave:
  
    {/* Unchain SCpnt from host_queue */
!       Scsi_Device *prev, *next;
!       Scsi_Device * dqptr;
!       
!       for(dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next) 
!           continue;
!       if(dqptr) 
!       {
!           prev = dqptr->prev;
!           next = dqptr->next;
!           if(prev)
!               prev->next = next;
!           else
!               shpnt->host_queue = next;
!           if(next) next->prev = prev;
!       }
    }
  
       /* Last device block does not exist.  Free memory. */
***************
*** 514,521 ****
  
      /* If we allocated a buffer so we could do DMA, free it now */
      if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
!       scsi_init_free (scsi_result, 512);
  
  }
  
  /*
--- 588,613 ----
  
      /* If we allocated a buffer so we could do DMA, free it now */
      if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
!     {
!         scsi_init_free (scsi_result, 512);
!     }
! 
!     {
!         int mm;
!         Scsi_Device * sdev;
!         Scsi_Cmnd   * scmd;
  
+         SCSI_LOG_SCAN_BUS(4,printk("Host status for host %p:\n", shpnt));
+         for(sdev = shpnt->host_queue; sdev; sdev = sdev->next)
+         {
+             SCSI_LOG_SCAN_BUS(4,printk("Device %d %p: ", sdev->id, sdev));
+             for(scmd=sdev->device_queue; scmd; scmd = scmd->next)
+             {
+                 SCSI_LOG_SCAN_BUS(4,printk("%p ", scmd));
+             }
+                 SCSI_LOG_SCAN_BUS(4,printk("\n", scmd));
+         }
+     }
  }
  
  /*
***************
*** 532,547 ****
    Scsi_Device * SDtail, *SDpnt=*SDpnt2;
    int bflags, type=-1;
  
-   SDtail = scsi_devices;
-   if (scsi_devices)
-     while (SDtail->next)
-       SDtail = SDtail->next;
- 
-   memset (SDpnt, 0, sizeof (Scsi_Device));
    SDpnt->host = shpnt;
    SDpnt->id = dev;
    SDpnt->lun = lun;
    SDpnt->channel = channel;
  
    /* Some low level driver could use device->type (DB) */
    SDpnt->type = -1;
--- 624,634 ----
    Scsi_Device * SDtail, *SDpnt=*SDpnt2;
    int bflags, type=-1;
  
    SDpnt->host = shpnt;
    SDpnt->id = dev;
    SDpnt->lun = lun;
    SDpnt->channel = channel;
+   SDpnt->online = TRUE;
  
    /* Some low level driver could use device->type (DB) */
    SDpnt->type = -1;
***************
*** 571,584 ****
                   (void *) scsi_result,
                   256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
      down (&sem);
    }
  
! #if defined(DEBUG) || defined(DEBUG_INIT)
!   printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
!           dev, lun, SCpnt->result);
!   print_driverbyte(SCpnt->result); print_hostbyte(SCpnt->result);
!   printk("\n");
! #endif
  
    if (SCpnt->result) {
      if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
--- 658,671 ----
                   (void *) scsi_result,
                   256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
      down (&sem);
+     SCpnt->request.sem = NULL;
    }
  
!   SCSI_LOG_SCAN_BUS(3,  printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
!           dev, lun, SCpnt->result));
!   SCSI_LOG_SCAN_BUS(3,print_driverbyte(SCpnt->result));
!   SCSI_LOG_SCAN_BUS(3,print_hostbyte(SCpnt->result));
!   SCSI_LOG_SCAN_BUS(3,printk("\n"));
  
    if (SCpnt->result) {
      if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
***************
*** 593,601 ****
        return 0;
    }
  
! #if defined (DEBUG) || defined(DEBUG_INIT)
!   printk ("scsi: performing INQUIRY\n");
! #endif
    /*
     * Build an INQUIRY command block.
     */
--- 680,686 ----
        return 0;
    }
  
!   SCSI_LOG_SCAN_BUS(3,printk ("scsi: performing INQUIRY\n"));
    /*
     * Build an INQUIRY command block.
     */
***************
*** 614,625 ****
                   (void *) scsi_result,
                   256, scan_scsis_done, SCSI_TIMEOUT, 3);
      down (&sem);
    }
  
! #if defined(DEBUG) || defined(DEBUG_INIT)
!   printk ("scsi: INQUIRY %s with code 0x%x\n",
!           SCpnt->result ? "failed" : "successful", SCpnt->result);
! #endif
  
    if (SCpnt->result)
      return 0;     /* assume no peripheral if any sort of error */
--- 699,709 ----
                   (void *) scsi_result,
                   256, scan_scsis_done, SCSI_TIMEOUT, 3);
      down (&sem);
+     SCpnt->request.sem = NULL;
    }
  
!   SCSI_LOG_SCAN_BUS(3,printk ("scsi: INQUIRY %s with code 0x%x\n",
!                               SCpnt->result ? "failed" : "successful", SCpnt->result));
  
    if (SCpnt->result)
      return 0;     /* assume no peripheral if any sort of error */
***************
*** 648,653 ****
--- 732,738 ----
    memcpy (SDpnt->rev, scsi_result + 32, 4);
  
    SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+   SDpnt->online = TRUE;
    SDpnt->lockable = SDpnt->removable;
    SDpnt->changed = 0;
    SDpnt->access_count = 0;
***************
*** 727,732 ****
--- 812,824 ----
      SDpnt->borken = 0;
  
    /*
+    * If we want to only allow I/O to one of the luns attached to this device
+    * at a time, then we set this flag.
+    */
+   if (bflags & BLIST_SINGLELUN)
+     SDpnt->single_lun = 1;
+ 
+   /*
     * These devices need this "key" to unlock the devices so we can use it
     */
    if ((bflags & BLIST_KEY) != 0) {
***************
*** 747,779 ****
                     (void *) scsi_result, 0x2a,
                     scan_scsis_done, SCSI_TIMEOUT, 3);
        down (&sem);
      }
    }
-   /* Add this device to the linked list at the end */
-   if (SDtail)
-     SDtail->next = SDpnt;
-   else
-     scsi_devices = SDpnt;
-   SDtail = SDpnt;
  
    SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
    *SDpnt2=SDpnt;
    if (!SDpnt)
!     printk ("scsi: scan_scsis_single: Cannot malloc\n");
  
  
    /*
!    * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
     */
!   if (bflags & BLIST_NOLUN)
!     return 0;                   /* break; */
  
    /*
!    * If we want to only allow I/O to one of the luns attached to this device
!    * at a time, then we set this flag.
     */
!   if (bflags & BLIST_SINGLELUN)
!     SDpnt->single_lun = 1;
  
    /*
     * If this device is known to support sparse multiple units, override the
--- 839,899 ----
                     (void *) scsi_result, 0x2a,
                     scan_scsis_done, SCSI_TIMEOUT, 3);
        down (&sem);
+       SCpnt->request.sem = NULL;
      }
    }
  
+   /*
+    * Detach the command from the device. It was just a temporary to be used while
+    * scanning the bus - the real ones will be allocated later.
+    */
+   SDpnt->device_queue = NULL;
+ 
+   /*
+    * This device was already hooked up to the host in question,
+    * so at this point we just let go of it and it should be fine.  We do need to
+    * allocate a new one and attach it to the host so that we can further scan the bus.
+    */
    SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
    *SDpnt2=SDpnt;
    if (!SDpnt)
!   {
!       printk ("scsi: scan_scsis_single: Cannot malloc\n");
!       return 0;
!   }
  
+   memset (SDpnt, 0, sizeof (Scsi_Device));
  
    /*
!    * And hook up our command block to the new device we will be testing
!    * for.
     */
!   SDpnt->device_queue = SCpnt;
!   SDpnt->online = TRUE;
  
    /*
!    * Since we just found one device, there had damn well better be one in the list
!    * already.
     */
!   if( shpnt->host_queue == NULL )
!       panic("scan_scsis_single: Host queue == NULL\n");
! 
!   SDtail = shpnt->host_queue;
!   while (SDtail->next)
!   {
!       SDtail = SDtail->next;
!   }
! 
!   /* Add this device to the linked list at the end */
!   SDtail->next = SDpnt;
!   SDpnt->prev = SDtail;
!   SDpnt->next = NULL;
! 
!   /*
!    * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
!    */
!   if (bflags & BLIST_NOLUN)
!     return 0;                   /* break; */
  
    /*
     * If this device is known to support sparse multiple units, override the
***************
*** 815,882 ****
  #define IN_RESET2 4
  #define IN_RESET3 8
  
- /*
-  * This is our time out function, called when the timer expires for a
-  * given host adapter.  It will attempt to abort the currently executing
-  * command, that failing perform a kernel panic.
-  */
- 
- static void scsi_times_out (Scsi_Cmnd * SCpnt)
- {
- 
-     switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
-     {
-     case NORMAL_TIMEOUT:
- 	{
- #ifdef DEBUG_TIMEOUT
- 	    scsi_dump_status();
- #endif
- 	}
- 
- 	if (!scsi_abort (SCpnt, DID_TIME_OUT))
- 	    return;
-     case IN_ABORT:
- 	printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
- 	       SCpnt->host->host_no, SCpnt->pid);
- 	if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
- 	    return;
-     case IN_RESET:
-     case (IN_ABORT | IN_RESET):
- 	/* This might be controversial, but if there is a bus hang,
- 	 * you might conceivably want the machine up and running
- 	 * esp if you have an ide disk.
- 	 */
- 	printk("SCSI host %d channel %d reset (pid %ld) timed out - "
-                "trying harder\n",
- 	       SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
- 	SCpnt->internal_timeout &= ~IN_RESET;
- 	SCpnt->internal_timeout |= IN_RESET2;
-         scsi_reset (SCpnt,
- 		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
-         return;
-     case (IN_ABORT | IN_RESET | IN_RESET2):
- 	/* Obviously the bus reset didn't work.
- 	 * Let's try even harder and call for an HBA reset.
-          * Maybe the HBA itself crashed and this will shake it loose.
- 	 */
- 	printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
- 	       SCpnt->host->host_no, SCpnt->pid);
- 	SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
- 	SCpnt->internal_timeout |= IN_RESET3;
-         scsi_reset (SCpnt,
- 		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
- 	return;
- 
-     default:
- 	printk("SCSI host %d reset (pid %ld) timed out again -\n",
- 	       SCpnt->host->host_no, SCpnt->pid);
- 	printk("probably an unrecoverable SCSI bus or device hang.\n");
- 	return;
- 
-     }
- 
- }
- 
  
  /* This function takes a quick look at a request, and decides if it
   * can be queued now, or if there would be a stall while waiting for
--- 935,940 ----
***************
*** 885,891 ****
   * of the calling code to ensure that this is the case.
   */
  
! Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
  {
      Scsi_Cmnd * SCpnt = NULL;
      int tablesize;
--- 943,949 ----
   * of the calling code to ensure that this is the case.
   */
  
! Scsi_Cmnd * scsi_request_queueable (struct request * req, Scsi_Device * device)
  {
      Scsi_Cmnd * SCpnt = NULL;
      int tablesize;
***************
*** 893,902 ****
      struct buffer_head * bh, *bhp;
  
      if (!device)
! 	panic ("No device passed to request_queueable().\n");
  
      if (req && req->rq_status == RQ_INACTIVE)
! 	panic("Inactive in request_queueable");
  
      /*
       * Look for a free command block.  If we have been instructed not to queue
--- 951,960 ----
      struct buffer_head * bh, *bhp;
  
      if (!device)
! 	panic ("No device passed to scsi_request_queueable().\n");
  
      if (req && req->rq_status == RQ_INACTIVE)
! 	panic("Inactive in scsi_request_queueable");
  
      /*
       * Look for a free command block.  If we have been instructed not to queue
***************
*** 908,917 ****
  	SCpnt = device->device_queue;
  	while(SCpnt){
  	    if(SCpnt->request.rq_status == RQ_INACTIVE) break;
! 	    SCpnt = SCpnt->device_next;
  	}
      } else {
! 	SCpnt = device->host->host_queue;
  	while(SCpnt){
  	    if(SCpnt->channel == device->channel
                  && SCpnt->target == device->id) {
--- 966,975 ----
  	SCpnt = device->device_queue;
  	while(SCpnt){
  	    if(SCpnt->request.rq_status == RQ_INACTIVE) break;
! 	    SCpnt = SCpnt->next;
  	}
      } else {
! 	SCpnt = device->device_queue;
  	while(SCpnt){
  	    if(SCpnt->channel == device->channel
                  && SCpnt->target == device->id) {
***************
*** 978,983 ****
--- 1036,1044 ----
  				      * either */
      }
  
+     atomic_inc(&SCpnt->host->host_active); 
+     SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target,
+                                atomic_read(&SCpnt->host->host_active)));
      SCpnt->use_sg = 0;               /* Reset the scatter-gather flag */
      SCpnt->old_use_sg  = 0;
      SCpnt->transfersize = 0;
***************
*** 990,995 ****
--- 1051,1058 ----
      SCpnt->channel = device->channel;
      SCpnt->lun = device->lun;
      SCpnt->target = device->id;
+     SCpnt->state = SCSI_STATE_INITIALIZING;
+     SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
  
      return SCpnt;
  }
***************
*** 1000,1010 ****
   * not to return a descriptor if the host is unable to accept any more
   * commands for the time being.  We need to keep in mind that there is no
   * guarantee that the host remain not busy.  Keep in mind the
!  * request_queueable function also knows the internal allocation scheme
   * of the packets for each device
   */
  
! Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
  			     int wait)
  {
      kdev_t dev;
--- 1063,1073 ----
   * not to return a descriptor if the host is unable to accept any more
   * commands for the time being.  We need to keep in mind that there is no
   * guarantee that the host remain not busy.  Keep in mind the
!  * scsi_request_queueable function also knows the internal allocation scheme
   * of the packets for each device
   */
  
! Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
  			     int wait)
  {
      kdev_t dev;
***************
*** 1018,1024 ****
      Scsi_Cmnd * found = NULL;
  
      if (!device)
! 	panic ("No device passed to allocate_device().\n");
  
      if (reqp) req = *reqp;
  
--- 1081,1087 ----
      Scsi_Cmnd * found = NULL;
  
      if (!device)
! 	panic ("No device passed to scsi_allocate_device().\n");
  
      if (reqp) req = *reqp;
  
***************
*** 1039,1048 ****
  	    while(SCpnt){
  		SCwait = SCpnt;
  		if(SCpnt->request.rq_status == RQ_INACTIVE) break;
! 		SCpnt = SCpnt->device_next;
  	    }
  	} else {
! 	    SCpnt = device->host->host_queue;
  	    while(SCpnt){
  		if(SCpnt->channel == device->channel
                     && SCpnt->target == device->id) {
--- 1102,1111 ----
  	    while(SCpnt){
  		SCwait = SCpnt;
  		if(SCpnt->request.rq_status == RQ_INACTIVE) break;
! 		SCpnt = SCpnt->next;
  	    }
  	} else {
! 	    SCpnt = device->device_queue;
  	    while(SCpnt){
  		if(SCpnt->channel == device->channel
                     && SCpnt->target == device->id) {
***************
*** 1079,1085 ****
  	}
  	if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE)	/* Might have changed */
  	{
- #if 1	/* NEW CODE */
  		if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){
   			sleep_on(&device->device_wait);
   			restore_flags(flags);
--- 1142,1147 ----
***************
*** 1090,1110 ****
  	 			printk("Attempt to allocate device channel %d,"
                                         " target %d, lun %d\n", device->channel,
                                         device->id, device->lun);
!  				panic("No device found in allocate_device\n");
  	 		}
   		}
- #else	/* ORIGINAL CODE */
- 		    restore_flags(flags);
- 		    if(!wait) return NULL;
- 		    if (!SCwait) {
- 			printk("Attempt to allocate device channel %d, target"
-                                " %d, lun %d\n", device->channel, device->id,
-                                device->lun);
- 			panic("No device found in allocate_device\n");
- 		    }
- 		    SCSI_SLEEP(&device->device_wait,
- 			       (SCwait->request.rq_status != RQ_INACTIVE));
- #endif
  	} else {
  	    if (req) {
  		memcpy(&SCpnt->request, req, sizeof(struct request));
--- 1152,1160 ----
  	 			printk("Attempt to allocate device channel %d,"
                                         " target %d, lun %d\n", device->channel,
                                         device->id, device->lun);
!  				panic("No device found in scsi_allocate_device\n");
  	 		}
   		}
  	} else {
  	    if (req) {
  		memcpy(&SCpnt->request, req, sizeof(struct request));
***************
*** 1145,1151 ****
--- 1195,1205 ----
  		SCpnt->request.sem = NULL;   /* And no one is waiting for this
  					      * to complete */
  	    }
+             atomic_inc(&SCpnt->host->host_active); 
  	    restore_flags(flags);
+             SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", 
+                                        SCpnt->target,
+                                        atomic_read(&SCpnt->host->host_active)));
  	    break;
  	}
      }
***************
*** 1159,1173 ****
--- 1213,1266 ----
  
      /* Since not everyone seems to set the device info correctly
       * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+      * FIXME(eric) This doesn't make any sense.
       */
      SCpnt->channel = device->channel;
      SCpnt->lun = device->lun;
      SCpnt->target = device->id;
+     SCpnt->state = SCSI_STATE_INITIALIZING;
+     SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
  
      return SCpnt;
  }
  
  /*
+  * Function:    scsi_release_command
+  *
+  * Purpose:     Release a command block.
+  *
+  * Arguments:   SCpnt - command block we are releasing.
+  *
+  * Notes:       The command block can no longer be used by the caller once
+  *              this funciton is called.  This is in effect the inverse
+  *              of scsi_allocate_device/scsi_request_queueable.
+  */
+ void
+ scsi_release_command(Scsi_Cmnd * SCpnt)
+ {
+   SCpnt->request.rq_status = RQ_INACTIVE;
+   SCpnt->state = SCSI_STATE_UNUSED;
+   SCpnt->owner = SCSI_OWNER_NOBODY;
+   atomic_dec(&SCpnt->host->host_active); 
+ 
+   SCSI_LOG_MLQUEUE(5, printk("Deactivating command for device %d (active=%d, failed=%d)\n", 
+                              SCpnt->target,
+                              atomic_read(&SCpnt->host->host_active),
+                              SCpnt->host->host_failed));
+ 
+   /*
+    * If the host is having troubles, then look to see if this was the last
+    * command that might have failed.  If so, wake up the error handler.
+    */
+   if( SCpnt->host->in_recovery
+       && !SCpnt->host->eh_active
+       && atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+   {
+       up(SCpnt->host->eh_wait);
+   }
+ }
+ 
+ /*
   * This is inline because we have stack problemes if we recurse to deeply.
   */
  
***************
*** 1218,1242 ****
      }
      restore_flags(flags);
  
!     update_timeout(SCpnt, SCpnt->timeout_per_command);
  
      /*
       * We will use a queued command if possible, otherwise we will emulate the
       * queuing and calling of completion function ourselves.
       */
! #ifdef DEBUG
!     printk("internal_cmnd (host = %d, channel = %d, target = %d, "
  	   "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
  	   SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
! 	   SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
! #endif
  
      if (host->can_queue)
      {
! #ifdef DEBUG
! 	printk("queuecommand : routine at %p\n",
! 	       host->hostt->queuecommand);
! #endif
  	/* This locking tries to prevent all sorts of races between
  	 * queuecommand and the interrupt code.  In effect,
  	 * we are only allowed to be in queuecommand once at
--- 1311,1341 ----
      }
      restore_flags(flags);
  
!     if( host->hostt->use_new_eh_code )
!       {
!         scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out);
!       }
!     else
!       {
!         scsi_add_timer(SCpnt, SCpnt->timeout_per_command, 
!                             scsi_old_times_out);
!       }
  
      /*
       * We will use a queued command if possible, otherwise we will emulate the
       * queuing and calling of completion function ourselves.
       */
!     SCSI_LOG_MLQUEUE(3,printk("internal_cmnd (host = %d, channel = %d, target = %d, "
  	   "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
  	   SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
! 	   SCpnt->buffer, SCpnt->bufflen, SCpnt->done));
  
+     SCpnt->state = SCSI_STATE_QUEUED;
+     SCpnt->owner = SCSI_OWNER_LOWLEVEL;
      if (host->can_queue)
      {
! 	SCSI_LOG_MLQUEUE(3,printk("queuecommand : routine at %p\n",
!                                   host->hostt->queuecommand));
  	/* This locking tries to prevent all sorts of races between
  	 * queuecommand and the interrupt code.  In effect,
  	 * we are only allowed to be in queuecommand once at
***************
*** 1249,1255 ****
  	if(!in_interrupt() && SCpnt->host->irq)
  	    disable_irq(SCpnt->host->irq);
  
! 	host->hostt->queuecommand (SCpnt, scsi_done);
  
  	if(!in_interrupt() && SCpnt->host->irq)
  	    enable_irq(SCpnt->host->irq);
--- 1348,1365 ----
  	if(!in_interrupt() && SCpnt->host->irq)
  	    disable_irq(SCpnt->host->irq);
  
!         /*
!          * Use the old error handling code if we haven't converted the driver
!          * to use the new one yet.
!          */
!         if( host->hostt->use_new_eh_code )
!           {
!             host->hostt->queuecommand (SCpnt, scsi_done);
!           }
!         else
!           {
!             host->hostt->queuecommand (SCpnt, scsi_old_done);
!           }
  
  	if(!in_interrupt() && SCpnt->host->irq)
  	    enable_irq(SCpnt->host->irq);
***************
*** 1258,1266 ****
      {
  	int temp;
  
! #ifdef DEBUG
! 	printk("command() :  routine at %p\n", host->hostt->command);
! #endif
  	temp = host->hostt->command (SCpnt);
  	SCpnt->result = temp;
  #ifdef DEBUG_DELAY
--- 1368,1374 ----
      {
  	int temp;
  
! 	SCSI_LOG_MLQUEUE(3,printk("command() :  routine at %p\n", host->hostt->command));
  	temp = host->hostt->command (SCpnt);
  	SCpnt->result = temp;
  #ifdef DEBUG_DELAY
***************
*** 1269,1307 ****
  	printk("done(host = %d, result = %04x) : routine at %p\n",
  	       host->host_no, temp, host->hostt->command);
  #endif
! 	scsi_done(SCpnt);
      }
! #ifdef DEBUG
!     printk("leaving internal_cmnd()\n");
! #endif
  }
  
- static void scsi_request_sense (Scsi_Cmnd * SCpnt)
- {
-     unsigned long flags;
- 
-     save_flags(flags);
-     cli();
-     SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
-     update_timeout(SCpnt, SENSE_TIMEOUT);
-     restore_flags(flags);
- 
- 
-     memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
- 	    sizeof(generic_sense));
- 
-     SCpnt->cmnd[1] = SCpnt->lun << 5;
-     SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
- 
-     SCpnt->request_buffer = &SCpnt->sense_buffer;
-     SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
-     SCpnt->use_sg = 0;
-     SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-     internal_cmnd (SCpnt);
- }
- 
- 
- 
  /*
   * scsi_do_cmd sends all the commands out to the low-level driver.  It
   * handles the specifics required for each low level driver - ie queued
--- 1377,1394 ----
  	printk("done(host = %d, result = %04x) : routine at %p\n",
  	       host->host_no, temp, host->hostt->command);
  #endif
!         if( host->hostt->use_new_eh_code )
!           {
!             scsi_done(SCpnt);
!           }
!         else
!           {
!             scsi_old_done(SCpnt);
!           }
      }
!     SCSI_LOG_MLQUEUE(3,printk("leaving internal_cmnd()\n"));
  }
  
  /*
   * scsi_do_cmd sends all the commands out to the low-level driver.  It
   * handles the specifics required for each low level driver - ie queued
***************
*** 1316,1322 ****
      unsigned long flags;
      struct Scsi_Host * host = SCpnt->host;
  
! #ifdef DEBUG
      {
  	int i;
  	int target = SCpnt->target;
--- 1403,1411 ----
      unsigned long flags;
      struct Scsi_Host * host = SCpnt->host;
  
!     SCpnt->owner = SCSI_OWNER_MIDLEVEL;
! 
! SCSI_LOG_MLQUEUE(4,
      {
  	int i;
  	int target = SCpnt->target;
***************
*** 1328,1335 ****
  	for (i = 0; i < 10; ++i)
  	    printk ("%02x  ", ((unsigned char *) cmnd)[i]);
  	printk("\n");
!     }
! #endif
  
      if (!host)
      {
--- 1417,1423 ----
  	for (i = 0; i < 10; ++i)
  	    printk ("%02x  ", ((unsigned char *) cmnd)[i]);
  	printk("\n");
!     });
  
      if (!host)
      {
***************
*** 1368,1379 ****
       */
  
      memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12);
- #if 0
-     SCpnt->host = host;
-     SCpnt->channel = channel;
-     SCpnt->target = target;
-     SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);
- #endif
      SCpnt->reset_chain = NULL;
      SCpnt->serial_number = 0;
      SCpnt->bufflen = bufflen;
--- 1456,1461 ----
***************
*** 1402,2368 ****
      SCpnt->abort_reason = 0;
      internal_cmnd (SCpnt);
  
! #ifdef DEBUG
!     printk ("Leaving scsi_do_cmd()\n");
! #endif
! }
! 
! static int check_sense (Scsi_Cmnd * SCpnt)
! {
!     /* If there is no sense information, request it.  If we have already
!      * requested it, there is no point in asking again - the firmware must
!      * be confused.
!      */
!     if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
! 	if(!(SCpnt->flags & ASKED_FOR_SENSE))
! 	    return SUGGEST_SENSE;
! 	else
! 	    return SUGGEST_RETRY;
!     }
! 
!     SCpnt->flags &= ~ASKED_FOR_SENSE;
! 
! #ifdef DEBUG_INIT
!     printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
!     print_sense("", SCpnt);
!     printk("\n");
! #endif
!     if (SCpnt->sense_buffer[2] & 0xe0)
! 	return SUGGEST_ABORT;
! 
!     switch (SCpnt->sense_buffer[2] & 0xf)
!     {
!     case NO_SENSE:
! 	return 0;
!     case RECOVERED_ERROR:
! 	return SUGGEST_IS_OK;
! 
!     case ABORTED_COMMAND:
! 	return SUGGEST_RETRY;
!     case NOT_READY:
!     case UNIT_ATTENTION:
!         /*
!          * If we are expecting a CC/UA because of a bus reset that we
!          * performed, treat this just as a retry.  Otherwise this is
!          * information that we should pass up to the upper-level driver
!          * so that we can deal with it there.
!          */
!         if( SCpnt->device->expecting_cc_ua )
!         {
!             SCpnt->device->expecting_cc_ua = 0;
!             return SUGGEST_RETRY;
!         }
! 	return SUGGEST_ABORT;
! 
!     /* these three are not supported */
!     case COPY_ABORTED:
!     case VOLUME_OVERFLOW:
!     case MISCOMPARE:
! 
!     case MEDIUM_ERROR:
! 	return SUGGEST_REMAP;
!     case BLANK_CHECK:
!     case DATA_PROTECT:
!     case HARDWARE_ERROR:
!     case ILLEGAL_REQUEST:
!     default:
! 	return SUGGEST_ABORT;
!     }
  }
  
  /* This function is the mid-level interrupt routine, which decides how
   *  to handle error conditions.  Each invocation of this function must
   *  do one and *only* one of the following:
   *
!  *  (1) Call last_cmnd[host].done.  This is done for fatal errors and
!  *      normal completion, and indicates that the handling for this
!  *      request is complete.
!  *  (2) Call internal_cmnd to requeue the command.  This will result in
!  *      scsi_done being called again when the retry is complete.
!  *  (3) Call scsi_request_sense.  This asks the host adapter/drive for
!  *      more information about the error condition.  When the information
!  *      is available, scsi_done will be called again.
!  *  (4) Call reset().  This is sort of a last resort, and the idea is that
!  *      this may kick things loose and get the drive working again.  reset()
!  *      automatically calls scsi_request_sense, and thus scsi_done will be
!  *      called again once the reset is complete.
!  *
!  *      If none of the above actions are taken, the drive in question
!  *      will hang. If more than one of the above actions are taken by
!  *      scsi_done, then unpredictable behavior will result.
!  */
! static void scsi_done (Scsi_Cmnd * SCpnt)
! {
!     int status=0;
!     int exit=0;
!     int checked;
!     int oldto;
!     struct Scsi_Host * host = SCpnt->host;
!     int result = SCpnt->result;
!     SCpnt->serial_number = 0;
!     oldto = update_timeout(SCpnt, 0);
! 
! #ifdef DEBUG_TIMEOUT
!     if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
! 		      result, SCpnt->target, SCpnt->lun);
! #endif
! 
!     /* If we requested an abort, (and we got it) then fix up the return
!      *  status to say why
!      */
!     if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
! 	SCpnt->result = result = (result & 0xff00ffff) |
! 	    (SCpnt->abort_reason << 16);
! 
! 
! #define FINISHED 0
! #define MAYREDO  1
! #define REDO     3
! #define PENDING  4
! 
! #ifdef DEBUG
!     printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
! #endif
! 
!     if(SCpnt->flags & WAS_SENSE)
!     {
! 	SCpnt->use_sg = SCpnt->old_use_sg;
! 	SCpnt->cmd_len = SCpnt->old_cmd_len;
!     }
! 
!     switch (host_byte(result))
!     {
!     case DID_OK:
! 	if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
! 	    /* Failed to obtain sense information */
! 	{
! 	    SCpnt->flags &= ~WAS_SENSE;
! #if 0	/* This cannot possibly be correct. */
! 	    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
! #endif
! 
! 	    if (!(SCpnt->flags & WAS_RESET))
! 	    {
! 		printk("scsi%d : channel %d target %d lun %d request sense"
! 		       " failed, performing reset.\n",
! 		       SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
! 		       SCpnt->lun);
! 		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
! 		return;
! 	    }
! 	    else
! 	    {
! 		exit = (DRIVER_HARD | SUGGEST_ABORT);
! 		status = FINISHED;
! 	    }
! 	}
! 	else switch(msg_byte(result))
! 	{
! 	case COMMAND_COMPLETE:
! 	    switch (status_byte(result))
! 	    {
! 	    case GOOD:
! 		if (SCpnt->flags & WAS_SENSE)
! 		{
! #ifdef DEBUG
! 		    printk ("In scsi_done, GOOD status, COMMAND COMPLETE, "
!                             "parsing sense information.\n");
! #endif
! 		    SCpnt->flags &= ~WAS_SENSE;
! #if 0	/* This cannot possibly be correct. */
! 		    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
! #endif
! 
! 		    switch (checked = check_sense(SCpnt))
! 		    {
! 		    case SUGGEST_SENSE:
! 		    case 0:
! #ifdef DEBUG
! 			printk("NO SENSE.  status = REDO\n");
! #endif
! 			update_timeout(SCpnt, oldto);
! 			status = REDO;
! 			break;
! 		    case SUGGEST_IS_OK:
! 			break;
! 		    case SUGGEST_REMAP:
! #ifdef DEBUG
! 			printk("SENSE SUGGEST REMAP - status = FINISHED\n");
! #endif
! 			status = FINISHED;
! 			exit = DRIVER_SENSE | SUGGEST_ABORT;
! 			break;
! 		    case SUGGEST_RETRY:
! #ifdef DEBUG
! 			printk("SENSE SUGGEST RETRY - status = MAYREDO\n");
! #endif
! 			status = MAYREDO;
! 			exit = DRIVER_SENSE | SUGGEST_RETRY;
! 			break;
! 		    case SUGGEST_ABORT:
! #ifdef DEBUG
! 			printk("SENSE SUGGEST ABORT - status = FINISHED");
! #endif
! 			status = FINISHED;
! 			exit =  DRIVER_SENSE | SUGGEST_ABORT;
! 			break;
! 		    default:
! 			printk ("Internal error %s %d \n", __FILE__,
! 				__LINE__);
! 		    }
! 		} /* end WAS_SENSE */
! 		else
! 		{
! #ifdef DEBUG
! 		    printk("COMMAND COMPLETE message returned, "
!                            "status = FINISHED. \n");
! #endif
! 		    exit =  DRIVER_OK;
! 		    status = FINISHED;
! 		}
! 		break;
! 
! 	    case CHECK_CONDITION:
! 	    case COMMAND_TERMINATED:
! 		switch (check_sense(SCpnt))
! 		{
! 		case 0:
! 		    update_timeout(SCpnt, oldto);
! 		    status = REDO;
! 		    break;
! 		case SUGGEST_REMAP:
! 		    status = FINISHED;
! 		    exit =  DRIVER_SENSE | SUGGEST_ABORT;
! 		    break;
! 		case SUGGEST_RETRY:
! 		    status = MAYREDO;
! 		    exit = DRIVER_SENSE | SUGGEST_RETRY;
! 		    break;
! 		case SUGGEST_ABORT:
! 		    status = FINISHED;
! 		    exit =  DRIVER_SENSE | SUGGEST_ABORT;
! 		    break;
! 		case SUGGEST_SENSE:
! 		    scsi_request_sense (SCpnt);
! 		    status = PENDING;
! 		    break;
! 		}
! 		break;
! 
! 	    case CONDITION_GOOD:
! 	    case INTERMEDIATE_GOOD:
! 	    case INTERMEDIATE_C_GOOD:
! 		break;
! 
! 	    case BUSY:
! 	    case QUEUE_FULL:
! 		update_timeout(SCpnt, oldto);
! 		status = REDO;
! 		break;
! 
! 	    case RESERVATION_CONFLICT:
! 		printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
! 		       " reset.\n", SCpnt->host->host_no, SCpnt->channel);
! 		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
! 		return;
! #if 0
! 		exit = DRIVER_SOFT | SUGGEST_ABORT;
! 		status = MAYREDO;
! 		break;
! #endif
! 	    default:
! 		printk ("Internal error %s %d \n"
! 			"status byte = %d \n", __FILE__,
! 			__LINE__, status_byte(result));
! 
! 	    }
! 	    break;
! 	default:
! 	    panic("scsi: unsupported message byte %d received\n",
! 		  msg_byte(result));
! 	}
! 	break;
!     case DID_TIME_OUT:
! #ifdef DEBUG
! 	printk("Host returned DID_TIME_OUT - ");
! #endif
! 
! 	if (SCpnt->flags & WAS_TIMEDOUT)
! 	{
! #ifdef DEBUG
! 	    printk("Aborting\n");
! #endif
! 	    /*
! 	      Allow TEST_UNIT_READY and INQUIRY commands to timeout early
! 	      without causing resets.  All other commands should be retried.
! 	    */
! 	    if (SCpnt->cmnd[0] != TEST_UNIT_READY &&
! 		SCpnt->cmnd[0] != INQUIRY)
! 		    status = MAYREDO;
! 	    exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
! 	}
! 	else
! 	{
! #ifdef DEBUG
! 	    printk ("Retrying.\n");
! #endif
! 	    SCpnt->flags  |= WAS_TIMEDOUT;
! 	    SCpnt->internal_timeout &= ~IN_ABORT;
! 	    status = REDO;
! 	}
! 	break;
!     case DID_BUS_BUSY:
!     case DID_PARITY:
! 	status = REDO;
! 	break;
!     case DID_NO_CONNECT:
! #ifdef DEBUG
! 	printk("Couldn't connect.\n");
! #endif
! 	exit  = (DRIVER_HARD | SUGGEST_ABORT);
! 	break;
!     case DID_ERROR:
! 	status = MAYREDO;
! 	exit = (DRIVER_HARD | SUGGEST_ABORT);
! 	break;
!     case DID_BAD_TARGET:
!     case DID_ABORT:
! 	exit = (DRIVER_INVALID | SUGGEST_ABORT);
! 	break;
!     case DID_RESET:
! 	if (SCpnt->flags & IS_RESETTING)
! 	{
! 	    SCpnt->flags &= ~IS_RESETTING;
! 	    status = REDO;
! 	    break;
! 	}
! 
! 	if(msg_byte(result) == GOOD &&
! 	   status_byte(result) == CHECK_CONDITION) {
! 	    switch (check_sense(SCpnt)) {
! 	    case 0:
! 		update_timeout(SCpnt, oldto);
! 		status = REDO;
! 		break;
! 	    case SUGGEST_REMAP:
! 	    case SUGGEST_RETRY:
! 		status = MAYREDO;
! 		exit = DRIVER_SENSE | SUGGEST_RETRY;
! 		break;
! 	    case SUGGEST_ABORT:
! 		status = FINISHED;
! 		exit =  DRIVER_SENSE | SUGGEST_ABORT;
! 		break;
! 	    case SUGGEST_SENSE:
! 		scsi_request_sense (SCpnt);
! 		status = PENDING;
! 		break;
! 	    }
! 	} else {
! 	    status=REDO;
! 	    exit = SUGGEST_RETRY;
! 	}
! 	break;
!     default :
! 	exit = (DRIVER_ERROR | SUGGEST_DIE);
!     }
! 
!     switch (status)
!     {
!     case FINISHED:
!     case PENDING:
! 	break;
!     case MAYREDO:
! #ifdef DEBUG
! 	printk("In MAYREDO, allowing %d retries, have %d\n",
! 	       SCpnt->allowed, SCpnt->retries);
! #endif
! 	if ((++SCpnt->retries) < SCpnt->allowed)
! 	{
! 	    if ((SCpnt->retries >= (SCpnt->allowed >> 1))
! 		&& !(SCpnt->host->last_reset > 0 &&
! 		     jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
! 		&& !(SCpnt->flags & WAS_RESET))
! 	    {
! 		printk("scsi%d channel %d : resetting for second half of retries.\n",
! 		       SCpnt->host->host_no, SCpnt->channel);
! 		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
! 		break;
! 	    }
! 
! 	}
! 	else
! 	{
! 	    status = FINISHED;
! 	    break;
! 	}
! 	/* fall through to REDO */
! 
!     case REDO:
! 
! 	if (SCpnt->flags & WAS_SENSE)
! 	    scsi_request_sense(SCpnt);
! 	else
! 	{
! 	    memcpy ((void *) SCpnt->cmnd,
! 		    (void*) SCpnt->data_cmnd,
! 		    sizeof(SCpnt->data_cmnd));
! 	    SCpnt->request_buffer = SCpnt->buffer;
! 	    SCpnt->request_bufflen = SCpnt->bufflen;
! 	    SCpnt->use_sg = SCpnt->old_use_sg;
! 	    SCpnt->cmd_len = SCpnt->old_cmd_len;
! 	    internal_cmnd (SCpnt);
! 	}
! 	break;
!     default:
! 	INTERNAL_ERROR;
!     }
! 
!     if (status == FINISHED) {
! #ifdef DEBUG
! 	printk("Calling done function - at address %p\n", SCpnt->done);
! #endif
! 	host->host_busy--; /* Indicate that we are free */
! 
! 	if (host->block && host->host_busy == 0) {
! 	    host_active = NULL;
! 
! 	    /* For block devices "wake_up" is done in end_scsi_request */
! 	    if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
! 		MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
! 		struct Scsi_Host * next;
! 
! 		for (next = host->block; next != host; next = next->block)
! 		    wake_up(&next->host_wait);
! 	    }
! 
! 	}
! 
! 	wake_up(&host->host_wait);
! 	SCpnt->result = result | ((exit & 0xff) << 24);
! 	SCpnt->use_sg = SCpnt->old_use_sg;
! 	SCpnt->cmd_len = SCpnt->old_cmd_len;
! 	SCpnt->done (SCpnt);
!     }
! 
! #undef FINISHED
! #undef REDO
! #undef MAYREDO
! #undef PENDING
! }
! 
! /*
!  * The scsi_abort function interfaces with the abort() function of the host
!  * we are aborting, and causes the current command to not complete.  The
!  * caller should deal with any error messages or status returned on the
!  * next call.
   *
!  * This will not be called reentrantly for a given host.
!  */
! 
! /*
!  * Since we're nice guys and specified that abort() and reset()
!  * can be non-reentrant.  The internal_timeout flags are used for
!  * this.
   */
! 
! 
! int scsi_abort (Scsi_Cmnd * SCpnt, int why)
  {
!     int oldto;
!     unsigned long flags;
!     struct Scsi_Host * host = SCpnt->host;
! 
!     while(1)
!     {
! 	save_flags(flags);
! 	cli();
  
! 	/*
! 	 * Protect against races here.  If the command is done, or we are
! 	 * on a different command forget it.
! 	 */
! 	if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
! 	    restore_flags(flags);
! 	    return 0;
! 	}
! 
! 	if (SCpnt->internal_timeout & IN_ABORT)
! 	{
! 	    restore_flags(flags);
! 	    while (SCpnt->internal_timeout & IN_ABORT)
! 		barrier();
! 	}
! 	else
! 	{
! 	    SCpnt->internal_timeout |= IN_ABORT;
! 	    oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
! 
! 	    if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
! 		/* OK, this command must have died when we did the
! 		 *  reset.  The device itself must have lied.
! 		 */
! 		printk("Stale command on %d %d:%d appears to have died when"
! 		       " the bus was reset\n",
! 		       SCpnt->channel, SCpnt->target, SCpnt->lun);
! 	    }
  
! 	    restore_flags(flags);
! 	    if (!host->host_busy) {
! 		SCpnt->internal_timeout &= ~IN_ABORT;
! 		update_timeout(SCpnt, oldto);
! 		return 0;
! 	    }
! 	    printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
! 		   " channel %d, id %d, lun %d ",
! 		   SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
! 		   (int) SCpnt->target, (int) SCpnt->lun);
! 	    print_command (SCpnt->cmnd);
! 	    if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
! 		return 0;
! 	    SCpnt->abort_reason = why;
! 	    switch(host->hostt->abort(SCpnt)) {
! 		/* We do not know how to abort.  Try waiting another
! 		 * time increment and see if this helps. Set the
! 		 * WAS_TIMEDOUT flag set so we do not try this twice
! 		 */
! 	    case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
! 				   * this is too severe
! 				   */
! 	    case SCSI_ABORT_SNOOZE:
! 		if(why == DID_TIME_OUT) {
! 		    save_flags(flags);
! 		    cli();
! 		    SCpnt->internal_timeout &= ~IN_ABORT;
! 		    if(SCpnt->flags & WAS_TIMEDOUT) {
! 			restore_flags(flags);
! 			return 1; /* Indicate we cannot handle this.
! 				   * We drop down into the reset handler
! 				   * and try again
! 				   */
! 		    } else {
! 			SCpnt->flags |= WAS_TIMEDOUT;
! 			oldto = SCpnt->timeout_per_command;
! 			update_timeout(SCpnt, oldto);
! 		    }
! 		    restore_flags(flags);
! 		}
! 		return 0;
! 	    case SCSI_ABORT_PENDING:
! 		if(why != DID_TIME_OUT) {
! 		    save_flags(flags);
! 		    cli();
! 		    update_timeout(SCpnt, oldto);
! 		    restore_flags(flags);
! 		}
! 		return 0;
! 	    case SCSI_ABORT_SUCCESS:
! 		/* We should have already aborted this one.  No
! 		 * need to adjust timeout
! 		 */
!                  SCpnt->internal_timeout &= ~IN_ABORT;
!                  return 0;
! 	    case SCSI_ABORT_NOT_RUNNING:
! 		SCpnt->internal_timeout &= ~IN_ABORT;
! 		update_timeout(SCpnt, 0);
! 		return 0;
! 	    case SCSI_ABORT_ERROR:
! 	    default:
! 		SCpnt->internal_timeout &= ~IN_ABORT;
! 		return 1;
! 	    }
! 	}
      }
- }
- 
  
! /* Mark a single SCSI Device as having been reset. */
! 
! static inline void scsi_mark_device_reset(Scsi_Device *Device)
! {
!   Device->was_reset = 1;
!   Device->expecting_cc_ua = 1;
! }
  
  
! /* Mark all SCSI Devices on a specific Host as having been reset. */
! 
! void scsi_mark_host_reset(struct Scsi_Host *Host)
! {
!   Scsi_Cmnd *SCpnt;
!   for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
!       scsi_mark_device_reset(SCpnt->device);
! }
! 
! 
! /* Mark all SCSI Devices on a specific Host Bus as having been reset. */
! 
! void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
! {
!   Scsi_Cmnd *SCpnt;
!   for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
!       if (SCpnt->channel == channel)
! 	  scsi_mark_device_reset(SCpnt->device);
  }
  
  
! int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
! {
!     int temp;
!     unsigned long flags;
!     Scsi_Cmnd * SCpnt1;
!     struct Scsi_Host * host = SCpnt->host;
! 
!     printk("SCSI bus is being reset for host %d channel %d.\n",
! 	   host->host_no, SCpnt->channel);
! 
! #if 0
!     /*
!      * First of all, we need to make a recommendation to the low-level
!      * driver as to whether a BUS_DEVICE_RESET should be performed,
!      * or whether we should do a full BUS_RESET.  There is no simple
!      * algorithm here - we basically use a series of heuristics
!      * to determine what we should do.
!      */
!     SCpnt->host->suggest_bus_reset = FALSE;
! 
!     /*
!      * First see if all of the active devices on the bus have
!      * been jammed up so that we are attempting resets.  If so,
!      * then suggest a bus reset.  Forcing a bus reset could
!      * result in some race conditions, but no more than
!      * you would usually get with timeouts.  We will cross
!      * that bridge when we come to it.
!      *
!      * This is actually a pretty bad idea, since a sequence of
!      * commands will often timeout together and this will cause a
!      * Bus Device Reset followed immediately by a SCSI Bus Reset.
!      * If all of the active devices really are jammed up, the
!      * Bus Device Reset will quickly timeout and scsi_times_out
!      * will follow up with a SCSI Bus Reset anyway.
!      */
!     SCpnt1 = host->host_queue;
!     while(SCpnt1) {
! 	if( SCpnt1->request.rq_status != RQ_INACTIVE
! 	    && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
!             	break;
!         SCpnt1 = SCpnt1->next;
!  	}
!     if( SCpnt1 == NULL ) {
!         reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
!     }
! 
!     /*
!      * If the code that called us is suggesting a hard reset, then
!      * definitely request it.  This usually occurs because a
!      * BUS_DEVICE_RESET times out.
!      *
!      * Passing reset_flags along takes care of this automatically.
!      */
!     if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {
!         SCpnt->host->suggest_bus_reset = TRUE;
!     }
! #endif
! 
!     while (1) {
! 	save_flags(flags);
! 	cli();
! 
! 	/*
! 	 * Protect against races here.  If the command is done, or we are
! 	 * on a different command forget it.
! 	 */
! 	if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
! 	  if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
! 	    restore_flags(flags);
! 	    return 0;
! 	  }
! 
! 	if (SCpnt->internal_timeout & IN_RESET)
! 	{
! 	    restore_flags(flags);
! 	    while (SCpnt->internal_timeout & IN_RESET)
! 		barrier();
! 	}
! 	else
! 	{
! 	    SCpnt->internal_timeout |= IN_RESET;
! 	    update_timeout(SCpnt, RESET_TIMEOUT);
! 
! 	    if (host->host_busy)
! 	    {
! 		restore_flags(flags);
! 		SCpnt1 = host->host_queue;
! 		while(SCpnt1) {
! 		    if (SCpnt1->request.rq_status != RQ_INACTIVE) {
! #if 0
! 			if (!(SCpnt1->flags & IS_RESETTING) &&
! 			    !(SCpnt1->internal_timeout & IN_ABORT))
! 			    scsi_abort(SCpnt1, DID_RESET);
! #endif
! 			SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
! 		    }
! 		    SCpnt1 = SCpnt1->next;
! 		}
! 
! 		host->last_reset = jiffies;
! 		temp = host->hostt->reset(SCpnt, reset_flags);
! 		/*
! 		  This test allows the driver to introduce an additional bus
! 		  settle time delay by setting last_reset up to 20 seconds in
! 		  the future.  In the normal case where the driver does not
! 		  modify last_reset, it must be assumed that the actual bus
! 		  reset occurred immediately prior to the return to this code,
! 		  and so last_reset must be updated to the current time, so
! 		  that the delay in internal_cmnd will guarantee at least a
! 		  MIN_RESET_DELAY bus settle time.
! 		*/
! 		if (host->last_reset - jiffies > 20UL * HZ)
! 		  host->last_reset = jiffies;
! 	    }
! 	    else
! 	    {
! 		if (!host->block) host->host_busy++;
! 		restore_flags(flags);
! 		host->last_reset = jiffies;
! 	        SCpnt->flags |= (WAS_RESET | IS_RESETTING);
! 		temp = host->hostt->reset(SCpnt, reset_flags);
! 		if ((host->last_reset < jiffies) ||
! 		    (host->last_reset > (jiffies + 20 * HZ)))
! 		  host->last_reset = jiffies;
! 		if (!host->block) host->host_busy--;
! 	    }
  
! #ifdef DEBUG
! 	    printk("scsi reset function returned %d\n", temp);
! #endif
  
!             /*
!              * Now figure out what we need to do, based upon
!              * what the low level driver said that it did.
! 	     * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
! 	     * or SCSI_RESET_WAKEUP, then the low level driver did a
! 	     * bus device reset or bus reset, so we should go through
! 	     * and mark one or all of the devices on that bus
! 	     * as having been reset.
!              */
!             switch(temp & SCSI_RESET_ACTION) {
! 	    case SCSI_RESET_SUCCESS:
! 	        if (temp & SCSI_RESET_HOST_RESET)
! 		  scsi_mark_host_reset(host);
! 	        else if (temp & SCSI_RESET_BUS_RESET)
! 		  scsi_mark_bus_reset(host, SCpnt->channel);
! 		else scsi_mark_device_reset(SCpnt->device);
! 		save_flags(flags);
! 		cli();
! 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
! 		restore_flags(flags);
! 		return 0;
! 	    case SCSI_RESET_PENDING:
! 	        if (temp & SCSI_RESET_HOST_RESET)
! 		  scsi_mark_host_reset(host);
! 	        else if (temp & SCSI_RESET_BUS_RESET)
! 		  scsi_mark_bus_reset(host, SCpnt->channel);
! 		else scsi_mark_device_reset(SCpnt->device);
! 	    case SCSI_RESET_NOT_RUNNING:
! 		return 0;
! 	    case SCSI_RESET_PUNT:
! 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
!                 scsi_request_sense (SCpnt);
!                 return 0;
! 	    case SCSI_RESET_WAKEUP:
! 	        if (temp & SCSI_RESET_HOST_RESET)
! 		  scsi_mark_host_reset(host);
! 	        else if (temp & SCSI_RESET_BUS_RESET)
! 		  scsi_mark_bus_reset(host, SCpnt->channel);
! 		else scsi_mark_device_reset(SCpnt->device);
! 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
! 		scsi_request_sense (SCpnt);
!                 /*
!                  * If a bus reset was performed, we
!                  * need to wake up each and every command
!                  * that was active on the bus or if it was a HBA
!                  * reset all active commands on all channels
!                  */
!                 if( temp & SCSI_RESET_HOST_RESET )
!                 {
! 		    SCpnt1 = host->host_queue;
! 		    while(SCpnt1) {
! 			if (SCpnt1->request.rq_status != RQ_INACTIVE
! 			    && SCpnt1 != SCpnt)
! 			    scsi_request_sense (SCpnt1);
! 			SCpnt1 = SCpnt1->next;
!                     }
!                 } else if( temp & SCSI_RESET_BUS_RESET ) {
!                     SCpnt1 = host->host_queue;
!                     while(SCpnt1) {
!                         if(SCpnt1->request.rq_status != RQ_INACTIVE
!                            && SCpnt1 != SCpnt
!                            && SCpnt1->channel == SCpnt->channel)
!                             scsi_request_sense (SCpnt);
!                         SCpnt1 = SCpnt1->next;
!                     }
!                 }
! 		return 0;
! 	    case SCSI_RESET_SNOOZE:
! 		/* In this case, we set the timeout field to 0
! 		 * so that this command does not time out any more,
! 		 * and we return 1 so that we get a message on the
! 		 * screen.
! 		 */
! 		save_flags(flags);
! 		cli();
! 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
! 		update_timeout(SCpnt, 0);
! 		restore_flags(flags);
! 		/* If you snooze, you lose... */
! 	    case SCSI_RESET_ERROR:
! 	    default:
! 		return 1;
! 	    }
  
- 	    return temp;
- 	}
-     }
  }
  
! 
! static void scsi_main_timeout(void)
! {
!     /*
!      * We must not enter update_timeout with a timeout condition still pending.
!      */
! 
!     int timed_out;
!     unsigned long flags;
!     struct Scsi_Host * host;
!     Scsi_Cmnd * SCpnt = NULL;
! 
!     save_flags(flags);
!     cli();
! 
!     update_timeout(NULL, 0);
! 
!     /*
!      * Find all timers such that they have 0 or negative (shouldn't happen)
!      * time remaining on them.
!      */
!     timed_out = 0;
!     for (host = scsi_hostlist; host; host = host->next) {
! 	for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
! 	    if (SCpnt->timeout == -1)
! 	      {
! 		SCpnt->timeout = 0;
! 		SCpnt->serial_number_at_timeout = SCpnt->serial_number;
! 		++timed_out;
! 	      }
!     }
!     if (timed_out > 0) {
! 	for (host = scsi_hostlist; host; host = host->next) {
! 	    for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
! 		if (SCpnt->serial_number_at_timeout > 0 &&
! 		    SCpnt->serial_number_at_timeout == SCpnt->serial_number)
! 		  {
! 		    restore_flags(flags);
! 		    scsi_times_out(SCpnt);
! 		    SCpnt->serial_number_at_timeout = 0;
! 		    cli();
! 		  }
! 	  }
!     }
!     restore_flags(flags);
  }
  
  /*
!  * The strategy is to cause the timer code to call scsi_times_out()
!  * when the soonest timeout is pending.
!  * The arguments are used when we are queueing a new command, because
!  * we do not want to subtract the time used from this time, but when we
!  * set the timer, we want to take this value into account.
   */
! 
! int update_timeout(Scsi_Cmnd * SCset, int timeout)
  {
-     unsigned int least, used;
-     unsigned int oldto;
-     unsigned long flags;
      struct Scsi_Host * host;
-     Scsi_Cmnd * SCpnt = NULL;
- 
-     save_flags(flags);
-     cli();
- 
-     oldto = 0;
- 
-     /*
-      * This routine can be a performance bottleneck under high loads, since
-      * it is called twice per SCSI operation: once when internal_cmnd is
-      * called, and again when scsi_done completes the command.  To limit
-      * the load this routine can cause, we shortcut processing if no clock
-      * ticks have occurred since the last time it was called.
-      */
- 
-     if (jiffies == time_start && timer_table[SCSI_TIMER].expires > 0) {
- 	if(SCset){
- 	    oldto = SCset->timeout;
- 	    SCset->timeout = timeout;
- 	    if (timeout > 0 &&
- 		jiffies + timeout < timer_table[SCSI_TIMER].expires)
- 		    timer_table[SCSI_TIMER].expires = jiffies + timeout;
- 	}
- 	restore_flags(flags);
- 	return oldto;
-     }
  
!     /*
!      * Figure out how much time has passed since the last time the timeouts
!      * were updated
!      */
!     used = (time_start) ? (jiffies - time_start) : 0;
! 
!     /*
!      * Find out what is due to timeout soonest, and adjust all timeouts for
!      * the amount of time that has passed since the last time we called
!      * update_timeout.
!      */
! 
!     oldto = 0;
! 
!     if(SCset){
! 	oldto = SCset->timeout - used;
! 	SCset->timeout = timeout;
!     }
! 
!     least = 0xffffffff;
! 
!     for(host = scsi_hostlist; host; host = host->next)
! 	for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
! 	    if (SCpnt->timeout > 0) {
! 	        if (SCpnt != SCset)
! 		    SCpnt->timeout -= used;
! 		if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
! 		if(SCpnt->timeout > 0 && SCpnt->timeout < least)
! 		    least = SCpnt->timeout;
! 	    }
! 
!     /*
!      * If something is due to timeout again, then we will set the next timeout
!      * interrupt to occur.  Otherwise, timeouts are disabled.
!      */
  
!     if (least != 0xffffffff)
!     {
! 	time_start = jiffies;
! 	timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
! 	timer_active |= 1 << SCSI_TIMER;
!     }
!     else
!     {
! 	timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
! 	timer_active &= ~(1 << SCSI_TIMER);
      }
!     restore_flags(flags);
!     return oldto;
  }
  
  #ifdef CONFIG_MODULES
--- 1484,1778 ----
      SCpnt->abort_reason = 0;
      internal_cmnd (SCpnt);
  
!     SCSI_LOG_MLQUEUE(3,printk ("Leaving scsi_do_cmd()\n"));
  }
  
  /* This function is the mid-level interrupt routine, which decides how
   *  to handle error conditions.  Each invocation of this function must
   *  do one and *only* one of the following:
   *
!  *      1) Insert command in BH queue.
!  *      2) Activate error handler for host.
   *
!  * FIXME(eric) - I am concerned about stack overflow (still).  An interrupt could
!  * come while we are processing the bottom queue, which would cause another command
!  * to be stuffed onto the bottom queue, and it would in turn be processed as that
!  * interrupt handler is returning.  Given a sufficiently steady rate of returning
!  * commands, this could cause the stack to overflow.  I am not sure what is the most
!  * appropriate solution here - we should probably keep a depth count, and not process
!  * any commands while we still have a bottom handler active higher in the stack.
!  *
!  * There is currently code in the bottom half handler to monitor recursion in the bottom
!  * handler and report if it ever happens.  If this becomes a problem, it won't be hard to
!  * engineer something to deal with it so that only the outer layer ever does any real
!  * processing.
   */
! void
! scsi_done (Scsi_Cmnd * SCpnt)
  {
!   unsigned long      flags;
!   Scsi_Cmnd        * SCswap;
  
!   /*
!    * We don't have to worry about this one timing out any more.
!    */
!   scsi_delete_timer(SCpnt);
  
!   /*
!    * First, see whether this command already timed out.  If so, we ignore
!    * the response.  We treat it as if the command never finished.
!    */
!   if( SCpnt->state == SCSI_STATE_TIMEOUT )
!     {
!       return;
      }
  
!   SCpnt->state = SCSI_STATE_BHQUEUE;
!   SCpnt->owner = SCSI_OWNER_BH_HANDLER;
!   SCpnt->bh_next = NULL;
  
+   /*
+    * Next, put this command in the BH queue.  All processing of the command
+    * past this point will take place with interrupts turned on.
+    * We start by atomicly swapping the pointer into the queue head slot.
+    * If it was NULL before, then everything is fine, and we are done
+    * (this is the normal case).  If it was not NULL, then we block interrupts,
+    * and link them together.
+    */
+   
+   SCswap = (Scsi_Cmnd *) xchg(&scsi_bh_queue_head, SCpnt);
+   if( SCswap != NULL )
+   {
+       /*
+        * If we assume that the interrupt handler doesn't dawdle, then it is safe to
+        * say that we should come in here extremely rarely.  Under very heavy load,
+        * the requests might not be removed from the list fast enough so that we
+        * *do* end up stacking them, and that would be bad.
+        */
+       save_flags(flags);
+       cli();
+       
+       /*
+        * See if the pointer is NULL - it might have been serviced already
+        */
+       if( scsi_bh_queue_head == NULL )
+       {
+           scsi_bh_queue_head = SCswap;
+       }
+       else
+       {
+           SCswap->bh_next = scsi_bh_queue_head;
+           scsi_bh_queue_head = SCswap;
+       }
+       
+       restore_flags(flags);
+   }
  
!   /*
!    * Mark the bottom half handler to be run.
!    */
!   mark_bh(SCSI_BH);
  }
  
+ /*
+  * Procedure:   scsi_bottom_half_handler
+  *
+  * Purpose:     Called after we have finished processing interrupts, it
+  *              performs post-interrupt handling for commands that may
+  *              have completed.
+  *
+  * Notes:       This is called with all interrupts enabled.  This should reduce
+  *              interrupt latency, stack depth, and reentrancy of the low-level
+  *              drivers.
+  */
+ void scsi_bottom_half_handler(void)
+ {
+   Scsi_Cmnd        * SCpnt;
+   Scsi_Cmnd        * SCnext;
+   static atomic_t    recursion_depth;
  
!   
!   while(1==1)
!   {
!       /*
!        * If the counter is > 0, that means that there is another interrupt handler
!        * out there somewhere processing commands.  We don't want to get these guys
!        * nested as this can lead to stack overflow problems, and there isn't any
!        * real sense in it anyways.
!        */
!       if( atomic_read(&recursion_depth) > 0 )
!       {
!           printk("SCSI bottom half recursion depth = %d \n", atomic_read(&recursion_depth));
!           SCSI_LOG_MLCOMPLETE(1,printk("SCSI bottom half recursion depth = %d \n", 
!                                        atomic_read(&recursion_depth)));
!           break;
!       }
!       
!       /*
!        * This is an atomic operation - swap the pointer with a NULL pointer
!        * We will process everything we find in the list here.
!        */
!       SCpnt = xchg(&scsi_bh_queue_head, NULL);
!       
!       if( SCpnt == NULL )
!       {
!           return;
!       }
!       
!       atomic_inc(&recursion_depth);
!       
!       SCnext = SCpnt->bh_next;
!       
!       for(; SCpnt; SCpnt = SCnext)
!       {
!           SCnext = SCpnt->bh_next;
!           
!           switch( scsi_decide_disposition(SCpnt) )
!           {
!           case SUCCESS:
!               /*
!                * Add to BH queue.
!                */
!               SCSI_LOG_MLCOMPLETE(3,printk("Command finished %d %d 0x%x\n", SCpnt->host->host_busy,
!                      SCpnt->host->host_failed,
!                      SCpnt->result));
!               
!               scsi_finish_command(SCpnt);
!               break;
!           case NEEDS_RETRY:
!               /*
!                * We only come in here if we want to retry a command.  The
!                * test to see whether the command should be retried should be
!                * keeping track of the number of tries, so we don't end up looping,
!                * of course.
!                */
!               SCSI_LOG_MLCOMPLETE(3,printk("Command needs retry %d %d 0x%x\n", SCpnt->host->host_busy,
!                      SCpnt->host->host_failed, SCpnt->result));
!               
!               scsi_retry_command(SCpnt);
!               break;
!           default:
!               /*
!                * Here we have a fatal error of some sort.  Turn it over to
!                * the error handler.
!                */
!               SCSI_LOG_MLCOMPLETE(3,printk("Command failed %p %x active=%d busy=%d failed=%d\n", 
!                                            SCpnt, SCpnt->result,
!                                            atomic_read(&SCpnt->host->host_active),
!                                            SCpnt->host->host_busy,
!                                            SCpnt->host->host_failed));
!               
!               /*
!                * Dump the sense information too.
!                */
!               if ((status_byte (SCpnt->result) & CHECK_CONDITION) != 0)
!               {
!                   SCSI_LOG_MLCOMPLETE(3,print_sense("bh",SCpnt));
!               }
! 
! 
!               if( SCpnt->host->eh_wait != NULL )
!               {
!                   SCpnt->host->host_failed++;
!                   SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
!                   SCpnt->state = SCSI_STATE_FAILED;
!                   SCpnt->host->in_recovery = 1;
!                   /*
!                    * If the host is having troubles, then look to see if this was the last
!                    * command that might have failed.  If so, wake up the error handler.
!                    */
!                   if( atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
!                   {
!                       up(SCpnt->host->eh_wait);
!                   }
!               }
!               else
!               {
!                   /*
!                    * We only get here if the error recovery thread has died.
!                    */
!                   scsi_finish_command(SCpnt);
!               }
!           }
!       } /* for(; SCpnt...) */
  
!       atomic_dec(&recursion_depth);
  
!   } /* while(1==1) */
  
  }
  
! /*
!  * Function:    scsi_retry_command
!  *
!  * Purpose:     Send a command back to the low level to be retried.
!  *
!  * Notes:       This command is always executed in the context of the
!  *              bottom half handler, or the error handler thread. Low
!  *              level drivers should not become re-entrant as a result of
!  *              this.
!  */
! int
! scsi_retry_command(Scsi_Cmnd * SCpnt)
! {
!   memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
!           sizeof(SCpnt->data_cmnd));
!   SCpnt->request_buffer = SCpnt->buffer;
!   SCpnt->request_bufflen = SCpnt->bufflen;
!   SCpnt->use_sg = SCpnt->old_use_sg;
!   SCpnt->cmd_len = SCpnt->old_cmd_len;
!   internal_cmnd (SCpnt);
!   return 0;
  }
  
  /*
!  * Function:    scsi_finish_command
!  *
!  * Purpose:     Pass command off to upper layer for finishing of I/O
!  *              request, waking processes that are waiting on results,
!  *              etc.
   */
! void
! scsi_finish_command(Scsi_Cmnd * SCpnt)
  {
      struct Scsi_Host * host;
  
!     host = SCpnt->host;
  
!     host->host_busy--; /* Indicate that we are free */
!   
!     if (host->block && host->host_busy == 0) 
!     {
!         host_active = NULL;
!         
!         /* For block devices "wake_up" is done in end_scsi_request */
!         if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
!             MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
!             struct Scsi_Host * next;
!             
!             for (next = host->block; next != host; next = next->block)
!                 wake_up(&next->host_wait);
!         }
!         
      }
!   
!     wake_up(&host->host_wait);
!     
!     /*
!      * If we have valid sense information, then some kind of recovery
!      * must have taken place.  Make a note of this.
!      */
!     if( scsi_sense_valid(SCpnt) )
!     {
!         SCpnt->result |= (DRIVER_SENSE << 24);
!     }
!     
!     SCSI_LOG_MLCOMPLETE(3,printk("Notifying upper driver of completion for device %d %x\n",
!                                      SCpnt->device->id, SCpnt->result));
!     
!     SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
!     SCpnt->state = SCSI_STATE_FINISHED;
!     SCpnt->done (SCpnt);
  }
  
  #ifdef CONFIG_MODULES
***************
*** 2388,2394 ****
  	    if ((dma_malloc_freelist[i] & (mask << j)) == 0){
  		dma_malloc_freelist[i] |= (mask << j);
  		restore_flags(flags);
! 		dma_free_sectors -= nbits;
  #ifdef DEBUG
  		printk("SMalloc: %d %p\n",len, dma_malloc_pages[i] + (j << 9));
  #endif
--- 1798,1804 ----
  	    if ((dma_malloc_freelist[i] & (mask << j)) == 0){
  		dma_malloc_freelist[i] |= (mask << j);
  		restore_flags(flags);
! 		scsi_dma_free_sectors -= nbits;
  #ifdef DEBUG
  		printk("SMalloc: %d %p\n",len, dma_malloc_pages[i] + (j << 9));
  #endif
***************
*** 2438,2444 ****
  #endif
                  panic("scsi_free:Trying to free unused memory");
              }
!             dma_free_sectors += nbits;
              dma_malloc_freelist[page] &= ~(mask << sector);
              restore_flags(flags);
              return 0;
--- 1848,1854 ----
  #endif
                  panic("scsi_free:Trying to free unused memory");
              }
!             scsi_dma_free_sectors += nbits;
              dma_malloc_freelist[page] &= ~(mask << sector);
              restore_flags(flags);
              return 0;
***************
*** 2507,2512 ****
--- 1917,1923 ----
                scsi_init_malloc(sizeof(Scsi_Cmnd),
                                 GFP_ATOMIC |
                                 (host->unchecked_isa_dma ? GFP_DMA : 0));
+         memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
  	SCpnt->host = host;
  	SCpnt->device = SDpnt;
  	SCpnt->target = SDpnt->id;
***************
*** 2516,2543 ****
  	SCpnt->use_sg = 0;
  	SCpnt->old_use_sg = 0;
  	SCpnt->old_cmd_len = 0;
- 	SCpnt->timeout = 0;
  	SCpnt->underflow = 0;
  	SCpnt->transfersize = 0;
  	SCpnt->serial_number = 0;
  	SCpnt->serial_number_at_timeout = 0;
  	SCpnt->host_scribble = NULL;
! 	if(host->host_queue)
! 	    host->host_queue->prev = SCpnt;
! 	SCpnt->next = host->host_queue;
! 	SCpnt->prev = NULL;
! 	host->host_queue = SCpnt;
! 	SCpnt->device_next = SDpnt->device_queue;
  	SDpnt->device_queue = SCpnt;
      }
      SDpnt->has_cmdblocks = 1;
  }
  
  /*
   * scsi_dev_init() is our initialization routine, which in turn calls host
   * initialization, bus scanning, and sd/st initialization routines.
   */
- 
  __initfunc(int scsi_dev_init(void))
  {
      Scsi_Device * SDpnt;
--- 1927,1949 ----
  	SCpnt->use_sg = 0;
  	SCpnt->old_use_sg = 0;
  	SCpnt->old_cmd_len = 0;
  	SCpnt->underflow = 0;
  	SCpnt->transfersize = 0;
  	SCpnt->serial_number = 0;
  	SCpnt->serial_number_at_timeout = 0;
  	SCpnt->host_scribble = NULL;
! 	SCpnt->next = SDpnt->device_queue;
  	SDpnt->device_queue = SCpnt;
      }
      SDpnt->has_cmdblocks = 1;
  }
  
+ #ifndef MODULE /* { */
  /*
   * scsi_dev_init() is our initialization routine, which in turn calls host
   * initialization, bus scanning, and sd/st initialization routines.
+  * This is only used at boot time.
   */
  __initfunc(int scsi_dev_init(void))
  {
      Scsi_Device * SDpnt;
***************
*** 2555,2563 ****
      /* Init a few things so we can "malloc" memory. */
      scsi_loadable_module_flag = 0;
  
-     timer_table[SCSI_TIMER].fn = scsi_main_timeout;
-     timer_table[SCSI_TIMER].expires = 0;
- 
      /* Register the /proc/scsi/scsi entry */
  #if CONFIG_PROC_FS
      proc_scsi_register(0, &proc_scsi_scsi);
--- 1961,1966 ----
***************
*** 2607,2614 ****
--- 2010,2023 ----
  
      scsi_loadable_module_flag = 1;
  
+     /*
+      * This is where the processing takes place for most everything
+      * when commands are completed.
+      */
+     init_bh(SCSI_BH, scsi_bottom_half_handler);
      return 0;
  }
+ #endif /* MODULE */   /* } */
  
  static void print_inquiry(unsigned char *data)
  {
***************
*** 2661,2667 ****
  {
      Scsi_Cmnd *SCpnt;
      struct Scsi_Device_Template *SDTpnt;
!     Scsi_Device *scd, *scd_h = NULL;
      struct Scsi_Host *HBA_ptr;
      char *p;
      int   host, channel, id, lun;
--- 2070,2076 ----
  {
      Scsi_Cmnd *SCpnt;
      struct Scsi_Device_Template *SDTpnt;
!     Scsi_Device *scd;
      struct Scsi_Host *HBA_ptr;
      char *p;
      int   host, channel, id, lun;
***************
*** 2669,2705 ****
      off_t begin = 0;
      off_t pos = 0;
  
-     scd = scsi_devices;
-     HBA_ptr = scsi_hostlist;
- 
      if(inout == 0) {
! 	size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
  	len += size;
  	pos = begin + len;
! 	while (HBA_ptr) {
  #if 0
  	    size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no,
  	                    HBA_ptr->hostt->procname);
  	    len += size;
  	    pos = begin + len;
  #endif
! 	    scd = scsi_devices;
! 	    while (scd) {
! 		if (scd->host == HBA_ptr) {
! 		    proc_print_scsidevice(scd, buffer, &size, len);
! 		    len += size;
! 		    pos = begin + len;
! 
! 		    if (pos < offset) {
! 			len = 0;
! 			begin = pos;
! 		    }
! 		    if (pos > offset + length)
! 			goto stop_output;
! 		}
! 		scd = scd->next;
  	    }
- 	    HBA_ptr = HBA_ptr->next;
  	}
  
      stop_output:
--- 2078,2118 ----
      off_t begin = 0;
      off_t pos = 0;
  
      if(inout == 0) {
!         /*
!          * First, see if there are any attached devices or not.
!          */
! 	for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
!         {
!             if( HBA_ptr->host_queue != NULL )
!             {
!                 break;
!             }
!         }
! 	size = sprintf(buffer+len,"Attached devices: %s\n", (HBA_ptr)?"":"none");
  	len += size;
  	pos = begin + len;
! 	for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
!         {
  #if 0
  	    size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no,
  	                    HBA_ptr->hostt->procname);
  	    len += size;
  	    pos = begin + len;
  #endif
! 	    for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
!             {
!                 proc_print_scsidevice(scd, buffer, &size, len);
!                 len += size;
!                 pos = begin + len;
!                 
!                 if (pos < offset) {
!                     len = 0;
!                     begin = pos;
!                 }
!                 if (pos > offset + length)
!                     goto stop_output;
  	    }
  	}
  
      stop_output:
***************
*** 2710,2719 ****
  	return (len);
      }
  
!     if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
  	return(-EINVAL);
  
      /*
       * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
       * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
       * Consider this feature BETA.
--- 2123,2248 ----
  	return (len);
      }
  
!     if(!buffer || length < 11 || strncmp("scsi", buffer, 4))
  	return(-EINVAL);
  
      /*
+      * Usage: echo "scsi dump #N" > /proc/scsi/scsi
+      * to dump status of all scsi commands.  The number is used to specify the level
+      * of detail in the dump.
+      */
+     if(!strncmp("dump", buffer + 5, 4)) 
+     {
+         unsigned int level;
+ 
+ 	p = buffer + 10;
+ 
+         if( *p == '\0' )
+             return (-EINVAL);
+ 
+         level = simple_strtoul(p, NULL, 0);
+         scsi_dump_status(level);
+     }
+     /*
+      * Usage: echo "scsi log token #N" > /proc/scsi/scsi
+      * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
+      * llcomplete,hlqueue,hlcomplete]
+      */
+ #if CONFIG_SCSI_LOGGING /* { */
+ 
+     if(!strncmp("log", buffer + 5, 3)) 
+     {
+         char * token;
+         unsigned int level;
+ 
+ 	p = buffer + 9;
+         token = p;
+         while(*p != ' ' && *p != '\t' && *p != '\0')
+         {
+             p++;
+         }
+ 
+         if( *p == '\0' )
+         {
+             if( strncmp(token, "all", 3) == 0 )
+             {
+                 /*
+                  * Turn on absolutely everything.
+                  */
+                 scsi_logging_level = ~0;
+             }
+             else if( strncmp(token, "none", 4) == 0 )
+             {
+                 /*
+                  * Turn off absolutely everything.
+                  */
+                 scsi_logging_level = 0;
+             }
+             else
+             {
+                 return (-EINVAL);
+             }
+         }
+         else
+         {
+             *p++ = '\0';
+             
+             level = simple_strtoul(p, NULL, 0);
+             
+             /*
+              * Now figure out what to do with it.
+              */
+             if( strcmp(token, "error") == 0 )
+             {
+                 SCSI_SET_ERROR_RECOVERY_LOGGING(level);
+             }
+             else if( strcmp(token, "timeout") == 0 )
+             {
+                 SCSI_SET_TIMEOUT_LOGGING(level);
+             }
+             else if( strcmp(token, "scan") == 0 )
+             {
+                 SCSI_SET_SCAN_BUS_LOGGING(level);
+             }
+             else if( strcmp(token, "mlqueue") == 0 )
+             {
+                 SCSI_SET_MLQUEUE_LOGGING(level);
+             }
+             else if( strcmp(token, "mlcomplete") == 0 )
+             {
+                 SCSI_SET_MLCOMPLETE_LOGGING(level);
+             }
+             else if( strcmp(token, "llqueue") == 0 )
+             {
+                 SCSI_SET_LLQUEUE_LOGGING(level);
+             }
+             else if( strcmp(token, "llcomplete") == 0 )
+             {
+                 SCSI_SET_LLCOMPLETE_LOGGING(level);
+             }
+             else if( strcmp(token, "hlqueue") == 0 )
+             {
+                 SCSI_SET_HLQUEUE_LOGGING(level);
+             }
+             else if( strcmp(token, "hlcomplete") == 0 )
+             {
+                 SCSI_SET_HLCOMPLETE_LOGGING(level);
+             }
+             else if( strcmp(token, "ioctl") == 0 )
+             {
+                 SCSI_SET_IOCTL_LOGGING(level);
+             }
+             else
+             {
+                 return (-EINVAL);
+             }
+         }
+ 
+         printk("scsi logging level set to 0x%8.8x\n", scsi_logging_level);
+     }
+ #endif /* CONFIG_SCSI_LOGGING */ /* } */
+ 
+     /*
       * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
       * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
       * Consider this feature BETA.
***************
*** 2735,2754 ****
  	printk("scsi singledevice %d %d %d %d\n", host, channel,
  			id, lun);
  
! 	while(scd && (scd->host->host_no != host
! 	      || scd->channel != channel
! 	      || scd->id != id
! 	      || scd->lun != lun)) {
! 	    scd = scd->next;
! 	}
! 	if(scd)
! 	    return(-ENOSYS);  /* We do not yet support unplugging */
! 	while(HBA_ptr && HBA_ptr->host_no != host)
! 	    HBA_ptr = HBA_ptr->next;
! 
  	if(!HBA_ptr)
  	    return(-ENXIO);
  
  	scan_scsis (HBA_ptr, 1, channel, id, lun);
  	return(length);
  
--- 2264,2292 ----
  	printk("scsi singledevice %d %d %d %d\n", host, channel,
  			id, lun);
  
!         for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
!         {
!             if( HBA_ptr->host_no == host )
!             {
!                 break;
!             }
!         }
  	if(!HBA_ptr)
  	    return(-ENXIO);
  
+         for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
+         {
+             if((scd->channel == channel
+                 && scd->id == id
+                 && scd->lun == lun))
+             {
+                 break;
+             }
+         }
+ 
+ 	if(scd)
+ 	    return(-ENOSYS);  /* We do not yet support unplugging */
+ 
  	scan_scsis (HBA_ptr, 1, channel, id, lun);
  	return(length);
  
***************
*** 2773,2787 ****
          id      = simple_strtoul(p+1, &p, 0);
          lun     = simple_strtoul(p+1, &p, 0);
  
!         while(scd != NULL) {
!             if(scd->host->host_no == host
!                && scd->channel == channel
!                && scd->id == id
!                && scd->lun == lun){
                  break;
              }
-             scd_h = scd;
-             scd = scd->next;
          }
  
          if(scd == NULL)
--- 2311,2335 ----
          id      = simple_strtoul(p+1, &p, 0);
          lun     = simple_strtoul(p+1, &p, 0);
  
! 
!         for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
!         {
!             if( HBA_ptr->host_no == host )
!             {
!                 break;
!             }
!         }
! 	if(!HBA_ptr)
! 	    return(-ENODEV);
! 
!         for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
!         {
!             if((scd->channel == channel
!                 && scd->id == id
!                 && scd->lun == lun))
!             {
                  break;
              }
          }
  
          if(scd == NULL)
***************
*** 2801,2824 ****
               * Nobody is using this device any more.
               * Free all of the command structures.
               */
!             for(SCpnt=scd->host->host_queue; SCpnt; SCpnt = SCpnt->next){
!                 if(SCpnt->device == scd) {
!                     if(SCpnt->prev != NULL)
!                         SCpnt->prev->next = SCpnt->next;
!                     if(SCpnt->next != NULL)
!                         SCpnt->next->prev = SCpnt->prev;
!                     if(SCpnt == scd->host->host_queue)
!                         scd->host->host_queue = SCpnt->next;
!                     scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
!                 }
              }
              /* Now we can remove the device structure */
!             if(scd_h != NULL) {
!                 scd_h->next = scd->next;
!             } else if (scsi_devices == scd) {
!                 /* We had a hit on the first entry of the device list */
!                 scsi_devices = scd->next;
              }
              scsi_init_free((char *) scd, sizeof(Scsi_Device));
          } else {
              return(-EBUSY);
--- 2349,2371 ----
               * Nobody is using this device any more.
               * Free all of the command structures.
               */
!             for(SCpnt=scd->device_queue; SCpnt; SCpnt = SCpnt->next)
!             {
!                 scd->device_queue = SCpnt->next;
!                 scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
              }
              /* Now we can remove the device structure */
!             if( scd->next != NULL )
!                 scd->next->prev = scd->prev;
! 
!             if( scd->prev != NULL )
!                 scd->prev->next = scd->next;
! 
!             if( HBA_ptr->host_queue == scd )
!             {
!                 HBA_ptr->host_queue = scd->next;
              }
+ 
              scsi_init_free((char *) scd, sizeof(Scsi_Device));
          } else {
              return(-EBUSY);
***************
*** 2846,2858 ****
      unsigned int new_need_isa_buffer = 0;
      unsigned char ** new_dma_malloc_pages = NULL;
  
!     if( !scsi_devices )
      {
  	/*
  	 * Free up the DMA pool.
  	 */
! 	if( dma_free_sectors != dma_sectors )
! 	    panic("SCSI DMA pool memory leak %d %d\n",dma_free_sectors,dma_sectors);
  
  	for(i=0; i < dma_sectors / SECTORS_PER_PAGE; i++)
  	    scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
--- 2393,2405 ----
      unsigned int new_need_isa_buffer = 0;
      unsigned char ** new_dma_malloc_pages = NULL;
  
!     if( !scsi_hostlist )
      {
  	/*
  	 * Free up the DMA pool.
  	 */
! 	if( scsi_dma_free_sectors != dma_sectors )
! 	    panic("SCSI DMA pool memory leak %d %d\n",scsi_dma_free_sectors,dma_sectors);
  
  	for(i=0; i < dma_sectors / SECTORS_PER_PAGE; i++)
  	    scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
***************
*** 2865,2871 ****
                             (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_freelist));
  	dma_malloc_freelist = NULL;
  	dma_sectors = 0;
! 	dma_free_sectors = 0;
  	return;
      }
      /* Next, check to see if we need to extend the DMA buffer pool */
--- 2412,2418 ----
                             (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_freelist));
  	dma_malloc_freelist = NULL;
  	dma_sectors = 0;
! 	scsi_dma_free_sectors = 0;
  	return;
      }
      /* Next, check to see if we need to extend the DMA buffer pool */
***************
*** 2873,2924 ****
      new_dma_sectors = 2*SECTORS_PER_PAGE;		/* Base value we use */
  
      if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD)
! 	scsi_need_isa_bounce_buffers = 1;
      else
! 	scsi_need_isa_bounce_buffers = 0;
  
      if (scsi_devicelist)
  	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
  	    new_dma_sectors += SECTORS_PER_PAGE;	/* Increment for each host */
  
!     for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
! 	host = SDpnt->host;
! 
! 	/*
! 	 * sd and sr drivers allocate scatterlists.
! 	 * sr drivers may allocate for each command 1x2048 or 2x1024 extra
! 	 * buffers for 2k sector size and 1k fs.
! 	 * sg driver allocates buffers < 4k.
! 	 * st driver does not need buffers from the dma pool.
! 	 * estimate 4k buffer/command for devices of unknown type (should panic).
! 	 */
! 	if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
! 	    SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
! 	    new_dma_sectors += ((host->sg_tablesize *
! 	                         sizeof(struct scatterlist) + 511) >> 9) *
! 	                       SDpnt->queue_depth;
! 	    if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
! 	        new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
! 	}
! 	else if (SDpnt->type == TYPE_SCANNER ||
! 		 SDpnt->type == TYPE_PROCESSOR ||
! 		 SDpnt->type == TYPE_MEDIUM_CHANGER) {
! 	    new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
! 	}
! 	else {
! 	    if (SDpnt->type != TYPE_TAPE) {
! 	        printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
! 	        new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
! 	    }
          }
- 
- 	if(host->unchecked_isa_dma &&
- 	   scsi_need_isa_bounce_buffers &&
- 	   SDpnt->type != TYPE_TAPE) {
- 	    new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
- 						  SDpnt->queue_depth;
- 	    new_need_isa_buffer++;
- 	}
      }
  
  #ifdef DEBUG_INIT
--- 2420,2473 ----
      new_dma_sectors = 2*SECTORS_PER_PAGE;		/* Base value we use */
  
      if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD)
! 	need_isa_bounce_buffers = 1;
      else
! 	need_isa_bounce_buffers = 0;
  
      if (scsi_devicelist)
  	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
  	    new_dma_sectors += SECTORS_PER_PAGE;	/* Increment for each host */
  
!     for (host = scsi_hostlist; host; host = host->next)
!     {
!         for (SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) 
!         {
!             /*
!              * sd and sr drivers allocate scatterlists.
!              * sr drivers may allocate for each command 1x2048 or 2x1024 extra
!              * buffers for 2k sector size and 1k fs.
!              * sg driver allocates buffers < 4k.
!              * st driver does not need buffers from the dma pool.
!              * estimate 4k buffer/command for devices of unknown type (should panic).
!              */
!             if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
!                 SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
!                 new_dma_sectors += ((host->sg_tablesize *
!                                      sizeof(struct scatterlist) + 511) >> 9) *
!                     SDpnt->queue_depth;
!                 if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
!                     new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
!             }
!             else if (SDpnt->type == TYPE_SCANNER ||
!                      SDpnt->type == TYPE_PROCESSOR ||
!                      SDpnt->type == TYPE_MEDIUM_CHANGER) {
!                 new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
!             }
!             else {
!                 if (SDpnt->type != TYPE_TAPE) {
!                     printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
!                     new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
!                 }
!             }
!             
!             if(host->unchecked_isa_dma &&
!                need_isa_bounce_buffers &&
!                SDpnt->type != TYPE_TAPE) {
!                 new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
!                     SDpnt->queue_depth;
!                 new_need_isa_buffer++;
!             }
          }
      }
  
  #ifdef DEBUG_INIT
***************
*** 2976,2991 ****
  	scsi_init_free((char *) dma_malloc_pages, size);
      }
  
!     dma_free_sectors += new_dma_sectors - dma_sectors;
      dma_malloc_pages = new_dma_malloc_pages;
      dma_sectors = new_dma_sectors;
!     need_isa_buffer = new_need_isa_buffer;
      restore_flags(flags);
  
  #ifdef DEBUG_INIT
!     printk("resize_dma_pool: dma free sectors   = %d\n", dma_free_sectors);
      printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
!     printk("resize_dma_pool: need isa buffers   = %d\n", need_isa_buffer);
  #endif
  }
  
--- 2525,2540 ----
  	scsi_init_free((char *) dma_malloc_pages, size);
      }
  
!     scsi_dma_free_sectors += new_dma_sectors - dma_sectors;
      dma_malloc_pages = new_dma_malloc_pages;
      dma_sectors = new_dma_sectors;
!     scsi_need_isa_buffer = new_need_isa_buffer;
      restore_flags(flags);
  
  #ifdef DEBUG_INIT
!     printk("resize_dma_pool: dma free sectors   = %d\n", scsi_dma_free_sectors);
      printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
!     printk("resize_dma_pool: need isa buffers   = %d\n", scsi_need_isa_buffer);
  #endif
  }
  
***************
*** 3009,3021 ****
      pcount = next_scsi_host;
      if ((tpnt->present = tpnt->detect(tpnt)))
      {
! 	if(pcount == next_scsi_host) {
! 	    if(tpnt->present > 1) {
  		printk("Failure to register low-level scsi driver");
  		scsi_unregister_host(tpnt);
  		return 1;
  	    }
! 	    /* The low-level driver failed to register a driver.  We
  	     *  can do this now.
  	     */
  	    scsi_register(tpnt,0);
--- 2558,2573 ----
      pcount = next_scsi_host;
      if ((tpnt->present = tpnt->detect(tpnt)))
      {
! 	if(pcount == next_scsi_host) 
!         {
! 	    if(tpnt->present > 1) 
!             {
  		printk("Failure to register low-level scsi driver");
  		scsi_unregister_host(tpnt);
  		return 1;
  	    }
! 	    /* 
!              * The low-level driver failed to register a driver.  We
  	     *  can do this now.
  	     */
  	    scsi_register(tpnt,0);
***************
*** 3028,3043 ****
--- 2580,2625 ----
  	build_proc_dir_entries(tpnt);
  #endif
  
+ 
+         /*
+          * Add the kernel threads for each host adapter that will
+          * handle error correction.
+          */
+         for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+         {
+             if( shpnt->hostt == tpnt && shpnt->hostt->use_new_eh_code )
+             {
+                 struct semaphore sem = MUTEX_LOCKED;
+                 
+                 shpnt->eh_notify = &sem;
+                 kernel_thread((int (*)(void *))scsi_error_handler, 
+                               (void *) shpnt, 0);
+                 
+                 /*
+                  * Now wait for the kernel error thread to initialize itself
+                  * as it might be needed when we scan the bus.
+                  */
+                 down (&sem);
+                 shpnt->eh_notify = NULL;
+             }
+         }
+         
  	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+         {
  	    if(shpnt->hostt == tpnt)
  	    {
  		if(tpnt->info)
+                 {
  		    name = tpnt->info(shpnt);
+                 }
  		else
+                 {
  		    name = tpnt->name;
+                 }
  		printk ("scsi%d : %s\n", /* And print a little message */
  			shpnt->host_no, name);
  	    }
+         }
  
  	printk ("scsi : %d host%s.\n", next_scsi_host,
  		(next_scsi_host == 1) ? "" : "s");
***************
*** 3047,3072 ****
  	/* The next step is to call scan_scsis here.  This generates the
  	 * Scsi_Devices entries
  	 */
- 
  	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
! 	    if(shpnt->hostt == tpnt) {
! 	      scan_scsis(shpnt,0,0,0,0);
! 	      if (shpnt->select_queue_depths != NULL)
! 		  (shpnt->select_queue_depths)(shpnt, scsi_devices);
  	    }
  
  	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
  	    if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
  
! 	/* Next we create the Scsi_Cmnd structures for this host */
! 
! 	for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
! 	    if(SDpnt->host->hostt == tpnt)
! 	    {
! 		for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
! 		    if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
! 		if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
! 	    }
  
  	/*
  	 * Now that we have all of the devices, resize the DMA pool,
--- 2629,2664 ----
  	/* The next step is to call scan_scsis here.  This generates the
  	 * Scsi_Devices entries
  	 */
  	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
!         {
! 	    if(shpnt->hostt == tpnt) 
!             {
!                 scan_scsis(shpnt,0,0,0,0);
!                 if (shpnt->select_queue_depths != NULL)
!                 {
!                     (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
!                 }
  	    }
+         }
  
  	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+         {
  	    if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
+         }
  
! 	/*
!          * Next we create the Scsi_Cmnd structures for this host 
!          */
!         for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
!         {
!             for(SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
!                 if(SDpnt->host->hostt == tpnt)
!                 {
!                     for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
!                         if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
!                     if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
!                 }
!         }
  
  	/*
  	 * Now that we have all of the devices, resize the DMA pool,
***************
*** 3076,3083 ****
--- 2668,2679 ----
  
  	/* This does any final handling that is required. */
  	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+         {
  	    if(sdtpnt->finish && sdtpnt->nr_dev)
+             {
  		(*sdtpnt->finish)();
+             }
+         }
      }
  
  #if defined(USE_STATIC_SCSI_MEMORY)
***************
*** 3094,3183 ****
  /*
   * Similarly, this entry point should be called by a loadable module if it
   * is trying to remove a low level scsi driver from the system.
   */
  static void scsi_unregister_host(Scsi_Host_Template * tpnt)
  {
!     Scsi_Host_Template * SHT, *SHTp;
!     Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
!     Scsi_Cmnd * SCpnt;
!     unsigned long flags;
      struct Scsi_Device_Template * sdtpnt;
!     struct Scsi_Host * shpnt, *sh1;
!     int pcount;
  
!     /* First verify that this host adapter is completely free with no pending
!      * commands */
  
!     for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
! 	if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->module
! 	   && sdpnt->host->hostt->module->usecount) return;
  
      for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
      {
! 	if (shpnt->hostt != tpnt) continue;
! 	for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
! 	{
! 	    save_flags(flags);
! 	    cli();
! 	    if(SCpnt->request.rq_status != RQ_INACTIVE) {
! 		restore_flags(flags);
! 		for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
! 		    if(SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
! 			SCpnt->request.rq_status = RQ_INACTIVE;
! 		printk("Device busy???\n");
! 		return;
  	    }
! 	    SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING;  /* Mark as busy */
! 	    restore_flags(flags);
! 	}
      }
      /* Next we detach the high level drivers from the Scsi_Device structures */
  
!     for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
! 	if(sdpnt->host->hostt == tpnt)
! 	{
  	    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
! 		if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt);
! 	    /* If something still attached, punt */
! 	    if (sdpnt->attached) {
! 		printk("Attached usage count = %d\n", sdpnt->attached);
! 		return;
! 	    }
  	}
  
      /* Next we free up the Scsi_Cmnd structures for this host */
  
!     for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
! 	if(sdpnt->host->hostt == tpnt)
! 	    while (sdpnt->host->host_queue) {
! 		SCpnt = sdpnt->host->host_queue->next;
! 		scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
! 		sdpnt->host->host_queue = SCpnt;
! 		if (SCpnt) SCpnt->prev = NULL;
! 		sdpnt->has_cmdblocks = 0;
! 	    }
  
!     /* Next free up the Scsi_Device structures for this host */
  
!     sdppnt = NULL;
!     for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1)
!     {
! 	sdpnt1 = sdpnt->next;
! 	if (sdpnt->host->hostt == tpnt) {
! 	    if (sdppnt)
! 		sdppnt->next = sdpnt->next;
! 	    else
! 		scsi_devices = sdpnt->next;
! 	    scsi_init_free((char *) sdpnt, sizeof (Scsi_Device));
! 	} else
! 	    sdppnt = sdpnt;
      }
  
      /* Next we go through and remove the instances of the individual hosts
       * that were detected */
  
!     shpnt = scsi_hostlist;
!     while(shpnt) {
  	sh1 = shpnt->next;
  	if(shpnt->hostt == tpnt) {
  	    if(shpnt->loaded_as_module) {
--- 2690,2876 ----
  /*
   * Similarly, this entry point should be called by a loadable module if it
   * is trying to remove a low level scsi driver from the system.
+  *
+  * Note - there is a fatal flaw in the deregister module function.
+  * There is no way to return a code that says 'I cannot be unloaded now'.
+  * The system relies entirely upon usage counts that are maintained,
+  * and the assumption is that if the usage count is 0, then the module
+  * can be unloaded.
   */
  static void scsi_unregister_host(Scsi_Host_Template * tpnt)
  {
!     unsigned long                 flags;
!     int                           online_status;
!     int                           pcount;
!     Scsi_Cmnd                   * SCpnt;
!     Scsi_Device                 * SDpnt;
!     Scsi_Device                 * SDpnt1;
      struct Scsi_Device_Template * sdtpnt;
!     struct Scsi_Host            * sh1;
!     struct Scsi_Host            * shpnt;
!     Scsi_Host_Template          * SHT;
!     Scsi_Host_Template          * SHTp;
! 
!     /*
!      * First verify that this host adapter is completely free with no pending
!      * commands 
!      */
!     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
!     {
!         for(SDpnt = shpnt->host_queue; SDpnt; 
!             SDpnt = SDpnt->next)
!         {
!             if(SDpnt->host->hostt == tpnt 
!                && SDpnt->host->hostt->module
!                && SDpnt->host->hostt->module->usecount) return;
!             /* 
!              * FIXME(eric) - We need to find a way to notify the
!              * low level driver that we are shutting down - via the
!              * special device entry that still needs to get added. 
!              *
!              * Is detach interface below good enough for this?
!              */
!         }
!     }
  
!     /*
!      * FIXME(eric) put a spinlock on this.  We force all of the devices offline
!      * to help prevent race conditions where other hosts/processors could try and
!      * get in and queue a command.
!      */
!     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
!     {
!         for(SDpnt = shpnt->host_queue; SDpnt; 
!             SDpnt = SDpnt->next)
!         {
!             if(SDpnt->host->hostt == tpnt )
!                 SDpnt->online = FALSE;
  
!         }
!     }
  
      for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
      {
! 	if (shpnt->hostt != tpnt)
!         {
!             continue;
!         }
! 
!         for(SDpnt = shpnt->host_queue; SDpnt; 
!             SDpnt = SDpnt->next)
!         {
!             /*
!              * Loop over all of the commands associated with the device.  If any of
!              * them are busy, then set the state back to inactive and bail.
!              */
!             for(SCpnt = SDpnt->device_queue; SCpnt; 
!                 SCpnt = SCpnt->next)
! 	    {
!                 online_status = SDpnt->online;
!                 SDpnt->online = FALSE;
! 	        save_flags(flags);
! 	        cli();
! 	        if(SCpnt->request.rq_status != RQ_INACTIVE) 
!                 {
! 		    restore_flags(flags);
!                     printk("SCSI device not inactive - state=%d, id=%d\n",
!                            SCpnt->request.rq_status, SCpnt->target);
!                     for(SDpnt1 = shpnt->host_queue; SDpnt1; 
!                         SDpnt1 = SDpnt1->next)
!                       {
!                         for(SCpnt = SDpnt1->device_queue; SCpnt; 
!                             SCpnt = SCpnt->next)
!                           if(SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
! 			    SCpnt->request.rq_status = RQ_INACTIVE;
!                       }
!                     SDpnt->online = online_status;
! 		    printk("Device busy???\n");
! 		    return;
! 	        }
!                 /*
!                  * No, this device is really free.  Mark it as such, and
!                  * continue on.
!                  */
!                 SCpnt->state = SCSI_STATE_DISCONNECTING;
! 	        SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING;  /* Mark as busy */
! 	        restore_flags(flags);
  	    }
!         }
      }
      /* Next we detach the high level drivers from the Scsi_Device structures */
  
!     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
!     {
!         if(shpnt->hostt != tpnt)
!         {
!             continue;
!         }
! 
!         for(SDpnt = shpnt->host_queue; SDpnt; 
!             SDpnt = SDpnt->next)
!         {
  	    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
!               if(sdtpnt->detach) (*sdtpnt->detach)(SDpnt);
! 
!             /* If something still attached, punt */
!             if (SDpnt->attached) 
!             {
!                 printk("Attached usage count = %d\n", SDpnt->attached);
!                 return;
!             }
  	}
+     }
+ 
+     /*
+      * Next, kill the kernel error recovery thread for this host.
+      */
+     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+     {
+         if(   shpnt->hostt == tpnt 
+               && shpnt->hostt->use_new_eh_code
+               && shpnt->ehandler != NULL )
+         {
+             struct semaphore sem = MUTEX_LOCKED;
+             
+             shpnt->eh_notify = &sem;
+             send_sig(SIGKILL, shpnt->ehandler, 1);
+             down(&sem);
+             shpnt->eh_notify = NULL;
+         }
+     }
  
      /* Next we free up the Scsi_Cmnd structures for this host */
  
!     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
!     {
! 	if(shpnt->hostt != tpnt)
!         {
!             continue;
!         }
! 
!         for(SDpnt = shpnt->host_queue; SDpnt; 
!             SDpnt = shpnt->host_queue)
!         {
!             while (SDpnt->device_queue)
!             {
!                 SCpnt = SDpnt->device_queue->next;
!                 scsi_init_free((char *) SDpnt->device_queue, sizeof(Scsi_Cmnd));
!                 SDpnt->device_queue = SCpnt;
!             }
!             SDpnt->has_cmdblocks = 0;
  
!             /* Next free up the Scsi_Device structures for this host */
!             shpnt->host_queue = SDpnt->next;
! 	    scsi_init_free((char *) SDpnt, sizeof (Scsi_Device));
  
!         }
      }
  
      /* Next we go through and remove the instances of the individual hosts
       * that were detected */
  
!     for(shpnt = scsi_hostlist; shpnt; shpnt = sh1) 
!     {
  	sh1 = shpnt->next;
  	if(shpnt->hostt == tpnt) {
  	    if(shpnt->loaded_as_module) {
***************
*** 3203,3209 ****
  		tpnt->present--;
  	    }
  	}
- 	shpnt = sh1;
      }
  
      /*
--- 2896,2901 ----
***************
*** 3211,3217 ****
       * to completely nuke the DMA pool.  The resize operation will
       * do the right thing and free everything.
       */
!     if( !scsi_devices )
  	resize_dma_pool();
  
      printk ("scsi : %d host%s.\n", next_scsi_host,
--- 2903,2909 ----
       * to completely nuke the DMA pool.  The resize operation will
       * do the right thing and free everything.
       */
!     if( !scsi_hosts )
  	resize_dma_pool();
  
      printk ("scsi : %d host%s.\n", next_scsi_host,
***************
*** 3255,3261 ****
   */
  static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
  {
!     Scsi_Device * SDpnt;
  
      if (tpnt->next) return 1;
  
--- 2947,2954 ----
   */
  static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
  {
!     Scsi_Device      * SDpnt;
!     struct Scsi_Host * shpnt;
  
      if (tpnt->next) return 1;
  
***************
*** 3264,3271 ****
       * First scan the devices that we know about, and see if we notice them.
       */
  
!     for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
! 	if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
  
      /*
       * If any of the devices would match this driver, then perform the
--- 2957,2970 ----
       * First scan the devices that we know about, and see if we notice them.
       */
  
!     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
!     {
!         for(SDpnt = shpnt->host_queue; SDpnt; 
!             SDpnt = SDpnt->next)
!         {
!             if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
!         }
!     }
  
      /*
       * If any of the devices would match this driver, then perform the
***************
*** 3277,3291 ****
      /*
       * Now actually connect the devices to the new driver.
       */
!     for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
      {
! 	if(tpnt->attach)  (*tpnt->attach)(SDpnt);
! 	/*
! 	 * If this driver attached to the device, and we no longer
! 	 * have anything attached, release the scsi command blocks.
! 	 */
! 	if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
! 	    scsi_build_commandblocks(SDpnt);
      }
  
      /*
--- 2976,2997 ----
      /*
       * Now actually connect the devices to the new driver.
       */
!     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
      {
!         for(SDpnt = shpnt->host_queue; SDpnt; 
!             SDpnt = SDpnt->next)
!         {
!             if(tpnt->attach)  (*tpnt->attach)(SDpnt);
!             /*
!              * If this driver attached to the device, and don't have any
!              * command blocks for this device, allocate some.
!              */
!             if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
!             {
!                 SDpnt->online = TRUE;
!                 scsi_build_commandblocks(SDpnt);
!             }
!         }
      }
  
      /*
***************
*** 3300,3305 ****
--- 3006,3012 ----
  {
      Scsi_Device * SDpnt;
      Scsi_Cmnd * SCpnt;
+     struct Scsi_Host * shpnt;
      struct Scsi_Device_Template * spnt;
      struct Scsi_Device_Template * prev_spnt;
  
***************
*** 3312,3341 ****
       * Next, detach the devices from the driver.
       */
  
!     for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
      {
! 	if(tpnt->detach) (*tpnt->detach)(SDpnt);
! 	if(SDpnt->attached == 0)
! 	{
! 	    /*
! 	     * Nobody is using this device any more.  Free all of the
! 	     * command structures.
! 	     */
! 	    for(SCpnt = SDpnt->host->host_queue; SCpnt; SCpnt = SCpnt->next)
  	    {
! 		if(SCpnt->device == SDpnt)
! 		{
! 		    if(SCpnt->prev != NULL)
! 			SCpnt->prev->next = SCpnt->next;
! 		    if(SCpnt->next != NULL)
! 			SCpnt->next->prev = SCpnt->prev;
! 		    if(SCpnt == SDpnt->host->host_queue)
! 			SDpnt->host->host_queue = SCpnt->next;
  		    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
! 		}
  	    }
! 	    SDpnt->has_cmdblocks = 0;
! 	}
      }
      /*
       * Extract the template from the linked list.
--- 3019,3048 ----
       * Next, detach the devices from the driver.
       */
  
!     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
      {
!         for(SDpnt = shpnt->host_queue; SDpnt; 
!             SDpnt = SDpnt->next)
!         {
!             if(tpnt->detach) (*tpnt->detach)(SDpnt);
! 	    if(SDpnt->attached == 0)
  	    {
!                 SDpnt->online = FALSE;
! 
!                 /*
! 	         * Nobody is using this device any more.  Free all of the
! 	         * command structures.
! 	         */
! 	        for(SCpnt = SDpnt->device_queue; SCpnt; 
!                     SCpnt = SCpnt->next)
! 	        {
! 		    if(SCpnt == SDpnt->device_queue)
! 			SDpnt->device_queue = SCpnt->next;
  		    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
! 	        }
! 	        SDpnt->has_cmdblocks = 0;
  	    }
!         }
      }
      /*
       * Extract the template from the linked list.
***************
*** 3363,3388 ****
  
  int scsi_register_module(int module_type, void * ptr)
  {
!     switch(module_type){
      case MODULE_SCSI_HA:
  	return scsi_register_host((Scsi_Host_Template *) ptr);
! 
  	/* Load upper level device handler of some kind */
      case MODULE_SCSI_DEV:
  #ifdef CONFIG_KERNELD
  	if (scsi_hosts == NULL)
! 		request_module("scsi_hostadapter");
  #endif
  	return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
  	/* The rest of these are not yet implemented */
! 
  	/* Load constants.o */
      case MODULE_SCSI_CONST:
! 
  	/* Load specialized ioctl handler for some device.  Intended for
  	 * cdroms that have non-SCSI2 audio command sets. */
      case MODULE_SCSI_IOCTL:
! 
      default:
  	return 1;
      }
--- 3070,3096 ----
  
  int scsi_register_module(int module_type, void * ptr)
  {
!     switch(module_type)
!     {
      case MODULE_SCSI_HA:
  	return scsi_register_host((Scsi_Host_Template *) ptr);
!         
  	/* Load upper level device handler of some kind */
      case MODULE_SCSI_DEV:
  #ifdef CONFIG_KERNELD
  	if (scsi_hosts == NULL)
!             request_module("scsi_hostadapter");
  #endif
  	return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
  	/* The rest of these are not yet implemented */
!         
  	/* Load constants.o */
      case MODULE_SCSI_CONST:
!         
  	/* Load specialized ioctl handler for some device.  Intended for
  	 * cdroms that have non-SCSI2 audio command sets. */
      case MODULE_SCSI_IOCTL:
!         
      default:
  	return 1;
      }
***************
*** 3390,3396 ****
  
  void scsi_unregister_module(int module_type, void * ptr)
  {
!     switch(module_type) {
      case MODULE_SCSI_HA:
  	scsi_unregister_host((Scsi_Host_Template *) ptr);
  	break;
--- 3098,3105 ----
  
  void scsi_unregister_module(int module_type, void * ptr)
  {
!     switch(module_type) 
!     {
      case MODULE_SCSI_HA:
  	scsi_unregister_host((Scsi_Host_Template *) ptr);
  	break;
***************
*** 3408,3472 ****
  
  #endif		/* CONFIG_MODULES */
  
! #ifdef DEBUG_TIMEOUT
  static void
! scsi_dump_status(void)
  {
      int i;
      struct Scsi_Host * shpnt;
      Scsi_Cmnd * SCpnt;
      printk("Dump of scsi parameters:\n");
      i = 0;
      for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
! 	for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
  	{
! 	    /*  (0) 0:0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x      */
! 	    printk("(%d) %d:%d:%d:%d (%s %ld %ld %ld %d) (%d %d %x) (%d %d %d) %x %x %x\n",
! 		   i++, SCpnt->host->host_no,
! 		   SCpnt->channel,
! 		   SCpnt->target,
! 		   SCpnt->lun,
! 		   kdevname(SCpnt->request.rq_dev),
! 		   SCpnt->request.sector,
! 		   SCpnt->request.nr_sectors,
! 		   SCpnt->request.current_nr_sectors,
! 		   SCpnt->use_sg,
! 		   SCpnt->retries,
! 		   SCpnt->allowed,
! 		   SCpnt->flags,
! 		   SCpnt->timeout_per_command,
! 		   SCpnt->timeout,
! 		   SCpnt->internal_timeout,
! 		   SCpnt->cmnd[0],
! 		   SCpnt->sense_buffer[2],
! 		   SCpnt->result);
! 	}
!     printk("wait_for_request = %p\n", wait_for_request);
!     /* Now dump the request lists for each block device */
!     printk("Dump of pending block device requests\n");
!     for(i=0; i<MAX_BLKDEV; i++)
! 	if(blk_dev[i].current_request)
  	{
! 	    struct request * req;
! 	    printk("%d: ", i);
! 	    req = blk_dev[i].current_request;
! 	    while(req) {
! 		printk("(%s %d %ld %ld %ld) ",
! 		       kdevname(req->rq_dev),
! 		       req->cmd,
! 		       req->sector,
! 		       req->nr_sectors,
! 		       req->current_nr_sectors);
! 		req = req->next;
! 	    }
! 	    printk("\n");
! 	}
  }
- #endif
  
  #ifdef MODULE
  
! int init_module(void) {
      unsigned long size;
  
      /*
--- 3117,3226 ----
  
  #endif		/* CONFIG_MODULES */
  
! /*
!  * Function:    scsi_dump_status
!  *
!  * Purpose:     Brain dump of scsi system, used for problem solving.
!  *
!  * Arguments:   level - used to indicate level of detail.
!  *
!  * Notes:       The level isn't used at all yet, but we need to find some way
!  *              of sensibly logging varying degrees of information.  A quick one-line
!  *              display of each command, plus the status would be most useful.
!  *
!  *              This does depend upon CONFIG_SCSI_LOGGING - I do want some way of turning
!  *              it all off if the user wants a lean and mean kernel.  It would probably
!  *              also be useful to allow the user to specify one single host to be dumped.
!  *              A second argument to the function would be useful for that purpose.
!  *
!  *              FIXME - some formatting of the output into tables would be very handy.
!  */
  static void
! scsi_dump_status(int level)
  {
      int i;
      struct Scsi_Host * shpnt;
      Scsi_Cmnd * SCpnt;
+     Scsi_Device * SDpnt;
+ #if CONFIG_PROC_FS
+ #if CONFIG_SCSI_LOGGING /* { */
      printk("Dump of scsi parameters:\n");
      i = 0;
      for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
!     {
!         printk("h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n");
! 	for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
  	{
!             for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
!             {
!                 /*  (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x      */
!                 printk("(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
!                        i++, 
! 
!                        SCpnt->host->host_no,
!                        SCpnt->channel,
!                        SCpnt->target,
!                        SCpnt->lun,
! 
!                        kdevname(SCpnt->request.rq_dev),
!                        SCpnt->request.sector,
!                        SCpnt->request.nr_sectors,
!                        SCpnt->request.current_nr_sectors,
!                        SCpnt->request.rq_status,
!                        SCpnt->use_sg,
! 
!                        SCpnt->retries,
!                        SCpnt->allowed,
!                        SCpnt->flags,
! 
!                        SCpnt->timeout_per_command,
!                        SCpnt->timeout,
!                        SCpnt->internal_timeout,
! 
!                        SCpnt->cmnd[0],
!                        SCpnt->sense_buffer[2],
!                        SCpnt->result);
!             }
!         }
!     }
! 
!     for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
!     {
! 	for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
  	{
!             /* Now dump the request lists for each block device */
!             printk("Dump of pending block device requests\n");
!             for(i=0; i<MAX_BLKDEV; i++)
!             {
!                 if(blk_dev[i].current_request)
!                 {
!                     struct request * req;
!                     printk("%d: ", i);
!                     req = blk_dev[i].current_request;
!                     while(req) 
!                     {
!                         printk("(%s %d %ld %ld %ld) ",
!                                kdevname(req->rq_dev),
!                                req->cmd,
!                                req->sector,
!                                req->nr_sectors,
!                                req->current_nr_sectors);
!                         req = req->next;
!                     }
!                     printk("\n");
!                 }
!             }
!         }
!     }
!     printk("wait_for_request = %p\n", wait_for_request);
! #endif /* CONFIG_SCSI_LOGGING */ /* } */
! #endif /* CONFIG_PROC_FS */
  }
  
  #ifdef MODULE
  
! int init_module(void) 
! {
      unsigned long size;
  
      /*
***************
*** 3476,3483 ****
      dispatch_scsi_info_ptr = dispatch_scsi_info;
  #endif
  
-     timer_table[SCSI_TIMER].fn = scsi_main_timeout;
-     timer_table[SCSI_TIMER].expires = 0;
      scsi_loadable_module_flag = 1;
  
      /* Register the /proc/scsi/scsi entry */
--- 3230,3235 ----
***************
*** 3487,3493 ****
  
  
      dma_sectors = PAGE_SIZE / SECTOR_SIZE;
!     dma_free_sectors= dma_sectors;
      /*
       * Set up a minimal DMA buffer list - this will be used during scan_scsis
       * in some cases.
--- 3239,3245 ----
  
  
      dma_sectors = PAGE_SIZE / SECTOR_SIZE;
!     scsi_dma_free_sectors= dma_sectors;
      /*
       * Set up a minimal DMA buffer list - this will be used during scan_scsis
       * in some cases.
***************
*** 3503,3513 ****
--- 3255,3274 ----
  	scsi_init_malloc((dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages), GFP_ATOMIC);
      dma_malloc_pages[0] = (unsigned char *)
  	scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+ 
+     /*
+      * This is where the processing takes place for most everything
+      * when commands are completed.
+      */
+     init_bh(SCSI_BH, scsi_bottom_half_handler);
+ 
      return 0;
  }
  
  void cleanup_module( void)
  {
+     remove_bh(SCSI_BH);
+ 
  #if CONFIG_PROC_FS
      proc_scsi_unregister(0, PROC_SCSI_SCSI);
  
***************
*** 3520,3527 ****
       */
      resize_dma_pool();
  
-     timer_table[SCSI_TIMER].fn = NULL;
-     timer_table[SCSI_TIMER].expires = 0;
  }
  #endif /* MODULE */
  
--- 3281,3286 ----
Index: linux/drivers/scsi/scsi.h
diff -c linux/drivers/scsi/scsi.h:1.1.1.2 linux/drivers/scsi/scsi.h:1.3
*** linux/drivers/scsi/scsi.h:1.1.1.2	Wed May 28 07:54:07 1997
--- linux/drivers/scsi/scsi.h	Wed May 28 08:37:31 1997
***************
*** 24,29 ****
--- 24,30 ----
  #include <linux/random.h>
  
  #include <asm/hardirq.h>
+ #include <asm/scatterlist.h>
  
  /*
   * Some defs, in case these are not defined elsewhere.
***************
*** 37,45 ****
  
  #define MAX_SCSI_DEVICE_CODE 10
  
! extern void scsi_make_blocked_list(void);
! extern volatile int in_scan_scsis;
! extern const unsigned char scsi_command_size[8];
  #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
  
  #define IDENTIFY_BASE       0x80
--- 38,92 ----
  
  #define MAX_SCSI_DEVICE_CODE 10
  
! /*
!  *  Use these to separate status msg and our bytes
!  *
!  *  These are set by:
!  *
!  *      status byte = set from target device
!  *      msg_byte    = return status from host adapter itself.
!  *      host_byte   = set by low-level driver to indicate status.
!  *      driver_byte = set by mid-level.
!  */
! #define status_byte(result) (((result) >> 1) & 0x1f)
! #define msg_byte(result)    (((result) >> 8) & 0xff)
! #define host_byte(result)   (((result) >> 16) & 0xff)
! #define driver_byte(result) (((result) >> 24) & 0xff)
! #define suggestion(result)  (driver_byte(result) & SUGGEST_MASK)
! 
! #define sense_class(sense)  (((sense) >> 4) & 0x7)
! #define sense_error(sense)  ((sense) & 0xf)
! #define sense_valid(sense)  ((sense) & 0x80);
! 
! #define NEEDS_RETRY     0x2001
! #define SUCCESS         0x2002
! #define FAILED          0x2003
! #define QUEUED          0x2004
! #define SOFT_ERROR      0x2005
! 
! /*
!  * These are the values that scsi_cmd->state can take.
!  */
! #define SCSI_STATE_TIMEOUT         0x1000
! #define SCSI_STATE_FINISHED        0x1001
! #define SCSI_STATE_FAILED          0x1002
! #define SCSI_STATE_QUEUED          0x1003
! #define SCSI_STATE_UNUSED          0x1006
! #define SCSI_STATE_DISCONNECTING   0x1008
! #define SCSI_STATE_INITIALIZING    0x1009
! #define SCSI_STATE_BHQUEUE         0x100a
! 
! /*
!  * These are the values that the owner field can take.
!  * They are used as an indication of who the command belongs to.
!  */
! #define SCSI_OWNER_HIGHLEVEL      0x100
! #define SCSI_OWNER_MIDLEVEL       0x101
! #define SCSI_OWNER_LOWLEVEL       0x102
! #define SCSI_OWNER_ERROR_HANDLER  0x103
! #define SCSI_OWNER_BH_HANDLER     0x104
! #define SCSI_OWNER_NOBODY         0x105
! 
  #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
  
  #define IDENTIFY_BASE       0x80
***************
*** 48,53 ****
--- 95,220 ----
  		     ((lun) & 0x07)) 
  
  		 
+ /*
+  * This defines the scsi logging feature.  It is a means by which the
+  * user can select how much information they get about various goings on,
+  * and it can be really useful for fault tracing.  The logging word is divided
+  * into 8 nibbles, each of which describes a loglevel.  The division of things
+  * is somewhat arbitrary, and the division of the word could be changed if it
+  * were really needed for any reason.  The numbers below are the only place where these
+  * are specified.  For a first go-around, 3 bits is more than enough, since this
+  * gives 8 levels of logging (really 7, since 0 is always off).  Cutting to 2 bits
+  * might be wise at some point.
+  */
+ 
+ #define SCSI_LOG_ERROR_SHIFT              0
+ #define SCSI_LOG_TIMEOUT_SHIFT            3
+ #define SCSI_LOG_SCAN_SHIFT               6
+ #define SCSI_LOG_MLQUEUE_SHIFT            9
+ #define SCSI_LOG_MLCOMPLETE_SHIFT         12
+ #define SCSI_LOG_LLQUEUE_SHIFT            15
+ #define SCSI_LOG_LLCOMPLETE_SHIFT         18
+ #define SCSI_LOG_HLQUEUE_SHIFT            21
+ #define SCSI_LOG_HLCOMPLETE_SHIFT         24
+ #define SCSI_LOG_IOCTL_SHIFT              27
+ 
+ #define SCSI_LOG_ERROR_BITS               3
+ #define SCSI_LOG_TIMEOUT_BITS             3
+ #define SCSI_LOG_SCAN_BITS                3
+ #define SCSI_LOG_MLQUEUE_BITS             3
+ #define SCSI_LOG_MLCOMPLETE_BITS          3
+ #define SCSI_LOG_LLQUEUE_BITS             3
+ #define SCSI_LOG_LLCOMPLETE_BITS          3
+ #define SCSI_LOG_HLQUEUE_BITS             3
+ #define SCSI_LOG_HLCOMPLETE_BITS          3
+ #define SCSI_LOG_IOCTL_BITS               3
+ 
+ #if CONFIG_SCSI_LOGGING
+ 
+ #define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)     \
+ {                                                       \
+         unsigned int mask;                              \
+                                                         \
+         mask = (1 << (BITS)) - 1;                       \
+         if( ((scsi_logging_level >> (SHIFT)) & mask) > (LEVEL) ) \
+         {                                               \
+                 (CMD);                                  \
+         }						\
+ }
+ 
+ #define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)            \
+ {                                                       \
+         unsigned int mask;                              \
+                                                         \
+         mask = ((1 << (BITS)) - 1) << SHIFT;            \
+         scsi_logging_level = ((scsi_logging_level & ~mask) \
+                               | ((LEVEL << SHIFT) & mask));     \
+ }
+ 
+ 
+ 
+ #else
+ 
+ /*
+  * With no logging enabled, stub these out so they don't do anything.
+  */
+ #define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)
+ 
+ #define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)
+ #endif
+ 
+ /*
+  * These are the macros that are actually used throughout the code to
+  * log events.  If logging isn't enabled, they are no-ops and will be
+  * completely absent from the user's code.
+  *
+  * The 'set' versions of the macros are really intended to only be called
+  * from the /proc filesystem, and in production kernels this will be about
+  * all that is ever used.  It could be useful in a debugging environment to
+  * bump the logging level when certain strange events are detected, however.
+  */
+ #define SCSI_LOG_ERROR_RECOVERY(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD);
+ #define SCSI_LOG_TIMEOUT(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL,CMD);
+ #define SCSI_LOG_SCAN_BUS(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL,CMD);
+ #define SCSI_LOG_MLQUEUE(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL,CMD);
+ #define SCSI_LOG_MLCOMPLETE(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL,CMD);
+ #define SCSI_LOG_LLQUEUE(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL,CMD);
+ #define SCSI_LOG_LLCOMPLETE(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL,CMD);
+ #define SCSI_LOG_HLQUEUE(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL,CMD);
+ #define SCSI_LOG_HLCOMPLETE(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL,CMD);
+ #define SCSI_LOG_IOCTL(LEVEL,CMD)  \
+         SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD);
+     
+ 
+ #define SCSI_SET_ERROR_RECOVERY_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL);
+ #define SCSI_SET_TIMEOUT_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL);
+ #define SCSI_SET_SCAN_BUS_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL);
+ #define SCSI_SET_MLQUEUE_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL);
+ #define SCSI_SET_MLCOMPLETE_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL);
+ #define SCSI_SET_LLQUEUE_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL);
+ #define SCSI_SET_LLCOMPLETE_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL);
+ #define SCSI_SET_HLQUEUE_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL);
+ #define SCSI_SET_HLCOMPLETE_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL);
+ #define SCSI_SET_IOCTL_LOGGING(LEVEL)  \
+         SCSI_SET_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL);
      
  /*
   *  the return of the status word will be in the following format :
***************
*** 79,84 ****
--- 246,252 ----
  #define DID_ERROR       0x07 /* Internal error                          */
  #define DID_RESET       0x08 /* Reset by somebody.                      */
  #define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */ 
+ #define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
  #define DRIVER_OK       0x00 /* Driver status                           */ 
  
  /*
***************
*** 137,150 ****
  #define IS_ABORTING     0x10
  #define ASKED_FOR_SENSE 0x20
  
  /*
   *  The scsi_device struct contains what we know about each given scsi
   *  device.
   */
  
! typedef struct scsi_device {
      struct scsi_device * next;      /* Used for linked list */
  
      unsigned char id, lun, channel;
  
      unsigned int manufacturer;      /* Manufacturer of device, for using 
--- 305,410 ----
  #define IS_ABORTING     0x10
  #define ASKED_FOR_SENSE 0x20
  
+ 
+ #define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
+ 
+ /*
+  * This is the crap from the old error handling code.  We have it in a special
+  * place so that we can more easily delete it later on.
+  */
+ #include "scsi_obsolete.h"
+ 
+ /*
+  * Add some typedefs so that we can prototyope a bunch of the functions.
+  */
+ typedef struct scsi_device Scsi_Device;
+ typedef struct scsi_cmnd   Scsi_Cmnd;
+ 
+ /*
+  * Here is where we prototype most of the mid-layer.
+  */
+ 
+ /*
+  *  Initializes all SCSI devices.  This scans all scsi busses.
+  */ 
+ 
+ extern int scsi_dev_init (void);
+ 
+ 
+ 
+ void *   scsi_malloc(unsigned int);
+ int      scsi_free(void *, unsigned int);
+ extern unsigned int scsi_logging_level; /* What do we log? */
+ extern unsigned int scsi_dma_free_sectors;  /* How much room do we have left */
+ extern unsigned int scsi_need_isa_buffer;   /* True if some devices need indirection
+ 					* buffers */
+ extern void scsi_make_blocked_list(void);
+ extern volatile int in_scan_scsis;
+ extern const unsigned char scsi_command_size[8];
+ 
+ /*
+  * These are the error handling functions defined in scsi_error.c
+  */
+ extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout, 
+                                 void (*complete)(Scsi_Cmnd *));
+ extern void scsi_done (Scsi_Cmnd *SCpnt);
+ extern int  scsi_delete_timer(Scsi_Cmnd * SCset);
+ extern void scsi_error_handler(void * host);
+ extern int  scsi_retry_command(Scsi_Cmnd *);
+ extern void scsi_finish_command(Scsi_Cmnd *);
+ extern int  scsi_sense_valid(Scsi_Cmnd *);
+ extern int  scsi_decide_disposition (Scsi_Cmnd * SCpnt);
+ extern int  scsi_block_when_processing_errors(Scsi_Device *);
+ extern void scsi_sleep(int);
+ 
+ /*
+  *  scsi_abort aborts the current command that is executing on host host.
+  *  The error code, if non zero is returned in the host byte, otherwise 
+  *  DID_ABORT is returned in the hostbyte.
+  */
+ 
+ extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
+ 			 void *buffer, unsigned bufflen, 
+ 			 void (*done)(struct scsi_cmnd *),
+ 			 int timeout, int retries);
+ 
+ 
+ extern Scsi_Cmnd * scsi_allocate_device(struct request **, Scsi_Device *, int);
+ 
+ extern Scsi_Cmnd * scsi_request_queueable(struct request *, Scsi_Device *);
+ 
+ extern void scsi_release_command(Scsi_Cmnd *);
+ 
+ extern int max_scsi_hosts;
+ 
+ extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
+ 
+ extern void print_command(unsigned char *);
+ extern void print_sense(const char *, Scsi_Cmnd *);
+ extern void print_driverbyte(int scsiresult);
+ extern void print_hostbyte(int scsiresult);
+ 
  /*
   *  The scsi_device struct contains what we know about each given scsi
   *  device.
   */
  
! struct scsi_device {
! /* private: */
!     /*
!      * This information is private to the scsi mid-layer.  Wrapping it in a
!      * struct private is a way of marking it in a sort of C++ type of way.
!      */
      struct scsi_device * next;      /* Used for linked list */
+     struct scsi_device * prev;      /* Used for linked list */
+     struct wait_queue  * device_wait;/* Used to wait if
+                                                       device is busy */
+     struct Scsi_Host   * host;
+     void              (* scsi_request_fn)(void);  /* Used to jumpstart things after an 
+                                      * ioctl */
+     Scsi_Cmnd          * device_queue;    /* queue of SCSI Command structures */
  
+ /* public: */
      unsigned char id, lun, channel;
  
      unsigned int manufacturer;      /* Manufacturer of device, for using 
***************
*** 152,162 ****
      int attached;                   /* # of high level drivers attached to 
  				     * this */
      int access_count;               /* Count of open channels/mounts */
!     struct wait_queue * device_wait;/* Used to wait if device is busy */
!     struct Scsi_Host * host;
!     void (*scsi_request_fn)(void);  /* Used to jumpstart things after an 
! 				     * ioctl */
!     struct scsi_cmnd *device_queue; /* queue of SCSI Command structures */
      void *hostdata;                 /* available to low-level driver */
      char type;
      char scsi_level;
--- 412,418 ----
      int attached;                   /* # of high level drivers attached to 
  				     * this */
      int access_count;               /* Count of open channels/mounts */
! 
      void *hostdata;                 /* available to low-level driver */
      char type;
      char scsi_level;
***************
*** 166,171 ****
--- 422,428 ----
      unsigned char sync_max_offset;  /* Not greater than this offset */
      unsigned char queue_depth;	    /* How deep a queue to use */
  
+     unsigned online:1;
      unsigned writeable:1;
      unsigned removable:1; 
      unsigned random:1;
***************
*** 188,222 ****
                                       * this device */
      unsigned expecting_cc_ua:1;     /* Expecting a CHECK_CONDITION/UNIT_ATTN
                                       * because we did a bus reset. */
! } Scsi_Device;
! 
! /*
!  *  Use these to separate status msg and our bytes
!  */
! 
! #define status_byte(result) (((result) >> 1) & 0x1f)
! #define msg_byte(result)    (((result) >> 8) & 0xff)
! #define host_byte(result)   (((result) >> 16) & 0xff)
! #define driver_byte(result) (((result) >> 24) & 0xff)
! #define suggestion(result)  (driver_byte(result) & SUGGEST_MASK)
! 
! #define sense_class(sense)  (((sense) >> 4) & 0x7)
! #define sense_error(sense)  ((sense) & 0xf)
! #define sense_valid(sense)  ((sense) & 0x80);
! 
! /*
!  *  These are the SCSI devices available on the system.
!  */
! 
! extern Scsi_Device * scsi_devices;
! 
! /*
!  *  Initializes all SCSI devices.  This scans all scsi busses.
!  */ 
! 
! extern int scsi_dev_init (void);
! 
! #include <asm/scatterlist.h>
  
  #ifdef __mc68000__
  #include <asm/pgtable.h>
--- 445,451 ----
                                       * this device */
      unsigned expecting_cc_ua:1;     /* Expecting a CHECK_CONDITION/UNIT_ATTN
                                       * because we did a bus reset. */
! };
  
  #ifdef __mc68000__
  #include <asm/pgtable.h>
***************
*** 228,336 ****
  
  
  /*
-  * These are the return codes for the abort and reset functions.  The mid-level
-  * code uses these to decide what to do next.  Each of the low level abort
-  * and reset functions must correctly indicate what it has done.
-  * The descriptions are written from the point of view of the mid-level code,
-  * so that the return code is telling the mid-level drivers exactly what
-  * the low level driver has already done, and what remains to be done.
-  */
- 
- /* We did not do anything.  
-  * Wait some more for this command to complete, and if this does not work, 
-  * try something more serious. */ 
- #define SCSI_ABORT_SNOOZE 0
- 
- /* This means that we were able to abort the command.  We have already
-  * called the mid-level done function, and do not expect an interrupt that 
-  * will lead to another call to the mid-level done function for this command */
- #define SCSI_ABORT_SUCCESS 1
- 
- /* We called for an abort of this command, and we should get an interrupt 
-  * when this succeeds.  Thus we should not restore the timer for this
-  * command in the mid-level abort function. */
- #define SCSI_ABORT_PENDING 2
- 
- /* Unable to abort - command is currently on the bus.  Grin and bear it. */
- #define SCSI_ABORT_BUSY 3
- 
- /* The command is not active in the low level code. Command probably
-  * finished. */
- #define SCSI_ABORT_NOT_RUNNING 4
- 
- /* Something went wrong.  The low level driver will indicate the correct
-  * error condition when it calls scsi_done, so the mid-level abort function
-  * can simply wait until this comes through */
- #define SCSI_ABORT_ERROR 5
- 
- /* We do not know how to reset the bus, or we do not want to.  Bummer.
-  * Anyway, just wait a little more for the command in question, and hope that
-  * it eventually finishes.  If it never finishes, the SCSI device could
-  * hang, so use this with caution. */
- #define SCSI_RESET_SNOOZE 0
- 
- /* We do not know how to reset the bus, or we do not want to.  Bummer.
-  * We have given up on this ever completing.  The mid-level code will
-  * request sense information to decide how to proceed from here. */
- #define SCSI_RESET_PUNT 1
- 
- /* This means that we were able to reset the bus.  We have restarted all of
-  * the commands that should be restarted, and we should be able to continue
-  * on normally from here.  We do not expect any interrupts that will return
-  * DID_RESET to any of the other commands in the host_queue, and the mid-level
-  * code does not need to do anything special to keep the commands alive. 
-  * If a hard reset was performed then all outstanding commands on the
-  * bus have been restarted. */
- #define SCSI_RESET_SUCCESS 2
- 
- /* We called for a reset of this bus, and we should get an interrupt 
-  * when this succeeds.  Each command should get its own status
-  * passed up to scsi_done, but this has not happened yet. 
-  * If a hard reset was performed, then we expect an interrupt
-  * for *each* of the outstanding commands that will have the
-  * effect of restarting the commands.
-  */
- #define SCSI_RESET_PENDING 3
- 
- /* We did a reset, but do not expect an interrupt to signal DID_RESET.
-  * This tells the upper level code to request the sense info, and this
-  * should keep the command alive. */
- #define SCSI_RESET_WAKEUP 4
- 
- /* The command is not active in the low level code. Command probably
-    finished. */
- #define SCSI_RESET_NOT_RUNNING 5
- 
- /* Something went wrong, and we do not know how to fix it. */
- #define SCSI_RESET_ERROR 6
- 
- #define SCSI_RESET_SYNCHRONOUS		0x01
- #define SCSI_RESET_ASYNCHRONOUS		0x02
- #define SCSI_RESET_SUGGEST_BUS_RESET	0x04
- #define SCSI_RESET_SUGGEST_HOST_RESET	0x08
- /*
-  * This is a bitmask that is ored with one of the above codes.
-  * It tells the mid-level code that we did a hard reset.
-  */
- #define SCSI_RESET_BUS_RESET 0x100
- /*
-  * This is a bitmask that is ored with one of the above codes.
-  * It tells the mid-level code that we did a host adapter reset.
-  */
- #define SCSI_RESET_HOST_RESET 0x200
- /*
-  * Used to mask off bits and to obtain the basic action that was
-  * performed.  
-  */
- #define SCSI_RESET_ACTION   0xff
- 
- void *   scsi_malloc(unsigned int);
- int      scsi_free(void *, unsigned int);
- extern unsigned int dma_free_sectors;  /* How much room do we have left */
- extern unsigned int need_isa_buffer;   /* True if some devices need indirection
- 					* buffers */
- 
- /*
   * The Scsi_Cmnd structure is used by scsi.c internally, and for communication
   * with low level drivers that support multiple outstanding commands.
   */
--- 457,462 ----
***************
*** 347,389 ****
      volatile int phase;
  } Scsi_Pointer;
  
! typedef struct scsi_cmnd {
      struct Scsi_Host * host;
!     Scsi_Device * device;
!     unsigned char target, lun, channel;
!     unsigned char cmd_len;
!     unsigned char old_cmd_len;
!     struct scsi_cmnd *next, *prev, *device_next, *reset_chain;
!     
!     /* These elements define the operation we are about to perform */
!     unsigned char cmnd[12];
!     unsigned request_bufflen;	/* Actual request size */
!     
!     void * request_buffer;	/* Actual requested buffer */
!     
!     /* These elements define the operation we ultimately want to perform */
!     unsigned char data_cmnd[12];
!     unsigned short old_use_sg;	/* We save  use_sg here when requesting
! 				 * sense info */
!     unsigned short use_sg;	/* Number of pieces of scatter-gather */
!     unsigned short sglist_len;	/* size of malloc'd scatter-gather list */
!     unsigned short abort_reason;/* If the mid-level code requests an
! 				 * abort, this is the reason. */
!     unsigned bufflen;		/* Size of data buffer */
!     void *buffer;		/* Data buffer */
!     
!     unsigned underflow;		/* Return error if less than this amount is 
! 				 * transfered */
!     
!     unsigned transfersize;	/* How much we are guaranteed to transfer with
! 				 * each SCSI transfer (ie, between disconnect /
! 				 * reconnects.	 Probably == sector size */
      
!     
!     struct request request;	/* A copy of the command we are working on */
! 
!     unsigned char sense_buffer[16];  /* Sense for this command, if needed */
! 
      /*
        A SCSI Command is assigned a nonzero serial_number when internal_cmnd
        passes it to the driver's queue command function.  The serial_number
--- 473,494 ----
      volatile int phase;
  } Scsi_Pointer;
  
! 
! struct scsi_cmnd {
! /* private: */
!     /*
!      * This information is private to the scsi mid-layer.  Wrapping it in a
!      * struct private is a way of marking it in a sort of C++ type of way.
!      */
      struct Scsi_Host * host;
!     unsigned short     state;
!     unsigned short     owner;
!     Scsi_Device      * device;
!     struct scsi_cmnd * next;
!     struct scsi_cmnd * reset_chain;
      
!     int                 eh_state; /* Used for state tracking in error handlr */
!     void               (*done)(struct scsi_cmnd *);  /* Mid-level done function */
      /*
        A SCSI Command is assigned a nonzero serial_number when internal_cmnd
        passes it to the driver's queue command function.  The serial_number
***************
*** 396,436 ****
        completed and the SCSI Command structure has already being reused
        for another command, so that we can avoid incorrectly aborting or
        resetting the new command.
!     */
! 
!     unsigned long serial_number;
!     unsigned long serial_number_at_timeout;
! 
!     int retries;
!     int allowed;
!     int timeout_per_command, timeout_total, timeout;
! 
      /*
!      *	We handle the timeout differently if it happens when a reset, 
!      *	abort, etc are in process. 
       */
      unsigned volatile char internal_timeout;
      
!     unsigned flags;
      
      /* These variables are for the cdrom only. Once we have variable size 
       * buffers in the buffer cache, they will go away. */
!     int this_count; 
      /* End of special cdrom variables */
      
      /* Low-level done function - can be used by low-level driver to point
       *	to completion function.	 Not used by mid/upper level code. */
!     void (*scsi_done)(struct scsi_cmnd *);  
!     void (*done)(struct scsi_cmnd *);  /* Mid-level done function */
      
      /*
       * The following fields can be written to by the host specific code. 
       * Everything else should be left alone. 
       */
      
!     Scsi_Pointer SCp;	/* Scratchpad used by some host adapters */
      
!     unsigned char * host_scribble; /* The host adapter is allowed to
  				    * call scsi_malloc and get some memory
  				    * and hang it here.	 The host adapter
  				    * is also expected to call scsi_free
--- 501,586 ----
        completed and the SCSI Command structure has already being reused
        for another command, so that we can avoid incorrectly aborting or
        resetting the new command.
!       */
!     
!     unsigned long      serial_number;
!     unsigned long      serial_number_at_timeout;
!     
!     int                retries;
!     int                allowed;
!     int                timeout_per_command;
!     int                timeout_total;
!     int                timeout;
!     
      /*
!      * We handle the timeout differently if it happens when a reset, 
!      * abort, etc are in process. 
       */
      unsigned volatile char internal_timeout;
+     struct scsi_cmnd  * bh_next;  /* To enumerate the commands waiting 
+                                      to be processed. */
+     
+ /* public: */
+ 
+     unsigned char      target;
+     unsigned char      lun;
+     unsigned char      channel;
+     unsigned char      cmd_len;
+     unsigned char      old_cmd_len;
+ 
+     /* These elements define the operation we are about to perform */
+     unsigned char      cmnd[12];
+     unsigned           request_bufflen;	/* Actual request size */
+     
+     struct timer_list  eh_timeout;         /* Used to time out the command. */
+     void             * request_buffer;	/* Actual requested buffer */
+     
+     /* These elements define the operation we ultimately want to perform */
+     unsigned char      data_cmnd[12];
+     unsigned short     old_use_sg;	/* We save  use_sg here when requesting
+                                          * sense info */
+     unsigned short     use_sg;          /* Number of pieces of scatter-gather */
+     unsigned short     sglist_len;	/* size of malloc'd scatter-gather list */
+     unsigned short     abort_reason;    /* If the mid-level code requests an
+                                          * abort, this is the reason. */
+     unsigned           bufflen;		/* Size of data buffer */
+     void             * buffer;		/* Data buffer */
+     
+     unsigned           underflow;	/* Return error if less than
+                                            this amount is transfered */
+     
+     unsigned           transfersize;	/* How much we are guaranteed to
+                                            transfer with each SCSI transfer
+                                            (ie, between disconnect / 
+                                            reconnects.	 Probably == sector
+                                            size */
      
!     
!     struct request     request;           /* A copy of the command we are
!                                              working on */
! 
!     unsigned char      sense_buffer[16];  /* Sense for this command, 
!                                              needed */
!     
!     unsigned           flags;
      
      /* These variables are for the cdrom only. Once we have variable size 
       * buffers in the buffer cache, they will go away. */
!     int                this_count; 
      /* End of special cdrom variables */
      
      /* Low-level done function - can be used by low-level driver to point
       *	to completion function.	 Not used by mid/upper level code. */
!     void               (*scsi_done)(struct scsi_cmnd *);  
      
      /*
       * The following fields can be written to by the host specific code. 
       * Everything else should be left alone. 
       */
      
!     Scsi_Pointer       SCp;	   /* Scratchpad used by some host adapters */
      
!     unsigned char    * host_scribble; /* The host adapter is allowed to
  				    * call scsi_malloc and get some memory
  				    * and hang it here.	 The host adapter
  				    * is also expected to call scsi_free
***************
*** 438,479 ****
  				    * obtained by scsi_malloc is guaranteed
  				    * to be at an address < 16Mb). */
      
!     int result;			   /* Status code from lower level driver */
      
!     unsigned char tag;		   /* SCSI-II queued command tag */
!     unsigned long pid;		   /* Process ID, starts at 0 */
! } Scsi_Cmnd;	     
! 
! /*
!  *  scsi_abort aborts the current command that is executing on host host.
!  *  The error code, if non zero is returned in the host byte, otherwise 
!  *  DID_ABORT is returned in the hostbyte.
!  */
! 
! extern int scsi_abort (Scsi_Cmnd *, int code);
! 
! extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
! 			 void *buffer, unsigned bufflen, 
! 			 void (*done)(struct scsi_cmnd *),
! 			 int timeout, int retries);
! 
! 
! extern Scsi_Cmnd * allocate_device(struct request **, Scsi_Device *, int);
! 
! extern Scsi_Cmnd * request_queueable(struct request *, Scsi_Device *);
! extern int scsi_reset (Scsi_Cmnd *, unsigned int);
! 
! extern int max_scsi_hosts;
! 
! extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
! 
! extern void print_command(unsigned char *);
! extern void print_sense(const char *, Scsi_Cmnd *);
! extern void print_driverbyte(int scsiresult);
! extern void print_hostbyte(int scsiresult);
  
- extern void scsi_mark_host_reset(struct Scsi_Host *Host);
- extern void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel);
  
  #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
  #include "hosts.h"
--- 588,599 ----
  				    * obtained by scsi_malloc is guaranteed
  				    * to be at an address < 16Mb). */
      
!     int                result;	   /* Status code from lower level driver */
      
!     unsigned char      tag;	   /* SCSI-II queued command tag */
!     unsigned long      pid;	   /* Process ID, starts at 0 */
! };
  
  
  #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
  #include "hosts.h"
***************
*** 526,534 ****
  	    wake_up(&next->host_wait);
      }
      
-     req->rq_status = RQ_INACTIVE;
      wake_up(&wait_for_request);
      wake_up(&SCpnt->device->device_wait);
      return NULL;
  }
  
--- 646,654 ----
  	    wake_up(&next->host_wait);
      }
      
      wake_up(&wait_for_request);
      wake_up(&SCpnt->device->device_wait);
+     scsi_release_command(SCpnt);
      return NULL;
  }
  
Index: linux/drivers/scsi/scsi_debug.c
diff -c linux/drivers/scsi/scsi_debug.c:1.1.1.1 linux/drivers/scsi/scsi_debug.c:1.2
*** linux/drivers/scsi/scsi_debug.c:1.1.1.1	Sun May 18 19:18:08 1997
--- linux/drivers/scsi/scsi_debug.c	Sun May 18 19:27:19 1997
***************
*** 43,48 ****
--- 43,55 ----
  
  /* A few options that we want selected */
  
+ #define NR_HOSTS_PRESENT 1
+ #define NR_FAKE_DISKS   3
+ #define N_HEAD          32
+ #define N_SECTOR        64
+ #define DISK_READONLY(TGT)      (1)
+ #define DISK_REMOVEABLE(TGT)    (1)
+ 
  /* Do not attempt to use a timer to simulate a real disk with latency */
  /* Only use this in the actual kernel, not in the simulator. */
  #define IMMEDIATE
***************
*** 63,69 ****
  #define DISK_SPEED     10
  #define CAPACITY (0x80000)
  
! static int starts[] = {4, 1000, 50000, CAPACITY, 0};
  static int npart = 0;
  
  #include "scsi_debug.h"
--- 70,76 ----
  #define DISK_SPEED     10
  #define CAPACITY (0x80000)
  
! static int starts[] = {N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0};
  static int npart = 0;
  
  #include "scsi_debug.h"
***************
*** 74,81 ****
  #endif
  
  #ifdef SPEEDY
! #define VERIFY1_DEBUG(RW) 1
! #define VERIFY_DEBUG(RW) 1
  #else
  
  #define VERIFY1_DEBUG(RW)                           \
--- 81,88 ----
  #endif
  
  #ifdef SPEEDY
! #define VERIFY1_DEBUG(RW) 
! #define VERIFY_DEBUG(RW) 
  #else
  
  #define VERIFY1_DEBUG(RW)                           \
***************
*** 111,120 ****
      };
  #endif
  
! static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, };
! extern void scsi_debug_interrupt();
  
! volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
  static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,};
  static volatile unsigned int timeout[8] ={0,};
  
--- 118,130 ----
      };
  #endif
  
! typedef void (*done_fct_t)(Scsi_Cmnd *);
! 
! static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = {NULL, };
! 
! static void scsi_debug_intr_handle(void);
  
! Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
  static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,};
  static volatile unsigned int timeout[8] ={0,};
  
***************
*** 137,147 ****
  	sgpnt = (struct scatterlist *) SCpnt->buffer;
  	for(i=0; i<SCpnt->use_sg; i++) {
  	    lpnt = (int *) sgpnt[i].alt_address;
! 	    printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
  	    if (lpnt) printk(" (Alt %x) ",lpnt[15]);
  	};
      } else {
! 	printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
  	       SCpnt->bufflen);
  	lpnt = (int *) SCpnt->request.buffer;
  	if (lpnt) printk(" (Alt %x) ",lpnt[15]);
--- 147,157 ----
  	sgpnt = (struct scatterlist *) SCpnt->buffer;
  	for(i=0; i<SCpnt->use_sg; i++) {
  	    lpnt = (int *) sgpnt[i].alt_address;
! 	    printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
  	    if (lpnt) printk(" (Alt %x) ",lpnt[15]);
  	};
      } else {
! 	printk("nosg: %p %p %d\n",SCpnt->request.buffer, SCpnt->buffer,
  	       SCpnt->bufflen);
  	lpnt = (int *) SCpnt->request.buffer;
  	if (lpnt) printk(" (Alt %x) ",lpnt[15]);
***************
*** 167,180 ****
      };
      printk("\n");
  #endif
!     printk("DMA free %d sectors.\n", dma_free_sectors);
  }
  
  int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
  {
      unchar *cmd = (unchar *) SCpnt->cmnd;
      struct partition * p;
!     int block, start;
      struct buffer_head * bh = NULL;
      unsigned char * buff;
      int nbytes, sgcount;
--- 177,190 ----
      };
      printk("\n");
  #endif
!     printk("DMA free %d sectors.\n", scsi_dma_free_sectors);
  }
  
  int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
  {
      unchar *cmd = (unchar *) SCpnt->cmnd;
      struct partition * p;
!     int block;
      struct buffer_head * bh = NULL;
      unsigned char * buff;
      int nbytes, sgcount;
***************
*** 187,201 ****
      sgcount = 0;
      sgpnt = NULL;
      
!     DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;});
      
      buff = (unsigned char *) SCpnt->request_buffer;
      
!     if(target>=1 || SCpnt->lun != 0) {
  	SCpnt->result =  DID_NO_CONNECT << 16;
  	done(SCpnt);
  	return 0;
!     };
      
      if( SCrst[target] != 0 && !scsi_debug_lockup )
      {
--- 197,224 ----
      sgcount = 0;
      sgpnt = NULL;
      
!     /*
!      * If we are being notified of the mid-level reposessing a command due to timeout,
!      * just return.
!      */
!     if( done == NULL )
!     {
!         return 0;
!     }
! 
!     DEB(if (target >= NR_FAKE_DISKS) 
!         { 
!             SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;
!         });
      
      buff = (unsigned char *) SCpnt->request_buffer;
      
!     if(target>=NR_FAKE_DISKS || SCpnt->lun != 0) 
!     {
  	SCpnt->result =  DID_NO_CONNECT << 16;
  	done(SCpnt);
  	return 0;
!     }
      
      if( SCrst[target] != 0 && !scsi_debug_lockup )
      {
***************
*** 208,218 ****
      }
      switch(*cmd){
      case REQUEST_SENSE:
! 	printk("Request sense...\n");
  #ifndef DEBUG
  	{ 
  	    int i;
! 	    printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
  	    for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
  	    printk("\n");
  	};
--- 231,241 ----
      }
      switch(*cmd){
      case REQUEST_SENSE:
! 	SCSI_LOG_LLQUEUE(3,printk("Request sense...\n"));
  #ifndef DEBUG
  	{ 
  	    int i;
! 	    printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
  	    for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
  	    printk("\n");
  	};
***************
*** 224,238 ****
  	done(SCpnt); 
  	return 0;
      case ALLOW_MEDIUM_REMOVAL:
! 	if(cmd[4]) printk("Medium removal inhibited...");
! 	else printk("Medium removal enabled...");
  	scsi_debug_errsts = 0;
  	break;
      case INQUIRY:
! 	printk("Inquiry...(%x %d)\n", buff, bufflen);
  	memset(buff, 0, bufflen);
  	buff[0] = TYPE_DISK;
! 	buff[1] = 0x80;  /* Removable disk */
  	buff[2] = 1;
  	buff[4] = 33 - 5;
  	memcpy(&buff[8],"Foo Inc",7);
--- 247,267 ----
  	done(SCpnt); 
  	return 0;
      case ALLOW_MEDIUM_REMOVAL:
! 	if(cmd[4]) 
!         {
!             SCSI_LOG_LLQUEUE(2,printk("Medium removal inhibited..."));
!         }
! 	else
!         {
!             SCSI_LOG_LLQUEUE(2,printk("Medium removal enabled..."));
!         }
  	scsi_debug_errsts = 0;
  	break;
      case INQUIRY:
! 	SCSI_LOG_LLQUEUE(3,printk("Inquiry...(%p %d)\n", buff, bufflen));
  	memset(buff, 0, bufflen);
  	buff[0] = TYPE_DISK;
! 	buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;  /* Removable disk */
  	buff[2] = 1;
  	buff[4] = 33 - 5;
  	memcpy(&buff[8],"Foo Inc",7);
***************
*** 241,253 ****
  	scsi_debug_errsts = 0;
  	break;
      case TEST_UNIT_READY:
! 	printk("Test unit ready(%x %d)\n", buff, bufflen);
  	if (buff)
  	    memset(buff, 0, bufflen);
  	scsi_debug_errsts = 0;
  	break;
      case READ_CAPACITY:
! 	printk("Read Capacity\n");
  	if(NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
  	memset(buff, 0, bufflen);
  	buff[0] = (CAPACITY >> 24);
--- 270,282 ----
  	scsi_debug_errsts = 0;
  	break;
      case TEST_UNIT_READY:
! 	SCSI_LOG_LLQUEUE(3,printk("Test unit ready(%p %d)\n", buff, bufflen));
  	if (buff)
  	    memset(buff, 0, bufflen);
  	scsi_debug_errsts = 0;
  	break;
      case READ_CAPACITY:
! 	SCSI_LOG_LLQUEUE(3,printk("Read Capacity\n"));
  	if(NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
  	memset(buff, 0, bufflen);
  	buff[0] = (CAPACITY >> 24);
***************
*** 308,313 ****
--- 337,348 ----
  		    p->start_sect = starts[npart];
  		    p->nr_sects = starts[npart+1] - starts [npart];
  		    p->sys_ind = 0x81;  /* Linux partition */
+                     p->head       = (npart == 0 ? 1 : 0);
+                     p->sector     = 1;
+                     p->cyl        = starts[npart] / N_HEAD / N_SECTOR;
+                     p->end_head   = N_HEAD - 1;
+                     p->end_sector = N_SECTOR;
+                     p->end_cyl    = starts[npart + 1] / N_HEAD / N_SECTOR;
  		    p++;
  		    npart++;
  		};
***************
*** 365,371 ****
  	
  	SCpnt->result = 0;
  	(done)(SCpnt);
! 	return;
  	
  	if (SCpnt->use_sg && !scsi_debug_errsts)
  	    if(bh) scsi_dump(SCpnt, 0);
--- 400,406 ----
  	
  	SCpnt->result = 0;
  	(done)(SCpnt);
! 	return 0;
  	
  	if (SCpnt->use_sg && !scsi_debug_errsts)
  	    if(bh) scsi_dump(SCpnt, 0);
***************
*** 396,403 ****
  #endif
  	scsi_debug_errsts = 0;
  	break;
      default:
! 	printk("Unknown command %d\n",*cmd);
  	SCpnt->result =  DID_NO_CONNECT << 16;
  	done(SCpnt);
  	return 0;
--- 431,445 ----
  #endif
  	scsi_debug_errsts = 0;
  	break;
+     case MODE_SENSE:
+         /*
+          * Used to detect write protected status.
+          */
+ 	scsi_debug_errsts = 0;
+         memset(buff, 0, 6);
+         break;
      default:
! 	SCSI_LOG_LLQUEUE(3,printk("Unknown command %d\n",*cmd));
  	SCpnt->result =  DID_NO_CONNECT << 16;
  	done(SCpnt);
  	return 0;
***************
*** 552,563 ****
  
  int scsi_debug_detect(Scsi_Host_Template * tpnt)
  {
!     tpnt->proc_dir = &proc_scsi_scsi_debug;
  #ifndef IMMEDIATE
!     timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle;
!     timer_table[SCSI_DEBUG_TIMER].expires = 0;
  #endif
!     return 1;
  }
  
  int scsi_debug_abort(Scsi_Cmnd * SCpnt)
--- 594,611 ----
  
  int scsi_debug_detect(Scsi_Host_Template * tpnt)
  {
!     int i;
! 
!     for(i=0; i < NR_HOSTS_PRESENT; i++)
!     {
!         tpnt->proc_dir = &proc_scsi_scsi_debug;
  #ifndef IMMEDIATE
!         timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle;
!         timer_table[SCSI_DEBUG_TIMER].expires = 0;
  #endif
!         scsi_register(tpnt,0);
!     }
!     return NR_HOSTS_PRESENT;
  }
  
  int scsi_debug_abort(Scsi_Cmnd * SCpnt)
***************
*** 587,606 ****
  
  int scsi_debug_biosparam(Disk * disk, kdev_t dev, int* info){
      int size = disk->capacity;
!     info[0] = 32;
!     info[1] = 64;
      info[2] = (size + 2047) >> 11;
      if (info[2] >= 1024) info[2] = 1024;
      return 0;
  }
  
! int scsi_debug_reset(Scsi_Cmnd * SCpnt)
  {
      int i;
      unsigned long flags;
      
      void (*my_done)(Scsi_Cmnd *);
!     printk("Bus unlocked by reset(%d)\n", SCpnt->host->suggest_bus_reset);
      scsi_debug_lockup = 0;
      DEB(printk("scsi_debug_reset called\n"));
      for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
--- 635,654 ----
  
  int scsi_debug_biosparam(Disk * disk, kdev_t dev, int* info){
      int size = disk->capacity;
!     info[0] = N_HEAD;
!     info[1] = N_SECTOR;
      info[2] = (size + 2047) >> 11;
      if (info[2] >= 1024) info[2] = 1024;
      return 0;
  }
  
! int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
  {
      int i;
      unsigned long flags;
      
      void (*my_done)(Scsi_Cmnd *);
!     printk("Bus unlocked by reset - %d\n", why);
      scsi_debug_lockup = 0;
      DEB(printk("scsi_debug_reset called\n"));
      for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
***************
*** 633,644 ****
--- 681,701 ----
      int len, pos, begin;
      int orig_length;
  
+     orig_length = length;
+ 
      if(inout == 1)
      {
          /* First check for the Signature */
          if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
              buffer += 11;
              length -= 11;
+ 
+             if( buffer[length - 1] == '\n' )
+             {
+                 buffer[length-1] = '\0';
+                 length--;
+             }
+ 
              /*
               * OK, we are getting some kind of command.  Figure out
               * what we are supposed to do here.  Simulate bus lockups
***************
*** 647,664 ****
              if( length == 6 && strncmp(buffer, "lockup", length) == 0 )
              {
                  scsi_debug_lockup = 1;
!                 return length;
              } 
              
              if( length == 6 && strncmp(buffer, "unlock", length) == 0 )
              {
                  scsi_debug_lockup = 0;
!                 return length;
              } 
              
!             printk("Unknown command:%s\n", buffer);
          } else 
!             printk("Wrong Signature:%10s\n", (char *) ((ulong)buffer-11));
  
          return -EINVAL;
          
--- 704,721 ----
              if( length == 6 && strncmp(buffer, "lockup", length) == 0 )
              {
                  scsi_debug_lockup = 1;
!                 return orig_length;
              } 
              
              if( length == 6 && strncmp(buffer, "unlock", length) == 0 )
              {
                  scsi_debug_lockup = 0;
!                 return orig_length;
              } 
              
!             printk("Unknown command:%s (%d)\n", buffer, length);
          } else 
!             printk("Wrong Signature:%10s\n", (char *) buffer);
  
          return -EINVAL;
          
Index: linux/drivers/scsi/scsi_debug.h
diff -c linux/drivers/scsi/scsi_debug.h:1.1.1.1 linux/drivers/scsi/scsi_debug.h:1.2
*** linux/drivers/scsi/scsi_debug.h:1.1.1.1	Sun May 18 19:18:08 1997
--- linux/drivers/scsi/scsi_debug.h	Sun May 18 19:27:19 1997
***************
*** 8,14 ****
  int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
  int scsi_debug_abort(Scsi_Cmnd *);
  int scsi_debug_biosparam(Disk *, kdev_t, int[]);
! int scsi_debug_reset(Scsi_Cmnd *);
  int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
   
  #ifndef NULL
--- 8,14 ----
  int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
  int scsi_debug_abort(Scsi_Cmnd *);
  int scsi_debug_biosparam(Disk *, kdev_t, int[]);
! int scsi_debug_reset(Scsi_Cmnd *, unsigned int);
  int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
   
  #ifndef NULL
***************
*** 18,30 ****
  
  #define SCSI_DEBUG_MAILBOXES 8
  
! #define SCSI_DEBUG {NULL, NULL, NULL, scsi_debug_proc_info, \
! 		"SCSI DEBUG", scsi_debug_detect, NULL, \
! 		NULL, scsi_debug_command,		\
! 		scsi_debug_queuecommand,			\
! 		scsi_debug_abort,				\
! 		scsi_debug_reset,				\
! 		NULL,						\
! 		scsi_debug_biosparam,				\
! 		SCSI_DEBUG_MAILBOXES, 7, SG_ALL, 1, 0, 1, ENABLE_CLUSTERING}
  #endif
--- 18,37 ----
  
  #define SCSI_DEBUG_MAILBOXES 8
  
! #define SCSI_DEBUG {proc_info:         scsi_debug_proc_info,	\
! 		    name:              "SCSI DEBUG",		\
! 		    detect:            scsi_debug_detect,	\
! 		    command:           scsi_debug_command,	\
! 		    queuecommand:      scsi_debug_queuecommand, \
! 		    abort:             scsi_debug_abort,	\
! 		    reset:             scsi_debug_reset,	\
! 		    bios_param:        scsi_debug_biosparam,	\
! 		    can_queue:         SCSI_DEBUG_MAILBOXES,	\
! 		    this_id:           7,			\
! 		    sg_tablesize:      SG_ALL,			\
! 		    cmd_per_lun:       1,			\
! 		    unchecked_isa_dma: 1,			\
! 		    use_clustering:    ENABLE_CLUSTERING,	\
! 		    use_new_eh_code:   1,			\
! }
  #endif
Index: linux/drivers/scsi/scsi_error.c
diff -c /dev/null linux/drivers/scsi/scsi_error.c:1.5
*** /dev/null	Fri Jun  6 01:03:52 1997
--- linux/drivers/scsi/scsi_error.c	Thu Jun  5 23:30:40 1997
***************
*** 0 ****
--- 1,1877 ----
+ /*
+  *  scsi_error.c Copyright (C) 1997 Eric Youngdale
+  *
+  *  SCSI error/timeout handling
+  *      Initial versions: Eric Youngdale.  Based upon conversations with
+  *			  Leonard Zubkoff and David Miller at Linux Expo, 
+  *			  ideas originating from all over the place.
+  *
+  */
+ 
+ #include <linux/config.h>
+ #define __NO_VERSION__
+ #include <linux/module.h>
+ 
+ #include <linux/sched.h>
+ #include <linux/timer.h>
+ #include <linux/string.h>
+ #include <linux/malloc.h>
+ #include <linux/ioport.h>
+ #include <linux/kernel.h>
+ #include <linux/stat.h>
+ #include <linux/blk.h>
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+ #include <asm/smp_lock.h>
+ 
+ #define __KERNEL_SYSCALLS__
+ 
+ #include <linux/unistd.h>
+ 
+ #include <asm/system.h>
+ #include <asm/irq.h>
+ #include <asm/dma.h>
+ 
+ #include "scsi.h"
+ #include "hosts.h"
+ #include "constants.h"
+ 
+ #ifdef CONFIG_KERNELD
+ #include <linux/kerneld.h>
+ #endif
+ 
+ #ifdef DEBUG
+     #define SENSE_TIMEOUT SCSI_TIMEOUT
+     #define ABORT_TIMEOUT SCSI_TIMEOUT
+     #define RESET_TIMEOUT SCSI_TIMEOUT
+ #else
+     #define SENSE_TIMEOUT (10*HZ)
+     #define RESET_TIMEOUT (2*HZ)
+     #define ABORT_TIMEOUT (15*HZ)
+ #endif
+ 
+ #define STATIC
+ 
+ /*
+  * These should *probably* be handled by the host itself.
+  * Since it is allowed to sleep, it probably should.
+  */
+ #define BUS_RESET_SETTLE_TIME   5*HZ
+ #define HOST_RESET_SETTLE_TIME  10*HZ
+ 
+ 
+ static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_error.c,v 1.5 1997/06/06 03:30:40 eric Exp $";
+ 
+ STATIC int         scsi_check_sense (Scsi_Cmnd * SCpnt);
+ STATIC int         scsi_request_sense(Scsi_Cmnd *);
+ STATIC void        scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout);
+ STATIC int         scsi_try_to_abort_command(Scsi_Cmnd *, int);
+ STATIC int         scsi_test_unit_ready(Scsi_Cmnd *);
+ STATIC int         scsi_try_bus_device_reset(Scsi_Cmnd *, int timeout);
+ STATIC int         scsi_try_bus_reset(Scsi_Cmnd *);
+ STATIC int         scsi_try_host_reset(Scsi_Cmnd *);
+ STATIC int         scsi_unit_is_ready(Scsi_Cmnd *);
+ STATIC void        scsi_eh_action_done(Scsi_Cmnd *, int);
+ STATIC int         scsi_eh_retry_command(Scsi_Cmnd *);
+ STATIC int	   scsi_eh_completed_normally(Scsi_Cmnd * SCpnt);
+ STATIC void        scsi_restart_operations(struct Scsi_Host *);
+ STATIC void        scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt);
+ 
+ 
+ /*
+  * Function:    scsi_add_timer()
+  *
+  * Purpose:     Start timeout timer for a single scsi command.
+  *
+  * Arguments:   SCset   - command that is about to start running.
+  *              timeout - amount of time to allow this command to run.
+  *              complete - timeout function to call if timer isn't
+  *                      canceled.
+  *
+  * Returns:     Nothing
+  *
+  * Notes:	This should be turned into an inline function.
+  *
+  * More Notes:  Each scsi command has it's own timer, and as it is added to
+  *              the queue, we set up the timer.  When the command completes,
+  *              we cancel the timer.  Pretty simple, really, especially
+  *              compared to the old way of handling this crap.
+  */
+ void
+ scsi_add_timer(Scsi_Cmnd * SCset, 
+ 			int timeout, 
+ 			void (*complete)(Scsi_Cmnd *))
+ {
+ 
+     /*
+      * If the clock was already running for this command, then
+      * first delete the timer.  The timer handling code gets rather
+      * confused if we don't do this.
+      */
+     if( SCset->eh_timeout.function != NULL )
+     {
+         del_timer(&SCset->eh_timeout);
+     }
+ 
+     SCset->eh_timeout.data = (unsigned long) SCset;
+     SCset->eh_timeout.expires = jiffies + timeout;
+     SCset->eh_timeout.function = (void (*)(unsigned long))complete;
+     
+     SCSI_LOG_ERROR_RECOVERY(5,printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete));
+     
+     add_timer(&SCset->eh_timeout);
+ 
+ }
+ 
+ /*
+  * Function:    scsi_delete_timer()
+  *
+  * Purpose:     Delete/cancel timer for a given function.
+  *
+  * Arguments:   SCset   - command that we are canceling timer for.
+  *
+  * Returns:     Amount of time remaining before command would have timed out.
+  *
+  * Notes:	This should be turned into an inline function.
+  */
+ int
+ scsi_delete_timer(Scsi_Cmnd * SCset)
+ {
+   int rtn;
+ 
+   rtn = jiffies - SCset->eh_timeout.expires;
+   del_timer(&SCset->eh_timeout);
+ 
+   SCSI_LOG_ERROR_RECOVERY(5,printk("Clearing timer for command %p\n", SCset));
+ 
+   SCset->eh_timeout.data = (unsigned long) NULL;
+   SCset->eh_timeout.expires = 0;
+   SCset->eh_timeout.function = NULL;
+ 
+   return rtn;
+ }
+ 
+ /*
+  * Function:    scsi_times_out()
+  *
+  * Purpose:     Timeout function for normal scsi commands..
+  *
+  * Arguments:   SCpnt   - command that is timing out.
+  *
+  * Returns:     Nothing.
+  *
+  * Notes:
+  */
+ void scsi_times_out (Scsi_Cmnd * SCpnt)
+ {
+ 
+     /* 
+      * Notify the low-level code that this operation failed and we are
+      * reposessing the command.  
+      */
+ #ifdef ERIC_neverdef
+     /*
+      * FIXME(eric)
+      * Allow the host adapter to push a queue ordering tag
+      * out to the bus to force the command in question to complete.
+      * If the host wants to do this, then we just restart the timer
+      * for the command.  Before we really do this, some real thought
+      * as to the optimum way to handle this should be done.  We *do*
+      * need to force ordering every so often to ensure that all requests
+      * do eventually complete, but I am not sure if this is the best way
+      * to actually go about it.
+      *
+      * Better yet, force a sync here, but don't block since we are in an
+      * interrupt.
+      */
+     if( SCpnt->host->hostt->eh_ordered_queue_tag )
+     {
+         if( (*SCpnt->host->hostt->eh_ordered_queue_tag)(SCpnt))
+         {
+             scsi_add_timer(SCpnt, SCpnt->internal_timeout,
+                            scsi_times_out);
+             return;
+         }
+     }
+     /*
+      * FIXME(eric) - add a second special interface to handle this
+      * case.  Ideally that interface can also be used to request
+      * a queu
+      */
+      if (SCpnt->host->can_queue)
+      {
+          SCpnt->host->hostt->queuecommand (SCpnt, NULL);
+      }
+ #endif
+ 
+     SCpnt->state = SCSI_STATE_TIMEOUT;
+     SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+     
+     SCpnt->host->in_recovery = 1;
+     SCpnt->host->host_failed++;
+     
+     SCSI_LOG_TIMEOUT(3,printk("Command timed out active=%d busy=%d failed=%d\n", 
+                               atomic_read(&SCpnt->host->host_active),
+                               SCpnt->host->host_busy, 
+                               SCpnt->host->host_failed));
+     
+     /*
+      * If the host is having troubles, then look to see if this was the last
+      * command that might have failed.  If so, wake up the error handler.
+      */
+     if( atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+     {
+         up(SCpnt->host->eh_wait);
+     }
+ }
+ 
+ /*
+  * Function     scsi_block_when_processing_errors
+  *
+  * Purpose:     Prevent more commands from being queued while error recovery
+  *              is taking place.
+  *
+  * Arguments:   SDpnt - device on which we are performing recovery.
+  *
+  * Returns:     FALSE   The device was taken offline by error recovery.
+  *              TRUE    OK to proceed.
+  *
+  * Notes:       We block until the host is out of error recovery, and then
+  *              check to see whether the host or the device is offline.
+  */
+ int  
+ scsi_block_when_processing_errors(Scsi_Device * SDpnt)
+ {
+ 
+   SCSI_SLEEP( &SDpnt->host->host_wait, SDpnt->host->in_recovery);
+ 
+   SCSI_LOG_ERROR_RECOVERY(5,printk("Open returning %d\n", SDpnt->online));
+ 
+   return SDpnt->online;
+ }
+ 
+ /*
+  * Function:    scsi_eh_times_out()
+  *
+  * Purpose:     Timeout function for error handling.
+  *
+  * Arguments:   SCpnt   - command that is timing out.
+  *
+  * Returns:     Nothing.
+  *
+  * Notes:	During error handling, the kernel thread will be sleeping
+  *		waiting for some action to complete on the device.  Our only
+  *		job is to record that it timed out, and to wake up the
+  *		thread.
+  */
+ STATIC
+ void scsi_eh_times_out (Scsi_Cmnd * SCpnt)
+ {
+   SCpnt->request.rq_status = RQ_SCSI_DONE;
+   SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+   SCpnt->eh_state = SCSI_STATE_TIMEOUT;
+ 
+   if (SCpnt->host->eh_action != NULL)
+     up(SCpnt->host->eh_action);
+ }
+ 
+ 
+ /*
+  * Function:    scsi_eh_done()
+  *
+  * Purpose:     Completion function for error handling.
+  *
+  * Arguments:   SCpnt   - command that is timing out.
+  *
+  * Returns:     Nothing.
+  *
+  * Notes:	During error handling, the kernel thread will be sleeping
+  *		waiting for some action to complete on the device.  Our only
+  *		job is to record that the action completed, and to wake up the
+  *		thread.
+  */
+ STATIC
+ void scsi_eh_done (Scsi_Cmnd * SCpnt)
+ {
+   SCpnt->request.rq_status = RQ_SCSI_DONE;
+   
+   SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+   SCpnt->eh_state = SUCCESS;
+ 
+   SCSI_LOG_ERROR_RECOVERY(5,printk("In eh_done %p result:%x\n", SCpnt, 
+                                    SCpnt->result));
+ 
+   if (SCpnt->host->eh_action != NULL)
+     up(SCpnt->host->eh_action);
+ }
+ 
+ /*
+  * Function:    scsi_eh_action_done()
+  *
+  * Purpose:     Completion function for error handling.
+  *
+  * Arguments:   SCpnt   - command that is timing out.
+  *		answer  - boolean that indicates whether operation succeeded.
+  *
+  * Returns:     Nothing.
+  *
+  * Notes:	This callback is only used for abort and reset operations.
+  */
+ STATIC
+ void scsi_eh_action_done (Scsi_Cmnd * SCpnt, int answer)
+ {
+   SCpnt->request.rq_status = RQ_SCSI_DONE;
+   
+   SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+   SCpnt->eh_state = (answer ? SUCCESS : FAILED);
+ 
+   if (SCpnt->host->eh_action != NULL)
+     up(SCpnt->host->eh_action);
+ }
+ 
+ /*
+  * Function:	scsi_sense_valid()
+  *
+  * Purpose:	Determine whether a host has automatically obtained sense
+  *		information or not.  If we have it, then give a recommendation
+  *		as to what we should do next.
+  */
+ int
+ scsi_sense_valid(Scsi_Cmnd * SCpnt)
+ {
+   if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) 
+     {
+       return FALSE;
+     }
+   return TRUE;
+ }
+ 
+ /*
+  * Function:	scsi_eh_retry_command()
+  *
+  * Purpose:	Retry the original command
+  *
+  * Returns:	SUCCESS - we were able to get the sense data.
+  *		FAILED  - we were not able to get the sense data.
+  * 
+  * Notes:	This function will *NOT* return until the command either
+  *		times out, or it completes.
+  */
+ STATIC int
+ scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
+ {
+   memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
+           sizeof(SCpnt->data_cmnd));
+   SCpnt->request_buffer = SCpnt->buffer;
+   SCpnt->request_bufflen = SCpnt->bufflen;
+   SCpnt->use_sg = SCpnt->old_use_sg;
+   SCpnt->cmd_len = SCpnt->old_cmd_len;
+ 
+   SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ 
+   scsi_send_eh_cmnd (SCpnt, SCpnt->timeout_per_command);
+ 
+   /*
+    * Hey, we are done.  Let's look to see what happened.
+    */
+   return SCpnt->eh_state;
+ }
+ 
+ /*
+  * Function:	scsi_request_sense()
+  *
+  * Purpose:	Request sense data from a particular target.
+  *
+  * Returns:	SUCCESS - we were able to get the sense data.
+  *		FAILED  - we were not able to get the sense data.
+  * 
+  * Notes:	Some hosts automatically obtain this information, others
+  *		require that we obtain it on our own.
+  *
+  *		This function will *NOT* return until the command either
+  *		times out, or it completes.
+  */
+ STATIC int
+ scsi_request_sense(Scsi_Cmnd * SCpnt)
+ {
+   static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+ 
+   memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
+ 	  sizeof(generic_sense));
+ 
+   SCpnt->cmnd[1] = SCpnt->lun << 5;
+   SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+ 
+   SCpnt->request_buffer = &SCpnt->sense_buffer;
+   SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+   SCpnt->use_sg = 0;
+   SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ 
+   scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
+ 
+   /*
+    * Hey, we are done.  Let's look to see what happened.
+    */
+   return SCpnt->eh_state;
+ }
+ 
+ /*
+  * Function:	scsi_test_unit_ready()
+  *
+  * Purpose:	Run test unit ready command to see if the device is talking to us or not.
+  *
+  */
+ STATIC int
+ scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
+ {
+   static unsigned char tur_command[6] = {TEST_UNIT_READY, 0,0,0,0,0};
+ 
+   memcpy ((void *) SCpnt->cmnd , (void *) tur_command,
+ 	  sizeof(tur_command));
+ 
+   SCpnt->cmnd[1] = SCpnt->lun << 5;
+   SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+ 
+   SCpnt->request_buffer = &SCpnt->sense_buffer;
+   SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+   SCpnt->use_sg = 0;
+   SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ 
+   scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
+ 
+   /*
+    * Hey, we are done.  Let's look to see what happened.
+    */
+   return SCpnt->eh_state;
+ }
+ 
+ STATIC
+ void scsi_sleep_done (struct semaphore * sem)
+ {
+     if( sem != NULL )
+     {
+         up(sem);
+     }
+ }
+ 
+ 
+ void scsi_sleep (int timeout)
+ {
+     struct semaphore sem = MUTEX_LOCKED;
+     struct timer_list timer;
+ 
+     timer.data = (unsigned long) &sem;
+     timer.expires = jiffies + timeout;
+     timer.function = (void (*)(unsigned long))scsi_sleep_done;
+     
+     SCSI_LOG_ERROR_RECOVERY(5,printk("Sleeping for timer tics %d\n", timeout));
+     
+     add_timer(&timer);
+ 
+     down(&sem);
+     
+     del_timer(&timer);
+ }
+ 
+ /*
+  * Function:	scsi_send_eh_cmnd
+  *
+  * Purpose:	Send a command out to a device as part of error recovery.
+  *
+  * Notes:	The initialization of the structures is quite a bit different
+  *		in this case, and furthermore, there is a different completion
+  *		handler.
+  */
+ STATIC void scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout)
+ {
+     struct Scsi_Host * host;
+ 
+     host = SCpnt->host;
+ 
+ retry:
+     /*
+      * We will use a queued command if possible, otherwise we will emulate the
+      * queuing and calling of completion function ourselves.
+      */
+     SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+ 
+     if (host->can_queue)
+     {
+         struct semaphore sem = MUTEX_LOCKED;
+ 
+         SCpnt->eh_state = SCSI_STATE_QUEUED;
+ 
+         scsi_add_timer(SCpnt, timeout, scsi_eh_times_out);
+ 
+ 	/*
+ 	 * Set up the semaphore so we wait for the command to complete.
+ 	 */
+ 	SCpnt->host->eh_action = &sem;
+ 	SCpnt->request.rq_status = RQ_SCSI_BUSY;
+ 
+ 	host->hostt->queuecommand (SCpnt, scsi_eh_done);
+ 	down(&sem);
+         SCpnt->host->eh_action = NULL;
+ 
+ 	del_timer(&SCpnt->eh_timeout);
+ 
+ 	/*
+ 	 * See if timeout.  If so, tell the host to forget about it.
+ 	 * In other words, we don't want a callback any more.
+ 	 */
+ 	if( SCpnt->eh_state == SCSI_STATE_TIMEOUT )
+ 	  {
+ 	    SCpnt->eh_state = FAILED;
+ 	  }
+ 
+         SCSI_LOG_ERROR_RECOVERY(5,printk("send_eh_cmnd: %p eh_state:%x\n", 
+                                          SCpnt, SCpnt->eh_state));
+     }
+     else
+       {
+ 	int temp;
+ 
+ 	/*
+ 	 * We damn well had better never use this code.  There is no timeout
+ 	 * protection here, since we would end up waiting in the actual low
+ 	 * level driver, we don't know how to wake it up.
+ 	 */
+ 	temp = host->hostt->command (SCpnt);
+ 	SCpnt->result = temp;
+ 	if( scsi_eh_completed_normally(SCpnt) )
+ 	  {
+ 	    SCpnt->eh_state = SUCCESS;
+ 	  }
+ 	else
+ 	  {
+ 	    SCpnt->eh_state = FAILED;
+ 	  }
+       }
+ 
+     /*
+      * Now examine the actual status codes to see whether the command actually
+      * did complete normally.
+      */
+     if( SCpnt->eh_state == SUCCESS )
+       {
+ 	switch( scsi_eh_completed_normally(SCpnt) )
+ 	  {
+ 	  case SUCCESS:
+ 	    SCpnt->eh_state = SUCCESS;
+ 	    break;
+ 	  case NEEDS_RETRY:
+ 	    goto retry;
+ 	  case FAILED:
+ 	  default:
+ 	    SCpnt->eh_state = FAILED;
+ 	    break;
+ 	  }
+       }
+     else
+       {
+ 	SCpnt->eh_state = FAILED;
+       }
+ }
+ 
+ /*
+  * Function:	scsi_unit_is_ready()
+  *
+  * Purpose:	Called after TEST_UNIT_READY is run, to test to see if
+  *		the unit responded in a way that indicates it is ready.
+  */
+ STATIC int
+ scsi_unit_is_ready(Scsi_Cmnd * SCpnt)
+ {
+   if (SCpnt->result) 
+     {
+       if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
+ 	   (status_byte (SCpnt->result) & CHECK_CONDITION)) &&
+ 	  ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) 
+ 	{
+ 	  if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
+ 	      ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
+ 	      ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST))
+ 	    {
+ 	      return 0;
+ 	    }
+ 	}
+     }
+   
+   return 1;
+ }
+ 
+ /*
+  * Function:    scsi_eh_finish_command
+  *
+  * Purpose:     Handle a command that we are finished with WRT error handling.
+  *
+  * Arguments:   SClist - pointer to list into which we are putting completed commands.
+  *              SCpnt  - command that is completing
+  *
+  * Notes:       We don't want to use the normal command completion while we are
+  *              are still handling errors - it may cause other commands to be queued,
+  *              and that would disturb what we are doing.  Thus we really want to keep
+  *              a list of pending commands for final completion, and once we
+  *              are ready to leave error handling we handle completion for real.
+  */
+ STATIC void
+ scsi_eh_finish_command(Scsi_Cmnd **SClist, Scsi_Cmnd * SCpnt)
+ {
+     SCpnt->state = SCSI_STATE_BHQUEUE;
+     SCpnt->bh_next = *SClist;
+     *SClist = SCpnt;
+ }
+ 
+ /*
+  * Function:	scsi_try_to_abort_command
+  *
+  * Purpose:	Ask host adapter to abort a running command.
+  *
+  * Returns:	FAILED		Operation failed or not supported.
+  *		SUCCESS		Succeeded.
+  *
+  * Notes:	This function will not return until the user's completion
+  *		function has been called.  There is no timeout on this
+  *              operation.  If the author of the low-level driver wishes
+  *              this operation to be timed, they can provide this facility
+  *              themselves.  Helper functions in scsi_error.c can be supplied
+  *              to make this easier to do.
+  *
+  * Notes:	It may be possible to combine this with all of the reset
+  *		handling to eliminate a lot of code duplication.  I don't
+  *		know what makes more sense at the moment - this is just a
+  *		prototype.
+  */
+ STATIC int
+ scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout)
+ {
+   SCpnt->eh_state = FAILED; /* Until we come up with something better */
+ 
+   if( SCpnt->host->hostt->eh_abort_handler == NULL )
+     {
+       return FAILED;
+     }
+   
+   SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+ 
+   return SCpnt->host->hostt->eh_abort_handler(SCpnt);
+ }
+ 
+ /*
+  * Function:	scsi_try_bus_device_reset
+  *
+  * Purpose:	Ask host adapter to perform a bus device reset for a given
+  *		device.
+  *
+  * Returns:	FAILED		Operation failed or not supported.
+  *		SUCCESS		Succeeded.
+  *
+  * Notes:	There is no timeout for this operation.  If this operation is
+  *              unreliable for a given host, then the host itself needs to put a
+  *              timer on it, and set the host back to a consistent state prior
+  *              to returning.
+  */
+ STATIC int
+ scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout)
+ {
+   SCpnt->eh_state = FAILED; /* Until we come up with something better */
+ 
+   if( SCpnt->host->hostt->eh_device_reset_handler == NULL )
+     {
+       return FAILED;
+     }
+   
+   SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+     
+   return SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
+ }
+ 
+ /*
+  * Function:	scsi_try_bus_reset
+  *
+  * Purpose:	Ask host adapter to perform a bus reset for a host.
+  *
+  * Returns:	FAILED		Operation failed or not supported.
+  *		SUCCESS		Succeeded.
+  *
+  * Notes:	
+  */
+ STATIC int
+ scsi_try_bus_reset(Scsi_Cmnd * SCpnt)
+ {
+   int		   rtn;
+ 
+   SCpnt->eh_state = FAILED; /* Until we come up with something better */
+   SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+ 
+   if( SCpnt->host->hostt->eh_bus_reset_handler == NULL )
+     {
+       return FAILED;
+     }
+ 
+   rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
+ 
+   /*
+    * If we had a successful bus reset, mark the command blocks to expect
+    * a condition code of unit attention.
+    */
+   scsi_sleep(BUS_RESET_SETTLE_TIME);
+   if( SCpnt->eh_state == SUCCESS )
+     {
+       Scsi_Device * SDloop;
+       for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next)
+ 	{
+             if( SCpnt->channel == SDloop->channel )
+             {
+                 SDloop->was_reset = 1;
+                 SDloop->expecting_cc_ua = 1;
+             }
+ 	}
+     }
+ 
+   return SCpnt->eh_state;
+ }
+ 
+ /*
+  * Function:	scsi_try_host_reset
+  *
+  * Purpose:	Ask host adapter to reset itself, and the bus.
+  *
+  * Returns:	FAILED		Operation failed or not supported.
+  *		SUCCESS		Succeeded.
+  *
+  * Notes:
+  */
+ STATIC int
+ scsi_try_host_reset(Scsi_Cmnd * SCpnt)
+ {
+     int		   rtn;
+ 
+     SCpnt->eh_state = FAILED; /* Until we come up with something better */
+     SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+     
+     if( SCpnt->host->hostt->eh_host_reset_handler == NULL )
+     {
+         return FAILED;
+     }
+     
+     rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
+ 
+     /*
+      * If we had a successful host reset, mark the command blocks to expect
+      * a condition code of unit attention.
+      */
+     scsi_sleep(HOST_RESET_SETTLE_TIME);
+     if( SCpnt->eh_state == SUCCESS )
+     {
+         Scsi_Device * SDloop;
+         for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next)
+ 	{
+             SDloop->was_reset = 1;
+             SDloop->expecting_cc_ua = 1;
+ 	}
+     }
+     
+     return SCpnt->eh_state;
+ }
+ 
+ /*
+  * Function:	scsi_decide_disposition
+  *
+  * Purpose:	Examine a command block that has come back from the low-level
+  *		and figure out what to do next.
+  *
+  * Returns:	SUCCESS		- pass on to upper level.
+  *		FAILED		- pass on to error handler thread.
+  *		RETRY		- command should be retried.
+  *		SOFTERR		- command succeeded, but we need to log
+  *				  a soft error.
+  *
+  * Notes:	This is *ONLY* called when we are examining the status
+  *		after sending out the actual data command.  Any commands
+  *		that are queued for error recovery (i.e. TEST_UNIT_READY)
+  *		do *NOT* come through here.
+  *
+  *              NOTE - When this routine returns FAILED, it means the error
+  *              handler thread is woken.  In cases where the error code
+  *              indicates an error that doesn't require the error handler
+  *              thread (i.e. we don't need to abort/reset), then this function
+  *              should return SUCCESS.
+  */
+ int scsi_decide_disposition (Scsi_Cmnd * SCpnt)
+ {
+   int	rtn;
+ 
+   /*
+    * If the device is offline, then we clearly just pass the result back
+    * up to the top level.
+    */
+   if( SCpnt->device->online == FALSE )
+   {
+       SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: device offline - report as SUCCESS\n"));
+       return SUCCESS;
+   }
+ 
+   /*
+    * First check the host byte, to see if there is anything in there
+    * that would indicate what we need to do.
+    */
+ 
+   switch(host_byte(SCpnt->result))
+     {
+     case DID_PASSTHROUGH:
+         /*
+          * No matter what, pass this through to the upper layer.
+          * Nuke this special code so that it looks like we are saying
+          * DID_OK.
+          */
+         SCpnt->result &= 0xff00ffff;
+         return SUCCESS;
+     case DID_OK:
+       /*
+        * Looks good.  Drop through, and check the next byte.
+        */
+       break;
+     case DID_NO_CONNECT:
+     case DID_BAD_TARGET:
+     case DID_ABORT:
+       /*
+        * Note - this means that we just report the status back to the
+        * top level driver, not that we actually think that it indicates
+        * sucess.
+        */
+       return SUCCESS;
+     case DID_PARITY:
+     case DID_BUS_BUSY:
+     case DID_ERROR:
+       goto maybe_retry;
+     case DID_TIME_OUT:
+       /*
+          * When we scan the bus, we get timeout messages for
+          * these commands if there is no device available.
+          * Other hosts report DID_NO_CONNECT for the same thing.
+          */
+         if( (SCpnt->cmnd[0] == TEST_UNIT_READY ||
+              SCpnt->cmnd[0] == INQUIRY) )
+         {
+             return SUCCESS;
+         }
+         else
+         {
+             return FAILED;
+         }
+     case DID_RESET:
+       /*
+        * In the normal case where we haven't initiated a reset, this is
+        * a failure.
+        */
+       if( SCpnt->flags & IS_RESETTING )
+ 	{
+ 	  SCpnt->flags &= ~IS_RESETTING;
+ 	  goto maybe_retry;
+ 	}
+ 
+       /*
+        * Examine the sense data to figure out how to proceed from here.
+        * If there is no sense data, we will be forced into the error
+        * handler thread, where we get to examine the thing in a lot more
+        * detail.
+        */
+       return scsi_check_sense (SCpnt);
+     default:
+       return FAILED;
+     }
+ 
+   /*
+    * Next, check the message byte.
+    */
+   if( msg_byte(SCpnt->result) != COMMAND_COMPLETE )
+     {
+       return FAILED;
+     }
+ 
+   /*
+    * Now, check the status byte to see if this indicates anything special.
+    */
+   switch (status_byte(SCpnt->result))
+     {
+     case GOOD:
+     case COMMAND_TERMINATED:
+       return SUCCESS;
+     case CHECK_CONDITION:
+       rtn = scsi_check_sense(SCpnt);
+       if( rtn == NEEDS_RETRY )
+ 	{
+ 	  goto maybe_retry;
+ 	}
+       return rtn;
+     case CONDITION_GOOD:
+     case INTERMEDIATE_GOOD:
+     case INTERMEDIATE_C_GOOD:
+       /*
+        * Who knows?  FIXME(eric)
+        */
+       return SUCCESS;
+     case BUSY:
+     case QUEUE_FULL:
+     case RESERVATION_CONFLICT:
+       goto maybe_retry;
+     default:
+       return FAILED;
+     }
+   return FAILED;
+ 
+ maybe_retry:
+ 
+   if ((++SCpnt->retries) < SCpnt->allowed)
+     {
+       return NEEDS_RETRY;
+     }
+   else
+     {
+       return FAILED;
+     }
+ }
+ 
+ /*
+  * Function:	scsi_eh_completed_normally
+  *
+  * Purpose:	Examine a command block that has come back from the low-level
+  *		and figure out what to do next.
+  *
+  * Returns:	SUCCESS		- pass on to upper level.
+  *		FAILED		- pass on to error handler thread.
+  *		RETRY		- command should be retried.
+  *		SOFTERR		- command succeeded, but we need to log
+  *				  a soft error.
+  *
+  * Notes:	This is *ONLY* called when we are examining the status
+  *		of commands queued during error recovery.  The main
+  *		difference here is that we don't allow for the possibility
+  *		of retries here, and we are a lot more restrictive about what
+  *              we consider acceptable.
+  */
+ STATIC int scsi_eh_completed_normally (Scsi_Cmnd * SCpnt)
+ {
+   int	rtn;
+   /*
+    * First check the host byte, to see if there is anything in there
+    * that would indicate what we need to do.
+    */
+   if( host_byte(SCpnt->result) == DID_RESET )
+     {
+      if (SCpnt->flags & IS_RESETTING )
+        {
+ 	 /*
+ 	  * OK, this is normal.  We don't know whether in fact the
+ 	  * command in question really needs to be rerun or not - 
+ 	  * if this was the original data command then the answer is yes,
+ 	  * otherwise we just flag it as success.
+ 	  */
+ 	 SCpnt->flags &= ~IS_RESETTING;
+ 	 return NEEDS_RETRY;
+        }
+ 
+      /*
+       * Rats.  We are already in the error handler, so we now get to try
+       * and figure out what to do next.  If the sense is valid, we have
+       * a pretty good idea of what to do.  If not, we mark it as failed.
+       */
+      return scsi_check_sense (SCpnt);
+     }
+ 
+   if(host_byte(SCpnt->result) != DID_OK )
+   {
+       return FAILED;
+   }
+ 
+   /*
+    * Next, check the message byte.
+    */
+   if( msg_byte(SCpnt->result) != COMMAND_COMPLETE )
+     {
+       return FAILED;
+     }
+ 
+   /*
+    * Now, check the status byte to see if this indicates anything special.
+    */
+   switch (status_byte(SCpnt->result))
+     {
+     case GOOD:
+     case COMMAND_TERMINATED:
+       return SUCCESS;
+     case CHECK_CONDITION:
+       rtn = scsi_check_sense(SCpnt);
+       if( rtn == NEEDS_RETRY )
+ 	{
+ 	  return FAILED;
+ 	}
+       return rtn;
+     case CONDITION_GOOD:
+     case INTERMEDIATE_GOOD:
+     case INTERMEDIATE_C_GOOD:
+       /*
+        * Who knows?  FIXME(eric)
+        */
+       return SUCCESS;
+     case BUSY:
+     case QUEUE_FULL:
+     case RESERVATION_CONFLICT:
+     default:
+       return FAILED;
+     }
+   return FAILED;
+ }
+ 
+ /*
+  * Function:	scsi_check_sense
+  *
+  * Purpose:	Examine sense information - give suggestion as to what
+  *		we should do with it.
+  */
+ STATIC  int scsi_check_sense (Scsi_Cmnd * SCpnt)
+ {
+     if ( !scsi_sense_valid(SCpnt) ) 
+       {
+ 	return FAILED;
+       }
+ 
+     if (SCpnt->sense_buffer[2] & 0xe0)
+ 	return FAILED;
+ 
+     switch (SCpnt->sense_buffer[2] & 0xf)
+     {
+     case NO_SENSE:
+ 	return SUCCESS;
+     case RECOVERED_ERROR:
+ 	return SOFT_ERROR;
+ 
+     case ABORTED_COMMAND:
+ 	return NEEDS_RETRY;
+     case NOT_READY:
+     case UNIT_ATTENTION:
+         /*
+          * If we are expecting a CC/UA because of a bus reset that we
+          * performed, treat this just as a retry.  Otherwise this is
+          * information that we should pass up to the upper-level driver
+          * so that we can deal with it there.
+          */
+         if( SCpnt->device->expecting_cc_ua )
+         {
+             SCpnt->device->expecting_cc_ua = 0;
+             return NEEDS_RETRY;
+         }
+ 	return SUCCESS;
+ 
+     /* these three are not supported */
+     case COPY_ABORTED:
+     case VOLUME_OVERFLOW:
+     case MISCOMPARE:
+ 
+     case MEDIUM_ERROR:
+ 	return FAILED;
+ 
+     case BLANK_CHECK:
+     case DATA_PROTECT:
+     case HARDWARE_ERROR:
+     case ILLEGAL_REQUEST:
+     default:
+ 	return FAILED;
+     }
+ }
+ 
+ 
+ /*
+  * Function:	scsi_restart_operations
+  *
+  * Purpose:	Restart IO operations to the specified host.
+  *
+  * Arguments:	host  - host that we are restarting
+  *
+  * Returns:	Nothing
+  *
+  * Notes:	When we entered the error handler, we blocked all further
+  *		I/O to this device.  We need to 'reverse' this process.
+  */
+ STATIC void
+ scsi_restart_operations(struct Scsi_Host * host)
+ {
+   Scsi_Device * SDpnt;
+ 
+   /*
+    * Next free up anything directly waiting upon the host.  This will be
+    * requests for character device operations, and also for ioctls to queued
+    * block devices.
+    */
+   SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: Waking up host to restart\n"));
+ 
+    wake_up(&host->host_wait);
+ 
+    /*
+     * Finally, block devices need an extra kick in the pants.  This is because
+     * the request queueing mechanism may have queued lots of pending requests
+     * and there won't be a process waiting in a place where we can simply wake
+     * it up.  Thus we simply go through and call the request function to goose
+     * the various top level drivers and get things moving again.
+     */
+    for( SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next )
+      {
+        SCSI_LOG_ERROR_RECOVERY(5,printk("Calling request function to restart things...\n"));
+ 
+        if( SDpnt->scsi_request_fn != NULL )
+ 	 (*SDpnt->scsi_request_fn)();
+      }
+ }
+ 
+ /*
+  * Function:	scsi_unjam_host
+  *
+  * Purpose:	Attempt to fix a host which has a command that failed for
+  *		some reason.
+  *
+  * Arguments:	host	- host that needs unjamming.
+  * 
+  * Returns:	Nothing
+  *
+  * Notes:	When we come in here, we *know* that all commands on the
+  *		bus have either completed, failed or timed out.  We also
+  *		know that no further commands are being sent to the host,
+  *		so things are relatively quiet and we have freedom to
+  *		fiddle with things as we wish.
+  *
+  * Additional note:  This is only the *default* implementation.  It is possible
+  *		for individual drivers to supply their own version of this
+  *		function, and if the maintainer wishes to do this, it is
+  *		strongly suggested that this function be taken as a template
+  *		and modified.  This function was designed to correctly handle
+  *		problems for about 95% of the different cases out there, and
+  *		it should always provide at least a reasonable amount of error
+  *		recovery.
+  *
+  * Note3:       Any command marked 'FAILED' or 'TIMEOUT' must eventually
+  *              have scsi_finish_command() called for it.  We do all of
+  *              the retry stuff here, so when we restart the host after we
+  *              return it should have an empty queue.
+  */
+ STATIC int
+ scsi_unjam_host(struct Scsi_Host * host)
+ {
+   int           devices_failed;
+   int           numfailed;
+   int           ourrtn;
+   int		rtn = FALSE;
+   int		result;
+   Scsi_Cmnd   * SCloop;
+   Scsi_Cmnd   * SCpnt;
+   Scsi_Device * SDpnt;
+   Scsi_Device * SDloop;
+   Scsi_Cmnd   * SCdone;
+   int           timed_out;
+ 
+   SCdone = NULL;
+ 
+   /*
+    * First, protect against any sort of race condition.  If any of the outstanding
+    * commands are in states that indicate that we are not yet blocked (i.e. we are
+    * not in a quiet state) then we got woken up in error.  If we ever end up here,
+    * we need to re-examine some of the assumptions.
+    */
+   for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+   {
+       for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+       {
+           if( SCpnt->state == SCSI_STATE_FAILED 
+               || SCpnt->state == SCSI_STATE_TIMEOUT 
+               || SCpnt->state == SCSI_STATE_UNUSED)
+           {
+               continue;
+           }
+ 
+           /*
+            * Rats.  Something is still floating around out there.  This could
+            * be the result of the fact that the upper level drivers are still frobbing
+            * commands that might have succeeded.  There are two outcomes.  One is that
+            * the command block will eventually be freed, and the other one is that
+            * the command will be queued and will be finished along the way.
+            */
+           SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler prematurely woken - commands still active\n"));
+           panic("SCSI Error handler woken too early\n");
+       }
+   }
+ 
+   /*
+    * Next, see if we need to request sense information.  if so,
+    * then get it now, so we have a better idea of what to do.
+    * FIXME(eric) this has the unfortunate side effect that if a host
+    * adapter does not automatically request sense information, that we end
+    * up shutting it down before we request it.  All hosts should be doing this
+    * anyways, so for now all I have to say is tough noogies if you end up in here.
+    * On second thought, this is probably a good idea.  We *really* want to give
+    * authors an incentive to automatically request this.
+    */
+   SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we need to request sense\n"));
+ 
+   for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+   {
+       for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+       {
+           if( SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt) )
+           {
+               continue;
+           }
+ 
+           SCSI_LOG_ERROR_RECOVERY(2,printk("scsi_unjam_host: Requesting sense for %d\n",
+                                            SCpnt->target));
+           rtn = scsi_request_sense(SCpnt);
+           if( rtn != SUCCESS )
+           {
+               continue;
+           }
+ 
+           SCSI_LOG_ERROR_RECOVERY(3,printk("Sense requested for %p - result %x\n",
+                                            SCpnt, SCpnt->result));
+           SCSI_LOG_ERROR_RECOVERY(3,print_sense("bh",SCpnt));
+                   
+           result = scsi_decide_disposition(SCpnt);
+ 
+           /*
+            * If the result was normal, then just pass it along to the
+            * upper level.
+            */
+           if( result == SUCCESS )
+           {
+               SCpnt->host->host_failed--;
+               scsi_eh_finish_command(&SCdone, SCpnt);
+           }
+ 
+           if( result != NEEDS_RETRY )
+           {
+               continue;
+           }
+ 
+           /* 
+            * We only come in here if we want to retry a
+            * command.  The test to see whether the command
+            * should be retried should be keeping track of the
+            * number of tries, so we don't end up looping, of
+            * course.  
+            */
+           SCpnt->state = NEEDS_RETRY;
+           rtn = scsi_eh_retry_command(SCpnt);
+           if( rtn != SUCCESS )
+           {
+               continue;
+           }
+ 
+           /*
+            * We eventually hand this one back to the top level.
+            */
+           SCpnt->host->host_failed--;
+           scsi_eh_finish_command(&SCdone, SCpnt);
+       }
+   }
+ 
+   /*
+    * Go through the list of commands and figure out where we stand and how bad things
+    * really are.
+    */
+   numfailed = 0;
+   timed_out = 0;
+   devices_failed = 0;
+   for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+   {
+       unsigned int device_error = 0;
+ 
+       for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+       {
+           if( SCpnt->state == SCSI_STATE_FAILED )
+           {
+               SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d failed\n", 
+                                                SCpnt->target));
+               numfailed++;
+               device_error++;
+           }
+           if( SCpnt->state == SCSI_STATE_TIMEOUT )
+           {
+               SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d timedout\n", 
+                                                SCpnt->target));
+               timed_out++;
+               device_error++;
+           }
+       }
+       if( device_error > 0 )
+       {
+           devices_failed++;
+       }
+   }
+ 
+   SCSI_LOG_ERROR_RECOVERY(2,printk("Total of %d+%d commands on %d devices require eh work\n", 
+                                    numfailed, timed_out, devices_failed));
+ 
+   if( host->host_failed == 0 )
+   {
+       ourrtn = TRUE;
+       goto leave;
+   }
+ 
+ 
+   /*
+    * Next, try and see whether or not it makes sense to try and abort
+    * the running command.  This only works out to be the case if we have
+    * one command that has timed out.  If the command simply failed, it
+    * makes no sense to try and abort the command, since as far as the
+    * host adapter is concerned, it isn't running.
+    */
+ 
+   SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try abort\n"));
+ 
+   for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+   {
+       for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
+       {
+           if( SCloop->state != SCSI_STATE_TIMEOUT )
+           {
+               continue;
+           }
+ 
+ 	  rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT);
+ 
+ 	  if( rtn == SUCCESS )
+           {
+ 	      rtn = scsi_test_unit_ready(SCloop);
+               
+ 	      if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+               {
+ 		  rtn = scsi_eh_retry_command(SCloop);
+                   
+ 		  if( rtn == SUCCESS )
+                   {
+                       SCloop->host->host_failed--;
+ 		      scsi_eh_finish_command(&SCdone,SCloop);
+                   }
+               }
+           }
+       }
+   }
+   
+   /*
+    * If we have corrected all of the problems, then we are done.
+    */
+   if( host->host_failed == 0 )
+   {
+       ourrtn = TRUE;
+       goto leave;
+   }
+ 
+   /*
+    * Either the abort wasn't appropriate, or it didn't succeed.
+    * Now try a bus device reset.  Still, look to see whether we have
+    * multiple devices that are jammed or not - if we have multiple devices,
+    * it makes no sense to try BUS_DEVICE_RESET - we really would need
+    * to try a BUS_RESET instead.
+    *
+    * Does this make sense - should we try BDR on each device individually?
+    * Yes, definitely.
+    */
+   SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try BDR\n"));
+ 
+   for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+   {
+       for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
+       {
+           if( SCloop->state == SCSI_STATE_FAILED 
+               || SCloop->state == SCSI_STATE_TIMEOUT )
+           {
+               break;
+           }
+       }
+ 
+       if( SCloop == NULL )
+       {
+           continue;
+       }
+ 
+       /*
+        * OK, we have a device that is having problems.  Try and send
+        * a bus device reset to it.
+        *
+        * FIXME(eric) - make sure we handle the case where multiple
+        * commands to the same device have failed. They all must
+        * get properly restarted.
+        */
+       rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT);
+       
+       if( rtn == SUCCESS )
+       {
+ 	  rtn = scsi_test_unit_ready(SCloop);
+ 	  
+ 	  if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+           {
+ 	      rtn = scsi_eh_retry_command(SCloop);
+ 	      
+ 	      if( rtn == SUCCESS )
+               {
+                   SCloop->host->host_failed--;
+ 		  scsi_eh_finish_command(&SCdone,SCloop);
+               }
+           }
+       }
+       
+   }
+   
+   if( host->host_failed == 0 )
+   {
+       ourrtn = TRUE;
+       goto leave;
+   }
+ 
+   /*
+    * If we ended up here, we have serious problems.  The only thing left
+    * to try is a full bus reset.  If someone has grabbed the bus and isn't
+    * letting go, then perhaps this will help.
+    */
+   SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard bus reset\n"));
+ 
+   /* 
+    * We really want to loop over the various channels, and do this on
+    * a channel by channel basis.  We should also check to see if any
+    * of the failed commands are on soft_reset devices, and if so, skip
+    * the reset.  
+    */
+   for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+   {
+ next_device:
+       for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+       {
+           if( SCpnt->state != SCSI_STATE_FAILED 
+               && SCpnt->state != SCSI_STATE_TIMEOUT )
+           {
+               continue;
+           }
+           /*
+            * We have a failed command.  Make sure there are no other failed
+            * commands on the same channel that are timed out and implement a
+            * soft reset.
+            */
+           for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
+           {
+               for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
+               {
+                   if( SCloop->channel != SCpnt->channel )
+                   {
+                       continue;
+                   }
+                   
+                   if( SCloop->state != SCSI_STATE_FAILED 
+                       && SCloop->state != SCSI_STATE_TIMEOUT )
+                   {
+                       continue;
+                   }
+                   
+                   if( SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT )
+                   {
+                       /* 
+                        * If this device uses the soft reset option, and this
+                        * is one of the devices acting up, then our only
+                        * option is to wait a bit, since the command is
+                        * supposedly still running.  
+                        *
+                        * FIXME(eric) - right now we will just end up falling
+                        * through to the 'take device offline' case.
+                        *
+                        * FIXME(eric) - It is possible that the command completed
+                        * *after* the error recovery procedure started, and if this
+                        * is the case, we are worrying about nothing here.
+                        */
+                       goto next_device;
+                   }
+               }
+           }
+ 
+           /*
+            * We now know that we are able to perform a reset for the
+            * bus that SCpnt points to.  There are no soft-reset devices
+            * with outstanding timed out commands.
+            */
+           rtn = scsi_try_bus_reset(SCpnt);
+           if( rtn == SUCCESS )
+           {
+               for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
+               {
+                   for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
+                   {
+                       if( SCloop->channel != SCpnt->channel )
+                       {
+                           continue;
+                       }
+                       
+                       if( SCloop->state != SCSI_STATE_FAILED 
+                           && SCloop->state != SCSI_STATE_TIMEOUT )
+                       {
+                           continue;
+                       }
+                       
+                       rtn = scsi_test_unit_ready(SCloop);
+                       
+                       if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+                       {
+                           rtn = scsi_eh_retry_command(SCloop);
+                           
+                           if( rtn == SUCCESS )
+                           {
+                               SCpnt->host->host_failed--;
+                               scsi_eh_finish_command(&SCdone,SCloop);
+                           }
+                       }
+                       
+                       /*
+                        * If the bus reset worked, but we are still unable to
+                        * talk to the device, take it offline.
+                        * FIXME(eric) - is this really the correct thing to do?
+                        */
+                       if( rtn != SUCCESS )
+                       {
+                           SCloop->device->online = FALSE;
+                           SCloop->host->host_failed--;
+                           scsi_eh_finish_command(&SCdone,SCloop);
+                       }
+                   }
+               }
+           }
+       }
+   }
+ 
+   if( host->host_failed == 0 )
+   {
+       ourrtn = TRUE;
+       goto leave;
+   }
+   /*
+    * If we ended up here, we have serious problems.  The only thing left
+    * to try is a full host reset - perhaps the firmware on the device
+    * crashed, or something like that.
+    *
+    * It is assumed that a succesful host reset will cause *all* information
+    * about the command to be flushed from both the host adapter *and* the
+    * device.
+    *
+    * FIXME(eric) - it isn't clear that devices that implement the soft reset
+    * option can ever be cleared except via cycling the power.  The problem is
+    * that sending the host reset command will cause the host to forget
+    * about the pending command, but the device won't forget.  For now, we
+    * skip the host reset option if any of the failed devices are configured
+    * to use the soft reset option.
+    */
+   for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+   {
+ next_device2:
+       for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+       {
+           if( SCpnt->state != SCSI_STATE_FAILED 
+               && SCpnt->state != SCSI_STATE_TIMEOUT )
+           {
+               continue;
+           }
+           if( SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT )
+           {
+               /* 
+                * If this device uses the soft reset option, and this
+                * is one of the devices acting up, then our only
+                * option is to wait a bit, since the command is
+                * supposedly still running.  
+                *
+                * FIXME(eric) - right now we will just end up falling
+                * through to the 'take device offline' case.
+                */
+               SCSI_LOG_ERROR_RECOVERY(3,
+                         printk("scsi_unjam_host: Unable to try hard host reset\n"));
+               goto next_device2;
+           }
+ 
+           SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard host reset\n"));
+ 
+           /*
+            * FIXME(eric) - we need to obtain a valid SCpnt to perform this call.
+            */
+           rtn = scsi_try_host_reset(SCpnt);
+           if( rtn == SUCCESS )
+           {
+               /*
+                * FIXME(eric) we assume that all commands are flushed from the
+                * controller.  We should get a DID_RESET for all of the commands
+                * that were pending.  We should ignore these so that we can
+                * guarantee that we are in a consistent state.
+                *
+                * I believe this to be the case right now, but this needs to be
+                * tested.
+                */
+             for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
+               {
+                   for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
+                   {
+                       if( SCloop->state != SCSI_STATE_FAILED 
+                           && SCloop->state != SCSI_STATE_TIMEOUT )
+                       {
+                           continue;
+                       }
+                       
+                       rtn = scsi_test_unit_ready(SCloop);
+                       
+                       if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+                       {
+                           rtn = scsi_eh_retry_command(SCloop);
+                           
+                           if( rtn == SUCCESS )
+                           {
+                               SCpnt->host->host_failed--;
+                               scsi_eh_finish_command(&SCdone,SCloop);
+                           }
+                       }
+                       if( rtn != SUCCESS )
+                       {
+                           SCloop->device->online = FALSE;
+                           SCloop->host->host_failed--;
+                           scsi_eh_finish_command(&SCdone,SCloop);
+                       }
+                   }
+               }
+           }
+       }
+   }
+ 
+ 
+   /*
+    * If we solved all of the problems, then let's rev up the engines again.
+    */
+   if( host->host_failed == 0 )
+   {
+       ourrtn = TRUE;
+       goto leave;
+   }
+ 
+   /*
+    * If the HOST RESET failed, then for now we assume that the entire host
+    * adapter is too hosed to be of any use.  For our purposes, however, it is
+    * easier to simply take the devices offline that correspond to commands
+    * that failed.
+    */
+   SCSI_LOG_ERROR_RECOVERY(1,printk("scsi_unjam_host: Take device offline\n"));
+ force_device_offline:
+ 
+   for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+   {
+       for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
+       {
+           if( SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT )
+           {
+               SCloop->device->online = FALSE;
+               
+               /*
+                * This should pass the failure up to the top level driver, and
+                * it will have to try and do something intelligent with it.
+                */
+               SCloop->host->host_failed--;
+               
+               if( SCloop->state == SCSI_STATE_TIMEOUT )
+               {
+                   SCloop->result |= (DRIVER_TIMEOUT << 24);
+               }
+ 
+               SCSI_LOG_ERROR_RECOVERY(3,printk("Finishing command for device %d %x\n",
+                      SCloop->device->id, SCloop->result));
+               
+               scsi_eh_finish_command(&SCdone,SCloop);
+           }
+       }
+   }
+ 
+   if( host->host_failed != 0 )
+   {
+       panic("scsi_unjam_host: Miscount of number of failed commands.\n");
+   }
+ 
+   SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Returning\n"));
+ 
+   ourrtn = FALSE;
+ 
+ leave:
+ 
+   /*
+    * We should have a list of commands that we 'finished' during the course of
+    * error recovery.  This should be the same as the list of commands that timed out
+    * or failed.  We are currently holding these things in a linked list - we didn't
+    * put them in the bottom half queue because we wanted to keep things quiet while
+    * we were working on recovery, and passing them up to the top level could easily
+    * cause the top level to try and queue something else again.
+    *
+    * Start by marking that the host is no longer in error recovery.
+    */
+   host->in_recovery = 0;
+ 
+   /*
+    * Take the list of commands, and stick them in the bottom half queue.
+    * The current implementation of scsi_done will do this for us - if need
+    * be we can create a special version of this function to do the
+    * same job for us.
+    */
+   for(SCpnt = SCdone; SCpnt != NULL; SCpnt = SCdone)
+   {
+       SCdone = SCpnt->bh_next;
+       SCpnt->bh_next = NULL;
+       scsi_done(SCpnt);
+   }
+ 
+   return (ourrtn);
+ }
+ 
+ 
+ /*
+  * Function:	scsi_error_handler
+  *
+  * Purpose:	Handle errors/timeouts of scsi commands, try and clean up
+  *		and unjam the bus, and restart things.
+  *
+  * Arguments:	host	- host for which we are running.
+  *
+  * Returns:	Never returns.
+  *
+  * Notes:	This is always run in the context of a kernel thread.  The
+  *		idea is that we start this thing up when the kernel starts
+  *		up (one per host that we detect), and it immediately goes to
+  *		sleep and waits for some event (i.e. failure).  When this
+  *		takes place, we have the job of trying to unjam the bus
+  *		and restarting things.
+  *
+  */
+ void
+ scsi_error_handler(void * data)
+ {
+ 	struct Scsi_Host     * host = (struct Scsi_Host *) data;
+ 	int	               rtn;
+ 	struct semaphore sem = MUTEX_LOCKED;
+ 
+ 	lock_kernel();
+ 
+ 	/*
+ 	 * If we were started as result of loading a module, close all of the
+ 	 * user space pages.  We don't need them, and if we didn't close them
+ 	 * they would be locked into memory.
+ 	 */
+ 	exit_mm(current);
+ 
+ 
+ 	current->session = 1;
+ 	current->pgrp = 1;
+         /*
+          * FIXME(eric) this is still a child process of the one that did the insmod.
+          * This needs to be attached to task[0] instead.
+          */
+ 
+ 
+ 	/*
+ 	 * Set the name of this process.
+ 	 */
+ 	sprintf(current->comm, "scsi_eh_%d", host->host_no);
+ 
+ 	host->eh_wait = &sem;
+ 	host->ehandler = current;
+         
+         /*
+          * Wake up the thread that created us.
+          */
+         SCSI_LOG_ERROR_RECOVERY(3,printk("Wake up parent %d\n", host->eh_notify->count.counter));
+ 
+         up(host->eh_notify);
+ 
+ 	while(1)
+ 	  {
+ 	    /*
+ 	     * If we get a signal, it means we are supposed to go
+ 	     * away and die.  This typically happens if the user is
+ 	     * trying to unload a module.
+ 	     */
+             SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler sleeping\n"));
+ 	    current->signal = 0;
+ 	    down_interruptible (&sem);
+ 
+ 	    if (current->signal & ~current->blocked)
+ 	      break;
+ 
+             SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler waking up\n"));
+ 
+             host->eh_active = 1;
+ 
+ 	    /*
+ 	     * We have a host that is failing for some reason.  Figure out
+ 	     * what we need to do to get it up and online again (if we can).
+ 	     * If we fail, we end up taking the thing offline.
+ 	     */
+ 	    if( host->hostt->eh_strategy_handler != NULL )
+ 	      {
+ 		rtn = host->hostt->eh_strategy_handler(host);
+ 	      }
+ 	    else
+ 	      {
+ 		rtn = scsi_unjam_host(host);
+ 	      }
+ 
+ 	    /*
+ 	     * Note - if the above fails completely, the action is to take
+ 	     * individual devices offline and flush the queue of any
+ 	     * outstanding requests that may have been pending.  When we
+ 	     * restart, we restart any I/O to any other devices on the bus
+ 	     * which are still online.
+ 	     */
+ 	    scsi_restart_operations(host);
+ 	  }
+ 
+         SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler exiting\n"));
+ 
+ 	/*
+ 	 * Make sure that nobody tries to wake us up again.
+ 	 */
+ 	host->eh_wait = NULL;
+ 
+ 	/*
+ 	 * Knock this down too.  From this point on, the host is flying
+ 	 * without a pilot.  If this is because the module is being unloaded,
+ 	 * that's fine.  If the user sent a signal to this thing, we are
+ 	 * potentially in real danger.
+ 	 */
+ 	host->in_recovery = 0;
+         host->eh_active = 0;
+ 	host->ehandler = NULL;
+ 
+ 	/*
+ 	 * If anyone is waiting for us to exit (i.e. someone trying to unload
+ 	 * a driver), then wake up that process to let them know we are on
+ 	 * the way out the door.  This may be overkill - I *think* that we
+ 	 * could probably just unload the driver and send the signal, and when
+ 	 * the error handling thread wakes up that it would just exit without
+ 	 * needing to touch any memory associated with the driver itself.
+ 	 */
+ 	if( host->eh_notify != NULL )
+ 	  up(host->eh_notify);
+ 
+ 	unlock_kernel();
+ }
+ 
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+  * adjust the settings for this buffer only.  This must remain at the end
+  * of the file.
+  * ---------------------------------------------------------------------------
+  * Local variables:
+  * c-indent-level: 4
+  * c-brace-imaginary-offset: 0
+  * c-brace-offset: -4
+  * c-argdecl-indent: 4
+  * c-label-offset: -4
+  * c-continued-statement-offset: 4
+  * c-continued-brace-offset: 0
+  * indent-tabs-mode: nil
+  * tab-width: 8
+  * End:
+  */
Index: linux/drivers/scsi/scsi_ioctl.c
diff -c linux/drivers/scsi/scsi_ioctl.c:1.1.1.1 linux/drivers/scsi/scsi_ioctl.c:1.2
*** linux/drivers/scsi/scsi_ioctl.c:1.1.1.1	Sun May 18 19:18:08 1997
--- linux/drivers/scsi/scsi_ioctl.c	Sun May 18 19:27:20 1997
***************
*** 1,8 ****
- /*
-  * Don't import our own symbols, as this would severely mess up our
-  * symbol tables.
-  */
- #define _SCSI_SYMS_VER_
  #define __NO_VERSION__
  #include <linux/module.h>
  
--- 1,3 ----
***************
*** 105,112 ****
  {
      int result;
      Scsi_Cmnd * SCpnt;
!     
!     SCpnt = allocate_device(NULL, dev, 1);
      {
  	struct semaphore sem = MUTEX_LOCKED;
  	SCpnt->request.sem = &sem;
--- 100,109 ----
  {
      int result;
      Scsi_Cmnd * SCpnt;
!     Scsi_Device * SDpnt;
! 
!     SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
!     SCpnt = scsi_allocate_device(NULL, dev, 1);
      {
  	struct semaphore sem = MUTEX_LOCKED;
  	SCpnt->request.sem = &sem;
***************
*** 114,121 ****
--- 111,121 ----
  		    scsi_ioctl_done,  MAX_TIMEOUT,
  		    MAX_RETRIES);
  	down(&sem);
+         SCpnt->request.sem = NULL;
      }
      
+     SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", SCpnt->result));
+ 
      if(driver_byte(SCpnt->result) != 0)
  	switch(SCpnt->sense_buffer[2] & 0xf) {
  	case ILLEGAL_REQUEST:
***************
*** 148,159 ****
  	};
      
      result = SCpnt->result;
-     SCpnt->request.rq_status = RQ_INACTIVE;
  
!     if (!SCpnt->device->was_reset && SCpnt->device->scsi_request_fn)
! 	(*SCpnt->device->scsi_request_fn)();
  
!     wake_up(&SCpnt->device->device_wait);
      return result;
  }
  
--- 148,163 ----
  	};
      
      result = SCpnt->result;
  
!     SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
!     SDpnt = SCpnt->device;
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
  
!     if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
! 	(*SDpnt->scsi_request_fn)();
! 
!     wake_up(&SDpnt->device_wait);
      return result;
  }
  
***************
*** 168,173 ****
--- 172,178 ----
      unsigned char cmd[12]; 
      char * cmd_in;
      Scsi_Cmnd * SCpnt;
+     Scsi_Device * SDpnt;
      unsigned char opcode;
      int inlen, outlen, cmdlen;
      int needed, buf_needed;
***************
*** 223,229 ****
      cmdlen = COMMAND_SIZE(opcode);
  
      result = verify_area(VERIFY_READ, cmd_in, 
!                          cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen);
      if (result) return result;
  
      copy_from_user ((void *) cmd,  cmd_in,  cmdlen);
--- 228,234 ----
      cmdlen = COMMAND_SIZE(opcode);
  
      result = verify_area(VERIFY_READ, cmd_in, 
!                          cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
      if (result) return result;
  
      copy_from_user ((void *) cmd,  cmd_in,  cmdlen);
***************
*** 263,269 ****
  
  #ifndef DEBUG_NO_CMD
      
!     SCpnt = allocate_device(NULL, dev, 1);
  
      {
  	struct semaphore sem = MUTEX_LOCKED;
--- 268,274 ----
  
  #ifndef DEBUG_NO_CMD
      
!     SCpnt = scsi_allocate_device(NULL, dev, 1);
  
      {
  	struct semaphore sem = MUTEX_LOCKED;
***************
*** 271,276 ****
--- 276,282 ----
  	scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,
  		    timeout, retries);
  	down(&sem);
+         SCpnt->request.sem = NULL;
      }
      
      /* 
***************
*** 291,304 ****
      }
      result = SCpnt->result;
  
!     SCpnt->request.rq_status = RQ_INACTIVE;
  
      if (buf) scsi_free(buf, buf_needed);
      
!     if(SCpnt->device->scsi_request_fn)
! 	(*SCpnt->device->scsi_request_fn)();
      
-     wake_up(&SCpnt->device->device_wait);
      return result;
  #else
      {
--- 297,312 ----
      }
      result = SCpnt->result;
  
!     wake_up(&SCpnt->device->device_wait);
!     SDpnt = SCpnt->device;
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
  
      if (buf) scsi_free(buf, buf_needed);
      
!     if(SDpnt->scsi_request_fn)
! 	(*SDpnt->scsi_request_fn)();
      
      return result;
  #else
      {
***************
*** 330,335 ****
--- 338,354 ----
      
      /* No idea how this happens.... */
      if (!dev) return -ENXIO;
+     
+     /*
+      * If we are in the middle of error recovery, don't let anyone
+      * else try and use this device.  Also, if error recovery fails, it
+      * may try and take the device offline, in which case all further
+      * access to the device is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(dev) )
+       {
+         return -ENODEV;
+       }
      
      switch (cmd) {
      case SCSI_IOCTL_GET_IDLUN:
Index: linux/drivers/scsi/scsi_obsolete.c
diff -c /dev/null linux/drivers/scsi/scsi_obsolete.c:1.1
*** /dev/null	Fri Jun  6 01:03:53 1997
--- linux/drivers/scsi/scsi_obsolete.c	Sun May 18 19:27:21 1997
***************
*** 0 ****
--- 1,1131 ----
+ /*
+  *  scsi.c Copyright (C) 1992 Drew Eckhardt
+  *         Copyright (C) 1993, 1994, 1995 Eric Youngdale
+  *
+  *  generic mid-level SCSI driver
+  *      Initial versions: Drew Eckhardt
+  *      Subsequent revisions: Eric Youngdale
+  *
+  *  <drew@colorado.edu>
+  *
+  *  Bug correction thanks go to :
+  *      Rik Faith <faith@cs.unc.edu>
+  *      Tommy Thorn <tthorn>
+  *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
+  *
+  *  Modified by Eric Youngdale eric@aib.com to
+  *  add scatter-gather, multiple outstanding request, and other
+  *  enhancements.
+  *
+  *  Native multichannel, wide scsi, /proc/scsi and hot plugging
+  *  support added by Michael Neuffer <mike@i-connect.net>
+  *
+  *  Added request_module("scsi_hostadapter") for kerneld:
+  *  (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
+  *  Bjorn Ekwall  <bj0rn@blox.se>
+  *
+  *  Major improvements to the timeout, abort, and reset processing,
+  *  as well as performance modifications for large queue depths by
+  *  Leonard N. Zubkoff <lnz@dandelion.com>
+  */
+ 
+ /*
+  *#########################################################################
+  *#########################################################################
+  *#########################################################################
+  *#########################################################################
+  *		NOTE - NOTE - NOTE - NOTE - NOTE - NOTE - NOTE
+  *
+  *#########################################################################
+  *#########################################################################
+  *#########################################################################
+  *#########################################################################
+  *
+  * This file contains the 'old' scsi error handling.  It is only present
+  * while the new error handling code is being debugged, and while the low
+  * level drivers are being converted to use the new code.  Once the last
+  * driver uses the new code this *ENTIRE* file will be nuked.
+  */
+ 
+ #define __NO_VERSION__
+ #include <linux/module.h>
+ 
+ #include <linux/sched.h>
+ #include <linux/timer.h>
+ #include <linux/string.h>
+ #include <linux/malloc.h>
+ #include <linux/ioport.h>
+ #include <linux/kernel.h>
+ #include <linux/stat.h>
+ #include <linux/blk.h>
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+ 
+ #include <asm/system.h>
+ #include <asm/irq.h>
+ #include <asm/dma.h>
+ 
+ #include "scsi.h"
+ #include "hosts.h"
+ #include "constants.h"
+ 
+ #ifdef CONFIG_KERNELD
+ #include <linux/kerneld.h>
+ #endif
+ 
+ #undef USE_STATIC_SCSI_MEMORY
+ 
+ /*
+ static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_obsolete.c,v 1.1 1997/05/18 23:27:21 eric Exp $";
+ */
+ 
+ 
+ #define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
+ 
+ 
+ static int scsi_abort (Scsi_Cmnd *, int code);
+ static int scsi_reset (Scsi_Cmnd *, unsigned int);
+ 
+ extern void scsi_old_done (Scsi_Cmnd *SCpnt);
+ static int update_timeout (Scsi_Cmnd *, int);
+ extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
+ extern void internal_cmnd (Scsi_Cmnd * SCpnt);
+ 
+ static volatile struct Scsi_Host * host_active = NULL;
+ #define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
+ 			  || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
+ 
+ static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+ 
+ /*
+  *  This is the number  of clock ticks we should wait before we time out
+  *  and abort the command.  This is for  where the scsi.c module generates
+  *  the command, not where it originates from a higher level, in which
+  *  case the timeout is specified there.
+  *
+  *  ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
+  *  respectively.
+  */
+ 
+ #ifdef DEBUG_TIMEOUT
+ static void scsi_dump_status(void);
+ #endif
+ 
+ 
+ #ifdef DEBUG
+     #define SCSI_TIMEOUT (5*HZ)
+ #else
+     #define SCSI_TIMEOUT (2*HZ)
+ #endif
+ 
+ #ifdef DEBUG
+     #define SENSE_TIMEOUT SCSI_TIMEOUT
+     #define ABORT_TIMEOUT SCSI_TIMEOUT
+     #define RESET_TIMEOUT SCSI_TIMEOUT
+ #else
+     #define SENSE_TIMEOUT (5*HZ/10)
+     #define RESET_TIMEOUT (5*HZ/10)
+     #define ABORT_TIMEOUT (5*HZ/10)
+ #endif
+ 
+ 
+ /* Do not call reset on error if we just did a reset within 15 sec. */
+ #define MIN_RESET_PERIOD (15*HZ)
+ 
+ 
+ 
+ /*
+  *  Flag bits for the internal_timeout array
+  */
+ #define NORMAL_TIMEOUT 0
+ #define IN_ABORT  1
+ #define IN_RESET  2
+ #define IN_RESET2 4
+ #define IN_RESET3 8
+ 
+ /*
+  * This is our time out function, called when the timer expires for a
+  * given host adapter.  It will attempt to abort the currently executing
+  * command, that failing perform a kernel panic.
+  */
+ 
+ void scsi_old_times_out (Scsi_Cmnd * SCpnt)
+ {
+ 
+     switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
+     {
+     case NORMAL_TIMEOUT:
+ 	{
+ #ifdef DEBUG_TIMEOUT
+ 	    scsi_dump_status();
+ #endif
+ 	}
+ 
+ 	if (!scsi_abort (SCpnt, DID_TIME_OUT))
+ 	    return;
+     case IN_ABORT:
+ 	printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
+ 	       SCpnt->host->host_no, SCpnt->pid);
+ 	if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
+ 	    return;
+     case IN_RESET:
+     case (IN_ABORT | IN_RESET):
+ 	/* This might be controversial, but if there is a bus hang,
+ 	 * you might conceivably want the machine up and running
+ 	 * esp if you have an ide disk.
+ 	 */
+ 	printk("SCSI host %d channel %d reset (pid %ld) timed out - "
+                "trying harder\n",
+ 	       SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
+ 	SCpnt->internal_timeout &= ~IN_RESET;
+ 	SCpnt->internal_timeout |= IN_RESET2;
+         scsi_reset (SCpnt,
+ 		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
+         return;
+     case (IN_ABORT | IN_RESET | IN_RESET2):
+ 	/* Obviously the bus reset didn't work.
+ 	 * Let's try even harder and call for an HBA reset.
+          * Maybe the HBA itself crashed and this will shake it loose.
+ 	 */
+ 	printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
+ 	       SCpnt->host->host_no, SCpnt->pid);
+ 	SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
+ 	SCpnt->internal_timeout |= IN_RESET3;
+         scsi_reset (SCpnt,
+ 		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
+ 	return;
+ 
+     default:
+ 	printk("SCSI host %d reset (pid %ld) timed out again -\n",
+ 	       SCpnt->host->host_no, SCpnt->pid);
+ 	printk("probably an unrecoverable SCSI bus or device hang.\n");
+ 	return;
+ 
+     }
+ 
+ }
+ 
+ 
+ static void scsi_request_sense (Scsi_Cmnd * SCpnt)
+ {
+     unsigned long flags;
+ 
+     save_flags(flags);
+     cli();
+     SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
+     update_timeout(SCpnt, SENSE_TIMEOUT);
+     restore_flags(flags);
+ 
+ 
+     memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
+ 	    sizeof(generic_sense));
+ 
+     SCpnt->cmnd[1] = SCpnt->lun << 5;
+     SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+ 
+     SCpnt->request_buffer = &SCpnt->sense_buffer;
+     SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+     SCpnt->use_sg = 0;
+     SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+     internal_cmnd (SCpnt);
+ }
+ 
+ 
+ 
+ 
+ static int check_sense (Scsi_Cmnd * SCpnt)
+ {
+     /* If there is no sense information, request it.  If we have already
+      * requested it, there is no point in asking again - the firmware must
+      * be confused.
+      */
+     if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
+ 	if(!(SCpnt->flags & ASKED_FOR_SENSE))
+ 	    return SUGGEST_SENSE;
+ 	else
+ 	    return SUGGEST_RETRY;
+     }
+ 
+     SCpnt->flags &= ~ASKED_FOR_SENSE;
+ 
+ #ifdef DEBUG_INIT
+     printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
+     print_sense("", SCpnt);
+     printk("\n");
+ #endif
+     if (SCpnt->sense_buffer[2] & 0xe0)
+ 	return SUGGEST_ABORT;
+ 
+     switch (SCpnt->sense_buffer[2] & 0xf)
+     {
+     case NO_SENSE:
+ 	return 0;
+     case RECOVERED_ERROR:
+ 	return SUGGEST_IS_OK;
+ 
+     case ABORTED_COMMAND:
+ 	return SUGGEST_RETRY;
+     case NOT_READY:
+     case UNIT_ATTENTION:
+         /*
+          * If we are expecting a CC/UA because of a bus reset that we
+          * performed, treat this just as a retry.  Otherwise this is
+          * information that we should pass up to the upper-level driver
+          * so that we can deal with it there.
+          */
+         if( SCpnt->device->expecting_cc_ua )
+         {
+             SCpnt->device->expecting_cc_ua = 0;
+             return SUGGEST_RETRY;
+         }
+ 	return SUGGEST_ABORT;
+ 
+     /* these three are not supported */
+     case COPY_ABORTED:
+     case VOLUME_OVERFLOW:
+     case MISCOMPARE:
+ 
+     case MEDIUM_ERROR:
+ 	return SUGGEST_REMAP;
+     case BLANK_CHECK:
+     case DATA_PROTECT:
+     case HARDWARE_ERROR:
+     case ILLEGAL_REQUEST:
+     default:
+ 	return SUGGEST_ABORT;
+     }
+ }
+ 
+ /* This function is the mid-level interrupt routine, which decides how
+  *  to handle error conditions.  Each invocation of this function must
+  *  do one and *only* one of the following:
+  *
+  *  (1) Call last_cmnd[host].done.  This is done for fatal errors and
+  *      normal completion, and indicates that the handling for this
+  *      request is complete.
+  *  (2) Call internal_cmnd to requeue the command.  This will result in
+  *      scsi_done being called again when the retry is complete.
+  *  (3) Call scsi_request_sense.  This asks the host adapter/drive for
+  *      more information about the error condition.  When the information
+  *      is available, scsi_done will be called again.
+  *  (4) Call reset().  This is sort of a last resort, and the idea is that
+  *      this may kick things loose and get the drive working again.  reset()
+  *      automatically calls scsi_request_sense, and thus scsi_done will be
+  *      called again once the reset is complete.
+  *
+  *      If none of the above actions are taken, the drive in question
+  *      will hang. If more than one of the above actions are taken by
+  *      scsi_done, then unpredictable behavior will result.
+  */
+ void scsi_old_done (Scsi_Cmnd * SCpnt)
+ {
+     int status=0;
+     int exit=0;
+     int checked;
+     int oldto;
+     struct Scsi_Host * host = SCpnt->host;
+     int result = SCpnt->result;
+     SCpnt->serial_number = 0;
+     oldto = update_timeout(SCpnt, 0);
+ 
+ #ifdef DEBUG_TIMEOUT
+     if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
+ 		      result, SCpnt->target, SCpnt->lun);
+ #endif
+ 
+     /* If we requested an abort, (and we got it) then fix up the return
+      *  status to say why
+      */
+     if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
+ 	SCpnt->result = result = (result & 0xff00ffff) |
+ 	    (SCpnt->abort_reason << 16);
+ 
+ 
+ #define CMD_FINISHED 0
+ #define MAYREDO  1
+ #define REDO     3
+ #define PENDING  4
+ 
+ #ifdef DEBUG
+     printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
+ #endif
+ 
+     if(SCpnt->flags & WAS_SENSE)
+     {
+ 	SCpnt->use_sg = SCpnt->old_use_sg;
+ 	SCpnt->cmd_len = SCpnt->old_cmd_len;
+     }
+ 
+     switch (host_byte(result))
+     {
+     case DID_OK:
+ 	if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
+ 	    /* Failed to obtain sense information */
+ 	{
+ 	    SCpnt->flags &= ~WAS_SENSE;
+ #if 0	/* This cannot possibly be correct. */
+ 	    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+ #endif
+ 
+ 	    if (!(SCpnt->flags & WAS_RESET))
+ 	    {
+ 		printk("scsi%d : channel %d target %d lun %d request sense"
+ 		       " failed, performing reset.\n",
+ 		       SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
+ 		       SCpnt->lun);
+ 		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+ 		return;
+ 	    }
+ 	    else
+ 	    {
+ 		exit = (DRIVER_HARD | SUGGEST_ABORT);
+ 		status = CMD_FINISHED;
+ 	    }
+ 	}
+ 	else switch(msg_byte(result))
+ 	{
+ 	case COMMAND_COMPLETE:
+ 	    switch (status_byte(result))
+ 	    {
+ 	    case GOOD:
+ 		if (SCpnt->flags & WAS_SENSE)
+ 		{
+ #ifdef DEBUG
+ 		    printk ("In scsi_done, GOOD status, COMMAND COMPLETE, "
+                             "parsing sense information.\n");
+ #endif
+ 		    SCpnt->flags &= ~WAS_SENSE;
+ #if 0	/* This cannot possibly be correct. */
+ 		    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+ #endif
+ 
+ 		    switch (checked = check_sense(SCpnt))
+ 		    {
+ 		    case SUGGEST_SENSE:
+ 		    case 0:
+ #ifdef DEBUG
+ 			printk("NO SENSE.  status = REDO\n");
+ #endif
+ 			update_timeout(SCpnt, oldto);
+ 			status = REDO;
+ 			break;
+ 		    case SUGGEST_IS_OK:
+ 			break;
+ 		    case SUGGEST_REMAP:
+ #ifdef DEBUG
+ 			printk("SENSE SUGGEST REMAP - status = CMD_FINISHED\n");
+ #endif
+ 			status = CMD_FINISHED;
+ 			exit = DRIVER_SENSE | SUGGEST_ABORT;
+ 			break;
+ 		    case SUGGEST_RETRY:
+ #ifdef DEBUG
+ 			printk("SENSE SUGGEST RETRY - status = MAYREDO\n");
+ #endif
+ 			status = MAYREDO;
+ 			exit = DRIVER_SENSE | SUGGEST_RETRY;
+ 			break;
+ 		    case SUGGEST_ABORT:
+ #ifdef DEBUG
+ 			printk("SENSE SUGGEST ABORT - status = CMD_FINISHED");
+ #endif
+ 			status = CMD_FINISHED;
+ 			exit =  DRIVER_SENSE | SUGGEST_ABORT;
+ 			break;
+ 		    default:
+ 			printk ("Internal error %s %d \n", __FILE__,
+ 				__LINE__);
+ 		    }
+ 		} /* end WAS_SENSE */
+ 		else
+ 		{
+ #ifdef DEBUG
+ 		    printk("COMMAND COMPLETE message returned, "
+                            "status = CMD_FINISHED. \n");
+ #endif
+ 		    exit =  DRIVER_OK;
+ 		    status = CMD_FINISHED;
+ 		}
+ 		break;
+ 
+ 	    case CHECK_CONDITION:
+ 	    case COMMAND_TERMINATED:
+ 		switch (check_sense(SCpnt))
+ 		{
+ 		case 0:
+ 		    update_timeout(SCpnt, oldto);
+ 		    status = REDO;
+ 		    break;
+ 		case SUGGEST_REMAP:
+ 		    status = CMD_FINISHED;
+ 		    exit =  DRIVER_SENSE | SUGGEST_ABORT;
+ 		    break;
+ 		case SUGGEST_RETRY:
+ 		    status = MAYREDO;
+ 		    exit = DRIVER_SENSE | SUGGEST_RETRY;
+ 		    break;
+ 		case SUGGEST_ABORT:
+ 		    status = CMD_FINISHED;
+ 		    exit =  DRIVER_SENSE | SUGGEST_ABORT;
+ 		    break;
+ 		case SUGGEST_SENSE:
+ 		    scsi_request_sense (SCpnt);
+ 		    status = PENDING;
+ 		    break;
+ 		}
+ 		break;
+ 
+ 	    case CONDITION_GOOD:
+ 	    case INTERMEDIATE_GOOD:
+ 	    case INTERMEDIATE_C_GOOD:
+ 		break;
+ 
+ 	    case BUSY:
+ 	    case QUEUE_FULL:
+ 		update_timeout(SCpnt, oldto);
+ 		status = REDO;
+ 		break;
+ 
+ 	    case RESERVATION_CONFLICT:
+ 		printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
+ 		       " reset.\n", SCpnt->host->host_no, SCpnt->channel);
+ 		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+ 		return;
+ #if 0
+ 		exit = DRIVER_SOFT | SUGGEST_ABORT;
+ 		status = MAYREDO;
+ 		break;
+ #endif
+ 	    default:
+ 		printk ("Internal error %s %d \n"
+ 			"status byte = %d \n", __FILE__,
+ 			__LINE__, status_byte(result));
+ 
+ 	    }
+ 	    break;
+ 	default:
+ 	    panic("scsi: unsupported message byte %d received\n",
+ 		  msg_byte(result));
+ 	}
+ 	break;
+     case DID_TIME_OUT:
+ #ifdef DEBUG
+ 	printk("Host returned DID_TIME_OUT - ");
+ #endif
+ 
+ 	if (SCpnt->flags & WAS_TIMEDOUT)
+ 	{
+ #ifdef DEBUG
+ 	    printk("Aborting\n");
+ #endif
+ 	    /*
+ 	      Allow TEST_UNIT_READY and INQUIRY commands to timeout early
+ 	      without causing resets.  All other commands should be retried.
+ 	    */
+ 	    if (SCpnt->cmnd[0] != TEST_UNIT_READY &&
+ 		SCpnt->cmnd[0] != INQUIRY)
+ 		    status = MAYREDO;
+ 	    exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
+ 	}
+ 	else
+ 	{
+ #ifdef DEBUG
+ 	    printk ("Retrying.\n");
+ #endif
+ 	    SCpnt->flags  |= WAS_TIMEDOUT;
+ 	    SCpnt->internal_timeout &= ~IN_ABORT;
+ 	    status = REDO;
+ 	}
+ 	break;
+     case DID_BUS_BUSY:
+     case DID_PARITY:
+ 	status = REDO;
+ 	break;
+     case DID_NO_CONNECT:
+ #ifdef DEBUG
+ 	printk("Couldn't connect.\n");
+ #endif
+ 	exit  = (DRIVER_HARD | SUGGEST_ABORT);
+ 	break;
+     case DID_ERROR:
+ 	status = MAYREDO;
+ 	exit = (DRIVER_HARD | SUGGEST_ABORT);
+ 	break;
+     case DID_BAD_TARGET:
+     case DID_ABORT:
+ 	exit = (DRIVER_INVALID | SUGGEST_ABORT);
+ 	break;
+     case DID_RESET:
+ 	if (SCpnt->flags & IS_RESETTING)
+ 	{
+ 	    SCpnt->flags &= ~IS_RESETTING;
+ 	    status = REDO;
+ 	    break;
+ 	}
+ 
+ 	if(msg_byte(result) == GOOD &&
+ 	   status_byte(result) == CHECK_CONDITION) {
+ 	    switch (check_sense(SCpnt)) {
+ 	    case 0:
+ 		update_timeout(SCpnt, oldto);
+ 		status = REDO;
+ 		break;
+ 	    case SUGGEST_REMAP:
+ 	    case SUGGEST_RETRY:
+ 		status = MAYREDO;
+ 		exit = DRIVER_SENSE | SUGGEST_RETRY;
+ 		break;
+ 	    case SUGGEST_ABORT:
+ 		status = CMD_FINISHED;
+ 		exit =  DRIVER_SENSE | SUGGEST_ABORT;
+ 		break;
+ 	    case SUGGEST_SENSE:
+ 		scsi_request_sense (SCpnt);
+ 		status = PENDING;
+ 		break;
+ 	    }
+ 	} else {
+ 	    status=REDO;
+ 	    exit = SUGGEST_RETRY;
+ 	}
+ 	break;
+     default :
+ 	exit = (DRIVER_ERROR | SUGGEST_DIE);
+     }
+ 
+     switch (status)
+     {
+     case CMD_FINISHED:
+     case PENDING:
+ 	break;
+     case MAYREDO:
+ #ifdef DEBUG
+ 	printk("In MAYREDO, allowing %d retries, have %d\n",
+ 	       SCpnt->allowed, SCpnt->retries);
+ #endif
+ 	if ((++SCpnt->retries) < SCpnt->allowed)
+ 	{
+ 	    if ((SCpnt->retries >= (SCpnt->allowed >> 1))
+ 		&& !(SCpnt->host->last_reset > 0 &&
+ 		     jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
+ 		&& !(SCpnt->flags & WAS_RESET))
+ 	    {
+ 		printk("scsi%d channel %d : resetting for second half of retries.\n",
+ 		       SCpnt->host->host_no, SCpnt->channel);
+ 		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+ 		break;
+ 	    }
+ 
+ 	}
+ 	else
+ 	{
+ 	    status = CMD_FINISHED;
+ 	    break;
+ 	}
+ 	/* fall through to REDO */
+ 
+     case REDO:
+ 
+ 	if (SCpnt->flags & WAS_SENSE)
+ 	    scsi_request_sense(SCpnt);
+ 	else
+ 	{
+ 	    memcpy ((void *) SCpnt->cmnd,
+ 		    (void*) SCpnt->data_cmnd,
+ 		    sizeof(SCpnt->data_cmnd));
+ 	    SCpnt->request_buffer = SCpnt->buffer;
+ 	    SCpnt->request_bufflen = SCpnt->bufflen;
+ 	    SCpnt->use_sg = SCpnt->old_use_sg;
+ 	    SCpnt->cmd_len = SCpnt->old_cmd_len;
+ 	    internal_cmnd (SCpnt);
+ 	}
+ 	break;
+     default:
+ 	INTERNAL_ERROR;
+     }
+ 
+     if (status == CMD_FINISHED) {
+ #ifdef DEBUG
+ 	printk("Calling done function - at address %p\n", SCpnt->done);
+ #endif
+ 	host->host_busy--; /* Indicate that we are free */
+ 
+ 	if (host->block && host->host_busy == 0) {
+ 	    host_active = NULL;
+ 
+ 	    /* For block devices "wake_up" is done in end_scsi_request */
+ 	    if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
+ 		MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
+ 		struct Scsi_Host * next;
+ 
+ 		for (next = host->block; next != host; next = next->block)
+ 		    wake_up(&next->host_wait);
+ 	    }
+ 
+ 	}
+ 
+ 	wake_up(&host->host_wait);
+ 	SCpnt->result = result | ((exit & 0xff) << 24);
+ 	SCpnt->use_sg = SCpnt->old_use_sg;
+ 	SCpnt->cmd_len = SCpnt->old_cmd_len;
+ 	SCpnt->done (SCpnt);
+     }
+ 
+ #undef CMD_FINISHED
+ #undef REDO
+ #undef MAYREDO
+ #undef PENDING
+ }
+ 
+ /*
+  * The scsi_abort function interfaces with the abort() function of the host
+  * we are aborting, and causes the current command to not complete.  The
+  * caller should deal with any error messages or status returned on the
+  * next call.
+  *
+  * This will not be called reentrantly for a given host.
+  */
+ 
+ /*
+  * Since we're nice guys and specified that abort() and reset()
+  * can be non-reentrant.  The internal_timeout flags are used for
+  * this.
+  */
+ 
+ 
+ static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
+ {
+     int oldto;
+     unsigned long flags;
+     struct Scsi_Host * host = SCpnt->host;
+ 
+     while(1)
+     {
+ 	save_flags(flags);
+ 	cli();
+ 
+ 	/*
+ 	 * Protect against races here.  If the command is done, or we are
+ 	 * on a different command forget it.
+ 	 */
+ 	if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+ 	    restore_flags(flags);
+ 	    return 0;
+ 	}
+ 
+ 	if (SCpnt->internal_timeout & IN_ABORT)
+ 	{
+ 	    restore_flags(flags);
+ 	    while (SCpnt->internal_timeout & IN_ABORT)
+ 		barrier();
+ 	}
+ 	else
+ 	{
+ 	    SCpnt->internal_timeout |= IN_ABORT;
+ 	    oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
+ 
+ 	    if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
+ 		/* OK, this command must have died when we did the
+ 		 *  reset.  The device itself must have lied.
+ 		 */
+ 		printk("Stale command on %d %d:%d appears to have died when"
+ 		       " the bus was reset\n",
+ 		       SCpnt->channel, SCpnt->target, SCpnt->lun);
+ 	    }
+ 
+ 	    restore_flags(flags);
+ 	    if (!host->host_busy) {
+ 		SCpnt->internal_timeout &= ~IN_ABORT;
+ 		update_timeout(SCpnt, oldto);
+ 		return 0;
+ 	    }
+ 	    printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
+ 		   " channel %d, id %d, lun %d ",
+ 		   SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
+ 		   (int) SCpnt->target, (int) SCpnt->lun);
+ 	    print_command (SCpnt->cmnd);
+ 	    if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
+ 		return 0;
+ 	    SCpnt->abort_reason = why;
+ 	    switch(host->hostt->abort(SCpnt)) {
+ 		/* We do not know how to abort.  Try waiting another
+ 		 * time increment and see if this helps. Set the
+ 		 * WAS_TIMEDOUT flag set so we do not try this twice
+ 		 */
+ 	    case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
+ 				   * this is too severe
+ 				   */
+ 	    case SCSI_ABORT_SNOOZE:
+ 		if(why == DID_TIME_OUT) {
+ 		    save_flags(flags);
+ 		    cli();
+ 		    SCpnt->internal_timeout &= ~IN_ABORT;
+ 		    if(SCpnt->flags & WAS_TIMEDOUT) {
+ 			restore_flags(flags);
+ 			return 1; /* Indicate we cannot handle this.
+ 				   * We drop down into the reset handler
+ 				   * and try again
+ 				   */
+ 		    } else {
+ 			SCpnt->flags |= WAS_TIMEDOUT;
+ 			oldto = SCpnt->timeout_per_command;
+ 			update_timeout(SCpnt, oldto);
+ 		    }
+ 		    restore_flags(flags);
+ 		}
+ 		return 0;
+ 	    case SCSI_ABORT_PENDING:
+ 		if(why != DID_TIME_OUT) {
+ 		    save_flags(flags);
+ 		    cli();
+ 		    update_timeout(SCpnt, oldto);
+ 		    restore_flags(flags);
+ 		}
+ 		return 0;
+ 	    case SCSI_ABORT_SUCCESS:
+ 		/* We should have already aborted this one.  No
+ 		 * need to adjust timeout
+ 		 */
+                  SCpnt->internal_timeout &= ~IN_ABORT;
+                  return 0;
+ 	    case SCSI_ABORT_NOT_RUNNING:
+ 		SCpnt->internal_timeout &= ~IN_ABORT;
+ 		update_timeout(SCpnt, 0);
+ 		return 0;
+ 	    case SCSI_ABORT_ERROR:
+ 	    default:
+ 		SCpnt->internal_timeout &= ~IN_ABORT;
+ 		return 1;
+ 	    }
+ 	}
+     }
+ }
+ 
+ 
+ /* Mark a single SCSI Device as having been reset. */
+ 
+ static inline void scsi_mark_device_reset(Scsi_Device *Device)
+ {
+   Device->was_reset = 1;
+   Device->expecting_cc_ua = 1;
+ }
+ 
+ 
+ /* Mark all SCSI Devices on a specific Host as having been reset. */
+ 
+ static void scsi_mark_host_reset(struct Scsi_Host *Host)
+ {
+   Scsi_Cmnd   * SCpnt;
+   Scsi_Device * SDpnt;
+ 
+   for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next)
+     {
+       for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+         scsi_mark_device_reset(SCpnt->device);
+     }
+ }
+ 
+ 
+ /* Mark all SCSI Devices on a specific Host Bus as having been reset. */
+ 
+ static void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
+ {
+   Scsi_Cmnd *SCpnt;
+   Scsi_Device * SDpnt;
+ 
+   for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next)
+     {
+       for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+         if (SCpnt->channel == channel)
+ 	  scsi_mark_device_reset(SCpnt->device);
+     }
+ }
+ 
+ 
+ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+ {
+     int temp;
+     unsigned long flags;
+     Scsi_Cmnd * SCpnt1;
+     Scsi_Device * SDpnt;
+     struct Scsi_Host * host = SCpnt->host;
+ 
+     printk("SCSI bus is being reset for host %d channel %d.\n",
+ 	   host->host_no, SCpnt->channel);
+ 
+ #if 0
+     /*
+      * First of all, we need to make a recommendation to the low-level
+      * driver as to whether a BUS_DEVICE_RESET should be performed,
+      * or whether we should do a full BUS_RESET.  There is no simple
+      * algorithm here - we basically use a series of heuristics
+      * to determine what we should do.
+      */
+     SCpnt->host->suggest_bus_reset = FALSE;
+ 
+     /*
+      * First see if all of the active devices on the bus have
+      * been jammed up so that we are attempting resets.  If so,
+      * then suggest a bus reset.  Forcing a bus reset could
+      * result in some race conditions, but no more than
+      * you would usually get with timeouts.  We will cross
+      * that bridge when we come to it.
+      *
+      * This is actually a pretty bad idea, since a sequence of
+      * commands will often timeout together and this will cause a
+      * Bus Device Reset followed immediately by a SCSI Bus Reset.
+      * If all of the active devices really are jammed up, the
+      * Bus Device Reset will quickly timeout and scsi_times_out
+      * will follow up with a SCSI Bus Reset anyway.
+      */
+     SCpnt1 = host->host_queue;
+     while(SCpnt1) {
+ 	if( SCpnt1->request.rq_status != RQ_INACTIVE
+ 	    && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
+             	break;
+         SCpnt1 = SCpnt1->next;
+  	}
+     if( SCpnt1 == NULL ) {
+         reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
+     }
+ 
+     /*
+      * If the code that called us is suggesting a hard reset, then
+      * definitely request it.  This usually occurs because a
+      * BUS_DEVICE_RESET times out.
+      *
+      * Passing reset_flags along takes care of this automatically.
+      */
+     if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {
+         SCpnt->host->suggest_bus_reset = TRUE;
+     }
+ #endif
+ 
+     while (1) {
+ 	save_flags(flags);
+ 	cli();
+ 
+ 	/*
+ 	 * Protect against races here.  If the command is done, or we are
+ 	 * on a different command forget it.
+ 	 */
+ 	if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
+ 	  if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+ 	    restore_flags(flags);
+ 	    return 0;
+ 	  }
+ 
+ 	if (SCpnt->internal_timeout & IN_RESET)
+ 	{
+ 	    restore_flags(flags);
+ 	    while (SCpnt->internal_timeout & IN_RESET)
+ 		barrier();
+ 	}
+ 	else
+ 	{
+ 	    SCpnt->internal_timeout |= IN_RESET;
+ 	    update_timeout(SCpnt, RESET_TIMEOUT);
+ 
+ 	    if (host->host_busy)
+ 	    {
+ 		restore_flags(flags);
+                 for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
+                 {
+                     SCpnt1 = SDpnt->device_queue;
+                     while(SCpnt1) {
+                         if (SCpnt1->request.rq_status != RQ_INACTIVE) {
+ #if 0
+                             if (!(SCpnt1->flags & IS_RESETTING) &&
+                                 !(SCpnt1->internal_timeout & IN_ABORT))
+                                 scsi_abort(SCpnt1, DID_RESET);
+ #endif
+                             SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
+                         }
+                         SCpnt1 = SCpnt1->next;
+                     }
+                 }
+ 
+ 		host->last_reset = jiffies;
+ 		temp = host->hostt->reset(SCpnt, reset_flags);
+ 		/*
+ 		  This test allows the driver to introduce an additional bus
+ 		  settle time delay by setting last_reset up to 20 seconds in
+ 		  the future.  In the normal case where the driver does not
+ 		  modify last_reset, it must be assumed that the actual bus
+ 		  reset occurred immediately prior to the return to this code,
+ 		  and so last_reset must be updated to the current time, so
+ 		  that the delay in internal_cmnd will guarantee at least a
+ 		  MIN_RESET_DELAY bus settle time.
+ 		*/
+ 		if (host->last_reset - jiffies > 20UL * HZ)
+ 		  host->last_reset = jiffies;
+ 	    }
+ 	    else
+ 	    {
+ 		if (!host->block) host->host_busy++;
+ 		restore_flags(flags);
+ 		host->last_reset = jiffies;
+ 	        SCpnt->flags |= (WAS_RESET | IS_RESETTING);
+ 		temp = host->hostt->reset(SCpnt, reset_flags);
+ 		if ((host->last_reset < jiffies) ||
+ 		    (host->last_reset > (jiffies + 20 * HZ)))
+ 		  host->last_reset = jiffies;
+ 		if (!host->block) host->host_busy--;
+ 	    }
+ 
+ #ifdef DEBUG
+ 	    printk("scsi reset function returned %d\n", temp);
+ #endif
+ 
+             /*
+              * Now figure out what we need to do, based upon
+              * what the low level driver said that it did.
+ 	     * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
+ 	     * or SCSI_RESET_WAKEUP, then the low level driver did a
+ 	     * bus device reset or bus reset, so we should go through
+ 	     * and mark one or all of the devices on that bus
+ 	     * as having been reset.
+              */
+             switch(temp & SCSI_RESET_ACTION) {
+ 	    case SCSI_RESET_SUCCESS:
+ 	        if (temp & SCSI_RESET_HOST_RESET)
+ 		  scsi_mark_host_reset(host);
+ 	        else if (temp & SCSI_RESET_BUS_RESET)
+ 		  scsi_mark_bus_reset(host, SCpnt->channel);
+ 		else scsi_mark_device_reset(SCpnt->device);
+ 		save_flags(flags);
+ 		cli();
+ 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+ 		restore_flags(flags);
+ 		return 0;
+ 	    case SCSI_RESET_PENDING:
+ 	        if (temp & SCSI_RESET_HOST_RESET)
+ 		  scsi_mark_host_reset(host);
+ 	        else if (temp & SCSI_RESET_BUS_RESET)
+ 		  scsi_mark_bus_reset(host, SCpnt->channel);
+ 		else scsi_mark_device_reset(SCpnt->device);
+ 	    case SCSI_RESET_NOT_RUNNING:
+ 		return 0;
+ 	    case SCSI_RESET_PUNT:
+ 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+                 scsi_request_sense (SCpnt);
+                 return 0;
+ 	    case SCSI_RESET_WAKEUP:
+ 	        if (temp & SCSI_RESET_HOST_RESET)
+ 		  scsi_mark_host_reset(host);
+ 	        else if (temp & SCSI_RESET_BUS_RESET)
+ 		  scsi_mark_bus_reset(host, SCpnt->channel);
+ 		else scsi_mark_device_reset(SCpnt->device);
+ 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+ 		scsi_request_sense (SCpnt);
+                 /*
+                  * If a bus reset was performed, we
+                  * need to wake up each and every command
+                  * that was active on the bus or if it was a HBA
+                  * reset all active commands on all channels
+                  */
+                 if( temp & SCSI_RESET_HOST_RESET )
+                 {
+                     for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
+                     {
+                         SCpnt1 = SDpnt->device_queue;
+                         while(SCpnt1) {
+                             if (SCpnt1->request.rq_status != RQ_INACTIVE
+                                 && SCpnt1 != SCpnt)
+                                 scsi_request_sense (SCpnt1);
+                             SCpnt1 = SCpnt1->next;
+                         }
+                     }
+                 } else if( temp & SCSI_RESET_BUS_RESET ) {
+                     for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
+                     {
+                         SCpnt1 = SDpnt->device_queue;
+                         while(SCpnt1) {
+                             if(SCpnt1->request.rq_status != RQ_INACTIVE
+                                && SCpnt1 != SCpnt
+                                && SCpnt1->channel == SCpnt->channel)
+                                 scsi_request_sense (SCpnt);
+                             SCpnt1 = SCpnt1->next;
+                         }
+                     }
+                 }
+ 		return 0;
+ 	    case SCSI_RESET_SNOOZE:
+ 		/* In this case, we set the timeout field to 0
+ 		 * so that this command does not time out any more,
+ 		 * and we return 1 so that we get a message on the
+ 		 * screen.
+ 		 */
+ 		save_flags(flags);
+ 		cli();
+ 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+ 		update_timeout(SCpnt, 0);
+ 		restore_flags(flags);
+ 		/* If you snooze, you lose... */
+ 	    case SCSI_RESET_ERROR:
+ 	    default:
+ 		return 1;
+ 	    }
+ 
+ 	    return temp;
+ 	}
+     }
+ }
+ 
+ /*
+  * The strategy is to cause the timer code to call scsi_times_out()
+  * when the soonest timeout is pending.
+  * The arguments are used when we are queueing a new command, because
+  * we do not want to subtract the time used from this time, but when we
+  * set the timer, we want to take this value into account.
+  */
+ 
+ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
+ {
+   int	rtn;
+ 
+   /*
+    * We are using the new error handling code to actually register/deregister
+    * timers for timeout.
+    */
+ 
+   if( SCset->eh_timeout.expires == 0 )
+     {
+       rtn = 0;
+     }
+   else
+     {
+       rtn = SCset->eh_timeout.expires - jiffies;
+     }
+ 
+   if( timeout == 0 )
+     {
+       scsi_delete_timer(SCset);
+     }
+   else
+     {
+       scsi_add_timer(SCset, timeout, scsi_old_times_out);
+     }
+ 
+   return rtn;
+ }
+ 
+ 
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+  * adjust the settings for this buffer only.  This must remain at the end
+  * of the file.
+  * ---------------------------------------------------------------------------
+  * Local variables:
+  * c-indent-level: 4
+  * c-brace-imaginary-offset: 0
+  * c-brace-offset: -4
+  * c-argdecl-indent: 4
+  * c-label-offset: -4
+  * c-continued-statement-offset: 4
+  * c-continued-brace-offset: 0
+  * indent-tabs-mode: nil
+  * tab-width: 8
+  * End:
+  */
Index: linux/drivers/scsi/scsi_obsolete.h
diff -c /dev/null linux/drivers/scsi/scsi_obsolete.h:1.1
*** /dev/null	Fri Jun  6 01:03:54 1997
--- linux/drivers/scsi/scsi_obsolete.h	Sun May 18 19:27:21 1997
***************
*** 0 ****
--- 1,106 ----
+ /*
+  *  scsi_obsolete.h Copyright (C) 1997 Eric Youngdale
+  *
+  */
+ 
+ #ifndef _SCSI_OBSOLETE_H
+ #define _SCSI_OBSOLETE_H
+ 
+ /*
+  * These are the return codes for the abort and reset functions.  The mid-level
+  * code uses these to decide what to do next.  Each of the low level abort
+  * and reset functions must correctly indicate what it has done.
+  * The descriptions are written from the point of view of the mid-level code,
+  * so that the return code is telling the mid-level drivers exactly what
+  * the low level driver has already done, and what remains to be done.
+  */
+ 
+ /* We did not do anything.  
+  * Wait some more for this command to complete, and if this does not work, 
+  * try something more serious. */ 
+ #define SCSI_ABORT_SNOOZE 0
+ 
+ /* This means that we were able to abort the command.  We have already
+  * called the mid-level done function, and do not expect an interrupt that 
+  * will lead to another call to the mid-level done function for this command */
+ #define SCSI_ABORT_SUCCESS 1
+ 
+ /* We called for an abort of this command, and we should get an interrupt 
+  * when this succeeds.  Thus we should not restore the timer for this
+  * command in the mid-level abort function. */
+ #define SCSI_ABORT_PENDING 2
+ 
+ /* Unable to abort - command is currently on the bus.  Grin and bear it. */
+ #define SCSI_ABORT_BUSY 3
+ 
+ /* The command is not active in the low level code. Command probably
+  * finished. */
+ #define SCSI_ABORT_NOT_RUNNING 4
+ 
+ /* Something went wrong.  The low level driver will indicate the correct
+  * error condition when it calls scsi_done, so the mid-level abort function
+  * can simply wait until this comes through */
+ #define SCSI_ABORT_ERROR 5
+ 
+ /* We do not know how to reset the bus, or we do not want to.  Bummer.
+  * Anyway, just wait a little more for the command in question, and hope that
+  * it eventually finishes.  If it never finishes, the SCSI device could
+  * hang, so use this with caution. */
+ #define SCSI_RESET_SNOOZE 0
+ 
+ /* We do not know how to reset the bus, or we do not want to.  Bummer.
+  * We have given up on this ever completing.  The mid-level code will
+  * request sense information to decide how to proceed from here. */
+ #define SCSI_RESET_PUNT 1
+ 
+ /* This means that we were able to reset the bus.  We have restarted all of
+  * the commands that should be restarted, and we should be able to continue
+  * on normally from here.  We do not expect any interrupts that will return
+  * DID_RESET to any of the other commands in the host_queue, and the mid-level
+  * code does not need to do anything special to keep the commands alive. 
+  * If a hard reset was performed then all outstanding commands on the
+  * bus have been restarted. */
+ #define SCSI_RESET_SUCCESS 2
+ 
+ /* We called for a reset of this bus, and we should get an interrupt 
+  * when this succeeds.  Each command should get its own status
+  * passed up to scsi_done, but this has not happened yet. 
+  * If a hard reset was performed, then we expect an interrupt
+  * for *each* of the outstanding commands that will have the
+  * effect of restarting the commands.
+  */
+ #define SCSI_RESET_PENDING 3
+ 
+ /* We did a reset, but do not expect an interrupt to signal DID_RESET.
+  * This tells the upper level code to request the sense info, and this
+  * should keep the command alive. */
+ #define SCSI_RESET_WAKEUP 4
+ 
+ /* The command is not active in the low level code. Command probably
+    finished. */
+ #define SCSI_RESET_NOT_RUNNING 5
+ 
+ /* Something went wrong, and we do not know how to fix it. */
+ #define SCSI_RESET_ERROR 6
+ 
+ #define SCSI_RESET_SYNCHRONOUS		0x01
+ #define SCSI_RESET_ASYNCHRONOUS		0x02
+ #define SCSI_RESET_SUGGEST_BUS_RESET	0x04
+ #define SCSI_RESET_SUGGEST_HOST_RESET	0x08
+ /*
+  * This is a bitmask that is ored with one of the above codes.
+  * It tells the mid-level code that we did a hard reset.
+  */
+ #define SCSI_RESET_BUS_RESET 0x100
+ /*
+  * This is a bitmask that is ored with one of the above codes.
+  * It tells the mid-level code that we did a host adapter reset.
+  */
+ #define SCSI_RESET_HOST_RESET 0x200
+ /*
+  * Used to mask off bits and to obtain the basic action that was
+  * performed.  
+  */
+ #define SCSI_RESET_ACTION   0xff
+ 
+ #endif /* SCSI_OBSOLETE_H */
Index: linux/drivers/scsi/scsi_proc.c
diff -c linux/drivers/scsi/scsi_proc.c:1.1.1.2 linux/drivers/scsi/scsi_proc.c:1.3
*** linux/drivers/scsi/scsi_proc.c:1.1.1.2	Sun May 18 19:35:39 1997
--- linux/drivers/scsi/scsi_proc.c	Sun May 18 20:19:59 1997
***************
*** 16,26 ****
   * Michael A. Griffith <grif@acm.org>
   */
  
- /*
-  * Don't import our own symbols, as this would severely mess up our
-  * symbol tables.
-  */
- #define _SCSI_SYMS_VER_
  #define __NO_VERSION__
  #include <linux/module.h>
  
--- 16,21 ----
***************
*** 39,44 ****
--- 34,40 ----
  #define FALSE 0
  #endif
  
+ #ifdef CONFIG_PROC_FS
  extern int scsi_proc_info(char *, char **, off_t, int, int, int);
   
  struct scsi_dir {
***************
*** 295,300 ****
--- 291,297 ----
      *size = y; 
      return;
  }
+ #endif /* CONFIG_SCSI_PROC */
  
  /*
   * Overrides for Emacs so that we get a uniform tabbing style.
Index: linux/drivers/scsi/scsi_syms.c
diff -c linux/drivers/scsi/scsi_syms.c:1.1.1.1 linux/drivers/scsi/scsi_syms.c:1.3
*** linux/drivers/scsi/scsi_syms.c:1.1.1.1	Sun May 18 19:18:10 1997
--- linux/drivers/scsi/scsi_syms.c	Wed Jun  4 08:58:20 1997
***************
*** 38,43 ****
--- 38,45 ----
  extern void print_command (unsigned char *command);
  extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt);
  
+ extern const char *const scsi_device_types[];
+ 
  EXPORT_SYMBOL(scsi_register_module);
  EXPORT_SYMBOL(scsi_unregister_module);
  EXPORT_SYMBOL(scsi_free);
***************
*** 45,51 ****
  EXPORT_SYMBOL(scsi_register);
  EXPORT_SYMBOL(scsi_unregister);
  EXPORT_SYMBOL(scsicam_bios_param);
! EXPORT_SYMBOL(allocate_device);
  EXPORT_SYMBOL(scsi_do_cmd);
  EXPORT_SYMBOL(scsi_command_size);
  EXPORT_SYMBOL(scsi_init_malloc);
--- 47,53 ----
  EXPORT_SYMBOL(scsi_register);
  EXPORT_SYMBOL(scsi_unregister);
  EXPORT_SYMBOL(scsicam_bios_param);
! EXPORT_SYMBOL(scsi_allocate_device);
  EXPORT_SYMBOL(scsi_do_cmd);
  EXPORT_SYMBOL(scsi_command_size);
  EXPORT_SYMBOL(scsi_init_malloc);
***************
*** 55,67 ****
  EXPORT_SYMBOL(print_sense);
  EXPORT_SYMBOL(print_msg);
  EXPORT_SYMBOL(print_status);
! EXPORT_SYMBOL(dma_free_sectors);
  EXPORT_SYMBOL(kernel_scsi_ioctl);
! EXPORT_SYMBOL(need_isa_buffer);
! EXPORT_SYMBOL(request_queueable);
  EXPORT_SYMBOL(print_Scsi_Cmnd);
! EXPORT_SYMBOL(scsi_mark_host_reset);
! EXPORT_SYMBOL(scsi_mark_bus_reset);
  #if defined(CONFIG_PROC_FS)
  EXPORT_SYMBOL(proc_print_scsidevice);
  #endif
--- 57,75 ----
  EXPORT_SYMBOL(print_sense);
  EXPORT_SYMBOL(print_msg);
  EXPORT_SYMBOL(print_status);
! EXPORT_SYMBOL(scsi_dma_free_sectors);
  EXPORT_SYMBOL(kernel_scsi_ioctl);
! EXPORT_SYMBOL(scsi_need_isa_buffer);
! EXPORT_SYMBOL(scsi_request_queueable);
! EXPORT_SYMBOL(scsi_release_command);
  EXPORT_SYMBOL(print_Scsi_Cmnd);
! EXPORT_SYMBOL(scsi_block_when_processing_errors);
! #if defined(CONFIG_SCSI_LOGGING) /* { */
! EXPORT_SYMBOL(scsi_logging_level);
! #endif
! 
! EXPORT_SYMBOL(scsi_device_types);
! 
  #if defined(CONFIG_PROC_FS)
  EXPORT_SYMBOL(proc_print_scsidevice);
  #endif
***************
*** 71,76 ****
  EXPORT_SYMBOL(scsi_hostlist);
  EXPORT_SYMBOL(scsi_hosts);
  EXPORT_SYMBOL(scsi_devicelist);
- EXPORT_SYMBOL(scsi_devices);
  
  #endif /* CONFIG_MODULES */
--- 79,83 ----
Index: linux/drivers/scsi/scsicam.c
diff -c linux/drivers/scsi/scsicam.c:1.1.1.1 linux/drivers/scsi/scsicam.c:1.2
*** linux/drivers/scsi/scsicam.c:1.1.1.1	Sun May 18 19:18:11 1997
--- linux/drivers/scsi/scsicam.c	Sun May 18 19:27:22 1997
***************
*** 10,20 ****
   * For more information, please consult the SCSI-CAM draft.
   */
  
- /*
-  * Don't import our own symbols, as this would severely mess up our
-  * symbol tables.
-  */
- #define _SCSI_SYMS_VER_
  #define __NO_VERSION__
  #include <linux/module.h>
  
--- 10,15 ----
Index: linux/drivers/scsi/sd.c
diff -c linux/drivers/scsi/sd.c:1.1.1.2 linux/drivers/scsi/sd.c:1.4
*** linux/drivers/scsi/sd.c:1.1.1.2	Sun May 18 19:35:20 1997
--- linux/drivers/scsi/sd.c	Wed May 28 08:37:32 1997
***************
*** 99,108 ****
--- 99,119 ----
      int target;
      target =  DEVICE_NR(inode->i_rdev);
  
+     printk("target=%d, max=%d\n", target, sd_template.dev_max);
+ 
      if(target >= sd_template.dev_max || !rscsi_disks[target].device)
  	return -ENXIO;   /* No such device */
  
      /*
+      * If the device is in error recovery, wait until it is done.
+      * If the device is offline, then disallow any access to it.
+      */
+     if( !scsi_block_when_processing_errors(rscsi_disks[target].device) )
+       {
+         return -ENXIO;
+       }
+ 
+     /*
       * Make sure that only one process can do a check_change_disk at one time.
       * This is also used to lock out further access when the partition table
       * is being re-read.
***************
*** 129,134 ****
--- 140,155 ----
      }
  
      /*
+      * It is possible that the disk changing stuff resulted in the device being taken
+      * offline.  If this is the case, report this to the user, and don't pretend that
+      * the open actually succeeded.
+      */
+     if( !rscsi_disks[target].device->online )
+     {
+         return -ENXIO;
+     }
+ 
+     /*
       * See if we are requesting a non-existent partition.  Do this
       * after checking for disk change.
       */
***************
*** 226,235 ****
      int good_sectors = (result == 0 ? this_count : 0);
      int block_sectors = 1;
  
! #ifdef DEBUG
!     printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.rq_dev),
! 	   SCpnt->host->host_no, result);
! #endif
  
      /*
        Handle MEDIUM ERRORs that indicate partial success.  Since this is a
--- 247,254 ----
      int good_sectors = (result == 0 ? this_count : 0);
      int block_sectors = 1;
  
!     SCSI_LOG_HLCOMPLETE(1,printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.rq_dev),
! 	   SCpnt->host->host_no, result));
  
      /*
        Handle MEDIUM ERRORs that indicate partial success.  Since this is a
***************
*** 276,295 ****
  
      if (good_sectors > 0) {
  
! #ifdef DEBUG
! 	printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.rq_dev),
! 	       SCpnt->request.nr_sectors);
! 	printk("use_sg is %d\n ",SCpnt->use_sg);
! #endif
  	if (SCpnt->use_sg) {
  	    struct scatterlist * sgpnt;
  	    int i;
  	    sgpnt = (struct scatterlist *) SCpnt->buffer;
  	    for(i=0; i<SCpnt->use_sg; i++) {
! #ifdef DEBUG
! 		printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address,
! 		       sgpnt[i].length);
! #endif
  		if (sgpnt[i].alt_address) {
  		    if (SCpnt->request.cmd == READ)
  			memcpy(sgpnt[i].alt_address, sgpnt[i].address,
--- 295,313 ----
  
      if (good_sectors > 0) {
  
! 	SCSI_LOG_HLCOMPLETE(1,printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.rq_dev),
! 	       SCpnt->request.nr_sectors));
! 	SCSI_LOG_HLCOMPLETE(1,printk("use_sg is %d\n ",SCpnt->use_sg));
! 
  	if (SCpnt->use_sg) {
  	    struct scatterlist * sgpnt;
  	    int i;
  	    sgpnt = (struct scatterlist *) SCpnt->buffer;
  	    for(i=0; i<SCpnt->use_sg; i++) {
! 
! 		SCSI_LOG_HLCOMPLETE(3,printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address,
! 		       sgpnt[i].length));
! 
  		if (sgpnt[i].alt_address) {
  		    if (SCpnt->request.cmd == READ)
  			memcpy(sgpnt[i].alt_address, sgpnt[i].address,
***************
*** 302,311 ****
  	    scsi_free(SCpnt->buffer, SCpnt->sglist_len);
  	} else {
  	    if (SCpnt->buffer != SCpnt->request.buffer) {
! #ifdef DEBUG
! 		printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
! 		       SCpnt->bufflen);
! #endif
  		if (SCpnt->request.cmd == READ)
  		    memcpy(SCpnt->request.buffer, SCpnt->buffer,
  			   SCpnt->bufflen);
--- 320,329 ----
  	    scsi_free(SCpnt->buffer, SCpnt->sglist_len);
  	} else {
  	    if (SCpnt->buffer != SCpnt->request.buffer) {
! 		SCSI_LOG_HLCOMPLETE(3,printk("nosg: %p %p %d\n",
!                                              SCpnt->request.buffer, SCpnt->buffer,
!                                              SCpnt->bufflen));
! 
  		if (SCpnt->request.cmd == READ)
  		    memcpy(SCpnt->request.buffer, SCpnt->buffer,
  			   SCpnt->bufflen);
***************
*** 323,332 ****
  
  	    if (!SCpnt->request.bh)
  	    {
! #ifdef DEBUG
! 		printk("sd%c : handling page request, no buffer\n",
! 		       'a' + MINOR(SCpnt->request.rq_dev));
! #endif
  		/*
  		 * The SCpnt->request.nr_sectors field is always done in
  		 * 512 byte sectors, even if this really isn't the case.
--- 341,349 ----
  
  	    if (!SCpnt->request.bh)
  	    {
! 		SCSI_LOG_HLCOMPLETE(2,printk("sd%c : handling page request, no buffer\n",
! 		       'a' + MINOR(SCpnt->request.rq_dev)));
! 
  		/*
  		 * The SCpnt->request.nr_sectors field is always done in
  		 * 512 byte sectors, even if this really isn't the case.
***************
*** 351,370 ****
  	int i;
  	sgpnt = (struct scatterlist *) SCpnt->buffer;
  	for(i=0; i<SCpnt->use_sg; i++) {
! #ifdef DEBUG
! 	    printk("err: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
! 		   SCpnt->bufflen);
! #endif
  	    if (sgpnt[i].alt_address) {
  		scsi_free(sgpnt[i].address, sgpnt[i].length);
  	    }
  	}
  	scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
      } else {
! #ifdef DEBUG
! 	printk("nosgerr: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
! 	       SCpnt->bufflen);
! #endif
  	if (SCpnt->buffer != SCpnt->request.buffer)
  	    scsi_free(SCpnt->buffer, SCpnt->bufflen);
      }
--- 368,385 ----
  	int i;
  	sgpnt = (struct scatterlist *) SCpnt->buffer;
  	for(i=0; i<SCpnt->use_sg; i++) {
! 	    SCSI_LOG_HLCOMPLETE(3,printk("err: %p %p %d\n",
!                                          SCpnt->request.buffer, SCpnt->buffer,
!                                          SCpnt->bufflen));
  	    if (sgpnt[i].alt_address) {
  		scsi_free(sgpnt[i].address, sgpnt[i].length);
  	    }
  	}
  	scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
      } else {
! 	SCSI_LOG_HLCOMPLETE(2,printk("nosgerr: %p %p %d\n",
!                                      SCpnt->request.buffer, SCpnt->buffer,
!                                      SCpnt->bufflen));
  	if (SCpnt->buffer != SCpnt->request.buffer)
  	    scsi_free(SCpnt->buffer, SCpnt->bufflen);
      }
***************
*** 485,490 ****
--- 500,516 ----
          SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device;
  
          /*
+          * If the host for this device is in error recovery mode, don't
+          * do anything at all here.  When the host leaves error recovery
+          * mode, it will automatically restart things and start queueing
+          * commands again.
+          */
+         if( SDev->host->in_recovery )
+           {
+             return;
+           }
+ 
+         /*
           * I am not sure where the best place to do this is.  We need
           * to hook in a place where we are likely to come if in user
           * space.
***************
*** 495,501 ****
  	     * We need to relock the door, but we might
  	     * be in an interrupt handler.  Only do this
  	     * from user space, since we do not want to
! 	     * sleep from an interrupt.
  	     */
  	    if( SDev->removable && !in_interrupt() )
  	    {
--- 521,528 ----
  	     * We need to relock the door, but we might
  	     * be in an interrupt handler.  Only do this
  	     * from user space, since we do not want to
! 	     * sleep from an interrupt.  FIXME(eric) - do this
!              * from the kernel error handling thred.
  	     */
  	    if( SDev->removable && !in_interrupt() )
  	    {
***************
*** 507,527 ****
  	    SDev->was_reset = 0;
          }
  
! 	/* We have to be careful here. allocate_device will get a free pointer,
  	 * but there is no guarantee that it is queueable.  In normal usage,
  	 * we want to call this, because other types of devices may have the
  	 * host all tied up, and we want to make sure that we have at least
  	 * one request pending for this type of device. We can also come
  	 * through here while servicing an interrupt, because of the need to
! 	 * start another command. If we call allocate_device more than once,
  	 * then the system can wedge if the command is not queueable. The
! 	 * request_queueable function is safe because it checks to make sure
  	 * that the host is able to take another command before it returns
  	 * a pointer.
  	 */
  
  	if (flag++ == 0)
! 	    SCpnt = allocate_device(&CURRENT,
  			   rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
  	else SCpnt = NULL;
  
--- 534,554 ----
  	    SDev->was_reset = 0;
          }
  
! 	/* We have to be careful here. scsi_allocate_device will get a free pointer,
  	 * but there is no guarantee that it is queueable.  In normal usage,
  	 * we want to call this, because other types of devices may have the
  	 * host all tied up, and we want to make sure that we have at least
  	 * one request pending for this type of device. We can also come
  	 * through here while servicing an interrupt, because of the need to
! 	 * start another command. If we call scsi_allocate_device more than once,
  	 * then the system can wedge if the command is not queueable. The
! 	 * scsi_request_queueable function is safe because it checks to make sure
  	 * that the host is able to take another command before it returns
  	 * a pointer.
  	 */
  
  	if (flag++ == 0)
! 	    SCpnt = scsi_allocate_device(&CURRENT,
  			   rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
  	else SCpnt = NULL;
  
***************
*** 539,553 ****
  	 * one disk drive.  We want to have the interrupts off when monkeying
  	 * with the request list, because otherwise the kernel might try to
  	 * slip in a request in between somewhere.
  	 */
- 
  	if (!SCpnt && sd_template.nr_dev > 1){
  	    struct request *req1;
  	    req1 = NULL;
  	    cli();
  	    req = CURRENT;
  	    while(req){
! 		SCpnt = request_queueable(req,
                                     rscsi_disks[DEVICE_NR(req->rq_dev)].device);
  		if(SCpnt) break;
  		req1 = req;
--- 566,584 ----
  	 * one disk drive.  We want to have the interrupts off when monkeying
  	 * with the request list, because otherwise the kernel might try to
  	 * slip in a request in between somewhere.
+          *
+          * FIXME(eric) - this doesn't belong at this level.  The device code in
+          * ll_rw_blk.c should know how to dig down into the device queue to
+          * figure out what it can deal with, and what it can't.  Consider
+          * possibility of pulling entire queue down into scsi layer.
  	 */
  	if (!SCpnt && sd_template.nr_dev > 1){
  	    struct request *req1;
  	    req1 = NULL;
  	    cli();
  	    req = CURRENT;
  	    while(req){
! 		SCpnt = scsi_request_queueable(req,
                                     rscsi_disks[DEVICE_NR(req->rq_dev)].device);
  		if(SCpnt) break;
  		req1 = req;
***************
*** 591,605 ****
      block = SCpnt->request.sector;
      this_count = 0;
  
! #ifdef DEBUG
!     printk("Doing sd request, dev = %d, block = %d\n", devm, block);
! #endif
  
      if (devm >= (sd_template.dev_max << 4) ||
  	!rscsi_disks[dev].device ||
  	block + SCpnt->request.nr_sectors > sd[devm].nr_sects)
      {
  	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
  	goto repeat;
      }
  
--- 622,637 ----
      block = SCpnt->request.sector;
      this_count = 0;
  
!     SCSI_LOG_HLQUEUE(1,printk("Doing sd request, dev = %d, block = %d\n", devm, block));
  
      if (devm >= (sd_template.dev_max << 4) ||
  	!rscsi_disks[dev].device ||
+ 	!rscsi_disks[dev].device->online ||
  	block + SCpnt->request.nr_sectors > sd[devm].nr_sects)
      {
+         SCSI_LOG_HLQUEUE(2,printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
  	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+         SCSI_LOG_HLQUEUE(2,printk("Retry with 0x%p\n", SCpnt));
  	goto repeat;
      }
  
***************
*** 616,625 ****
  	goto repeat;
      }
  
! #ifdef DEBUG
!     printk("sd%c : real dev = /dev/sd%c, block = %d\n",
! 	   'a' + devm, dev, block);
! #endif
  
      /*
       * If we have a 1K hardware sectorsize, prevent access to single
--- 648,655 ----
  	goto repeat;
      }
  
!     SCSI_LOG_HLQUEUE(2,printk("sd%c : real dev = /dev/sd%c, block = %d\n",
! 	   'a' + devm, dev, block));
  
      /*
       * If we have a 1K hardware sectorsize, prevent access to single
***************
*** 702,708 ****
  	SCpnt->use_sg = 0;
  
      } else if (SCpnt->host->sg_tablesize == 0 ||
! 	       (need_isa_buffer && dma_free_sectors <= 10)) {
  
  	/* Case of host adapter that cannot scatter-gather.  We also
  	 * come here if we are running low on DMA buffer memory.  We set
--- 732,738 ----
  	SCpnt->use_sg = 0;
  
      } else if (SCpnt->host->sg_tablesize == 0 ||
! 	       (scsi_need_isa_buffer && scsi_dma_free_sectors <= 10)) {
  
  	/* Case of host adapter that cannot scatter-gather.  We also
  	 * come here if we are running low on DMA buffer memory.  We set
***************
*** 712,719 ****
  	 * we have no choice but to panic.
  	 */
  	if (SCpnt->host->sg_tablesize != 0 &&
! 	    need_isa_buffer &&
! 	    dma_free_sectors <= 10)
  	    printk("Warning: SCSI DMA buffer space running low.  Using non scatter-gather I/O.\n");
  
  	this_count = SCpnt->request.current_nr_sectors;
--- 742,749 ----
  	 * we have no choice but to panic.
  	 */
  	if (SCpnt->host->sg_tablesize != 0 &&
! 	    scsi_need_isa_buffer &&
! 	    scsi_dma_free_sectors <= 10)
  	    printk("Warning: SCSI DMA buffer space running low.  Using non scatter-gather I/O.\n");
  
  	this_count = SCpnt->request.current_nr_sectors;
***************
*** 787,793 ****
  		     * easier to control usage here. In other places we might
  		     * have a more pressing need, and we would be screwed if
  		     * we ran out */
! 		    if(dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
  			sgpnt[count].address = NULL;
  		    } else {
  			sgpnt[count].address =
--- 817,823 ----
  		     * easier to control usage here. In other places we might
  		     * have a more pressing need, and we would be screwed if
  		     * we ran out */
! 		    if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
  			sgpnt[count].address = NULL;
  		    } else {
  			sgpnt[count].address =
***************
*** 832,838 ****
  			!sgpnt[count].alt_address) continue;
  
  		    if(!sgpnt[count].alt_address) {count--; continue; }
! 		    if(dma_free_sectors > 10)
  			tmp = (char *) scsi_malloc(sgpnt[count].length
  						   + bhp->b_size);
  		    else {
--- 862,868 ----
  			!sgpnt[count].alt_address) continue;
  
  		    if(!sgpnt[count].alt_address) {count--; continue; }
! 		    if(scsi_dma_free_sectors > 10)
  			tmp = (char *) scsi_malloc(sgpnt[count].length
  						   + bhp->b_size);
  		    else {
***************
*** 861,867 ****
  	       > SCpnt->host->sg_tablesize){
  		bh = SCpnt->request.bh;
  		printk("Use sg, count %d %x %d\n",
! 		       SCpnt->use_sg, count, dma_free_sectors);
  		printk("maxsg = %x, counted = %d this_count = %d\n",
  		       max_sg, counted, this_count);
  		while(bh){
--- 891,897 ----
  	       > SCpnt->host->sg_tablesize){
  		bh = SCpnt->request.bh;
  		printk("Use sg, count %d %x %d\n",
! 		       SCpnt->use_sg, count, scsi_dma_free_sectors);
  		printk("maxsg = %x, counted = %d this_count = %d\n",
  		       max_sg, counted, this_count);
  		while(bh){
***************
*** 903,914 ****
  		memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
  	}
      }
! #ifdef DEBUG
!     printk("sd%c : %s %d/%d 512 byte blocks.\n",
! 	   'a' + devm,
! 	   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
! 	   this_count, SCpnt->request.nr_sectors);
! #endif
  
      cmd[1] = (SCpnt->lun << 5) & 0xe0;
  
--- 933,942 ----
  		memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
  	}
      }
!     SCSI_LOG_HLQUEUE(2,printk("sd%c : %s %d/%d 512 byte blocks.\n",
!                               'a' + devm,
!                               (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
!                               this_count, SCpnt->request.nr_sectors));
  
      cmd[1] = (SCpnt->lun << 5) & 0xe0;
  
***************
*** 989,994 ****
--- 1017,1036 ----
  
      if(!rscsi_disks[target].device->removable) return 0;
  
+     /*
+      * If the device is offline, don't send any commands - just pretend as if
+      * the command failed.  If the device ever comes back online, we can deal with
+      * it then.  It is only because of unrecoverable errors that we would ever
+      * take a device offline in the first place.
+      */
+     if( rscsi_disks[target].device->online == FALSE )
+     {
+ 	rscsi_disks[target].ready = 0;
+ 	rscsi_disks[target].device->changed = 1;
+ 	return 1; /* This will force a flush, if called from
+ 		   * check_disk_change */
+     }
+ 
      inode.i_rdev = full_dev;  /* This is all we really need here */
      retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
  
***************
*** 1036,1047 ****
      int the_result, retries;
      Scsi_Cmnd * SCpnt;
  
      /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
       * considered a fatal error, and many devices report such an error
       * just after a scsi bus reset.
       */
  
!     SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1);
      buffer = (unsigned char *) scsi_malloc(512);
  
      spintime = 0;
--- 1078,1098 ----
      int the_result, retries;
      Scsi_Cmnd * SCpnt;
  
+     /*
+      * If the device is offline, don't try and read capacity or any of the other
+      * nicities.
+      */
+     if( rscsi_disks[i].device->online == FALSE )
+     {
+         return i;
+     }
+ 
      /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
       * considered a fatal error, and many devices report such an error
       * just after a scsi bus reset.
       */
  
!     SCpnt = scsi_allocate_device(NULL, rscsi_disks[i].device, 1);
      buffer = (unsigned char *) scsi_malloc(512);
  
      spintime = 0;
***************
*** 1069,1074 ****
--- 1120,1126 ----
  				 512, sd_init_done,  SD_TIMEOUT,
  				 MAX_RETRIES);
  		    down(&sem);
+                     SCpnt->request.sem = NULL;
  		}
  
  		the_result = SCpnt->result;
***************
*** 1104,1109 ****
--- 1156,1162 ----
  				     512, sd_init_done,  SD_TIMEOUT,
  				     MAX_RETRIES);
  			down(&sem);
+                         SCpnt->request.sem = NULL;
  		    }
  
  		    spintime = jiffies;
***************
*** 1141,1146 ****
--- 1194,1200 ----
  			 8, sd_init_done,  SD_TIMEOUT,
  			 MAX_RETRIES);
  	    down(&sem);	/* sleep until it is ready */
+             SCpnt->request.sem = NULL;
  	}
  
  	the_result = SCpnt->result;
***************
*** 1148,1159 ****
  
      } while(the_result && retries);
  
-     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
- 
-     wake_up(&SCpnt->device->device_wait);
- 
-     /* Wake up a process waiting for device */
- 
      /*
       * The SCSI standard says:
       * "READ CAPACITY is necessary for self configuring software"
--- 1202,1207 ----
***************
*** 1231,1236 ****
--- 1279,1290 ----
  		rscsi_disks[i].device = NULL;
  		sd_template.nr_dev--;
  		sd_gendisk.nr_real--;
+ 
+                 /* Wake up a process waiting for device */
+                 wake_up(&SCpnt->device->device_wait);
+                 scsi_release_command(SCpnt);
+                 SCpnt = NULL;
+                 
  		return i;
  	    }
  	}
***************
*** 1315,1325 ****
  			 512, sd_init_done,  SD_TIMEOUT,
  			 MAX_RETRIES);
  	    down(&sem);
  	}
  
  	the_result = SCpnt->result;
- 	SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
- 	wake_up(&SCpnt->device->device_wait);
  
  	if ( the_result ) {
  	    printk ("sd%c: test WP failed, assume Write Protected\n",i+'a');
--- 1369,1378 ----
  			 512, sd_init_done,  SD_TIMEOUT,
  			 MAX_RETRIES);
  	    down(&sem);
+             SCpnt->request.sem = NULL;
  	}
  
  	the_result = SCpnt->result;
  
  	if ( the_result ) {
  	    printk ("sd%c: test WP failed, assume Write Protected\n",i+'a');
***************
*** 1331,1336 ****
--- 1384,1394 ----
  	}
  
      }	/* check for write protect */
+ 
+     /* Wake up a process waiting for device */
+     wake_up(&SCpnt->device->device_wait);
+     scsi_release_command(SCpnt);
+     SCpnt = NULL;
  
      rscsi_disks[i].ten = 1;
      rscsi_disks[i].remap = 1;
Index: linux/drivers/scsi/sd_ioctl.c
diff -c linux/drivers/scsi/sd_ioctl.c:1.1.1.1 linux/drivers/scsi/sd_ioctl.c:1.2
*** linux/drivers/scsi/sd_ioctl.c:1.1.1.1	Sun May 18 19:18:08 1997
--- linux/drivers/scsi/sd_ioctl.c	Sun May 18 19:27:23 1997
***************
*** 25,33 ****
--- 25,46 ----
      kdev_t dev = inode->i_rdev;
      int error;
      struct Scsi_Host * host;
+     Scsi_Device * SDev;
      int diskinfo[4];
      struct hd_geometry *loc = (struct hd_geometry *) arg;
      
+     SDev = rscsi_disks[MINOR(dev) >> 4].device;
+     /*
+      * If we are in the middle of error recovery, don't let anyone
+      * else try and use this device.  Also, if error recovery fails, it
+      * may try and take the device offline, in which case all further
+      * access to the device is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(SDev) )
+       {
+         return -ENODEV;
+       }
+ 
      switch (cmd) {
      case HDIO_GETGEO:   /* Return BIOS disk parameters */
  	if (!loc)  return -EINVAL;
Index: linux/drivers/scsi/seagate.h
diff -c linux/drivers/scsi/seagate.h:1.1.1.2 linux/drivers/scsi/seagate.h:1.3
*** linux/drivers/scsi/seagate.h:1.1.1.2	Sun May 18 19:35:21 1997
--- linux/drivers/scsi/seagate.h	Sun May 18 20:20:00 1997
***************
*** 27,39 ****
  #include <linux/kdev_t.h>
  int seagate_st0x_biosparam(Disk *, kdev_t, int*);
  
! #define SEAGATE_ST0X  {  NULL, NULL, NULL, NULL, \
! 			 NULL, seagate_st0x_detect, 	\
! 			 NULL, 						\
! 			 seagate_st0x_info, seagate_st0x_command,  	\
! 			 seagate_st0x_queue_command, seagate_st0x_abort, \
! 			 seagate_st0x_reset, NULL, seagate_st0x_biosparam, \
! 			 1, 7, SG_ALL, 1, 0, 0, DISABLE_CLUSTERING}
  #endif /* ASM */
  
  #endif /* _SEAGATE_H */
--- 27,44 ----
  #include <linux/kdev_t.h>
  int seagate_st0x_biosparam(Disk *, kdev_t, int*);
  
! #define SEAGATE_ST0X  {  detect:         seagate_st0x_detect,		\
! 			 info:           seagate_st0x_info,		\
! 			 command:        seagate_st0x_command,		\
! 			 queuecommand:   seagate_st0x_queue_command,	\
! 			 abort:          seagate_st0x_abort,		\
! 			 reset:          seagate_st0x_reset,		\
! 			 bios_param:     seagate_st0x_biosparam,	\
! 			 can_queue:      1,				\
! 			 this_id:        7,				\
! 			 sg_tablesize:   SG_ALL,			\
! 			 cmd_per_lun:    1,				\
! 			 use_clustering: DISABLE_CLUSTERING}
  #endif /* ASM */
  
  #endif /* _SEAGATE_H */
Index: linux/drivers/scsi/sg.c
diff -c linux/drivers/scsi/sg.c:1.1.1.1 linux/drivers/scsi/sg.c:1.2
*** linux/drivers/scsi/sg.c:1.1.1.1	Sun May 18 19:18:10 1997
--- linux/drivers/scsi/sg.c	Sun May 18 19:27:23 1997
***************
*** 67,76 ****
  static int sg_ioctl(struct inode * inode,struct file * file,
  		    unsigned int cmd_in, unsigned long arg)
  {
!     int result;
!     int dev = MINOR(inode->i_rdev);
      if ((dev<0) || (dev>=sg_template.dev_max))
  	return -ENXIO;
      switch(cmd_in)
      {
      case SG_SET_TIMEOUT:
--- 67,88 ----
  static int sg_ioctl(struct inode * inode,struct file * file,
  		    unsigned int cmd_in, unsigned long arg)
  {
!     int                         dev = MINOR(inode->i_rdev);
!     int                         result;
! 
      if ((dev<0) || (dev>=sg_template.dev_max))
  	return -ENXIO;
+ 
+     /*
+      * If we are in the middle of error recovery, then don't allow any
+      * access to this device.  Also, error recovery *may* have taken the
+      * device offline, in which case all further access is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+       {
+         return -ENXIO;
+       }
+ 
      switch(cmd_in)
      {
      case SG_SET_TIMEOUT:
***************
*** 92,97 ****
--- 104,115 ----
      int flags=filp->f_flags;
      if (dev>=sg_template.dev_max || !scsi_generics[dev].device)
  	return -ENXIO;
+ 
+     if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+       {
+         return -ENXIO;
+       }
+ 
      if (O_RDWR!=(flags & O_ACCMODE))
  	return -EACCES;
  
***************
*** 206,211 ****
--- 224,242 ----
      int i;
      unsigned long flags;
      struct scsi_generic *device=&scsi_generics[dev];
+ 
+     /*
+      * If we are in the middle of error recovery, don't let anyone
+      * else try and use this device.  Also, if error recovery fails, it
+      * may try and take the device offline, in which case all further
+      * access to the device is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+       {
+         return -ENXIO;
+       }
+ 
+ 
      if ((i=verify_area(VERIFY_WRITE,buf,count)))
  	return i;
  
***************
*** 271,277 ****
      if (!device->pending)
      {
  	printk("unexpected done for sg %d\n",dev);
! 	SCpnt->request.rq_status = RQ_INACTIVE;
  	return;
      }
  
--- 302,309 ----
      if (!device->pending)
      {
  	printk("unexpected done for sg %d\n",dev);
!         scsi_release_command(SCpnt);
!         SCpnt = NULL;
  	return;
      }
  
***************
*** 318,324 ****
       * result.
       */
      device->complete=1;
!     SCpnt->request.rq_status = RQ_INACTIVE;
      wake_up(&scsi_generics[dev].read_wait);
  }
  
--- 350,357 ----
       * result.
       */
      device->complete=1;
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
      wake_up(&scsi_generics[dev].read_wait);
  }
  
***************
*** 333,338 ****
--- 366,382 ----
      unsigned char	  opcode;
      Scsi_Cmnd		* SCpnt;
  
+     /*
+      * If we are in the middle of error recovery, don't let anyone
+      * else try and use this device.  Also, if error recovery fails, it
+      * may try and take the device offline, in which case all further
+      * access to the device is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+       {
+         return -ENXIO;
+       }
+ 
      if ((i=verify_area(VERIFY_READ,buf,count)))
  	return i;
      /*
***************
*** 431,437 ****
       * Grab a device pointer for the device we want to talk to.  If we
       * don't want to block, just return with the appropriate message.
       */
!     if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
      {
  	device->pending=0;
  	wake_up(&device->write_wait);
--- 475,481 ----
       * Grab a device pointer for the device we want to talk to.  If we
       * don't want to block, just return with the appropriate message.
       */
!     if (!(SCpnt=scsi_allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
      {
  	device->pending=0;
  	wake_up(&device->write_wait);
Index: linux/drivers/scsi/sr.c
diff -c linux/drivers/scsi/sr.c:1.1.1.1 linux/drivers/scsi/sr.c:1.2
*** linux/drivers/scsi/sr.c:1.1.1.1	Sun May 18 19:18:09 1997
--- linux/drivers/scsi/sr.c	Sun May 18 19:27:24 1997
***************
*** 380,385 ****
--- 380,400 ----
  {
      check_disk_change(cdi->dev);
  
+     if(   MINOR(cdi->dev) >= sr_template.dev_max 
+        || !scsi_CDs[MINOR(cdi->dev)].device)
+       {
+ 	return -ENXIO;   /* No such device */
+       }
+ 
+     /*
+      * If the device is in error recovery, wait until it is done.
+      * If the device is offline, then disallow any access to it.
+      */
+     if( !scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device) )
+       {
+         return -ENXIO;
+       }
+ 
      scsi_CDs[MINOR(cdi->dev)].device->access_count++;
      if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
  	__MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
***************
*** 423,428 ****
--- 438,454 ----
  
  	SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device;
  
+         /*
+          * If the host for this device is in error recovery mode, don't
+          * do anything at all here.  When the host leaves error recovery
+          * mode, it will automatically restart things and start queueing
+          * commands again.
+          */
+         if( SDev->host->in_recovery )
+           {
+             return;
+           }
+ 
  	/*
  	 * I am not sure where the best place to do this is.  We need
  	 * to hook in a place where we are likely to come if in user
***************
*** 444,450 ****
  	}
  
  	if (flag++ == 0)
! 	    SCpnt = allocate_device(&CURRENT,
  				    scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
  	else SCpnt = NULL;
  	restore_flags(flags);
--- 470,476 ----
  	}
  
  	if (flag++ == 0)
! 	    SCpnt = scsi_allocate_device(&CURRENT,
  				    scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
  	else SCpnt = NULL;
  	restore_flags(flags);
***************
*** 463,469 ****
  	    cli();
  	    req = CURRENT;
  	    while(req){
! 		SCpnt = request_queueable(req,
  					  scsi_CDs[DEVICE_NR(req->rq_dev)].device);
  		if(SCpnt) break;
  		req1 = req;
--- 489,495 ----
  	    cli();
  	    req = CURRENT;
  	    while(req){
! 		SCpnt = scsi_request_queueable(req,
  					  scsi_CDs[DEVICE_NR(req->rq_dev)].device);
  		if(SCpnt) break;
  		req1 = req;
***************
*** 521,526 ****
--- 547,559 ----
  		goto repeat;
  	}
  
+ 	if( !scsi_CDs[dev].device->online )
+           {
+             SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+             tries = 2;
+             goto repeat;
+           }
+ 
  	if (scsi_CDs[dev].device->changed) {
  	/*
  	 * quietly refuse to do anything to a changed disc
***************
*** 567,574 ****
  	SCpnt->use_sg = 0;
  
  	if (SCpnt->host->sg_tablesize > 0 &&
! 	    (!need_isa_buffer ||
! 	 dma_free_sectors >= 10)) {
  	struct buffer_head * bh;
  	struct scatterlist * sgpnt;
  	int count, this_count_max;
--- 600,607 ----
  	SCpnt->use_sg = 0;
  
  	if (SCpnt->host->sg_tablesize > 0 &&
! 	    (!scsi_need_isa_buffer ||
! 	 scsi_dma_free_sectors >= 10)) {
  	struct buffer_head * bh;
  	struct scatterlist * sgpnt;
  	int count, this_count_max;
***************
*** 639,645 ****
  		    /* We try to avoid exhausting the DMA pool, since it is easier
  		     * to control usage here.  In other places we might have a more
  		     * pressing need, and we would be screwed if we ran out */
! 		    if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
  			sgpnt[count].address = NULL;
  		    } else {
  			sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
--- 672,678 ----
  		    /* We try to avoid exhausting the DMA pool, since it is easier
  		     * to control usage here.  In other places we might have a more
  		     * pressing need, and we would be screwed if we ran out */
! 		    if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
  			sgpnt[count].address = NULL;
  		    } else {
  			sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
***************
*** 843,849 ****
      Scsi_Cmnd * SCpnt;
  
      buffer = (unsigned char *) scsi_malloc(512);
!     SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1);
  
      retries = 3;
      do {
--- 876,882 ----
      Scsi_Cmnd * SCpnt;
  
      buffer = (unsigned char *) scsi_malloc(512);
!     SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1);
  
      retries = 3;
      do {
***************
*** 871,879 ****
  
      } while(the_result && retries);
  
-     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  
      wake_up(&SCpnt->device->device_wait);
  
      if (the_result) {
  	scsi_CDs[i].capacity = 0x1fffff;
--- 904,913 ----
  
      } while(the_result && retries);
  
  
      wake_up(&SCpnt->device->device_wait);
+     scsi_release_command(SCpnt);
+     SCpnt = NULL;
  
      if (the_result) {
  	scsi_CDs[i].capacity = 0x1fffff;
Index: linux/drivers/scsi/sr_ioctl.c
diff -c linux/drivers/scsi/sr_ioctl.c:1.1.1.1 linux/drivers/scsi/sr_ioctl.c:1.2
*** linux/drivers/scsi/sr_ioctl.c:1.1.1.1	Sun May 18 19:18:09 1997
--- linux/drivers/scsi/sr_ioctl.c	Sun May 18 19:27:24 1997
***************
*** 43,49 ****
      Scsi_Cmnd * SCpnt;
      int result;
  
!     SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
      {
  	struct semaphore sem = MUTEX_LOCKED;
  	SCpnt->request.sem = &sem;
--- 43,49 ----
      Scsi_Cmnd * SCpnt;
      int result;
  
!     SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1);
      {
  	struct semaphore sem = MUTEX_LOCKED;
  	SCpnt->request.sem = &sem;
***************
*** 51,56 ****
--- 51,57 ----
  		    (void *) sr_cmd, buffer, buflength, sr_ioctl_done, 
  		    IOCTL_TIMEOUT, IOCTL_RETRIES);
  	down(&sem);
+         SCpnt->request.sem = NULL;
      }
      
      result = SCpnt->result;
***************
*** 73,80 ****
  	};
      
      result = SCpnt->result;
-     SCpnt->request.rq_status = RQ_INACTIVE; /* Deallocate */
      wake_up(&SCpnt->device->device_wait);
      /* Wake up a process waiting for device*/
      return result;
  }
--- 74,82 ----
  	};
      
      result = SCpnt->result;
      wake_up(&SCpnt->device->device_wait);
+     scsi_release_command(SCpnt);
+     SCpnt = NULL;
      /* Wake up a process waiting for device*/
      return result;
  }
***************
*** 207,216 ****
--- 209,231 ----
  int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
  {
      u_char  sr_cmd[10];    
+     Scsi_Device * SDev;
      int result, target;
      
      target = MINOR(cdi->dev);
      
+     SDev = scsi_CDs[target].device;
+     /*
+      * If we are in the middle of error recovery, don't let anyone
+      * else try and use this device.  Also, if error recovery fails, it
+      * may try and take the device offline, in which case all further
+      * access to the device is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(SDev) )
+       {
+         return -ENODEV;
+       }
+ 
      switch (cmd) 
      {
  	/* Sun-compatible */
***************
*** 520,528 ****
--- 535,556 ----
                   unsigned int cmd, unsigned long arg)
  {
      int target, err;
+     Scsi_Device * SDev;
      
      target = MINOR(cdi->dev);
      
+     SDev = scsi_CDs[target].device;
+     /*
+      * If we are in the middle of error recovery, don't let anyone
+      * else try and use this device.  Also, if error recovery fails, it
+      * may try and take the device offline, in which case all further
+      * access to the device is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(SDev) )
+       {
+         return -ENODEV;
+       }
+ 
      switch (cmd) {
      /* these are compatible with the ide-cd driver */
      case CDROMREADRAW:
Index: linux/drivers/scsi/st.c
diff -c linux/drivers/scsi/st.c:1.1.1.2 linux/drivers/scsi/st.c:1.3
*** linux/drivers/scsi/st.c:1.1.1.2	Wed May 28 07:54:10 1997
--- linux/drivers/scsi/st.c	Wed May 28 08:37:33 1997
***************
*** 234,240 ****
      if ((STp->buffer)->writing) {
        /* Process errors before releasing request */
        (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
!       SCpnt->request.rq_status = RQ_INACTIVE;
      }
      else
        SCpnt->request.rq_status = RQ_SCSI_DONE;
--- 234,241 ----
      if ((STp->buffer)->writing) {
        /* Process errors before releasing request */
        (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
!       scsi_release_command(SCpnt);
!       SCpnt = NULL;
      }
      else
        SCpnt->request.rq_status = RQ_SCSI_DONE;
***************
*** 261,267 ****
  	   int timeout, int retries)
  {
    if (SCpnt == NULL)
!     if ((SCpnt = allocate_device(NULL, STp->device, 1)) == NULL) {
        printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
        return NULL;
      }
--- 262,268 ----
  	   int timeout, int retries)
  {
    if (SCpnt == NULL)
!     if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
        printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
        return NULL;
      }
***************
*** 349,355 ****
    if (!SCpnt)
      return (-EBUSY);
  
!   SCpnt->request.rq_status = RQ_INACTIVE;
    if ((STp->buffer)->last_result != 0)
      printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n",
  	   TAPE_NR(STp->devt), forward ? "forward" : "backward");
--- 350,358 ----
    if (!SCpnt)
      return (-EBUSY);
  
!   scsi_release_command(SCpnt);
!   SCpnt = NULL;
! 
    if ((STp->buffer)->last_result != 0)
      printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n",
  	   TAPE_NR(STp->devt), forward ? "forward" : "backward");
***************
*** 430,436 ****
        STp->dirty = 0;
        (STp->buffer)->buffer_bytes = 0;
      }
!     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
    }
    return result;
  }
--- 433,440 ----
        STp->dirty = 0;
        (STp->buffer)->buffer_bytes = 0;
      }
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
    }
    return result;
  }
***************
*** 552,557 ****
--- 556,567 ----
  
      if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
        return (-ENXIO);
+ 
+     if( !scsi_block_when_processing_errors(scsi_tapes[dev].device) )
+       {
+         return -ENXIO;
+       }
+ 
      STp = &(scsi_tapes[dev]);
      if (STp->in_use) {
  #if DEBUG
***************
*** 650,656 ****
  	STp->ready = ST_NO_TAPE;
        } else
  	STp->ready = ST_NOT_READY;
!       SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
        STp->density = 0;   	/* Clear the erroneous "residue" */
        STp->write_prot = 0;
        STp->block_size = 0;
--- 660,667 ----
  	STp->ready = ST_NO_TAPE;
        } else
  	STp->ready = ST_NOT_READY;
!       scsi_release_command(SCpnt);
!       SCpnt = NULL;
        STp->density = 0;   	/* Clear the erroneous "residue" */
        STp->write_prot = 0;
        STp->block_size = 0;
***************
*** 742,748 ****
        }
        STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
      }
!     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  
      if (STp->block_size > 0)
        (STp->buffer)->buffer_blocks = st_buffer_size / STp->block_size;
--- 753,760 ----
        }
        STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
      }
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
  
      if (STp->block_size > 0)
        (STp->buffer)->buffer_blocks = st_buffer_size / STp->block_size;
***************
*** 872,878 ****
  	if (!SCpnt)
  	  goto out;
  
! 	SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  
  	if ((STp->buffer)->last_result_fatal != 0 &&
  	    ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
--- 884,891 ----
  	if (!SCpnt)
  	  goto out;
  
! 	scsi_release_command(SCpnt);
! 	SCpnt = NULL;
  
  	if ((STp->buffer)->last_result_fatal != 0 &&
  	    ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
***************
*** 972,977 ****
--- 985,1003 ----
      int dev = TAPE_NR(inode->i_rdev);
  
      STp = &(scsi_tapes[dev]);
+ 
+     /*
+      * If we are in the middle of error recovery, don't let anyone
+      * else try and use this device.  Also, if error recovery fails, it
+      * may try and take the device offline, in which case all further
+      * access to the device is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(STp->device) )
+       {
+         return -ENXIO;
+       }
+     
+ 
      if (STp->ready != ST_READY)
        return (-EIO);
      STm = &(STp->modes[STp->current_mode]);
***************
*** 1095,1101 ****
  			 (STp->buffer)->buffer_bytes, b_point, do_count);
        if (i) {
  	  if (SCpnt != NULL)
! 	      SCpnt->request.rq_status = RQ_INACTIVE;
  	  return (-EFAULT);
        }
  
--- 1121,1130 ----
  			 (STp->buffer)->buffer_bytes, b_point, do_count);
        if (i) {
  	  if (SCpnt != NULL)
! 	    {
! 	      scsi_release_command(SCpnt);
! 	      SCpnt = NULL;
! 	    }
  	  return (-EFAULT);
        }
  
***************
*** 1164,1170 ****
  	  retval = (-EIO);
  	}
  
! 	SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  	(STp->buffer)->buffer_bytes = 0;
  	STp->dirty = 0;
  	if (count < total)
--- 1193,1200 ----
  	  retval = (-EIO);
  	}
  
! 	scsi_release_command(SCpnt);
! 	SCpnt = NULL;
  	(STp->buffer)->buffer_bytes = 0;
  	STp->dirty = 0;
  	if (count < total)
***************
*** 1190,1196 ****
  			 (STp->buffer)->buffer_bytes, b_point, count);
        if (i) {
  	  if (SCpnt != NULL)
! 	      SCpnt->request.rq_status = RQ_INACTIVE;
  	  return (-EFAULT);
        }
        filp->f_pos += count;
--- 1220,1229 ----
  			 (STp->buffer)->buffer_bytes, b_point, count);
        if (i) {
  	  if (SCpnt != NULL)
! 	    {
! 	      scsi_release_command(SCpnt);
! 	      SCpnt = NULL;
! 	    }
  	  return (-EFAULT);
        }
        filp->f_pos += count;
***************
*** 1199,1205 ****
      }
  
      if (doing_write && (STp->buffer)->last_result_fatal != 0) {
!       SCpnt->request.rq_status = RQ_INACTIVE;
        return (STp->buffer)->last_result_fatal;
      }
  
--- 1232,1239 ----
      }
  
      if (doing_write && (STp->buffer)->last_result_fatal != 0) {
!       scsi_release_command(SCpnt);
!       SCpnt = NULL;
        return (STp->buffer)->last_result_fatal;
      }
  
***************
*** 1209,1215 ****
  	 STp->block_size == 0) ) {
        /* Schedule an asynchronous write */
        if (!SCpnt) {
! 	SCpnt = allocate_device(NULL, STp->device, 1);
  	if (!SCpnt)
  	  return (-EBUSY);
        }
--- 1243,1249 ----
  	 STp->block_size == 0) ) {
        /* Schedule an asynchronous write */
        if (!SCpnt) {
! 	SCpnt = scsi_allocate_device(NULL, STp->device, 1);
  	if (!SCpnt)
  	  return (-EBUSY);
        }
***************
*** 1242,1249 ****
  		   st_sleep_done, STp->timeout, MAX_WRITE_RETRIES);
      }
      else if (SCpnt != NULL)
!       SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
! 
      STps->at_sm &= (total == 0);
      if (total > 0)
  	STps->eof = ST_NOEOF;
--- 1276,1285 ----
  		   st_sleep_done, STp->timeout, MAX_WRITE_RETRIES);
      }
      else if (SCpnt != NULL)
!       {
! 	scsi_release_command(SCpnt);
! 	SCpnt = NULL;
!       }
      STps->at_sm &= (total == 0);
      if (total > 0)
  	STps->eof = ST_NOEOF;
***************
*** 1343,1349 ****
  			(STp->buffer)->buffer_bytes = bytes - transfer;
  		    }
  		    else {
! 			SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  			SCpnt = NULL;
  			if (transfer == blks) {  /* We did not get anything, error */
  			    printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
--- 1379,1385 ----
  			(STp->buffer)->buffer_bytes = bytes - transfer;
  		    }
  		    else {
! 		        scsi_release_command(SCpnt);
  			SCpnt = NULL;
  			if (transfer == blks) {  /* We did not get anything, error */
  			    printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
***************
*** 1454,1459 ****
--- 1490,1507 ----
      int dev = TAPE_NR(inode->i_rdev);
  
      STp = &(scsi_tapes[dev]);
+ 
+     /*
+      * If we are in the middle of error recovery, don't let anyone
+      * else try and use this device.  Also, if error recovery fails, it
+      * may try and take the device offline, in which case all further
+      * access to the device is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(STp->device) )
+       {
+         return -ENXIO;
+       }
+     
      if (STp->ready != ST_READY)
        return (-EIO);
      STm = &(STp->modes[STp->current_mode]);
***************
*** 1524,1530 ****
  	  special = read_tape(inode, count - total, &SCpnt);
  	  if (special < 0) { /* No need to continue read */
  	      if (SCpnt != NULL)
! 		  SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  	      return special;
  	  }
        }
--- 1572,1580 ----
  	  special = read_tape(inode, count - total, &SCpnt);
  	  if (special < 0) { /* No need to continue read */
  	      if (SCpnt != NULL)
! 		{
! 		  scsi_release_command(SCpnt);
! 		}
  	      return special;
  	  }
        }
***************
*** 1542,1548 ****
  			 (STp->buffer)->read_pointer, transfer);
  	if (i) {
  	    if (SCpnt != NULL)
! 		SCpnt->request.rq_status = RQ_INACTIVE;
  	    return (-EFAULT);
  	}
  	filp->f_pos += transfer;
--- 1592,1601 ----
  			 (STp->buffer)->read_pointer, transfer);
  	if (i) {
  	    if (SCpnt != NULL)
! 	      {
! 		scsi_release_command(SCpnt);
! 		SCpnt = NULL;
! 	      }
  	    return (-EFAULT);
  	}
  	filp->f_pos += transfer;
***************
*** 1558,1564 ****
      } /* for (total = 0, special = 0; total < count && !special; ) */
  
      if (SCpnt != NULL)
!       SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  
      /* Change the eof state if no data from tape or buffer */
      if (total == 0) {
--- 1611,1620 ----
      } /* for (total = 0, special = 0; total < count && !special; ) */
  
      if (SCpnt != NULL)
!       {
! 	scsi_release_command(SCpnt);
! 	SCpnt = NULL;
!       }
  
      /* Change the eof state if no data from tape or buffer */
      if (total == 0) {
***************
*** 1802,1808 ****
      if (debugging)
        printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev);
  #endif
!     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
      return (-EIO);
    }
  #if DEBUG
--- 1858,1865 ----
      if (debugging)
        printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev);
  #endif
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
      return (-EIO);
    }
  #if DEBUG
***************
*** 1817,1823 ****
      if (debugging)
        printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev);
  #endif
!     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
      return (-EIO);
    }
  
--- 1874,1881 ----
      if (debugging)
        printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev);
  #endif
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
      return (-EIO);
    }
  
***************
*** 1842,1848 ****
      if (debugging)
        printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev);
  #endif
!     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
      return (-EIO);
    }
  
--- 1900,1907 ----
      if (debugging)
        printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev);
  #endif
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
      return (-EIO);
    }
  
***************
*** 1852,1858 ****
  	   dev, state);
  #endif
  
!   SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
    STp->compression_changed = TRUE;
    return 0;
  }
--- 1911,1918 ----
  	   dev, state);
  #endif
  
!   scsi_release_command(SCpnt);
!   SCpnt = NULL;
    STp->compression_changed = TRUE;
    return 0;
  }
***************
*** 2221,2227 ****
  
     ioctl_result = (STp->buffer)->last_result_fatal;
  
!    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  
     if (!ioctl_result) {  /* SCSI command successful */
       STps->drv_block = blkno;
--- 2281,2288 ----
  
     ioctl_result = (STp->buffer)->last_result_fatal;
  
!    scsi_release_command(SCpnt);
!    SCpnt = NULL;
  
     if (!ioctl_result) {  /* SCSI command successful */
       STps->drv_block = blkno;
***************
*** 2424,2430 ****
  #endif
  
      }
!     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  
      return result;
  }
--- 2485,2492 ----
  #endif
  
      }
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
  
      return result;
  }
***************
*** 2537,2543 ****
  	STps->drv_block = STps->drv_file = 0;
        result = 0;
      }
!     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  
      return result;
  }
--- 2599,2606 ----
  	STps->drv_block = STps->drv_file = 0;
        result = 0;
      }
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
  
      return result;
  }
***************
*** 2605,2611 ****
      SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES);
      if (SCpnt == NULL)
        return (-EBUSY);
!     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  
      if ((STp->buffer)->last_result_fatal != 0) {
  #if DEBUG
--- 2668,2675 ----
      SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES);
      if (SCpnt == NULL)
        return (-EBUSY);
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
  
      if ((STp->buffer)->last_result_fatal != 0) {
  #if DEBUG
***************
*** 2679,2685 ****
      SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout, MAX_READY_RETRIES);
      if (SCpnt == NULL)
        return (-EBUSY);
!     SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
  
      if ((STp->buffer)->last_result_fatal != 0) {
        printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
--- 2743,2750 ----
      SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout, MAX_READY_RETRIES);
      if (SCpnt == NULL)
        return (-EBUSY);
!     scsi_release_command(SCpnt);
!     SCpnt = NULL;
  
      if ((STp->buffer)->last_result_fatal != 0) {
        printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
***************
*** 2716,2721 ****
--- 2781,2797 ----
  #endif
     STm = &(STp->modes[STp->current_mode]);
     STps = &(STp->ps[STp->partition]);
+ 
+     /*
+      * If we are in the middle of error recovery, don't let anyone
+      * else try and use this device.  Also, if error recovery fails, it
+      * may try and take the device offline, in which case all further
+      * access to the device is prohibited.
+      */
+     if( !scsi_block_when_processing_errors(STp->device) )
+       {
+         return -ENXIO;
+       }
  
     cmd_type = _IOC_TYPE(cmd_in);
     cmd_nr   = _IOC_NR(cmd_in);
Index: linux/drivers/scsi/st.h
diff -c linux/drivers/scsi/st.h:1.1.1.2 linux/drivers/scsi/st.h:1.3
*** linux/drivers/scsi/st.h:1.1.1.2	Wed May 28 07:54:11 1997
--- linux/drivers/scsi/st.h	Wed May 28 08:37:33 1997
***************
*** 64,70 ****
    unsigned capacity;
    struct wait_queue * waiting;
    Scsi_Device* device;
!   Scsi_Cmnd SCpnt;
    struct semaphore sem;
    ST_buffer * buffer;
  
--- 64,70 ----
    unsigned capacity;
    struct wait_queue * waiting;
    Scsi_Device* device;
!   /*  Scsi_Cmnd SCpnt; */
    struct semaphore sem;
    ST_buffer * buffer;
  
Index: linux/drivers/scsi/t128.h
diff -c linux/drivers/scsi/t128.h:1.1.1.1 linux/drivers/scsi/t128.h:1.2
*** linux/drivers/scsi/t128.h:1.1.1.1	Sun May 18 19:18:10 1997
--- linux/drivers/scsi/t128.h	Sun May 18 19:27:26 1997
***************
*** 119,131 ****
  
  #if defined(HOSTS_C) || defined(MODULE)
  
! #define TRANTOR_T128 {NULL, NULL, NULL, NULL, \
! 	"Trantor T128/T128F/T228", t128_detect, NULL,  \
! 	NULL,							\
! 	NULL, t128_queue_command, t128_abort, t128_reset, NULL, 	\
! 	t128_biosparam, 						\
! 	/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,			\
! 	/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
  
  #endif
  
--- 119,136 ----
  
  #if defined(HOSTS_C) || defined(MODULE)
  
! #define TRANTOR_T128 {					\
! 	name:           "Trantor T128/T128F/T228",	\
! 	detect:         t128_detect,			\
! 	queuecommand:   t128_queue_command,		\
! 	abort:          t128_abort,			\
! 	reset:          t128_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}
  
  #endif
  
Index: linux/drivers/scsi/u14-34f.h
diff -c linux/drivers/scsi/u14-34f.h:1.1.1.2 linux/drivers/scsi/u14-34f.h:1.3
*** linux/drivers/scsi/u14-34f.h:1.1.1.2	Wed May 28 07:54:21 1997
--- linux/drivers/scsi/u14-34f.h	Wed May 28 08:37:34 1997
***************
*** 13,39 ****
  
  #define U14_34F_VERSION "3.10.00"
  
! #define ULTRASTOR_14_34F {                                            \
! 		NULL, /* Ptr for modules */                           \
! 		NULL, /* usage count for modules */		      \
! 		NULL,		                                      \
! 		NULL,		                                      \
! 		"UltraStor 14F/34F rev. " U14_34F_VERSION " ",        \
! 		u14_34f_detect,                                       \
! 		u14_34f_release,                                      \
! 		NULL,						      \
! 		NULL,                                                 \
! 		u14_34f_queuecommand,                                 \
! 		u14_34f_abort,                                        \
! 		u14_34f_reset,                                        \
! 		NULL,                                                 \
! 		u14_34f_biosparam,                                    \
! 		0,   /* can_queue, reset by detect */                 \
! 		7,   /* this_id, reset by detect */                   \
! 		0,   /* sg_tablesize, reset by detect */              \
! 		0,   /* cmd_per_lun, reset by detect */               \
! 		0,   /* number of boards present */                   \
! 		1,   /* unchecked isa dma, reset by detect */         \
! 		ENABLE_CLUSTERING                                     \
  		}
  #endif
--- 13,28 ----
  
  #define U14_34F_VERSION "3.10.00"
  
! #define ULTRASTOR_14_34F {							   \
! 		name:              "UltraStor 14F/34F rev. " U14_34F_VERSION " ",  \
! 		detect:            u14_34f_detect,                                 \
! 		release:           u14_34f_release,                                \
! 		queuecommand:      u14_34f_queuecommand,                           \
! 		abort:             u14_34f_abort,                                  \
! 		reset:             u14_34f_reset,                                  \
! 		bios_param:        u14_34f_biosparam,                              \
! 		this_id:           7,   /* this_id, reset by detect */             \
! 		unchecked_isa_dma: 1,   /* unchecked isa dma, reset by detect */   \
! 		use_clustering:    ENABLE_CLUSTERING                               \
  		}
  #endif
Index: linux/drivers/scsi/ultrastor.h
diff -c linux/drivers/scsi/ultrastor.h:1.1.1.1 linux/drivers/scsi/ultrastor.h:1.2
*** linux/drivers/scsi/ultrastor.h:1.1.1.1	Sun May 18 19:18:09 1997
--- linux/drivers/scsi/ultrastor.h	Sun May 18 19:27:27 1997
***************
*** 31,56 ****
  #define ULTRASTOR_24F_PORT 0xC80
  
  
! #define ULTRASTOR_14F { NULL, NULL, /* Ptr for modules*/ \
! 			  NULL,                         \
! 			  NULL,                         \
! 			  "UltraStor 14F/24F/34F", 	\
! 			  ultrastor_detect, 		\
! 			  NULL,	/* Release */		\
! 			  ultrastor_info, 		\
! 			  0, 				\
! 			  ultrastor_queuecommand,	\
! 			  ultrastor_abort, 		\
! 			  ultrastor_reset,		\
! 			  0,				\
! 			  ultrastor_biosparam, 		\
! 			  ULTRASTOR_MAX_CMDS,		\
! 			  0, 				\
! 			  ULTRASTOR_14F_MAX_SG, 	\
! 			  ULTRASTOR_MAX_CMDS_PER_LUN, 	\
! 			  0, 				\
! 			  1, 				\
! 			  ENABLE_CLUSTERING }
  
  
  #ifdef ULTRASTOR_PRIVATE
--- 31,49 ----
  #define ULTRASTOR_24F_PORT 0xC80
  
  
! #define ULTRASTOR_14F {   name:              "UltraStor 14F/24F/34F", 	\
! 			  detect:            ultrastor_detect, 		\
! 			  info:              ultrastor_info, 		\
! 			  queuecommand:      ultrastor_queuecommand,	\
! 			  abort:             ultrastor_abort, 		\
! 			  reset:             ultrastor_reset,		\
! 			  bios_param:        ultrastor_biosparam, 	\
! 			  can_queue:         ULTRASTOR_MAX_CMDS,	\
! 			  this_id:           0, 			\
! 			  sg_tablesize:      ULTRASTOR_14F_MAX_SG, 	\
! 			  cmd_per_lun:       ULTRASTOR_MAX_CMDS_PER_LUN,\
! 			  unchecked_isa_dma: 1, 			\
! 			  use_clustering:    ENABLE_CLUSTERING }
  
  
  #ifdef ULTRASTOR_PRIVATE
Index: linux/drivers/scsi/wd7000.h
diff -c linux/drivers/scsi/wd7000.h:1.1.1.1 linux/drivers/scsi/wd7000.h:1.2
*** linux/drivers/scsi/wd7000.h:1.1.1.1	Sun May 18 19:18:09 1997
--- linux/drivers/scsi/wd7000.h	Sun May 18 19:27:27 1997
***************
*** 38,55 ****
  #define WD7000_Q    16
  #define WD7000_SG   16
  
! #define WD7000 { NULL, NULL,            \
! 	NULL,		                \
! 	NULL,		                \
! 	"Western Digital WD-7000",      \
! 	wd7000_detect,                  \
! 	NULL,				\
! 	NULL,				\
! 	wd7000_command,			\
! 	wd7000_queuecommand,		\
! 	wd7000_abort,			\
! 	wd7000_reset,			\
! 	NULL,                           \
! 	wd7000_biosparam,               \
! 	WD7000_Q, 7, WD7000_SG, 1, 0, 1, ENABLE_CLUSTERING}
  #endif
--- 38,55 ----
  #define WD7000_Q    16
  #define WD7000_SG   16
  
! #define WD7000 {					   \
! 	name:              "Western Digital WD-7000",      \
! 	detect:            wd7000_detect,                  \
! 	command:           wd7000_command,		   \
! 	queuecommand:      wd7000_queuecommand,		   \
! 	abort:             wd7000_abort,		   \
! 	reset:             wd7000_reset,		   \
! 	bios_param:        wd7000_biosparam,               \
! 	can_queue:         WD7000_Q,			   \
! 	this_id:           7,				   \
! 	sg_tablesize:      WD7000_SG,			   \
! 	cmd_per_lun:       1,				   \
! 	unchecked_isa_dma: 1,				   \
! 	use_clustering:    ENABLE_CLUSTERING}
  #endif
Index: linux/fs/buffer.c
diff -c linux/fs/buffer.c:1.1.1.4 linux/fs/buffer.c:1.2
*** linux/fs/buffer.c:1.1.1.4	Wed May 28 07:49:00 1997
--- linux/fs/buffer.c	Wed May 28 08:37:35 1997
***************
*** 261,266 ****
--- 261,277 ----
  	sync_inodes(dev);
  	sync_buffers(dev, 0);
  	sync_dquots(dev, -1);
+ 	/* 
+ 	 * FIXME(eric) we need to sync the physical devices here. 
+ 	 * This is because some (scsi) controllers have huge amounts of
+ 	 * cache onboard (hundreds of Mb), and we need to instruct
+ 	 * them to commit all of the dirty memory to disk, and we should
+ 	 * not return until this has happened.
+ 	 *
+ 	 * This would need to get implemented by going through the assorted
+ 	 * layers so that each block major number can be synced, and this
+ 	 * would call down into the upper and mid-layer scsi.
+ 	 */
  }
  
  int fsync_dev(kdev_t dev)
Index: linux/fs/isofs/namei.c
diff -c linux/fs/isofs/namei.c:1.1.1.2 linux/fs/isofs/namei.c:1.3
*** linux/fs/isofs/namei.c:1.1.1.2	Wed May 28 07:49:11 1997
--- linux/fs/isofs/namei.c	Mon May 19 22:39:53 1997
***************
*** 68,73 ****
--- 68,74 ----
  	unsigned int old_offset;
  	unsigned int backlink;
  	int dlen, rrflag, match;
+ 	char *lcname = NULL;
  	char * dpnt;
  	struct iso_directory_record * de;
  	char c;
***************
*** 84,89 ****
--- 85,95 ----
  
  	if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
    
+ 	if(dir->i_sb->u.isofs_sb.s_mapping == 'n')
+ 	{
+ 	    lcname = kmalloc(32+1+32+1+5+1, GFP_KERNEL);
+ 	}
+ 
  	while (f_pos < dir->i_size) {
  		de = (struct iso_directory_record *) (bh->b_data + offset);
  		backlink = dir->i_ino;
***************
*** 158,169 ****
  			break;
  		      }
  		      if (c == ';') c = '.';
! 		      de->name[i] = c;
  		    }
  		    /* This allows us to match with and without a trailing
  		       period.  */
! 		    if(dpnt[dlen-1] == '.' && namelen == dlen-1)
  		      dlen--;
  		  }
  		}
  		/*
--- 164,176 ----
  			break;
  		      }
  		      if (c == ';') c = '.';
! 		      lcname[i] = c;
  		    }
  		    /* This allows us to match with and without a trailing
  		       period.  */
! 		    if(lcname[dlen-1] == '.' && namelen == dlen-1)
  		      dlen--;
+ 		    dpnt = lcname;
  		  }
  		}
  		/*
***************
*** 193,202 ****
--- 200,217 ----
  			}
  			*ino = inode_number;
  			*ino_back = backlink;
+ 			if( lcname != NULL )
+ 			{
+ 			    kfree(lcname);
+ 			}
  			return bh;
  		}
  	}
   out:
+ 	if( lcname != NULL )
+ 	{
+ 	    kfree(lcname);
+ 	}
  	brelse(bh);
  	return NULL;
  }
Index: linux/include/linux/interrupt.h
diff -c linux/include/linux/interrupt.h:1.1.1.1 linux/include/linux/interrupt.h:1.2
*** linux/include/linux/interrupt.h:1.1.1.1	Sun May 18 19:17:13 1997
--- linux/include/linux/interrupt.h	Sun May 18 19:27:34 1997
***************
*** 36,41 ****
--- 36,42 ----
  	RISCOM8_BH,
  	ESP_BH,
  	NET_BH,
+ 	SCSI_BH,
  	IMMEDIATE_BH,
  	KEYBOARD_BH,
  	CYCLADES_BH,
Index: linux/include/linux/timer.h
diff -c linux/include/linux/timer.h:1.1.1.1 linux/include/linux/timer.h:1.2
*** linux/include/linux/timer.h:1.1.1.1	Sun May 18 19:17:11 1997
--- linux/include/linux/timer.h	Sun May 18 19:27:38 1997
***************
*** 23,30 ****
   *
   * FLOPPY_TIMER		floppy disk timer (not used right now)
   * 
-  * SCSI_TIMER		scsi.c timeout timer
-  *
   * NET_TIMER		tcp/ip timeout timer
   *
   * COPRO_TIMER		387 timeout for buggy hardware..
--- 23,28 ----
***************
*** 44,50 ****
  
  #define HD_TIMER	16
  #define FLOPPY_TIMER	17
- #define SCSI_TIMER 	18
  #define NET_TIMER	19
  #define SOUND_TIMER	20
  #define COPRO_TIMER	21
--- 42,47 ----
Index: linux/init/main.c
diff -c linux/init/main.c:1.1.1.4 linux/init/main.c:1.5
*** linux/init/main.c:1.1.1.4	Wed May 28 07:49:38 1997
--- linux/init/main.c	Wed May 28 08:37:40 1997
***************
*** 114,119 ****
--- 114,120 ----
  extern void ppa_setup(char *str, int *ints);
  #endif
  extern void scsi_luns_setup(char *str, int *ints);
+ extern void scsi_logging_setup(char *str, int *ints);
  extern void sound_setup(char *str, int *ints);
  extern void reboot_setup(char *str, int *ints);
  extern void video_setup(char *str, int *ints);
***************
*** 332,337 ****
--- 333,339 ----
  #endif
  #ifdef CONFIG_SCSI
  	{ "max_scsi_luns=", scsi_luns_setup },
+ 	{ "scsi_logging=", scsi_logging_setup },
  #endif
  #ifdef CONFIG_SCSI_ADVANSYS
  	{ "advansys=", advansys_setup },
