diff -u --recursive --new-file v1.1.14/linux/Makefile linux/Makefile
--- v1.1.14/linux/Makefile	Tue May 24 08:47:06 1994
+++ linux/Makefile	Tue May 24 09:45:54 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 14
+SUBLEVEL = 15
 
 all:	Version zImage
 
diff -u --recursive --new-file v1.1.14/linux/config.in linux/config.in
--- v1.1.14/linux/config.in	Tue May 24 08:47:06 1994
+++ linux/config.in	Wed May 25 15:48:07 1994
@@ -50,13 +50,16 @@
 bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
 bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
 bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
+bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
 bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
 bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
+#bool 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 n
 bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n
 bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n
 bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
 bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
 bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
+#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
 fi
 
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog
--- v1.1.14/linux/drivers/scsi/ChangeLog	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/ChangeLog	Tue May 24 09:19:21 1994
@@ -0,0 +1,645 @@
+Sun May 15 20:24:34 1994  Eric Youngdale  (eric@esp22)
+
+	Post-codefreeze thaw...
+
+	* buslogic.[c,h]: New driver from David Gentzel.
+
+	* hosts.h: Add use_clustering field to explicitly say whether
+	clustering should be used for devices attached to this host
+	adapter.  The buslogic board apparently supports large SG lists,
+	but it is apparently faster if sd.c condenses this into a smaller
+	list.
+
+	* sd.c: Use this field instead of heuristic.
+
+	* All host adapter include files: Add appropriate initializer for
+	use_clustering field.
+
+	* scsi.h: Add #defines for return codes for the abort and reset
+	functions.  There are now a specific set of return codes to fully
+	specify all of the possible things that the low-level adapter
+	could do.
+
+	* scsi.c: Act based upon return codes from abort/reset functions.
+
+	* All host adapter abort/reset functions: Return new return code.
+
+	* Add code in scsi.c to help debug timeouts.  Use #define
+	DEBUG_TIMEOUT to enable this.
+
+	* scsi.c: If the host->irq field is set, use
+	disable_irq/enable_irq before calling queuecommand if we
+	are not already in an interrupt.  Reduce races, and we
+	can be sloppier about cli/sti in the interrupt routines now
+	(reduce interrupt latency).
+
+	* constants.c: Fix some things to eliminate warnings.  Add some
+	sense descriptions that were omitted before.
+
+	* aha1542.c: Watch for SCRD from host adapter - if we see it, set
+	a flag.  Currently we only print out the number of pending
+	commands that might need to be restarted.
+
+	* aha1542.c (aha1542_abort): Look for lost interrupts, OGMB still
+	full, and attempt to recover.  Otherwise give up.
+
+	* aha1542.c (aha1542_reset): Try BUS DEVICE RESET, and then pass
+	DID_RESET back up to the upper level code for all commands running
+	on this target (even on different LUNs).
+
+Sat May  7 14:54:01 1994
+
+	* Linux 1.1.12 released.
+
+	* st.c, st.h: New version from Kai.  Supports boot time
+	specification of number of buffers.
+
+	* wd7000.[c,h]: Updated driver from John Boyd.  Now supports
+	more than one wd7000 board in machine at one time, among other things.
+
+Wed Apr 20 22:20:35 1994
+
+	* Linux 1.1.8 released.
+
+	* sd.c: Add a few type casts where scsi_malloc is called.
+
+Wed Apr 13 12:53:29 1994
+
+	* Linux 1.1.4 released.
+
+	* scsi.c: Clean up a few printks (use %p to print pointers).
+
+Wed Apr 13 11:33:02 1994
+
+	* Linux 1.1.3 released.
+
+	* fdomain.c: Update to version 5.16 (Handle different FIFO sizes
+	better).  
+
+Fri Apr  8 08:57:19 1994
+
+	* Linux 1.1.2 released.
+
+	* Throughout: SCSI portion of cluster diffs added.
+
+Tue Apr  5 07:41:50 1994
+
+	* Linux 1.1 development tree initiated.
+
+	* The linux 1.0 development tree is now effectively frozen except
+	for obvious bugfixes.
+
+******************************************************************
+******************************************************************
+******************************************************************
+******************************************************************
+
+Sun Apr 17 00:17:39 1994
+
+	* Linux 1.0, patchlevel 9 released.
+
+	* fdomain.c: Update to version 5.16 (Handle different FIFO sizes
+	better).  
+
+Thu Apr  7 08:36:20 1994
+
+	* Linux 1.0, patchlevel8 released.
+
+	* fdomain.c: Update to version 5.15 from 5.9.  Handles 3.4 bios.
+
+Sun Apr  3 14:43:03 1994
+
+	* Linux 1.0, patchlevel6 released.
+
+	* wd7000.c: Make stab at fixing race condition.
+
+Sat Mar 26 14:14:50 1994
+
+	* Linux 1.0, patchlevel5 released.
+
+	* aha152x.c, Makefile: Fix a few bugs (too much data message).
+	Add a few more bios signatures. (Patches from Juergen).
+
+	* aha1542.c: Fix race condition in aha1542_out.
+
+Mon Mar 21 16:36:20 1994
+
+	* Linux 1.0, patchlevel3 released.
+
+	* sd.c, st.c, sr.c, sg.c: Return -ENXIO, not -ENODEV if we attempt
+	to open a non-existant device.
+
+	* scsi.c: Add Chinon cdrom to blacklist.
+
+	* sr_ioctl.c: Check return status of verify_area.
+
+Sat Mar  6 16:06:19 1994
+
+	* Linux 1.0 released (technically a pre-release).
+
+	* scsi.c: Add IMS CDD521, Maxtor XT-8760S to blacklist.
+
+Tue Feb 15 10:58:20 1994
+
+        * pl15e released.
+
+        * aha1542.c: For 1542C, allow dynamic device scan with >1Gb turned
+	off.
+
+	* constants.c: Fix typo in definition of CONSTANTS.
+
+        * pl15d released.
+
+Fri Feb 11 10:10:16 1994
+
+        * pl15c released.
+
+	* scsi.c: Add Maxtor XT-3280 and Rodime RO3000S to blacklist.
+
+	* scsi.c: Allow tagged queueing for scsi 3 devices as well.
+	Some really old devices report a version number of 0.  Disallow
+	LUN != 0 for these.
+
+Thu Feb 10 09:48:57 1994
+
+        * pl15b released.
+
+Sun Feb  6 12:19:46 1994
+
+        * pl15a released.
+
+Fri Feb  4 09:02:17 1994
+
+        * scsi.c: Add Teac cdrom to blacklist.
+
+Thu Feb  3 14:16:43 1994
+
+	* pl15 released.
+
+Tue Feb  1 15:47:43 1994
+
+	* pl14w released.
+
+	* wd7000.c (wd_bases): Fix typo in last change.
+
+Mon Jan 24 17:37:23 1994  
+
+	* pl14u released.
+
+	* aha1542.c: Support 1542CF/extended bios.  Different from 1542C
+
+	* wd7000.c: Allow bios at 0xd8000 as well.
+
+	* ultrastor.c: Do not truncate cylinders to 1024.
+
+	* fdomain.c: Update to version 5.9 (add new bios signature).
+
+	* NCR5380.c: Update from Drew - should work a lot better now.
+
+Sat Jan  8 15:13:10 1994  
+
+	* pl14o released.
+
+	* sr_ioctl.c: Zero reserved field before trying to set audio volume.
+
+Wed Jan  5 13:21:10 1994  
+
+	* pl14m released.
+
+	* fdomain.c: Update to version 5.8.  No functional difference???
+
+Tue Jan  4 14:26:13 1994  
+
+	* pl14l released.
+
+	* ultrastor.c: Remove outl, inl functions (now provided elsewhere).
+
+Mon Jan  3 12:27:25 1994  
+
+	* pl14k released.
+
+	* aha152x.c: Remove insw and outsw functions.
+
+	* fdomain.c: Ditto.
+
+Wed Dec 29 09:47:20 1993  
+
+	* pl14i released.
+
+	* scsi.c: Support RECOVERED_ERROR for tape drives.
+
+	* st.c: Update of tape driver from Kai.
+
+Tue Dec 21 09:18:30 1993  
+
+	* pl14g released.
+
+	* aha1542.[c,h]: Support extended BIOS stuff.
+
+	* scsi.c: Clean up messages about disks, so they are displayed as
+	sda, sdb, etc instead of sd0, sd1, etc.
+
+	* sr.c:  Force reread of capacity if disk was changed.
+	Clear buffer before asking for capacity/sectorsize (some drives
+	do not report this properly).  Set needs_sector_size flag if
+	drive did not return sensible sector size.
+
+Mon Dec 13 12:13:47 1993  
+
+	* aha152x.c: Update to version .101 from Juergen.
+
+Mon Nov 29 03:03:00 1993  
+
+        * linux 0.99.14 released.
+
+	* All scsi stuff moved from kernel/blk_drv/scsi to drivers/scsi.
+
+	* Throughout: Grammatical corrections to various comments.
+
+	* Makefile: fix so that we do not need to compile things we are
+	not going to use.
+
+	* NCR5380.c, NCR5380.h, g_NCR5380.c, g_NCR5380.h, pas16.c,
+	pas16.h, t128.c, t128.h:  New files from Drew.
+
+	* aha152x.c, aha152x.h: New files from Juergen Fischer.
+
+	* aha1542.c: Support for more than one 1542 in the machine
+	at the same time.  Make functions static that do not need
+	visibility.
+
+	* aha1740.c: Set NEEDS_JUMPSTART flag in reset function, so we
+	know to restart the command.  Change prototype of aha1740_reset
+	to take a command pointer.
+
+	* constants.c: Clean up a few things.
+
+	* fdomain.c: Update to version 5.6.  Move snarf_region.  Allow
+	board to be set at different SCSI ids.  Remove support for
+	reselection (did not work well).  Set JUMPSTART flag in reset
+	code.
+
+	* hosts.c: Support new low-level adapters.  Allow for more than
+	one adapter of a given type.
+
+	* hosts.h: Allow for more than one adapter of a given type. 
+
+	* scsi.c:  Add scsi_device_types array, if NEEDS_JUMPSTART is set
+	after a low-level reset, start the command again.  Sort blacklist,
+	and add Maxtor MXT-1240S, XT-4170S, NEC CDROM 84, Seagate ST157N.
+
+	* scsi.h: Add constants for tagged queueing.
+
+	* Throughout: Use constants from major.h instead of hardcoded
+	numbers for major numbers.
+
+	* scsi_ioctl.c: Fix bug in buffer length in ioctl_command.  Use
+	verify_area in GET_IDLUN ioctl.  Add new ioctls for
+	TAGGED_QUEUE_ENABLE, DISABLE.  Only allow IOCTL_SEND_COMMAND by
+	superuser.
+
+	* sd.c: Only pay attention to UNIT_ATTENTION for removable disks.
+	Fix bug where sometimes portions of blocks would get lost
+	resulting in processes hanging.  Add messages when we spin up a
+	disk, and fix a bug in the timing.  Increase read-ahead for disks
+	that are on a scatter-gather capable host adapter.
+
+	* seagate.c: Fix so that some parameters can be set from the lilo
+	prompt.  Supply jumpstart flag if we are resetting and need the
+	command restarted.   Fix so that we return 1 if we detect a card
+	so that multiple card detection works correctly.  Add yet another
+	signature for FD cards (950).  Add another signature for ST0x.
+
+	* sg.c, sg.h: New files from Lawrence Foard for generic scsi
+	access.
+
+	* sr.c:  Add type casts for (void*) so that we can do pointer
+	arithmetic.  Works with GCC without this, but it is not strictly
+	correct.  Same bugfix as was in sd.c.  Increase read-ahead a la
+	disk driver.
+
+	* sr_ioctl.c: Use scsi_malloc buffer instead of buffer from stack
+	since we cannot guarantee that the stack is < 16Mb.
+
+	ultrastor.c: Update to support 24f properly (JFC's driver).
+
+	wd7000.c: Supply jumpstart flag for reset.  Do not round up
+	number of cylinders in biosparam function.
+
+Sat Sep  4 20:49:56 1993  
+
+    * 0.99pl13 released.
+
+    * Throughout:  Use check_region/snarf_region for all low-level
+    drivers.
+
+    * aha1542.c: Do hard reset instead of soft (some ethercard probes
+    screw us up).
+
+    * scsi.c: Add new flag ASKED_FOR_SENSE so that we can tell if we are
+    in a loop whereby the device returns null sense data.
+
+    * sd.c: Add code to spin up a drive if it is not already spinning.
+    Do this one at a time to make it easier on power supplies.
+
+    * sd_ioctl.c: Use sync_dev instead of fsync_dev in BLKFLSBUF ioctl.
+
+    * seagate.c: Switch around DATA/CONTROL lines.
+
+    * st.c: Change sense to unsigned.
+
+Thu Aug  5 11:59:18 1993  
+
+    * 0.99pl12 released.
+
+    * constants.c, constants.h: New files with ascii descriptions of
+    various conditions.
+
+    * Makefile: Do not try and count the number of low-level drivers,
+    just generate the list of .o files.
+
+    * aha1542.c: Replace 16 with sizeof(SCpnt->sense_buffer).  Add tests
+    for addresses > 16Mb, panic if we find one.
+
+    * aha1740.c: Ditto with sizeof().
+
+    * fdomain.c: Update to version 3.18.  Add new signature, register IRQ
+    with irqaction.  Use ID 7 for new board.  Be more intelligent about
+    obtaining the h/s/c numbers for biosparam.
+
+    * hosts.c: Do not depend upon Makefile generated count of the number
+    of low-level host adapters.
+
+    * scsi.c: Use array for scsi_command_size instead of a function.  Add
+    Texel cdrom and Maxtor XT-4380S to blacklist.  Allow compile time
+    option for no-multi lun scan.  Add semaphore for possible problems
+    with handshaking, assume device is faulty until we know it not to be
+    the case.  Add DEBUG_INIT symbol to dump info as we scan for devices.
+    Zero sense buffer so we can tell if we need to request it.  When
+    examining sense information, request sense if buffer is all zero.
+    If RESET, request sense information to see what to do next.
+
+    * scsi_debug.c: Change some constants to use symbols like INT_MAX.
+
+    * scsi_ioctl.c (kernel_scsi_ioctl): New function -for making ioctl
+    calls from kernel space.
+
+    * sd.c: Increase timeout to 300.  Use functions in constants.h to
+    display info.  Use scsi_malloc buffer for READ_CAPACITY, since
+    we cannot guarantee that a stack based buffer is < 16Mb.
+
+    * sd_ioctl.c: Add BLKFLSBUF ioctl.
+
+    * seagate.c: Add new compile time options for ARBITRATE,
+    SLOW_HANDSHAKE, and SLOW_RATE.  Update assembly loops for transferring
+    data.  Use kernel_scsi_ioctl to request mode page with geometry.
+
+    * sr.c: Use functions in constants.c to display messages.
+
+    * st.c: Support for variable block size.
+
+    * ultrastor.c: Do not use cache for tape drives.  Set
+    unchecked_isa_dma flag, even though this may not be needed (gets set
+    later).
+
+Sat Jul 17 18:32:44 1993  
+
+    * 0.99pl11 released.  C++ compilable.
+
+    * Throughout: Add type casts all over the place, and use "ip" instead
+    of "info" in the various biosparam functions.
+
+    * Makefile: Compile seagate.c with C++ compiler.
+
+    * aha1542.c: Always set ccb pointer as this gets trashed somehow on
+    some systems.  Add a few type casts.  Update biosparam function a little.
+
+    * aha1740.c: Add a few type casts.
+
+    * fdomain.c: Update to version 3.17 from 3.6.  Now works with
+    TMC-18C50.
+
+    * scsi.c: Minor changes here and there with datatypes.  Save use_sg
+    when requesting sense information so that this can properly be
+    restored if we retry the command.  Set aside dma buffers assuming each
+    block is 1 page, not 1Kb minix block.
+
+    * scsi_ioctl.c: Add a few type casts.  Other minor changes.
+
+    * sd.c:  Correctly  free all scsi_malloc'd memory if we run out of
+    dma_pool. Store blocksize information for each partition.
+
+    * seagate.c: Minor cleanups here and there.
+
+    * sr.c: Set up blocksize array for all discs.  Fix bug in freeing
+    buffers if we run out of dma pool.
+
+Thu Jun  2 17:58:11 1993  
+
+    * 0.99pl10 released.
+
+    * aha1542.c: Support for BT 445S (VL-bus board with no dma channel).
+
+    * fdomain.c: Upgrade to version 3.6. Preliminary support for TNC-18C50.
+
+    * scsi.c: First attempt to fix problem with old_use_sg.  Change
+    NOT_READY to a SUGGEST_ABORT.  Fix timeout race where time might
+    get decremented past zero.
+
+    * sd.c: Add block_fsync function to dispatch table.
+
+    * sr.c: Increase timeout to 500 from 250.  Add entry for sync in
+    dispatch table (supply NULL).  If we do not have a sectorsize,
+    try and get it in the sd_open function.  Add new function just to
+    obtain sectorsize.
+
+    * sr.h: Add needs_sector_size semaphore.
+
+    * st.c: Add NULL for fsync in dispatch table.
+
+    * wd7000.c: Allow another condition for power on that are normal
+    and do not require a panic.
+
+Thu Apr 22 23:10:11 1993  
+
+    * 0.99pl9 released.
+
+    * aha1542.c: Use (void) instead of () in setup_mailboxes.
+
+    * scsi.c: Initialize transfersize and underflow fields in SCmd to 0.
+    Do not panic for unsupported message bytes.
+
+    * scsi.h: Allocate 12 bytes instead of 10 for commands.  Add
+    transfersize and underflow fields.
+
+    * scsi_ioctl.c: Further bugfix to ioctl_probe.
+
+    * sd.c: Use long instead of int for last parameter in sd_ioctl.
+    Initialize transfersize and underflow fields.    
+
+    * sd_ioctl.c: Ditto for sd_ioctl(,,,,);
+
+    * seagate.c: New version from Drew.  Includes new signatures for FD
+    cards.  Support for 0ws jumper. Correctly initialize
+    scsi_hosts[hostnum].this_id.  Improved handing of
+    disconnect/reconnect, and support command linking.  Use
+    transfersize and underflow fields.  Support scatter-gather.
+
+    * sr.c, sr_ioctl.c: Use long instead of int for last parameter in sr_ioctl.
+    Use buffer and buflength in do_ioctl.  Patches from Chris Newbold for
+    scsi-2 audio commands.
+
+    * ultrastor.c: Comment out in_byte (compiler warning).
+
+    * wd7000.c: Change () to (void) in wd7000_enable_dma.
+
+Wed Mar 31 16:36:25 1993  
+
+    * 0.99pl8 released.
+
+    * aha1542.c: Handle mailboxes better for 1542C.
+        Do not truncate number of cylinders at 1024 for biosparam call.
+
+    * aha1740.c: Fix a few minor bugs for multiple devices.
+        Same as above for biosparam.
+
+    * scsi.c: Add lockable semaphore for removable devices that can have
+    media removal prevented.  Add another signature for flopticals.
+    (allocate_device): Fix race condition.  Allow more space in dma pool
+    for blocksizes of up to 4Kb.
+
+    * scsi.h: Define COMMAND_SIZE.  Define a SCSI specific version of
+    INIT_REQUEST that can run with interrupts off.
+
+    * scsi_ioctl.c: Make ioctl_probe function more idiot-proof.  If
+    a removable device says ILLEGAL REQUEST to a door-locking command,
+    clear lockable flag.  Add SCSI_IOCTL_GET_IDLUN ioctl.  Do not attempt
+    to lock door for devices that do not have lockable semaphore set.
+
+    * sd.c: Fix race condition for multiple disks.  Use INIT_SCSI_REQUEST
+    instead of INIT_REQUEST.  Allow sector sizes of 1024 and 256.  For
+    removable disks that are not ready, mark them as having a media change
+    (some drives do not report this later).
+
+    * seagate.c: Use volatile keyword for memory-mapped register pointers.
+
+    * sr.c: Fix race condition, a la sd.c.  Increase the number of retries
+    to 1.  Use INIT_SCSI_REQUEST.  Allow 512 byte sector sizes.  Do a
+    read_capacity when we init the device so we know the size and
+    sectorsize.
+
+    * st.c: If ioctl not found in st.c, try scsi_ioctl for others.
+
+    * ultrastor.c: Do not truncate number of cylinders at 1024 for
+    biosparam call.
+
+    * wd7000.c: Ditto.
+    Throughout: Use COMMAND_SIZE macro to determine length of scsi
+    command.
+
+
+
+Sat Mar 13 17:31:29 1993  
+
+    * 0.99pl7 released.
+
+    Throughout: Improve punctuation in some messages, and use new
+    verify_area syntax.
+
+    * aha1542.c: Handle unexpected interrupts better.
+
+    * scsi.c: Ditto.  Handle reset conditions a bit better, asking for
+    sense information and retrying if required.
+
+    * scsi_ioctl.c: Allow for 12 byte scsi commands.
+
+    * ultrastor.c: Update to use scatter-gather.
+
+Sat Feb 20 17:57:15 1993  
+
+    * 0.99pl6 released.
+
+    * fdomain.c: Update to version 3.5.  Handle spurious interrupts
+    better.
+
+    * sd.c: Use register_blkdev function.
+
+    * sr.c: Ditto.
+
+    * st.c: Use register_chrdev function.
+
+    * wd7000.c: Undo previous change.
+
+Sat Feb  6 11:20:43 1993  
+
+    * 0.99pl5 released.
+
+    * scsi.c: Fix bug in testing for UNIT_ATTENTION.
+
+    * wd7000.c: Check at more addresses for bios.  Fix bug in biosparam
+    (heads & sectors turned around).
+
+Wed Jan 20 18:13:59 1993  
+
+    * 0.99pl4 released.
+
+    * scsi.c: Ignore leading spaces when looking for blacklisted devices.
+
+    * seagate.c: Add a few new signatures for FD cards.  Another patch
+    with SCint to fix race condition.  Use recursion_depth to keep track
+    of how many times we have been recursively called, and do not start
+    another command unless we are on the outer level.  Fixes bug
+    with Syquest cartridge drives (used to crash kernel), because
+    they do not disconnect with large data transfers.
+
+Tue Jan 12 14:33:36 1993  
+
+    * 0.99pl3 released.
+
+    * fdomain.c: Update to version 3.3 (a few new signatures).
+
+    * scsi.c: Add CDU-541, Denon DRD-25X to blacklist.
+    (allocate_request, request_queueable): Init request.waiting to NULL if
+    non-buffer type of request.
+
+    * seagate.c:  Allow controller to be overridden with CONTROLLER symbol.
+    Set SCint=NULL when we are done, to remove race condition.
+
+    * st.c: Changes from Kai.
+
+Wed Dec 30 20:03:47 1992  
+
+    * 0.99pl2 released.
+
+    * scsi.c: Blacklist back in.  Remove Newbury drive as other bugfix
+    eliminates need for it here.
+
+    * sd.c: Return ENODEV instead of EACCES if no such device available.
+    (sd_init) Init blkdev_fops earlier so that sd_open is available sooner.
+
+    * sr.c: Same as above for sd.c.
+
+    * st.c: Return ENODEV instead of ENXIO if no device.  Init chrdev_fops
+    sooner, so that it is always there even if no tapes.
+
+    * seagate.c (controller_type): New variable to keep track of ST0x or
+    FD.  Modify signatures list to indicate controller type, and init
+    controller_type once we find a match.
+
+    * wd7000.c (wd7000_set_sync): Remove redundant function.
+
+Sun Dec 20 16:26:24 1992  
+
+    * 0.99pl1 released.
+
+    * scsi_ioctl.c: Bugfix - check dev->index, not dev->id against
+    NR_SCSI_DEVICES.
+
+    * sr_ioctl.c: Verify that device exists before allowing an ioctl.
+
+    * st.c: Patches from Kai - change timeout values, improve end of tape
+    handling.
+
+Sun Dec 13 18:15:23 1992  
+
+    * 0.99 kernel released.  Baseline for this ChangeLog.
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.1.14/linux/drivers/scsi/Makefile	Sat Mar 26 15:08:15 1994
+++ linux/drivers/scsi/Makefile	Tue May 24 09:19:22 1994
@@ -11,6 +11,14 @@
 
 AHA152X	= -DDEBUG_AHA152X -DAUTOCONF
 
+ifeq (${CFLAGS},)
+CFLAGS = -D__KERNEL__=1 \
+	-Wall -Wstrict-prototypes -I. -I../../include \
+	-O2 -fomit-frame-pointer -m486
+
+include ../../.config
+endif
+
 SCSI_OBJS =
 SCSI_SRCS =
 
@@ -54,6 +62,11 @@
 SCSI_SRCS := $(SCSI_SRCS) aha1740.c
 endif
 
+ifdef CONFIG_SCSI_BUSLOGIC
+SCSI_OBJS := $(SCSI_OBJS) buslogic.o
+SCSI_SRCS := $(SCSI_SRCS) buslogic.c
+endif
+
 ifdef CONFIG_SCSI_DEBUG
 SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o
 SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
@@ -62,6 +75,11 @@
 ifdef CONFIG_SCSI_FUTURE_DOMAIN
 SCSI_OBJS := $(SCSI_OBJS) fdomain.o
 SCSI_SRCS := $(SCSI_SRCS) fdomain.c
+endif
+
+ifdef CONFIG_SCSI_IN2000
+SCSI_OBJS := $(SCSI_OBJS) in2000.o
+SCSI_SRCS := $(SCSI_SRCS) in2000.c
 endif
 
 ifdef CONFIG_SCSI_GENERIC_NCR5380
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v1.1.14/linux/drivers/scsi/NCR5380.c	Mon Jan 24 14:19:19 1994
+++ linux/drivers/scsi/NCR5380.c	Tue May 24 09:19:22 1994
@@ -2266,7 +2266,7 @@
 #endif /* def REAL_DMA */
 
 /*
- * Function : int NCR5380_abort (Scsi_Cmnd *cmd, int code)
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
  *
  * Purpose : abort a command
  *
@@ -2285,7 +2285,7 @@
 #ifndef NCR5380_abort
 static
 #endif
-int NCR5380_abort (Scsi_Cmnd *cmd, int code) {
+int NCR5380_abort (Scsi_Cmnd *cmd) {
     NCR5380_local_declare();
     struct Scsi_Host *instance = cmd->host;
     struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
@@ -2313,14 +2313,14 @@
 	if (cmd == tmp) {
 	    (*prev) = (Scsi_Cmnd *) tmp->host_scribble;
 	    tmp->host_scribble = NULL;
-	    tmp->result = (code ? code : DID_ABORT) << 16;
+	    tmp->result = DID_ABORT << 16;
 	    sti();
 #if (NDEBUG & NDEBUG_ABORT)
     printk("scsi%d : abort removed command from issue queue.\n", 
 	instance->host_no);
 #endif
 	    tmp->done(tmp);
-	    return 0;
+	    return SCSI_ABORT_SUCCESS;
 	}
 
 /* 
@@ -2339,7 +2339,7 @@
 #if (NDEBUG & NDEBUG_ABORT)
     printk("scsi%d : abort failed, command connected.\n", instance->host_no);
 #endif
-        return -1;
+        return SCSI_ABORT_NOT_RUNNING;
     }
 
 /*
@@ -2376,7 +2376,7 @@
 #endif
   
             if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
-		return 1;
+		return SCSI_ABORT_BUSY;
 
 #if (NDEBUG & NDEBUG_ABORT)
     printk("scsi%d : nexus restablished.\n", instance->host_no);
@@ -2397,10 +2397,10 @@
 		    if (cmd == tmp) {
 		    *prev = (Scsi_Cmnd *) tmp->host_scribble;
 		    tmp->host_scribble = NULL;
-		    tmp->result = (code ? code : DID_ABORT) << 16;
+		    tmp->result = DID_ABORT << 16;
 		    sti();
 		    tmp->done(tmp);
-		    return 0;
+		    return SCSI_ABORT_SUCCESS;
 		}
 	}
 
@@ -2417,7 +2417,7 @@
     sti();
     printk("scsi%d : warning : SCSI command probably completed successfully\n"
            "         before abortion\n", instance->host_no); 
-    return 0;
+    return SCSI_ABORT_NOT_RUNNING;
 }
 
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/NCR5380.h linux/drivers/scsi/NCR5380.h
--- v1.1.14/linux/drivers/scsi/NCR5380.h	Mon Jan 24 14:19:57 1994
+++ linux/drivers/scsi/NCR5380.h	Tue May 24 09:19:18 1994
@@ -249,7 +249,7 @@
 #ifndef NCR5380_abort
 static
 #endif
-int NCR5380_abort (Scsi_Cmnd *cmd, int code);
+int NCR5380_abort (Scsi_Cmnd *cmd);
 #ifndef NCR5380_reset
 static
 #endif
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v1.1.14/linux/drivers/scsi/aha152x.c	Sat Mar 26 15:08:16 1994
+++ linux/drivers/scsi/aha152x.c	Tue May 24 09:19:18 1994
@@ -155,7 +155,7 @@
 
  Drew Eckhardt (drew@cs.colorado.edu)
 
- Eric Youngdale (eric@tantalus.nrl.navy.mil) 
+ Eric Youngdale (ericy@cais.com) 
 
  special thanks to Eric Youngdale for the free(!) supplying the
  documentation on the chip.
@@ -781,7 +781,7 @@
  *  Abort a queued command
  *  (commands that are on the bus can't be aborted easily)
  */
-int aha152x_abort( Scsi_Cmnd *SCpnt, int code )
+int aha152x_abort( Scsi_Cmnd *SCpnt)
 {
   Scsi_Cmnd *ptr, *prev;
 
@@ -809,16 +809,16 @@
       sti();
 
       ptr->host_scribble = NULL;
-      ptr->result = (code ? code : DID_ABORT ) << 16;
+      ptr->result = DID_ABORT << 16;
       ptr->done(ptr);
-      return 0;
+      return SCSI_ABORT_SUCCESS;
     }
 
   /* Fail abortion, if we're on the bus */
   if (current_SC)
     {
        sti();
-       return -1;
+       return SCSI_ABORT_BUSY;
     }
 
   /* look for command in disconnected queue */
@@ -852,7 +852,7 @@
       SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
 
       SETBITS( DMACNTRL0, INTEN );
-      abort_result=0;
+      abort_result=SCSI_ABORT_SUCCESS;
       sti();
 
       /* sleep until the abortion is complete */
@@ -864,7 +864,7 @@
 
   /* command wasn't found */
   sti();
-  return 0;
+  return SCSI_ABORT_NOT_RUNNING;
 }
 
 /*
@@ -922,6 +922,10 @@
 
        show_queues();
 
+       /* FIXME - if the device implements soft resets, the command will still
+	  be running after the bus reset. In this case we should do nothing
+	  and let the command continue. -ERY */
+
        if(current_SC)
          {
            current_SC->host_scribble = NULL;
@@ -951,7 +955,7 @@
        SETPORT( DMACNTRL0, INTEN );
     }
 
-  return 0;
+  return SCSI_RESET_SUCCESS;
 }
 
 /*
@@ -1246,7 +1250,7 @@
 
                 if(current_SC->SCp.phase & aborted)
                   {
-                    abort_result=1;
+                    abort_result=SCSI_ABORT_ERROR;
                     wake_up( &abortion_complete );
                   }
 
@@ -1304,7 +1308,7 @@
 #if defined(DEBUG_ABORT)
               printk("(ABORT) selection timeout, ");
 #endif
-              abort_result=1;
+              abort_result=SCSI_ABORT_ERROR;
               wake_up( &abortion_complete );
             }
 
@@ -1390,7 +1394,7 @@
         if(message==ABORT)
           {
             /* revive abort(); abort() enables interrupts */
-            abort_result=0;
+            abort_result=SCSI_ABORT_SUCCESS;
             wake_up( &abortion_complete );
 
             current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h
--- v1.1.14/linux/drivers/scsi/aha152x.h	Sat Mar 26 15:08:16 1994
+++ linux/drivers/scsi/aha152x.h	Tue May 24 09:19:18 1994
@@ -14,7 +14,7 @@
 const char *aha152x_info(void);
 int        aha152x_command(Scsi_Cmnd *);
 int        aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int        aha152x_abort(Scsi_Cmnd *, int);
+int        aha152x_abort(Scsi_Cmnd *);
 int        aha152x_reset(Scsi_Cmnd *);
 int        aha152x_biosparam(int, int, int*);
 
@@ -39,7 +39,8 @@
                         /* sg_tablesize */	SG_ALL,                     \
                         /* cmd_per_lun */	1,                          \
                         /* present */		0,                          \
-                        /* unchecked_isa_dma */	0 }
+                        /* unchecked_isa_dma */	0,			    \
+			/* use_clustering */	DISABLE_CLUSTERING }
 #endif
 
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v1.1.14/linux/drivers/scsi/aha1542.c	Sat May  7 14:54:03 1994
+++ linux/drivers/scsi/aha1542.c	Tue May 24 09:19:19 1994
@@ -2,6 +2,7 @@
  *  linux/kernel/aha1542.c
  *
  *  Copyright (C) 1992  Tommy Thorn
+ *  Copyright (C) 1993, 1994 Eric Youngdale
  *
  *  Modified by Eric Youngdale
  *        Use request_irq and request_dma to help prevent unexpected conflicts
@@ -75,6 +76,7 @@
 #define WAITnexttimeout 3000000
 
 static void setup_mailboxes(int base_io, struct Scsi_Host * shpnt);
+static int aha1542_restart(struct Scsi_Host * shost);
 
 #define aha1542_intr_reset(base)  outb(IRST, CONTROL(base))
 
@@ -215,7 +217,9 @@
     /* Reset the adapter. I ought to make a hard reset, but it's not really nessesary */
     
     /*  DEB(printk("aha1542_test_port called \n")); */
-    
+
+    /* In case some other card was probing here, reset interrupts */
+    aha1542_intr_reset(bse);     /* reset interrupts, so they don't block */	
     outb(SRST|IRST/*|SCRST*/, CONTROL(bse));
 
     i = jiffies + 2;
@@ -259,7 +263,7 @@
     outb(IRST, CONTROL(bse));
     
     debug = 11;
-    
+
     return debug;				/* 1 = ok */
   fail:
     return 0;					/* 0 = not ok */
@@ -281,7 +285,8 @@
     int number_serviced;
     struct Scsi_Host * shost;
     Scsi_Cmnd * SCtmp;
-    int irqno, * irqp;
+    int irqno, * irqp, flag;
+    int needs_restart;
     struct mailbox * mb;
     struct ccb  *ccb;
 
@@ -297,7 +302,7 @@
 
 #ifdef DEBUG
     {
-    int flag = inb(INTRFLAGS(shost->io_port));
+    flag = inb(INTRFLAGS(shost->io_port));
     printk("aha1542_intr_handle: ");
     if (!(flag&ANYINTR)) printk("no interrupt?");
     if (flag&MBIF) printk("MBIF ");
@@ -308,8 +313,24 @@
   };
 #endif
     number_serviced = 0;
+    needs_restart = 0;
 
     while(1==1){
+      flag = inb(INTRFLAGS(shost->io_port));
+
+      /* Check for unusual interrupts.  If any of these happen, we should
+	 probably do something special, but for now just printing a message
+	 is sufficient.  A SCSI reset detected is something that we really
+	 need to deal with in some way. */
+      if (flag & ~MBIF) {
+	if (flag&MBOA) printk("MBOF ");
+	if (flag&HACC) printk("HACC ");
+	if (flag&SCRD) {
+	  needs_restart = 1;
+	  printk("SCRD ");
+	}
+      }
+
       aha1542_intr_reset(shost->io_port);
 
       cli();
@@ -325,8 +346,11 @@
       if(mb[mbi].status == 0){
 	sti();
 	/* Hmm, no mail.  Must have read it the last time around */
-	if (number_serviced) return;
-	printk("aha1542.c: interrupt received, but no mail.\n");
+	if (!number_serviced && !needs_restart)
+	  printk("aha1542.c: interrupt received, but no mail.\n");
+	/* We detected a reset.  Restart all pending commands for
+	   devices that use the hard reset option */
+	if(needs_restart) aha1542_restart(shost);
 	return;
       };
 
@@ -354,6 +378,8 @@
 
       if (!SCtmp || !SCtmp->scsi_done) {
 	printk("aha1542_intr_handle: Unexpected interrupt\n");
+	printk("tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat, 
+	       ccb[mbo].hastat, ccb[mbo].idlun, mbo);
 	return;
       }
       
@@ -883,39 +909,156 @@
     return count;
 }
 
+static int aha1542_restart(struct Scsi_Host * shost)
+{
+  int i;
+  int count = 0;
+#if 0
+  unchar ahacmd = CMD_START_SCSI;
+#endif
+
+  for(i=0; i< AHA1542_MAILBOXES; i++)
+   if(HOSTDATA(shost)->SCint[i] && 
+      !(HOSTDATA(shost)->SCint[i]->device->soft_reset))
+     {
+#if 0
+	HOSTDATA(shost)->mb[i].status = 1; /* Indicate ready to restart... */
+#endif
+	count++;
+     }     
+
+  printk("Potential to restart %d stalled commands...\n", count);
+#if 0
+  /* start scsi command */
+  if (count) aha1542_out(shost->io_port, &ahacmd, 1);
+#endif
+  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, int i)
+int aha1542_abort(Scsi_Cmnd * SCpnt)
 {
 #if 0
-    unchar ahacmd = CMD_START_SCSI;
-    int mbo;
+  int intval[3];
+  unchar ahacmd = CMD_START_SCSI;
+  struct mailbox * mb;
+  int mbi, mbo, i;
+
+  printk("In aha1542_abort: %x %x\n",
+	 inb(STATUS(SCpnt->host->io_port)),
+	 inb(INTRFLAGS(SCpnt->host->io_port)));
+
+  cli();
+  mb = HOSTDATA(SCpnt->host)->mb;
+  mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1;
+  if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
+  
+  do{
+    if(mb[mbi].status != 0) break;
+    mbi++;
+    if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
+  } while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used);
+  sti();
+
+  if(mb[mbi].status) {
+    printk("Lost interrupt discovered on irq %d - attempting to recover\n", 
+	   SCpnt->host->irq);
+    intval[0] = SCpnt->host->irq;
+    aha1542_intr_handle((int) &intval[2]);
+    return 0;
+  }
+
+  /* OK, no lost interrupt.  Try looking to see how many pending commands
+     we think we have. */
+
+  for(i=0; i< AHA1542_MAILBOXES; i++)
+   if(HOSTDATA(SCpnt->host)->SCint[i])
+     {
+       if(HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+	 printk("Timed out command pending for %4.4x\n", SCpnt->request.dev);
+	 if (HOSTDATA(SCpnt->host)->mb[i].status) {
+	   printk("OGMB still full - restarting\n");
+	   aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+	 };
+       } else
+	 printk("Other pending command %4.4x\n", SCpnt->request.dev);
+     }
+
 #endif
+
     DEB(printk("aha1542_abort\n"));
 #if 0
     cli();
     for(mbo = 0; mbo < AHA1542_MAILBOXES; mbo++)
       if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]){
 	mb[mbo].status = 2;  /* Abort command */
-	aha1542_out(&ahacmd, 1);		/* start scsi command */
+	aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */
 	sti();
 	break;
       };
 #endif
-    return 0;
+    return SCSI_ABORT_SNOOZE;
 }
 
-/* We do not implement a reset function here, but the upper level code assumes
-   that it will get some kind of response for the command in SCpnt.  We must
-   oblige, or the command will hang the scsi system */
+/* We do not implement a reset function here, but the upper level code
+   assumes that it will get some kind of response for the command in
+   SCpnt.  We must oblige, or the command will hang the scsi system.
+   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)
 {
+    unchar ahacmd = CMD_START_SCSI;
+    int i;
+
     DEB(printk("aha1542_reset called\n"));
-    if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
-    return 0;
+#if 0
+    /* This does a scsi reset for all devices on the bus */
+    outb(SCRST, CONTROL(SCpnt->host->io_port));
+#else
+    /* This does a selective reset of just the one device */
+    /* First locate the ccb for this command */
+    for(i=0; i< AHA1542_MAILBOXES; i++)
+      if(HOSTDATA(SCpnt->host)->SCint[i] == SCpnt)
+	{
+	  HOSTDATA(SCpnt->host)->ccb[i].op = 0x81;  /* BUS DEVICE RESET */
+	  /* Now tell the 1542 to flush all pending commands for this target */
+	  aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+
+	  /* Here is the tricky part.  What to do next.  Do we get an interrupt
+	     for the commands that we aborted with the specified target, or
+	     do we generate this on our own?  Try it without first and see
+	     what happens */
+	  printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+	  /* If the first does not work, then try the second.  I think the
+	     first option is more likely to be correct. Free the command
+	     block for all commands running on this target... */
+#if 1
+	  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];
+	      SCtmp->result = DID_RESET << 16;
+	      if (SCtmp->host_scribble) scsi_free(SCtmp->host_scribble, 512);
+	      printk("Sending DID_RESET for target %d\n", SCpnt->target);
+	      SCtmp->scsi_done(SCpnt);
+	      
+	      HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+	    }
+	  return SCSI_RESET_SUCCESS;
+#else
+	  return SCSI_RESET_PENDING;
+#endif
+	}
+
+#endif
+    return SCSI_RESET_PENDING;
 }
 
 #ifdef CONFIG_BLK_DEV_SD
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/aha1542.h linux/drivers/scsi/aha1542.h
--- v1.1.14/linux/drivers/scsi/aha1542.h	Fri Dec 17 08:20:31 1993
+++ linux/drivers/scsi/aha1542.h	Tue May 24 09:19:19 1994
@@ -131,7 +131,7 @@
 int aha1542_detect(int);
 int aha1542_command(Scsi_Cmnd *);
 int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int aha1542_abort(Scsi_Cmnd *, int);
+int aha1542_abort(Scsi_Cmnd *);
 const char *aha1542_info(void);
 int aha1542_reset(Scsi_Cmnd *);
 int aha1542_biosparam(int, int, int*);
@@ -152,6 +152,6 @@
 	        NULL,		                        \
 		aha1542_biosparam,                      \
 		AHA1542_MAILBOXES, 7, AHA1542_SCATTER, AHA1542_CMDLUN \
-		  , 0, 1}
+		  , 0, 1, ENABLE_CLUSTERING}
 
 #endif
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c
--- v1.1.14/linux/drivers/scsi/aha1740.c	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/aha1740.c	Tue May 24 09:19:22 1994
@@ -474,10 +474,10 @@
 knees.  I cannot (at this moment in time) think of any reason to reset the
 card once it's running.  So there. */
 
-int aha1740_abort(Scsi_Cmnd * SCpnt, int i)
+int aha1740_abort(Scsi_Cmnd * SCpnt)
 {
     DEB(printk("aha1740_abort called\n"));
-    return 0;
+    return SCSI_ABORT_SNOOZE;
 }
 
 /* We do not implement a reset function here, but the upper level code assumes
@@ -487,8 +487,7 @@
 int aha1740_reset(Scsi_Cmnd * SCpnt)
 {
     DEB(printk("aha1740_reset called\n"));
-    if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
-    return 0;
+    return SCSI_RESET_SNOOZE;
 }
 
 int aha1740_biosparam(int size, int dev, int* ip)
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/aha1740.h linux/drivers/scsi/aha1740.h
--- v1.1.14/linux/drivers/scsi/aha1740.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/aha1740.h	Tue May 24 09:19:19 1994
@@ -155,7 +155,7 @@
 int aha1740_detect(int);
 int aha1740_command(Scsi_Cmnd *);
 int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int aha1740_abort(Scsi_Cmnd *, int);
+int aha1740_abort(Scsi_Cmnd *);
 const char *aha1740_info(void);
 int aha1740_reset(Scsi_Cmnd *);
 int aha1740_biosparam(int, int, int*);
@@ -174,7 +174,7 @@
 		aha1740_reset,				\
 	        NULL,		                        \
 		aha1740_biosparam,                      \
-		AHA1740_ECBS, 7, AHA1740_SCATTER, 1, 0, 0}
+		AHA1740_ECBS, 7, AHA1740_SCATTER, 1, 0, 0, ENABLE_CLUSTERING}
 
 #endif
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c
--- v1.1.14/linux/drivers/scsi/buslogic.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/buslogic.c	Tue May 24 09:19:23 1994
@@ -0,0 +1,1203 @@
+/*
+ *	buslogic.c	(C) 1993 David B. Gentzel
+ *	Low-level scsi driver for BusLogic adapters
+ *	by David B. Gentzel, Whitfield Software Services, Carnegie, PA
+ *	    (gentzel@nova.enet.dec.com)
+ *	Thanks to BusLogic for providing the necessary documentation
+ *
+ *	The original version of this driver was derived from aha1542.[ch] which
+ *	is Copyright (C) 1992 Tommy Thorn.  Much has been reworked, but most of
+ *	basic structure and substantial chunks of code still remain.
+ */
+
+/*
+ * TODO:
+ *	1. Cleanup error handling & reporting.
+ *	2. Find out why scatter/gather is limited to 16 requests per command.
+ *	3. Add multiple outstanding requests.
+ *	4. See if we can make good use of having more than one command per lun.
+ *	5. Test/improve/fix abort & reset functions.
+ *	6. Look at command linking.
+ */
+
+/*
+ * NOTES:
+ *    BusLogic (formerly BusTek) manufactures an extensive family of
+ *    intelligent, high performance SCSI-2 host adapters.  They all support
+ *    command queueing and scatter/gather I/O.  Most importantly, they all
+ *    support identical programming interfaces, so a single driver can be used
+ *    for all boards.
+ *
+ *    Actually, they all support TWO identical programming interfaces!  They
+ *    have an Adaptec 154x compatible interface (complete with 24 bit
+ *    addresses) as well as a "native" 32 bit interface.  As such, the Linux
+ *    aha1542 driver can be used to drive them, but with less than optimal
+ *    performance (at least for the EISA, VESA, and MCA boards).
+ *
+ *    Here is the scoop on the various models:
+ *	BT-542B - ISA first-party DMA with floppy support.
+ *	BT-545S - 542B + FAST SCSI and active termination.
+ *	BT-545D - 545S + differential termination.
+ *	BT-445S - VESA bus-master FAST SCSI with active termination and floppy
+ *		  support.
+ *	BT-640A - MCA bus-master with floppy support.
+ *	BT-646S - 640A + FAST SCSI and active termination.
+ *	BT-646D - 646S + differential termination.
+ *	BT-742A - EISA bus-master with floppy support.
+ *	BT-747S - 742A + FAST SCSI, active termination, and 2.88M floppy.
+ *	BT-747D - 747S + differential termination.
+ *	BT-757S - 747S + WIDE SCSI.
+ *	BT-757D - 747D + WIDE SCSI.
+ *
+ *    Should you require further information on any of these boards, BusLogic
+ *    can be reached at (408)492-9090.
+ *
+ *    This driver SHOULD support all of these boards.  It has only been tested
+ *    with a 747S.  An earlier version was tested with a 445S.
+ *
+ *    Places flagged with a triple question-mark are things which are either
+ *    unfinished, questionable, or wrong.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#ifdef CONFIG_BLK_DEV_SD
+# include "sd.h"
+#endif
+#define BUSLOGIC_PRIVATE_H	/* Get the "private" stuff */
+#include "buslogic.h"
+
+#ifndef BUSLOGIC_DEBUG
+# define BUSLOGIC_DEBUG UD_ABORT
+#endif
+
+#define BUSLOGIC_VERSION "1.00"
+
+/* ??? This *MAY* work to properly report the geometry of disks > 1G when the
+   alternate geometry is enabled on the host adapter.  It is completely
+   untested as I have no such disk to experiment with.  I rarely refuse gifts,
+   however... */
+/* Check out the stuff in aha1542.c - is this the same as how buslogic does
+   it? - ERY */
+/* ??? Not Yet Implemented */
+/*#ifdef BUSLOGIC_ALTERNATE_MAPPING*/
+
+/* Not a random value - if this is too large, the system hangs for a long time
+   waiting for something to happen if a board is not installed. */
+#define WAITNEXTTIMEOUT 3000000
+
+/* This is for the scsi_malloc call in buslogic_queuecommand. */
+/* ??? I'd up this to 4096, but would we be in danger of using up the
+   scsi_malloc memory pool? */
+/* This could be a concern, I guess.  It may be possible to fix things so that
+   the table generated in sd.c is compatible with the low-level code, but
+   don't hold your breath.  -ERY */
+#define BUSLOGIC_SG_MALLOC 512
+
+/* Since the SG list is malloced, we have to limit the length. */
+#define BUSLOGIC_MAX_SG (BUSLOGIC_SG_MALLOC / sizeof (struct chain))
+
+/* The DMA-Controller.  We need to fool with this because we want to be able to
+   use an ISA BusLogic without having to have the BIOS enabled. */
+#define DMA_MODE_REG 0xD6
+#define DMA_MASK_REG 0xD4
+#define	CASCADE 0xC0
+
+#define BUSLOGIC_MAILBOXES 16	/* ??? Arbitrary? */
+
+/* BusLogic boards can be configured for quite a number of port addresses (six
+   to be exact), but I generally do not want the driver poking around at
+   random.  We allow two port addresses - this allows people to use a BusLogic
+   with a MIDI card, which frequently also used 0x330.  If different port
+   addresses are needed (e.g. to install more than two cards), you must define
+   BUSLOGIC_PORT_OVERRIDE to be a list of the addresses which will be checked.
+   This can also be used to resolve a conflict if the port-probing at a
+   standard port causes problems with another board. */
+static const unsigned int bases[] = {
+#ifdef BUSLOGIC_PORT_OVERRIDE
+    BUSLOGIC_PORT_OVERRIDE
+#else
+    0x330, 0x334, /* 0x130, 0x134, 0x230, 0x234 */
+#endif
+};
+
+#define BIOS_TRANSLATION_6432 1		/* Default case */
+#define BIOS_TRANSLATION_25563 2	/* Big disk case */
+
+struct hostdata {
+    unsigned char bus_type;
+    int bios_translation;	/* Mapping bios uses - for compatibility */
+    size_t last_mbi_used;
+    size_t last_mbo_used;
+    Scsi_Cmnd *SCint[BUSLOGIC_MAILBOXES];
+    struct mailbox mb[2 * BUSLOGIC_MAILBOXES];
+    struct ccb ccbs[BUSLOGIC_MAILBOXES];
+};
+
+#define HOSTDATA(host) ((struct hostdata *)&(host)->hostdata)
+
+/* One for each IRQ level (9-15), although 13 will never be used. */
+static struct Scsi_Host *host[7] = { NULL, };
+
+static int setup_mailboxes(unsigned int base, struct Scsi_Host *SHpnt);
+
+#define INTR_RESET(base) outb(RINT, CONTROL(base))
+
+#define buslogic_printk buslogic_prefix(),printk
+
+#define CHECK(cond) if (cond) ; else goto fail
+
+#define WAIT(port, mask, allof, noneof) CHECK(wait(port, mask, allof, noneof))
+#define WAIT_WHILE(port, mask) WAIT(port, mask, 0, mask)
+#define WAIT_UNTIL(port, mask) WAIT(port, mask, mask, 0)
+
+static __inline__ int wait(unsigned short port, unsigned char mask,
+			   unsigned char allof, unsigned char noneof)
+{
+    int bits;
+    unsigned int timeout = WAITNEXTTIMEOUT;
+
+    for (;;) {
+	bits = inb(port) & mask;
+	if ((bits & allof) == allof && (bits & noneof) == 0)
+	    break;
+	if (--timeout == 0)
+	    return FALSE;
+    }
+    return TRUE;
+}
+
+static void buslogic_prefix(void)
+{
+    printk("BusLogic SCSI: ");
+}
+
+#if 0
+static void buslogic_stat(unsigned int base)
+{
+    int s = inb(STATUS(base)), i = inb(INTERRUPT(base));
+
+    printk("status=%02X intrflags=%02X\n", s, i);
+}
+#else
+# define buslogic_stat(base)
+#endif
+
+/* This is a bit complicated, but we need to make sure that an interrupt
+   routine does not send something out while we are in the middle of this.
+   Fortunately, it is only at boot time that multi-byte messages are ever
+   sent. */
+static int buslogic_out(unsigned int base, const unsigned char *cmdp, size_t len)
+{
+    if (len == 1) {
+	for (;;) {
+	    WAIT_WHILE(STATUS(base), CPRBSY);
+	    cli();
+	    if (!(inb(STATUS(base)) & CPRBSY)) {
+		outb(*cmdp, COMMAND_PARAMETER(base));
+		sti();
+		return FALSE;
+	    }
+	    sti();
+	}
+    } else {
+	cli();
+	while (len--) {
+	    WAIT_WHILE(STATUS(base), CPRBSY);
+	    outb(*cmdp++, COMMAND_PARAMETER(base));
+	}
+	sti();
+    }
+    return FALSE;
+  fail:
+    sti();
+    buslogic_printk("buslogic_out failed(%u): ", len + 1);
+    buslogic_stat(base);
+    return TRUE;
+}
+
+static int buslogic_in(unsigned int base, unsigned char *cmdp, size_t len)
+{
+    cli();
+    while (len--) {
+	WAIT_UNTIL(STATUS(base), DIRRDY);
+	*cmdp++ = inb(DATA_IN(base));
+    }
+    sti();
+    return FALSE;
+  fail:
+    sti();
+    buslogic_printk("buslogic_in failed(%u): ", len + 1);
+    buslogic_stat(base);
+    return TRUE;
+}
+
+static unsigned int makecode(unsigned int hosterr, unsigned int scsierr)
+{
+    switch (hosterr) {
+      case 0x00:	/* Normal completion. */
+      case 0x0A:	/* Linked command complete without error and linked
+			   normally. */
+      case 0x0B:	/* Linked command complete without error, interrupt
+			   generated. */
+	hosterr = DID_OK;
+	break;
+
+      case 0x11:	/* Selection time out: the initiator selection or
+			   target reselection was not complete within the SCSI
+			   Time out period. */
+	hosterr = DID_TIME_OUT;
+	break;
+
+      case 0x14:	/* Target bus phase sequence failure - An invalid bus
+			   phase or bus phase sequence was requested by the
+			   target.  The host adapter will generate a SCSI
+			   Reset Condition, notifying the host with a RSTS
+			   interrupt. */
+	hosterr = DID_RESET;	/* ??? Is this right? */
+	break;
+
+      case 0x12:	/* Data overrun/underrun: the target attempted to
+			   transfer more data than was allocated by the Data
+			   Length field or the sum of the Scatter/Gather Data
+			   Length fields. */
+      case 0x13:	/* Unexpected bus free - The target dropped the SCSI
+			   BSY at an unexpected time. */
+      case 0x15:	/* MBO command was not 00, 01, or 02 - The first byte
+			   of the MB was invalid.  This usually indicates a
+			   software failure. */
+      case 0x16:	/* Invalid CCB Operation Code - The first byte of the
+			   CCB was invalid.  This usually indicates a software
+			   failure. */
+      case 0x17:	/* Linked CCB does not have the same LUN - A
+			   subsequent CCB of a set of linked CCB's does not
+			   specify the same logical unit number as the
+			   first. */
+      case 0x18:	/* Invalid Target Direction received from Host - The
+			   direction of a Target Mode CCB was invalid. */
+      case 0x19:	/* Duplicate CCB Received in Target Mode - More than
+			   once CCB was received to service data transfer
+			   between the same target LUN and initiator SCSI ID
+			   in the same direction. */
+      case 0x1A:	/* Invalid CCB or Segment List Parameter - A segment
+			   list with a zero length segment or invalid segment
+			   list boundaries was received.  A CCB parameter was
+			   invalid. */
+      case 0x1B:	/* Auto request sense failed. */
+      case 0x1C:	/* SCSI-2 tagged queueing message was rejected by the
+			   target. */
+      case 0x20:	/* The host adapter hardware failed. */
+      case 0x21:	/* The target did not respond to SCSI ATN and the host
+			   adapter consequently issued a SCSI bus reset to
+			   clear up the failure. */
+      case 0x22:	/* The host adapter asserted a SCSI bus reset. */
+      case 0x23:	/* Other SCSI devices asserted a SCSI bus reset. */
+#if BUSLOGIC_DEBUG
+	buslogic_printk("%X %X\n", hosterr, scsierr);
+#endif
+	hosterr = DID_ERROR;	/* ??? Couldn't find any better. */
+	break;
+
+      default:
+	buslogic_printk("makecode: unknown hoststatus %X\n", hosterr);
+	break;
+    }
+    return (hosterr << 16) | scsierr;
+}
+
+static int test_port(unsigned int base, struct Scsi_Host *SHpnt)
+{
+    unsigned int i;
+    unsigned char inquiry_cmd[] = { CMD_INQUIRY };
+    unsigned char inquiry_result[4];
+    unsigned char *cmdp;
+    int len;
+    volatile int debug = 0;
+
+    /* Quick and dirty test for presence of the card. */
+    if (inb(STATUS(base)) == 0xFF)
+	return TRUE;
+
+    /* Reset the adapter.  I ought to make a hard reset, but it's not really
+       necessary. */
+
+#if BUSLOGIC_DEBUG
+    buslogic_printk("test_port called\n");
+#endif
+
+    outb(RSOFT | RINT/* | RSBUS*/, CONTROL(base));
+
+    /* Wait a little bit for things to settle down. */
+    i = jiffies + 2;
+    while (i > jiffies);
+
+    debug = 1;
+    /* Expect INREQ and HARDY, any of the others are bad. */
+    WAIT(STATUS(base), STATMASK, INREQ | HARDY,
+	 DACT | DFAIL | CMDINV | DIRRDY | CPRBSY);
+
+    debug = 2;
+    /* Shouldn't have generated any interrupts during reset. */
+    if (inb(INTERRUPT(base)) & INTRMASK)
+	goto fail;
+
+    /* Perform a host adapter inquiry instead so we do not need to set up the
+       mailboxes ahead of time. */
+    buslogic_out(base, inquiry_cmd, 1);
+
+    debug = 3;
+    len = 4;
+    cmdp = &inquiry_result[0];
+    while (len--) {
+	WAIT(STATUS(base), DIRRDY, DIRRDY, 0);
+	*cmdp++ = inb(DATA_IN(base));
+    }
+
+    debug = 4;
+    /* Reading port should reset DIRRDY. */
+    if (inb(STATUS(base)) & DIRRDY)
+	goto fail;
+
+    debug = 5;
+    /* When CMDC, command is completed, and we're though testing. */
+    WAIT_UNTIL(INTERRUPT(base), CMDC);
+
+    /* now initialize adapter. */
+
+    debug = 6;
+    /* Clear interrupts. */
+    outb(RINT, CONTROL(base));
+
+    debug = 7;
+
+    return FALSE;				/* 0 = ok */
+  fail:
+    return TRUE;				/* 1 = not ok */
+}
+
+const char *buslogic_info(void)
+{
+    return "BusLogic SCSI Driver version " BUSLOGIC_VERSION;
+}
+
+/* A "high" level interrupt handler. */
+static void buslogic_interrupt(int junk)
+{
+    void (*my_done)(Scsi_Cmnd *) = NULL;
+    int errstatus, mbistatus = 0, number_serviced, found;
+    size_t mbi, mbo = 0;
+    struct Scsi_Host *SHpnt;
+    Scsi_Cmnd *SCtmp;
+    int irqno, base;
+    struct mailbox *mb;
+    struct ccb *ccb;
+
+    /* Magic - this -2 is only required for slow interrupt handlers */
+    irqno = ((int *)junk)[-2];
+
+    SHpnt = host[irqno - 9];
+    if (!SHpnt)
+	panic("buslogic.c: NULL SCSI host entry");
+
+    mb = HOSTDATA(SHpnt)->mb;
+    ccb = HOSTDATA(SHpnt)->ccbs;
+    base = SHpnt->io_port;
+
+#if BUSLOGIC_DEBUG
+    {
+	int flag = inb(INTERRUPT(base));
+
+	buslogic_printk("buslogic_interrupt: ");
+	if (!(flag & INTV))
+	    printk("no interrupt? ");
+	if (flag & IMBL)
+	    printk("IMBL ");
+	if (flag & MBOR)
+	    printk("MBOR ");
+	if (flag & CMDC)
+	    printk("CMDC ");
+	if (flag & RSTS)
+	    printk("RSTS ");
+	printk("status %02X\n", inb(STATUS(base)));
+    }
+#endif
+
+    number_serviced = 0;
+
+    for (;;) {
+	INTR_RESET(base);
+
+	cli();
+
+	mbi = HOSTDATA(SHpnt)->last_mbi_used + 1;
+	if (mbi >= 2 * BUSLOGIC_MAILBOXES)
+	    mbi = BUSLOGIC_MAILBOXES;
+
+	/* I use the "found" variable as I like to keep cli/sti pairs at the
+	   same block level.  Debugging dropped sti's is no fun... */
+
+	found = FALSE;
+	do {
+	    if (mb[mbi].status != MBX_NOT_IN_USE) {
+		found = TRUE;
+		break;
+	    }
+	    mbi++;
+	    if (mbi >= 2 * BUSLOGIC_MAILBOXES)
+		mbi = BUSLOGIC_MAILBOXES;
+	} while (mbi != HOSTDATA(SHpnt)->last_mbi_used);
+
+	if (found) {
+	    mbo = (struct ccb *)mb[mbi].ccbptr - ccb;
+	    mbistatus = mb[mbi].status;
+	    mb[mbi].status = MBX_NOT_IN_USE;
+	    HOSTDATA(SHpnt)->last_mbi_used = mbi;
+	}
+
+	sti();
+
+	if (!found) {
+	    /* Hmm, no mail.  Must have read it the last time around. */
+	    if (number_serviced)
+		return;
+	    buslogic_printk("interrupt received, but no mail\n");
+	    return;
+	}
+
+#if BUSLOGIC_DEBUG
+	if (ccb[mbo].tarstat || ccb[mbo].hastat)
+	    buslogic_printk("buslogic_interrupt: returning %08X (status %d)\n",
+			    ((int)ccb[mbo].hastat << 16) | ccb[mbo].tarstat,
+			    mb[mbi].status);
+#endif
+
+	if (mbistatus == 0x03)	/* ??? 0x03 == Aborted CCB not found. */
+	    continue;
+
+#if BUSLOGIC_DEBUG
+	buslogic_printk("...done %u %u\n", mbo, mbi);
+#endif
+
+	SCtmp = HOSTDATA(SHpnt)->SCint[mbo];
+
+	if (!SCtmp || !SCtmp->scsi_done) {
+	    buslogic_printk("buslogic_interrupt: Unexpected interrupt\n");
+	    return;
+	}
+
+	my_done = SCtmp->scsi_done;
+	if (SCtmp->host_scribble)
+	    scsi_free(SCtmp->host_scribble, BUSLOGIC_SG_MALLOC);
+
+	/* ??? more error checking left out here */
+	if (mbistatus != 1)
+	    /* ??? This is surely wrong, but I don't know what's right. */
+	    errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
+	else
+	    errstatus = 0;
+
+#if BUSLOGIC_DEBUG
+	if (errstatus)
+	    buslogic_printk("error: %08X %04X %04X\n",
+			    errstatus, ccb[mbo].hastat, ccb[mbo].tarstat);
+
+	if (status_byte(ccb[mbo].tarstat) == CHECK_CONDITION) {
+	    size_t i;
+
+	    buslogic_printk("buslogic_interrupt: sense: ");
+	    for (i = 0; i < sizeof SCtmp->sense_buffer; i++)
+		printk(" %02X", SCtmp->sense_buffer[i]);
+	    printk("\n");
+	}
+
+	if (errstatus)
+	    buslogic_printk("buslogic_interrupt: returning %08X\n", errstatus);
+#endif
+
+	SCtmp->result = errstatus;
+	HOSTDATA(SHpnt)->SCint[mbo] = NULL;	/* This effectively frees up
+						   the mailbox slot, as far as
+						   queuecommand is concerned. */
+	my_done(SCtmp);
+	number_serviced++;
+    }
+}
+
+int buslogic_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+    static const unsigned char buscmd[] = { CMD_START_SCSI };
+    unsigned char direction;
+    unsigned char *cmd = (unsigned char *)SCpnt->cmnd;
+    unsigned char target = SCpnt->target;
+    unsigned char lun = SCpnt->lun;
+    void *buff = SCpnt->request_buffer;
+    int bufflen = SCpnt->request_bufflen;
+    int mbo;
+    struct mailbox *mb;
+    struct ccb *ccb;
+
+#if BUSLOGIC_DEBUG
+    if (target > 1) {
+	SCpnt->result = DID_TIME_OUT << 16;
+	done(SCpnt);
+	return 0;
+    }
+#endif
+
+    if (*cmd == REQUEST_SENSE) {
+#ifndef DEBUG
+	if (bufflen != sizeof SCpnt->sense_buffer) {
+	    buslogic_printk("Wrong buffer length supplied for request sense (%d)\n",
+			    bufflen);
+	    panic("buslogic.c: wrong buffer length for request sense");
+	}
+#endif
+	SCpnt->result = 0;
+	done(SCpnt);
+	return 0;
+    }
+
+#if BUSLOGIC_DEBUG
+    {
+	int i;
+
+	if (*cmd == READ_10 || *cmd == WRITE_10)
+	    i = xscsi2int(cmd + 2);
+	else if (*cmd == READ_6 || *cmd == WRITE_6)
+	    i = scsi2int(cmd + 2);
+	else
+	    i = -1;
+	buslogic_printk("buslogic_queuecommand: dev %d cmd %02X pos %d len %d ",
+			target, *cmd, i, bufflen);
+	buslogic_stat(SCpnt->host->io_port);
+	buslogic_printk("buslogic_queuecommand: dumping scsi cmd: ");
+	for (i = 0; i < (COMMAND_SIZE(*cmd)); i++)
+	    printk(" %02X", cmd[i]);
+	printk("\n");
+	if (*cmd == WRITE_10 || *cmd == WRITE_6)
+	    return 0;	/* we are still testing, so *don't* write */
+    }
+#endif
+
+    mb = HOSTDATA(SCpnt->host)->mb;
+    ccb = HOSTDATA(SCpnt->host)->ccbs;
+
+    /* Use the outgoing mailboxes in a round-robin fashion, because this
+       is how the host adapter will scan for them. */
+
+    cli();
+
+    mbo = HOSTDATA(SCpnt->host)->last_mbo_used + 1;
+    if (mbo >= BUSLOGIC_MAILBOXES)
+	mbo = 0;
+
+    do {
+	if (mb[mbo].status == MBX_NOT_IN_USE
+	    && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
+	    break;
+	mbo++;
+	if (mbo >= BUSLOGIC_MAILBOXES)
+	    mbo = 0;
+    } while (mbo != HOSTDATA(SCpnt->host)->last_mbo_used);
+
+    if (mb[mbo].status != MBX_NOT_IN_USE || HOSTDATA(SCpnt->host)->SCint[mbo]) {
+	/* ??? Instead of panicing, we should enable OMBR interrupts and
+	   sleep until we get one. */
+	panic("buslogic.c: unable to find empty mailbox");
+    }
+
+    HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt;	/* This will effectively
+						   prevent someone else from
+						   screwing with this cdb. */
+
+    HOSTDATA(SCpnt->host)->last_mbo_used = mbo;
+
+    sti();
+
+#if BUSLOGIC_DEBUG
+    buslogic_printk("sending command (%d %08X)...", mbo, done);
+#endif
+
+    /* This gets trashed for some reason */
+    mb[mbo].ccbptr = &ccb[mbo];
+
+    memset(&ccb[mbo], 0, sizeof (struct ccb));
+
+    ccb[mbo].cdblen = COMMAND_SIZE(*cmd);	/* SCSI Command Descriptor
+						   Block Length */
+
+    direction = 0;
+    if (*cmd == READ_10 || *cmd == READ_6)
+	direction = 8;
+    else if (*cmd == WRITE_10 || *cmd == WRITE_6)
+	direction = 16;
+
+    memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
+
+    if (SCpnt->use_sg) {
+	struct scatterlist *sgpnt;
+	struct chain *cptr;
+	size_t i;
+
+	ccb[mbo].op = CCB_OP_INIT_SG;	/* SCSI Initiator Command w/scatter-gather */
+	SCpnt->host_scribble = (unsigned char *)scsi_malloc(BUSLOGIC_SG_MALLOC);
+	if (SCpnt->host_scribble == NULL)
+	    panic("buslogic.c: unable to allocate DMA memory");
+	sgpnt = (struct scatterlist *)SCpnt->request_buffer;
+	cptr = (struct chain *)SCpnt->host_scribble;
+	if (SCpnt->use_sg > SCpnt->host->sg_tablesize) {
+	    buslogic_printk("buslogic_queuecommand bad segment list, %d > %d\n",
+			    SCpnt->use_sg, SCpnt->host->sg_tablesize);
+	    panic("buslogic.c: bad segment list");
+	}
+	for (i = 0; i < SCpnt->use_sg; i++) {
+	    cptr[i].dataptr = sgpnt[i].address;
+	    cptr[i].datalen = sgpnt[i].length;
+	}
+	ccb[mbo].datalen = SCpnt->use_sg * sizeof (struct chain);
+	ccb[mbo].dataptr = cptr;
+#if BUSLOGIC_DEBUG
+	{
+	    unsigned char *ptr;
+
+	    buslogic_printk("cptr %08X: ", cptr);
+	    ptr = (unsigned char *)cptr;
+	    for (i = 0; i < 18; i++)
+		printk(" %02X", ptr[i]);
+	    printk("\n");
+	}
+#endif
+    } else {
+	ccb[mbo].op = CCB_OP_INIT;	/* SCSI Initiator Command */
+	SCpnt->host_scribble = NULL;
+	ccb[mbo].datalen = bufflen;
+	ccb[mbo].dataptr = buff;
+    }
+    ccb[mbo].id = target;
+    ccb[mbo].lun = lun;
+    ccb[mbo].dir = direction;
+    ccb[mbo].rsalen = sizeof SCpnt->sense_buffer;
+    ccb[mbo].senseptr = SCpnt->sense_buffer;
+    ccb[mbo].linkptr = NULL;
+    ccb[mbo].commlinkid = 0;
+
+#if BUSLOGIC_DEBUG
+    {
+	size_t i;
+
+	buslogic_printk("buslogic_queuecommand: sending...");
+	for (i = 0; i < sizeof ccb[mbo]; i++)
+	    printk(" %02X", ((unsigned char *)&ccb[mbo])[i]);
+	printk("\n");
+    }
+#endif
+
+    if (done) {
+#if BUSLOGIC_DEBUG
+	buslogic_printk("buslogic_queuecommand: now waiting for interrupt: ");
+	buslogic_stat(SCpnt->host->io_port);
+#endif
+	SCpnt->scsi_done = done;
+	mb[mbo].status = MBX_ACTION_START;
+	/* start scsi command */
+	buslogic_out(SCpnt->host->io_port, buscmd, sizeof buscmd);
+#if BUSLOGIC_DEBUG
+	buslogic_printk("buslogic_queuecommand: status: ");
+	buslogic_stat(SCpnt->host->io_port);
+#endif
+    } else
+	buslogic_printk("buslogic_queuecommand: done can't be NULL\n");
+
+    return 0;
+}
+
+#if 0
+static void internal_done(Scsi_Cmnd *SCpnt)
+{
+    SCpnt->SCp.Status++;
+}
+
+int buslogic_command(Scsi_Cmnd *SCpnt)
+{
+#if BUSLOGIC_DEBUG
+    buslogic_printk("buslogic_command: ..calling buslogic_queuecommand\n");
+#endif
+
+    buslogic_queuecommand(SCpnt, internal_done);
+
+    SCpnt->SCp.Status = 0;
+    while (!SCpnt->SCp.Status)
+	continue;
+    return SCpnt->result;
+    return internal_done_errcode;
+}
+#endif
+
+/* Initialize mailboxes. */
+static int setup_mailboxes(unsigned int base, struct Scsi_Host *SHpnt)
+{
+    size_t i;
+    int ok = FALSE;		/* Innocent until proven guilty... */
+    struct mailbox *mb = HOSTDATA(SHpnt)->mb;
+    struct ccb *ccb = HOSTDATA(SHpnt)->ccbs;
+    struct {
+	unsigned char cmd, count;
+	void *base PACKED;
+    } cmd = { CMD_INITEXTMB, BUSLOGIC_MAILBOXES, mb };
+
+    for (i = 0; i < BUSLOGIC_MAILBOXES; i++) {
+	mb[i].status = mb[BUSLOGIC_MAILBOXES + i].status = MBX_NOT_IN_USE;
+	mb[i].ccbptr = &ccb[i];
+    }
+    INTR_RESET(base);	/* reset interrupts, so they don't block */
+
+    /* If this fails, this must be an Adaptec board */
+    if (buslogic_out(base, (unsigned char *)&cmd, sizeof cmd))
+	goto must_be_adaptec;
+
+    /* Wait until host adapter is done messing around, and then check to see
+       if the command was accepted.  If it failed, this must be an Adaptec
+       board. */
+    WAIT_UNTIL(STATUS(base), HARDY);
+    if (inb(STATUS(base)) & CMDINV)
+	goto must_be_adaptec;
+
+    WAIT_UNTIL(INTERRUPT(base), CMDC);
+    while (0) {
+      fail:
+	buslogic_printk("buslogic_detect: failed setting up mailboxes\n");
+    }
+    ok = TRUE;
+  must_be_adaptec:
+    INTR_RESET(base);
+    printk("- must be Adaptec\n"); /* So that the adaptec detect looks clean */
+    return ok;
+}
+
+static int getconfig(unsigned int base, unsigned char *irq,
+		     unsigned char *dma, unsigned char *id,
+		     unsigned char *bus_type, unsigned short *max_sg)
+{
+    unsigned char inquiry_cmd[2];
+    unsigned char inquiry_result[4];
+    int i;
+
+    i = inb(STATUS(base));
+    if (i & DIRRDY)
+	i = inb(DATA_IN(base));
+    inquiry_cmd[0] = CMD_RETCONF;
+    buslogic_out(base, inquiry_cmd, 1);
+    buslogic_in(base, inquiry_result, 3);
+    WAIT_UNTIL(INTERRUPT(base), CMDC);
+    INTR_RESET(base);
+    /* Defer using the DMA value until we know the bus type. */
+    *dma = inquiry_result[0];
+    switch (inquiry_result[1]) {
+      case 0x01:
+	*irq = 9;
+	break;
+      case 0x02:
+	*irq = 10;
+	break;
+      case 0x04:
+	*irq = 11;
+	break;
+      case 0x08:
+	*irq = 12;
+	break;
+      case 0x20:
+	*irq = 14;
+	break;
+      case 0x40:
+	*irq = 15;
+	break;
+      default:
+	buslogic_printk("Unable to determine BusLogic IRQ level.  Disabling board.\n");
+	return TRUE;
+    }
+    *id = inquiry_result[2] & 0x7;
+
+    inquiry_cmd[0] = CMD_INQEXTSETUP;
+    inquiry_cmd[1] = 4;
+    if (buslogic_out(base, inquiry_cmd, 2)
+	|| buslogic_in(base, inquiry_result, 4))
+	return TRUE;
+    WAIT_UNTIL(INTERRUPT(base), CMDC);
+    INTR_RESET(base);
+
+#ifdef BUSLOGIC_BUS_TYPE_OVERRIDE
+    *bus_type = BUS_TYPE_OVERRIDE;
+#else
+    *bus_type = inquiry_result[0];
+#endif
+    CHECK(*bus_type == 'A' || *bus_type == 'E' || *bus_type == 'M');
+#ifdef BUSLOGIC_BUS_TYPE_OVERRIDE
+    if (inquiry_result[0] != BUS_TYPE_OVERRIDE)
+	buslogic_printk("Overriding bus type %c with %c\n",
+			inquiry_result[0], BUS_TYPE_OVERRIDE);
+#endif
+    *max_sg = (inquiry_result[3] << 8) | inquiry_result[2];
+
+    /* We only need a DMA channel for ISA boards.  Some other types of boards
+       (such as the 747S) have an option to report a DMA channel even though
+       none is used (for compatability with Adaptec drivers which require a
+       DMA channel).  We ignore this. */
+    if (*bus_type == 'A')
+	switch (*dma) {
+	  case 0:	/* This indicates a that no DMA channel is used. */
+	    *dma = 0;
+	    break;
+	  case 0x20:
+	    *dma = 5;
+	    break;
+	  case 0x40:
+	    *dma = 6;
+	    break;
+	  case 0x80:
+	    *dma = 7;
+	    break;
+	  default:
+	    buslogic_printk("Unable to determine BusLogic DMA channel.  Disabling board.\n");
+	    return TRUE;
+	}
+    else
+	*dma = 0;
+
+    while (0) {
+      fail:
+	buslogic_printk("buslogic_detect: query board settings\n");
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* Query the board to find out the model. */
+static int buslogic_query(unsigned int base, int *trans)
+{
+#if 0
+    unsigned const char inquiry_cmd[] = { CMD_INQUIRY };
+    unsigned char inquiry_result[4];
+    int i;
+
+    i = inb(STATUS(base));
+    if (i & DIRRDY)
+	i = inb(DATA_IN(base));
+    buslogic_out(base, inquiry_cmd, sizeof inquiry_cmd);
+    buslogic_in(base, inquiry_result, 4);
+    WAIT_UNTIL(INTERRUPT(base), CMDC);
+    while (0) {
+      fail:
+	buslogic_printk("buslogic_detect: query card type\n");
+    }
+    INTR_RESET(base);
+#endif
+
+    *trans = BIOS_TRANSLATION_6432;	/* Default case */
+
+    return FALSE;
+}
+
+/* return non-zero on detection */
+int buslogic_detect(int hostnum)
+{
+    unsigned char dma;
+    unsigned char irq;
+    unsigned int base = 0;
+    unsigned char id;
+    unsigned char bus_type;
+    unsigned short max_sg;
+    int trans;
+    struct Scsi_Host *SHpnt = NULL;
+    int count = 0;
+    int indx;
+    int val;
+
+#if BUSLOGIC_DEBUG
+    buslogic_printk("buslogic_detect:\n");
+#endif
+
+    for (indx = 0; indx < ARRAY_SIZE(bases); indx++)
+	if (!check_region(bases[indx], 3)) {
+	    SHpnt = scsi_register(hostnum, sizeof (struct hostdata));
+
+	    base = bases[indx];
+
+	    if (test_port(base, SHpnt))
+		goto unregister;
+
+	    /* Set the Bus on/off-times as not to ruin floppy performance. */
+	    {
+		/* The default ON/OFF times for BusLogic adapters is 7/4. */
+		static const unsigned char oncmd[] = { CMD_BUSON_TIME, 7 };
+		static const unsigned char offcmd[] = { CMD_BUSOFF_TIME, 5 };
+
+		INTR_RESET(base);
+		buslogic_out(base, oncmd, sizeof oncmd);
+		WAIT_UNTIL(INTERRUPT(base), CMDC);
+		/* CMD_BUSOFF_TIME is a noop for EISA boards, but as there is
+		   no way to to differentiate EISA from VESA we send it
+		   unconditionally. */
+		INTR_RESET(base);
+		buslogic_out(base, offcmd, sizeof offcmd);
+		WAIT_UNTIL(INTERRUPT(base), CMDC);
+		while (0) {
+		  fail:
+		    buslogic_printk("buslogic_detect: setting bus on/off-time failed\n");
+		}
+		INTR_RESET(base);
+	    }
+
+	    if (buslogic_query(base, &trans))
+		goto unregister;
+
+	    if (getconfig(base, &irq, &dma, &id, &bus_type, &max_sg))
+		goto unregister;
+
+#if BUSLOGIC_DEBUG
+	    buslogic_stat(base);
+#endif
+	    /* Here is where we tell the men from the boys (i.e. an Adaptec
+	       will fail in setup_mailboxes, the men will not :-) */
+	    if (!setup_mailboxes(base, SHpnt))
+		goto unregister;
+
+	    printk("Configuring BusLogic %s HA at port 0x%03X, IRQ %u",
+		   (bus_type == 'A' ? "ISA"
+		    : (bus_type == 'E' ? "EISA/VESA" : "MCA")),
+		   base, irq);
+	    if (dma != 0)
+		printk(", DMA %u", dma);
+	    printk(", ID %u\n", id);
+
+#if BUSLOGIC_DEBUG
+	    buslogic_stat(base);
+#endif
+
+#if BUSLOGIC_DEBUG
+	    buslogic_printk("buslogic_detect: enable interrupt channel %d\n",
+			    irq);
+#endif
+
+	    cli();
+	    val = request_irq(irq, buslogic_interrupt);
+	    if (val) {
+		buslogic_printk("Unable to allocate IRQ for "
+				"BusLogic controller.\n");
+		sti();
+		goto unregister;
+	    }
+
+	    if (dma) {
+		if (request_dma(dma)) {
+		    buslogic_printk("Unable to allocate DMA channel for "
+				    "BusLogic controller.\n");
+		    free_irq(irq);
+		    sti();
+		    goto unregister;
+		}
+
+		if (dma >= 5) {
+		    outb((dma - 4) | CASCADE, DMA_MODE_REG);
+		    outb(dma - 4, DMA_MASK_REG);
+		}
+	    }
+
+	    host[irq - 9] = SHpnt;
+	    SHpnt->this_id = id;
+	    /* Only type 'A' (AT/ISA) bus adapters use unchecked DMA. */
+	    SHpnt->unchecked_isa_dma = (bus_type == 'A');
+	    SHpnt->sg_tablesize = max_sg;
+	    if (SHpnt->sg_tablesize > BUSLOGIC_MAX_SG)
+		SHpnt->sg_tablesize = BUSLOGIC_MAX_SG;
+	    /* ??? If we can dynamically allocate the mailbox arrays, I'll
+	       probably bump up this number. */
+	    SHpnt->hostt->can_queue = BUSLOGIC_MAILBOXES;
+	    /*SHpnt->base = ???;*/
+	    SHpnt->io_port = base;
+	    SHpnt->dma_channel = dma;
+	    SHpnt->irq = irq;
+	    HOSTDATA(SHpnt)->bios_translation = trans;
+	    if (trans == BIOS_TRANSLATION_25563)
+		buslogic_printk("Using extended bios translation.\n");
+	    HOSTDATA(SHpnt)->last_mbi_used  = 2 * BUSLOGIC_MAILBOXES - 1;
+	    HOSTDATA(SHpnt)->last_mbo_used  = BUSLOGIC_MAILBOXES - 1;
+	    memset(HOSTDATA(SHpnt)->SCint, 0, sizeof HOSTDATA(SHpnt)->SCint);
+	    sti();
+
+#if 0
+	    {
+		unsigned char buf[8];
+		unsigned char cmd[]
+		    = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+		size_t i;
+
+#if BUSLOGIC_DEBUG
+		buslogic_printk("*** READ CAPACITY ***\n");
+#endif
+		for (i = 0; i < sizeof buf; i++)
+		    buf[i] = 0x87;
+		for (i = 0; i < 2; i++)
+		    if (!buslogic_command(i, cmd, buf, sizeof buf)) {
+			buslogic_printk("bus_detect: LU %u sector_size %d "
+					"device_size %d\n",
+					i, xscsi2int(buf + 4), xscsi2int(buf));
+		    }
+
+#if BUSLOGIC_DEBUG
+		buslogic_printk("*** NOW RUNNING MY OWN TEST ***\n");
+#endif
+		for (i = 0; i < 4; i++) {
+		    static buffer[512];
+
+		    cmd[0] = READ_10;
+		    cmd[1] = 0;
+		    xany2scsi(cmd + 2, i);
+		    cmd[6] = 0;
+		    cmd[7] = 0;
+		    cmd[8] = 1;
+		    cmd[9] = 0;
+		    buslogic_command(0, cmd, buffer, sizeof buffer);
+		}
+	    }
+#endif
+
+	    snarf_region(bases[indx], 3);	/* Register the IO ports that
+						   we use */
+	    count++;
+	    continue;
+	  unregister:
+	    scsi_unregister(SHpnt, sizeof (struct hostdata));
+	}
+    return count;
+}
+
+/* ??? The abort command for the aha1542 does not leave the device in a clean
+   state where it is available to be used again.  As it is not clear whether
+   the same problem exists with BusLogic boards, we will enable this and see
+   if it works. */
+int buslogic_abort(Scsi_Cmnd *SCpnt)
+{
+    static const unsigned char buscmd[] = { CMD_START_SCSI };
+    struct mailbox *mb;
+    int mbi, mbo, i;
+
+    buslogic_printk("buslogic_abort: %X %X\n",
+		    inb(STATUS(SCpnt->host->io_port)),
+		    inb(INTERRUPT(SCpnt->host->io_port)));
+
+    cli();
+    mb = HOSTDATA(SCpnt->host)->mb;
+    mbi = HOSTDATA(SCpnt->host)->last_mbi_used + 1;
+    if (mbi >= 2 * BUSLOGIC_MAILBOXES)
+	mbi = BUSLOGIC_MAILBOXES;
+
+    do {
+	if (mb[mbi].status != MBX_NOT_IN_USE)
+	    break;
+	mbi++;
+	if (mbi >= 2 * BUSLOGIC_MAILBOXES)
+	    mbi = BUSLOGIC_MAILBOXES;
+    } while (mbi != HOSTDATA(SCpnt->host)->last_mbi_used);
+    sti();
+
+    if (mb[mbi].status != MBX_NOT_IN_USE) {
+	buslogic_printk("Lost interrupt discovered on irq %d - attempting to recover\n",
+			SCpnt->host->irq);
+	{
+	    int intval[3];
+
+	    intval[0] = SCpnt->host->irq;
+	    buslogic_interrupt((int)&intval[2]);
+	    return SCSI_ABORT_SUCCESS;
+	}
+    }
+
+    /* OK, no lost interrupt.  Try looking to see how many pending commands we
+       think we have. */
+    for (i = 0; i < BUSLOGIC_MAILBOXES; i++)
+	if (HOSTDATA(SCpnt->host)->SCint[i]) {
+	    if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+		buslogic_printk("Timed out command pending for %4.4X\n",
+				SCpnt->request.dev);
+		if (HOSTDATA(SCpnt->host)->mb[i].status != MBX_NOT_IN_USE) {
+		    buslogic_printk("OGMB still full - restarting\n");
+		    buslogic_out(SCpnt->host->io_port, buscmd, sizeof buscmd);
+		}
+	    } else
+		buslogic_printk("Other pending command %4.4X\n",
+				SCpnt->request.dev);
+	}
+
+#if (BUSLOGIC_DEBUG & BD_ABORT)
+    buslogic_printk("buslogic_abort\n");
+#endif
+
+#if 1
+    /* This section of code should be used carefully - some devices cannot
+       abort a command, and this merely makes it worse. */
+    cli();
+    for (mbo = 0; mbo < BUSLOGIC_MAILBOXES; mbo++)
+	if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) {
+	    HOSTDATA(SCpnt->host)->mb[mbo].status = MBX_ACTION_ABORT;
+	    buslogic_out(SCpnt->host->io_port, buscmd, sizeof buscmd);
+	    break;
+	}
+    sti();
+#endif
+
+    return SCSI_ABORT_PENDING;
+}
+
+/* We do not implement a reset function here, but the upper level code assumes
+   that it will get some kind of response for the command in SCpnt.  We must
+   oblige, or the command will hang the SCSI system. */
+int buslogic_reset(Scsi_Cmnd *SCpnt)
+{
+#if BUSLOGIC_DEBUG
+    buslogic_printk("buslogic_reset\n");
+#endif
+    return SCSI_RESET_SNOOZE;
+}
+
+int buslogic_biosparam(int size, int dev, int *ip)
+{
+    /* ??? This is wrong if disk is configured for > 1G mapping.
+       Unfortunately, unlike UltraStor, I see know way of determining whether
+       > 1G mapping has been enabled. */
+#ifdef CONFIG_BLK_DEV_SD
+    int translation_algorithm;
+    Scsi_Device *disk;
+
+    disk = rscsi_disks[MINOR(dev) >> 4].device;
+    translation_algorithm = HOSTDATA(disk->host)->bios_translation;
+    /* ??? Should this be > 1024, or >= 1024?  Enquiring minds want to know. */
+    if ((size >> 11) > 1024
+	&& translation_algorithm == BIOS_TRANSLATION_25563) {
+	/* Please verify that this is the same as what DOS returns */
+	ip[0] = 255;
+	ip[1] = 63;
+	ip[2] = size / 255 / 63;
+    } else {
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+    }
+/*    if (ip[2] > 1024)
+      ip[2] = 1024; */
+#endif
+    return 0;
+}
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/buslogic.h linux/drivers/scsi/buslogic.h
--- v1.1.14/linux/drivers/scsi/buslogic.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/buslogic.h	Tue May 24 09:19:22 1994
@@ -0,0 +1,175 @@
+/*
+ *	buslogic.h	(C) 1993 David B. Gentzel
+ *	Low-level scsi driver for BusLogic adapters
+ *	by David B. Gentzel, Whitfield Software Services, Carnegie, PA
+ *	    (gentzel@nova.enet.dec.com)
+ *	Thanks to BusLogic for providing the necessary documentation
+ *
+ *	The original version of this driver was derived from aha1542.[ch] which
+ *	is Copyright (C) 1992 Tommy Thorn.  Much has been reworked, but most of
+ *	basic structure and substantial chunks of code still remain.
+ */
+
+#ifndef _BUSLOGIC_H
+
+int buslogic_detect(int);
+int buslogic_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int buslogic_abort(Scsi_Cmnd *);
+const char *buslogic_info(void);
+int buslogic_reset(Scsi_Cmnd *);
+int buslogic_biosparam(int, int, int *);
+
+#define BUSLOGIC_CMDLUN 1	/* ??? */
+
+#define BUSLOGIC { "BusLogic",			\
+		   buslogic_detect,		\
+		   buslogic_info,		\
+		   0,	/* no command func */	\
+		   buslogic_queuecommand,	\
+		   buslogic_abort,		\
+		   buslogic_reset,		\
+		   0,	/* slave_attach NYI */	\
+		   buslogic_biosparam,		\
+		   0,	/* set by driver */	\
+		   0,	/* set by driver */	\
+		   0,	/* set by driver */	\
+		   BUSLOGIC_CMDLUN,		\
+		   0,				\
+		   0,	/* set by driver */	\
+		   ENABLE_CLUSTERING		\
+		 }
+
+#ifdef BUSLOGIC_PRIVATE_H
+
+/* ??? These don't really belong here */
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
+
+#define PACKED __attribute__((packed))
+
+#define BD_ABORT	0x0001
+#define BD_COMMAND	0x0002
+#define BD_DETECT	0x0004
+#define BD_INTERRUPT	0x0008
+#define BD_RESET	0x0010
+
+/* I/O Port interface */
+/* READ */
+#define STATUS(base) (base)
+#define DACT 0x80		/* Diagnostic Active */
+#define DFAIL 0x40		/* Diagonostic Failure */
+#define INREQ 0x20		/* Initialization Required */
+#define HARDY 0x10		/* Host Adapter Ready */
+#define CPRBSY 0x08		/* Command/Parameter Register Busy */
+#define DIRRDY 0x04		/* Data In Register Ready */
+#define CMDINV 0x01		/* Command Invalid */
+#define STATMASK 0xFD		/* 0x02 is reserved */
+
+#define DATA_IN(base) (STATUS(base) + 1)
+
+#define INTERRUPT(base) (STATUS(base) + 2)
+#define INTV 0x80		/* Interrupt Valid */
+#define RSTS 0x08		/* SCSI Reset State */
+#define CMDC 0x04		/* Command Complete */
+#define MBOR 0x02		/* Mailbox Out Ready */
+#define IMBL 0x01		/* Incoming Mailbox Loaded */
+#define INTRMASK 0x8F		/* 0x70 are reserved */
+
+/* WRITE */
+#define CONTROL(base) STATUS(base)
+#define RHARD 0x80		/* Hard Reset */
+#define RSOFT 0x40		/* Soft Reset */
+#define RINT 0x20		/* Interrupt Reset */
+#define RSBUS 0x10		/* SCSI Bus Reset */
+
+#define COMMAND_PARAMETER(base) (STATUS(base) + 1)
+#define CMD_TSTCMDCINT 0x00	/* Test CMDC Interrupt */
+#define CMD_INITMB 0x01		/* Initialize Mailbox */
+#define CMD_START_SCSI 0x02	/* Start Mailbox */
+#define CMD_START_BIOS 0x03	/* Start BIOS */
+#define CMD_INQUIRY 0x04	/* Inquire Board ID */
+#define CMD_ENBOMBRINT 0x05	/* Enable OMBR Interrupt */
+#define CMD_SETSELTIMOUT 0x06	/* Set SCSI Selection Time-Out */
+#define CMD_BUSON_TIME 0x07	/* Set Bus-On Time */
+#define CMD_BUSOFF_TIME 0x08	/* Set Bus-Off Time */
+#define CMD_BUSXFR_RATE 0x09	/* Set Bus Transfer Rate */
+#define CMD_INQ_DEVICES 0x0A	/* Inquire Installed Devices */
+#define CMD_RETCONF 0x0B	/* Return Configuration */
+#define CMD_TARGET_MODE 0x0C	/* Set Target Mode */
+#define CMD_INQ_SETUP_INFO 0x0D	/* Inquire Set-up Information */
+#define CMD_WRITE_LCL_RAM 0x1A	/* Write Adapter Local RAM */
+#define CMD_READ_LCL_RAM 0x1B	/* Read Adapter Local RAM */
+#define CMD_WRITE_BM_FIFO 0x1C	/* Write Bus Master Chip FIFO */
+#define CMD_READ_BM_FIFO 0x1D	/* Read Bus Master Chip FIFO */
+#define CMD_ECHO 0x1F		/* Echo Data Byte */
+#define CMD_HA_DIAG 0x20	/* Host Adapter Diagnostic */
+#define CMD_HA_OPTIONS 0x21	/* Host Adapter Options */
+#define CMD_INITEXTMB 0x81	/* Initialize Extended Mailbox */
+#define CMD_INQEXTSETUP 0x8D	/* Inquire Extended Set-up Information */
+#define CMD_WRITE_INQ_BUF 0x9A	/* Write Inquery Data Buffer
+				   (Target Mode Only) */
+#define CMD_READ_INQ_BUF 0x9B	/* Read Inquery Data Buffer
+				   (Target Mode Only) */
+
+#define MBX_NOT_IN_USE 0x00
+#define MBX_ACTION_START 0x01
+#define MBX_ACTION_ABORT 0x02
+#define MBX_COMPLETION_OK 0x01
+#define MBX_COMPLETION_ABORTED 0x02
+#define MBX_COMPLETION_NOT_FOUND 0x03
+#define MBX_COMPLETION_ERROR 0x04
+
+/* Mailbox Definition */
+struct mailbox {
+    void *ccbptr;		/* lsb, ..., msb */
+    unsigned char btstat;
+    unsigned char sdstat;
+    unsigned char reserved;
+    unsigned char status;	/* Command/Status */
+};
+
+/* This is used with scatter-gather */
+struct chain {
+    unsigned long datalen;	/* Size of this part of chain */
+    void *dataptr;		/* Location of data */
+};
+
+#define MAX_CDB 12
+
+struct ccb {			/* Command Control Block */
+    unsigned char op;		/* Command Control Block Operation Code */
+    unsigned char dir;
+    unsigned char cdblen;	/* SCSI Command Length */
+    unsigned char rsalen;	/* Request Sense Allocation Length/Disable */
+    unsigned long datalen;	/* Data Length (msb, ..., lsb) */
+    void *dataptr;		/* Data Pointer */
+    unsigned char reserved[2];
+    unsigned char hastat;	/* Host Adapter Status (HASTAT) */
+    unsigned char tarstat;	/* Target Device Status */
+    unsigned char id;
+    unsigned char lun;
+    unsigned char cdb[MAX_CDB];
+    unsigned char ccbcontrol;
+    unsigned char commlinkid;	/* Command Linking Identifier */
+    void *linkptr;		/* Link Pointer */
+    void *senseptr;
+};
+
+#define CCB_OP_INIT 0x00	/* Initiator CCB */
+#define CCB_OP_TARG 0x01	/* Target CCB */
+#define CCB_OP_INIT_SG 0x02	/* Initiator CCB with scatter-gather */
+#define CCB_OP_INIT_R 0x03	/* Initiator CCB with residual data length
+				   returned */
+#define CCB_OP_INIT_SG_R 0x04	/* Initiator CCB with scatter-gather and
+				   residual data length returned */
+#define CCB_OP_BUS_RESET 0x81	/* SCSI bus device reset */
+
+#endif
+
+#endif
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c
--- v1.1.14/linux/drivers/scsi/constants.c	Tue Feb 15 07:26:30 1994
+++ linux/drivers/scsi/constants.c	Tue May 24 09:19:19 1994
@@ -73,7 +73,7 @@
 static const char vendor[] = "VENDOR SPECIFIC";
 
 static void print_opcode(int opcode) {
-  char **table = commands[ group(opcode) ];
+  const char **table = commands[ group(opcode) ];
   switch ((int) table) {
   case RESERVED_GROUP:
   	printk("%s(0x%02x) ", reserved, opcode); 
@@ -351,8 +351,8 @@
 static char *snstext[] = {
 	"None","Recovered Error","Not Ready","Medium Error","Hardware Error",
 	"Illegal Request","Unit Attention","Data Protect","Blank Check",
-	"Key=E","Key=F","Filemark","End-Of-Medium","Incorrect Block Length",
-	"14","15"};
+	"Key=9","Copy Aborted","Aborted Command","End-Of-Medium",
+	"Volume Overflow", "Miscompare", "Key=15"};
 #endif
 
 
@@ -394,9 +394,6 @@
 	  printk("%s error ", error);
 	  
 #if (CONSTANTS & CONST_SENSE)
-	  if (sense_buffer[2] & 0x80) printk( "FMK ");
-	  if (sense_buffer[2] & 0x40) printk( "EOM ");
-	  if (sense_buffer[2] & 0x20) printk( "ILI ");
 	  printk( "%s%x: sense key %s\n", devclass, dev, snstext[sense_buffer[2] & 0x0f]);
 #else
 	  printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]);
@@ -437,9 +434,12 @@
 	}
 	
       done:
+#if !(CONSTANTS & CONST_SENSE)
+	printk("Raw sense data:");
 	for (i = 0; i < s; ++i) 
 	  printk("0x%02x ", sense_buffer[i]);
-
+	printk("\n");
+#endif
 	return;
 }
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v1.1.14/linux/drivers/scsi/fdomain.c	Tue Apr 19 10:53:18 1994
+++ linux/drivers/scsi/fdomain.c	Tue May 24 09:19:19 1994
@@ -68,7 +68,7 @@
  revision 10h, October 17, 1991)
 
  Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric
- Youngdale (eric@tantalus.nrl.navy.mil), 1992.
+ Youngdale (ericy@cais.com), 1992.
 
  Private communication, Tuong Le (Future Domain Engineering department),
  1994. (Disk geometry computations for Future Domain BIOS version 3.4, and
@@ -1394,9 +1394,8 @@
 		 inb( port_base + Configuration2 ) );
 }
 
-int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code )
+int fdomain_16x0_abort( Scsi_Cmnd *SCpnt)
 {
-
 #if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
    printk( "Future Domain: Abort " );
 #endif
@@ -1407,11 +1406,7 @@
       printk( " (not in command)\n" );
 #endif
       sti();
-      return 0;
-   } else {
-#if EVERY_ACCESS || ERRORS_ONLY
-      printk( " code = %d\n", code );
-#endif
+      return SCSI_ABORT_NOT_RUNNING;
    }
 
 #if DEBUG_ABORT
@@ -1422,14 +1417,14 @@
 
    current_SC->SCp.phase |= aborted;
 
-   current_SC->result = code ? code : DID_ABORT;
+   current_SC->result = DID_ABORT << 16;
 
    sti();
    
    /* Aborts are not done well. . . */
-   my_done( code << 16 );
+   my_done( DID_ABORT << 16 );
 
-   return 0;
+   return SCSI_ABORT_SUCCESS;
 }
 
 int fdomain_16x0_reset( Scsi_Cmnd *SCpnt )
@@ -1458,10 +1453,7 @@
       is probably hosed at this point.  We will, however, try to keep
       things going by informing the high-level code that we need help. */
 
-   if (SCpnt)
-	 SCpnt->flags |= NEEDS_JUMPSTART;
-   
-   return 0;
+   return SCSI_RESET_WAKEUP;
 }
 
 #ifdef CONFIG_BLK_DEV_SD
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/fdomain.h linux/drivers/scsi/fdomain.h
--- v1.1.14/linux/drivers/scsi/fdomain.h	Tue Apr 19 10:52:15 1994
+++ linux/drivers/scsi/fdomain.h	Tue May 24 09:19:19 1994
@@ -27,7 +27,7 @@
 
 int        fdomain_16x0_detect( int );
 int        fdomain_16x0_command( Scsi_Cmnd * );
-int        fdomain_16x0_abort( Scsi_Cmnd *, int );
+int        fdomain_16x0_abort( Scsi_Cmnd *);
 const char *fdomain_16x0_info( void );
 int        fdomain_16x0_reset( Scsi_Cmnd * ); 
 int        fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
@@ -47,5 +47,5 @@
 		        fdomain_16x0_reset,               \
 		        NULL,                             \
 		        fdomain_16x0_biosparam,           \
-		        1, 6, 64 /* SG_NONE */, 1 ,0, 0 }
+		        1, 6, 64 /* SG_NONE */, 1 ,0, 0, DISABLE_CLUSTERING}
 #endif
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/g_NCR5380.h linux/drivers/scsi/g_NCR5380.h
--- v1.1.14/linux/drivers/scsi/g_NCR5380.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/g_NCR5380.h	Tue May 24 09:19:19 1994
@@ -33,7 +33,7 @@
 
 
 #ifndef ASM
-int generic_NCR5380_abort(Scsi_Cmnd *, int);
+int generic_NCR5380_abort(Scsi_Cmnd *);
 int generic_NCR5380_detect(int);
 const char *generic_NCR5380_info(void);
 int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
@@ -59,7 +59,7 @@
 	generic_NCR5380_queue_command, generic_NCR5380_abort, 		\
 	generic_NCR5380_reset, NULL, 					\
 	NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,		\
-	/* cmd per lun */ CMD_PER_LUN , 0, 0}
+	/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
 
 #else
 #define NCR5380_implementation_fields \
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.1.14/linux/drivers/scsi/hosts.c	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/hosts.c	Tue May 24 09:19:20 1994
@@ -39,6 +39,10 @@
 #include "aha1740.h"
 #endif
 
+#ifdef CONFIG_SCSI_BUSLOGIC
+#include "buslogic.h"
+#endif
+
 #ifdef CONFIG_SCSI_FUTURE_DOMAIN
 #include "fdomain.h"
 #endif
@@ -47,6 +51,10 @@
 #include "g_NCR5380.h"
 #endif
 
+#ifdef CONFIG_SCSI_IN2000
+#include "in2000.h"
+#endif
+
 #ifdef CONFIG_SCSI_PAS16
 #include "pas16.h"
 #endif
@@ -105,6 +113,10 @@
 #ifdef CONFIG_SCSI_AHA152X
 	AHA152X,
 #endif
+/* Buslogic must come before aha1542.c */
+#ifdef CONFIG_SCSI_BUSLOGIC
+	BUSLOGIC,
+#endif
 #ifdef CONFIG_SCSI_AHA1542
 	AHA1542,
 #endif
@@ -114,6 +126,9 @@
 #ifdef CONFIG_SCSI_FUTURE_DOMAIN
 	FDOMAIN_16X0,
 #endif
+#ifdef CONFIG_SCSI_IN2000
+	IN2000,
+#endif
 #ifdef CONFIG_SCSI_GENERIC_NCR5380
         GENERIC_NCR5380,
 #endif
@@ -181,6 +196,7 @@
 	retval->host_queue = NULL;	
 	retval->host_wait = NULL;	
 	retval->last_reset = 0;	
+	retval->irq = 0;
 	retval->hostt = &scsi_hosts[i];	
 	retval->next = NULL;
 #ifdef DEBUG
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v1.1.14/linux/drivers/scsi/hosts.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/hosts.h	Tue May 24 09:19:22 1994
@@ -21,16 +21,11 @@
 */
 
 
-/* A jumpstart is often required when the reset() function is called -
-   many host adapters cannot do this cleanly, so they do nothing at all.
-   To get the command going again, these routines set this bit in the flags
-   so that a scsi_request_sense() is executed, and the command starts running
-   again */
-
-#define NEEDS_JUMPSTART 0x20
-
 #define SG_NONE 0
-#define SG_ALL 0xff
+#define SG_ALL 0x7fff
+
+#define DISABLE_CLUSTERING 0
+#define ENABLE_CLUSTERING 1
 
 /* The various choices mean:
    NONE: Self evident.  Host adapter is not capable of scatter-gather.
@@ -109,7 +104,11 @@
 	/*
 		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.  If non-zero, the code passed to it 
+		abortion was successful.  The field SCpnt->abort reason
+		can be filled in with the appropriate reason why we wanted
+		the abort in the first place, and this will be used
+		in the mid-level code instead of the host_byte().
+		If non-zero, the code passed to it 
 		will be used as the return code, otherwise 
 		DID_ABORT  should be returned.
 
@@ -117,7 +116,7 @@
 		resetting the bus, etc.  if necessary. 
 	*/
 
-	int (* abort)(Scsi_Cmnd *, int);
+	int (* abort)(Scsi_Cmnd *);
 
 	/*
 		The reset function will reset the SCSI bus.  Any executing 
@@ -192,6 +191,15 @@
 	  true if this host adapter uses unchecked DMA onto an ISA bus.
 	*/
 	unsigned unchecked_isa_dma:1;
+	/*
+	  true if this host adapter can make good use of clustering.
+	  I originally thought that if the tablesize was large that it
+	  was a waste of CPU cycles to prepare a cluster list, but
+	  it works out that the Buslogic is faster if you use a smaller
+	  number of segments (i.e. use clustering).  I guess it is
+	  inefficient.
+	*/
+	unsigned use_clustering:1;
 	} Scsi_Host_Template;
 
 /*
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/pas16.h linux/drivers/scsi/pas16.h
--- v1.1.14/linux/drivers/scsi/pas16.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/pas16.h	Tue May 24 09:19:20 1994
@@ -114,7 +114,7 @@
 
 
 #ifndef ASM
-int pas16_abort(Scsi_Cmnd *, int);
+int pas16_abort(Scsi_Cmnd *);
 int pas16_biosparam(int, int, int*);
 int pas16_detect(int);
 const char *pas16_info(void);
@@ -145,7 +145,7 @@
 	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}
+	/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
 
 #else
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.1.14/linux/drivers/scsi/scsi.c	Tue Apr 19 10:52:47 1994
+++ linux/drivers/scsi/scsi.c	Tue May 24 09:19:20 1994
@@ -1,5 +1,7 @@
 /*
  *	scsi.c Copyright (C) 1992 Drew Eckhardt 
+ *	       Copyright (C) 1993, 1994 Eric Youngdale
+ *
  *	generic mid-level SCSI driver by
  *		Drew Eckhardt 
  *
@@ -10,7 +12,7 @@
  *		Tommy Thorn <tthorn>
  *		Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
  * 
- *       Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
+ *       Modified by Eric Youngdale ericy@cais.com to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  */
@@ -19,6 +21,7 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
+#include <asm/irq.h>
 
 #include "../block/blk.h"
 #include "scsi.h"
@@ -84,8 +87,8 @@
 #define WAS_TIMEDOUT 	0x02
 #define WAS_SENSE	0x04
 #define IS_RESETTING	0x08
-#define ASKED_FOR_SENSE 0x10
-/* #define NEEDS_JUMPSTART 0x20  defined in hosts.h */
+#define IS_ABORTING	0x10
+#define ASKED_FOR_SENSE 0x20
 
 /*
  *	This is the number  of clock ticks we should wait before we time out 
@@ -97,6 +100,11 @@
  *	respectively.
  */
 
+#ifdef DEBUG_TIMEOUT
+static void scsi_dump_status(void);
+#endif
+
+
 #ifdef DEBUG
 	#define SCSI_TIMEOUT 500
 #else
@@ -350,6 +358,8 @@
 			  type = -1;
 		      }
 
+		    scsi_devices[NR_SCSI_DEVICES].soft_reset = 
+		      (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
 		    scsi_devices[NR_SCSI_DEVICES].random = 
 		      (type == TYPE_TAPE) ? 0 : 1;
 		    scsi_devices[NR_SCSI_DEVICES].type = type;
@@ -503,9 +513,13 @@
  	switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
 		{
 		case NORMAL_TIMEOUT:
-			if (!in_scan)
-			      printk("SCSI host %d timed out - aborting command\n",
-				SCpnt->host->host_no);
+			if (!in_scan) {
+			  printk("SCSI host %d timed out - aborting command\n",
+				 SCpnt->host->host_no);
+#ifdef DEBUG_TIMEOUT
+			  scsi_dump_status();
+#endif
+			}
 			
 			if (!scsi_abort	(SCpnt, DID_TIME_OUT))
 				return;				
@@ -516,7 +530,13 @@
 				return;
 		case IN_RESET:
 		case (IN_ABORT | IN_RESET):
-			panic("Unable to reset scsi host %d\n",SCpnt->host->host_no);
+		  /* 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("Unable to reset scsi host %d - ",SCpnt->host->host_no);
+			printk("probably a SCSI bus hang.\n");
+			return;
+
 		default:
 			INTERNAL_ERROR;
 		}
@@ -739,11 +759,26 @@
 
         if (host->hostt->can_queue)
 		{
+		  extern unsigned long intr_count;
 #ifdef DEBUG
 	printk("queuecommand : routine at %08x\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
+		     any given time, and we can only be in the interrupt
+		     handler and the queuecommand function at the same time
+		     when queuecommand is called while servicing the
+		     interrupt. */
+
+		if(!intr_count && SCpnt->host->irq)
+		  disable_irq(SCpnt->host->irq);
+
                 host->hostt->queuecommand (SCpnt, scsi_done);
+
+		if(!intr_count && SCpnt->host->irq)
+		  enable_irq(SCpnt->host->irq);
 		}
 	else
 		{
@@ -876,6 +911,7 @@
 	/* Start the timer ticking.  */
 
 	SCpnt->internal_timeout = 0;
+	SCpnt->abort_reason = 0;
 	internal_cmnd (SCpnt);
 
 #ifdef DEBUG
@@ -904,10 +940,12 @@
 	printk("performing request sense\n");
 #endif
 	
+#if 0  /* FIXME - remove this when done */
 	if(SCpnt->flags & NEEDS_JUMPSTART) {
 	  SCpnt->flags &= ~NEEDS_JUMPSTART;
 	  scsi_request_sense (SCpnt);
 	};
+#endif
 }
 	
 	
@@ -997,6 +1035,18 @@
 	int result = SCpnt->result;
 	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
@@ -1008,13 +1058,6 @@
 	switch (host_byte(result))	
 	{
 	case DID_OK:
-		if (SCpnt->flags & IS_RESETTING)
-			{
-			SCpnt->flags &= ~IS_RESETTING;
-			status = REDO;
-			break;
-			}
-
 		if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
 			/* Failed to obtain sense information */
 			{
@@ -1154,7 +1197,7 @@
 	printk("Host returned DID_TIME_OUT - ");
 #endif
 
-		if (SCpnt->flags & WAS_TIMEDOUT)	
+		if (SCpnt->flags & WAS_TIMEDOUT)
 			{
 #ifdef DEBUG
 	printk("Aborting\n");
@@ -1167,6 +1210,7 @@
 			printk ("Retrying.\n");
 #endif
 			SCpnt->flags  |= WAS_TIMEDOUT;
+			SCpnt->internal_timeout &= ~IN_ABORT;
 			status = REDO;
 			}
 		break;
@@ -1189,6 +1233,13 @@
 		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)) {
@@ -1305,7 +1356,7 @@
 
 int scsi_abort (Scsi_Cmnd * SCpnt, int why)
 	{
-	int temp, oldto;
+	int oldto;
 	struct Scsi_Host * host = SCpnt->host;
 	
 	while(1)	
@@ -1321,22 +1372,67 @@
 			SCpnt->internal_timeout |= IN_ABORT;
 			oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
 
-			
-			sti();
-			if (!host->host_busy || !host->hostt->abort(SCpnt, why))
-				temp =  0;
-			else
-				temp = 1;
+			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 appears to have died when"
+				 " the bus was reset\n", SCpnt->target, SCpnt->lun);
+			}
 			
-			cli();
-			SCpnt->internal_timeout &= ~IN_ABORT;
-			update_timeout(SCpnt, oldto);
 			sti();
-			return temp;
+			if (!host->host_busy) {
+			  SCpnt->internal_timeout &= ~IN_ABORT;
+			  update_timeout(SCpnt, oldto);
+			  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) {
+			    cli();
+			    SCpnt->internal_timeout &= ~IN_ABORT;
+			    if(SCpnt->flags & WAS_TIMEDOUT) {
+			      sti();
+			      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);
+			    }
+			    sti();
+			  }
+			  return 0;
+			case SCSI_ABORT_PENDING:
+			  if(why != DID_TIME_OUT) {
+			    cli();
+			    update_timeout(SCpnt, oldto);
+			    sti();
+			  }
+			  return 0;
+			case SCSI_ABORT_SUCCESS:
+			  /* We should have already aborted this one.  No
+			     need to adjust timeout */
+			case SCSI_ABORT_NOT_RUNNING:
+			  SCpnt->internal_timeout &= ~IN_ABORT;
+			  return 0;
+			case SCSI_ABORT_ERROR:
+			default:
+			  SCpnt->internal_timeout &= ~IN_ABORT;
+			  return 1;
+			}
+		      }
+	      }	
+      }
+     
 int scsi_reset (Scsi_Cmnd * SCpnt)
 	{
 	int temp, oldto;
@@ -1363,10 +1459,14 @@
 				sti();
 				SCpnt1 = host->host_queue;
 				while(SCpnt1) {
-				  if ((SCpnt1->request.dev > 0) &&
-				      !(SCpnt1->flags & IS_RESETTING) && 
+				  if (SCpnt1->request.dev > 0) {
+#if 0				  
+				    if (!(SCpnt1->flags & IS_RESETTING) && 
 				      !(SCpnt1->internal_timeout & IN_ABORT))
 				    scsi_abort(SCpnt1, DID_RESET);
+#endif
+				    SCpnt1->flags |= IS_RESETTING;
+				  }
 				  SCpnt1 = SCpnt1->next;
 				};
 
@@ -1381,11 +1481,35 @@
 				host->last_reset = jiffies;
 				host->host_busy--;
 				}
+
+			switch(temp) {
+			case SCSI_RESET_SUCCESS:
+			  cli();
+			  SCpnt->internal_timeout &= ~IN_RESET;
+			  update_timeout(SCpnt, oldto);
+			  sti();
+			  return 0;
+			case SCSI_RESET_PENDING:
+			  return 0;
+			case SCSI_RESET_WAKEUP:
+			  SCpnt->internal_timeout &= ~IN_RESET;
+			  scsi_request_sense (SCpnt);
+			  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. */
+			  cli();
+			  SCpnt->internal_timeout &= ~IN_RESET;
+			  update_timeout(SCpnt, 0);
+			  sti();
+			  /* If you snooze, you lose... */
+			case SCSI_RESET_ERROR:
+			default:
+			  return 1;
+			}
 	
-			cli();
-			SCpnt->internal_timeout &= ~IN_RESET;
-			update_timeout(SCpnt, oldto);
-			sti();
 			return temp;	
 			}
 		}
@@ -1405,6 +1529,7 @@
 	do 	{	
 		cli();
 
+		update_timeout(NULL, 0);
 	/*
 		Find all timers such that they have 0 or negative (shouldn't happen)
 		time remaining on them.
@@ -1412,9 +1537,8 @@
 			
 		timed_out = 0;
 		for(host = scsi_hostlist; host; host = host->next) {
-		  SCpnt = host->host_queue;
-		  while (SCpnt){
-		    if (SCpnt->timeout > 0 && SCpnt->timeout <= time_elapsed)
+		  for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
+		    if (SCpnt->timeout == -1)
 		      {
 			sti();
 			SCpnt->timeout = 0;
@@ -1422,10 +1546,7 @@
 			++timed_out; 
 			cli();
 		      }
-		  SCpnt =  SCpnt->next;
-		  };
 		};
-		update_timeout(NULL, 0);
 	      } while (timed_out);	
 	sti();
       }
@@ -1468,14 +1589,14 @@
 
 	least = 0xffffffff;
 
-	for(host = scsi_hostlist; host; host = host->next) {
-	  SCpnt = host->host_queue;
-	  while (SCpnt){
-	    if (SCpnt->timeout > 0 && (SCpnt->timeout -= used) < least)
-	      least = SCpnt->timeout;
-	    SCpnt =  SCpnt->next;
-	  };
-	};
+	for(host = scsi_hostlist; host; host = host->next)
+	  for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
+	    if (SCpnt->timeout > 0) {
+	      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 
@@ -1617,6 +1738,7 @@
 	  if(scsi_devices[i].type != -1){
 	    for(j=0;j<scsi_devices[i].host->hostt->cmd_per_lun;j++){
 	      SCpnt->host = scsi_devices[i].host;
+	      SCpnt->device = &scsi_devices[i];
 	      SCpnt->target = scsi_devices[i].id;
 	      SCpnt->lun = scsi_devices[i].lun;
 	      SCpnt->index = i;
@@ -1724,3 +1846,62 @@
 	else
 	  printk("\n");
 }
+
+#ifdef DEBUG_TIMEOUT
+static void 
+scsi_dump_status(void)
+{
+  int i, i1;
+  Scsi_Cmnd * SCpnt;
+  printk("Dump of scsi parameters:\n");
+  SCpnt = last_cmnd;
+  for(i=0; i<NR_SCSI_DEVICES; i++)
+    for(i1=0; i1<scsi_devices[i].host->hostt->cmd_per_lun;i1++)
+      {
+	/*  (0) 0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x      */
+	printk("(%d) %d:%d:%d (%4.4x %d %d %d %d) (%d %d %x) (%d %d %d) %x %x %d %x\n",
+	       i, SCpnt->host->host_no,
+	       SCpnt->target,
+	       SCpnt->lun,
+	       SCpnt->request.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->request.waiting ? 
+		SCpnt->request.waiting->pid : 0),
+	       SCpnt->result);
+	SCpnt++;
+      };
+  printk("wait_for_request = %x\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("(%x %d %d %d %d %d) ",
+		 req->dev,
+		 req->cmd,
+		 req->sector,
+		 req->nr_sectors,
+		 req->current_nr_sectors,
+		 (req->waiting ? 
+		  req->waiting->pid : 0));
+	  req = req->next;
+	}
+	printk("\n");
+      }
+}
+#endif
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.1.14/linux/drivers/scsi/scsi.h	Tue Apr 19 10:52:47 1994
+++ linux/drivers/scsi/scsi.h	Tue May 24 09:19:20 1994
@@ -276,6 +276,7 @@
 	unsigned tagged_supported:1; /* Supports SCSI-II tagged queing */
 	unsigned tagged_queue:1;   /*SCSI-II tagged queing enabled */
 	unsigned disconnect:1;     /* can disconnect */
+	unsigned soft_reset:1;		/* Uses soft reset option */
 	unsigned char current_tag; /* current tag */
 } Scsi_Device;
 /*
@@ -315,6 +316,63 @@
 #define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
 
 
+/*
+ * 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.
+ */
+
+/* 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 */
+#define SCSI_RESET_SNOOZE 0
+
+/* 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. */
+#define SCSI_RESET_SUCCESS 1
+
+/* We called for an reset of this bus, and we should get an interrupt 
+   when this succeeds.  Each command should get it's own status
+   passed up to scsi_done, but this has not happened yet. */
+#define SCSI_RESET_PENDING 2
+
+/* 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 3
+
+/* Something went wrong, and we do not know how to fix it. */
+#define SCSI_RESET_ERROR 4
+
 void *   scsi_malloc(unsigned int);
 int      scsi_free(void *, unsigned int);
 extern unsigned int dma_free_sectors;   /* How much room do we have left */
@@ -340,6 +398,7 @@
 
 typedef struct scsi_cmnd {
 	struct Scsi_Host * host;
+	Scsi_Device * device;
 	unsigned char target, lun,  index;
 	struct scsi_cmnd *next, *prev;	
 
@@ -355,6 +414,8 @@
 				       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 */
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v1.1.14/linux/drivers/scsi/scsi_debug.c	Tue Apr 19 10:52:48 1994
+++ linux/drivers/scsi/scsi_debug.c	Tue May 24 09:19:22 1994
@@ -521,7 +521,7 @@
     return 1;
 }
 
-int scsi_debug_abort(Scsi_Cmnd * SCpnt,int i)
+int scsi_debug_abort(Scsi_Cmnd * SCpnt)
 {
     int j;
     void (*my_done)(Scsi_Cmnd *);
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h
--- v1.1.14/linux/drivers/scsi/scsi_debug.h	Tue Apr 19 10:52:48 1994
+++ linux/drivers/scsi/scsi_debug.h	Tue May 24 09:19:20 1994
@@ -23,5 +23,5 @@
 		scsi_debug_reset,				\
 		NULL,						\
 		scsi_debug_biosparam,				\
-		SCSI_DEBUG_MAILBOXES, 7, SG_ALL, 1, 0, 1}
+		SCSI_DEBUG_MAILBOXES, 7, SG_ALL, 1, 0, 1, ENABLE_CLUSTERING}
 #endif
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.1.14/linux/drivers/scsi/sd.c	Mon Apr 25 10:04:32 1994
+++ linux/drivers/scsi/sd.c	Tue May 24 09:19:20 1994
@@ -1,11 +1,12 @@
 /*
  *	sd.c Copyright (C) 1992 Drew Eckhardt 
+ *	     Copyright (C) 1993, 1994 Eric Youngdale
  *	Linux scsi disk driver by
  *		Drew Eckhardt 
  *
  *	<drew@colorado.edu>
  *
- *       Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
+ *       Modified by Eric Youngdale ericy@cais.com to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  */
@@ -40,7 +41,7 @@
 #define SD_TIMEOUT 300
 #define SD_MOD_TIMEOUT 750
 
-#define CLUSTERABLE_DEVICE(SC) (SC->host->sg_tablesize < 64 && \
+#define CLUSTERABLE_DEVICE(SC) (SC->host->hostt->use_clustering && \
 			    scsi_devices[SC->index].type != TYPE_MOD)
 
 struct hd_struct * sd;
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v1.1.14/linux/drivers/scsi/seagate.c	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/seagate.c	Tue May 24 09:19:20 1994
@@ -1546,14 +1546,11 @@
 	return retcode (st0x_aborted);
 	}
 
-int seagate_st0x_abort (Scsi_Cmnd * SCpnt, int code)
+int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
 	{
-	if (code)
-		st0x_aborted = code;
-	else
-		st0x_aborted = DID_ABORT;
-
-		return 0;
+	  st0x_aborted = DID_ABORT;
+	  
+	  return SCSI_ABORT_PENDING;
 	}
 
 /*
@@ -1590,8 +1587,7 @@
 #ifdef DEBUG
 	printk("SCSI bus reset.\n");
 #endif
-	if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
-	return 0;
+	return SCSI_RESET_PENDING;
 	}
 
 #ifdef CONFIG_BLK_DEV_SD
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/seagate.h linux/drivers/scsi/seagate.h
--- v1.1.14/linux/drivers/scsi/seagate.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/seagate.h	Tue May 24 09:19:21 1994
@@ -16,7 +16,7 @@
 int seagate_st0x_command(Scsi_Cmnd *);
 int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 
-int seagate_st0x_abort(Scsi_Cmnd *, int);
+int seagate_st0x_abort(Scsi_Cmnd *);
 const char *seagate_st0x_info(void);
 int seagate_st0x_reset(Scsi_Cmnd *); 
 
@@ -34,7 +34,7 @@
 			 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}
+			 1, 7, SG_ALL, 1, 0, 0, DISABLE_CLUSTERING}
 #endif
 
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.1.14/linux/drivers/scsi/sr.c	Tue Apr 19 10:52:49 1994
+++ linux/drivers/scsi/sr.c	Tue May 24 09:19:21 1994
@@ -1,5 +1,6 @@
 /*
- *      sr.c by David Giller
+ *      sr.c Copyright (C) 1992 David Giller
+ *	     Copyright (C) 1993, 1994 Eric Youngdale
  *
  *      adapted from:
  *	sd.c Copyright (C) 1992 Drew Eckhardt 
@@ -8,7 +9,7 @@
  *
  *	<drew@colorado.edu>
  *
- *       Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
+ *       Modified by Eric Youngdale ericy@cais.com to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  */
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/t128.h linux/drivers/scsi/t128.h
--- v1.1.14/linux/drivers/scsi/t128.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/t128.h	Tue May 24 09:19:21 1994
@@ -91,7 +91,7 @@
 #define T_DATA_REG_OFFSET	0x1e00	/* rw 512 bytes long */
 
 #ifndef ASM
-int t128_abort(Scsi_Cmnd *, int);
+int t128_abort(Scsi_Cmnd *);
 int t128_biosparam(int, int, int*);
 int t128_detect(int);
 const char *t128_info(void);
@@ -122,7 +122,7 @@
 	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}
+	/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
 
 #else
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v1.1.14/linux/drivers/scsi/ultrastor.c	Mon Jan 24 09:55:21 1994
+++ linux/drivers/scsi/ultrastor.c	Tue May 24 09:19:21 1994
@@ -6,7 +6,7 @@
  *  scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
  *  24F and multiple command support by John F. Carr (jfc@athena.mit.edu)
  *    John's work modified by Caleb Epstein (cae@jpmorgan.com) and 
- *    Eric Youngdale (eric@tantalus.nrl.navy.mil).
+ *    Eric Youngdale (ericy@cais.com).
  *	Thanks to UltraStor for providing the necessary documentation
  */
 
@@ -796,7 +796,7 @@
 
  */
 
-int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
+int ultrastor_abort(Scsi_Cmnd *SCpnt)
 {
 #if ULTRASTOR_DEBUG & UD_ABORT
     char out[108];
@@ -807,7 +807,8 @@
     unsigned char old_aborted;
     void (*done)(Scsi_Cmnd *);
 
-    if(config.slot) return 0;  /* Do not attempt an abort for the 24f */
+    if(config.slot) 
+      return SCSI_ABORT_SNOOZE;  /* Do not attempt an abort for the 24f */
 
     mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp;
     if (mscp_index >= ULTRASTOR_MAX_CMDS)
@@ -851,16 +852,16 @@
 	cli();
 	ultrastor_interrupt(0);
 	restore_flags(flags);
-	return 0;
+	return SCSI_ABORT_SUCCESS;  /* FIXME - is this correct? -ERY */
       }
 #endif
 
-    old_aborted = xchgb(code ? code : DID_ABORT, &config.aborted[mscp_index]);
+    old_aborted = xchgb(DID_ABORT, &config.aborted[mscp_index]);
 
     /* aborted == 0xff is the signal that queuecommand has not yet sent
        the command.  It will notice the new abort flag and fail.  */
     if (old_aborted == 0xff)
-	return 0;
+	return SCSI_ABORT_SUCCESS;
 
     /* On 24F, send an abort MSCP request.  The adapter will interrupt
        and the interrupt handler will call done.  */
@@ -879,7 +880,7 @@
 	printk(out, ogm_status, ogm_addr, icm_status, icm_addr);
 #endif
 	restore_flags(flags);
-	return 0;
+	return SCSI_ABORT_PENDING;
       }
 
 #if ULTRASTOR_DEBUG & UD_ABORT
@@ -891,13 +892,18 @@
        still be using it.  Setting SCint = 0 causes the interrupt
        handler to ignore the command.  */
 
+    /* FIXME - devices that implement soft resets will still be running
+       the command after a bus reset.  We would probably rather leave
+       the command in the queue.  The upper level code will automatically
+       leave the command in the active state instead of requeueing it. ERY */
+
 #if ULTRASTOR_DEBUG & UD_ABORT
     if (config.mscp[mscp_index].SCint != SCpnt)
 	printk("abort: command mismatch, %x != %x\n",
 	       config.mscp[mscp_index].SCint, SCpnt);
 #endif
     if (config.mscp[mscp_index].SCint == 0)
-	return 1;
+	return SCSI_ABORT_NOT_RUNNING;
 
     if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort");
     config.mscp[mscp_index].SCint = 0;
@@ -908,7 +914,7 @@
     done(SCpnt);
 
     /* Need to set a timeout here in case command never completes.  */
-    return 0;
+    return SCSI_ABORT_SUCCESS;
 
 }
 
@@ -920,10 +926,8 @@
     printk("US14F: reset: called\n");
 #endif
 
-    if(config.slot) {
-      if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
-      return 0;  /* Do not attempt a reset for the 24f */
-    };
+    if(config.slot)
+      return SCSI_RESET_SNOOZE;  /* Do not attempt a reset for the 24f */
 
     save_flags(flags);
     cli();
@@ -958,6 +962,9 @@
       }
 #endif
 
+    /* FIXME - if the device implements soft resets, then the command
+       will still be running.  ERY */
+
     memset((unsigned char *)config.aborted, 0, sizeof config.aborted);
 #if ULTRASTOR_MAX_CMDS == 1
     config.mscp_busy = 0;
@@ -966,7 +973,7 @@
 #endif
 
     restore_flags(flags);
-    return 0;
+    return SCSI_RESET_SUCCESS;
 
 }
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/ultrastor.h linux/drivers/scsi/ultrastor.h
--- v1.1.14/linux/drivers/scsi/ultrastor.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/ultrastor.h	Tue May 24 09:19:21 1994
@@ -16,7 +16,7 @@
 int ultrastor_detect(int);
 const char *ultrastor_info(void);
 int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int ultrastor_abort(Scsi_Cmnd *, int);
+int ultrastor_abort(Scsi_Cmnd *);
 int ultrastor_reset(Scsi_Cmnd *);
 int ultrastor_biosparam(int, int, int *);
 
@@ -31,7 +31,8 @@
     { "UltraStor 14F/24F/34F", ultrastor_detect, 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 }
+      ULTRASTOR_14F_MAX_SG, ULTRASTOR_MAX_CMDS_PER_LUN, 0, 1, \
+	ENABLE_CLUSTERING }
 
 
 #ifdef ULTRASTOR_PRIVATE
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v1.1.14/linux/drivers/scsi/wd7000.c	Mon May 23 12:14:24 1994
+++ linux/drivers/scsi/wd7000.c	Tue May 24 09:19:21 1994
@@ -1185,18 +1185,17 @@
 /*
  *  I have absolutely NO idea how to do an abort with the WD7000...
  */
-int wd7000_abort(Scsi_Cmnd * SCpnt, int i)
+int wd7000_abort(Scsi_Cmnd * SCpnt)
 {
-#ifdef DEBUG
-    printk("wd7000_abort: Scsi_Cmnd = 0x%06x, code = %d ", (int) SCpnt, i);
-    printk("id %d lun %d cdb", SCpnt->target, SCpnt->lun);
-    {
-        int j;  unchar *cdbj = (unchar *) SCpnt->cmnd;
-	for (j=0; j < COMMAND_SIZE(*cdbj);  j++)  printk(" %02x", *(cdbj++));
-	printk(" result %08x\n", SCpnt->result);
+    Adapter *host = (Adapter *) SCpnt->host->hostdata;
+
+    if (inb(host->iobase+ASC_STAT) & INT_IM)  {
+        printk("wd7000_abort: lost interrupt\n");
+	wd7000_intr_handle(host->irq);
+	return SCSI_ABORT_SUCCESS;
     }
-#endif
-    return 0;
+
+    return SCSI_ABORT_SNOOZE;
 }
 
 
@@ -1205,21 +1204,7 @@
  */
 int wd7000_reset(Scsi_Cmnd * SCpnt)
 {
-#ifdef DEBUG
-    printk("wd7000_reset: Scsi_Cmnd = 0x%06x ", (int) SCpnt);
-    if (SCpnt)  {
-        printk("id %d lun %d cdb", SCpnt->target, SCpnt->lun);
-	{
-	    int j;  unchar *cdbj = (unchar *) SCpnt->cmnd;
-	    for (j=0; j < COMMAND_SIZE(*cdbj);  j++)
-	        printk(" %02x", *(cdbj++));
-	    printk(" result %08x", SCpnt->result);
-	}
-    }
-    printk("\n");
-#endif
-    if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
-    return 0;
+    return SCSI_RESET_SNOOZE;
 }
 
 
diff -u --recursive --new-file v1.1.14/linux/drivers/scsi/wd7000.h linux/drivers/scsi/wd7000.h
--- v1.1.14/linux/drivers/scsi/wd7000.h	Mon May 23 12:14:24 1994
+++ linux/drivers/scsi/wd7000.h	Tue May 24 09:19:21 1994
@@ -15,7 +15,7 @@
 int wd7000_detect(int);
 int wd7000_command(Scsi_Cmnd *);
 int wd7000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd7000_abort(Scsi_Cmnd *, int);
+int wd7000_abort(Scsi_Cmnd *);
 const char *wd7000_info(void);
 int wd7000_reset(Scsi_Cmnd *);
 int wd7000_biosparam(int, int, int*);
@@ -48,5 +48,5 @@
 	wd7000_reset,			\
 	NULL,                           \
 	wd7000_biosparam,               \
-	WD7000_Q, 7, WD7000_SG, 1, 0, 1}
+	WD7000_Q, 7, WD7000_SG, 1, 0, 1, ENABLE_CLUSTERING}
 #endif
diff -u --recursive --new-file v1.1.14/linux/fs/exec.c linux/fs/exec.c
--- v1.1.14/linux/fs/exec.c	Tue May 24 08:47:06 1994
+++ linux/fs/exec.c	Wed May 25 15:31:46 1994
@@ -572,6 +572,8 @@
 		last_task_used_math = NULL;
 	current->used_math = 0;
 	current->personality = 0;
+	current->lcall7 = no_lcall7;
+	current->signal_map = current->signal_invmap = ident_map;
 }
 
 /*
@@ -760,6 +762,25 @@
 	error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, &regs);
 	putname(filename);
 	return error;
+}
+
+/*
+ * signal mapping: this is the default identity mapping used for normal
+ * linux binaries (it's both the reverse and the normal map, of course)
+ */
+unsigned long ident_map[33] = {
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+	13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+	23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+};
+
+/*
+ * default lcall7 handler.. The native linux stuff doesn't
+ * use it at all, so we just segfault on it.
+ */
+asmlinkage void no_lcall7(struct pt_regs * regs)
+{
+	send_sig(SIGSEGV, current, 1);
 }
 
 static void set_brk(unsigned long start, unsigned long end)
diff -u --recursive --new-file v1.1.14/linux/fs/ext/namei.c linux/fs/ext/namei.c
--- v1.1.14/linux/fs/ext/namei.c	Sat May  7 14:54:05 1994
+++ linux/fs/ext/namei.c	Wed May 25 08:46:39 1994
@@ -543,8 +543,9 @@
 	retval = -EPERM;
 	if (!(inode = iget(dir->i_sb, de->inode)))
 		goto end_rmdir;
-	if ((dir->i_mode & S_ISVTX) && current->euid &&
-	   inode->i_uid != current->euid)
+        if ((dir->i_mode & S_ISVTX) && !suser() &&
+            current->euid != inode->i_uid &&
+            current->euid != dir->i_uid)
 		goto end_rmdir;
 	if (inode->i_dev != dir->i_dev)
 		goto end_rmdir;
diff -u --recursive --new-file v1.1.14/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v1.1.14/linux/fs/ext2/file.c	Tue Apr 19 10:53:21 1994
+++ linux/fs/ext2/file.c	Wed May 25 09:02:46 1994
@@ -277,10 +277,6 @@
 		}
 		p = (pos % sb->s_blocksize) + bh->b_data;
 		pos += c;
-		if (pos > inode->i_size) {
-			inode->i_size = pos;
-			inode->i_dirt = 1;
-		}
 		written += c;
 		memcpy_fromfs (p, buf, c);
 		buf += c;
@@ -288,6 +284,8 @@
 		mark_buffer_dirty(bh, 0);
 		brelse (bh);
 	}
+	if (pos > inode->i_size)
+		inode->i_size = pos;
 	up(&inode->i_sem);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	filp->f_pos = pos;
diff -u --recursive --new-file v1.1.14/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v1.1.14/linux/fs/ext2/namei.c	Sat May  7 14:54:06 1994
+++ linux/fs/ext2/namei.c	Wed May 25 08:46:40 1994
@@ -630,8 +630,9 @@
 		schedule();
 		goto repeat;
 	}
-	if ((dir->i_mode & S_ISVTX) && current->euid &&
-	    inode->i_uid != current->euid)
+        if ((dir->i_mode & S_ISVTX) && !suser() &&
+            current->euid != inode->i_uid &&
+            current->euid != dir->i_uid)
 		goto end_rmdir;
 	if (inode == dir)	/* we may not delete ".", but "../dir" is ok */
 		goto end_rmdir;
diff -u --recursive --new-file v1.1.14/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v1.1.14/linux/fs/ext2/super.c	Tue Apr 19 10:53:22 1994
+++ linux/fs/ext2/super.c	Wed May 25 08:46:40 1994
@@ -410,8 +410,8 @@
 
 		brelse (bh);
 		set_blocksize (dev, sb->s_blocksize);
-		logic_sb_block = sb_block / sb->s_blocksize;
-		offset = sb_block % sb->s_blocksize;
+		logic_sb_block = (sb_block*BLOCK_SIZE) / sb->s_blocksize;
+		offset = (sb_block*BLOCK_SIZE) % sb->s_blocksize;
 		bh = bread (dev, logic_sb_block, sb->s_blocksize);
 		if(!bh)
 			return NULL;
diff -u --recursive --new-file v1.1.14/linux/fs/minix/file.c linux/fs/minix/file.c
--- v1.1.14/linux/fs/minix/file.c	Tue Apr 19 10:53:23 1994
+++ linux/fs/minix/file.c	Wed May 25 09:02:46 1994
@@ -201,16 +201,13 @@
 		printk("minix_file_write: mode = %07o\n",inode->i_mode);
 		return -EINVAL;
 	}
-/*
- * ok, append may not work when many processes are writing at the same time
- * but so what. That way leads to madness anyway.
- */
+	down(&inode->i_sem);
 	if (filp->f_flags & O_APPEND)
 		pos = inode->i_size;
 	else
 		pos = filp->f_pos;
 	written = 0;
-	while (written<count) {
+	while (written < count) {
 		bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
 		if (!bh) {
 			if (!written)
@@ -232,10 +229,6 @@
 		}
 		p = (pos % BLOCK_SIZE) + bh->b_data;
 		pos += c;
-		if (pos > inode->i_size) {
-			inode->i_size = pos;
-			inode->i_dirt = 1;
-		}
 		written += c;
 		memcpy_fromfs(p,buf,c);
 		buf += c;
@@ -243,6 +236,9 @@
 		mark_buffer_dirty(bh, 0);
 		brelse(bh);
 	}
+	if (pos > inode->i_size)
+		inode->i_size = pos;
+	up(&inode->i_sem);
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	filp->f_pos = pos;
 	inode->i_dirt = 1;
diff -u --recursive --new-file v1.1.14/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v1.1.14/linux/fs/minix/namei.c	Sat May  7 14:54:07 1994
+++ linux/fs/minix/namei.c	Wed May 25 08:46:40 1994
@@ -443,8 +443,9 @@
 	retval = -EPERM;
 	if (!(inode = iget(dir->i_sb, de->inode)))
 		goto end_rmdir;
-	if ((dir->i_mode & S_ISVTX) && current->euid &&
-	   inode->i_uid != current->euid)
+        if ((dir->i_mode & S_ISVTX) && !suser() &&
+            current->euid != inode->i_uid &&
+            current->euid != dir->i_uid)
 		goto end_rmdir;
 	if (inode->i_dev != dir->i_dev)
 		goto end_rmdir;
diff -u --recursive --new-file v1.1.14/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v1.1.14/linux/fs/sysv/namei.c	Sat May  7 14:54:11 1994
+++ linux/fs/sysv/namei.c	Wed May 25 08:46:40 1994
@@ -447,8 +447,9 @@
 	retval = -EPERM;
 	if (!(inode = iget(dir->i_sb, de->inode)))
 		goto end_rmdir;
-	if ((dir->i_mode & S_ISVTX) && current->euid &&
-	    inode->i_uid != current->euid)
+        if ((dir->i_mode & S_ISVTX) && !suser() &&
+            current->euid != inode->i_uid &&
+            current->euid != dir->i_uid)
 		goto end_rmdir;
 	if (inode->i_dev != dir->i_dev)
 		goto end_rmdir;
diff -u --recursive --new-file v1.1.14/linux/fs/xiafs/namei.c linux/fs/xiafs/namei.c
--- v1.1.14/linux/fs/xiafs/namei.c	Sat May  7 14:54:12 1994
+++ linux/fs/xiafs/namei.c	Wed May 25 08:46:40 1994
@@ -496,8 +496,9 @@
     retval = -EPERM;
     if (!(inode = iget(dir->i_sb, de->d_ino)))
         goto end_rmdir;
-    if ((dir->i_mode & S_ISVTX) && current->euid &&
-	    inode->i_uid != current->euid)
+    if ((dir->i_mode & S_ISVTX) && !suser() &&
+            current->euid != inode->i_uid &&
+            current->euid != dir->i_uid)
         goto end_rmdir;
     if (inode->i_dev != dir->i_dev)
         goto end_rmdir;
diff -u --recursive --new-file v1.1.14/linux/ibcs/Makefile linux/ibcs/Makefile
--- v1.1.14/linux/ibcs/Makefile	Wed Dec  1 14:44:15 1993
+++ linux/ibcs/Makefile	Wed May 25 11:24:50 1994
@@ -36,4 +36,3 @@
 ifeq (.depend,$(wildcard .depend))
 include .depend
 endif
-
diff -u --recursive --new-file v1.1.14/linux/ibcs/emulate.c linux/ibcs/emulate.c
--- v1.1.14/linux/ibcs/emulate.c	Tue Jan 25 09:37:08 1994
+++ linux/ibcs/emulate.c	Wed May 25 11:26:10 1994
@@ -5,23 +5,6 @@
  */
 
 /*
- * Emulate.c contains the entry point for the 'lcall 7,xxx' handler.
+ * Yes, sir, this file is completely empty, waiting for some real code..
+ * I still copyright it, silly me.
  */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/segment.h>
-#include <linux/ptrace.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-asmlinkage void iABI_emulate(struct pt_regs * regs)
-{
-	printk("iBCS2 binaries not supported yet\n");
-	do_exit(SIGSEGV);
-}
diff -u --recursive --new-file v1.1.14/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.1.14/linux/include/linux/sched.h	Tue May 24 08:47:07 1994
+++ linux/include/linux/sched.h	Wed May 25 12:36:40 1994
@@ -89,6 +89,7 @@
 #include <linux/resource.h>
 #include <linux/vm86.h>
 #include <linux/math_emu.h>
+#include <linux/ptrace.h>
 
 #define TASK_RUNNING		0
 #define TASK_INTERRUPTIBLE	1
@@ -251,6 +252,7 @@
 	unsigned long flags;	/* per process flags, defined below */
 	int errno;
 	int debugreg[8];  /* Hardware debugging registers */
+	asmlinkage void (*lcall7)(struct pt_regs *);
 /* various fields */
 	struct task_struct *next_task, *prev_task;
 	struct sigaction sigaction[32];
@@ -324,6 +326,7 @@
 #define INIT_TASK \
 /* state etc */	{ 0,15,15,0,0,0,0, \
 /* debugregs */ { 0, },            \
+/* lcall 7 */	no_lcall7, \
 /* schedlink */	&init_task,&init_task, \
 /* signals */	{{ 0, },}, ident_map, ident_map, \
 /* stack */	0,(unsigned long) &init_kernel_stack, \
@@ -357,6 +360,9 @@
 extern unsigned long itimer_next;
 extern struct timeval xtime;
 extern int need_resched;
+
+extern unsigned long ident_map[33];
+extern asmlinkage void no_lcall7(struct pt_regs *);
 
 #define CURRENT_TIME (xtime.tv_sec)
 
diff -u --recursive --new-file v1.1.14/linux/include/linux/string.h linux/include/linux/string.h
--- v1.1.14/linux/include/linux/string.h	Tue Apr  5 07:37:24 1994
+++ linux/include/linux/string.h	Tue May 24 08:33:03 1994
@@ -99,11 +99,10 @@
 	"jne 1b\n\t"
 	"xorl %%eax,%%eax\n\t"
 	"jmp 3f\n"
-	"2:\tmovl $1,%%eax\n\t"
-	"jb 3f\n\t"
-	"negl %%eax\n"
+	"2:\tsbbl %%eax,%%eax\n\t"
+	"orb $1,%%eax\n"
 	"3:"
-	:"=a" (__res):"D" (cs),"S" (ct):"si","di");
+	:"=a" (__res):"S" (cs),"D" (ct):"si","di");
 return __res;
 }
 
@@ -120,11 +119,10 @@
 	"jne 1b\n"
 	"2:\txorl %%eax,%%eax\n\t"
 	"jmp 4f\n"
-	"3:\tmovl $1,%%eax\n\t"
-	"jb 4f\n\t"
-	"negl %%eax\n"
+	"3:\tsbbl %%eax,%%eax\n\t"
+	"orb $1,%%al\n"
 	"4:"
-	:"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx");
+	:"=a" (__res):"S" (cs),"D" (ct),"c" (count):"si","di","cx");
 return __res;
 }
 
@@ -153,8 +151,7 @@
 	"1:\tlodsb\n\t"
 	"cmpb %%ah,%%al\n\t"
 	"jne 2f\n\t"
-	"movl %%esi,%0\n\t"
-	"decl %0\n"
+	"leal -1(%%esi),%0\n"
 	"2:\ttestb %%al,%%al\n\t"
 	"jne 1b"
 	:"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
@@ -384,11 +381,10 @@
 	"repe\n\t"
 	"cmpsb\n\t"
 	"je 1f\n\t"
-	"movl $1,%%eax\n\t"
-	"jb 1f\n\t"
-	"negl %%eax\n"
+	"sbbl %%eax,%%eax\n\t"
+	"orb $1,%%al\n"
 	"1:"
-	:"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count)
+	:"=a" (__res):"0" (0),"S" (cs),"D" (ct),"c" (count)
 	:"si","di","cx");
 return __res;
 }
diff -u --recursive --new-file v1.1.14/linux/kernel/exit.c linux/kernel/exit.c
--- v1.1.14/linux/kernel/exit.c	Tue May 24 08:47:07 1994
+++ linux/kernel/exit.c	Tue May 24 08:53:30 1994
@@ -282,12 +282,10 @@
  * POSIX specifies that kill(-1,sig) is unspecified, but what we have
  * is probably wrong.  Should make it like BSD or SYSV.
  */
-asmlinkage int sys_kill(int pid, unsigned int sig)
+asmlinkage int sys_kill(int pid,int sig)
 {
 	int err, retval = 0, count = 0;
 
-	if (sig > 32)
-		return -EINVAL;
 	if (!pid)
 		return(kill_pg(current->pgrp,sig,0));
 	if (pid == -1) {
diff -u --recursive --new-file v1.1.14/linux/kernel/sched.c linux/kernel/sched.c
--- v1.1.14/linux/kernel/sched.c	Tue May 24 08:47:08 1994
+++ linux/kernel/sched.c	Wed May 25 10:56:27 1994
@@ -87,16 +87,6 @@
 extern int timer_interrupt(void);
 asmlinkage int system_call(void);
 
-/*
- * signal mapping: this is the default identity mapping used for normal
- * linux binaries (it's both the reverse and the normal map, of course)
- */
-static unsigned long ident_map[33] = {
-	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
-	13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
-	23, 24, 25, 26, 27, 28, 29, 30, 31, 32
-};
-
 static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
 struct task_struct init_task = INIT_TASK;
 
diff -u --recursive --new-file v1.1.14/linux/kernel/sys_call.S linux/kernel/sys_call.S
--- v1.1.14/linux/kernel/sys_call.S	Sat May  7 14:54:16 1994
+++ linux/kernel/sys_call.S	Wed May 25 13:19:26 1994
@@ -78,6 +78,7 @@
 errno		= 24
 dbgreg6		= 52
 dbgreg7		= 56
+lcall7		= 60
 
 ENOSYS = 38
 
@@ -141,8 +142,10 @@
 	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%esp)	#
 	movl %esp,%eax
+	movl _current,%edx
 	pushl %eax
-	call _iABI_emulate
+	movl lcall7(%edx),%edx
+	call *%edx
 	popl %eax
 	jmp ret_from_sys_call
 
diff -u --recursive --new-file v1.1.14/linux/net/inet/ip.c linux/net/inet/ip.c
--- v1.1.14/linux/net/inet/ip.c	Tue May 24 00:35:02 1994
+++ linux/net/inet/ip.c	Wed May 25 16:27:36 1994
@@ -1264,7 +1264,7 @@
   			return;
 	}
 	
-	if(memcmp(skb->data,dev->broadcast, dev->addr_len))
+	if(!memcmp(skb->data,dev->broadcast, dev->addr_len))
 		return;
 	
 
