Commit 7eb2fd0c authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.15

parent 1650f8d3
VERSION = 1 VERSION = 1
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 14 SUBLEVEL = 15
all: Version zImage all: Version zImage
......
...@@ -50,13 +50,16 @@ comment 'SCSI low-level drivers' ...@@ -50,13 +50,16 @@ comment 'SCSI low-level drivers'
bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n 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 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 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 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n
bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE 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 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
fi fi
......
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.
...@@ -11,6 +11,14 @@ ...@@ -11,6 +11,14 @@
AHA152X = -DDEBUG_AHA152X -DAUTOCONF 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_OBJS =
SCSI_SRCS = SCSI_SRCS =
...@@ -54,6 +62,11 @@ SCSI_OBJS := $(SCSI_OBJS) aha1740.o ...@@ -54,6 +62,11 @@ SCSI_OBJS := $(SCSI_OBJS) aha1740.o
SCSI_SRCS := $(SCSI_SRCS) aha1740.c SCSI_SRCS := $(SCSI_SRCS) aha1740.c
endif endif
ifdef CONFIG_SCSI_BUSLOGIC
SCSI_OBJS := $(SCSI_OBJS) buslogic.o
SCSI_SRCS := $(SCSI_SRCS) buslogic.c
endif
ifdef CONFIG_SCSI_DEBUG ifdef CONFIG_SCSI_DEBUG
SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o
SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
...@@ -64,6 +77,11 @@ SCSI_OBJS := $(SCSI_OBJS) fdomain.o ...@@ -64,6 +77,11 @@ SCSI_OBJS := $(SCSI_OBJS) fdomain.o
SCSI_SRCS := $(SCSI_SRCS) fdomain.c SCSI_SRCS := $(SCSI_SRCS) fdomain.c
endif endif
ifdef CONFIG_SCSI_IN2000
SCSI_OBJS := $(SCSI_OBJS) in2000.o
SCSI_SRCS := $(SCSI_SRCS) in2000.c
endif
ifdef CONFIG_SCSI_GENERIC_NCR5380 ifdef CONFIG_SCSI_GENERIC_NCR5380
SCSI_OBJS := $(SCSI_OBJS) g_NCR5380.o SCSI_OBJS := $(SCSI_OBJS) g_NCR5380.o
SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c
......
...@@ -2266,7 +2266,7 @@ static void NCR5380_dma_complete (NCR5380_instance *instance) { ...@@ -2266,7 +2266,7 @@ static void NCR5380_dma_complete (NCR5380_instance *instance) {
#endif /* def REAL_DMA */ #endif /* def REAL_DMA */
/* /*
* Function : int NCR5380_abort (Scsi_Cmnd *cmd, int code) * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
* *
* Purpose : abort a command * Purpose : abort a command
* *
...@@ -2285,7 +2285,7 @@ static void NCR5380_dma_complete (NCR5380_instance *instance) { ...@@ -2285,7 +2285,7 @@ static void NCR5380_dma_complete (NCR5380_instance *instance) {
#ifndef NCR5380_abort #ifndef NCR5380_abort
static static
#endif #endif
int NCR5380_abort (Scsi_Cmnd *cmd, int code) { int NCR5380_abort (Scsi_Cmnd *cmd) {
NCR5380_local_declare(); NCR5380_local_declare();
struct Scsi_Host *instance = cmd->host; struct Scsi_Host *instance = cmd->host;
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
...@@ -2313,14 +2313,14 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) { ...@@ -2313,14 +2313,14 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) {
if (cmd == tmp) { if (cmd == tmp) {
(*prev) = (Scsi_Cmnd *) tmp->host_scribble; (*prev) = (Scsi_Cmnd *) tmp->host_scribble;
tmp->host_scribble = NULL; tmp->host_scribble = NULL;
tmp->result = (code ? code : DID_ABORT) << 16; tmp->result = DID_ABORT << 16;
sti(); sti();
#if (NDEBUG & NDEBUG_ABORT) #if (NDEBUG & NDEBUG_ABORT)
printk("scsi%d : abort removed command from issue queue.\n", printk("scsi%d : abort removed command from issue queue.\n",
instance->host_no); instance->host_no);
#endif #endif
tmp->done(tmp); tmp->done(tmp);
return 0; return SCSI_ABORT_SUCCESS;
} }
/* /*
...@@ -2339,7 +2339,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) { ...@@ -2339,7 +2339,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) {
#if (NDEBUG & NDEBUG_ABORT) #if (NDEBUG & NDEBUG_ABORT)
printk("scsi%d : abort failed, command connected.\n", instance->host_no); printk("scsi%d : abort failed, command connected.\n", instance->host_no);
#endif #endif
return -1; return SCSI_ABORT_NOT_RUNNING;
} }
/* /*
...@@ -2376,7 +2376,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) { ...@@ -2376,7 +2376,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) {
#endif #endif
if (NCR5380_select (instance, cmd, (int) cmd->tag)) if (NCR5380_select (instance, cmd, (int) cmd->tag))
return 1; return SCSI_ABORT_BUSY;
#if (NDEBUG & NDEBUG_ABORT) #if (NDEBUG & NDEBUG_ABORT)
printk("scsi%d : nexus restablished.\n", instance->host_no); printk("scsi%d : nexus restablished.\n", instance->host_no);
...@@ -2397,10 +2397,10 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) { ...@@ -2397,10 +2397,10 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) {
if (cmd == tmp) { if (cmd == tmp) {
*prev = (Scsi_Cmnd *) tmp->host_scribble; *prev = (Scsi_Cmnd *) tmp->host_scribble;
tmp->host_scribble = NULL; tmp->host_scribble = NULL;
tmp->result = (code ? code : DID_ABORT) << 16; tmp->result = DID_ABORT << 16;
sti(); sti();
tmp->done(tmp); tmp->done(tmp);
return 0; return SCSI_ABORT_SUCCESS;
} }
} }
...@@ -2417,7 +2417,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) { ...@@ -2417,7 +2417,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd, int code) {
sti(); sti();
printk("scsi%d : warning : SCSI command probably completed successfully\n" printk("scsi%d : warning : SCSI command probably completed successfully\n"
" before abortion\n", instance->host_no); " before abortion\n", instance->host_no);
return 0; return SCSI_ABORT_NOT_RUNNING;
} }
......
...@@ -249,7 +249,7 @@ static void NCR5380_print_options (struct Scsi_Host *instance); ...@@ -249,7 +249,7 @@ static void NCR5380_print_options (struct Scsi_Host *instance);
#ifndef NCR5380_abort #ifndef NCR5380_abort
static static
#endif #endif
int NCR5380_abort (Scsi_Cmnd *cmd, int code); int NCR5380_abort (Scsi_Cmnd *cmd);
#ifndef NCR5380_reset #ifndef NCR5380_reset
static static
#endif #endif
......
...@@ -155,7 +155,7 @@ ...@@ -155,7 +155,7 @@
Drew Eckhardt (drew@cs.colorado.edu) 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 special thanks to Eric Youngdale for the free(!) supplying the
documentation on the chip. documentation on the chip.
...@@ -781,7 +781,7 @@ int aha152x_command( Scsi_Cmnd *SCpnt ) ...@@ -781,7 +781,7 @@ int aha152x_command( Scsi_Cmnd *SCpnt )
* Abort a queued command * Abort a queued command
* (commands that are on the bus can't be aborted easily) * (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; Scsi_Cmnd *ptr, *prev;
...@@ -809,16 +809,16 @@ int aha152x_abort( Scsi_Cmnd *SCpnt, int code ) ...@@ -809,16 +809,16 @@ int aha152x_abort( Scsi_Cmnd *SCpnt, int code )
sti(); sti();
ptr->host_scribble = NULL; ptr->host_scribble = NULL;
ptr->result = (code ? code : DID_ABORT ) << 16; ptr->result = DID_ABORT << 16;
ptr->done(ptr); ptr->done(ptr);
return 0; return SCSI_ABORT_SUCCESS;
} }
/* Fail abortion, if we're on the bus */ /* Fail abortion, if we're on the bus */
if (current_SC) if (current_SC)
{ {
sti(); sti();
return -1; return SCSI_ABORT_BUSY;
} }
/* look for command in disconnected queue */ /* look for command in disconnected queue */
...@@ -852,7 +852,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt, int code ) ...@@ -852,7 +852,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt, int code )
SETBITS(SCSISEQ, ENSELO | ENAUTOATNO ); SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
SETBITS( DMACNTRL0, INTEN ); SETBITS( DMACNTRL0, INTEN );
abort_result=0; abort_result=SCSI_ABORT_SUCCESS;
sti(); sti();
/* sleep until the abortion is complete */ /* sleep until the abortion is complete */
...@@ -864,7 +864,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt, int code ) ...@@ -864,7 +864,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt, int code )
/* command wasn't found */ /* command wasn't found */
sti(); sti();
return 0; return SCSI_ABORT_NOT_RUNNING;
} }
/* /*
...@@ -922,6 +922,10 @@ int aha152x_reset(Scsi_Cmnd * __unused) ...@@ -922,6 +922,10 @@ int aha152x_reset(Scsi_Cmnd * __unused)
show_queues(); 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) if(current_SC)
{ {
current_SC->host_scribble = NULL; current_SC->host_scribble = NULL;
...@@ -951,7 +955,7 @@ int aha152x_reset(Scsi_Cmnd * __unused) ...@@ -951,7 +955,7 @@ int aha152x_reset(Scsi_Cmnd * __unused)
SETPORT( DMACNTRL0, INTEN ); SETPORT( DMACNTRL0, INTEN );
} }
return 0; return SCSI_RESET_SUCCESS;
} }
/* /*
...@@ -1246,7 +1250,7 @@ void aha152x_intr( int irqno ) ...@@ -1246,7 +1250,7 @@ void aha152x_intr( int irqno )
if(current_SC->SCp.phase & aborted) if(current_SC->SCp.phase & aborted)
{ {
abort_result=1; abort_result=SCSI_ABORT_ERROR;
wake_up( &abortion_complete ); wake_up( &abortion_complete );
} }
...@@ -1304,7 +1308,7 @@ void aha152x_intr( int irqno ) ...@@ -1304,7 +1308,7 @@ void aha152x_intr( int irqno )
#if defined(DEBUG_ABORT) #if defined(DEBUG_ABORT)
printk("(ABORT) selection timeout, "); printk("(ABORT) selection timeout, ");
#endif #endif
abort_result=1; abort_result=SCSI_ABORT_ERROR;
wake_up( &abortion_complete ); wake_up( &abortion_complete );
} }
...@@ -1390,7 +1394,7 @@ void aha152x_intr( int irqno ) ...@@ -1390,7 +1394,7 @@ void aha152x_intr( int irqno )
if(message==ABORT) if(message==ABORT)
{ {
/* revive abort(); abort() enables interrupts */ /* revive abort(); abort() enables interrupts */
abort_result=0; abort_result=SCSI_ABORT_SUCCESS;
wake_up( &abortion_complete ); wake_up( &abortion_complete );
current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16)); current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
......
...@@ -14,7 +14,7 @@ int aha152x_detect(int); ...@@ -14,7 +14,7 @@ int aha152x_detect(int);
const char *aha152x_info(void); const char *aha152x_info(void);
int aha152x_command(Scsi_Cmnd *); int aha152x_command(Scsi_Cmnd *);
int aha152x_queue(Scsi_Cmnd *, void (*done)(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_reset(Scsi_Cmnd *);
int aha152x_biosparam(int, int, int*); int aha152x_biosparam(int, int, int*);
...@@ -39,7 +39,8 @@ int aha152x_biosparam(int, int, int*); ...@@ -39,7 +39,8 @@ int aha152x_biosparam(int, int, int*);
/* sg_tablesize */ SG_ALL, \ /* sg_tablesize */ SG_ALL, \
/* cmd_per_lun */ 1, \ /* cmd_per_lun */ 1, \
/* present */ 0, \ /* present */ 0, \
/* unchecked_isa_dma */ 0 } /* unchecked_isa_dma */ 0, \
/* use_clustering */ DISABLE_CLUSTERING }
#endif #endif
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* linux/kernel/aha1542.c * linux/kernel/aha1542.c
* *
* Copyright (C) 1992 Tommy Thorn * Copyright (C) 1992 Tommy Thorn
* Copyright (C) 1993, 1994 Eric Youngdale
* *
* Modified by Eric Youngdale * Modified by Eric Youngdale
* Use request_irq and request_dma to help prevent unexpected conflicts * Use request_irq and request_dma to help prevent unexpected conflicts
...@@ -75,6 +76,7 @@ static struct Scsi_Host * aha_host[7] = {NULL,}; /* One for each IRQ level (9-1 ...@@ -75,6 +76,7 @@ static struct Scsi_Host * aha_host[7] = {NULL,}; /* One for each IRQ level (9-1
#define WAITnexttimeout 3000000 #define WAITnexttimeout 3000000
static void setup_mailboxes(int base_io, struct Scsi_Host * shpnt); 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)) #define aha1542_intr_reset(base) outb(IRST, CONTROL(base))
...@@ -215,7 +217,9 @@ static int aha1542_test_port(int bse, struct Scsi_Host * shpnt) ...@@ -215,7 +217,9 @@ static int aha1542_test_port(int bse, struct Scsi_Host * shpnt)
/* Reset the adapter. I ought to make a hard reset, but it's not really nessesary */ /* Reset the adapter. I ought to make a hard reset, but it's not really nessesary */
/* DEB(printk("aha1542_test_port called \n")); */ /* 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)); outb(SRST|IRST/*|SCRST*/, CONTROL(bse));
i = jiffies + 2; i = jiffies + 2;
...@@ -259,7 +263,7 @@ static int aha1542_test_port(int bse, struct Scsi_Host * shpnt) ...@@ -259,7 +263,7 @@ static int aha1542_test_port(int bse, struct Scsi_Host * shpnt)
outb(IRST, CONTROL(bse)); outb(IRST, CONTROL(bse));
debug = 11; debug = 11;
return debug; /* 1 = ok */ return debug; /* 1 = ok */
fail: fail:
return 0; /* 0 = not ok */ return 0; /* 0 = not ok */
...@@ -281,7 +285,8 @@ static void aha1542_intr_handle(int foo) ...@@ -281,7 +285,8 @@ static void aha1542_intr_handle(int foo)
int number_serviced; int number_serviced;
struct Scsi_Host * shost; struct Scsi_Host * shost;
Scsi_Cmnd * SCtmp; Scsi_Cmnd * SCtmp;
int irqno, * irqp; int irqno, * irqp, flag;
int needs_restart;
struct mailbox * mb; struct mailbox * mb;
struct ccb *ccb; struct ccb *ccb;
...@@ -297,7 +302,7 @@ static void aha1542_intr_handle(int foo) ...@@ -297,7 +302,7 @@ static void aha1542_intr_handle(int foo)
#ifdef DEBUG #ifdef DEBUG
{ {
int flag = inb(INTRFLAGS(shost->io_port)); flag = inb(INTRFLAGS(shost->io_port));
printk("aha1542_intr_handle: "); printk("aha1542_intr_handle: ");
if (!(flag&ANYINTR)) printk("no interrupt?"); if (!(flag&ANYINTR)) printk("no interrupt?");
if (flag&MBIF) printk("MBIF "); if (flag&MBIF) printk("MBIF ");
...@@ -308,8 +313,24 @@ static void aha1542_intr_handle(int foo) ...@@ -308,8 +313,24 @@ static void aha1542_intr_handle(int foo)
}; };
#endif #endif
number_serviced = 0; number_serviced = 0;
needs_restart = 0;
while(1==1){ 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); aha1542_intr_reset(shost->io_port);
cli(); cli();
...@@ -325,8 +346,11 @@ static void aha1542_intr_handle(int foo) ...@@ -325,8 +346,11 @@ static void aha1542_intr_handle(int foo)
if(mb[mbi].status == 0){ if(mb[mbi].status == 0){
sti(); sti();
/* Hmm, no mail. Must have read it the last time around */ /* Hmm, no mail. Must have read it the last time around */
if (number_serviced) return; if (!number_serviced && !needs_restart)
printk("aha1542.c: interrupt received, but no mail.\n"); 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; return;
}; };
...@@ -354,6 +378,8 @@ static void aha1542_intr_handle(int foo) ...@@ -354,6 +378,8 @@ static void aha1542_intr_handle(int foo)
if (!SCtmp || !SCtmp->scsi_done) { if (!SCtmp || !SCtmp->scsi_done) {
printk("aha1542_intr_handle: Unexpected interrupt\n"); 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; return;
} }
...@@ -883,39 +909,156 @@ int aha1542_detect(int hostnum) ...@@ -883,39 +909,156 @@ int aha1542_detect(int hostnum)
return count; 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 /* 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 it is available to be used again. Until this gets worked out, we will
leave it commented out. */ leave it commented out. */
int aha1542_abort(Scsi_Cmnd * SCpnt, int i) int aha1542_abort(Scsi_Cmnd * SCpnt)
{ {
#if 0 #if 0
unchar ahacmd = CMD_START_SCSI; int intval[3];
int mbo; 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 #endif
DEB(printk("aha1542_abort\n")); DEB(printk("aha1542_abort\n"));
#if 0 #if 0
cli(); cli();
for(mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) for(mbo = 0; mbo < AHA1542_MAILBOXES; mbo++)
if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]){ if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]){
mb[mbo].status = 2; /* Abort command */ 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(); sti();
break; break;
}; };
#endif #endif
return 0; return SCSI_ABORT_SNOOZE;
} }
/* We do not implement a reset function here, but the upper level code assumes /* We do not implement a reset function here, but the upper level code
that it will get some kind of response for the command in SCpnt. We must assumes that it will get some kind of response for the command in
oblige, or the command will hang the scsi system */ 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) int aha1542_reset(Scsi_Cmnd * SCpnt)
{ {
unchar ahacmd = CMD_START_SCSI;
int i;
DEB(printk("aha1542_reset called\n")); DEB(printk("aha1542_reset called\n"));
if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; #if 0
return 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 #ifdef CONFIG_BLK_DEV_SD
......
...@@ -131,7 +131,7 @@ struct ccb { /* Command Control Block 5.3 */ ...@@ -131,7 +131,7 @@ struct ccb { /* Command Control Block 5.3 */
int aha1542_detect(int); int aha1542_detect(int);
int aha1542_command(Scsi_Cmnd *); int aha1542_command(Scsi_Cmnd *);
int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(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); const char *aha1542_info(void);
int aha1542_reset(Scsi_Cmnd *); int aha1542_reset(Scsi_Cmnd *);
int aha1542_biosparam(int, int, int*); int aha1542_biosparam(int, int, int*);
...@@ -152,6 +152,6 @@ int aha1542_biosparam(int, int, int*); ...@@ -152,6 +152,6 @@ int aha1542_biosparam(int, int, int*);
NULL, \ NULL, \
aha1542_biosparam, \ aha1542_biosparam, \
AHA1542_MAILBOXES, 7, AHA1542_SCATTER, AHA1542_CMDLUN \ AHA1542_MAILBOXES, 7, AHA1542_SCATTER, AHA1542_CMDLUN \
, 0, 1} , 0, 1, ENABLE_CLUSTERING}
#endif #endif
...@@ -474,10 +474,10 @@ but it hasn't happened yet, and doing aborts brings the Adaptec to its ...@@ -474,10 +474,10 @@ but it hasn't happened yet, and doing aborts brings the Adaptec to its
knees. I cannot (at this moment in time) think of any reason to reset the knees. I cannot (at this moment in time) think of any reason to reset the
card once it's running. So there. */ 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")); 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 /* We do not implement a reset function here, but the upper level code assumes
...@@ -487,8 +487,7 @@ int aha1740_abort(Scsi_Cmnd * SCpnt, int i) ...@@ -487,8 +487,7 @@ int aha1740_abort(Scsi_Cmnd * SCpnt, int i)
int aha1740_reset(Scsi_Cmnd * SCpnt) int aha1740_reset(Scsi_Cmnd * SCpnt)
{ {
DEB(printk("aha1740_reset called\n")); DEB(printk("aha1740_reset called\n"));
if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; return SCSI_RESET_SNOOZE;
return 0;
} }
int aha1740_biosparam(int size, int dev, int* ip) int aha1740_biosparam(int size, int dev, int* ip)
......
...@@ -155,7 +155,7 @@ struct ecb { /* Enhanced Control Block 6.1 */ ...@@ -155,7 +155,7 @@ struct ecb { /* Enhanced Control Block 6.1 */
int aha1740_detect(int); int aha1740_detect(int);
int aha1740_command(Scsi_Cmnd *); int aha1740_command(Scsi_Cmnd *);
int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(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); const char *aha1740_info(void);
int aha1740_reset(Scsi_Cmnd *); int aha1740_reset(Scsi_Cmnd *);
int aha1740_biosparam(int, int, int*); int aha1740_biosparam(int, int, int*);
...@@ -174,7 +174,7 @@ int aha1740_biosparam(int, int, int*); ...@@ -174,7 +174,7 @@ int aha1740_biosparam(int, int, int*);
aha1740_reset, \ aha1740_reset, \
NULL, \ NULL, \
aha1740_biosparam, \ aha1740_biosparam, \
AHA1740_ECBS, 7, AHA1740_SCATTER, 1, 0, 0} AHA1740_ECBS, 7, AHA1740_SCATTER, 1, 0, 0, ENABLE_CLUSTERING}
#endif #endif
/*
* 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;
}
/*
* 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
...@@ -73,7 +73,7 @@ static const char reserved[] = "RESERVED"; ...@@ -73,7 +73,7 @@ static const char reserved[] = "RESERVED";
static const char vendor[] = "VENDOR SPECIFIC"; static const char vendor[] = "VENDOR SPECIFIC";
static void print_opcode(int opcode) { static void print_opcode(int opcode) {
char **table = commands[ group(opcode) ]; const char **table = commands[ group(opcode) ];
switch ((int) table) { switch ((int) table) {
case RESERVED_GROUP: case RESERVED_GROUP:
printk("%s(0x%02x) ", reserved, opcode); printk("%s(0x%02x) ", reserved, opcode);
...@@ -351,8 +351,8 @@ static struct error_info additional[] = ...@@ -351,8 +351,8 @@ static struct error_info additional[] =
static char *snstext[] = { static char *snstext[] = {
"None","Recovered Error","Not Ready","Medium Error","Hardware Error", "None","Recovered Error","Not Ready","Medium Error","Hardware Error",
"Illegal Request","Unit Attention","Data Protect","Blank Check", "Illegal Request","Unit Attention","Data Protect","Blank Check",
"Key=E","Key=F","Filemark","End-Of-Medium","Incorrect Block Length", "Key=9","Copy Aborted","Aborted Command","End-Of-Medium",
"14","15"}; "Volume Overflow", "Miscompare", "Key=15"};
#endif #endif
...@@ -394,9 +394,6 @@ void print_sense(char * devclass, Scsi_Cmnd * SCpnt) ...@@ -394,9 +394,6 @@ void print_sense(char * devclass, Scsi_Cmnd * SCpnt)
printk("%s error ", error); printk("%s error ", error);
#if (CONSTANTS & CONST_SENSE) #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]); printk( "%s%x: sense key %s\n", devclass, dev, snstext[sense_buffer[2] & 0x0f]);
#else #else
printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]); printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]);
...@@ -437,9 +434,12 @@ void print_sense(char * devclass, Scsi_Cmnd * SCpnt) ...@@ -437,9 +434,12 @@ void print_sense(char * devclass, Scsi_Cmnd * SCpnt)
} }
done: done:
#if !(CONSTANTS & CONST_SENSE)
printk("Raw sense data:");
for (i = 0; i < s; ++i) for (i = 0; i < s; ++i)
printk("0x%02x ", sense_buffer[i]); printk("0x%02x ", sense_buffer[i]);
printk("\n");
#endif
return; return;
} }
......
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
revision 10h, October 17, 1991) revision 10h, October 17, 1991)
Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric 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), Private communication, Tuong Le (Future Domain Engineering department),
1994. (Disk geometry computations for Future Domain BIOS version 3.4, and 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and
...@@ -1394,9 +1394,8 @@ void print_info( Scsi_Cmnd *SCpnt ) ...@@ -1394,9 +1394,8 @@ void print_info( Scsi_Cmnd *SCpnt )
inb( port_base + Configuration2 ) ); 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 #if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
printk( "Future Domain: Abort " ); printk( "Future Domain: Abort " );
#endif #endif
...@@ -1407,11 +1406,7 @@ int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code ) ...@@ -1407,11 +1406,7 @@ int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code )
printk( " (not in command)\n" ); printk( " (not in command)\n" );
#endif #endif
sti(); sti();
return 0; return SCSI_ABORT_NOT_RUNNING;
} else {
#if EVERY_ACCESS || ERRORS_ONLY
printk( " code = %d\n", code );
#endif
} }
#if DEBUG_ABORT #if DEBUG_ABORT
...@@ -1422,14 +1417,14 @@ int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code ) ...@@ -1422,14 +1417,14 @@ int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code )
current_SC->SCp.phase |= aborted; current_SC->SCp.phase |= aborted;
current_SC->result = code ? code : DID_ABORT; current_SC->result = DID_ABORT << 16;
sti(); sti();
/* Aborts are not done well. . . */ /* 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 ) int fdomain_16x0_reset( Scsi_Cmnd *SCpnt )
...@@ -1458,10 +1453,7 @@ int fdomain_16x0_reset( Scsi_Cmnd *SCpnt ) ...@@ -1458,10 +1453,7 @@ int fdomain_16x0_reset( Scsi_Cmnd *SCpnt )
is probably hosed at this point. We will, however, try to keep is probably hosed at this point. We will, however, try to keep
things going by informing the high-level code that we need help. */ things going by informing the high-level code that we need help. */
if (SCpnt) return SCSI_RESET_WAKEUP;
SCpnt->flags |= NEEDS_JUMPSTART;
return 0;
} }
#ifdef CONFIG_BLK_DEV_SD #ifdef CONFIG_BLK_DEV_SD
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
int fdomain_16x0_detect( int ); int fdomain_16x0_detect( int );
int fdomain_16x0_command( Scsi_Cmnd * ); 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 ); const char *fdomain_16x0_info( void );
int fdomain_16x0_reset( Scsi_Cmnd * ); int fdomain_16x0_reset( Scsi_Cmnd * );
int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
...@@ -47,5 +47,5 @@ int fdomain_16x0_biosparam( int, int, int * ); ...@@ -47,5 +47,5 @@ int fdomain_16x0_biosparam( int, int, int * );
fdomain_16x0_reset, \ fdomain_16x0_reset, \
NULL, \ NULL, \
fdomain_16x0_biosparam, \ fdomain_16x0_biosparam, \
1, 6, 64 /* SG_NONE */, 1 ,0, 0 } 1, 6, 64 /* SG_NONE */, 1 ,0, 0, DISABLE_CLUSTERING}
#endif #endif
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#ifndef ASM #ifndef ASM
int generic_NCR5380_abort(Scsi_Cmnd *, int); int generic_NCR5380_abort(Scsi_Cmnd *);
int generic_NCR5380_detect(int); int generic_NCR5380_detect(int);
const char *generic_NCR5380_info(void); const char *generic_NCR5380_info(void);
int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
...@@ -59,7 +59,7 @@ int generic_NCR5380_reset(Scsi_Cmnd *); ...@@ -59,7 +59,7 @@ int generic_NCR5380_reset(Scsi_Cmnd *);
generic_NCR5380_queue_command, generic_NCR5380_abort, \ generic_NCR5380_queue_command, generic_NCR5380_abort, \
generic_NCR5380_reset, NULL, \ generic_NCR5380_reset, NULL, \
NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \ 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 #else
#define NCR5380_implementation_fields \ #define NCR5380_implementation_fields \
......
...@@ -39,6 +39,10 @@ ...@@ -39,6 +39,10 @@
#include "aha1740.h" #include "aha1740.h"
#endif #endif
#ifdef CONFIG_SCSI_BUSLOGIC
#include "buslogic.h"
#endif
#ifdef CONFIG_SCSI_FUTURE_DOMAIN #ifdef CONFIG_SCSI_FUTURE_DOMAIN
#include "fdomain.h" #include "fdomain.h"
#endif #endif
...@@ -47,6 +51,10 @@ ...@@ -47,6 +51,10 @@
#include "g_NCR5380.h" #include "g_NCR5380.h"
#endif #endif
#ifdef CONFIG_SCSI_IN2000
#include "in2000.h"
#endif
#ifdef CONFIG_SCSI_PAS16 #ifdef CONFIG_SCSI_PAS16
#include "pas16.h" #include "pas16.h"
#endif #endif
...@@ -105,6 +113,10 @@ Scsi_Host_Template scsi_hosts[] = ...@@ -105,6 +113,10 @@ Scsi_Host_Template scsi_hosts[] =
#ifdef CONFIG_SCSI_AHA152X #ifdef CONFIG_SCSI_AHA152X
AHA152X, AHA152X,
#endif #endif
/* Buslogic must come before aha1542.c */
#ifdef CONFIG_SCSI_BUSLOGIC
BUSLOGIC,
#endif
#ifdef CONFIG_SCSI_AHA1542 #ifdef CONFIG_SCSI_AHA1542
AHA1542, AHA1542,
#endif #endif
...@@ -114,6 +126,9 @@ Scsi_Host_Template scsi_hosts[] = ...@@ -114,6 +126,9 @@ Scsi_Host_Template scsi_hosts[] =
#ifdef CONFIG_SCSI_FUTURE_DOMAIN #ifdef CONFIG_SCSI_FUTURE_DOMAIN
FDOMAIN_16X0, FDOMAIN_16X0,
#endif #endif
#ifdef CONFIG_SCSI_IN2000
IN2000,
#endif
#ifdef CONFIG_SCSI_GENERIC_NCR5380 #ifdef CONFIG_SCSI_GENERIC_NCR5380
GENERIC_NCR5380, GENERIC_NCR5380,
#endif #endif
...@@ -181,6 +196,7 @@ struct Scsi_Host * scsi_register(int i, int j){ ...@@ -181,6 +196,7 @@ struct Scsi_Host * scsi_register(int i, int j){
retval->host_queue = NULL; retval->host_queue = NULL;
retval->host_wait = NULL; retval->host_wait = NULL;
retval->last_reset = 0; retval->last_reset = 0;
retval->irq = 0;
retval->hostt = &scsi_hosts[i]; retval->hostt = &scsi_hosts[i];
retval->next = NULL; retval->next = NULL;
#ifdef DEBUG #ifdef DEBUG
......
...@@ -21,16 +21,11 @@ ...@@ -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_NONE 0
#define SG_ALL 0xff #define SG_ALL 0x7fff
#define DISABLE_CLUSTERING 0
#define ENABLE_CLUSTERING 1
/* The various choices mean: /* The various choices mean:
NONE: Self evident. Host adapter is not capable of scatter-gather. NONE: Self evident. Host adapter is not capable of scatter-gather.
...@@ -109,7 +104,11 @@ typedef struct ...@@ -109,7 +104,11 @@ typedef struct
/* /*
Since the mid level driver handles time outs, etc, we want to Since the mid level driver handles time outs, etc, we want to
be able to abort the current command. Abort returns 0 if the 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 will be used as the return code, otherwise
DID_ABORT should be returned. DID_ABORT should be returned.
...@@ -117,7 +116,7 @@ typedef struct ...@@ -117,7 +116,7 @@ typedef struct
resetting the bus, etc. if necessary. 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 The reset function will reset the SCSI bus. Any executing
...@@ -192,6 +191,15 @@ typedef struct ...@@ -192,6 +191,15 @@ typedef struct
true if this host adapter uses unchecked DMA onto an ISA bus. true if this host adapter uses unchecked DMA onto an ISA bus.
*/ */
unsigned unchecked_isa_dma:1; 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; } Scsi_Host_Template;
/* /*
......
...@@ -114,7 +114,7 @@ ...@@ -114,7 +114,7 @@
#ifndef ASM #ifndef ASM
int pas16_abort(Scsi_Cmnd *, int); int pas16_abort(Scsi_Cmnd *);
int pas16_biosparam(int, int, int*); int pas16_biosparam(int, int, int*);
int pas16_detect(int); int pas16_detect(int);
const char *pas16_info(void); const char *pas16_info(void);
...@@ -145,7 +145,7 @@ int pas16_reset(Scsi_Cmnd *); ...@@ -145,7 +145,7 @@ int pas16_reset(Scsi_Cmnd *);
NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL, \ NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL, \
pas16_biosparam, \ pas16_biosparam, \
/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \ /* 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 #else
......
/* /*
* scsi.c Copyright (C) 1992 Drew Eckhardt * scsi.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994 Eric Youngdale
*
* generic mid-level SCSI driver by * generic mid-level SCSI driver by
* Drew Eckhardt * Drew Eckhardt
* *
...@@ -10,7 +12,7 @@ ...@@ -10,7 +12,7 @@
* Tommy Thorn <tthorn> * Tommy Thorn <tthorn>
* Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de> * 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 * add scatter-gather, multiple outstanding request, and other
* enhancements. * enhancements.
*/ */
...@@ -19,6 +21,7 @@ ...@@ -19,6 +21,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/string.h> #include <linux/string.h>
#include <asm/irq.h>
#include "../block/blk.h" #include "../block/blk.h"
#include "scsi.h" #include "scsi.h"
...@@ -84,8 +87,8 @@ static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0}; ...@@ -84,8 +87,8 @@ static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
#define WAS_TIMEDOUT 0x02 #define WAS_TIMEDOUT 0x02
#define WAS_SENSE 0x04 #define WAS_SENSE 0x04
#define IS_RESETTING 0x08 #define IS_RESETTING 0x08
#define ASKED_FOR_SENSE 0x10 #define IS_ABORTING 0x10
/* #define NEEDS_JUMPSTART 0x20 defined in hosts.h */ #define ASKED_FOR_SENSE 0x20
/* /*
* This is the number of clock ticks we should wait before we time out * This is the number of clock ticks we should wait before we time out
...@@ -97,6 +100,11 @@ static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0}; ...@@ -97,6 +100,11 @@ static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
* respectively. * respectively.
*/ */
#ifdef DEBUG_TIMEOUT
static void scsi_dump_status(void);
#endif
#ifdef DEBUG #ifdef DEBUG
#define SCSI_TIMEOUT 500 #define SCSI_TIMEOUT 500
#else #else
...@@ -350,6 +358,8 @@ static void scan_scsis (void) ...@@ -350,6 +358,8 @@ static void scan_scsis (void)
type = -1; type = -1;
} }
scsi_devices[NR_SCSI_DEVICES].soft_reset =
(scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
scsi_devices[NR_SCSI_DEVICES].random = scsi_devices[NR_SCSI_DEVICES].random =
(type == TYPE_TAPE) ? 0 : 1; (type == TYPE_TAPE) ? 0 : 1;
scsi_devices[NR_SCSI_DEVICES].type = type; scsi_devices[NR_SCSI_DEVICES].type = type;
...@@ -503,9 +513,13 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt) ...@@ -503,9 +513,13 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt)
switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET)) switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
{ {
case NORMAL_TIMEOUT: case NORMAL_TIMEOUT:
if (!in_scan) if (!in_scan) {
printk("SCSI host %d timed out - aborting command\n", printk("SCSI host %d timed out - aborting command\n",
SCpnt->host->host_no); SCpnt->host->host_no);
#ifdef DEBUG_TIMEOUT
scsi_dump_status();
#endif
}
if (!scsi_abort (SCpnt, DID_TIME_OUT)) if (!scsi_abort (SCpnt, DID_TIME_OUT))
return; return;
...@@ -516,7 +530,13 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt) ...@@ -516,7 +530,13 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt)
return; return;
case IN_RESET: case IN_RESET:
case (IN_ABORT | 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: default:
INTERNAL_ERROR; INTERNAL_ERROR;
} }
...@@ -739,11 +759,26 @@ update_timeout(SCpnt, SCpnt->timeout_per_command); ...@@ -739,11 +759,26 @@ update_timeout(SCpnt, SCpnt->timeout_per_command);
if (host->hostt->can_queue) if (host->hostt->can_queue)
{ {
extern unsigned long intr_count;
#ifdef DEBUG #ifdef DEBUG
printk("queuecommand : routine at %08x\n", printk("queuecommand : routine at %08x\n",
host->hostt->queuecommand); host->hostt->queuecommand);
#endif #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); host->hostt->queuecommand (SCpnt, scsi_done);
if(!intr_count && SCpnt->host->irq)
enable_irq(SCpnt->host->irq);
} }
else else
{ {
...@@ -876,6 +911,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , ...@@ -876,6 +911,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
/* Start the timer ticking. */ /* Start the timer ticking. */
SCpnt->internal_timeout = 0; SCpnt->internal_timeout = 0;
SCpnt->abort_reason = 0;
internal_cmnd (SCpnt); internal_cmnd (SCpnt);
#ifdef DEBUG #ifdef DEBUG
...@@ -904,10 +940,12 @@ static void reset (Scsi_Cmnd * SCpnt) ...@@ -904,10 +940,12 @@ static void reset (Scsi_Cmnd * SCpnt)
printk("performing request sense\n"); printk("performing request sense\n");
#endif #endif
#if 0 /* FIXME - remove this when done */
if(SCpnt->flags & NEEDS_JUMPSTART) { if(SCpnt->flags & NEEDS_JUMPSTART) {
SCpnt->flags &= ~NEEDS_JUMPSTART; SCpnt->flags &= ~NEEDS_JUMPSTART;
scsi_request_sense (SCpnt); scsi_request_sense (SCpnt);
}; };
#endif
} }
...@@ -997,6 +1035,18 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -997,6 +1035,18 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
int result = SCpnt->result; int result = SCpnt->result;
oldto = update_timeout(SCpnt, 0); oldto = update_timeout(SCpnt, 0);
#ifdef DEBUG_TIMEOUT
if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
result, SCpnt->target, SCpnt->lun);
#endif
/* If we requested an abort, (and we got it) then fix up the return
status to say why */
if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
SCpnt->result = result = (result & 0xff00ffff) |
(SCpnt->abort_reason << 16);
#define FINISHED 0 #define FINISHED 0
#define MAYREDO 1 #define MAYREDO 1
#define REDO 3 #define REDO 3
...@@ -1008,13 +1058,6 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -1008,13 +1058,6 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
switch (host_byte(result)) switch (host_byte(result))
{ {
case DID_OK: case DID_OK:
if (SCpnt->flags & IS_RESETTING)
{
SCpnt->flags &= ~IS_RESETTING;
status = REDO;
break;
}
if (status_byte(result) && (SCpnt->flags & WAS_SENSE)) if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
/* Failed to obtain sense information */ /* Failed to obtain sense information */
{ {
...@@ -1154,7 +1197,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -1154,7 +1197,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
printk("Host returned DID_TIME_OUT - "); printk("Host returned DID_TIME_OUT - ");
#endif #endif
if (SCpnt->flags & WAS_TIMEDOUT) if (SCpnt->flags & WAS_TIMEDOUT)
{ {
#ifdef DEBUG #ifdef DEBUG
printk("Aborting\n"); printk("Aborting\n");
...@@ -1167,6 +1210,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -1167,6 +1210,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
printk ("Retrying.\n"); printk ("Retrying.\n");
#endif #endif
SCpnt->flags |= WAS_TIMEDOUT; SCpnt->flags |= WAS_TIMEDOUT;
SCpnt->internal_timeout &= ~IN_ABORT;
status = REDO; status = REDO;
} }
break; break;
...@@ -1189,6 +1233,13 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -1189,6 +1233,13 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
exit = (DRIVER_INVALID | SUGGEST_ABORT); exit = (DRIVER_INVALID | SUGGEST_ABORT);
break; break;
case DID_RESET: case DID_RESET:
if (SCpnt->flags & IS_RESETTING)
{
SCpnt->flags &= ~IS_RESETTING;
status = REDO;
break;
}
if(msg_byte(result) == GOOD && if(msg_byte(result) == GOOD &&
status_byte(result) == CHECK_CONDITION) { status_byte(result) == CHECK_CONDITION) {
switch (check_sense(SCpnt)) { switch (check_sense(SCpnt)) {
...@@ -1305,7 +1356,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -1305,7 +1356,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
int scsi_abort (Scsi_Cmnd * SCpnt, int why) int scsi_abort (Scsi_Cmnd * SCpnt, int why)
{ {
int temp, oldto; int oldto;
struct Scsi_Host * host = SCpnt->host; struct Scsi_Host * host = SCpnt->host;
while(1) while(1)
...@@ -1321,22 +1372,67 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why) ...@@ -1321,22 +1372,67 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why)
SCpnt->internal_timeout |= IN_ABORT; SCpnt->internal_timeout |= IN_ABORT;
oldto = update_timeout(SCpnt, ABORT_TIMEOUT); oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
if ((SCpnt->flags & IS_RESETTING) &&
SCpnt->device->soft_reset) {
/* OK, this command must have died when we did the
reset. The device itself must have lied. */
printk("Stale command on %d:%d appears to have died when"
" the bus was reset\n", SCpnt->target, SCpnt->lun);
}
sti(); sti();
if (!host->host_busy || !host->hostt->abort(SCpnt, why)) if (!host->host_busy) {
temp = 0; SCpnt->internal_timeout &= ~IN_ABORT;
else update_timeout(SCpnt, oldto);
temp = 1; return 0;
cli();
SCpnt->internal_timeout &= ~IN_ABORT;
update_timeout(SCpnt, oldto);
sti();
return temp;
} }
} 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 scsi_reset (Scsi_Cmnd * SCpnt)
{ {
int temp, oldto; int temp, oldto;
...@@ -1363,10 +1459,14 @@ int scsi_reset (Scsi_Cmnd * SCpnt) ...@@ -1363,10 +1459,14 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
sti(); sti();
SCpnt1 = host->host_queue; SCpnt1 = host->host_queue;
while(SCpnt1) { while(SCpnt1) {
if ((SCpnt1->request.dev > 0) && if (SCpnt1->request.dev > 0) {
!(SCpnt1->flags & IS_RESETTING) && #if 0
if (!(SCpnt1->flags & IS_RESETTING) &&
!(SCpnt1->internal_timeout & IN_ABORT)) !(SCpnt1->internal_timeout & IN_ABORT))
scsi_abort(SCpnt1, DID_RESET); scsi_abort(SCpnt1, DID_RESET);
#endif
SCpnt1->flags |= IS_RESETTING;
}
SCpnt1 = SCpnt1->next; SCpnt1 = SCpnt1->next;
}; };
...@@ -1381,11 +1481,35 @@ int scsi_reset (Scsi_Cmnd * SCpnt) ...@@ -1381,11 +1481,35 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
host->last_reset = jiffies; host->last_reset = jiffies;
host->host_busy--; 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; return temp;
} }
} }
...@@ -1405,6 +1529,7 @@ static void scsi_main_timeout(void) ...@@ -1405,6 +1529,7 @@ static void scsi_main_timeout(void)
do { do {
cli(); cli();
update_timeout(NULL, 0);
/* /*
Find all timers such that they have 0 or negative (shouldn't happen) Find all timers such that they have 0 or negative (shouldn't happen)
time remaining on them. time remaining on them.
...@@ -1412,9 +1537,8 @@ static void scsi_main_timeout(void) ...@@ -1412,9 +1537,8 @@ static void scsi_main_timeout(void)
timed_out = 0; timed_out = 0;
for(host = scsi_hostlist; host; host = host->next) { for(host = scsi_hostlist; host; host = host->next) {
SCpnt = host->host_queue; for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
while (SCpnt){ if (SCpnt->timeout == -1)
if (SCpnt->timeout > 0 && SCpnt->timeout <= time_elapsed)
{ {
sti(); sti();
SCpnt->timeout = 0; SCpnt->timeout = 0;
...@@ -1422,10 +1546,7 @@ static void scsi_main_timeout(void) ...@@ -1422,10 +1546,7 @@ static void scsi_main_timeout(void)
++timed_out; ++timed_out;
cli(); cli();
} }
SCpnt = SCpnt->next;
};
}; };
update_timeout(NULL, 0);
} while (timed_out); } while (timed_out);
sti(); sti();
} }
...@@ -1468,14 +1589,14 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout) ...@@ -1468,14 +1589,14 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
least = 0xffffffff; least = 0xffffffff;
for(host = scsi_hostlist; host; host = host->next) { for(host = scsi_hostlist; host; host = host->next)
SCpnt = host->host_queue; for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
while (SCpnt){ if (SCpnt->timeout > 0) {
if (SCpnt->timeout > 0 && (SCpnt->timeout -= used) < least) SCpnt->timeout -= used;
least = SCpnt->timeout; if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
SCpnt = SCpnt->next; if(SCpnt->timeout > 0 && SCpnt->timeout < least)
}; least = SCpnt->timeout;
}; };
/* /*
If something is due to timeout again, then we will set the next timeout If something is due to timeout again, then we will set the next timeout
...@@ -1617,6 +1738,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end ...@@ -1617,6 +1738,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
if(scsi_devices[i].type != -1){ if(scsi_devices[i].type != -1){
for(j=0;j<scsi_devices[i].host->hostt->cmd_per_lun;j++){ for(j=0;j<scsi_devices[i].host->hostt->cmd_per_lun;j++){
SCpnt->host = scsi_devices[i].host; SCpnt->host = scsi_devices[i].host;
SCpnt->device = &scsi_devices[i];
SCpnt->target = scsi_devices[i].id; SCpnt->target = scsi_devices[i].id;
SCpnt->lun = scsi_devices[i].lun; SCpnt->lun = scsi_devices[i].lun;
SCpnt->index = i; SCpnt->index = i;
...@@ -1724,3 +1846,62 @@ static void print_inquiry(unsigned char *data) ...@@ -1724,3 +1846,62 @@ static void print_inquiry(unsigned char *data)
else else
printk("\n"); 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
...@@ -276,6 +276,7 @@ typedef struct scsi_device { ...@@ -276,6 +276,7 @@ typedef struct scsi_device {
unsigned tagged_supported:1; /* Supports SCSI-II tagged queing */ unsigned tagged_supported:1; /* Supports SCSI-II tagged queing */
unsigned tagged_queue:1; /*SCSI-II tagged queing enabled */ unsigned tagged_queue:1; /*SCSI-II tagged queing enabled */
unsigned disconnect:1; /* can disconnect */ unsigned disconnect:1; /* can disconnect */
unsigned soft_reset:1; /* Uses soft reset option */
unsigned char current_tag; /* current tag */ unsigned char current_tag; /* current tag */
} Scsi_Device; } Scsi_Device;
/* /*
...@@ -315,6 +316,63 @@ struct scatterlist { ...@@ -315,6 +316,63 @@ struct scatterlist {
#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data) #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); void * scsi_malloc(unsigned int);
int scsi_free(void *, unsigned int); int scsi_free(void *, unsigned int);
extern unsigned int dma_free_sectors; /* How much room do we have left */ extern unsigned int dma_free_sectors; /* How much room do we have left */
...@@ -340,6 +398,7 @@ typedef struct scsi_pointer { ...@@ -340,6 +398,7 @@ typedef struct scsi_pointer {
typedef struct scsi_cmnd { typedef struct scsi_cmnd {
struct Scsi_Host * host; struct Scsi_Host * host;
Scsi_Device * device;
unsigned char target, lun, index; unsigned char target, lun, index;
struct scsi_cmnd *next, *prev; struct scsi_cmnd *next, *prev;
...@@ -355,6 +414,8 @@ typedef struct scsi_cmnd { ...@@ -355,6 +414,8 @@ typedef struct scsi_cmnd {
sense info */ sense info */
unsigned short use_sg; /* Number of pieces of scatter-gather */ unsigned short use_sg; /* Number of pieces of scatter-gather */
unsigned short sglist_len; /* size of malloc'd scatter-gather list */ 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 */ unsigned bufflen; /* Size of data buffer */
void *buffer; /* Data buffer */ void *buffer; /* Data buffer */
......
...@@ -521,7 +521,7 @@ int scsi_debug_detect(int hostnum) ...@@ -521,7 +521,7 @@ int scsi_debug_detect(int hostnum)
return 1; return 1;
} }
int scsi_debug_abort(Scsi_Cmnd * SCpnt,int i) int scsi_debug_abort(Scsi_Cmnd * SCpnt)
{ {
int j; int j;
void (*my_done)(Scsi_Cmnd *); void (*my_done)(Scsi_Cmnd *);
......
...@@ -23,5 +23,5 @@ int scsi_debug_reset(Scsi_Cmnd *); ...@@ -23,5 +23,5 @@ int scsi_debug_reset(Scsi_Cmnd *);
scsi_debug_reset, \ scsi_debug_reset, \
NULL, \ NULL, \
scsi_debug_biosparam, \ scsi_debug_biosparam, \
SCSI_DEBUG_MAILBOXES, 7, SG_ALL, 1, 0, 1} SCSI_DEBUG_MAILBOXES, 7, SG_ALL, 1, 0, 1, ENABLE_CLUSTERING}
#endif #endif
/* /*
* sd.c Copyright (C) 1992 Drew Eckhardt * sd.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994 Eric Youngdale
* Linux scsi disk driver by * Linux scsi disk driver by
* Drew Eckhardt * Drew Eckhardt
* *
* <drew@colorado.edu> * <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 * add scatter-gather, multiple outstanding request, and other
* enhancements. * enhancements.
*/ */
...@@ -40,7 +41,7 @@ static const char RCSid[] = "$Header:"; ...@@ -40,7 +41,7 @@ static const char RCSid[] = "$Header:";
#define SD_TIMEOUT 300 #define SD_TIMEOUT 300
#define SD_MOD_TIMEOUT 750 #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) scsi_devices[SC->index].type != TYPE_MOD)
struct hd_struct * sd; struct hd_struct * sd;
......
...@@ -1546,14 +1546,11 @@ else { ...@@ -1546,14 +1546,11 @@ else {
return retcode (st0x_aborted); return retcode (st0x_aborted);
} }
int seagate_st0x_abort (Scsi_Cmnd * SCpnt, int code) int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
{ {
if (code) st0x_aborted = DID_ABORT;
st0x_aborted = code;
else return SCSI_ABORT_PENDING;
st0x_aborted = DID_ABORT;
return 0;
} }
/* /*
...@@ -1590,8 +1587,7 @@ int seagate_st0x_reset (Scsi_Cmnd * SCpnt) ...@@ -1590,8 +1587,7 @@ int seagate_st0x_reset (Scsi_Cmnd * SCpnt)
#ifdef DEBUG #ifdef DEBUG
printk("SCSI bus reset.\n"); printk("SCSI bus reset.\n");
#endif #endif
if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; return SCSI_RESET_PENDING;
return 0;
} }
#ifdef CONFIG_BLK_DEV_SD #ifdef CONFIG_BLK_DEV_SD
......
...@@ -16,7 +16,7 @@ int seagate_st0x_detect(int); ...@@ -16,7 +16,7 @@ int seagate_st0x_detect(int);
int seagate_st0x_command(Scsi_Cmnd *); int seagate_st0x_command(Scsi_Cmnd *);
int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(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); const char *seagate_st0x_info(void);
int seagate_st0x_reset(Scsi_Cmnd *); int seagate_st0x_reset(Scsi_Cmnd *);
...@@ -34,7 +34,7 @@ int seagate_st0x_biosparam(int, int, int*); ...@@ -34,7 +34,7 @@ int seagate_st0x_biosparam(int, int, int*);
seagate_st0x_info, seagate_st0x_command, \ seagate_st0x_info, seagate_st0x_command, \
seagate_st0x_queue_command, seagate_st0x_abort, \ seagate_st0x_queue_command, seagate_st0x_abort, \
seagate_st0x_reset, NULL, seagate_st0x_biosparam, \ seagate_st0x_reset, NULL, seagate_st0x_biosparam, \
1, 7, SG_ALL, 1, 0, 0} 1, 7, SG_ALL, 1, 0, 0, DISABLE_CLUSTERING}
#endif #endif
......
/* /*
* sr.c by David Giller * sr.c Copyright (C) 1992 David Giller
* Copyright (C) 1993, 1994 Eric Youngdale
* *
* adapted from: * adapted from:
* sd.c Copyright (C) 1992 Drew Eckhardt * sd.c Copyright (C) 1992 Drew Eckhardt
...@@ -8,7 +9,7 @@ ...@@ -8,7 +9,7 @@
* *
* <drew@colorado.edu> * <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 * add scatter-gather, multiple outstanding request, and other
* enhancements. * enhancements.
*/ */
......
...@@ -91,7 +91,7 @@ ...@@ -91,7 +91,7 @@
#define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */ #define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */
#ifndef ASM #ifndef ASM
int t128_abort(Scsi_Cmnd *, int); int t128_abort(Scsi_Cmnd *);
int t128_biosparam(int, int, int*); int t128_biosparam(int, int, int*);
int t128_detect(int); int t128_detect(int);
const char *t128_info(void); const char *t128_info(void);
...@@ -122,7 +122,7 @@ int t128_reset(Scsi_Cmnd *); ...@@ -122,7 +122,7 @@ int t128_reset(Scsi_Cmnd *);
NULL, t128_queue_command, t128_abort, t128_reset, NULL, \ NULL, t128_queue_command, t128_abort, t128_reset, NULL, \
t128_biosparam, \ t128_biosparam, \
/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \ /* 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 #else
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu) * scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
* 24F and multiple command support by John F. Carr (jfc@athena.mit.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 * 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 * Thanks to UltraStor for providing the necessary documentation
*/ */
...@@ -796,7 +796,7 @@ int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) ...@@ -796,7 +796,7 @@ int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
*/ */
int ultrastor_abort(Scsi_Cmnd *SCpnt, int code) int ultrastor_abort(Scsi_Cmnd *SCpnt)
{ {
#if ULTRASTOR_DEBUG & UD_ABORT #if ULTRASTOR_DEBUG & UD_ABORT
char out[108]; char out[108];
...@@ -807,7 +807,8 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code) ...@@ -807,7 +807,8 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
unsigned char old_aborted; unsigned char old_aborted;
void (*done)(Scsi_Cmnd *); 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; mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp;
if (mscp_index >= ULTRASTOR_MAX_CMDS) if (mscp_index >= ULTRASTOR_MAX_CMDS)
...@@ -851,16 +852,16 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code) ...@@ -851,16 +852,16 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
cli(); cli();
ultrastor_interrupt(0); ultrastor_interrupt(0);
restore_flags(flags); restore_flags(flags);
return 0; return SCSI_ABORT_SUCCESS; /* FIXME - is this correct? -ERY */
} }
#endif #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 /* aborted == 0xff is the signal that queuecommand has not yet sent
the command. It will notice the new abort flag and fail. */ the command. It will notice the new abort flag and fail. */
if (old_aborted == 0xff) if (old_aborted == 0xff)
return 0; return SCSI_ABORT_SUCCESS;
/* On 24F, send an abort MSCP request. The adapter will interrupt /* On 24F, send an abort MSCP request. The adapter will interrupt
and the interrupt handler will call done. */ and the interrupt handler will call done. */
...@@ -879,7 +880,7 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code) ...@@ -879,7 +880,7 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
printk(out, ogm_status, ogm_addr, icm_status, icm_addr); printk(out, ogm_status, ogm_addr, icm_status, icm_addr);
#endif #endif
restore_flags(flags); restore_flags(flags);
return 0; return SCSI_ABORT_PENDING;
} }
#if ULTRASTOR_DEBUG & UD_ABORT #if ULTRASTOR_DEBUG & UD_ABORT
...@@ -891,13 +892,18 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code) ...@@ -891,13 +892,18 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
still be using it. Setting SCint = 0 causes the interrupt still be using it. Setting SCint = 0 causes the interrupt
handler to ignore the command. */ 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 ULTRASTOR_DEBUG & UD_ABORT
if (config.mscp[mscp_index].SCint != SCpnt) if (config.mscp[mscp_index].SCint != SCpnt)
printk("abort: command mismatch, %x != %x\n", printk("abort: command mismatch, %x != %x\n",
config.mscp[mscp_index].SCint, SCpnt); config.mscp[mscp_index].SCint, SCpnt);
#endif #endif
if (config.mscp[mscp_index].SCint == 0) if (config.mscp[mscp_index].SCint == 0)
return 1; return SCSI_ABORT_NOT_RUNNING;
if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort"); if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort");
config.mscp[mscp_index].SCint = 0; config.mscp[mscp_index].SCint = 0;
...@@ -908,7 +914,7 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code) ...@@ -908,7 +914,7 @@ int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
done(SCpnt); done(SCpnt);
/* Need to set a timeout here in case command never completes. */ /* Need to set a timeout here in case command never completes. */
return 0; return SCSI_ABORT_SUCCESS;
} }
...@@ -920,10 +926,8 @@ int ultrastor_reset(Scsi_Cmnd * SCpnt) ...@@ -920,10 +926,8 @@ int ultrastor_reset(Scsi_Cmnd * SCpnt)
printk("US14F: reset: called\n"); printk("US14F: reset: called\n");
#endif #endif
if(config.slot) { if(config.slot)
if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; return SCSI_RESET_SNOOZE; /* Do not attempt a reset for the 24f */
return 0; /* Do not attempt a reset for the 24f */
};
save_flags(flags); save_flags(flags);
cli(); cli();
...@@ -958,6 +962,9 @@ int ultrastor_reset(Scsi_Cmnd * SCpnt) ...@@ -958,6 +962,9 @@ int ultrastor_reset(Scsi_Cmnd * SCpnt)
} }
#endif #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); memset((unsigned char *)config.aborted, 0, sizeof config.aborted);
#if ULTRASTOR_MAX_CMDS == 1 #if ULTRASTOR_MAX_CMDS == 1
config.mscp_busy = 0; config.mscp_busy = 0;
...@@ -966,7 +973,7 @@ int ultrastor_reset(Scsi_Cmnd * SCpnt) ...@@ -966,7 +973,7 @@ int ultrastor_reset(Scsi_Cmnd * SCpnt)
#endif #endif
restore_flags(flags); restore_flags(flags);
return 0; return SCSI_RESET_SUCCESS;
} }
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
int ultrastor_detect(int); int ultrastor_detect(int);
const char *ultrastor_info(void); const char *ultrastor_info(void);
int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); 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_reset(Scsi_Cmnd *);
int ultrastor_biosparam(int, int, int *); int ultrastor_biosparam(int, int, int *);
...@@ -31,7 +31,8 @@ int ultrastor_biosparam(int, int, int *); ...@@ -31,7 +31,8 @@ int ultrastor_biosparam(int, int, int *);
{ "UltraStor 14F/24F/34F", ultrastor_detect, ultrastor_info, 0, \ { "UltraStor 14F/24F/34F", ultrastor_detect, ultrastor_info, 0, \
ultrastor_queuecommand, ultrastor_abort, ultrastor_reset, \ ultrastor_queuecommand, ultrastor_abort, ultrastor_reset, \
0, ultrastor_biosparam, ULTRASTOR_MAX_CMDS, 0, \ 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 #ifdef ULTRASTOR_PRIVATE
......
...@@ -1185,18 +1185,17 @@ int wd7000_detect(int hostnum) ...@@ -1185,18 +1185,17 @@ int wd7000_detect(int hostnum)
/* /*
* I have absolutely NO idea how to do an abort with the WD7000... * 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 Adapter *host = (Adapter *) SCpnt->host->hostdata;
printk("wd7000_abort: Scsi_Cmnd = 0x%06x, code = %d ", (int) SCpnt, i);
printk("id %d lun %d cdb", SCpnt->target, SCpnt->lun); if (inb(host->iobase+ASC_STAT) & INT_IM) {
{ printk("wd7000_abort: lost interrupt\n");
int j; unchar *cdbj = (unchar *) SCpnt->cmnd; wd7000_intr_handle(host->irq);
for (j=0; j < COMMAND_SIZE(*cdbj); j++) printk(" %02x", *(cdbj++)); return SCSI_ABORT_SUCCESS;
printk(" result %08x\n", SCpnt->result);
} }
#endif
return 0; return SCSI_ABORT_SNOOZE;
} }
...@@ -1205,21 +1204,7 @@ int wd7000_abort(Scsi_Cmnd * SCpnt, int i) ...@@ -1205,21 +1204,7 @@ int wd7000_abort(Scsi_Cmnd * SCpnt, int i)
*/ */
int wd7000_reset(Scsi_Cmnd * SCpnt) int wd7000_reset(Scsi_Cmnd * SCpnt)
{ {
#ifdef DEBUG return SCSI_RESET_SNOOZE;
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;
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
int wd7000_detect(int); int wd7000_detect(int);
int wd7000_command(Scsi_Cmnd *); int wd7000_command(Scsi_Cmnd *);
int wd7000_queuecommand(Scsi_Cmnd *, void (*done)(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); const char *wd7000_info(void);
int wd7000_reset(Scsi_Cmnd *); int wd7000_reset(Scsi_Cmnd *);
int wd7000_biosparam(int, int, int*); int wd7000_biosparam(int, int, int*);
...@@ -48,5 +48,5 @@ int wd7000_biosparam(int, int, int*); ...@@ -48,5 +48,5 @@ int wd7000_biosparam(int, int, int*);
wd7000_reset, \ wd7000_reset, \
NULL, \ NULL, \
wd7000_biosparam, \ wd7000_biosparam, \
WD7000_Q, 7, WD7000_SG, 1, 0, 1} WD7000_Q, 7, WD7000_SG, 1, 0, 1, ENABLE_CLUSTERING}
#endif #endif
...@@ -572,6 +572,8 @@ void flush_old_exec(struct linux_binprm * bprm) ...@@ -572,6 +572,8 @@ void flush_old_exec(struct linux_binprm * bprm)
last_task_used_math = NULL; last_task_used_math = NULL;
current->used_math = 0; current->used_math = 0;
current->personality = 0; current->personality = 0;
current->lcall7 = no_lcall7;
current->signal_map = current->signal_invmap = ident_map;
} }
/* /*
...@@ -762,6 +764,25 @@ asmlinkage int sys_execve(struct pt_regs regs) ...@@ -762,6 +764,25 @@ asmlinkage int sys_execve(struct pt_regs regs)
return error; 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) static void set_brk(unsigned long start, unsigned long end)
{ {
start = PAGE_ALIGN(start); start = PAGE_ALIGN(start);
......
...@@ -543,8 +543,9 @@ int ext_rmdir(struct inode * dir, const char * name, int len) ...@@ -543,8 +543,9 @@ int ext_rmdir(struct inode * dir, const char * name, int len)
retval = -EPERM; retval = -EPERM;
if (!(inode = iget(dir->i_sb, de->inode))) if (!(inode = iget(dir->i_sb, de->inode)))
goto end_rmdir; goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && current->euid && if ((dir->i_mode & S_ISVTX) && !suser() &&
inode->i_uid != current->euid) current->euid != inode->i_uid &&
current->euid != dir->i_uid)
goto end_rmdir; goto end_rmdir;
if (inode->i_dev != dir->i_dev) if (inode->i_dev != dir->i_dev)
goto end_rmdir; goto end_rmdir;
......
...@@ -277,10 +277,6 @@ static int ext2_file_write (struct inode * inode, struct file * filp, ...@@ -277,10 +277,6 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
} }
p = (pos % sb->s_blocksize) + bh->b_data; p = (pos % sb->s_blocksize) + bh->b_data;
pos += c; pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
inode->i_dirt = 1;
}
written += c; written += c;
memcpy_fromfs (p, buf, c); memcpy_fromfs (p, buf, c);
buf += c; buf += c;
...@@ -288,6 +284,8 @@ static int ext2_file_write (struct inode * inode, struct file * filp, ...@@ -288,6 +284,8 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
mark_buffer_dirty(bh, 0); mark_buffer_dirty(bh, 0);
brelse (bh); brelse (bh);
} }
if (pos > inode->i_size)
inode->i_size = pos;
up(&inode->i_sem); up(&inode->i_sem);
inode->i_ctime = inode->i_mtime = CURRENT_TIME; inode->i_ctime = inode->i_mtime = CURRENT_TIME;
filp->f_pos = pos; filp->f_pos = pos;
......
...@@ -630,8 +630,9 @@ int ext2_rmdir (struct inode * dir, const char * name, int len) ...@@ -630,8 +630,9 @@ int ext2_rmdir (struct inode * dir, const char * name, int len)
schedule(); schedule();
goto repeat; goto repeat;
} }
if ((dir->i_mode & S_ISVTX) && current->euid && if ((dir->i_mode & S_ISVTX) && !suser() &&
inode->i_uid != current->euid) current->euid != inode->i_uid &&
current->euid != dir->i_uid)
goto end_rmdir; goto end_rmdir;
if (inode == dir) /* we may not delete ".", but "../dir" is ok */ if (inode == dir) /* we may not delete ".", but "../dir" is ok */
goto end_rmdir; goto end_rmdir;
......
...@@ -410,8 +410,8 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, ...@@ -410,8 +410,8 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
brelse (bh); brelse (bh);
set_blocksize (dev, sb->s_blocksize); set_blocksize (dev, sb->s_blocksize);
logic_sb_block = sb_block / sb->s_blocksize; logic_sb_block = (sb_block*BLOCK_SIZE) / sb->s_blocksize;
offset = sb_block % sb->s_blocksize; offset = (sb_block*BLOCK_SIZE) % sb->s_blocksize;
bh = bread (dev, logic_sb_block, sb->s_blocksize); bh = bread (dev, logic_sb_block, sb->s_blocksize);
if(!bh) if(!bh)
return NULL; return NULL;
......
...@@ -201,16 +201,13 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf ...@@ -201,16 +201,13 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
printk("minix_file_write: mode = %07o\n",inode->i_mode); printk("minix_file_write: mode = %07o\n",inode->i_mode);
return -EINVAL; return -EINVAL;
} }
/* down(&inode->i_sem);
* ok, append may not work when many processes are writing at the same time
* but so what. That way leads to madness anyway.
*/
if (filp->f_flags & O_APPEND) if (filp->f_flags & O_APPEND)
pos = inode->i_size; pos = inode->i_size;
else else
pos = filp->f_pos; pos = filp->f_pos;
written = 0; written = 0;
while (written<count) { while (written < count) {
bh = minix_getblk(inode,pos/BLOCK_SIZE,1); bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
if (!bh) { if (!bh) {
if (!written) if (!written)
...@@ -232,10 +229,6 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf ...@@ -232,10 +229,6 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
} }
p = (pos % BLOCK_SIZE) + bh->b_data; p = (pos % BLOCK_SIZE) + bh->b_data;
pos += c; pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
inode->i_dirt = 1;
}
written += c; written += c;
memcpy_fromfs(p,buf,c); memcpy_fromfs(p,buf,c);
buf += c; buf += c;
...@@ -243,6 +236,9 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf ...@@ -243,6 +236,9 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
mark_buffer_dirty(bh, 0); mark_buffer_dirty(bh, 0);
brelse(bh); brelse(bh);
} }
if (pos > inode->i_size)
inode->i_size = pos;
up(&inode->i_sem);
inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos; filp->f_pos = pos;
inode->i_dirt = 1; inode->i_dirt = 1;
......
...@@ -443,8 +443,9 @@ int minix_rmdir(struct inode * dir, const char * name, int len) ...@@ -443,8 +443,9 @@ int minix_rmdir(struct inode * dir, const char * name, int len)
retval = -EPERM; retval = -EPERM;
if (!(inode = iget(dir->i_sb, de->inode))) if (!(inode = iget(dir->i_sb, de->inode)))
goto end_rmdir; goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && current->euid && if ((dir->i_mode & S_ISVTX) && !suser() &&
inode->i_uid != current->euid) current->euid != inode->i_uid &&
current->euid != dir->i_uid)
goto end_rmdir; goto end_rmdir;
if (inode->i_dev != dir->i_dev) if (inode->i_dev != dir->i_dev)
goto end_rmdir; goto end_rmdir;
......
...@@ -447,8 +447,9 @@ int sysv_rmdir(struct inode * dir, const char * name, int len) ...@@ -447,8 +447,9 @@ int sysv_rmdir(struct inode * dir, const char * name, int len)
retval = -EPERM; retval = -EPERM;
if (!(inode = iget(dir->i_sb, de->inode))) if (!(inode = iget(dir->i_sb, de->inode)))
goto end_rmdir; goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && current->euid && if ((dir->i_mode & S_ISVTX) && !suser() &&
inode->i_uid != current->euid) current->euid != inode->i_uid &&
current->euid != dir->i_uid)
goto end_rmdir; goto end_rmdir;
if (inode->i_dev != dir->i_dev) if (inode->i_dev != dir->i_dev)
goto end_rmdir; goto end_rmdir;
......
...@@ -496,8 +496,9 @@ int xiafs_rmdir(struct inode * dir, const char * name, int len) ...@@ -496,8 +496,9 @@ int xiafs_rmdir(struct inode * dir, const char * name, int len)
retval = -EPERM; retval = -EPERM;
if (!(inode = iget(dir->i_sb, de->d_ino))) if (!(inode = iget(dir->i_sb, de->d_ino)))
goto end_rmdir; goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && current->euid && if ((dir->i_mode & S_ISVTX) && !suser() &&
inode->i_uid != current->euid) current->euid != inode->i_uid &&
current->euid != dir->i_uid)
goto end_rmdir; goto end_rmdir;
if (inode->i_dev != dir->i_dev) if (inode->i_dev != dir->i_dev)
goto end_rmdir; goto end_rmdir;
......
...@@ -36,4 +36,3 @@ dummy: ...@@ -36,4 +36,3 @@ dummy:
ifeq (.depend,$(wildcard .depend)) ifeq (.depend,$(wildcard .depend))
include .depend include .depend
endif endif
...@@ -5,23 +5,6 @@ ...@@ -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);
}
...@@ -89,6 +89,7 @@ extern unsigned long avenrun[]; /* Load averages */ ...@@ -89,6 +89,7 @@ extern unsigned long avenrun[]; /* Load averages */
#include <linux/resource.h> #include <linux/resource.h>
#include <linux/vm86.h> #include <linux/vm86.h>
#include <linux/math_emu.h> #include <linux/math_emu.h>
#include <linux/ptrace.h>
#define TASK_RUNNING 0 #define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1 #define TASK_INTERRUPTIBLE 1
...@@ -251,6 +252,7 @@ struct task_struct { ...@@ -251,6 +252,7 @@ struct task_struct {
unsigned long flags; /* per process flags, defined below */ unsigned long flags; /* per process flags, defined below */
int errno; int errno;
int debugreg[8]; /* Hardware debugging registers */ int debugreg[8]; /* Hardware debugging registers */
asmlinkage void (*lcall7)(struct pt_regs *);
/* various fields */ /* various fields */
struct task_struct *next_task, *prev_task; struct task_struct *next_task, *prev_task;
struct sigaction sigaction[32]; struct sigaction sigaction[32];
...@@ -324,6 +326,7 @@ struct task_struct { ...@@ -324,6 +326,7 @@ struct task_struct {
#define INIT_TASK \ #define INIT_TASK \
/* state etc */ { 0,15,15,0,0,0,0, \ /* state etc */ { 0,15,15,0,0,0,0, \
/* debugregs */ { 0, }, \ /* debugregs */ { 0, }, \
/* lcall 7 */ no_lcall7, \
/* schedlink */ &init_task,&init_task, \ /* schedlink */ &init_task,&init_task, \
/* signals */ {{ 0, },}, ident_map, ident_map, \ /* signals */ {{ 0, },}, ident_map, ident_map, \
/* stack */ 0,(unsigned long) &init_kernel_stack, \ /* stack */ 0,(unsigned long) &init_kernel_stack, \
...@@ -358,6 +361,9 @@ extern unsigned long itimer_next; ...@@ -358,6 +361,9 @@ extern unsigned long itimer_next;
extern struct timeval xtime; extern struct timeval xtime;
extern int need_resched; extern int need_resched;
extern unsigned long ident_map[33];
extern asmlinkage void no_lcall7(struct pt_regs *);
#define CURRENT_TIME (xtime.tv_sec) #define CURRENT_TIME (xtime.tv_sec)
extern void sleep_on(struct wait_queue ** p); extern void sleep_on(struct wait_queue ** p);
......
...@@ -99,11 +99,10 @@ __asm__("cld\n" ...@@ -99,11 +99,10 @@ __asm__("cld\n"
"jne 1b\n\t" "jne 1b\n\t"
"xorl %%eax,%%eax\n\t" "xorl %%eax,%%eax\n\t"
"jmp 3f\n" "jmp 3f\n"
"2:\tmovl $1,%%eax\n\t" "2:\tsbbl %%eax,%%eax\n\t"
"jb 3f\n\t" "orb $1,%%eax\n"
"negl %%eax\n"
"3:" "3:"
:"=a" (__res):"D" (cs),"S" (ct):"si","di"); :"=a" (__res):"S" (cs),"D" (ct):"si","di");
return __res; return __res;
} }
...@@ -120,11 +119,10 @@ __asm__("cld\n" ...@@ -120,11 +119,10 @@ __asm__("cld\n"
"jne 1b\n" "jne 1b\n"
"2:\txorl %%eax,%%eax\n\t" "2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n" "jmp 4f\n"
"3:\tmovl $1,%%eax\n\t" "3:\tsbbl %%eax,%%eax\n\t"
"jb 4f\n\t" "orb $1,%%al\n"
"negl %%eax\n"
"4:" "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; return __res;
} }
...@@ -153,8 +151,7 @@ __asm__("cld\n\t" ...@@ -153,8 +151,7 @@ __asm__("cld\n\t"
"1:\tlodsb\n\t" "1:\tlodsb\n\t"
"cmpb %%ah,%%al\n\t" "cmpb %%ah,%%al\n\t"
"jne 2f\n\t" "jne 2f\n\t"
"movl %%esi,%0\n\t" "leal -1(%%esi),%0\n"
"decl %0\n"
"2:\ttestb %%al,%%al\n\t" "2:\ttestb %%al,%%al\n\t"
"jne 1b" "jne 1b"
:"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si"); :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
...@@ -384,11 +381,10 @@ __asm__("cld\n\t" ...@@ -384,11 +381,10 @@ __asm__("cld\n\t"
"repe\n\t" "repe\n\t"
"cmpsb\n\t" "cmpsb\n\t"
"je 1f\n\t" "je 1f\n\t"
"movl $1,%%eax\n\t" "sbbl %%eax,%%eax\n\t"
"jb 1f\n\t" "orb $1,%%al\n"
"negl %%eax\n"
"1:" "1:"
:"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count) :"=a" (__res):"0" (0),"S" (cs),"D" (ct),"c" (count)
:"si","di","cx"); :"si","di","cx");
return __res; return __res;
} }
......
...@@ -282,12 +282,10 @@ int kill_proc(int pid, int sig, int priv) ...@@ -282,12 +282,10 @@ int kill_proc(int pid, int sig, int priv)
* POSIX specifies that kill(-1,sig) is unspecified, but what we have * POSIX specifies that kill(-1,sig) is unspecified, but what we have
* is probably wrong. Should make it like BSD or SYSV. * 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; int err, retval = 0, count = 0;
if (sig > 32)
return -EINVAL;
if (!pid) if (!pid)
return(kill_pg(current->pgrp,sig,0)); return(kill_pg(current->pgrp,sig,0));
if (pid == -1) { if (pid == -1) {
......
...@@ -87,16 +87,6 @@ extern void mem_use(void); ...@@ -87,16 +87,6 @@ extern void mem_use(void);
extern int timer_interrupt(void); extern int timer_interrupt(void);
asmlinkage int system_call(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, }; static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
struct task_struct init_task = INIT_TASK; struct task_struct init_task = INIT_TASK;
......
...@@ -78,6 +78,7 @@ flags = 20 ...@@ -78,6 +78,7 @@ flags = 20
errno = 24 errno = 24
dbgreg6 = 52 dbgreg6 = 52
dbgreg7 = 56 dbgreg7 = 56
lcall7 = 60
ENOSYS = 38 ENOSYS = 38
...@@ -141,8 +142,10 @@ _lcall7: ...@@ -141,8 +142,10 @@ _lcall7:
movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %edx,EIP(%esp) # Now we move them to their "normal" places
movl %ecx,CS(%esp) # movl %ecx,CS(%esp) #
movl %esp,%eax movl %esp,%eax
movl _current,%edx
pushl %eax pushl %eax
call _iABI_emulate movl lcall7(%edx),%edx
call *%edx
popl %eax popl %eax
jmp ret_from_sys_call jmp ret_from_sys_call
......
...@@ -1264,7 +1264,7 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) ...@@ -1264,7 +1264,7 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
return; return;
} }
if(memcmp(skb->data,dev->broadcast, dev->addr_len)) if(!memcmp(skb->data,dev->broadcast, dev->addr_len))
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment