]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.132pre3 2.1.132pre3
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:36 +0000 (15:17 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:36 +0000 (15:17 -0500)
160 files changed:
CREDITS
Documentation/00-INDEX
Documentation/Configure.help
Documentation/networking/ip-sysctl.txt
Documentation/smp [deleted file]
Documentation/smp.txt [new file with mode: 0644]
Documentation/sound/OPL3-SA2 [new file with mode: 0644]
Makefile
Rules.make
arch/alpha/config.in
arch/alpha/kernel/Makefile
arch/alpha/kernel/alpha_ksyms.c
arch/alpha/kernel/irq.c
arch/alpha/kernel/sys_sio.c
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/Makefile
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
arch/i386/kernel/irq.h
arch/i386/kernel/smp.c
arch/i386/kernel/time.c
arch/m68k/mac/mackeyb.c
arch/ppc/config.in
arch/ppc/defconfig
arch/ppc/kernel/Makefile
arch/ppc/lib/Makefile
arch/ppc/mbx_defconfig
arch/ppc/pmac_defconfig
arch/ppc/prep_defconfig
arch/sparc/config.in
arch/sparc/defconfig
arch/sparc/kernel/Makefile
arch/sparc/lib/Makefile
arch/sparc/mm/Makefile
arch/sparc64/Makefile
arch/sparc64/config.in
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
drivers/block/z2ram.c
drivers/cdrom/cdu31a.c
drivers/cdrom/mcdx.c
drivers/cdrom/sbpcd.c
drivers/cdrom/sjcd.c
drivers/char/mac_SCC.c
drivers/char/serial.c
drivers/net/Makefile
drivers/net/Space.c
drivers/net/acenic.c
drivers/net/epic100.c
drivers/net/hamradio/scc.c
drivers/net/ibmtr.c
drivers/net/irda/actisys.c
drivers/net/irda/esi.c
drivers/net/irda/pc87108.c
drivers/net/irda/tekram.c
drivers/net/irda/w83977af_ir.c
drivers/net/lance.c
drivers/net/net_init.c
drivers/net/ppp.c
drivers/net/rcif.h [new file with mode: 0644]
drivers/net/rcmtl.c [new file with mode: 0644]
drivers/net/rcmtl.h [new file with mode: 0644]
drivers/net/rcpci45.c [new file with mode: 0644]
drivers/net/slhc.c
drivers/net/via-rhine.c
drivers/net/yellowfin.c
drivers/pnp/parport_probe.c
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/NCR5380.c
drivers/scsi/NCR53C9x.c
drivers/scsi/NCR53C9x.h
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx_proc.c
drivers/scsi/atp870u.c [new file with mode: 0644]
drivers/scsi/atp870u.h [new file with mode: 0644]
drivers/scsi/fd_mcs.c
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/i91uscsi.c [new file with mode: 0644]
drivers/scsi/i91uscsi.h [new file with mode: 0644]
drivers/scsi/ini9100u.c [new file with mode: 0644]
drivers/scsi/ini9100u.h [new file with mode: 0644]
drivers/scsi/mac_esp.c [new file with mode: 0644]
drivers/scsi/mac_esp.h [new file with mode: 0644]
drivers/scsi/mca_53c9x.c [new file with mode: 0644]
drivers/scsi/mca_53c9x.h [new file with mode: 0644]
drivers/scsi/megaraid.c [new file with mode: 0644]
drivers/scsi/megaraid.h [new file with mode: 0644]
drivers/scsi/ppa.h
drivers/scsi/scsi.c
fs/ChangeLog
fs/affs/namei.c
fs/coda/Makefile
fs/coda/cache.c
fs/coda/cnode.c
fs/coda/coda_linux.c
fs/coda/dir.c
fs/coda/inode.c
fs/coda/psdev.c
fs/coda/stats.c
fs/coda/symlink.c
fs/coda/sysctl.c
fs/coda/upcall.c
fs/ext2/namei.c
fs/minix/namei.c
fs/msdos/namei.c
fs/namei.c
fs/nfsd/vfs.c
fs/nls/Config.in
fs/nls/Makefile
fs/nls/nls_base.c
fs/nls/nls_iso8859-15.c [new file with mode: 0644]
fs/proc/array.c
fs/proc/root.c
fs/qnx4/namei.c
fs/sysv/CHANGES
fs/sysv/namei.c
fs/ufs/namei.c
fs/umsdos/check.c
fs/vfat/namei.c
include/asm-i386/smp.h
include/linux/coda_cache.h
include/linux/coda_fs_i.h
include/linux/coda_linux.h
include/linux/coda_psdev.h
include/linux/fs.h
include/linux/mm.h
include/linux/proc_fs.h
include/linux/scc.h
include/linux/shm.h
include/linux/swap.h
include/linux/swapctl.h
include/linux/sysctl.h
include/linux/tasks.h
include/net/ax25.h
init/main.c
ipc/shm.c
kernel/ksyms.c
kernel/signal.c
kernel/sysctl.c
mm/filemap.c
mm/page_alloc.c
mm/page_io.c
mm/swap.c
mm/swap_state.c
mm/vmscan.c
net/ax25/af_ax25.c
net/ax25/ax25_ds_in.c
net/ax25/ax25_ds_timer.c
net/ax25/ax25_in.c
net/ax25/ax25_out.c
net/core/dev.c
net/ipv4/icmp.c
net/ipv4/sysctl_net_ipv4.c
net/irda/compressors/irda_deflate.c
net/irda/ircomm/irvtd.c
net/irda/irlap_comp.c
scripts/mkdep.c

diff --git a/CREDITS b/CREDITS
index f17f3ef6ea6bf976f12bd8eacfb1f0c26c57bc78..8269e777ef643190b7aba5f2a1c2f894eb5da2bb 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -265,6 +265,14 @@ S: 403 Gilmore Avenue
 S: Trafford, Pennsylvania 15085
 S: USA
 
+N: Dag Brattli
+E: dagb@cs.uit.no
+W: http://www.cs.uit.no/~dagb
+D: IrDA Subsystem
+S: 19. Wellington Road
+S: Lancaster, LA1 4DN
+S: UK, England
+
 N: Andries Brouwer
 E: aeb@cwi.nl
 D: random Linux hacker
@@ -338,10 +346,12 @@ S: Stanford, California 94305
 S: USA
 
 N: Juan Jose Ciarlante
+W: http://juanjox.linuxhq.com/
 E: jjciarla@raiz.uncu.edu.ar
-E: juanjo@irriga.uncu.edu.ar
+E: jjo@mendoza.gov.ar
 D: Network driver alias support
 D: IP masq hashing and app modules
+D: IP masq 2.1 features and bugs
 S: Las Cuevas 2385 - Bo Guemes
 S: Las Heras, Mendoza CP 5539
 S: Argentina
@@ -435,6 +445,15 @@ S: New Mexico Tech
 S: Socorro, New Mexico 87801
 S: USA
 
+N: Oleg Drokin
+E: green@ccssu.crimea.ua
+W: http://www.ccssu.crimea.ua/~green
+D: Cleaning up sound drivers.
+S: Skvoznoy per., 14a
+S: Evpatoria
+S: Crimea
+S: UKRAINE, 334320
+
 N: Thomas Dunbar
 E: tdunbar@vtaix.cc.vt.edu
 D: TeX & METAFONT hacking/maintenance
@@ -642,6 +661,17 @@ S: 8124 Constitution Apt. 7
 S: Sterling Heights, Michigan 48313
 S: USA
 
+N: Tristan Greaves
+E: Tristan.Greaves@icl.com
+E: tmg296@ecs.soton.ac.uk
+W: http://www.ecs.soton.ac.uk/~tmg296
+D: Miscellaneous ipv4 sysctl patches
+S: 15 Little Mead
+S: Denmead
+S: Hampshire
+S: PO7 6HS
+S: United Kingdom
+
 N: Michael A. Griffith
 E: grif@cs.ucr.edu
 W: http://www.cs.ucr.edu/~grif
@@ -863,6 +893,14 @@ S: Na Orechovce 7
 S: 160 00 Praha 6
 S: Czech Republic
 
+N: Niels Kristian Bech Jensen
+E: nkbj@image.dk
+W: http://www.image.dk/~nkbj
+D: 4.4BSD and NeXTstep support in read-only ufs
+S: Dr. Holsts Vej 34, lejl. 164
+S: DK-8230 Ã…byhøj
+S: Denmark
+
 N: Michael K. Johnson
 E: johnsonm@redhat.com
 W: http://www.redhat.com/~johnsonm
@@ -887,6 +925,17 @@ S: Tallak 95
 S: 8103 Rein
 S: Austria
 
+N: Jan "Yenya" Kasprzak
+E: kas@fi.muni.cz
+D: Author of the COSA/SRP sync serial board driver.
+D: Port of the syncppp.c from the 2.0 to the 2.1 kernel.
+P: 1024/D3498839 0D 99 A7 FB 20 66 05 D7  8B 35 FC DE 05 B1 8A 5E
+W: http://www.fi.muni.cz/~kas/
+S: c/o Faculty of Informatics, Masaryk University
+S: Botanicka' 68a
+S: 602 00 Brno
+S: Czech Republic
+
 N: Fred N. van Kempen
 E: waltje@uwalt.nl.mugnet.org
 D: NET-2
@@ -933,6 +982,17 @@ S: Post Office Box 611311
 S: San Jose, California 95161-1311
 S: USA
 
+N: Thorsten Knabe
+E: Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
+E: Thorsten Knabe <tek01@hrzpub.tu-darmstadt.de>
+W: http://www.student.informatik.tu-darmstadt.de/~tek
+W: http://www.tu-darmstadt.de/~tek01
+P: 1024/3BC8D885 8C 29 C5 0A C0 D1 D6 F4  20 D4 2D AB 29 F6 D0 60
+D: AD1816 sound driver
+S: Am Bergfried 10
+S: 63225 Langen
+S: Germany
+
 N: Alain L. Knaff
 E: Alain.Knaff@poboxes.com
 D: floppy driver
@@ -1026,11 +1086,11 @@ S: 3817 KS Amersfoort
 S: The Netherlands
 
 N: Volker Lendecke
-E: lendecke@namu01.Num.Math.Uni-Goettingen.de
+E: vl@kki.org
 D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.)
 D: NCP filesystem support (to mount NetWare volumes)
-S: Innersteweg 11
-S: 37081 Goettingen
+S: Von Ossietzky Str. 12
+S: 37085 Goettingen
 S: Germany
 
 N: Kevin Lentin
@@ -1551,7 +1611,7 @@ D: the gpm mouse server and kernel support for it
 
 N: Paul Russell
 E: Paul.Russell@rustcorp.com.au
-W: http://www.adelaide.net.au/~rustcorp
+W: http://www.rustcorp.com
 D: Ruggedly handsome.
 D: Developed Generic IP Firewalling Chains with Michael Neuling.
 
@@ -1591,6 +1651,11 @@ S: Molenbaan 29
 S: B2240 Zandhoven
 S: Belgium
 
+N: Henning P. Schmiedehausen
+E: hps@tanstaafl.de
+D: added PCI support to the serial driver
+S: Buckenhof, Germany
+
 N: Martin Schulze
 E: joey@linux.de
 W: http://home.pages.de/~joey/
@@ -1950,7 +2015,8 @@ S: USA
 
 N: Steven Whitehouse
 E: SteveW@ACM.org
-D: Linux DECnet project: http://eeshack3.swan.ac.uk/~gw7rrm/DECnet/index.html
+W: http://www-sigproc.eng.cam.ac.uk/~sjw44/
+D: Linux DECnet project: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html
 D: Minor debugging of other networking protocols.
 
 N: Hans-Joachim Widmaier
index ed078ac3e1d390e508121a36c738e01faf88a437..21a20542cafa558b5d6b5a3696fa6d23ae9f66aa 100644 (file)
@@ -111,10 +111,10 @@ serial-console.txt
        - how to set up linux with a serial line console as the default.
 smart-config.txt
        - description of the Smart Config makefile feature.
-smp
-       - how to setup the kernel for SMP
 smp.tex
        - TeX document describing implementation of Multiprocessor Linux
+smp.txt
+       - a few more notes on symmetric multi-processing
 sound/
        - directory with info on sound card support
 specialix.txt
index 34b408df656cd6732ca0e70688a2c79949227fa6..a1aabb540872bb8a69e9ecd333ed2226245c43c8 100644 (file)
@@ -7418,6 +7418,21 @@ CONFIG_NLS_ISO8859_10
   letters that were missing in Latin 4 to cover the entire Nordic
   area.
 
+nls iso8859-15
+CONFIG_NLS_ISO8859_15
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 9 character
+  set, which covers most West European languages such as Albanian,
+  Catalan, Danish, Dutch, English, Estonian, Faeroese, Finnish,
+  French, German, Galician, Irish, Icelandic, Italian, Norwegian,
+  Portuguese, Spanish, Swedish, and Valencian. Latin 9 is an update to
+  Latin 1 (ISO 8859-1) that removes a handful of rarely used
+  characters and instead adds support for Estonian, corrects the
+  support for French and Finnish, and adds the new Euro character.  If
+  unsure, say Y.
+
 nls koi8-r
 CONFIG_NLS_KOI8_R
   If you want to display filenames with native language characters
index 1d015b2e231e2452115868873932210818e5f705..8d2aa9eaf10d7c3d04d8995e6af3bd1b1bddc2e9 100644 (file)
@@ -123,6 +123,12 @@ icmp_echoreply_rate - INTEGER (not enabled per default)
        0 to disable any limiting, otherwise the maximal rate in jiffies(1)
        See the source for more information.
 
+icmp_ignore_bogus_error_responses - BOOLEAN
+       Some routers violate RFC 1122 by sending bogus responses to broadcast
+       frames.  Such violations are normally logged via a kernel warning.
+       If this is set to TRUE, the kernel will not give such warnings, which
+       will avoid log file clutter.
+       Default: FALSE
 
 (1) Jiffie: internal timeunit for the kernel. On the i386 1/100s, on the
 Alpha 1/1024s. See the HZ define in /usr/include/asm/param.h for the exact
diff --git a/Documentation/smp b/Documentation/smp
deleted file mode 100644 (file)
index 5706552..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-To set up SMP
-
-Edit linux/Makefile and uncomment SMP=1, then compile and install
-as usual.
-
-If you are using LILO, it is handy to have both SMP and non-SMP
-kernel images on hand. Edit /etc/lilo.conf to create an entry
-for another kernel image called "linux-smp" or something.
-
-The next time you compile the kernel, when running a SMP kernel,
-edit linux/Makefile and change "MAKE=make" to "MAKE=make -jN"
-(where N = number of CPU + 1, or if you have tons of memory/swap
- you can just use "-j" without a number). Feel free to experiment
-with this one.
-
-Of course you should time how long each build takes :-)
-Example:
-   make config
-   time -v sh -c 'make dep ; make clean install modules modules_install'
-
-If you are using some Compaq MP compliant machines you will need to set
-the operating system in the BIOS settings to "Unixware" - don't ask me
-why Compaqs don't work otherwise.
diff --git a/Documentation/smp.txt b/Documentation/smp.txt
new file mode 100644 (file)
index 0000000..130d647
--- /dev/null
@@ -0,0 +1,22 @@
+To set up SMP
+
+Configure the kernel and answer Y to CONFIG_SMP.
+
+If you are using LILO, it is handy to have both SMP and non-SMP
+kernel images on hand. Edit /etc/lilo.conf to create an entry
+for another kernel image called "linux-smp" or something.
+
+The next time you compile the kernel, when running a SMP kernel,
+edit linux/Makefile and change "MAKE=make" to "MAKE=make -jN"
+(where N = number of CPU + 1, or if you have tons of memory/swap
+ you can just use "-j" without a number). Feel free to experiment
+with this one.
+
+Of course you should time how long each build takes :-)
+Example:
+   make config
+   time -v sh -c 'make dep ; make clean install modules modules_install'
+
+If you are using some Compaq MP compliant machines you will need to set
+the operating system in the BIOS settings to "Unixware" - don't ask me
+why Compaqs don't work otherwise.
diff --git a/Documentation/sound/OPL3-SA2 b/Documentation/sound/OPL3-SA2
new file mode 100644 (file)
index 0000000..5a50e16
--- /dev/null
@@ -0,0 +1,121 @@
+Documentation for the OPL3-SA2, SA3, and SAx driver (opl3sa2.o)
+---------------------------------------------------------------
+
+Scott Murray, scottm@interlog.com
+December, 1998
+
+NOTE: All trademarked terms mentioned below are properties of their
+      respective owners.
+
+This driver is for PnP soundcards based on the following Yamaha audio
+controller chipsets:
+
+YMF711 aka OPL3-SA2
+YMF715 aka OPL3-SA3
+YMF719 aka OPL3-SAx (?)
+
+I'm a little fuzzy on what is classified a SAx, as I've seen the label
+used to refer to the whole 7xx family and as a specific identifier for
+the 719 on my no-name soundcard.  To make matters worse, there seem to
+be several reversions of the 715 chipset.
+
+Anyways, all of these chipsets implement the following devices:
+
+OPL3 FM synthesizer
+Soundblaster Pro
+Microsoft/Windows Sound System
+MPU401 MIDI interface
+
+Note that this driver uses the MSS device, and to my knowledge these
+chipsets enforce an either/or situation with the Soundblaster Pro
+device and the MSS device.  Since the MSS device has better
+capabilities, I have implemented the driver to use it.
+
+Being PnP cards, some configuration is required.  There are two ways
+of doing this.  The most common is to use the isapnptools package to
+initialize the card, and use the kernel module form of the sound
+subsystem and sound drivers.  Alternatively, some BIOS's allow manual
+configuration of installed PnP devices in the BIOS menus, which should
+allow using the non-modular sound drivers, i.e. built into the kernel.
+
+I personally use isapnp and modules, and do not have access to a PnP
+BIOS machine to test.  If you have such a beast, try building both the
+MSS driver and this driver into the kernel (appropiately configured,
+of course) and let me know if it works.  If it does not, then email me
+if you are willing to experiment in an effort to make it work.
+
+If you are using isapnp, follow the directions in its documentation to
+produce a configuration file.  Here is the relevant excerpt for my SAx
+card from my isapnp.conf:
+
+(CONFIGURE YMH0800/-1 (LD 0
+
+# Instead of (IO 0 (BASE 0x0220)), disable SB:
+(IO 0 (BASE 0x0000))
+(IO 1 (BASE 0x0530))
+(IO 2 (BASE 0x0388))
+(IO 3 (BASE 0x0330))
+(IO 4 (BASE 0x0370))
+(INT 0 (IRQ 7 (MODE +E)))
+(DMA 0 (CHANNEL 0))
+(DMA 1 (CHANNEL 3))
+
+Here, note that:
+
+Port  Acceptable Range  Purpose
+----  ----------------  -------
+IO 0  0x0220 - 0x0280   SB base address, I set to 0 just to be safe.
+IO 1  0x0530 - 0x0F48   MSS base address
+IO 2  0x0388 - 0x03F8   OPL3 base address
+IO 3  0x0300 - 0x0334   MPU base address
+IO 4  0x0100 - 0x0FFE   card's own base address for its control I/O ports
+
+The IRQ and DMA values can be any that considered acceptable for a
+MSS.  Assuming you've got isapnp all happy, then you should be able to
+do something like the following (which matches up with the isapnp
+configuration above):
+
+insmod mpu401
+insmod ad1848
+insmod opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3
+insmod opl3 io=0x388
+
+Remeber that the opl3sa2 module's io argument is for it's own control
+port, which handles the card's master mixer for volume (on all cards),
+and bass and treble (on SA3 and SAx).
+
+If all goes well an you see no error messages, you should be able to
+start using the sound capabilities of your system.  If you get an
+error message while trying to insert the opl3sa2 module, then make
+sure that the values of the various arguments match what you specified
+in your isapnp configuration file, and that there is no conflict with
+another device for an I/O port or interrupt.  Checking the contents of
+/proc/ioports and /proc/interrupts can be useful to see if you're
+butting heads with another device.
+
+If you still cannot get the module to load, look at the contents of
+your system log file, usually /var/log/messages.  If you see the
+message "No Yamaha audio controller found", then you have a different
+chipset than I've encountered so far.  Look for a line in the log file
+that says "opl3sa2.c: chipset version = <some number>".  If you want
+me to add support for your card, send me the number from this line and
+any information you have on the make and chipset of your sound card,
+and I may be able to work up something.  If you do not see these
+messages, and any of the other messages present in the log are not
+helpful, email me some details and I'll try my best to help.
+
+To set up automatic module loading with kmod, the kernel module loader,
+I currently use the following section in my conf.modules file:
+
+# Sound
+alias char-major-14 opl3sa2
+pre-install opl3sa2 modprobe "-k" "ad1848"
+post-install opl3sa2 modprobe "-k" "opl3"
+options opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3
+options opl3 io=0x388
+
+That's all it currently takes to get an OPL3-SAx card working on my
+system.  Once again, if you have any other problems, email me at the
+address listed above.
+
+Scott
index e3389755e8b512a27cdbabe861c9f3473999a800..39eda5fa88b799b20fdfb82d363cfc415a5d6ebe 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,15 +4,6 @@ SUBLEVEL = 132
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
-#
-# For SMP kernels, set this. We don't want to have this in the config file
-# because it makes re-config very ugly and too many fundamental files depend
-# on "CONFIG_SMP"
-#
-# For UP operations COMMENT THIS OUT, simply setting SMP = 0 won't work
-#
-SMP = 1
-
 .EXPORT_ALL_VARIABLES:
 
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
@@ -94,7 +85,7 @@ SVGA_MODE=    -DSVGA_MODE=NORMAL_VGA
 
 CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
 
-ifdef SMP
+ifdef CONFIG_SMP
 CFLAGS += -D__SMP__
 AFLAGS += -D__SMP__
 endif
@@ -270,7 +261,7 @@ newversion:
 
 include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
        @echo -n \#define UTS_VERSION \"\#`cat .version` > .ver
-       @if [ -n "$(SMP)" ] ; then echo -n " SMP" >> .ver; fi
+       @if [ -n "$(CONFIG_SMP)" ] ; then echo -n " SMP" >> .ver; fi
        @if [ -f .name ]; then  echo -n \-`cat .name` >> .ver; fi
        @echo ' '`date`'"' >> .ver
        @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> .ver
@@ -421,6 +412,9 @@ depend dep: dep-files $(MODVERFILE)
 checkconfig:
        perl -w scripts/checkconfig.pl `find * -name '*.[hcS]' -print | sort`
 
+checkhelp:
+       perl -w scripts/checkhelp.pl `find * -name [cC]onfig.in -print`
+
 ifdef CONFIGURATION
 ..$(CONFIGURATION):
        @echo
index 8b4759e43f495f78c9ec3c67bda01cd8a577911d..948c33dcd583ed978fad94de881d21a28df91263 100644 (file)
@@ -197,7 +197,7 @@ MODINCL = $(TOPDIR)/include/linux/modules
 # and SMP Intel boxes - AC - from bits by Michael Chastain
 #
 
-ifdef SMP
+ifdef CONFIG_SMP
        genksyms_smp_prefix := -p smp_
 else
        genksyms_smp_prefix := 
index 48e924fd79683db0543938f5b2fce41d7b038cd6..53467b99237d3e71ecec8f14afc6e7b3e1642796 100644 (file)
@@ -167,6 +167,8 @@ then
        define_bool CONFIG_ALPHA_AVANTI y
 fi
 
+bool 'Symmetric multi-processing support' CONFIG_SMP
+
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'PCI quirks' CONFIG_PCI_QUIRKS
   if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
index 68a130f4ee1d65c56241089fd9777400b97af2e5..76f05def7db7b1640c9aadfa486899ffe1bf5263 100644 (file)
@@ -111,7 +111,7 @@ endif
 
 endif # GENERIC
 
-ifdef SMP
+ifdef CONFIG_SMP
 O_OBJS   += smp.o
 endif
 
index 175df318b14f8c0c65c35ad0ca921360426cb03d..1fee6e5e33910105eea3ec6b46952dedc78f9433 100644 (file)
@@ -52,6 +52,7 @@ EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(screen_info);
+EXPORT_SYMBOL(perf_irq);
 
 /* platform dependent support */
 EXPORT_SYMBOL(_inb);
index 8f6afc14b93045de27ccd476ffabf989e8d8b3f4..4323b569596b0c50d92f5231ffb1678335788a15 100644 (file)
@@ -84,6 +84,15 @@ generic_ack_irq(unsigned long irq)
        }
 }
 
+
+
+static void dummy_perf(unsigned long vector, struct pt_regs *regs)
+{
+        printk(KERN_CRIT "Performance counter interrupt!\n");
+}
+
+void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf;
+
 /*
  * Dispatch device interrupts.
  */
@@ -879,8 +888,8 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
                __restore_flags(flags);
                return;
        case 4:
-               printk("Performance counter interrupt\n");
-               break;
+               perf_irq(vector, &regs);
+               return;
        default:
                printk("Hardware intr %ld %lx? Huh?\n", type, vector);
        }
index b5aaf5d81516411d696bd9b09782a8bfc65c602d..bf7460e52d0b4eec55b1c826f11cce88cbef80ce 100644 (file)
@@ -232,7 +232,7 @@ noname_pci_fixup(void)
         * selected... :-(
         */
        layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE);
-       sio_pci_fixup(noname_map_irq, 0x0b0a0f09);
+       sio_pci_fixup(noname_map_irq, 0x0b0a0f0e);
        sio_fixup_irq_levels(sio_collect_irq_levels());
         enable_ide(0x26e);
 }
index ca8c263e1476e2a34fb309b41250b9d552b8d68a..9a7bd3f5bd1713a0eefa48b2df799066d0abd2ce 100644 (file)
@@ -20,6 +20,7 @@ bool 'Math emulation' CONFIG_MATH_EMULATION
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 fi
+bool 'Symmetric multi-processing support' CONFIG_SMP
 endmenu
 
 mainmenu_option next_comment
index 78351e2d5a2ff7731e3c860e90f87dd0aa8db233..3f6ebecd15506f9e1b46e2b1d38b4e38ffd37091 100644 (file)
@@ -15,6 +15,7 @@
 CONFIG_M586=y
 # CONFIG_M686 is not set
 # CONFIG_MATH_EMULATION is not set
+CONFIG_SMP=y
 
 #
 # Loadable module support
@@ -139,6 +140,7 @@ CONFIG_SCSI_CONSTANTS=y
 # SCSI low-level drivers
 #
 # CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
@@ -146,14 +148,16 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
 # CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 CONFIG_SCSI_NCR53C8XX=y
@@ -168,6 +172,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
index b8a94af18db4ecb27562e9a2d6a858b6125636a2..3b2d0e94ea8652c4797fb97a511fa59d08106fc6 100644 (file)
@@ -38,7 +38,7 @@ ifdef CONFIG_APM
 OX_OBJS += apm.o
 endif
 
-ifdef SMP
+ifdef CONFIG_SMP
 O_OBJS += io_apic.o smp.o trampoline.o
 endif
 
index fa8ef26bbdafe5a3c261a59a2bdaefe544877f9d..e24633850110dc18673756047397ad86e3bf117a 100644 (file)
@@ -225,6 +225,13 @@ static void __init clear_IO_APIC_pin(unsigned int pin)
 int pirq_entries [MAX_PIRQS];
 int pirqs_enabled;
 
+void __init ioapic_setup(char *str, int *ints)
+{
+       extern int skip_ioapic_setup;   /* defined in arch/i386/kernel/smp.c */
+
+       skip_ioapic_setup = 1;
+}
+
 void __init ioapic_pirq_setup(char *str, int *ints)
 {
        int i, max;
index d8224f0f61780cf3186bd20da9078555728018bf..b1fbe0ebae2da1f25d61b3eba2af3355f4cbe0c5 100644 (file)
@@ -335,16 +335,17 @@ static void show(char * str)
        int i;
        unsigned long *stack;
        int cpu = smp_processor_id();
+       extern char *get_options(char *str, int *ints);
 
        printk("\n%s, CPU %d:\n", str, cpu);
        printk("irq:  %d [%d %d]\n",
                atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]);
        printk("bh:   %d [%d %d]\n",
                atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]);
-       stack = (unsigned long *) &str;
+       stack = (unsigned long *) &stack;
        for (i = 40; i ; i--) {
                unsigned long x = *++stack;
-               if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) {
+               if (x > (unsigned long) &get_options && x < (unsigned long) &vsprintf) {
                        printk("<[%08lx]> ", x);
                }
        }
@@ -706,9 +707,17 @@ void enable_irq(unsigned int irq)
        unsigned long flags;
 
        spin_lock_irqsave(&irq_controller_lock, flags);
-       if (!--irq_desc[irq].depth) {
+       switch (irq_desc[irq].depth) {
+       case 1:
                irq_desc[irq].status &= ~IRQ_DISABLED;
                irq_desc[irq].handler->enable(irq);
+               /* fall throught */
+       default:
+               irq_desc[irq].depth--;
+               break;
+       case 0:
+               printk("enable_irq() unbalanced from %p\n",
+                      __builtin_return_address(0));
        }
        spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
index 658bda7f26644d1dbd1c53a342e111b048c09710..aa6bfdcd112be6ec7cd877dfc915f3faf8c88964 100644 (file)
@@ -38,7 +38,6 @@ typedef struct {
        struct hw_interrupt_type *handler;      /* handle/enable/disable functions */
        struct irqaction *action;               /* IRQ action list */
        unsigned int depth;                     /* Disable depth for nested irq disables */
-       unsigned int unused[2];
 } irq_desc_t;
 
 #define IRQ0_TRAP_VECTOR 0x51
index a5f1f2de03eeeabc6d14b45a19a4d5c205c47f29..60979b172a594987b4c8d2001edfe0b52a48cfb6 100644 (file)
  */
 
 #include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
 #include <asm/i82489.h>
-#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <asm/pgtable.h>
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
-#include <asm/smp.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_MTRR
@@ -159,6 +153,7 @@ extern int mpc_default_type;
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, };
 int mp_current_pci_id = 0;
 unsigned long mp_lapic_addr = 0;
+int skip_ioapic_setup = 0;                             /* 1 if "noapic" boot option passed */
 
 /* #define SMP_DEBUG */
 
@@ -405,7 +400,11 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
                }
        }
        if (ioapics > 1)
+       {
                printk("Warning: Multiple IO-APICs not yet supported.\n");
+               printk("Warning: switching to non APIC mode.\n");
+               skip_ioapic_setup=1;
+       }
        return num_processors;
 }
 
@@ -1170,7 +1169,8 @@ void __init smp_boot_cpus(void)
         * Here we can be sure that there is an IO-APIC in the system. Let's
         * go and set it up:
         */
-       setup_IO_APIC();
+       if (!skip_ioapic_setup) 
+               setup_IO_APIC();
 
 smp_done:
 }
index dbd6e1942a91b702cb4a83d91d7c1748d2e37ed4..1cafe87c6a19ead6e56734e382b45560d906a825 100644 (file)
  *     (C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D.
  *     Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>;
  *     ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>).
+ * 1998-12-16    Andrea Arcangeli
+ *     Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy
+ *     because was not accounting lost_ticks. I also removed some ugly
+ *     not needed global cli() and where needed I used a disable_irq(0).
  */
 
 /* What about the "updated NTP code" stuff in 2.0 time.c? It's not in
@@ -92,9 +96,9 @@ static unsigned long do_fast_gettimeoffset(void)
        eax -= last_tsc_low;    /* tsc_low delta */
 
        /*
-         * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient.
-         *             = (tsc_low delta) / (clocks_per_usec)
-         *             = (tsc_low delta) / (clocks_per_jiffy / usecs_per_jiffy)
+         * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
+         *             = (tsc_low delta) * (usecs_per_clock)
+         *             = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
         *
         * Using a mull instead of a divl saves up to 31 clock cycles
         * in the critical path.
@@ -230,17 +234,19 @@ static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
  */
 void do_gettimeofday(struct timeval *tv)
 {
+       extern volatile unsigned long lost_ticks;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_flags(flags); cli();
        *tv = xtime;
        tv->tv_usec += do_gettimeoffset();
-       if (tv->tv_usec >= 1000000) {
+       if (lost_ticks)
+               tv->tv_usec += lost_ticks * (1000000/HZ);
+       restore_flags(flags);
+       while (tv->tv_usec >= 1000000) {
                tv->tv_usec -= 1000000;
                tv->tv_sec++;
        }
-       restore_flags(flags);
 }
 
 void do_settimeofday(struct timeval *tv)
@@ -254,7 +260,7 @@ void do_settimeofday(struct timeval *tv)
         */
        tv->tv_usec -= do_gettimeoffset();
 
-       if (tv->tv_usec < 0) {
+       while (tv->tv_usec < 0) {
                tv->tv_usec += 1000000;
                tv->tv_sec--;
        }
@@ -399,18 +405,20 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  */
 static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-       int count, flags;
+       int count;
 
        /* It is important that these two operations happen almost at the
         * same time. We do the RDTSC stuff first, since it's faster. To
-         * avoid any inconsistencies, we disable interrupts locally.
+         * avoid any inconsistencies, we need interrupts disabled locally.
          */
+
+       /*
+        * Interrupts are just disabled locally since the timer irq has the
+        * SA_INTERRUPT flag set. -arca
+        */
        
-       __save_flags(flags);
-       __cli(); 
        /* read Pentium cycle counter */
-       __asm__("rdtsc"
-               :"=a" (last_tsc_low):: "eax", "edx");
+       __asm__("rdtsc" : "=a" (last_tsc_low) : : "edx");
 
        outb_p(0x00, 0x43);     /* latch the count ASAP */
 
@@ -419,8 +427,7 @@ static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        count = ((LATCH-1) - count) * TICK_SIZE;
        delay_at_last_interrupt = (count + LATCH/2) / LATCH;
-       __restore_flags(flags);
-       
        timer_interrupt(irq, NULL, regs);
 }
 
index 555f3f5f3b215b263b3133cb7b12fccabde6bf27..e1dfdb603fa973ebfdba6719c983f71f931d9645 100644 (file)
@@ -17,6 +17,7 @@
  * misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c)
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/kd.h>
index 59223a45c46298f1d11011e9924440e712418ab1..0378a8e4b97c08abfeed7ebd98c295b58f605711 100644 (file)
@@ -22,6 +22,9 @@ choice 'Machine Type' \
 if [ "$CONFIG_ALL_PPC" != "y" ];then
   define_bool CONFIG_MACH_SPECIFIC y
 fi
+
+bool 'Symmetric multi-processing support' CONFIG_SMP
+
 endmenu
 
 if [ "$CONFIG_MBX" = "y" ];then
index ae1303bb481341402a58e810ef41997c3a629da6..b0c9ad966f43a59294165cb2ef9ffb7e4b744a48 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_PMAC=y
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 
 #
index 4846d5ebb8d03c3f18d12aa798241d2c006ff7ed..be0d214776b9c7bb725ca54fed700d52b50ddf39 100644 (file)
@@ -41,7 +41,7 @@ OX_OBJS += chrp_setup.o prep_setup.o
 endif
 endif
 
-ifdef SMP
+ifdef CONFIG_SMP
 O_OBJS += smp.o
 endif
 
index 4cc49de17f37bab348d3b7cf87a80b6760641e69..8ca9a3cd54666da6937af628910d2a05671e08df 100644 (file)
@@ -8,7 +8,7 @@
 O_TARGET = lib.o
 O_OBJS  = checksum.o string.o strcase.o
 
-ifdef SMP
+ifdef CONFIG_SMP
 O_OBJS += locks.o
 endif
 
index e0b94ce6ac538f082e9d0dc3aa7acf140e79c28b..5a2e7960bc222f9606c55888747c06cd18e30720 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_8xx=y
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 CONFIG_MBX=y
+# CONFIG_SMP is not set
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_MACH_SPECIFIC=y
 
index ae1303bb481341402a58e810ef41997c3a629da6..b0c9ad966f43a59294165cb2ef9ffb7e4b744a48 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_PMAC=y
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 
 #
index 41db35a4a4a9bf7f265a32b904115790ef69cc5e..14b4ea4a0ffc77141250974d4f638eff0d783789 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_PREP=y
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 
 #
index 97c9704815bd21683c1d71934bfb03de6334333d..6b7060c901ed88c0e2c78c4da4994b7e9910364b 100644 (file)
@@ -25,6 +25,7 @@ define_bool CONFIG_VT y
 define_bool CONFIG_VT_CONSOLE y
 
 bool 'Support for AP1000 multicomputer' CONFIG_AP1000
+bool 'Symmetric multi-processing support' CONFIG_SMP
 
 if [ "$CONFIG_AP1000" = "y" ]; then
        define_bool CONFIG_NO_KEYBOARD y
index 7ea12a1282fd7424650efc2210925368e5293d58..8e6d9e2f5ce1e5a86925fb20c706c4c6f698aaee 100644 (file)
@@ -20,6 +20,7 @@ CONFIG_KMOD=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 # CONFIG_AP1000 is not set
+# CONFIG_SMP is not set
 # CONFIG_SUN4 is not set
 # CONFIG_PCI is not set
 
index 18e487d866abd53b73e7825680cda5fee47bef82..d5f65dda306500b9deec2272618faec676f660e9 100644 (file)
@@ -30,7 +30,7 @@ ifdef CONFIG_SUN4
 O_OBJS += sun4setup.o
 endif
 
-ifdef SMP
+ifdef CONFIG_SMP
 O_OBJS += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
 endif
 
@@ -50,11 +50,17 @@ check_asm: dummy
        @echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
        @echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
        @echo "" >> asm_offsets.h
-       @echo "#ifndef __SMP__" >> asm_offsets.h
+       @echo "#include <linux/config.h>" >> asm_offsets.h
        @echo "" >> asm_offsets.h
-       @echo "#include <linux/sched.h>" > tmp.c
+       @echo "#ifndef CONFIG_SMP" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
+       @echo "#include <linux/config.h>" > tmp.c
+       @echo "#undef CONFIG_SMP" >> tmp.c
+       @echo "#include <linux/sched.h>" >> tmp.c
        $(CC) -E tmp.c -o tmp.i
        @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/config.h>" >> check_asm.c
+       @echo "#undef CONFIG_SMP" >> check_asm.c
        @echo "#include <linux/sched.h>" >> check_asm.c
        @echo 'struct task_struct _task;' >> check_asm.c
        @echo 'struct mm_struct _mm;' >> check_asm.c
@@ -69,11 +75,17 @@ check_asm: dummy
        ./check_asm >> asm_offsets.h
        @rm -f check_asm check_asm.c
        @echo "" >> asm_offsets.h
-       @echo "#else /* __SMP__ */" >> asm_offsets.h
+       @echo "#else /* CONFIG_SMP */" >> asm_offsets.h
        @echo "" >> asm_offsets.h
-       @echo "#include <linux/sched.h>" > tmp.c
+       @echo "#include <linux/config.h>" > tmp.c
+       @echo "#undef CONFIG_SMP" >> tmp.c
+       @echo "#define CONFIG_SMP 1" >> tmp.c
+       @echo "#include <linux/sched.h>" >> tmp.c
        $(CC) -D__SMP__ -E tmp.c -o tmp.i
        @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/config.h>" >> check_asm.c
+       @echo "#undef CONFIG_SMP" >> check_asm.c
+       @echo "#define CONFIG_SMP 1" >> check_asm.c
        @echo "#include <linux/sched.h>" >> check_asm.c
        @echo 'struct task_struct _task;' >> check_asm.c
        @echo 'struct mm_struct _mm;' >> check_asm.c
@@ -88,7 +100,7 @@ check_asm: dummy
        ./check_asm >> asm_offsets.h
        @rm -f check_asm check_asm.c
        @echo "" >> asm_offsets.h
-       @echo "#endif /* __SMP__ */" >> asm_offsets.h
+       @echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
        @echo "" >> asm_offsets.h
        @echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
        @if test -r $(HPATH)/asm/asm_offsets.h; then \
index 9ce3a66300efb0ef901d974567bf91e7c6b83cb0..0670ff2738e65ac72b7bbd4e0c1383c64f59e908 100644 (file)
@@ -7,7 +7,7 @@ OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
        strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
        copy_user.o locks.o atomic.o bitops.o debuglocks.o
 
-ifdef SMP
+ifdef CONFIG_SMP
 OBJS += irqlock.o
 endif
 
@@ -54,7 +54,7 @@ atomic.o: atomic.S
 bitops.o: bitops.S
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o bitops.o bitops.S
 
-ifdef SMP
+ifdef CONFIG_SMP
 irqlock.o: irqlock.S
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o irqlock.o irqlock.S
 endif
index a9e51c67f7512a8298492d9f54fa166ee1ca0e14..ecb1943c36c4a24ac7733d34f7ce9d819b82bf9b 100644 (file)
@@ -14,7 +14,7 @@ O_OBJS         += nosrmmu.o
 else
 O_OBJS  += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o
 endif
-ifdef SMP
+ifdef CONFIG_SMP
 O_OBJS   += nosun4c.o
 else
 O_OBJS   += sun4c.o
index 01d44a3fbfb3c1abb1fee8dc82cedcdc60f0c61b..9df70fc3687df56675ff9c55aebceae032a08ec7 100644 (file)
@@ -51,7 +51,7 @@ endif
 # Uncomment this to get spinlock/rwlock debugging on SMP.
 # DEBUG_SPINLOCK = 1
 
-ifdef SMP
+ifdef CONFIG_SMP
   ifdef DEBUG_SPINLOCK
     CFLAGS += -DSPIN_LOCK_DEBUG
     AFLAGS += -DSPIN_LOCK_DEBUG
index 103767d64dd4197b559f2bc482c79d6f3ed8c5da..82b991cb32d5755f51a60cc1e49d417a82ce4085 100644 (file)
@@ -25,6 +25,7 @@ define_bool CONFIG_VT y
 define_bool CONFIG_VT_CONSOLE y
 
 bool 'Support for AP1000 multicomputer' CONFIG_AP1000
+bool 'Symmetric multi-processing support' CONFIG_SMP
 
 mainmenu_option next_comment
 comment 'Console drivers'
index 3b743920f18d0892b8b20c258b72af81d2c2c4d1..59b3b4618fd031afcdd1e804eecf8481f2345817 100644 (file)
@@ -20,6 +20,7 @@ CONFIG_KMOD=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 # CONFIG_AP1000 is not set
+# CONFIG_SMP is not set
 
 #
 # Console drivers
index 4d1b1eb35ed8523a661a93ab6596d616ea3f1171..fbeb83126b65fbdede41e5bf3848e61baf649327 100644 (file)
@@ -27,7 +27,7 @@ ifdef CONFIG_PCI
   O_OBJS += ebus.o
 endif
 
-ifdef SMP
+ifdef CONFIG_SMP
 O_OBJS += smp.o trampoline.o
 endif
 
@@ -63,11 +63,17 @@ check_asm: dummy
        @echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
        @echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
        @echo "" >> asm_offsets.h
-       @echo "#ifndef __SMP__" >> asm_offsets.h
+       @echo "#include <linux/config.h>" >> asm_offsets.h
        @echo "" >> asm_offsets.h
-       @echo "#include <linux/sched.h>" > tmp.c
+       @echo "#ifndef CONFIG_SMP" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
+       @echo "#include <linux/config.h>" > tmp.c
+       @echo "#undef CONFIG_SMP" >> tmp.c
+       @echo "#include <linux/sched.h>" >> tmp.c
        $(CC) -E tmp.c -o tmp.i
        @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/config.h>" >> check_asm.c
+       @echo "#undef CONFIG_SMP" >> check_asm.c
        @echo "#include <linux/sched.h>" >> check_asm.c
        @echo 'struct task_struct _task;' >> check_asm.c
        @echo 'struct mm_struct _mm;' >> check_asm.c
@@ -87,13 +93,19 @@ check_asm: dummy
        ./check_asm >> asm_offsets.h
        @rm -f check_asm check_asm.c
        @echo "" >> asm_offsets.h
-       @echo "#else /* __SMP__ */" >> asm_offsets.h
+       @echo "#else /* CONFIG_SMP */" >> asm_offsets.h
        @echo "" >> asm_offsets.h
        @echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h
        @echo "" >> asm_offsets.h
-       @echo "#include <linux/sched.h>" > tmp.c
+       @echo "#include <linux/config.h>" > tmp.c
+       @echo "#undef CONFIG_SMP" >> tmp.c
+       @echo "#define CONFIG_SMP 1" >> tmp.c
+       @echo "#include <linux/sched.h>" >> tmp.c
        $(CC) -D__SMP__ -E tmp.c -o tmp.i
        @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/config.h>" >> check_asm.c
+       @echo "#undef CONFIG_SMP" >> check_asm.c
+       @echo "#define CONFIG_SMP 1" >> check_asm.c
        @echo "#include <linux/sched.h>" >> check_asm.c
        @echo 'struct task_struct _task;' >> check_asm.c
        @echo 'struct mm_struct _mm;' >> check_asm.c
@@ -118,6 +130,9 @@ check_asm: dummy
        @echo "#include <linux/sched.h>" > tmp.c
        $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
        @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/config.h>" >> check_asm.c
+       @echo "#undef CONFIG_SMP" >> check_asm.c
+       @echo "#define CONFIG_SMP 1" >> check_asm.c
        @echo "#include <linux/sched.h>" >> check_asm.c
        @echo 'struct task_struct _task;' >> check_asm.c
        @echo 'struct mm_struct _mm;' >> check_asm.c
@@ -138,7 +153,7 @@ check_asm: dummy
        @rm -f check_asm check_asm.c
        @echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
        @echo "" >> asm_offsets.h
-       @echo "#endif /* __SMP__ */" >> asm_offsets.h
+       @echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
        @echo "" >> asm_offsets.h
        @echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
        @if test -r $(HPATH)/asm/asm_offsets.h; then \
index 193208d0d8649b23c309eb4cc35ebebf27e0cc86..f863a8326fcdccaaff209b6d74b7664fe6625dd2 100644 (file)
@@ -14,6 +14,8 @@
 **          37     0       Use Zorro II and Chip ram
 **          37     1       Use only Zorro II ram
 **          37     2       Use only Chip ram
+**          37     4-7     Use memory list entry 1-4 (first is 0)
+** ++jskov: support for 1-4th memory list entry.
 **
 ** Permission to use, copy, modify, and distribute this software and its
 ** documentation for any purpose and without fee is hereby granted, provided
@@ -25,6 +27,7 @@
 
 #define MAJOR_NR    Z2RAM_MAJOR
 
+#include <linux/config.h>
 #include <linux/major.h>
 #include <linux/malloc.h>
 #include <linux/blk.h>
 #include <asm/setup.h>
 #include <asm/bitops.h>
 #include <asm/amigahw.h>
+#ifdef CONFIG_APUS
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#endif
 #include <linux/zorro.h>
 
+
+extern int num_memory;
+extern struct mem_info memory[NUM_MEMINFO];
+
 #define TRUE                  (1)
 #define FALSE                 (0)
 
 #define Z2MINOR_COMBINED      (0)
 #define Z2MINOR_Z2ONLY        (1)
 #define Z2MINOR_CHIPONLY      (2)
+#define Z2MINOR_MEMLIST1      (4)
+#define Z2MINOR_MEMLIST2      (5)
+#define Z2MINOR_MEMLIST3      (6)
+#define Z2MINOR_MEMLIST4      (7)
+#define Z2MINOR_COUNT         (8) /* Move this down when adding a new minor */
 
 #define Z2RAM_CHUNK1024       ( Z2RAM_CHUNKSIZE >> 10 )
 
 static u_long *z2ram_map    = NULL;
 static u_long z2ram_size    = 0;
-static int z2_blocksizes[3] = { 1024, 1024, 1024 };
-static int z2_sizes[3]      = {    0,    0,    0 };
+static int z2_blocksizes[Z2MINOR_COUNT];
+static int z2_sizes[Z2MINOR_COUNT];
 static int z2_count         = 0;
 static int chip_count       = 0;
+static int list_count       = 0;
 static int current_device   = -1;
 
 static void
@@ -166,8 +183,61 @@ z2_open( struct inode *inode, struct file *filp )
     {
        z2_count   = 0;
        chip_count = 0;
+       list_count = 0;
        z2ram_size = 0;
 
+       /* Use a specific list entry. */
+       if (device >= Z2MINOR_MEMLIST1 && device <= Z2MINOR_MEMLIST4) {
+               int index = device - Z2MINOR_MEMLIST1 + 1;
+               unsigned long size, paddr, vaddr;
+
+               if (index >= num_memory) {
+                       printk( KERN_ERR DEVICE_NAME
+                               ": no such entry in z2ram_map\n" );
+                       return -ENOMEM;
+               }
+
+               paddr = memory[index].addr;
+               size = memory[index].size & ~(Z2RAM_CHUNKSIZE-1);
+
+#ifdef __powerpc__
+               /* FIXME: ioremap doesn't build correct memory tables. */
+               {
+                       extern void* vmalloc (unsigned long);
+                       extern void vfree (void*);
+                       vfree(vmalloc (size));
+               }
+
+               vaddr = (unsigned long) __ioremap (paddr, size, 
+                                                  _PAGE_WRITETHRU);
+
+#else
+               vaddr = kernel_map (paddr, size, KERNELMAP_FULL_CACHING,
+                                   NULL);
+#endif
+               z2ram_map = 
+                       kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]),
+                               GFP_KERNEL);
+               if ( z2ram_map == NULL )
+               {
+                   printk( KERN_ERR DEVICE_NAME
+                       ": cannot get mem for z2ram_map\n" );
+                   return -ENOMEM;
+               }
+
+               while (size) {
+                       z2ram_map[ z2ram_size++ ] = vaddr;
+                       size -= Z2RAM_CHUNKSIZE;
+                       vaddr += Z2RAM_CHUNKSIZE;
+                       list_count++;
+               }
+
+               if ( z2ram_size != 0 )
+                   printk( KERN_INFO DEVICE_NAME
+                       ": using %iK List Entry %d Memory\n",
+                       list_count * Z2RAM_CHUNK1024, index );
+       } else
+
        switch ( device )
        {
            case Z2MINOR_COMBINED:
@@ -253,12 +323,11 @@ z2_open( struct inode *inode, struct file *filp )
     return 0;
 }
 
-static void 
+static int
 z2_release( struct inode *inode, struct file *filp )
 {
-
     if ( current_device == -1 )
-       return;     
+       return 0;     
 
     sync_dev( inode->i_rdev );
 
@@ -266,7 +335,7 @@ z2_release( struct inode *inode, struct file *filp )
     MOD_DEC_USE_COUNT;
 #endif
 
-    return;
+    return 0;
 }
 
 static struct file_operations z2_fops =
@@ -281,7 +350,10 @@ static struct file_operations z2_fops =
        z2_open,                /* open */
        NULL,                   /* flush */
        z2_release,             /* release */
-       block_fsync             /* fsync */
+       block_fsync,            /* fsync */
+       NULL,                   /* fasync */
+       NULL,                   /* check_media_change */
+       NULL,                   /* revalidate */
 };
 
 __initfunc(int
@@ -297,6 +369,16 @@ z2_init( void ))
            MAJOR_NR );
        return -EBUSY;
     }
+
+    {
+           /* Initialize size arrays. */
+           int i;
+
+           for (i = 0; i < Z2MINOR_COUNT; i++) {
+                   z2_blocksizes[ i ] = 1024;
+                   z2_sizes[ i ] = 0;
+           }
+    }    
    
     blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST;
     blksize_size[ MAJOR_NR ] = z2_blocksizes;
index 7bafb457a8605ac7e9573fef6a7bbde7756f6836..d893cdecd8159fd40f20c4db5003e9dac7f0e737 100644 (file)
@@ -32,7 +32,7 @@
  * the following:
  *
  *   retry_count = jiffies+ SONY_JIFFIES_TIMEOUT;
- *   while ((retry_count > jiffies) && (! <some condition to wait for))
+ *   while (time_before(jiffies, retry_count) && (! <some condition to wait for))
  *   {
  *      while (handle_sony_cd_attention())
  *         ;
@@ -488,7 +488,7 @@ static int scd_reset(struct cdrom_device_info * cdi)
   reset_drive();
 
   retry_count = jiffies + SONY_RESET_TIMEOUT;
-  while ((retry_count > jiffies) && (!is_attention()))
+  while (time_before(jiffies, retry_count) && (!is_attention()))
   {
      sony_sleep();
   }
@@ -740,7 +740,7 @@ restart_on_error(void)
    printk("cdu31a: Resetting drive on error\n");
    reset_drive();
    retry_count = jiffies + SONY_RESET_TIMEOUT;
-   while ((retry_count > jiffies) && (!is_attention()))
+   while (time_before(jiffies, retry_count) && (!is_attention()))
    {
       sony_sleep();
    }
@@ -808,7 +808,7 @@ get_result(unsigned char *result_buffer,
       ;
    /* Wait for the result data to be ready */
    retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-   while ((retry_count > jiffies) && (is_busy() || (!(is_result_ready()))))
+   while (time_before(jiffies, retry_count) && (is_busy() || (!(is_result_ready()))))
    {
       sony_sleep();
 
@@ -978,7 +978,7 @@ retry_cd_operation:
    sti();
    
    retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-   while ((retry_count > jiffies) && (is_busy()))
+   while (time_before(jiffies, retry_count) && (is_busy()))
    {
       sony_sleep();
       
@@ -1246,7 +1246,7 @@ start_request(unsigned int sector,
       ;
 
    retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-   while ((retry_count > jiffies) && (is_busy()))
+   while (time_before(jiffies, retry_count) && (is_busy()))
    {
       sony_sleep();
       
@@ -1514,7 +1514,7 @@ read_data_block(char          *buffer,
 
    /* Wait for the drive to tell us we have something */
    retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-   while ((retry_count > jiffies) && !(is_data_ready()))
+   while (time_before(jiffies, retry_count) && !(is_data_ready()))
    {
       while (handle_sony_cd_attention())
          ;
@@ -1553,7 +1553,7 @@ read_data_block(char          *buffer,
 
       /* Wait for the status from the drive. */
       retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-      while ((retry_count > jiffies) && !(is_result_ready()))
+      while (time_before(jiffies, retry_count) && !(is_result_ready()))
       {
          while (handle_sony_cd_attention())
             ;
@@ -2432,8 +2432,7 @@ read_audio_data(char          *buffer,
    /* Wait for the drive to tell us we have something */
    retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
 continue_read_audio_wait:
-   while (   (retry_count > jiffies)
-          && !(is_data_ready())
+   while (time_before(jiffies, retry_count) && !(is_data_ready())
           && !(is_result_ready() || result_read))
    {
       while (handle_sony_cd_attention())
@@ -2495,7 +2494,7 @@ continue_read_audio_wait:
       {
          /* Wait for the drive to tell us we have something */
          retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-         while ((retry_count > jiffies) && !(is_result_ready()))
+         while (time_before(jiffies, retry_count) && !(is_result_ready()))
          {
             while (handle_sony_cd_attention())
                ;
@@ -3286,7 +3285,7 @@ get_drive_configuration(unsigned short base_io,
        */
       reset_drive();
       retry_count = jiffies + SONY_RESET_TIMEOUT;
-      while ((retry_count > jiffies) && (!is_attention()))
+      while (time_before(jiffies, retry_count) && (!is_attention()))
       {
          sony_sleep();
       }
index 121550cc3d66cbb99eb012517ac6b05d14111699..708b728332b5c6abc70312e5ac4ca76b18e097d4 100644 (file)
@@ -1778,7 +1778,7 @@ mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
     if (!buf) buf = &c;
 
     while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
-        if (jiffies > timeout) return -1;
+        if (time_after(jiffies, timeout)) return -1;
         mcdx_delay(stuffp, delay);
     }
 
index 8c7592146e6f1ced8e62b131b06cfaf600283cfb..73750c56c4912fea0a53acc51da8228211b19419 100644 (file)
@@ -1014,20 +1014,20 @@ static int CDi_stat_loop_T(void)
               {
               case 4:
                 sbp_sleep(HZ);
-                if (jiffies > timeout_4) gear++;
+                if (time_after(jiffies, timeout_4)) gear++;
                 msg(DBG_TEA, "CDi_stat_loop_T: long sleep active.\n");
                 break;
               case 3:
                 sbp_sleep(HZ/10);
-                if (jiffies > timeout_3) gear++;
+                if (time_after(jiffies, timeout_3)) gear++;
                 break;
               case 2:
                 sbp_sleep(HZ/100);
-                if (jiffies > timeout_2) gear++;
+                if (time_after(jiffies, timeout_2)) gear++;
                 break;
               case 1:
                 sbp_sleep(0);
-                if (jiffies > timeout_1) gear++;
+                if (time_after(jiffies, timeout_1)) gear++;
               }
           } while (gear < 5);
        return -1;
@@ -1037,7 +1037,7 @@ static int CDi_stat_loop(void)
 {
        int i,j;
        
-       for(timeout = jiffies + 10*HZ, i=maxtim_data; timeout > jiffies; )
+       for(timeout = jiffies + 10*HZ, i=maxtim_data; time_before(jiffies, timeout); )
        {
                for ( ;i!=0;i--)
                {
@@ -1098,11 +1098,11 @@ static int ResponseInfo(void)
                                st=inb(CDi_status);
                                if (!(st&s_not_result_ready)) break;
                        }
-                       if ((j!=0)||(timeout<=jiffies)) break;
+                       if ((j!=0)||time_after_eq(jiffies, timeout)) break;
                        sbp_sleep(1);
                        j = 1;
                }
-               if (timeout<=jiffies) break;
+               if (time_after_eq(jiffies, timeout)) break;
                infobuf[i]=inb(CDi_info);
        }
 #if 000
@@ -1238,7 +1238,7 @@ static int ResponseStatus(void)
                        i=inb(CDi_status);
                        if (!(i&s_not_result_ready)) break;
                }
-               if ((j!=0)||(timeout<jiffies)) break;
+               if ((j!=0)||time_after(jiffies, timeout)) break;
                sbp_sleep(1);
                j = 1;
        }
@@ -4355,7 +4355,7 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd,
                                                if (!(j&s_not_result_ready)) break;
                                                if (fam0L_drive) if (j&s_attention) break;
                                        }
-                                       if (try != 0 || timeout <= jiffies) break;
+                                       if (try != 0 || time_after_eq(jiffies, timeout)) break;
                                        if (data_retrying == 0) data_waits++;
                                        data_retrying = 1;
                                        sbp_sleep(1);
@@ -4419,7 +4419,7 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd,
                        if (fam0L_drive)
                        {
                                i=maxtim_data;
-                               for (timeout=jiffies+9*HZ; timeout > jiffies; timeout--)
+                               for (timeout=jiffies+9*HZ; time_before(jiffies, timeout); timeout--)
                                {
                                        for ( ;i!=0;i--)
                                        {
@@ -4428,7 +4428,7 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd,
                                                if (!(j&s_not_result_ready)) break;
                                                if (j&s_attention) break;
                                        }
-                                       if (i != 0 || timeout <= jiffies) break;
+                                       if (i != 0 || time_after_eq(jiffies, timeout)) break;
                                        sbp_sleep(0);
                                        i = 1;
                                }
@@ -5250,7 +5250,7 @@ static int sbp_data(struct request *req)
        {
                SBPCD_CLI;
                i=maxtim_data;
-               for (timeout=jiffies+HZ; timeout > jiffies; timeout--)
+               for (timeout=jiffies+HZ; time_before(jiffies, timeout); timeout--)
                {
                        for ( ;i!=0;i--)
                        {
@@ -5259,7 +5259,7 @@ static int sbp_data(struct request *req)
                                if (!(j&s_not_result_ready)) break;
                                if (j&s_attention) break;
                        }
-                       if (i != 0 || timeout <= jiffies) break;
+                       if (i != 0 || time_after_eq(jiffies, timeout)) break;
                        sbp_sleep(0);
                        i = 1;
                }
@@ -5701,7 +5701,7 @@ __initfunc(int SBPCD_INIT(void))
                                if (i<0) break;
                                if (!st_caddy_in) break;
                                }
-                       while ((!st_diskok)||(timeout<jiffies));
+                       while ((!st_diskok)||time_after(jiffies, timeout));
                }
                i=SetSpeed();
                if (i>=0) D_S[j].CD_changed=1;
index 6681f2a19b76261395460af13258132fb355692d..631dbffa6e0045511fe6b2f3f80f19b26697f222 100644 (file)
@@ -1488,7 +1488,7 @@ __initfunc(int sjcd_init( void )){
     /*
      * Wait 10ms approx.
      */
-    for( timer = jiffies; jiffies <= timer; );
+    for( timer = jiffies; time_before_eq(jiffies, timer); );
     if ( (i % 100) == 0 ) printk( "." );
     ( void )sjcd_check_status();
   }
@@ -1509,7 +1509,7 @@ __initfunc(int sjcd_init( void )){
     /*
      * Wait 10ms approx.
      */
-    for( timer = jiffies; jiffies <= timer; );
+    for( timer = jiffies; time_before_eq(jiffies, timer); );
     if ( (i % 100) == 0 ) printk( "." );
     ( void )sjcd_check_status();
   }
@@ -1540,7 +1540,7 @@ __initfunc(int sjcd_init( void )){
       /*
        * Wait 10ms approx.
        */
-      for( timer = jiffies; jiffies <= timer; );
+      for( timer = jiffies; time_before_eq(jiffies, timer); );
       if ( (i % 100) == 0 ) printk( "." );
       ( void )sjcd_check_status();
     }
index 159a8336e78318e1152d65945eac7ec73404989f..c20e7a9f0e0525117d886781b3761defe6c53870 100644 (file)
@@ -197,18 +197,6 @@ static SERIALSWITCH SCC_switch = {
        SCC_check_open
 };
 
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char tmp_buf[4096]; /* This is cheating */
-static struct semaphore tmp_buf_sem = MUTEX;
-
 /*
  * This is used to figure out the divisor speeds and the timeouts
  */
@@ -771,7 +759,7 @@ static void SCC_init_port( struct m68k_async_struct *info, int type, int channel
 
        /* If console serial line, then enable interrupts. */
        if (info->private->is_cons) {
-               printk("mac_SCC: console line %lx; enabling interrupt!\n", info);
+               printk("mac_SCC: console line %d; enabling interrupt!\n", info->line);
                write_zsreg(info->private->zs_channel, R1,
                            (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
                write_zsreg(info->private->zs_channel, R9, (NV | MIE));
@@ -784,7 +772,7 @@ static void SCC_init_port( struct m68k_async_struct *info, int type, int channel
         * client attached to us asynchronously.
         */
        if (info->private->kgdb_channel) {
-               printk("mac_SCC: kgdb line %lx; enabling interrupt!\n", info);
+               printk("mac_SCC: kgdb line %d; enabling interrupt!\n", info->line);
                kgdb_chaninit(info, 1, info->private->zs_baud);
        }
        /* Report settings (in m68kserial.c) */
@@ -1141,8 +1129,6 @@ static void SCC_throttle(struct m68k_async_struct *info, int status)
 static void SCC_get_serial_info(struct m68k_async_struct * info,
                           struct serial_struct * retinfo)
 {
-       struct serial_struct tmp;
-  
        retinfo->baud_base = info->baud_base;
        retinfo->custom_divisor = info->custom_divisor;
 }
@@ -1190,8 +1176,7 @@ static unsigned int SCC_get_modem_info(struct m68k_async_struct *info)
 static int SCC_set_modem_info(struct m68k_async_struct *info, 
                              int new_dtr, int new_rts)
 {
-       int error;
-       unsigned int arg, bits;
+       unsigned int bits;
 
        bits = (new_rts ? RTS: 0) + (new_dtr ? DTR: 0);
        info->private->curregs[5] = (info->private->curregs[5] & ~(DTR | RTS)) | bits;
@@ -1231,7 +1216,6 @@ static int SCC_ioctl(struct tty_struct *tty, struct file * file,
                    unsigned long arg)
 {
        int error;
-       int retval;
 
        switch (cmd) {
                case TIOCSERGETLSR: /* Get line status register */
@@ -1315,9 +1299,9 @@ static void probe_sccs(void)
                                ZS_CONTROL+ZS_MOVE*n;
                zs_channels[n].data = (volatile unsigned char *)ZS_DATA+ZS_MOVE*n;
 #else
-               zs_channels[n].control = (volatile unsigned char *)
+               zs_channels[n].control = (volatile unsigned char *) /* 2, 0 */
                        (mac_bi_data.sccbase+ZS_CH_A_FIRST)+ZS_MOVE*n;
-               zs_channels[n].data = (volatile unsigned char *)
+               zs_channels[n].data = (volatile unsigned char *) /* 6, 4 */
                        (mac_bi_data.sccbase+ZS_CH_A_FIRST+ZS_DATA_MOVE)+ZS_MOVE*n;
 #endif
                zs_soft[n].private = &zs_soft_private[n];
@@ -1405,8 +1389,8 @@ static inline void
 rs_cons_check(struct m68k_async_struct *ss, int channel)
 {
        int i, o, io;
-       static consout_registered = 0;
-       static msg_printed = 0;
+       static int consout_registered = 0;
+       static int msg_printed = 0;
 
        i = o = io = 0;
 
@@ -1458,10 +1442,9 @@ volatile int test_done;
 /* rs_init inits the driver */
 int mac_SCC_init(void)
 {
-       int channel, line, nr = 0, i;
+       int channel, line, nr = 0;
        unsigned long flags;
        struct serial_struct req;
-       struct m68k_async_struct *info;
 
        printk("Mac68K Z8530 serial driver version 1.01\n");
 
@@ -1486,7 +1469,7 @@ int mac_SCC_init(void)
        for (channel = 0; channel < zs_channels_found; ++channel) {
                req.line = channel;
                req.type = SER_SCC_MAC;
-               req.port = zs_soft[channel].private->zs_channel->control;
+               req.port = (int) zs_soft[channel].private->zs_channel->control;
 
                if ((line = register_serial( &req )) >= 0) {
                        SCC_init_port( &rs_table[line], req.type, line );
index d207041c93443136f43b01f9890f99ac5b0d2f10..4dfbcd087814fc501725ac387e9bfc8b954e914d 100644 (file)
@@ -1673,7 +1673,7 @@ static int set_serial_info(struct async_struct * info,
                state->flags = ((state->flags & ~ASYNC_USR_MASK) |
                               (new_serial.flags & ASYNC_USR_MASK));
                info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-                              (info->flags & ASYNC_USR_MASK));
+                              (new_serial.flags & ASYNC_USR_MASK));
                state->custom_divisor = new_serial.custom_divisor;
                goto check_and_exit;
        }
index 096fc998fbc2d09535072a437165dabe4cf1c196..074fd01c24320c8d43737a77cb921ad19d8ae15c 100644 (file)
@@ -384,6 +384,10 @@ endif
 
 ifeq ($(CONFIG_LANCE),y)
 L_OBJS += lance.o
+else
+  ifeq ($(CONFIG_LANCE),m)
+  M_OBJS += lance.o
+  endif
 endif
 
 ifeq ($(CONFIG_PCNET32),y)
@@ -975,6 +979,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_RCPCI),y)
+L_OBJS += rcpci.o
+else
+  ifeq ($(CONFIG_RCPCI),m)
+  M_OBJS += rcpci.o
+  endif
+endif
+
 ifeq ($(CONFIG_MACE),y)
 L_OBJS += mace.o
 endif
@@ -1054,3 +1066,6 @@ clean:
 
 wanpipe.o: $(WANPIPE_OBJS)
        ld -r -o $@ $(WANPIPE_OBJS)
+
+rcpci.o: rcpci45.o rcmtl.o
+       $(LD) -r -o rcpci.o rcpci45.o rcmtl.o
index abfe3ffcc9e60dcc4a831d3edebe6ed358b56aac..f254f1aaee789cda1a8774c0d5b48d8488a96bf2 100644 (file)
@@ -111,6 +111,8 @@ extern int rtl8139_probe(struct device *dev);
 extern int hplance_probe(struct device *dev);
 extern int via_rhine_probe(struct device *dev);
 extern int tc515_probe(struct device *dev);
+extern int lance_probe(struct device *dev);
+extern int rcpci_probe(struct device *);
 
 /* Gigabit Ethernet adapters */
 extern int yellowfin_probe(struct device *dev);
@@ -169,6 +171,9 @@ struct devprobe pci_probes[] __initdata = {
 #ifdef CONFIG_DGRS
        {dgrs_probe, 0},
 #endif
+#ifdef CONFIG_RCPCI
+       {rcpci_probe, 0},
+#endif
 #ifdef CONFIG_VORTEX
        {tc59x_probe, 0},
 #endif
@@ -297,6 +302,9 @@ struct devprobe isa_probes[] __initdata = {
 #ifdef CONFIG_NE2000           /* ISA (use ne2k-pci for PCI cards) */
        {ne_probe, 0},
 #endif
+#ifdef CONFIG_LANCE            /* ISA/VLB (use pcnet32 for PCI cards) */
+       {lance_probe, 0},
+#endif
 #ifdef CONFIG_SMC9194
        {smc_init, 0},
 #endif
@@ -709,6 +717,9 @@ trif_probe(struct device *dev)
 #endif
 #ifdef CONFIG_SKTR
        && sktr_probe(dev)
+#endif
+#ifdef CONFIG_SMCTR
+       && smctr_probe(dev)
 #endif
        && 1 ) {
        return 1;       /* -ENODEV or -EAGAIN would be more accurate. */
index d30f3f70f101f552c35deffc086647567387718f..385bfec8f7620eaea2af410f2d2f2aa4cdf10ad5 100644 (file)
@@ -132,7 +132,7 @@ static int rx_coal_tick[8] = {0, };
 static int max_tx_desc[8] = {0, };
 static int max_rx_desc[8] = {0, };
 
-static const char *version = "acenic.c: v0.18 12/16/98  Jes Sorensen (Jes.Sorensen@cern.ch)\n";
+static const char *version = "acenic.c: v0.19 12/17/98  Jes Sorensen (Jes.Sorensen@cern.ch)\n";
 
 static struct device *root_dev = NULL;
 
@@ -418,7 +418,7 @@ __initfunc(static int ace_init(struct device *dev, int board_idx))
 
        {
                long myjif = jiffies + HZ;
-               while (myjif > jiffies);
+               while (time_before(jiffies, myjif));
        }
 #endif
 
@@ -754,7 +754,7 @@ __initfunc(static int ace_init(struct device *dev, int board_idx))
         * Wait for the firmware to spin up - max 3 seconds.
         */
        myjif = jiffies + 3 * HZ;
-       while ((myjif > jiffies) && !ap->fw_running);
+       while (time_before(jiffies, myjif) && !ap->fw_running);
        if (!ap->fw_running){
                printk(KERN_ERR "%s: firmware NOT running!\n", dev->name);
                ace_dump_trace(ap);
@@ -1228,10 +1228,15 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
                        ap->tx_full = 0;
                        dev->tbusy = 0;
                        mark_bh(NET_BH);
+
+                       /*
+                        * TX ring is no longer full, aka the
+                        * transmitter is working fine - kill timer.
+                        */
+                       del_timer(&ap->timer);
                }
 
                ap->tx_ret_csm = txcsm;
-               mod_timer(&ap->timer, jiffies + (5/2*HZ));
        }
 
        rxretprd = ap->rx_ret_prd;
@@ -1290,7 +1295,7 @@ static int ace_open(struct device *dev)
 
 #if 0
        { long myjif = jiffies + HZ;
-       while (jiffies < myjif);
+       while (time_before(jiffies, myjif));
        }
 
        cmd.evt = C_LNK_NEGOTIATION;
@@ -1309,10 +1314,8 @@ static int ace_open(struct device *dev)
         * Setup the timer
         */
        init_timer(&ap->timer);
-       ap->timer.expires = jiffies + (5/2 * HZ);
        ap->timer.data = (unsigned long)dev;
        ap->timer.function = ace_timer;
-       add_timer(&ap->timer);
        return 0;
 }
 
@@ -1389,6 +1392,12 @@ static int ace_start_xmit(struct sk_buff *skb, struct device *dev)
        if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm){
                ap->tx_full = 1;
                set_bit(0, (void*)&dev->tbusy);
+               /*
+                * Queue is full, add timer to detect whether the
+                * transmitter is stuck.
+                */
+               ap->timer.expires = jiffies + (3 * HZ);
+               add_timer(&ap->timer);
        }
 
        spin_unlock_irqrestore(&ap->lock, flags);
index f6552a8da03606157113fbf69ef8d7302b69d3f2..9955c7bc1e3745665ea78bbc1914ebd1d41857b9 100644 (file)
@@ -46,7 +46,6 @@ static int max_interrupt_work = 10;
 #define TX_FIFO_THRESH 256             /* Rounded down to 4 byte units. */
 #define RX_FIFO_THRESH 1               /* 0-3, 0==32, 64,96, or 3==128 bytes  */
 
-#include <linux/config.h>
 #include <linux/version.h>             /* Evil, but neccessary */
 #ifdef MODULE
 #ifdef MODVERSIONS
index 736d6b26bb0802c2e3f2dde33b179dedc5bc67c8..48ef86a9bd5bbbc7906e94a45fd5b2ca67891323 100644 (file)
@@ -1,4 +1,4 @@
-#define RCS_ID "$Id: scc.c,v 1.73 1998/01/29 17:38:51 jreuter Exp jreuter $"
+#define RCS_ID "$Id: scc.c,v 1.75 1998/11/04 15:15:01 jreuter Exp jreuter $"
 
 #define VERSION "3.0"
 #define BANNER  "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n"
    Incomplete history of z8530drv:
    -------------------------------
 
-   940913      - started to write the driver, rescued most of my own
-                 code (and Hans Alblas' memory buffer pool concept) from 
-                 an earlier project "sccdrv" which was initiated by 
-                 Guido ten Dolle. Not much of the old driver survived, 
-                 though. The first version I put my hands on was sccdrv1.3
-                 from August 1993. The memory buffer pool concept
-                 appeared in an unauthorized sccdrv version (1.5) from
-                 August 1994.
+   1994-09-13  started to write the driver, rescued most of my own
+               code (and Hans Alblas' memory buffer pool concept) from 
+               an earlier project "sccdrv" which was initiated by 
+               Guido ten Dolle. Not much of the old driver survived, 
+               though. The first version I put my hands on was sccdrv1.3
+               from August 1993. The memory buffer pool concept
+               appeared in an unauthorized sccdrv version (1.5) from
+               August 1994.
 
-   950131      - changed copyright notice to GPL without limitations.
+   1995-01-31  changed copyright notice to GPL without limitations.
    
      .
      . <SNIP>
      .
                  
-   961005      - New semester, new driver... 
+   1996-10-05  New semester, new driver... 
 
                  * KISS TNC emulator removed (TTY driver)
                  * Source moved to drivers/net/
                  The move to version number 3.0 reflects theses changes.
                  You can use 'kissbridge' if you need a KISS TNC emulator.
 
-   961213      - Fixed for Linux networking changes. (G4KLX)
-   970108      - Fixed the remaining problems.
-   970402      - Hopefully fixed the problems with the new *_timer()
-                 routines, added calibration code.
-   971012      - Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO
-   980129      - Small fix to avoid lock-up on initialization
+   1996-12-13  Fixed for Linux networking changes. (G4KLX)
+   1997-01-08  Fixed the remaining problems.
+   1997-04-02  Hopefully fixed the problems with the new *_timer()
+               routines, added calibration code.
+   1997-10-12  Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO
+   1998-01-29  Small fix to avoid lock-up on initialization
+   1998-09-29  Fixed the "grouping" bugs, tx_inhibit works again,
+               using dev->tx_queue_len now instead of MAXQUEUE now.
+   1998-10-21  Postponed the spinlock changes, would need a lot of
+               testing I currently don't have the time to. Softdcd doesn't
+               work.
+   1998-11-04  Softdcd does not work correctly in DPLL mode, in fact it 
+               never did. The DPLL locks on noise, the SYNC unit sees
+               flags that aren't... Restarting the DPLL does not help
+               either, it resynchronizes too slow and the first received
+               frame gets lost.
 
    Thanks to all who contributed to this driver with ideas and bug
    reports!
    Joerg Reuter        ampr-net: dl1bke@db0pra.ampr.org
                AX-25   : DL1BKE @ DB0ACH.#NRW.DEU.EU
                Internet: jreuter@poboxes.com
-               www     : http://www.rat.de/jr
+               www     : http://poboxes.com/jreuter/
 */
 
 /* ----------------------------------------------------------------------- */
 
 #undef  SCC_LDELAY     1       /* slow it even a bit more down */
-#undef  DONT_CHECK             /* don't look if the SCCs you specified are available */
+#undef  SCC_DONT_CHECK         /* don't look if the SCCs you specified are available */
 
-#define MAXSCC          4       /* number of max. supported chips */
-#define BUFSIZE         384     /* must not exceed 4096 */
-#define MAXQUEUE       8       /* number of buffers we queue ourself */
-#undef  DISABLE_ALL_INTS       /* use cli()/sti() in ISR instead of */
+#define SCC_MAXCHIPS   4       /* number of max. supported chips */
+#define SCC_BUFSIZE    384     /* must not exceed 4096 */
+#undef  SCC_DISABLE_ALL_INTS   /* use cli()/sti() in ISR instead of */
                                /* enable_irq()/disable_irq()        */
 #undef SCC_DEBUG
 
-#define DEFAULT_CLOCK  4915200 /* default pclock if nothing is specified */
+#define SCC_DEFAULT_CLOCK      4915200 
+                               /* default pclock if nothing is specified */
 
 /* ----------------------------------------------------------------------- */
 
@@ -214,13 +224,13 @@ static unsigned char *SCC_DriverName = "scc";
 
 static struct irqflags { unsigned char used : 1; } Ivec[16];
        
-static struct scc_channel SCC_Info[2 * MAXSCC];        /* information per channel */
+static struct scc_channel SCC_Info[2 * SCC_MAXCHIPS];  /* information per channel */
 
 static struct scc_ctrl {
        io_port chan_A;
        io_port chan_B;
        int irq;
-} SCC_ctrl[MAXSCC+1];
+} SCC_ctrl[SCC_MAXCHIPS+1];
 
 static unsigned char Driver_Initialized = 0;
 static int Nchips = 0;
@@ -236,7 +246,7 @@ MODULE_SUPPORTED_DEVICE("scc");
 
 /* These provide interrupt save 2-step access to the Z8530 registers */
 
-extern __inline__ unsigned char InReg(io_port port, unsigned char reg)
+static inline unsigned char InReg(io_port port, unsigned char reg)
 {
        unsigned long flags;
        unsigned char r;
@@ -256,7 +266,7 @@ extern __inline__ unsigned char InReg(io_port port, unsigned char reg)
        return r;
 }
 
-extern __inline__ void OutReg(io_port port, unsigned char reg, unsigned char val)
+static inline void OutReg(io_port port, unsigned char reg, unsigned char val)
 {
        unsigned long flags;
        
@@ -272,31 +282,31 @@ extern __inline__ void OutReg(io_port port, unsigned char reg, unsigned char val
        restore_flags(flags);
 }
 
-extern __inline__ void wr(struct scc_channel *scc, unsigned char reg,
+static inline void wr(struct scc_channel *scc, unsigned char reg,
        unsigned char val)
 {
        OutReg(scc->ctrl, reg, (scc->wreg[reg] = val));
 }
 
-extern __inline__ void or(struct scc_channel *scc, unsigned char reg, unsigned char val)
+static inline void or(struct scc_channel *scc, unsigned char reg, unsigned char val)
 {
        OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val));
 }
 
-extern __inline__ void cl(struct scc_channel *scc, unsigned char reg, unsigned char val)
+static inline void cl(struct scc_channel *scc, unsigned char reg, unsigned char val)
 {
        OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val));
 }
 
-#ifdef DISABLE_ALL_INTS
-extern __inline__ void scc_cli(int irq)
+#ifdef SCC_DISABLE_ALL_INTS
+static inline void scc_cli(int irq)
 { cli(); }
-extern __inline__ void scc_sti(int irq)
+static inline void scc_sti(int irq)
 { sti(); }
 #else
-static __inline__ void scc_cli(int irq)
+static inline void scc_cli(int irq)
 { disable_irq(irq); }
-static __inline__ void scc_sti(int irq)
+static inline void scc_sti(int irq)
 { enable_irq(irq); }
 #endif
 
@@ -305,17 +315,17 @@ static __inline__ void scc_sti(int irq)
 /* ******************************************************************** */
 
 
-extern __inline__ void scc_lock_dev(struct scc_channel *scc)
+static inline void scc_lock_dev(struct scc_channel *scc)
 {
        scc->dev->tbusy = 1;
 }
 
-extern __inline__ void scc_unlock_dev(struct scc_channel *scc)
+static inline void scc_unlock_dev(struct scc_channel *scc)
 {
        scc->dev->tbusy = 0;
 }
 
-extern __inline__ void scc_discard_buffers(struct scc_channel *scc)
+static inline void scc_discard_buffers(struct scc_channel *scc)
 {
        unsigned long flags;
        
@@ -343,7 +353,7 @@ extern __inline__ void scc_discard_buffers(struct scc_channel *scc)
 
 /* ----> subroutines for the interrupt handlers <---- */
 
-extern __inline__ void scc_notify(struct scc_channel *scc, int event)
+static inline void scc_notify(struct scc_channel *scc, int event)
 {
        struct sk_buff *skb;
        char *bp;
@@ -362,7 +372,7 @@ extern __inline__ void scc_notify(struct scc_channel *scc, int event)
                scc->stat.nospace++;
 }
 
-extern __inline__ void flush_rx_FIFO(struct scc_channel *scc)
+static inline void flush_rx_FIFO(struct scc_channel *scc)
 {
        int k;
        
@@ -377,12 +387,18 @@ extern __inline__ void flush_rx_FIFO(struct scc_channel *scc)
        }
 }
 
+static void start_hunt(struct scc_channel *scc)
+{
+       if ((scc->modem.clocksrc != CLK_EXTERNAL))
+               OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
+       or(scc,R3,ENT_HM|RxENABLE);  /* enable the receiver, hunt mode */
+}
 
 /* ----> four different interrupt handlers for Tx, Rx, changing of     */
 /*       DCD/CTS and Rx/Tx errors                                      */
 
 /* Transmitter interrupt handler */
-extern __inline__ void scc_txint(struct scc_channel *scc)
+static inline void scc_txint(struct scc_channel *scc)
 {
        struct sk_buff *skb;
 
@@ -446,7 +462,7 @@ extern __inline__ void scc_txint(struct scc_channel *scc)
 
 
 /* External/Status interrupt handler */
-extern __inline__ void scc_exint(struct scc_channel *scc)
+static inline void scc_exint(struct scc_channel *scc)
 {
        unsigned char status,changes,chg_and_stat;
 
@@ -461,35 +477,39 @@ extern __inline__ void scc_exint(struct scc_channel *scc)
        if (chg_and_stat & BRK_ABRT)            /* Received an ABORT */
                flush_rx_FIFO(scc);
 
+       /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */
+
+       if ((changes & SYNC_HUNT) && scc->kiss.softdcd)
+       {
+               if (status & SYNC_HUNT)
+               {
+                       scc->dcd = 0;
+                       flush_rx_FIFO(scc);
+                       if ((scc->modem.clocksrc != CLK_EXTERNAL))
+                               OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
+               } else {
+                       scc->dcd = 1;
+               }
+
+               scc_notify(scc, scc->dcd? HWEV_DCD_OFF:HWEV_DCD_ON);
+       }
 
        /* DCD: on = start to receive packet, off = ABORT condition */
        /* (a successfully received packet generates a special condition int) */
        
-       if(changes & DCD)                       /* DCD input changed state */
+       if((changes & DCD) && !scc->kiss.softdcd) /* DCD input changed state */
        {
                if(status & DCD)                /* DCD is now ON */
                {
-                       if (scc->modem.clocksrc != CLK_EXTERNAL)
-                               OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
-                               
-                       or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
+                       start_hunt(scc);
+                       scc->dcd = 1;
                } else {                        /* DCD is now OFF */
                        cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */
                        flush_rx_FIFO(scc);
+                       scc->dcd = 0;
                }
                
-               if (!scc->kiss.softdcd)
-                       scc_notify(scc, (status & DCD)? HWEV_DCD_ON:HWEV_DCD_OFF);
-       }
-       
-       /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */
-       
-       if (changes & SYNC_HUNT)
-       {
-               if (scc->kiss.softdcd)
-                       scc_notify(scc, (status & SYNC_HUNT)? HWEV_DCD_OFF:HWEV_DCD_ON);
-               else
-                       cl(scc,R15,SYNCIE);     /* oops, we were too lazy to disable this? */
+               scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
        }
 
 #ifdef notdef
@@ -527,7 +547,7 @@ extern __inline__ void scc_exint(struct scc_channel *scc)
 
 
 /* Receiver interrupt handler */
-extern __inline__ void scc_rxint(struct scc_channel *scc)
+static inline void scc_rxint(struct scc_channel *scc)
 {
        struct sk_buff *skb;
 
@@ -575,7 +595,7 @@ extern __inline__ void scc_rxint(struct scc_channel *scc)
 
 
 /* Receive Special Condition interrupt handler */
-extern __inline__ void scc_spint(struct scc_channel *scc)
+static inline void scc_spint(struct scc_channel *scc)
 {
        unsigned char status;
        struct sk_buff *skb;
@@ -646,8 +666,6 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
        struct scc_ctrl *ctrl;
        int k;
        
-       scc_cli(irq);
-
        if (Vector_Latch)
        {
                for(k=0; k < SCC_IRQTIMEOUT; k++)
@@ -665,7 +683,6 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
 
                        OutReg(scc->ctrl,R0,RES_H_IUS);              /* Reset Highest IUS */
                }  
-               scc_sti(irq);
 
                if (k == SCC_IRQTIMEOUT)
                        printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n");
@@ -718,8 +735,6 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
                } else
                        ctrl++;
        }
-       
-       scc_sti(irq);
 }
 
 
@@ -731,7 +746,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
 
 /* ----> set SCC channel speed <---- */
 
-extern __inline__ void set_brg(struct scc_channel *scc, unsigned int tc)
+static inline void set_brg(struct scc_channel *scc, unsigned int tc)
 {
        cl(scc,R14,BRENABL);            /* disable baudrate generator */
        wr(scc,R12,tc & 255);           /* brg rate LOW */
@@ -739,7 +754,7 @@ extern __inline__ void set_brg(struct scc_channel *scc, unsigned int tc)
        or(scc,R14,BRENABL);            /* enable baudrate generator */
 }
 
-extern __inline__ void set_speed(struct scc_channel *scc)
+static inline void set_speed(struct scc_channel *scc)
 {
        disable_irq(scc->irq);
 
@@ -752,7 +767,7 @@ extern __inline__ void set_speed(struct scc_channel *scc)
 
 /* ----> initialize a SCC channel <---- */
 
-extern __inline__ void init_brg(struct scc_channel *scc)
+static inline void init_brg(struct scc_channel *scc)
 {
        wr(scc, R14, BRSRC);                            /* BRG source = PCLK */
        OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]);    /* DPLL source = BRG */
@@ -875,19 +890,15 @@ static void init_channel(struct scc_channel *scc)
                wr(scc,R7,AUTOEOM);
        }
 
-       if((InReg(scc->ctrl,R0)) & DCD)         /* DCD is now ON */
+       if(scc->kiss.softdcd || (InReg(scc->ctrl,R0) & DCD))
+                                               /* DCD is now ON */
        {
-               if (scc->modem.clocksrc != CLK_EXTERNAL)
-                       or(scc,R14, SEARCH);
-                       
-               or(scc,R3,ENT_HM|RxENABLE);     /* enable the receiver, hunt mode */
+               start_hunt(scc);
        }
        
        /* enable ABORT, DCD & SYNC/HUNT interrupts */
 
-       wr(scc,R15, BRKIE|TxUIE|DCDIE);
-       if (scc->kiss.softdcd)
-               or(scc,R15, SYNCIE);
+       wr(scc,R15, BRKIE|TxUIE|(scc->kiss.softdcd? SYNCIE:DCDIE));
 
        Outb(scc->ctrl,RES_EXT_INT);    /* reset ext/status interrupts */
        Outb(scc->ctrl,RES_EXT_INT);    /* must be done twice */
@@ -940,14 +951,21 @@ static void scc_key_trx(struct scc_channel *scc, char tx)
                {
 #ifdef CONFIG_SCC_TRXECHO
                        cl(scc, R3, RxENABLE|ENT_HM);   /* switch off receiver */
-                       cl(scc, R15, DCDIE);            /* No DCD changes, please */
+                       cl(scc, R15, DCDIE|SYNCIE);     /* No DCD changes, please */
 #endif
                        set_brg(scc, time_const);       /* reprogram baudrate generator */
 
                        /* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */
                        wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR);
                        
-                       or(scc,R5,RTS|TxENAB);          /* set the RTS line and enable TX */
+                       /* By popular demand: tx_inhibit */
+                       if (scc->kiss.tx_inhibit)
+                       {
+                               or(scc,R5, TxENAB);
+                               scc->wreg[R5] |= RTS;
+                       } else {
+                               or(scc,R5,RTS|TxENAB);  /* set the RTS line and enable TX */
+                       }
                } else {
                        cl(scc,R5,RTS|TxENAB);
                        
@@ -955,10 +973,14 @@ static void scc_key_trx(struct scc_channel *scc, char tx)
                        
                        /* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */
                        wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
-#ifdef CONFIG_SCC_TRXECHO
-                       or(scc,R3,RxENABLE|ENT_HM);
-                       or(scc,R15, DCDIE);
+
+#ifndef CONFIG_SCC_TRXECHO
+                       if (scc->kiss.softdcd)
 #endif
+                       {
+                               or(scc,R15, scc->kiss.softdcd? SYNCIE:DCDIE);
+                               start_hunt(scc);
+                       }
                }
        } else {
                if (tx)
@@ -967,22 +989,30 @@ static void scc_key_trx(struct scc_channel *scc, char tx)
                        if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
                        {
                                cl(scc, R3, RxENABLE);
-                               cl(scc, R15, DCDIE);
+                               cl(scc, R15, DCDIE|SYNCIE);
                        }
 #endif
                                
-                               
-                       or(scc,R5,RTS|TxENAB);          /* enable tx */
+                       if (scc->kiss.tx_inhibit)
+                       {
+                               or(scc,R5, TxENAB);
+                               scc->wreg[R5] |= RTS;
+                       } else {        
+                               or(scc,R5,RTS|TxENAB);  /* enable tx */
+                       }
                } else {
                        cl(scc,R5,RTS|TxENAB);          /* disable tx */
 
-#ifdef CONFIG_SCC_TRXECHO
-                       if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
+                       if ((scc->kiss.fulldup == KISS_DUPLEX_HALF) &&
+#ifndef CONFIG_SCC_TRXECHO
+                           scc->kiss.softdcd)
+#else
+                           1)
+#endif
                        {
-                               or(scc, R3, RxENABLE|ENT_HM);
-                               or(scc, R15, DCDIE);
+                               or(scc, R15, scc->kiss.softdcd? SYNCIE:DCDIE);
+                               start_hunt(scc);
                        }
-#endif
                }
        }
 
@@ -1088,7 +1118,7 @@ static void scc_tx_done(struct scc_channel *scc)
 
 static unsigned char Rand = 17;
 
-extern __inline__ int is_grouped(struct scc_channel *scc)
+static inline int is_grouped(struct scc_channel *scc)
 {
        int k;
        struct scc_channel *scc2;
@@ -1109,7 +1139,7 @@ extern __inline__ int is_grouped(struct scc_channel *scc)
                        if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) )
                                return 1;
                        
-                       if ( (grp1 & RXGROUP) && (scc2->status & DCD) )
+                       if ( (grp1 & RXGROUP) && scc2->dcd )
                                return 1;
                }
        }
@@ -1144,7 +1174,7 @@ static void t_dwait(unsigned long channel)
        {
                Rand = Rand * 17 + 31;
                
-               if ( (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD))  || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) )
+               if (scc->dcd || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) )
                {
                        scc_start_defer(scc);
                        scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime);
@@ -1317,8 +1347,6 @@ static void scc_init_timer(struct scc_channel *scc)
 
 static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg)
 {
-       int dcd;
-
        switch (cmd)
        {
                case PARAM_TXDELAY:     scc->kiss.txdelay=arg;          break;
@@ -1338,9 +1366,14 @@ static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, uns
                case PARAM_SOFTDCD:     
                        scc->kiss.softdcd=arg;
                        if (arg)
+                       {
                                or(scc, R15, SYNCIE);
-                       else
+                               cl(scc, R15, DCDIE);
+                               start_hunt(scc);
+                       } else {
+                               or(scc, R15, DCDIE);
                                cl(scc, R15, SYNCIE);
+                       }
                        break;
                                
                case PARAM_SPEED:
@@ -1369,8 +1402,7 @@ static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, uns
                        break;
                        
                case PARAM_HWEVENT:
-                       dcd = (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD));
-                       scc_notify(scc, dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
+                       scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
                        break;
 
                default:                return -EINVAL;
@@ -1449,9 +1481,10 @@ scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern
 
        scc->tx_wdog.data = (unsigned long) scc;
        scc->tx_wdog.function = scc_stop_calibrate;
-       scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup;
+       scc->tx_wdog.expires = jiffies + HZ*duration;
        add_timer(&scc->tx_wdog);
-       
+
+       /* This doesn't seem to work. Why not? */       
        wr(scc, R6, 0);
        wr(scc, R7, pattern);
 
@@ -1680,6 +1713,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb)
        skb->dev      = scc->dev;
        skb->protocol = htons(ETH_P_AX25);
        skb->mac.raw  = skb->data;
+       skb->pkt_type = PACKET_HOST;
        
        netif_rx(skb);
        return;
@@ -1722,7 +1756,7 @@ static int scc_net_tx(struct sk_buff *skb, struct device *dev)
        save_flags(flags);
        cli();
        
-       if (skb_queue_len(&scc->tx_queue) >= MAXQUEUE-1)
+       if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len)
        {
                struct sk_buff *skb_del;
                skb_del = __skb_dequeue(&scc->tx_queue);
@@ -1791,7 +1825,7 @@ static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
                        if (!suser()) return -EPERM;
                        if (!arg) return -EFAULT;
 
-                       if (Nchips >= MAXSCC
+                       if (Nchips >= SCC_MAXCHIPS
                                return -EINVAL;
 
                        if (copy_from_user(&hwcfg, arg, sizeof(hwcfg)))
@@ -1811,14 +1845,15 @@ static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
                                Vector_Latch = hwcfg.vector_latch;
 
                        if (hwcfg.clock == 0)
-                               hwcfg.clock = DEFAULT_CLOCK;
+                               hwcfg.clock = SCC_DEFAULT_CLOCK;
 
-#ifndef DONT_CHECK
+#ifndef SCC_DONT_CHECK
                        disable_irq(hwcfg.irq);
 
                        check_region(scc->ctrl, 1);
                        Outb(hwcfg.ctrl_a, 0);
-                       udelay(5);
+                       OutReg(hwcfg.ctrl_a, R9, FHWRES);
+                       udelay(100);
                        OutReg(hwcfg.ctrl_a,R13,0x55);          /* is this chip really there? */
                        udelay(5);
 
@@ -1853,7 +1888,7 @@ static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
                                SCC_Info[2*Nchips+chan].option = hwcfg.option;
                                SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc;
 
-#ifdef DONT_CHECK
+#ifdef SCC_DONT_CHECK
                                printk(KERN_INFO "%s: data port = 0x%3.3x  control port = 0x%3.3x\n",
                                        device_name, 
                                        SCC_Info[2*Nchips+chan].data, 
@@ -1903,7 +1938,7 @@ static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
                        if (!suser()) return -EPERM;
                        if (!arg) return -EINVAL;
                        
-                       scc->stat.bufsize   = BUFSIZE;
+                       scc->stat.bufsize   = SCC_BUFSIZE;
 
                        if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem)))
                                return -EINVAL;
@@ -1980,7 +2015,7 @@ static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
                
                case SIOCSCCCAL:
                        if (!suser()) return -EPERM;
-                       if (!arg || copy_from_user(&cal, arg, sizeof(cal)))
+                       if (!arg || copy_from_user(&cal, arg, sizeof(cal)) || cal.time == 0)
                                return -EINVAL;
 
                        scc_start_calibrate(scc, cal.time, cal.pattern);
@@ -2169,7 +2204,7 @@ __initfunc(int scc_init (void))
        
        /* pre-init channel information */
        
-       for (chip = 0; chip < MAXSCC; chip++)
+       for (chip = 0; chip < SCC_MAXCHIPS; chip++)
        {
                memset((char *) &SCC_Info[2*chip  ], 0, sizeof(struct scc_channel));
                memset((char *) &SCC_Info[2*chip+1], 0, sizeof(struct scc_channel));
index f781abbf356b727bb703a924f6ad17cc64048d29..cf318f92704b461d816ea6e60c84a4702b39d86a 100644 (file)
@@ -1230,7 +1230,7 @@ static int tok_init_card(struct device *dev)
 {
        struct tok_info *ti;
        short PIOaddr;
-       int i;
+       unsigned long i;
        PIOaddr = dev->base_addr;
        ti=(struct tok_info *) dev->priv;
 
@@ -1252,7 +1252,7 @@ static int tok_init_card(struct device *dev)
 #endif
 
        outb(0, PIOaddr+ADAPTRESET);
-       for (i=jiffies+TR_RESET_INTERVAL; jiffies<=i;); /* wait 50ms */
+       for (i=jiffies+TR_RESET_INTERVAL; time_before_eq(jiffies, i);); /* wait 50ms */
        outb(0,PIOaddr+ADAPTRESETREL);
 
 #if !TR_NEWFORMAT
index c419d92979f769003bf7f092221cb17a1888c72f..39baa89df2de500343997d822b8a9b39b32e3ac2 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/delay.h>
 #include <linux/tty.h>
 #include <linux/sched.h>
-#include <linux/config.h>
 #include <linux/init.h>
 
 #include <asm/ioctls.h>
index a5106658840f7d16cf6f1bdf1aea518a192cb0b0..f95266888c8b5bfdf8338054e13e749c6fada134 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/delay.h>
 #include <linux/tty.h>
 #include <linux/sched.h>
-#include <linux/config.h>
 #include <linux/init.h>
 
 #include <asm/ioctls.h>
index 5a11460be74de6116b03e6fb6b74c40355b76648..f563308e6847897d4c234e9cd6bcc7ee8748dda4 100644 (file)
@@ -52,8 +52,6 @@
 #include <linux/malloc.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/config.h>
-#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
index 818937ee16a0331f7d3bf426f2d700b261fdd31d..de7421deb1afdf2d38a4c9925a8eb7f0b71c2fd5 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/delay.h>
 #include <linux/tty.h>
 #include <linux/sched.h>
-#include <linux/config.h>
 #include <linux/init.h>
 
 #include <asm/ioctls.h>
index 850ba7203149ef50dacaf1f8aea7cc6efbf8493a..5a7995ef7ead306e8d4ad9b085923cc0cfca7713 100644 (file)
@@ -49,8 +49,6 @@
 #include <linux/delay.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
-#include <linux/config.h>
-#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
index 15f7f9ad7c8b188e5fe1ca071c445c16600dcbef..f0f6c1ac80585115f5cb89ea3ecea504a3f473a7 100644 (file)
@@ -1,6 +1,6 @@
-/* lance.c: An AMD LANCE ethernet driver for linux. */
+/* lance.c: An AMD LANCE/PCnet ethernet driver for Linux. */
 /*
-       Written 1993,1994,1995 by Donald Becker.
+       Written/copyright 1993-1998 by Donald Becker.
 
        Copyright 1993 United States Government as represented by the
        Director, National Security Agency.
@@ -8,13 +8,12 @@
        of the GNU Public License, incorporated herein by reference.
 
        This driver is for the Allied Telesis AT1500 and HP J2405A, and should work
-       with most other LANCE-based bus-master (NE2100 clone) ethercards.
+       with most other LANCE-based bus-master (NE2100/NE2500) ethercards.
 
        The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
        Center of Excellence in Space Data and Information Sciences
           Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
-
        Fixing alignment problem with 1.3.* kernel and some minor changes
        by Andrey V. Savochkin, 1996.
 
        But I should to inform you that I'm not an expert in the LANCE card
        and it may occurs that you will receive no answer on your mail
        to Donald Becker. I didn't receive any answer on all my letters
-       to him. Who knows why... But may be you are more lucky?  ;-)
+       to him. Who knows why... But may be you are more lucky?  ;->
                                                           SAW
-    Fixed 7990 autoIRQ failure and reversed unneeded alignment. 8/20/96 djb
+
+       Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
+       - added support for Linux/Alpha, but removed most of it, because
+        it worked only for the PCI chip. 
+      - added hook for the 32bit lance driver
+      - added PCnetPCI II (79C970A) to chip table
+       Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
+       - hopefully fix above so Linux/Alpha can use ISA cards too.
+    8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb
+    v1.12 10/27/97 Module support -djb
+    v1.14  2/3/98 Module support modified, made PCI support optional -djb
+    
+    Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
+    the 2.1 version of the old driver - Alan Cox
 */
 
-static const char *version = "lance.c:v1.09 Aug 20 1996 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+static const char *version = "lance.c:v1.14ac 1998/11/20 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -54,13 +67,9 @@ static const char *version = "lance.c:v1.09 Aug 20 1996 dplatt@3do.com, becker@c
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-static unsigned int lance_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
-void lance_probe1(int ioaddr);
-
-#ifdef HAVE_DEVLIST
-struct netdev_entry lance_drv =
-{"lance", lance_probe1, LANCE_TOTAL_SIZE, lance_portlist};
-#endif
+static unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0};
+int lance_probe(struct device *dev);
+int lance_probe1(struct device *dev, int ioaddr, int irq, int options);
 
 #ifdef LANCE_DEBUG
 int lance_debug = LANCE_DEBUG;
@@ -96,7 +105,7 @@ of the otherwise-unused dev->mem_start value (aka PARAM1).  If unset it is
 probed for by enabling each free DMA channel in turn and checking if
 initialization succeeds.
 
-The HP-J2405A board is an exception: with this board it's easy to read the
+The HP-J2405A board is an exception: with this board it is easy to read the
 EEPROM-set values for the base, IRQ, and DMA.  (Of course you must already
 _know_ the base address -- that field is for writing the EEPROM.)
 
@@ -147,36 +156,19 @@ queue slot is empty, it clears the tbusy flag when finished otherwise it sets
 the 'lp->tx_full' flag.
 
 The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
+from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
 we can't avoid the interrupt overhead by having the Tx routine reap the Tx
 stats.)         After reaping the stats, it marks the queue entry as empty by setting
-the 'base' to zero.     Iff the 'lp->tx_full' flag is set, it clears both the
+the 'base' to zero. Iff the 'lp->tx_full' flag is set, it clears both the
 tx_full and tbusy flags.
 
 */
 
-/* Memory accessed from LANCE card must be aligned on 8-byte boundaries.
-   But we can't believe that kmalloc()'ed memory satisfies it. -- SAW */
-#define LANCE_KMALLOC(x) \
-       ((void *) (((unsigned long)kmalloc((x)+7, GFP_DMA | GFP_KERNEL)+7) & ~7))
-
-/*
- * Changes:
- *     Thomas Bogendoerfer (tsbogend@alpha.franken.de):
- *     - added support for Linux/Alpha, but removed most of it, because
- *        it worked only for the PCI chip. 
- *      - added hook for the 32bit lance driver
- *      - added PCnetPCI II (79C970A) to chip table
- *      - made 32bit driver standalone
- *      - changed setting of autoselect bit
- *
- *     Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
- *     - hopefully fix above so Linux/Alpha can use ISA cards too.
- */
-
 /* Set the number of Tx and Rx buffers, using Log_2(# buffers).
    Reasonable default values are 16 Tx buffers, and 16 Rx buffers.
-   That translates to 4 and 4 (16 == 2^^4). */
+   That translates to 4 and 4 (16 == 2^^4).
+   This is a compile-time option for efficiency.
+   */
 #ifndef LANCE_LOG_TX_BUFFERS
 #define LANCE_LOG_TX_BUFFERS 4
 #define LANCE_LOG_RX_BUFFERS 4
@@ -230,6 +222,8 @@ struct lance_private {
        const char *name;
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
        struct sk_buff* tx_skbuff[TX_RING_SIZE];
+       /* The addresses of receive-in-place skbuffs. */
+       struct sk_buff* rx_skbuff[RX_RING_SIZE];
        unsigned long rx_buffs;         /* Address of Rx and Tx buffers. */
        /* Tx low-memory "bounce buffer" address. */
        char (*tx_bounce_buffs)[PKT_BUF_SZ];
@@ -247,7 +241,6 @@ struct lance_private {
 #define LANCE_MUST_REINIT_RING  0x00000004
 #define LANCE_MUST_UNRESET      0x00000008
 #define LANCE_HAS_MISSED_FRAME  0x00000010
-#define PCNET32_POSSIBLE        0x00000020
 
 /* A mapping from the chip ID number to the part number and features.
    These are from the datasheets -- in real life the '970 version
@@ -267,21 +260,15 @@ static struct lance_chip_type {
                        LANCE_HAS_MISSED_FRAME},
        {0x2420, "PCnet/PCI 79C970",            /* 79C970 or 79C974 PCnet-SCSI, PCI. */
                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-                       LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
+                       LANCE_HAS_MISSED_FRAME},
        /* Bug: the PCnet/PCI actually uses the PCnet/VLB ID number, so just call
                it the PCnet32. */
        {0x2430, "PCnet32",                                     /* 79C965 PCnet for VL bus. */
                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-                       LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
+                       LANCE_HAS_MISSED_FRAME},
         {0x2621, "PCnet/PCI-II 79C970A",        /* 79C970A PCInetPCI II. */
                 LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-                        LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
-        {0x2623, "PCnet/FAST 79C971",        /* 79C971 PCInetFAST. */
-                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-                        LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
-        {0x2624, "PCnet/FAST+ 79C972",       /* 79C972 PCInetFAST+. */
-                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-                        LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
+                        LANCE_HAS_MISSED_FRAME},
        {0x0,    "PCnet (unknown)",
                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
                        LANCE_HAS_MISSED_FRAME},
@@ -298,7 +285,7 @@ static unsigned char lance_need_isa_bounce_buffers = 1;
 
 static int lance_open(struct device *dev);
 static int lance_open_fail(struct device *dev);
-static void lance_init_ring(struct device *dev);
+static void lance_init_ring(struct device *dev, int mode);
 static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
 static int lance_rx(struct device *dev);
 static void lance_interrupt(int irq, void *dev_id, struct pt_regs *regs);
@@ -308,24 +295,83 @@ static void set_multicast_list(struct device *dev);
 
 \f
 
-/* This lance probe is unlike the other board probes in 1.0.*.  The LANCE may
-   have to allocate a contiguous low-memory region for bounce buffers.
-   This requirement is satisfied by having the lance initialization occur
-   before the memory management system is started, and thus well before the
-   other probes. */
+#ifdef MODULE
+#define MAX_CARDS              8       /* Max number of interfaces (cards) per module */
+#define IF_NAMELEN             8       /* # of chars for storing dev->name */
+
+static int io[MAX_CARDS] = { 0, };
+static int dma[MAX_CARDS] = { 0, };
+static int irq[MAX_CARDS]  = { 0, };
 
-__initfunc(int lance_init(void))
+static char ifnames[MAX_CARDS][IF_NAMELEN] = { {0, }, };
+static struct device dev_lance[MAX_CARDS] =
+{{
+    0, /* device name is inserted by linux/drivers/net/net_init.c */
+       0, 0, 0, 0,
+       0, 0,
+       0, 0, 0, NULL, NULL}};
+
+int init_module(void)
 {
-       int *port;
+       int this_dev, found = 0;
+
+       for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
+               struct device *dev = &dev_lance[this_dev];
+               dev->name = ifnames[this_dev];
+               dev->irq = irq[this_dev];
+               dev->base_addr = io[this_dev];
+               dev->dma = dma[this_dev];
+               dev->init = lance_probe;
+               if (io[this_dev] == 0)  {
+                       if (this_dev != 0) break; /* only complain once */
+                       printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
+                       return -EPERM;
+               }
+               if (register_netdev(dev) != 0) {
+                       printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]);
+                       if (found != 0) return 0;       /* Got at least one. */
+                       return -ENXIO;
+               }
+               found++;
+       }
+
+       return 0;
+}
 
-       if (virt_to_bus(high_memory) <= 16*1024*1024)
+void cleanup_module(void)
+{
+       int this_dev;
+
+       for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
+               struct device *dev = &dev_lance[this_dev];
+               if (dev->priv != NULL) {
+                       kfree(dev->priv);
+                       dev->priv = NULL;
+                       free_dma(dev->dma);
+                       release_region(dev->base_addr, LANCE_TOTAL_SIZE);
+                       unregister_netdev(dev);
+               }
+       }
+}
+#endif /* MODULE */
+
+/* Starting in v2.1.*, the LANCE/PCnet probe is now similar to the other
+   board probes now that kmalloc() can allocate ISA DMA-able regions.
+   This also allows the LANCE driver to be used as a module.
+   */
+int lance_probe(struct device *dev)
+{
+       int *port, result;
+
+       if (high_memory <= 16*1024*1024)
                lance_need_isa_bounce_buffers = 0;
 
-#if defined(CONFIG_PCI) && !(defined(CONFIG_PCNET32) || defined(CONFIG_PCNET32_MODULE))
+#if defined(CONFIG_PCI)
     if (pci_present()) {
-           struct pci_dev *pdev = NULL;
+               struct pci_dev *pdev = NULL;
                if (lance_debug > 1)
-                       printk("lance.c: PCI is present, checking for devices...\n");
+                       printk("lance.c: PCI bios is present, checking for devices...\n");
+
                while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) {
                        unsigned int pci_ioaddr;
                        unsigned short pci_command;
@@ -344,8 +390,9 @@ __initfunc(int lance_init(void))
                        }
                        printk("Found PCnet/PCI at %#x, irq %d.\n",
                                   pci_ioaddr, pci_irq_line);
-                       lance_probe1(pci_ioaddr);
+                       result = lance_probe1(dev, pci_ioaddr, pci_irq_line, 0);
                        pci_irq_line = 0;
+                       if (!result) return 0;
                }
        }
 #endif  /* defined(CONFIG_PCI) */
@@ -359,16 +406,17 @@ __initfunc(int lance_init(void))
                        char offset15, offset14 = inb(ioaddr + 14);
                        
                        if ((offset14 == 0x52 || offset14 == 0x57) &&
-                               ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44))
-                               lance_probe1(ioaddr);
+                               ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) {
+                               result = lance_probe1(dev, ioaddr, 0, 0);
+                               if ( !result ) return 0;
+                       }
                }
        }
-       return 0;
+       return -ENODEV;
 }
 
-__initfunc(void lance_probe1(int ioaddr))
+__initfunc(int lance_probe1(struct device *dev, int ioaddr, int irq, int options))
 {
-       struct device *dev;
        struct lance_private *lp;
        short dma_channels;                                     /* Mark spuriously-busy DMA channels */
        int i, reset_val, lance_version;
@@ -406,7 +454,7 @@ __initfunc(void lance_probe1(int ioaddr))
 
        outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
        if (inw(ioaddr+LANCE_DATA) != 0x0004)
-               return;
+               return -ENODEV;
 
        /* Get the version of the chip. */
        outw(88, ioaddr+LANCE_ADDR);
@@ -419,24 +467,17 @@ __initfunc(void lance_probe1(int ioaddr))
                if (lance_debug > 2)
                        printk("  LANCE chip version is %#x.\n", chip_version);
                if ((chip_version & 0xfff) != 0x003)
-                       return;
+                       return -ENODEV;
                chip_version = (chip_version >> 12) & 0xffff;
                for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) {
                        if (chip_table[lance_version].id_number == chip_version)
                                break;
                }
        }
-    
-#if defined(CONFIG_PCNET32) || defined (CONFIG_PCNET32_MODULE)
-        /*
-        * if pcnet32 is configured and the chip is capable of 32bit mode
-        * leave the card alone
-        */
-        if (chip_table[lance_version].flags & PCNET32_POSSIBLE)
-          return;
-#endif    
 
-       dev = init_etherdev(0, 0);
+       /* We can't use init_etherdev() to allocate dev->priv because it must
+          a ISA DMA-able region. */
+       dev = init_etherdev(dev, 0);
        dev->open = lance_open_fail;
        chipname = chip_table[lance_version].name;
        printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
@@ -450,6 +491,7 @@ __initfunc(void lance_probe1(int ioaddr))
        request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
 
        /* Make certain the data structures used by the LANCE are aligned and DMAble. */
+               
        lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7,
                                                                                   GFP_DMA | GFP_KERNEL)+7) & ~7);
        if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
@@ -483,9 +525,9 @@ __initfunc(void lance_probe1(int ioaddr))
        outw(0x0000, ioaddr+LANCE_ADDR);
        inw(ioaddr+LANCE_ADDR);
 
-       if (pci_irq_line) {
+       if (irq) {                                      /* Set iff PCI card. */
                dev->dma = 4;                   /* Native bus-master, no DMA channel needed. */
-               dev->irq = pci_irq_line;
+               dev->irq = irq;
        } else if (hp_builtin) {
                static const char dma_tbl[4] = {3, 5, 6, 0};
                static const char irq_tbl[4] = {3, 4, 5, 9};
@@ -534,7 +576,7 @@ __initfunc(void lance_probe1(int ioaddr))
                        printk(", probed IRQ %d", dev->irq);
                else {
                        printk(", failed to detect IRQ line.\n");
-                       return;
+                       return -ENODEV;
                }
 
                /* Check for the initialization done bit, 0x0100, which means
@@ -548,7 +590,7 @@ __initfunc(void lance_probe1(int ioaddr))
        } else if (dev->dma) {
                if (request_dma(dev->dma, chipname)) {
                        printk("DMA %d allocation failed.\n", dev->dma);
-                       return;
+                       return -ENODEV;
                } else
                        printk(", assigned DMA %d.\n", dev->dma);
        } else {                        /* OK, we have to auto-DMA. */
@@ -588,7 +630,7 @@ __initfunc(void lance_probe1(int ioaddr))
                }
                if (i == 4) {                   /* Failure: bail. */
                        printk("DMA detection failed.\n");
-                       return;
+                       return -ENODEV;
                }
        }
 
@@ -601,7 +643,7 @@ __initfunc(void lance_probe1(int ioaddr))
                dev->irq = autoirq_report(4);
                if (dev->irq == 0) {
                        printk("  Failed to detect the 7990 IRQ line.\n");
-                       return;
+                       return -ENODEV;
                }
                printk("  Auto-IRQ detected IRQ%d.\n", dev->irq);
        }
@@ -610,8 +652,8 @@ __initfunc(void lance_probe1(int ioaddr))
                /* Turn on auto-select of media (10baseT or BNC) so that the user
                   can watch the LEDs even if the board isn't opened. */
                outw(0x0002, ioaddr+LANCE_ADDR);
-               /* set autoselect and clean xmausel */
-               outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF);
+               /* Don't touch 10base2 power bit. */
+               outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
        }
 
        if (lance_debug > 0  &&  did_version++ == 0)
@@ -624,7 +666,7 @@ __initfunc(void lance_probe1(int ioaddr))
        dev->get_stats = lance_get_stats;
        dev->set_multicast_list = set_multicast_list;
 
-       return;
+       return 0;
 }
 
 static int
@@ -647,6 +689,8 @@ lance_open(struct device *dev)
                return -EAGAIN;
        }
 
+       MOD_INC_USE_COUNT;
+
        /* We used to allocate DMA here, but that was silly.
           DMA lines can't be shared!  We now permanently allocate them. */
 
@@ -668,9 +712,9 @@ lance_open(struct device *dev)
        if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
                /* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */
                outw(0x0002, ioaddr+LANCE_ADDR);
-               /* set autoselect and clean xmausel */
-               outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF);
-       }
+               /* Only touch autoselect bit. */
+               outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
+       }
 
        if (lance_debug > 1)
                printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
@@ -679,7 +723,7 @@ lance_open(struct device *dev)
                           (u32) virt_to_bus(lp->rx_ring),
                           (u32) virt_to_bus(&lp->init_block));
 
-       lance_init_ring(dev);
+       lance_init_ring(dev, GFP_KERNEL);
        /* Re-initialize the LANCE, and start it when done. */
        outw(0x0001, ioaddr+LANCE_ADDR);
        outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
@@ -741,7 +785,7 @@ lance_purge_tx_ring(struct device *dev)
 
 /* Initialize the LANCE Rx and Tx rings. */
 static void
-lance_init_ring(struct device *dev)
+lance_init_ring(struct device *dev, int gfp)
 {
        struct lance_private *lp = (struct lance_private *)dev->priv;
        int i;
@@ -751,12 +795,26 @@ lance_init_ring(struct device *dev)
        lp->dirty_rx = lp->dirty_tx = 0;
 
        for (i = 0; i < RX_RING_SIZE; i++) {
-               lp->rx_ring[i].base = (u32)virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ) | 0x80000000;
+               struct sk_buff *skb;
+               void *rx_buff;
+
+               skb = alloc_skb(PKT_BUF_SZ, GFP_DMA | gfp);
+               lp->rx_skbuff[i] = skb;
+               if (skb) {
+                       skb->dev = dev;
+                       rx_buff = skb->tail;
+               } else
+                       rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | gfp);
+               if (rx_buff == NULL)
+                       lp->rx_ring[i].base = 0;
+               else
+                       lp->rx_ring[i].base = (u32)virt_to_bus(rx_buff) | 0x80000000;
                lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
        }
        /* The Tx buffer address is filled in as needed, but we do need to clear
           the upper ownership bit. */
        for (i = 0; i < TX_RING_SIZE; i++) {
+               lp->tx_skbuff[i] = 0;
                lp->tx_ring[i].base = 0;
        }
 
@@ -777,7 +835,7 @@ lance_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
        if (must_reinit ||
                (chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) {
                lance_purge_tx_ring(dev);
-               lance_init_ring(dev);
+               lance_init_ring(dev, GFP_ATOMIC);
        }
        outw(0x0000,    dev->base_addr + LANCE_ADDR);
        outw(csr0_bits, dev->base_addr + LANCE_DATA);
@@ -872,14 +930,14 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev)
                memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len);
                lp->tx_ring[entry].base =
                        ((u32)virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000;
-               dev_kfree_skb (skb);
+               dev_kfree_skb(skb);
        } else {
                lp->tx_skbuff[entry] = skb;
                lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
        }
        lp->cur_tx++;
-       lp->stats.tx_bytes+=skb->len;
-       
+       lp->stats.tx_bytes += skb->len;
+
        /* Trigger an immediate send poll. */
        outw(0x0000, ioaddr+LANCE_ADDR);
        outw(0x0048, ioaddr+LANCE_DATA);
@@ -915,7 +973,7 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        ioaddr = dev->base_addr;
        lp = (struct lance_private *)dev->priv;
        if (dev->interrupt)
-               printk("%s: Re-entering the interrupt handler.\n", dev->name);
+               printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);
 
        dev->interrupt = 1;
 
@@ -1110,6 +1168,7 @@ lance_close(struct device *dev)
 {
        int ioaddr = dev->base_addr;
        struct lance_private *lp = (struct lance_private *)dev->priv;
+       int i;
 
        dev->start = 0;
        dev->tbusy = 1;
@@ -1134,9 +1193,23 @@ lance_close(struct device *dev)
                disable_dma(dev->dma);
                release_dma_lock(flags);
        }
-
        free_irq(dev->irq, dev);
 
+       /* Free all the skbuffs in the Rx and Tx queues. */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               struct sk_buff *skb = lp->rx_skbuff[i];
+               lp->rx_skbuff[i] = 0;
+               lp->rx_ring[i].base = 0;                /* Not owned by LANCE chip. */
+               if (skb)
+                       dev_kfree_skb(skb);
+       }
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               if (lp->tx_skbuff[i])
+                       dev_kfree_skb(lp->tx_skbuff[i]);
+               lp->tx_skbuff[i] = 0;
+       }
+
+       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1195,11 +1268,3 @@ static void set_multicast_list(struct device *dev)
 
 }
 
-\f
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance.c"
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */
index 5e381d9856e22700492ccbd3c5abb04df3af6b1d..edb41febb4d433b79edbc39a6e576022a268d80c 100644 (file)
@@ -165,6 +165,9 @@ static int fddi_change_mtu(struct device *dev, int new_mtu)
 #endif
 
 #ifdef CONFIG_HIPPI
+#define MAX_HIP_CARDS  4
+static struct device *hipdev_index[MAX_HIP_CARDS];
+
 static int hippi_change_mtu(struct device *dev, int new_mtu)
 {
        /*
@@ -193,32 +196,60 @@ static int hippi_mac_addr(struct device *dev, void *p)
 
 struct device *init_hippi_dev(struct device *dev, int sizeof_priv)
 {
-       struct device *tmp_dev;         /* pointer to a device structure */
+       int new_device = 0;
+       int i;
 
-       /* Find next free HIPPI entry */
+       /* Use an existing correctly named device in Space.c:dev_base. */
+       if (dev == NULL) {
+               int alloc_size = sizeof(struct device) + sizeof("hip%d  ")
+                       + sizeof_priv + 3;
+               struct device *cur_dev;
+               char pname[8];
 
-       for (tmp_dev = dev; tmp_dev != NULL; tmp_dev = tmp_dev->next)
-               if ((strncmp(tmp_dev->name, "hip", 3) == 0) &&
-                   (tmp_dev->base_addr == 0))
-                       break;
+               for (i = 0; i < MAX_HIP_CARDS; ++i)
+                       if (hipdev_index[i] == NULL) {
+                               sprintf(pname, "hip%d", i);
+                               for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next)
+                                       if (strcmp(pname, cur_dev->name) == 0) {
+                                               dev = cur_dev;
+                                               dev->init = NULL;
+                                               sizeof_priv = (sizeof_priv + 3) & ~3;
+                                               dev->priv = sizeof_priv
+                                                         ? kmalloc(sizeof_priv, GFP_KERNEL)
+                                                         :     NULL;
+                                               if (dev->priv) memset(dev->priv, 0, sizeof_priv);
+                                               goto hipfound;
+                                       }
+                       }
 
-       if (tmp_dev == NULL)
-       {
-               printk("Could not find free HIPPI device structure.\n");
-               return NULL;
+               alloc_size &= ~3;               /* Round to dword boundary. */
+
+               dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
+               memset(dev, 0, alloc_size);
+               if (sizeof_priv)
+                       dev->priv = (void *) (dev + 1);
+               dev->name = sizeof_priv + (char *)(dev + 1);
+               new_device = 1;
        }
-               
-       tmp_dev->init = NULL;
-       sizeof_priv = (sizeof_priv + 3) & ~3;
-       tmp_dev->priv = sizeof_priv ?                                                           kmalloc(sizeof_priv, GFP_KERNEL) : NULL;
 
-       if (tmp_dev->priv)
-               memset(dev->priv, 0, sizeof_priv);
+hipfound:                              /* From the double loop above. */
 
-       /* Initialize remaining device structure information */
+       if (dev->name &&
+               ((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
+               for (i = 0; i < MAX_HIP_CARDS; ++i)
+                       if (hipdev_index[i] == NULL) {
+                               sprintf(dev->name, "hip%d", i);
+                               hipdev_index[i] = dev;
+                               break;
+                       }
+       }
 
-       hippi_setup(tmp_dev);
-       return tmp_dev;
+       hippi_setup(dev);
+       
+       if (new_device)
+               register_netdevice(dev);
+
+       return dev;
 }
 
 static int hippi_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
@@ -312,6 +343,19 @@ void fddi_setup(struct device *dev)
 #ifdef CONFIG_HIPPI
 void hippi_setup(struct device *dev)
 {
+       int i;
+
+       if (dev->name && (strncmp(dev->name, "hip", 3) == 0)) {
+               i = simple_strtoul(dev->name + 3, NULL, 0);
+               if (hipdev_index[i] == NULL) {
+                       hipdev_index[i] = dev;
+               }
+               else if (dev != hipdev_index[i]) {
+                       printk("hippi_setup: Ouch! Someone else took %s\n",
+                               dev->name);
+               }
+       }
+
        dev->set_multicast_list = NULL;
        dev->change_mtu                 = hippi_change_mtu;
        dev->hard_header                = hippi_header;
index c578ba87d92ccf15935b7842de2664cad634b34d..a6b4920fcc4b57f082d94896d57f517962667f78 100644 (file)
@@ -2041,7 +2041,7 @@ rcv_proto_vjc_comp(struct ppp *ppp, struct sk_buff *skb)
                return 0;
        new_count = slhc_uncompress(ppp->slcomp, skb->data + PPP_HDRLEN,
                                    skb->len - PPP_HDRLEN);
-       if (new_count < 0) {
+       if (new_count<=0) {
                if (ppp->flags & SC_DEBUG)
                        printk(KERN_NOTICE
                               "ppp: error in VJ decompression\n");
diff --git a/drivers/net/rcif.h b/drivers/net/rcif.h
new file mode 100644 (file)
index 0000000..4996b01
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+** *************************************************************************
+**
+**
+**     R C I F . H
+**
+**
+**  RedCreek InterFace include file.
+**
+**  ---------------------------------------------------------------------
+**  ---     Copyright (c) 1998, RedCreek Communications Inc.          ---
+**  ---                   All rights reserved.                        ---
+**  ---------------------------------------------------------------------
+**
+** File Description:
+**
+** Header file private ioctl commands.
+**
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+** *************************************************************************
+*/
+
+#ifndef RCIF_H
+#define RCIF_H
+
+/* The following protocol revision # should be incremented every time
+   a new protocol or new structures are used in this file. */
+int USER_PROTOCOL_REV = 1;     /* used to track different protocol revisions */
+
+/* define a single TCB & buffer */
+typedef struct                  /* a single buffer */
+{
+     U32 context;               /* context */
+     U32 scount;                /* segment count */
+     U32 size;                  /* segment size */
+     U32 addr;                  /* segment physical address */
+}
+__attribute__((packed))
+singleB, *psingleB ;
+typedef struct                  /* a single TCB */
+{
+     /*
+     **  +-----------------------+
+     **  |         1             |  one buffer in the TCB
+     **  +-----------------------+
+     **  |  <user's Context>     |  user's buffer reference
+     **  +-----------------------+
+     **  |         1             |  one segment buffer
+     **  +-----------------------+                            _
+     **  |    <buffer size>      |  size                       \ 
+     **  +-----------------------+                              \ segment descriptor
+     **  |  <physical address>   |  physical address of buffer  /
+     **  +-----------------------+                            _/
+     */
+     U32 bcount;                /* buffer count */
+     singleB b;                 /* buffer */
+
+}
+__attribute__((packed))
+singleTCB, *psingleTCB;
+
+/*
+   When adding new entries, please add all 5 related changes, since 
+   it helps keep everything consistent:
+      1) User structure entry
+      2) User data entry
+      3) Structure short-cut entry
+      4) Data short-cut entry
+      5) Command identifier entry
+
+   For Example ("GETSPEED"):
+      1) struct  RCgetspeed_tag { U32 LinkSpeedCode; } RCgetspeed;
+      2) struct  RCgetspeed_tag *getspeed;
+      3) #define RCUS_GETSPEED  data.RCgetspeed;
+      4) #define RCUD_GETSPEED  _RC_user_data.getspeed
+      5) #define RCUC_GETSPEED  0x02
+  
+   Notes for the "GETSPEED" entry, above:
+      1) RCgetspeed      - RC{name}
+         RCgetspeed_tag  - RC{name}_tag
+         LinkSpeedCode   - create any structure format desired (not too large,
+                           since memory will be unioned with all other entries)
+      2) RCgetspeed_tag  - RC{name}_tag chosen in #1
+         getspeed        - arbitrary name (ptr to structure in #1)
+      3) RCUS_GETSPEED   - RCUS_{NAME}   ("NAME" & "name" do not have to the same)
+         data.RCgetspeed - data.RC{name}  ("RC{name}" from #1)
+      4) RCUD_GETSPEED   - _RC_user_data.getspeed  ("getspeed" from #2)
+      5) RCUC_GETSPEED   - unique hex identifier entry.
+*/
+
+typedef struct RC_user_tag RCuser_struct;
+
+/* 1) User structure entry */
+struct RC_user_tag
+{
+    int cmd;
+    union
+    {
+        /* GETINFO structure */
+        struct RCgetinfo_tag {
+            unsigned long int mem_start;
+            unsigned long int mem_end;
+            unsigned long int base_addr;
+            unsigned char irq;
+            unsigned char dma;
+            unsigned char port;
+        } RCgetinfo;                    /* <---- RCgetinfo */
+     
+        /* GETSPEED structure */
+        struct  RCgetspeed_tag {
+            U32 LinkSpeedCode;
+        } RCgetspeed;                   /* <---- RCgetspeed */
+  
+        /* GETFIRMWAREVER structure */
+        #define FirmStringLen 80
+        struct RCgetfwver_tag {
+            U8 FirmString[FirmStringLen];
+        } RCgetfwver;                   /* <---- RCgetfwver */
+  
+        /* GETIPANDMASK structure */
+        struct RCgetipnmask_tag {
+            U32 IpAddr;
+            U32 NetMask;
+        } RCgetipandmask;               /* <---- RCgetipandmask */
+
+        /* GETMAC structure */
+        #define MAC_SIZE 10
+        struct RCgetmac_tag {
+            U8 mac[MAC_SIZE];
+        } RCgetmac;                     /* <---- RCgetmac */
+
+        /* GETLINKSTATUS structure */
+        struct RCgetlnkstatus_tag {
+            U32 ReturnStatus;
+        } RCgetlnkstatus;               /* <---- RCgetlnkstatus */
+
+        /* GETLINKSTATISTICS structure */
+        struct RCgetlinkstats_tag {
+            RCLINKSTATS StatsReturn;
+        } RCgetlinkstats;               /* <---- RCgetlinkstats */
+
+        /* DEFAULT structure (when no command was recognized) */
+        struct RCdefault_tag {
+            int rc;
+        } RCdefault;                    /* <---- RCdefault */
+
+    } data;
+
+};   /* struct RC_user_tag { ... } */
+
+/* 2) User data entry */
+/* RCUD = RedCreek User Data */
+union RC_user_data_tag {        /* structure tags used are taken from RC_user_tag structure above */
+    struct RCgetinfo_tag      *getinfo;
+    struct RCgetspeed_tag     *getspeed;
+    struct RCgetfwver_tag     *getfwver;
+    struct RCgetipnmask_tag   *getipandmask;
+    struct RCgetmac_tag       *getmac;
+    struct RCgetlnkstatus_tag *getlinkstatus;
+    struct RCgetlinkstats_tag *getlinkstatistics;
+    struct RCdefault_tag      *rcdefault;
+} _RC_user_data;  /* declare as a global, so the defines below will work */
+
+/* 3) Structure short-cut entry */
+/* define structure short-cuts */   /* structure names are taken from RC_user_tag structure above */
+#define RCUS_GETINFO           data.RCgetinfo;
+#define RCUS_GETSPEED          data.RCgetspeed;
+#define RCUS_GETFWVER          data.RCgetfwver;
+#define RCUS_GETIPANDMASK      data.RCgetipandmask;
+#define RCUS_GETMAC            data.RCgetmac;
+#define RCUS_GETLINKSTATUS     data.RCgetlnkstatus;
+#define RCUS_GETLINKSTATISTICS data.RCgetlinkstats;
+#define RCUS_DEFAULT           data.RCdefault;
+
+/* 4) Data short-cut entry */
+/* define data short-cuts */    /* pointer names are from RC_user_data_tag union (just below RC_user_tag) */
+#define RCUD_GETINFO           _RC_user_data.getinfo
+#define RCUD_GETSPEED          _RC_user_data.getspeed
+#define RCUD_GETFWVER          _RC_user_data.getfwver
+#define RCUD_GETIPANDMASK      _RC_user_data.getipandmask
+#define RCUD_GETMAC            _RC_user_data.getmac
+#define RCUD_GETLINKSTATUS     _RC_user_data.getlinkstatus
+#define RCUD_GETLINKSTATISTICS _RC_user_data.getlinkstatistics
+#define RCUD_DEFAULT           _RC_user_data.rcdefault
+
+/* 5) Command identifier entry */
+/* define command identifiers */
+#define RCUC_GETINFO            0x01
+#define RCUC_GETSPEED           0x02
+#define RCUC_GETFWVER           0x03
+#define RCUC_GETIPANDMASK       0x04
+#define RCUC_GETMAC             0x05
+#define RCUC_GETLINKSTATUS      0x06
+#define RCUC_GETLINKSTATISTICS  0x07
+#define RCUC_DEFAULT            0xff
+
+/* define ioctl commands to use, when talking to RC 45/PCI driver */
+#define RCU_PROTOCOL_REV         SIOCDEVPRIVATE
+#define RCU_COMMAND              SIOCDEVPRIVATE+1
+
+/*
+   Intended use for the above defines is shown below (GETINFO, as this example):
+
+      RCuser_struct RCuser;           // declare RCuser structure
+      struct ifreq ifr;               // declare an interface request structure
+
+      RCuser.cmd = RCUC_GETINFO;           // set user command to GETINFO
+      ifr->ifr_data = (caddr_t) &RCuser;   // set point to user structure
+
+      sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);   // get a socket
+      ioctl(sock, RCU_COMMAND, &ifr);                  // do ioctl on socket
+
+      RCUD_GETINFO = &RCuser.RCUS_GETINFO;   // set data pointer for GETINFO
+
+      // print results
+      printf("memory 0x%lx-0x%lx, base address 0x%x, irq 0x%x\n",
+              RCUD_GETINFO->mem_start, RCUD_GETINFO->mem_end,
+              RCUD_GETINFO->base_addr, RCUD_GETINFO->irq);
+*/
+
+#endif   /* RCIF_H */
+
diff --git a/drivers/net/rcmtl.c b/drivers/net/rcmtl.c
new file mode 100644 (file)
index 0000000..db1509a
--- /dev/null
@@ -0,0 +1,2058 @@
+/*
+** *************************************************************************
+**
+**
+**     R C M T L . C             $Revision: 1.1 $
+**
+**
+**  RedCreek Message Transport Layer program module.
+**
+**  ---------------------------------------------------------------------
+**  ---     Copyright (c) 1997-1998, RedCreek Communications Inc.     ---
+**  ---                   All rights reserved.                        ---
+**  ---------------------------------------------------------------------
+**
+** File Description:
+**
+** Host side message transport layer.
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+***************************************************************************/
+
+#undef DEBUG
+
+#define RC_LINUX_MODULE
+#include "rcmtl.h"
+
+#define dprintf kprintf
+
+extern int printk(const char * fmt, ...);
+
+ /* RedCreek LAN device Target ID */
+#define LAN_TARGET_ID  0x10 
+ /* RedCreek's OSM default LAN receive Initiator */
+#define DEFAULT_RECV_INIT_CONTEXT  0xA17  
+
+
+/*
+** message structures
+*/
+
+#define    TID_SZ                                  12
+#define    FUNCTION_SZ                             8
+
+/* Transaction Reply Lists (TRL) Control Word structure */
+
+#define    TRL_SINGLE_FIXED_LENGTH           0x00
+#define    TRL_SINGLE_VARIABLE_LENGTH        0x40
+#define    TRL_MULTIPLE_FIXED_LENGTH         0x80
+
+/* LAN Class specific functions */
+
+#define    LAN_PACKET_SEND                         0x3B
+#define    LAN_SDU_SEND                            0x3D
+#define    LAN_RECEIVE_POST                        0x3E
+#define    LAN_RESET                               0x35
+#define    LAN_SHUTDOWN                            0x37
+
+/* Private Class specfic function */
+#define    RC_PRIVATE                                 0xFF
+
+/*  RC Executive Function Codes.  */
+
+#define    RC_CMD_ADAPTER_ASSIGN                     0xB3
+#define    RC_CMD_ADAPTER_READ                       0xB2
+#define    RC_CMD_ADAPTER_RELEASE                    0xB5
+#define    RC_CMD_BIOS_INFO_SET                      0xA5
+#define    RC_CMD_BOOT_DEVICE_SET                    0xA7
+#define    RC_CMD_CONFIG_VALIDATE                    0xBB
+#define    RC_CMD_CONN_SETUP                         0xCA
+#define    RC_CMD_DEVICE_ASSIGN                      0xB7
+#define    RC_CMD_DEVICE_RELEASE                     0xB9
+#define    RC_CMD_HRT_GET                            0xA8
+#define    RC_CMD_ADAPTER_CLEAR                          0xBE
+#define    RC_CMD_ADAPTER_CONNECT                        0xC9
+#define    RC_CMD_ADAPTER_RESET                          0xBD
+#define    RC_CMD_LCT_NOTIFY                         0xA2
+#define    RC_CMD_OUTBOUND_INIT                      0xA1
+#define    RC_CMD_PATH_ENABLE                        0xD3
+#define    RC_CMD_PATH_QUIESCE                       0xC5
+#define    RC_CMD_PATH_RESET                         0xD7
+#define    RC_CMD_STATIC_MF_CREATE                   0xDD
+#define    RC_CMD_STATIC_MF_RELEASE                  0xDF
+#define    RC_CMD_STATUS_GET                         0xA0
+#define    RC_CMD_SW_DOWNLOAD                        0xA9
+#define    RC_CMD_SW_UPLOAD                          0xAB
+#define    RC_CMD_SW_REMOVE                          0xAD
+#define    RC_CMD_SYS_ENABLE                         0xD1
+#define    RC_CMD_SYS_MODIFY                         0xC1
+#define    RC_CMD_SYS_QUIESCE                        0xC3
+#define    RC_CMD_SYS_TAB_SET                        0xA3
+
+
+ /* Init Outbound Q status */
+#define    RC_CMD_OUTBOUND_INIT_IN_PROGRESS          0x01
+#define    RC_CMD_OUTBOUND_INIT_REJECTED             0x02
+#define    RC_CMD_OUTBOUND_INIT_FAILED               0x03
+#define    RC_CMD_OUTBOUND_INIT_COMPLETE             0x04
+
+
+#define    UTIL_NOP                                0x00
+
+
+/* RC Get Status State values */
+
+#define    ADAPTER_STATE_INITIALIZING                  0x01
+#define    ADAPTER_STATE_RESET                         0x02
+#define    ADAPTER_STATE_HOLD                          0x04
+#define    ADAPTER_STATE_READY                         0x05
+#define    ADAPTER_STATE_OPERATIONAL                   0x08
+#define    ADAPTER_STATE_FAILED                        0x10
+#define    ADAPTER_STATE_FAULTED                       0x11
+
+
+/* Defines for Request Status Codes:  Table 3-1 Reply Status Codes.  */
+
+#define    RC_REPLY_STATUS_SUCCESS                    0x00
+#define    RC_REPLY_STATUS_ABORT_DIRTY                0x01
+#define    RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     0x02
+#define    RC_REPLY_STATUS_ABORT_PARTIAL_TRANSFER     0x03
+#define    RC_REPLY_STATUS_ERROR_DIRTY                0x04
+#define    RC_REPLY_STATUS_ERROR_NO_DATA_TRANSFER     0x05
+#define    RC_REPLY_STATUS_ERROR_PARTIAL_TRANSFER     0x06
+#define    RC_REPLY_STATUS_PROCESS_ABORT_DIRTY        0x07
+#define    RC_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER   0x08
+#define    RC_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER   0x09
+#define    RC_REPLY_STATUS_TRANSACTION_ERROR          0x0A
+#define    RC_REPLY_STATUS_PROGRESS_REPORT            0x80
+
+
+/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/
+
+#define    RC_DS_SUCCESS                        0x0000
+#define    RC_DS_BAD_KEY                        0x0001
+#define    RC_DS_CHAIN_BUFFER_TOO_LARGE         0x0002
+#define    RC_DS_DEVICE_BUSY                    0x0003
+#define    RC_DS_DEVICE_LOCKED                  0x0004
+#define    RC_DS_DEVICE_NOT_AVAILABLE           0x0005
+#define    RC_DS_DEVICE_RESET                   0x0006
+#define    RC_DS_INAPPROPRIATE_FUNCTION         0x0007
+#define    RC_DS_INSUFFICIENT_RESOURCE_HARD     0x0008
+#define    RC_DS_INSUFFICIENT_RESOURCE_SOFT     0x0009
+#define    RC_DS_INVALID_INITIATOR_ADDRESS      0x000A
+#define    RC_DS_INVALID_MESSAGE_FLAGS          0x000B
+#define    RC_DS_INVALID_OFFSET                 0x000C
+#define    RC_DS_INVALID_PARAMETER              0x000D
+#define    RC_DS_INVALID_REQUEST                0x000E
+#define    RC_DS_INVALID_TARGET_ADDRESS         0x000F
+#define    RC_DS_MESSAGE_TOO_LARGE              0x0010
+#define    RC_DS_MESSAGE_TOO_SMALL              0x0011
+#define    RC_DS_MISSING_PARAMETER              0x0012
+#define    RC_DS_NO_SUCH_PAGE                   0x0013
+#define    RC_DS_REPLY_BUFFER_FULL              0x0014
+#define    RC_DS_TCL_ERROR                      0x0015
+#define    RC_DS_TIMEOUT                        0x0016
+#define    RC_DS_UNKNOWN_ERROR                  0x0017
+#define    RC_DS_UNKNOWN_FUNCTION               0x0018
+#define    RC_DS_UNSUPPORTED_FUNCTION           0x0019
+#define    RC_DS_UNSUPPORTED_VERSION            0x001A
+
+ /* msg header defines for VersionOffset */
+#define RCMSGVER_1   0x0001
+#define SGL_OFFSET_0    RCMSGVER_1
+#define SGL_OFFSET_4    (0x0040 | RCMSGVER_1)
+#define TRL_OFFSET_5    (0x0050 | RCMSGVER_1)
+#define TRL_OFFSET_6    (0x0060 | RCMSGVER_1)
+
+ /* msg header defines for MsgFlags */
+#define MSG_STATIC      0x0100
+#define MSG_64BIT_CNTXT 0x0200
+#define MSG_MULTI_TRANS 0x1000
+#define MSG_FAIL        0x2000
+#define MSG_LAST        0x4000
+#define MSG_REPLY       0x8000
+
+  /* normal LAN request message MsgFlags and VersionOffset (0x1041) */
+#define LAN_MSG_REQST  (MSG_MULTI_TRANS | SGL_OFFSET_4)
+
+ /* minimum size msg */
+#define THREE_WORD_MSG_SIZE 0x00030000
+#define FOUR_WORD_MSG_SIZE  0x00040000
+#define FIVE_WORD_MSG_SIZE  0x00050000
+#define SIX_WORD_MSG_SIZE   0x00060000
+#define SEVEN_WORD_MSG_SIZE 0x00070000
+#define EIGHT_WORD_MSG_SIZE 0x00080000
+#define NINE_WORD_MSG_SIZE  0x00090000
+
+/* Special TID Assignments */
+
+#define ADAPTER_TID   0
+#define HOST_TID  1
+
+ /* RedCreek private message codes */
+#define RC_PRIVATE_GET_MAC_ADDR     0x0001/**/ /* OBSOLETE */
+#define RC_PRIVATE_SET_MAC_ADDR     0x0002
+#define RC_PRIVATE_GET_LAN_STATS    0x0003
+#define RC_PRIVATE_GET_LINK_STATUS  0x0004
+#define RC_PRIVATE_SET_LINK_SPEED   0x0005
+#define RC_PRIVATE_SET_IP_AND_MASK  0x0006
+/* #define RC_PRIVATE_GET_IP_AND_MASK  0x0007 */ /* OBSOLETE */
+#define RC_PRIVATE_GET_LINK_SPEED   0x0008
+#define RC_PRIVATE_GET_FIRMWARE_REV 0x0009
+/* #define RC_PRIVATE_GET_MAC_ADDR     0x000A *//**/
+#define RC_PRIVATE_GET_IP_AND_MASK  0x000B /**/
+#define RC_PRIVATE_DEBUG_MSG        0x000C
+#define RC_PRIVATE_REPORT_DRIVER_CAPABILITY  0x000D
+
+#define RC_PRIVATE_REBOOT           0x00FF
+
+
+/* RC message header */
+typedef struct _RC_MSG_FRAME 
+{
+   U8                          VersionOffset;
+   U8                          MsgFlags;
+   U16                         MessageSize;
+   BF                          TargetAddress:TID_SZ;
+   BF                          InitiatorAddress:TID_SZ;
+   BF                          Function:FUNCTION_SZ;
+   U32                         InitiatorContext;
+   /* SGL[] */ 
+}
+ RC_MSG_FRAME, *PRC_MSG_FRAME;
+
+
+ /* assumed a 16K minus 256 byte space for outbound queue message frames */
+#define MSG_FRAME_SIZE  512
+#define NMBR_MSG_FRAMES 30
+
+/*
+**  Message Unit CSR definitions for RedCreek PCI45 board
+*/
+typedef struct tag_rcatu 
+{
+    volatile unsigned long APICRegSel;  /* APIC Register Select */
+    volatile unsigned long reserved0;
+    volatile unsigned long APICWinReg;  /* APIC Window Register */
+    volatile unsigned long reserved1;
+    volatile unsigned long InMsgReg0;   /* inbound message register 0 */
+    volatile unsigned long InMsgReg1;   /* inbound message register 1 */
+    volatile unsigned long OutMsgReg0;  /* outbound message register 0 */
+    volatile unsigned long OutMsgReg1;  /* outbound message register 1 */
+    volatile unsigned long InDoorReg;   /* inbound doorbell register */
+    volatile unsigned long InIntStat;   /* inbound interrupt status register */
+    volatile unsigned long InIntMask;   /* inbound interrupt mask register */
+    volatile unsigned long OutDoorReg;  /* outbound doorbell register */
+    volatile unsigned long OutIntStat;  /* outbound interrupt status register */
+    volatile unsigned long OutIntMask;  /* outbound interrupt mask register */
+    volatile unsigned long reserved2;
+    volatile unsigned long reserved3;
+    volatile unsigned long InQueue;     /* inbound queue port */
+    volatile unsigned long OutQueue;    /* outbound queue port */
+    volatile unsigned long reserved4;
+    volatile unsigned long reserver5;
+     /* RedCreek extension */
+    volatile unsigned long EtherMacLow;
+    volatile unsigned long EtherMacHi;
+    volatile unsigned long IPaddr;
+    volatile unsigned long IPmask;
+}
+ ATU, *PATU;
+
+ /* 
+ ** typedef PAB
+ **
+ ** PCI Adapter Block - holds instance specific information and is located
+ ** in a reserved space at the start of the message buffer allocated by user.
+ */
+typedef struct
+{
+    PATU             p_atu;                /* ptr to  ATU register block */
+    PU8              pPci45LinBaseAddr;
+    PU8              pLinOutMsgBlock;
+    U32              outMsgBlockPhyAddr; 
+    PFNTXCALLBACK    pTransCallbackFunc;
+    PFNRXCALLBACK    pRecvCallbackFunc;
+    PFNCALLBACK      pRebootCallbackFunc;
+    PFNCALLBACK      pCallbackFunc;
+    U16              ADAPTERState;
+    U16              InboundMFrameSize;
+}
+ PAB, *PPAB;
+
+ /* 
+ ** in reserved space right after PAB in host memory is area for returning
+ ** values from card 
+ */
+
+ /* 
+ ** Array of pointers to PCI Adapter Blocks.
+ ** Indexed by a zero based (0-31) interface number.
+ */ 
+#define MAX_ADAPTERS 32
+static PPAB  PCIAdapterBlock[MAX_ADAPTERS] = 
+{
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+
+/*
+** typedef NICSTAT
+**
+** Data structure for NIC statistics retruned from PCI card.  Data copied from
+** here to user allocated RCLINKSTATS (see rclanmtl.h) structure.
+*/
+typedef struct tag_NicStat 
+{
+        unsigned long   TX_good; 
+        unsigned long   TX_maxcol;
+        unsigned long   TX_latecol;
+        unsigned long   TX_urun;
+        unsigned long   TX_crs;         /* lost carrier sense */
+        unsigned long   TX_def;         /* transmit deferred */
+        unsigned long   TX_singlecol;   /* single collisions */
+        unsigned long   TX_multcol;
+        unsigned long   TX_totcol;
+        unsigned long   Rcv_good;
+        unsigned long   Rcv_CRCerr;
+        unsigned long   Rcv_alignerr;
+        unsigned long   Rcv_reserr;     /* rnr'd pkts */
+        unsigned long   Rcv_orun;
+        unsigned long   Rcv_cdt;
+        unsigned long   Rcv_runt;
+        unsigned long   dump_status;    /* last field directly from the chip */
+} 
+ NICSTAT, *P_NICSTAT;
+
+#define DUMP_DONE   0x0000A005      /* completed statistical dump */
+#define DUMP_CLEAR  0x0000A007      /* completed stat dump and clear counters */
+
+
+static volatile int msgFlag;
+
+
+/* local function prototypes */
+static void ProcessOutboundAdapterMsg(PPAB pPab, U32 phyMsgAddr);
+static int FillAdapterMsgSGLFromTCB(PU32 pMsg, PRCTCB pXmitCntrlBlock);
+static int GetAdapterStatus(PPAB pPab);
+static int SendAdapterOutboundQInitMsg(PPAB pPab);
+static int SendEnableSysMsg(PPAB pPab);
+
+
+ /* 1st 100h bytes of message block is reserved for messenger instance */
+#define ADAPTER_BLOCK_RESERVED_SPACE 0x100
+
+/*
+** =========================================================================
+** InitRCApiMsgLayer()
+**
+** Initialize the RedCreek API Module and adapter.
+**
+** Inputs:  AdapterID - interface number from 0 to 15
+**          pciBaseAddr - virual base address of PCI (set by BIOS)
+**          p_msgbuf - virual address to private message block (min. 16K)
+**          p_phymsgbuf - physical address of private message block
+**          TransmitCallbackFunction - address of transmit callback function
+**          ReceiveCallbackFunction  - address of receive  callback function
+**
+** private message block is allocated by user.  It must be in locked pages.
+** p_msgbuf and p_phymsgbuf point to the same location.  Must be contigous
+** memory block of a minimum of 16K byte and long word aligned.
+** =========================================================================
+*/
+RC_RETURN
+InitRCApiMsgLayer(U16 AdapterID, U32 pciBaseAddr, 
+                  PU8 p_msgbuf,  PU8 p_phymsgbuf,
+                  PFNTXCALLBACK  TransmitCallbackFunction,
+                  PFNRXCALLBACK  ReceiveCallbackFunction,
+                  PFNCALLBACK    RebootCallbackFunction)
+{
+     int result;
+     PPAB pPab; 
+    
+#ifdef DEBUG
+     kprintf("InitAPI: Adapter:0x%04.4ux ATU:0x%08.8ulx msgbuf:0x%08.8ulx phymsgbuf:0x%08.8ulx\n"
+             "TransmitCallbackFunction:0x%08.8ulx  ReceiveCallbackFunction:0x%08.8ulx\n",
+             AdapterID, pciBaseAddr, p_msgbuf, p_phymsgbuf, TransmitCallbackFunction, ReceiveCallbackFunction);
+#endif /* DEBUG */
+
+    
+     /* Check if this interface already initialized - if so, shut it down */
+     if (PCIAdapterBlock[AdapterID] != NULL)
+     {
+          printk("PCIAdapterBlock[%d]!=NULL\n", AdapterID);
+//        RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+          PCIAdapterBlock[AdapterID] = NULL;
+     }
+
+    /* 
+    ** store adapter instance values in adapter block.
+    ** Adapter block is at beginning of message buffer
+    */  
+    pPab = (PPAB)p_msgbuf;
+    
+    pPab->p_atu = (PATU)pciBaseAddr;
+    pPab->pPci45LinBaseAddr =  (PU8)pciBaseAddr;
+    
+     /* Set outbound message frame addr - skip over Adapter Block */
+    pPab->outMsgBlockPhyAddr = (U32)(p_phymsgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+    pPab->pLinOutMsgBlock    = (PU8)(p_msgbuf + ADAPTER_BLOCK_RESERVED_SPACE);
+
+     /* store callback function addresses */
+    pPab->pTransCallbackFunc = TransmitCallbackFunction;
+    pPab->pRecvCallbackFunc  = ReceiveCallbackFunction;
+    pPab->pRebootCallbackFunc  = RebootCallbackFunction;
+    pPab->pCallbackFunc  = (PFNCALLBACK)NULL;
+
+    /*
+    ** Initialize API 
+    */
+    result = GetAdapterStatus(pPab);
+    
+    if (result != RC_RTN_NO_ERROR)
+        return result;
+
+    if (pPab->ADAPTERState == ADAPTER_STATE_OPERATIONAL)
+    {
+         printk("pPab->ADAPTERState == op: resetting adapter\n");
+         RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL);
+    }
+        
+    result = SendAdapterOutboundQInitMsg(pPab);
+    
+    if (result != RC_RTN_NO_ERROR)
+         return result;
+
+    result = SendEnableSysMsg(pPab);
+   
+    if (result != RC_RTN_NO_ERROR)
+         return result;
+   
+    PCIAdapterBlock[AdapterID] = pPab;
+    return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** Disable and Enable Adapter interrupts.  Adapter interrupts are enabled at Init time
+** but can be disabled and re-enabled through these two function calls.
+** Packets will still be put into any posted received buffers and packets will
+** be sent through RCSendPacket() functions.  Disabling Adapter interrupts
+** will prevent hardware interrupt to host even though the outbound Adapter msg
+** queue is not emtpy.
+** =========================================================================
+*/
+#define i960_OUT_POST_Q_INT_BIT        0x0008 /* bit set masks interrupts */
+
+RC_RETURN RCDisableAdapterInterrupts(U16 AdapterID)
+{
+    PPAB pPab;
+
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+        
+    pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT;
+
+    return RC_RTN_NO_ERROR;
+}
+
+RC_RETURN RCEnableAdapterInterrupts(U16 AdapterID)
+{
+    PPAB pPab;
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+         return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT;
+    
+    return RC_RTN_NO_ERROR;
+
+}
+
+
+/*
+** =========================================================================
+** RCSendPacket()
+** =========================================================================
+*/
+RC_RETURN
+RCSendPacket(U16 AdapterID, U32 InitiatorContext, PRCTCB pTransCtrlBlock)
+{
+    U32 msgOffset;
+    PU32 pMsg;
+    int size;
+    PPAB pPab;
+
+#ifdef DEBUG
+kprintf("RCSendPacket()...\n");
+#endif /* DEBUG */
+    
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+     /* get Inbound free Q entry - reading from In Q gets free Q entry */
+     /* offset to Msg Frame in PCI msg block */
+
+    msgOffset = pPab->p_atu->InQueue; 
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("RCSendPacket(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+        
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+    size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+    if (size == -1) /* error processing TCB - send NOP msg */
+    {
+#ifdef DEBUG
+            kprintf("RCSendPacket(): Error Rrocess TCB!\n");
+#endif /* DEBUG */
+        pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+        pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+        return RC_RTN_TCB_ERROR;
+    }
+    else /* send over msg header */
+    {    
+        pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+        pMsg[1] = LAN_PACKET_SEND << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+        pMsg[2] = InitiatorContext;
+        pMsg[3] = 0;  /* batch reply */
+         /* post to Inbound Post Q */   
+        pPab->p_atu->InQueue = msgOffset;
+        return RC_RTN_NO_ERROR;
+    }
+}
+
+/*
+** =========================================================================
+** RCPostRecvBuffer()
+**
+** inputs:  pBufrCntrlBlock - pointer to buffer control block
+**
+** returns TRUE if successful in sending message, else FALSE.
+** =========================================================================
+*/
+RC_RETURN
+RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransCtrlBlock)
+{
+    U32 msgOffset;
+    PU32 pMsg;
+    int size;
+    PPAB pPab;
+
+#ifdef DEBUG
+kprintf("RCPostRecvBuffers()...\n");
+#endif /* DEBUG */
+    
+     /* search for DeviceHandle */
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+
+     /* get Inbound free Q entry - reading from In Q gets free Q entry */
+     /* offset to Msg Frame in PCI msg block */
+    msgOffset = pPab->p_atu->InQueue; 
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+            kprintf("RCPostRecvBuffers(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+   
+    }
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+    size = FillAdapterMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock);
+
+    if (size == -1) /* error prcessing TCB - send 3 DWORD private msg == NOP */
+    {
+#ifdef DEBUG
+        kprintf("RCPostRecvBuffers(): Error Processing TCB! size = %d\n", size);
+#endif /* DEBUG */
+        pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
+        pMsg[1] = UTIL_NOP << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+         /* post to Post Q */   
+        pPab->p_atu->InQueue = msgOffset;
+        return RC_RTN_TCB_ERROR;
+    }
+    else /* send over size msg header */
+    {    
+        pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
+        pMsg[1] = LAN_RECEIVE_POST << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+        pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+        pMsg[3] = *(PU32)pTransCtrlBlock; /* number of packet buffers */
+         /* post to Post Q */   
+        pPab->p_atu->InQueue = msgOffset;
+        return RC_RTN_NO_ERROR;
+    }
+}
+
+
+/*
+** =========================================================================
+** RCProcMsgQ()
+**
+** Process outbound message queue until empty.
+** =========================================================================
+*/
+void 
+RCProcMsgQ(U16 AdapterID)
+{
+    U32 phyAddrMsg;
+    PU8 p8Msg;
+    PU32 p32;
+    U16 count;
+    PPAB pPab;
+    unsigned char debug_msg[20];
+    
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return;
+    
+    phyAddrMsg = pPab->p_atu->OutQueue;
+
+    while (phyAddrMsg != 0xFFFFFFFF)
+    {
+        p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+        p32 = (PU32)p8Msg;
+        
+        //printk(" msg: 0x%x  0x%x \n", p8Msg[7], p32[5]);
+
+     /* 
+     ** Send Packet Reply Msg
+     */
+        if (LAN_PACKET_SEND == p8Msg[7])  /* function code byte */
+        {
+            count = *(PU16)(p8Msg+2);
+            count -= p8Msg[0] >> 4;
+                                      /* status, count, context[], adapter */
+           (*pPab->pTransCallbackFunc)(p8Msg[19], count, p32+5, AdapterID);
+        }             
+     /* 
+     ** Receive Packet Reply Msg */
+        else if (LAN_RECEIVE_POST == p8Msg[7])
+        {
+#ifdef DEBUG    
+    kprintf("RECV_REPLY pPab:0x%08.8ulx p8Msg:0x%08.8ulx p32:0x%08.8ulx\n", pPab, p8Msg, p32);
+    kprintf("msg: 0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+            p32[0], p32[1], p32[2], p32[3]);
+    kprintf("     0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+            p32[4], p32[5], p32[6], p32[7]);
+    kprintf("     0x%08.8ulx:0X%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+            p32[8], p32[9], p32[10], p32[11]);
+#endif
+               /*  status, count, buckets remaining, packetParmBlock, adapter */
+          (*pPab->pRecvCallbackFunc)(p8Msg[19], p8Msg[12], p32[5], p32+6, AdapterID);
+      
+      
+        }
+        else if (LAN_RESET == p8Msg[7] || LAN_SHUTDOWN == p8Msg[7])
+        {
+            if (pPab->pCallbackFunc)
+            {
+                (*pPab->pCallbackFunc)(p8Msg[19],0,0,AdapterID);
+            }
+            else
+            {
+                pPab->pCallbackFunc = (PFNCALLBACK) 1;
+            }
+            //PCIAdapterBlock[AdapterID] = 0;
+        }
+        else if (RC_PRIVATE == p8Msg[7])
+        {
+            //printk("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]);
+          switch (p32[5])
+          {
+          case RC_PRIVATE_DEBUG_MSG:
+               msgFlag = 1;
+               /*printk("Received RC_PRIVATE msg\n");*/
+               debug_msg[15]  = (p32[6]&0xff000000) >> 24;
+               debug_msg[14]  = (p32[6]&0x00ff0000) >> 16;
+               debug_msg[13]  = (p32[6]&0x0000ff00) >> 8;
+               debug_msg[12]  = (p32[6]&0x000000ff);
+
+               debug_msg[11]  = (p32[7]&0xff000000) >> 24;
+               debug_msg[10]  = (p32[7]&0x00ff0000) >> 16;
+               debug_msg[ 9]  = (p32[7]&0x0000ff00) >> 8;
+               debug_msg[ 8]  = (p32[7]&0x000000ff);
+
+               debug_msg[ 7]  = (p32[8]&0xff000000) >> 24;
+               debug_msg[ 6]  = (p32[8]&0x00ff0000) >> 16;
+               debug_msg[ 5] = (p32[8]&0x0000ff00) >> 8;
+               debug_msg[ 4] = (p32[8]&0x000000ff);
+
+               debug_msg[ 3] = (p32[9]&0xff000000) >> 24;
+               debug_msg[ 2] = (p32[9]&0x00ff0000) >> 16;
+               debug_msg[ 1] = (p32[9]&0x0000ff00) >> 8;
+               debug_msg[ 0] = (p32[9]&0x000000ff);
+
+               debug_msg[16] = '\0';
+               printk (debug_msg);
+               break;
+          case RC_PRIVATE_REBOOT:
+               printk("Adapter reboot initiated...\n");
+               if (pPab->pRebootCallbackFunc)
+               {
+                    (*pPab->pRebootCallbackFunc)(0,0,0,AdapterID);
+               }
+               break;
+          default:
+                printk("Unknown private msg received: 0x%x\n",
+                      p32[5]);
+               break;
+          }
+        }
+
+     /* 
+     ** Process other Msg's
+     */
+        else
+        {
+            ProcessOutboundAdapterMsg(pPab, phyAddrMsg);
+        }
+        
+         /* return MFA to outbound free Q*/
+        pPab->p_atu->OutQueue = phyAddrMsg;
+    
+         /* any more msgs? */
+        phyAddrMsg = pPab->p_atu->OutQueue;
+    }
+}
+
+
+/*
+** =========================================================================
+**  Returns LAN interface statistical counters to space provided by caller at
+**  StatsReturnAddr.  Returns 0 if success, else RC_RETURN code.
+**  This function will call the WaitCallback function provided by
+**  user while waiting for card to respond.
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatistics(U16 AdapterID, 
+                    P_RCLINKSTATS StatsReturnAddr,
+                    PFNWAITCALLBACK WaitCallback)
+{
+    U32 msgOffset;
+    volatile U32 timeout;
+    volatile PU32 pMsg;
+    volatile PU32 p32, pReturnAddr;
+    P_NICSTAT pStats;
+    int i;
+    PPAB pPab;
+
+/*kprintf("Get82558Stats() StatsReturnAddr:0x%08.8ulx\n", StatsReturnAddr);*/
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+    #ifdef DEBUG
+        kprintf("Get8255XStats(): Inbound Free Q empty!\n");
+    #endif
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+/*dprintf("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x112; /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LAN_STATS;
+    pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+
+    pStats = (P_NICSTAT)p32;
+    pStats->dump_status = 0xFFFFFFFF;
+
+     /* post to Inbound Post Q */
+    pPab->p_atu->InQueue = msgOffset;
+
+    timeout = 100000;
+    while (1)
+    {
+        if (WaitCallback)
+                (*WaitCallback)();
+        
+        for (i = 0; i < 1000; i++)
+            ;
+
+        if (pStats->dump_status != 0xFFFFFFFF)
+            break;
+
+        if (!timeout--)
+        {
+        #ifdef DEBUG
+            kprintf("RCGet82558Stats() Timeout waiting for NIC statistics\n");
+        #endif
+            return RC_RTN_MSG_REPLY_TIMEOUT;
+        }
+    }
+    
+    pReturnAddr = (PU32)StatsReturnAddr;
+    
+     /* copy Nic stats to user's structure */
+    for (i = 0; i < (int) sizeof(RCLINKSTATS) / 4; i++)
+        pReturnAddr[i] = p32[i];
+   
+    return RC_RTN_NO_ERROR;     
+}
+
+
+/*
+** =========================================================================
+** Get82558LinkStatus()
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkStatus(U16 AdapterID, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback)
+{
+    U32 msgOffset;
+    volatile U32 timeout;
+    volatile PU32 pMsg;
+    volatile PU32 p32;
+    PPAB pPab;
+
+/*kprintf("Get82558LinkStatus() ReturnPhysAddr:0x%08.8ulx\n", ReturnAddr);*/
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+    #ifdef DEBUG
+        dprintf("Get82558LinkStatus(): Inbound Free Q empty!\n");
+    #endif
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
+/*dprintf("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
+
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x112; /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS;
+    pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    *p32 = 0xFFFFFFFF;
+    
+     /* post to Inbound Post Q */
+    pPab->p_atu->InQueue = msgOffset;
+
+    timeout = 100000;
+    while (1)
+    {
+        U32 i;
+
+        if (WaitCallback)
+                (*WaitCallback)();
+        
+        for (i = 0; i < 1000; i++)
+            ;
+
+        if (*p32 != 0xFFFFFFFF)
+            break;
+
+        if (!timeout--)
+        {
+        #ifdef DEBUG
+            kprintf("Timeout waiting for link status\n");
+        #endif    
+            return RC_RTN_MSG_REPLY_TIMEOUT;
+        }
+    }
+    
+    *ReturnAddr = *p32; /* 1 = up 0 = down */
+    
+    return RC_RTN_NO_ERROR;
+    
+}
+
+/*
+** =========================================================================
+** RCGetMAC()
+**
+** get the MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback)
+{
+     unsigned i, timeout;
+     U32      off;
+     PU32     p;
+     U32      temp[2];
+     PPAB     pPab;
+     PATU     p_atu;
+    
+     pPab = PCIAdapterBlock[AdapterID];
+    
+     if (pPab == NULL)
+          return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+     p_atu = pPab->p_atu;
+
+     p_atu->EtherMacLow = 0;     /* first zero return data */
+     p_atu->EtherMacHi = 0;
+    
+     off = p_atu->InQueue;   /* get addresss of message */
+     if (0xFFFFFFFF == off)
+          return RC_RTN_FREE_Q_EMPTY;
+
+     p = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+#ifdef RCDEBUG
+     printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", 
+            (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+     /* setup private message */
+     p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+     p[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+     p[2] = 0;               /* initiator context */
+     p[3] = 0x218;           /* transaction context */
+     p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR;
+
+
+     p_atu->InQueue = off;   /* send it to the device */
+#ifdef RCDEBUG
+     printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", 
+            (uint)p_atu, (uint)off, (uint)p);
+#endif /* RCDEBUG */
+
+     /* wait for the rcpci45 board to update the info */
+     timeout = 1000000;
+     while (0 == p_atu->EtherMacLow) 
+     {
+          if (WaitCallback)
+               (*WaitCallback)();
+    
+          for (i = 0; i < 1000; i++)
+               ;
+
+          if (!timeout--)
+          {
+               printk("rc_getmac: Timeout\n");
+               return RC_RTN_MSG_REPLY_TIMEOUT;
+          }
+     }
+    
+     /* read the mac address  */
+     temp[0] = p_atu->EtherMacLow;
+     temp[1] = p_atu->EtherMacHi;
+     memcpy((char *)mac, (char *)temp, 6);
+
+
+#ifdef RCDEBUG
+//    printk("rc_getmac: 0x%X\n", ptr);
+#endif /* RCDEBUG */
+
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCSetMAC()
+**
+** set MAC address the adapter is listening for in non-promiscous mode.
+** MAC address is in media format.
+** =========================================================================
+*/
+RC_RETURN
+RCSetMAC(U16 AdapterID, PU8 mac)
+{
+    U32  off;
+    PU32 pMsg;
+    PPAB pPab;
+
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR;
+    pMsg[5] = *(unsigned *)mac;  /* first four bytes */
+    pMsg[6] = *(unsigned *)(mac + 4); /* last two bytes */
+    
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================
+** RCSetLinkSpeed()
+**
+** set ethernet link speed. 
+** input: speedControl - determines action to take as follows
+**          0 = reset and auto-negotiate (NWay)
+**          1 = Full Duplex 100BaseT
+**          2 = Half duplex 100BaseT
+**          3 = Full Duplex  10BaseT
+**          4 = Half duplex  10BaseT
+**          all other values are ignore (do nothing)
+** =========================================================================
+*/
+RC_RETURN
+RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode)
+{
+    U32  off;
+    PU32 pMsg;
+    PPAB pPab;
+
+    
+    pPab =PCIAdapterBlock[AdapterID];
+     
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED;
+    pMsg[5] = LinkSpeedCode;     /* link speed code */
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    return RC_RTN_NO_ERROR ;
+}
+
+/*
+** =========================================================================
+** RCGetLinkSpeed()
+**
+** get ethernet link speed. 
+**
+** 0 = Unknown
+** 1 = Full Duplex 100BaseT
+** 2 = Half duplex 100BaseT
+** 3 = Full Duplex  10BaseT
+** 4 = Half duplex  10BaseT
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback)
+{
+     U32 msgOffset, timeout;
+     PU32 pMsg;
+     volatile PU32 p32;
+     U8 AdapterLinkSpeed;
+     PPAB pPab;
+
+     pPab =PCIAdapterBlock[AdapterID];
+
+
+     msgOffset = pPab->p_atu->InQueue;
+
+
+     if (msgOffset == 0xFFFFFFFF)
+     {
+          kprintf("RCGetLinkSpeed(): Inbound Free Q empty!\n");
+          return RC_RTN_FREE_Q_EMPTY;
+     }
+
+     /* calc virtual address of msg - virtual already mapped to physical */    
+     pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+     /* virtual pointer to return buffer - clear first two dwords */
+     p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+     p32[0] = 0xff;
+
+     /* setup private message */
+     pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+     pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+     pMsg[2] = 0;                 /* initiator context */
+     pMsg[3] = 0x219;             /* transaction context */
+     pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED;
+     /* phys address to return status - area right after PAB */
+     pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+   
+     /* post to Inbound Post Q */   
+
+     pPab->p_atu->InQueue = msgOffset;
+
+     /* wait for response */
+     timeout = 1000000;
+     while(1)
+     {
+          int i;
+        
+          if (WaitCallback)
+                (*WaitCallback)();
+
+          for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+               ;
+            
+          if (p32[0] != 0xff)
+               break;
+            
+          if (!timeout--)
+          {
+               kprintf("Timeout waiting for link speed from adapter\n");
+               kprintf("0x%08.8ulx\n", p32[0]);
+               return RC_RTN_NO_LINK_SPEED;
+          }
+     }
+
+     /* get Link speed */
+     AdapterLinkSpeed = (U8)((volatile PU8)p32)[0] & 0x0f;
+
+     *pLinkSpeedCode= AdapterLinkSpeed;
+
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCReportDriverCapability(U16 AdapterID, U32 capability)
+**
+** Currently defined bits:
+** WARM_REBOOT_CAPABLE   0x01
+**
+** =========================================================================
+*/
+RC_RETURN
+RCReportDriverCapability(U16 AdapterID, U32 capability)
+{
+    U32  off;
+    PU32 pMsg;
+    PPAB pPab;
+
+    pPab =PCIAdapterBlock[AdapterID];
+     
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY;
+    pMsg[5] = capability;
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    return RC_RTN_NO_ERROR ;
+}
+
+/*
+** =========================================================================
+** RCGetFirmwareVer()
+**
+** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
+**
+** =========================================================================
+*/
+RC_RETURN
+RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback)
+{
+     U32 msgOffset, timeout;
+     PU32 pMsg;
+     volatile PU32 p32;
+     PPAB pPab;
+
+     pPab =PCIAdapterBlock[AdapterID];
+
+     msgOffset = pPab->p_atu->InQueue;
+
+
+     if (msgOffset == 0xFFFFFFFF)
+     {
+          kprintf("RCGetFirmwareVer(): Inbound Free Q empty!\n");
+          return RC_RTN_FREE_Q_EMPTY;
+     }
+
+     /* calc virtual address of msg - virtual already mapped to physical */    
+     pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+     /* virtual pointer to return buffer - clear first two dwords */
+     p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+     p32[0] = 0xff;
+
+     /* setup private message */
+     pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
+     pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+     pMsg[2] = 0;                 /* initiator context */
+     pMsg[3] = 0x219;             /* transaction context */
+     pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV;
+     /* phys address to return status - area right after PAB */
+     pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+
+   
+     /* post to Inbound Post Q */   
+
+     pPab->p_atu->InQueue = msgOffset;
+
+    
+     /* wait for response */
+     timeout = 1000000;
+     while(1)
+     {
+          int i;
+        
+          if (WaitCallback)
+                (*WaitCallback)();
+            
+          for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+               ;
+
+          if (p32[0] != 0xff)
+               break;
+            
+          if (!timeout--)
+          {
+               kprintf("Timeout waiting for link speed from adapter\n");
+               return RC_RTN_NO_FIRM_VER;
+          }
+     }
+
+     strcpy(pFirmString, (PU8)p32);
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCResetLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when 
+** reset is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** reset is done (if not NULL).
+**
+** =========================================================================
+*/
+RC_RETURN 
+RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+    unsigned long off;
+    unsigned long *pMsg;
+    PPAB pPab;
+    int i;
+    long timeout = 0;
+
+    
+    pPab =PCIAdapterBlock[AdapterID];
+     
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pPab->pCallbackFunc = CallbackFunction;
+
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup message */
+    pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = LAN_RESET << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = ResourceFlags << 16;   /* resource flags */
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    if (CallbackFunction == (PFNCALLBACK)NULL)
+    {
+        /* call RCProcMsgQ() until something in pPab->pCallbackFunc
+           or until timer goes off */
+        while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+        {
+            RCProcMsgQ(AdapterID);
+            for (i = 0; i < 100000; i++)     /* please don't hog the bus!!! */
+               ;
+            timeout++;
+            if (timeout > 10000)
+            {
+                break;
+            }
+        }
+        if (ReturnAddr != (PU32)NULL)
+           *ReturnAddr = (U32)pPab->pCallbackFunc;
+    }
+
+    return RC_RTN_NO_ERROR ;
+}
+/*
+** =========================================================================
+** RCResetAdapter()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.
+**
+** =========================================================================
+*/
+RC_RETURN 
+RCResetAdapter(U16 AdapterID)
+{
+     U32 msgOffset, timeout;
+     PU32 pMsg;
+     PPAB pPab;
+     volatile PU32 p32;
+    
+     pPab = PCIAdapterBlock[AdapterID];
+     msgOffset = pPab->p_atu->InQueue;
+
+     if (msgOffset == 0xFFFFFFFF)
+     {
+          return RC_RTN_FREE_Q_EMPTY;
+     }
+
+     /* calc virtual address of msg - virtual already mapped to physical */    
+     pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+     pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+     pMsg[1] = RC_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 | ADAPTER_TID;
+     pMsg[2] = 0; /* universal context */
+     pMsg[3] = 0; /* universal context */
+     pMsg[4] = 0; /* universal context */
+     pMsg[5] = 0; /* universal context */
+     /* phys address to return status - area right after PAB */
+     pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+     pMsg[7] = 0;
+     pMsg[8] = 1;  /*  return 1 byte */
+
+     /* virual pointer to return buffer - clear first two dwords */
+     p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+     p32[0] = 0;
+     p32[1] = 0;
+
+     /* post to Inbound Post Q */   
+
+     pPab->p_atu->InQueue = msgOffset;
+
+     /* wait for response */
+     timeout = 1000000;
+     while(1)
+     {
+          int i;
+        
+          for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+               ;
+            
+          if (p32[0] || p32[1])
+               break;
+            
+          if (!timeout--)
+          {
+               printk("RCResetAdapter timeout\n");
+               return RC_RTN_MSG_REPLY_TIMEOUT;
+          }
+     }
+     return RC_RTN_NO_ERROR;
+}
+
+/*
+** =========================================================================
+** RCShutdownLANCard()
+**
+** ResourceFlags indicates whether to return buffer resource explicitly
+** to host or keep and reuse.
+** CallbackFunction (if not NULL) is the function to be called when 
+** shutdown is complete.
+** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
+** shutdown is done (if not NULL).
+**
+** =========================================================================
+*/
+RC_RETURN 
+RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
+{
+    volatile PU32 pMsg;
+    U32 off;
+    PPAB pPab;
+    int i;
+    long timeout = 0;
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+
+    pPab->pCallbackFunc = CallbackFunction;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup message */
+    pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = LAN_SHUTDOWN << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = ResourceFlags << 16;   /* resource flags */
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+
+    if (CallbackFunction == (PFNCALLBACK)NULL)
+    {
+        /* call RCProcMsgQ() until something in pPab->pCallbackFunc
+           or until timer goes off */
+        while (pPab->pCallbackFunc == (PFNCALLBACK)NULL)
+        {
+            RCProcMsgQ(AdapterID);
+            for (i = 0; i < 100000; i++)     /* please don't hog the bus!!! */
+               ;
+            timeout++;
+            if (timeout > 10000)
+            {
+                break;
+            }
+        }
+        if (ReturnAddr != (PU32)NULL)
+           *ReturnAddr = (U32)pPab->pCallbackFunc;
+    }
+    return RC_RTN_NO_ERROR ;
+}
+
+
+/*
+** =========================================================================
+** RCSetRavlinIPandMask()
+**
+** Set the Ravlin 45/PCI cards IP address and network mask.
+**
+** IP address and mask must be in network byte order.
+** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
+** 0x04030201 and 0x00FFFFFF on a little endian machine.
+**
+** =========================================================================
+*/
+RC_RETURN
+RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask)
+{
+    volatile PU32 pMsg;
+    U32 off;
+    PPAB pPab;
+
+    pPab = PCIAdapterBlock[AdapterID];
+
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+
+    off = pPab->p_atu->InQueue; /* get addresss of message */
+    
+    if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+    /* setup private message */
+    pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;                 /* initiator context */
+    pMsg[3] = 0x219;             /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK;
+    pMsg[5] = ipAddr; 
+    pMsg[6] = netMask;
+
+
+    pPab->p_atu->InQueue = off;   /* send it to the device */
+    return RC_RTN_NO_ERROR ;
+
+}
+
+/*
+** =========================================================================
+** RCGetRavlinIPandMask()
+**
+** get the IP address and MASK from the card
+** 
+** =========================================================================
+*/
+RC_RETURN
+RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask, 
+                        PFNWAITCALLBACK WaitCallback)
+{
+    unsigned i, timeout;
+    U32      off;
+    PU32     pMsg, p32;
+    PPAB     pPab;
+    PATU     p_atu;
+    
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
+#endif /* DEBUG */
+
+    pPab = PCIAdapterBlock[AdapterID];
+    
+    if (pPab == NULL)
+        return RC_RTN_ADPTR_NOT_REGISTERED;
+    
+    p_atu = pPab->p_atu;
+    off = p_atu->InQueue;   /* get addresss of message */
+   if (0xFFFFFFFF == off)
+         return RC_RTN_FREE_Q_EMPTY;
+
+    p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    *p32 = 0xFFFFFFFF;
+
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + off);
+
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
+#endif /* DEBUG */
+    /* setup private message */
+    pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_PRIVATE << 24 | HOST_TID << 12 | LAN_TARGET_ID;
+    pMsg[2] = 0;               /* initiator context */
+    pMsg[3] = 0x218;           /* transaction context */
+    pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK;
+    pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p_atu->InQueue = off;   /* send it to the device */
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32);
+#endif /* DEBUG */
+
+     /* wait for the rcpci45 board to update the info */
+    timeout = 100000;
+    while (0xffffffff == *p32)
+    {
+        if (WaitCallback)
+                (*WaitCallback)();
+    
+        for (i = 0; i < 1000; i++)
+            ;
+
+        if (!timeout--)
+        {
+        #ifdef DEBUG
+            kprintf("RCGetRavlinIPandMask: Timeout\n");
+        #endif /* DEBUG */
+             return RC_RTN_MSG_REPLY_TIMEOUT;
+        }
+    }
+
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: after time out\n", \
+            "p32[0] (IpAddr) 0x%08.8ulx, p32[1] (IPmask) 0x%08.8ulx\n", p32[0], p32[1]);
+#endif /* DEBUG */
+    
+    /* send IP and mask to user's space  */
+    *pIpAddr  = p32[0];
+    *pNetMask = p32[1];
+
+
+#ifdef DEBUG
+    kprintf("RCGetRavlinIPandMask: pIpAddr is 0x%08.8ulx, *IpAddr is 0x%08.8ulx\n", pIpAddr, *pIpAddr);
+#endif /* DEBUG */
+
+    return RC_RTN_NO_ERROR;
+}
+
+/* 
+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+**
+**                        local functions
+**
+** /////////////////////////////////////////////////////////////////////////
+** /////////////////////////////////////////////////////////////////////////
+*/
+
+/*
+** =========================================================================
+** SendAdapterOutboundQInitMsg()
+**
+** =========================================================================
+*/
+static int 
+SendAdapterOutboundQInitMsg(PPAB pPab)
+{
+    U32 msgOffset, timeout, phyOutQFrames, i;
+    volatile PU32 pMsg;
+    volatile PU32 p32;
+    
+    
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("SendAdapterOutboundQInitMsg(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+    
+    
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+#ifdef DEBUG
+kprintf("SendAdapterOutboundQInitMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
+#endif /* DEBUG */
+
+    pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6;
+    pMsg[1] = RC_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x106; /* transaction context */
+    pMsg[4] = 4096; /* Host page frame size */
+    pMsg[5] = MSG_FRAME_SIZE  << 16 | 0x80; /* outbound msg frame size and Initcode */
+    pMsg[6] = 0xD0000004;       /* simple sgl element LE, EOB */
+     /* phys address to return status - area right after PAB */
+    pMsg[7] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+     /* virual pointer to return buffer - clear first two dwords */
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    p32[0] = 0;
+    
+     /* post to Inbound Post Q */   
+    pPab->p_atu->InQueue = msgOffset;
+    
+  /* wait for response */
+    timeout = 100000;
+    while(1)
+    {
+        for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+            ;
+            
+        if (p32[0])
+            break;
+            
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout wait for InitOutQ InPrgress status from adapter\n");
+#endif /* DEBUG */
+            return RC_RTN_NO_STATUS;
+        }
+    }
+
+    timeout = 100000;
+    while(1)
+    {
+        for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+            ;
+            
+        if (p32[0] == RC_CMD_OUTBOUND_INIT_COMPLETE)
+            break;
+
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout wait for InitOutQ Complete status from adapter\n");
+#endif /* DEBUG */
+            return RC_RTN_NO_STATUS;
+        }
+    }
+
+     /* load PCI outbound free Q with MF physical addresses */
+    phyOutQFrames = pPab->outMsgBlockPhyAddr;
+
+    for (i = 0; i < NMBR_MSG_FRAMES; i++)
+    {
+        pPab->p_atu->OutQueue = phyOutQFrames;
+        phyOutQFrames += MSG_FRAME_SIZE;
+    }
+    return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** GetAdapterStatus()
+**
+** Send StatusGet Msg, wait for results return directly to buffer.
+**
+** =========================================================================
+*/
+static int 
+GetAdapterStatus(PPAB pPab)
+{
+    U32 msgOffset, timeout;
+    PU32 pMsg;
+    volatile PU32 p32;
+    
+    
+    msgOffset = pPab->p_atu->InQueue; 
+    printk("GetAdapterStatus: msg offset = 0x%x\n", msgOffset);
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("GetAdapterStatus(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+    pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_CMD_STATUS_GET << 24 | HOST_TID << 12 | ADAPTER_TID;
+    pMsg[2] = 0; /* universal context */
+    pMsg[3] = 0; /* universal context */
+    pMsg[4] = 0; /* universal context */
+    pMsg[5] = 0; /* universal context */
+     /* phys address to return status - area right after PAB */
+    pMsg[6] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+    pMsg[7] = 0;
+    pMsg[8] = 88;  /*  return 88 bytes */
+
+     /* virual pointer to return buffer - clear first two dwords */
+    p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    p32[0] = 0;
+    p32[1] = 0;
+
+#ifdef DEBUG
+kprintf("GetAdapterStatus - pMsg:0x%08.8ulx, msgOffset:0x%08.8ulx, [1]:0x%08.8ulx, [6]:0x%08.8ulx\n",
+    pMsg, msgOffset, pMsg[1], pMsg[6]);
+#endif /* DEBUG */
+   
+     /* post to Inbound Post Q */   
+    pPab->p_atu->InQueue = msgOffset;
+    
+#ifdef DEBUG
+kprintf("Return status to p32 = 0x%08.8ulx\n", p32);
+#endif /* DEBUG */
+    
+     /* wait for response */
+    timeout = 1000000;
+    while(1)
+    {
+        int i;
+        
+        for (i = 0; i < 1000; i++)      /* please don't hog the bus!!! */
+            ;
+            
+        if (p32[0] && p32[1])
+            break;
+            
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout waiting for status from adapter\n");
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+            return RC_RTN_NO_STATUS;
+        }
+    }
+            
+#ifdef DEBUG
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]);
+#endif /* DEBUG */
+    /* get adapter state */
+    pPab->ADAPTERState = ((volatile PU8)p32)[10];
+    pPab->InboundMFrameSize  = ((volatile PU16)p32)[6];
+    
+#ifdef DEBUG
+    kprintf("adapter state 0x%02.2x InFrameSize = 0x%04.4x\n", 
+                        pPab->ADAPTERState, pPab->InboundMFrameSize);
+#endif /* DEBUG */
+    return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** SendEnableSysMsg()
+**
+**
+** =========================================================================
+*/
+static int 
+SendEnableSysMsg(PPAB pPab)
+{
+    U32 msgOffset; // timeout;
+    volatile PU32 pMsg;
+
+    msgOffset = pPab->p_atu->InQueue;
+
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("SendEnableSysMsg(): Inbound Free Q empty!\n");
+#endif /* DEBUG */
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+
+     /* calc virual address of msg - virual already mapped to physical */
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+#ifdef DEBUG
+kprintf("SendEnableSysMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
+#endif /* DEBUG */
+
+    pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
+    pMsg[1] = RC_CMD_SYS_ENABLE << 24 | HOST_TID << 12 | ADAPTER_TID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x110; /* transaction context */
+    pMsg[4] = 0x50657465; /*  RedCreek Private */
+
+     /* post to Inbound Post Q */
+    pPab->p_atu->InQueue = msgOffset;
+
+    return RC_RTN_NO_ERROR;
+}
+
+
+/*
+** =========================================================================
+** FillI12OMsgFromTCB()
+**
+** inputs   pMsgU32 - virual pointer (mapped to physical) of message frame
+**          pXmitCntrlBlock - pointer to caller buffer control block.
+**
+** fills in LAN SGL after Transaction Control Word or Bucket Count.
+** =========================================================================
+*/
+static int 
+FillAdapterMsgSGLFromTCB(PU32 pMsgFrame, PRCTCB pTransCtrlBlock)
+{
+    unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags;
+    PU32 pTCB, pMsg;
+
+ /* SGL element flags */   
+#define EOB        0x40000000
+#define LE         0x80000000
+#define SIMPLE_SGL 0x10000000
+#define BC_PRESENT 0x01000000
+
+    pTCB = (PU32)pTransCtrlBlock;
+    pMsg = pMsgFrame;
+    nmbrDwords = 0;
+
+#ifdef DEBUG
+ kprintf("FillAdapterMsgSGLFromTCBX\n");
+kprintf("TCB  0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n",
+               pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]);
+kprintf("pTCB 0x%08.8ulx, pMsg 0x%08.8ulx\n", pTCB, pMsg);
+#endif /* DEBUG */
+    
+    nmbrBuffers = *pTCB++;
+    
+    if (!nmbrBuffers)
+    {
+        return -1;
+    }
+
+    do
+    {
+        context = *pTCB++; /* buffer tag (context) */
+        nmbrSeg = *pTCB++; /* number of segments */
+
+        if (!nmbrSeg)
+        {
+            return -1;
+        }
+        
+        flags = SIMPLE_SGL | BC_PRESENT;
+
+        if (1 == nmbrSeg)
+        {
+            flags |= EOB;
+        
+            if (1 == nmbrBuffers)
+                flags |= LE;
+        }    
+
+         /* 1st SGL buffer element has context */
+        pMsg[0] = pTCB[0] | flags ; /* send over count (segment size) */
+        pMsg[1] = context;
+        pMsg[2] = pTCB[1]; /* send buffer segment physical address */
+        nmbrDwords += 3;
+        pMsg += 3;
+        pTCB += 2;
+
+        
+        if (--nmbrSeg)
+        {
+            do
+            {
+                flags = SIMPLE_SGL;
+                
+                if (1 == nmbrSeg)
+                {
+                    flags |= EOB;
+                
+                    if (1 == nmbrBuffers)
+                        flags |= LE;
+                }    
+                
+                pMsg[0] = pTCB[0] | flags;  /* send over count */
+                pMsg[1] = pTCB[1];   /* send buffer segment physical address */
+                nmbrDwords += 2;
+                pTCB += 2;
+                pMsg += 2;
+        
+            } while (--nmbrSeg);
+        }
+        
+    } while (--nmbrBuffers);
+    
+    return nmbrDwords;
+}
+
+
+/*
+** =========================================================================
+** ProcessOutboundAdapterMsg()
+**
+** process reply message
+** * change to msg structure *
+** =========================================================================
+*/
+static void 
+ProcessOutboundAdapterMsg(PPAB pPab, U32 phyAddrMsg)
+{
+    PU8 p8Msg;
+    PU32 p32;
+  //  U16 count;
+    
+    
+    p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
+    p32 = (PU32)p8Msg;
+    
+#ifdef DEBUG
+ kprintf("VXD: ProcessOutboundAdapterMsg - pPab 0x%08.8ulx, phyAdr 0x%08.8ulx, linAdr 0x%08.8ulx\n", pPab, phyAddrMsg, p8Msg);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[0], p32[1], p32[2], p32[3]);
+ kprintf("msg :0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[4], p32[5], p32[6], p32[7]);
+#endif /* DEBUG */
+
+    if (p32[4] >> 24 != RC_REPLY_STATUS_SUCCESS)
+    {
+#ifdef DEBUG
+        kprintf("Message reply status not success\n");
+#endif /* DEBUG */
+        return;
+    }
+    
+    switch (p8Msg[7] )  /* function code byte */
+    {
+        case RC_CMD_SYS_TAB_SET:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_SYS_TAB_SET reply\n");
+#endif /* DEBUG */
+            break;
+
+        case RC_CMD_HRT_GET:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_HRT_GET reply\n");
+#endif /* DEBUG */
+            break;
+        
+        case RC_CMD_LCT_NOTIFY:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_LCT_NOTIFY reply\n");
+#endif /* DEBUG */
+            break;
+        
+        case RC_CMD_SYS_ENABLE:
+            msgFlag = 1;
+#ifdef DEBUG
+        kprintf("Received RC_CMD_SYS_ENABLE reply\n");
+#endif /* DEBUG */
+            break;
+
+        default:    
+#ifdef DEBUG
+        kprintf("Received UNKNOWN reply\n");
+#endif /* DEBUG */
+            break;
+    }
+}
diff --git a/drivers/net/rcmtl.h b/drivers/net/rcmtl.h
new file mode 100644 (file)
index 0000000..cfd14e0
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+** *************************************************************************
+**
+**
+**     R C M T L . H             $Revision: 3 $
+**
+**
+**  RedCreek Message Transport Layer header file.
+**
+**  ---------------------------------------------------------------------
+**  ---     Copyright (c) 1997-1998, RedCreek Communications Inc.     ---
+**  ---                   All rights reserved.                        ---
+**  ---------------------------------------------------------------------
+**
+**  File Description:
+**
+**  Header file for host message transport layer API and data types.
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** *************************************************************************
+*/
+
+#ifndef RCMTL_H
+#define RCMTL_H
+
+/* Linux specific includes */
+#define kprintf printk
+#ifdef RC_LINUX_MODULE     /* linux modules need non-library version of string functions */
+#include <linux/string.h>
+#else
+#include <string.h>
+#endif
+
+/* PCI/45 Configuration space values */
+#define RC_PCI45_VENDOR_ID  0x4916
+#define RC_PCI45_DEVICE_ID  0x1960
+
+
+ /* RedCreek API function return values */
+#define RC_RTN_NO_ERROR             0
+#define RC_RTN_NOT_INIT             1
+#define RC_RTN_FREE_Q_EMPTY         2
+#define RC_RTN_TCB_ERROR            3
+#define RC_RTN_TRANSACTION_ERROR    4
+#define RC_RTN_ADAPTER_ALREADY_INIT 5
+#define RC_RTN_MALLOC_ERROR         6
+#define RC_RTN_ADPTR_NOT_REGISTERED 7
+#define RC_RTN_MSG_REPLY_TIMEOUT    8
+#define RC_RTN_NO_STATUS            9
+#define RC_RTN_NO_FIRM_VER         10
+#define RC_RTN_NO_LINK_SPEED       11
+
+/* Driver capability flags */
+#define WARM_REBOOT_CAPABLE      0x01
+
+ /* scalar data types */
+typedef unsigned char   U8;
+typedef unsigned char*  PU8;
+typedef unsigned short  U16;
+typedef unsigned short* PU16;
+typedef unsigned long   U32;
+typedef unsigned long*  PU32;
+typedef unsigned long   BF;
+typedef int             RC_RETURN;
+
+
+ /* 
+ ** type PFNWAITCALLBACK
+ **
+ ** pointer to void function - type used for WaitCallback in some functions 
+ */
+typedef void (*PFNWAITCALLBACK)(void);  /* void argument avoids compiler complaint */
+
+ /*
+ ** type PFNTXCALLBACK 
+ **
+ ** Pointer to user's transmit callback function.  This user function is
+ ** called from RCProcMsgQ() when packet have been transmitted from buffers
+ ** given in the RCSendPacket() function.  BufferContext is a pointer to
+ ** an array of 32 bit context values.  These are the values the user assigned
+ ** and passed in the TCB to the RCSendPacket() function.  PcktCount
+ ** indicates the number of buffer context values in the BufferContext[] array.
+ ** The User's TransmitCallbackFunction should recover (put back in free queue)
+ ** the packet buffers associated with the buffer context values.
+ */
+typedef void (*PFNTXCALLBACK)(U32  Status,
+                              U16  PcktCount,
+                              PU32 BufferContext,
+                              U16  AdaterID);
+
+ /* 
+ ** type PFNRXCALLBACK 
+ **
+ ** Pointer to user's receive callback function.  This user function
+ ** is called from RCProcMsgQ() when packets have been received into
+ ** previously posted packet buffers throught the RCPostRecvBuffers() function.
+ ** The received callback function should process the Packet Descriptor Block
+ ** pointed to by PacketDescBlock. See Packet Decription Block below.
+ */
+typedef void (*PFNRXCALLBACK)(U32  Status,
+                              U8   PktCount,
+                              U32  BucketsRemain,
+                              PU32 PacketDescBlock,
+                              U16  AdapterID);
+
+ /* 
+ ** type PFNCALLBACK 
+ **
+ ** Pointer to user's generic callback function.  This user function
+ ** can be passed to LANReset or LANShutdown and is called when the 
+ ** the reset or shutdown is complete.
+ ** Param1 and Param2 are invalid for LANReset and LANShutdown.
+ */
+typedef void (*PFNCALLBACK)(U32  Status,
+                              U32  Param1,
+                              U32  Param2,
+                              U16  AdapterID);
+
+/*
+** Status - Transmit and Receive callback status word 
+**
+** A 32 bit Status is returned to the TX and RX callback functions.  This value
+** contains both the reply status and the detailed status as follows:
+**
+**  32    24     16            0
+**  +------+------+------------+
+**  | Reply|      |  Detailed  |
+**  |Status|   0  |   Status   |
+**  +------+------+------------+
+**
+** Reply Status and Detailed Status of zero indicates No Errors.
+*/
+ /* reply message status defines */
+#define    RC_REPLY_STATUS_SUCCESS                    0x00
+#define    RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     0x02
+#define    RC_REPLY_STATUS_TRANSACTION_ERROR          0x0A
+
+
+/* DetailedStatusCode defines */
+#define    RC_DSC_SUCCESS                         0x0000
+#define    RC_DSC_DEVICE_FAILURE                  0x0001
+#define    RC_DSC_DESTINATION_NOT_FOUND           0x0002
+#define    RC_DSC_TRANSMIT_ERROR                  0x0003
+#define    RC_DSC_TRANSMIT_ABORTED                0x0004
+#define    RC_DSC_RECEIVE_ERROR                   0x0005
+#define    RC_DSC_RECEIVE_ABORTED                 0x0006
+#define    RC_DSC_DMA_ERROR                       0x0007
+#define    RC_DSC_BAD_PACKET_DETECTED             0x0008
+#define    RC_DSC_OUT_OF_MEMORY                   0x0009
+#define    RC_DSC_BUCKET_OVERRUN                  0x000A
+#define    RC_DSC_IOP_INTERNAL_ERROR              0x000B
+#define    RC_DSC_CANCELED                        0x000C
+#define    RC_DSC_INVALID_TRANSACTION_CONTEXT     0x000D
+#define    RC_DSC_DESTINATION_ADDRESS_DETECTED    0x000E
+#define    RC_DSC_DESTINATION_ADDRESS_OMITTED     0x000F
+#define    RC_DSC_PARTIAL_PACKET_RETURNED         0x0010
+
+
+/*
+** Packet Description Block   (Received packets)
+**
+** A pointer to this block structure is returned to the ReceiveCallback 
+** function.  It contains the list of packet buffers which have either been
+** filled with a packet or returned to host due to a LANReset function. 
+** Currently there will only be one packet per receive bucket (buffer) posted. 
+**
+**   32   24               0     
+**  +-----------------------+  -\
+**  |   Buffer 1 Context    |    \
+**  +-----------------------+     \
+**  |      0xC0000000       |     / First Bucket Descriptor
+**  +-----+-----------------+    /
+**  |  0  | packet 1 length |   / 
+**  +-----------------------+  -\
+**  |   Buffer 2 Context    |    \
+**  +-----------------------+     \
+**  |      0xC0000000       |     / Second Bucket Descriptor
+**  +-----+-----------------+    /
+**  |  0  | packet 2 length |   / 
+**  +-----+-----------------+  -
+**  |         ...           |  ----- more bucket descriptors
+**  +-----------------------+  -\
+**  |   Buffer n Context    |    \
+**  +-----------------------+     \
+**  |      0xC0000000       |     / Last Bucket Descriptor
+**  +-----+-----------------+    /
+**  |  0  | packet n length |   / 
+**  +-----+-----------------+  -
+**
+** Buffer Context values are those given to adapter in the TCB on calls to
+** RCPostRecvBuffers().
+**  
+*/
+
+
+
+/*
+** Transaction Control Block (TCB) structure
+**
+** A structure like this is filled in by the user and passed by reference to 
+** RCSendPacket() and RCPostRecvBuffers() functions.  Minimum size is five
+** 32-bit words for one buffer with one segment descriptor.  
+** MAX_NMBR_POST_BUFFERS_PER_MSG defines the maximum single segment buffers
+** that can be described in a given TCB.
+**
+**   32                    0
+**  +-----------------------+
+**  |   Buffer Count        |  Number of buffers in the TCB
+**  +-----------------------+
+**  |   Buffer 1 Context    |  first buffer reference
+**  +-----------------------+
+**  |   Buffer 1 Seg Count  |  number of segments in buffer
+**  +-----------------------+
+**  |   Buffer 1 Seg Desc 1 |  first segment descriptor (size, physical address)
+**  +-----------------------+
+**  |         ...           |  more segment descriptors (size, physical address)
+**  +-----------------------+
+**  |   Buffer 1 Seg Desc n |  last segment descriptor (size, physical address)
+**  +-----------------------+
+**  |   Buffer 2 Context    |  second buffer reference
+**  +-----------------------+
+**  |   Buffer 2 Seg Count  |  number of segments in buffer
+**  +-----------------------+
+**  |   Buffer 2 Seg Desc 1 |  segment descriptor (size, physical address)
+**  +-----------------------+
+**  |         ...           |  more segment descriptors (size, physical address)
+**  +-----------------------+
+**  |   Buffer 2 Seg Desc n |
+**  +-----------------------+
+**  |         ...           |  more buffer descriptor blocks ...
+**  +-----------------------+
+**  |   Buffer n Context    |
+**  +-----------------------+
+**  |   Buffer n Seg Count  |
+**  +-----------------------+
+**  |   Buffer n Seg Desc 1 |
+**  +-----------------------+
+**  |         ...           |
+**  +-----------------------+
+**  |   Buffer n Seg Desc n |
+**  +-----------------------+
+**
+**
+** A TCB for one contigous packet buffer would look like the following:
+**
+**   32                    0
+**  +-----------------------+
+**  |         1             |  one buffer in the TCB
+**  +-----------------------+
+**  |  <user's Context>     |  user's buffer reference
+**  +-----------------------+
+**  |         1             |  one segment buffer
+**  +-----------------------+                            _
+**  |    <buffer size>      |  size                       \ 
+**  +-----------------------+                              \ segment descriptor
+**  |  <physical address>   |  physical address of buffer  /
+**  +-----------------------+                            _/
+**
+*/
+
+ /* Buffer Segment Descriptor */
+typedef struct
+{
+    U32 size;
+    U32 phyAddress;
+}
+ BSD, *PBSD;
+typedef PU32 PRCTCB;
+/*
+** -------------------------------------------------------------------------
+** Exported functions comprising the API to the message transport layer
+** -------------------------------------------------------------------------
+*/
+
+
+ /*
+ ** InitRCApiMsgLayer()
+ ** 
+ ** Called once prior to using the API message transport layer.  User 
+ ** provides both the physical and virual address of a locked page buffer 
+ ** that is used as a private buffer for the RedCreek API message
+ ** transport layer.  This buffer must be a contigous memory block of a 
+ ** minimum of 16K bytes and long word aligned.  The user also must provide
+ ** the base address of the RedCreek PCI adapter assigned by BIOS or operating
+ ** system.  The user provided value AdapterID is a zero based index of the
+ ** Ravlin 45/PCI adapter.  This interface number is used in all subsequent API
+ ** calls to identify which adpapter for which the function is intended.  
+ ** Up to sixteen interfaces are supported with this API.
+ **
+ ** Inputs:  AdapterID - interface number from 0 to 15
+ **          pciBaseAddr - virual base address of PCI (set by BIOS)
+ **          p_msgbuf - virual address to private message block (min. 16K)
+ **          p_phymsgbuf - physical address of private message block
+ **          TransmitCallbackFunction - address of user's TX callback function
+ **          ReceiveCallbackFunction  - address of user's RX callback function
+ **
+ */
+RC_RETURN InitRCApiMsgLayer(U16 AdapterID, U32 pciBaseAddr, 
+                            PU8 p_msgbuf,  PU8 p_phymsgbuf,
+                            PFNTXCALLBACK TransmitCallbackFunction,
+                            PFNRXCALLBACK ReceiveCallbackFunction,
+                            PFNCALLBACK   RebootCallbackFunction);
+
+ /*
+ ** RCSetRavlinIPandMask()
+ **
+ ** Set the Ravlin 45/PCI cards IP address and network mask.
+ **
+ ** IP address and mask must be in network byte order.
+ ** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
+ ** 0x04030201 and 0x00FFFFFF on a little endian machine.
+ **
+ */
+RC_RETURN RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask);
+
+
+/*
+** =========================================================================
+** RCGetRavlinIPandMask()
+**
+** get the IP address and MASK from the card
+** 
+** =========================================================================
+*/
+RC_RETURN
+RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask, 
+                        PFNWAITCALLBACK WaitCallback);
+
+ /* 
+ ** RCProcMsgQ()
+ ** 
+ ** Called from user's polling loop or Interrupt Service Routine for a PCI 
+ ** interrupt from the RedCreek PCI adapter.  User responsible for determining
+ ** and hooking the PCI interrupt. This function will call the registered
+ ** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction,
+ ** if a TX or RX transaction has completed.
+ */
+void RCProcMsgQ(U16 AdapterID);
+
+
+ /*
+ ** Disable and Enable Adapter interrupts.  Adapter interrupts are enabled at 
+ ** Init time but can be disabled and re-enabled through these two function calls.
+ ** Packets will still be put into any posted recieved buffers and packets will
+ ** be sent through RCSendPacket() functions.  Disabling Adapter interrupts
+ ** will prevent hardware interrupt to host even though the outbound msg
+ ** queue is not emtpy.
+ */
+RC_RETURN RCEnableAdapterInterrupts(U16 adapterID);
+RC_RETURN RCDisableAdapterInterrupts(U16 AdapterID);
+
+
+ /* 
+ ** RCPostRecvBuffers()
+ ** 
+ ** Post user's page locked buffers for use by the PCI adapter to
+ ** return ethernet packets received from the LAN.  Transaction Control Block,
+ ** provided by user, contains buffer descriptor(s) which includes a buffer
+ ** context number along with buffer size and physical address.  See TCB above.
+ ** The buffer context and actual packet length are returned to the 
+ ** ReceiveCallbackFunction when packets have been received.  Buffers posted
+ ** to the RedCreek adapter are considered owned by the adapter until the
+ ** context is return to user through the ReceiveCallbackFunction.
+ */
+RC_RETURN RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransactionCtrlBlock);
+#define MAX_NMBR_POST_BUFFERS_PER_MSG 32
+
+ /*
+ ** RCSendPacket()
+ ** 
+ ** Send user's ethernet packet from a locked page buffer.  
+ ** Packet must have full MAC header, however without a CRC.  
+ ** Initiator context is a user provided value that is returned 
+ ** to the TransmitCallbackFunction when packet buffer is free.
+ ** Transmit buffer are considered owned by the adapter until context's
+ ** returned to user through the TransmitCallbackFunction.
+ */
+RC_RETURN RCSendPacket(U16 AdapterID, 
+                          U32 context, 
+                          PRCTCB pTransactionCtrlBlock);
+
+
+ /* Ethernet Link Statistics structure */
+typedef struct tag_RC_link_stats
+{
+    U32 TX_good;      /* good transmit frames */
+    U32 TX_maxcol;    /* frames not TX due to MAX collisions */
+    U32 TX_latecol;   /* frames not TX due to late collisions */
+    U32 TX_urun;      /* frames not TX due to DMA underrun */
+    U32 TX_crs;       /* frames TX with lost carrier sense */
+    U32 TX_def;       /* frames deferred due to activity on link */
+    U32 TX_singlecol; /* frames TX with one and only on collision */
+    U32 TX_multcol;   /* frames TX with more than one collision */
+    U32 TX_totcol;    /* total collisions detected during TX */
+    U32 Rcv_good;     /* good frames received */
+    U32 Rcv_CRCerr;   /* frames RX and discarded with CRC errors */
+    U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */
+    U32 Rcv_reserr;   /* good frames discarded due to no RX buffer */
+    U32 Rcv_orun;     /* RX frames lost due to FIFO overrun */
+    U32 Rcv_cdt;      /* RX frames with collision during RX */
+    U32 Rcv_runt;     /* RX frames shorter than 64 bytes */
+}
+ RCLINKSTATS, *P_RCLINKSTATS;
+
+ /*
+ ** RCGetLinkStatistics()
+ **
+ ** Returns link statistics in user's structure at address StatsReturnAddr
+ ** If given, not NULL, the function WaitCallback is called during the wait
+ ** loop while waiting for the adapter to respond.
+ */
+RC_RETURN RCGetLinkStatistics(U16 AdapterID,
+                              P_RCLINKSTATS StatsReturnAddr,
+                              PFNWAITCALLBACK WaitCallback);
+
+ /*
+ ** RCGetLinkStatus()
+ **
+ ** Return link status, up or down, to user's location addressed by ReturnAddr.
+ ** If given, not NULL, the function WaitCallback is called during the wait
+ ** loop while waiting for the adapter to respond.
+ */
+RC_RETURN RCGetLinkStatus(U16 AdapterID, 
+                          PU32 pReturnStatus,
+                          PFNWAITCALLBACK WaitCallback);
+                               
+ /* Link Status defines - value returned in pReturnStatus */
+#define LAN_LINK_STATUS_DOWN     0
+#define LAN_LINK_STATUS_UP       1
+
+ /*
+ ** RCGetMAC()
+ **
+ ** Get the current MAC address assigned to user.  RedCreek Ravlin 45/PCI 
+ ** has two MAC addresses.  One which is private to the PCI Card, and 
+ ** another MAC which is given to the user as its link layer MAC address. The
+ ** adapter runs in promiscous mode because of the dual address requirement.
+ ** The MAC address is returned to the unsigned char array pointer to by mac.
+ */
+RC_RETURN RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback);
+
+ /*
+ ** RCSetMAC()
+ **
+ ** Set a new user port MAC address.  This address will be returned on
+ ** subsequent RCGetMAC() calls.
+ */
+RC_RETURN RCSetMAC(U16 AdapterID, PU8 mac);
+
+ /*
+ ** RCSetLinkSpeed()
+ **
+ ** set adapter's link speed based on given input code.
+ */
+RC_RETURN RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode);
+ /* Set link speed codes */
+#define LNK_SPD_AUTO_NEG_NWAY   0
+#define LNK_SPD_100MB_FULL      1
+#define LNK_SPD_100MB_HALF      2
+#define LNK_SPD_10MB_FULL       3
+#define LNK_SPD_10MB_HALF       4
+
+
+
+
+ /*
+ ** RCGetLinkSpeed()
+ **
+ ** Return link speed code.
+ */
+ /* Return link speed codes */
+#define LNK_SPD_UNKNOWN         0
+#define LNK_SPD_100MB_FULL      1
+#define LNK_SPD_100MB_HALF      2
+#define LNK_SPD_10MB_FULL       3
+#define LNK_SPD_10MB_HALF       4
+
+RC_RETURN
+RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback);
+
+/*
+** =========================================================================
+** RCReportDriverCapability(U16 AdapterID, U32 capability)
+**
+** Currently defined bits:
+** WARM_REBOOT_CAPABLE   0x01
+**
+** =========================================================================
+*/
+RC_RETURN
+RCReportDriverCapability(U16 AdapterID, U32 capability);
+
+/*
+** RCGetFirmwareVer()
+**
+** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
+**
+** WARNING: user's space pointed to by pFirmString should be at least 60 bytes.
+*/
+RC_RETURN
+RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback);
+
+/*
+** ----------------------------------------------
+** LAN adapter Reset and Shutdown functions
+** ----------------------------------------------
+*/
+ /* resource flag bit assignments for RCResetLANCard() & RCShutdownLANCard() */
+#define RC_RESOURCE_RETURN_POSTED_RX_BUCKETS  0x0001 
+#define RC_RESOURCE_RETURN_PEND_TX_BUFFERS    0x0002
+
+ /*
+ ** RCResetLANCard()
+ **
+ ** Reset LAN card operation.  Causes a software reset of the ethernet
+ ** controller and restarts the command and receive units. Depending on 
+ ** the ResourceFlags given, the buffers are either returned to the
+ ** host with reply status of RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and
+ ** detailed status of RC_DSC_CANCELED (new receive buffers must be
+ ** posted after issuing this) OR the buffers are kept and reused by
+ ** the ethernet controller. If CallbackFunction is not NULL, the function
+ ** will be called when the reset is complete.  If the CallbackFunction is
+ ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset 
+ ** to complete (please disable adapter interrupts during this method).
+ ** Any outstanding transmit or receive buffers that are complete will be
+ ** returned via the normal reply messages before the requested resource
+ ** buffers are returned.
+ ** A call to RCPostRecvBuffers() is needed to return the ethernet to full
+ ** operation if the receive buffers were returned during LANReset.
+ ** Note: The IOP status is not affected by a LAN reset.
+ */
+RC_RETURN RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
+
+
+ /*
+ ** RCShutdownLANCard()
+ **
+ ** Shutdown LAN card operation and put into an idle (suspended) state.
+ ** The LAN card is restarted with RCResetLANCard() function.
+ ** Depending on the ResourceFlags given, the buffers are either returned 
+ ** to the host with reply status of RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 
+ ** and detailed status of RC_DSC_CANCELED (new receive buffers must be
+ ** posted after issuing this) OR the buffers are kept and reused by
+ ** the ethernet controller. If CallbackFunction is not NULL, the function
+ ** will be called when the reset is complete.  If the CallbackFunction is
+ ** NULL,a 1 will be put into the ReturnAddr after waiting for the reset 
+ ** to complete (please disable adapter interrupts during this method).
+ ** Any outstanding transmit or receive buffers that are complete will be
+ ** returned via the normal reply messages before the requested resource
+ ** buffers are returned.
+ ** Note: The IOP status is not affected by a LAN shutdown.
+ */                                      
+RC_RETURN 
+RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
+
+ /*
+ ** RCResetAdapter();
+ **     Initializes ADAPTERState to ADAPTER_STATE_RESET.
+ **     Stops access to outbound message Q.
+ **     Discards any outstanding transmit or posted receive buffers.
+ **     Clears outbound message Q. 
+ */
+RC_RETURN 
+RCResetAdapter(U16 AdapterID);
+
+#endif /* RCMTL_H */
diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c
new file mode 100644 (file)
index 0000000..acdb802
--- /dev/null
@@ -0,0 +1,1323 @@
+/* 
+**  RCpci45.c  
+**
+**
+**
+**  ---------------------------------------------------------------------
+**  ---     Copyright (c) 1998, RedCreek Communications Inc.          ---
+**  ---                   All rights reserved.                        ---
+**  ---------------------------------------------------------------------
+**
+** Written by Pete Popov and Brian Moyle.
+**
+** Known Problems
+** 
+** Billions and Billions...  
+**
+** ... apparently added by Brian.  Pete knows of no bugs.
+**
+**  TODO:
+**      -Get rid of the wait loops in the API and replace them
+**       with system independent delays ...something like
+**       "delayms(2)".
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**
+**  Ported to 2.1.x by Alan Cox 1998/12/9. If this doesnt work try 2.0.x
+**  and let me know.
+**
+***************************************************************************/
+
+static char *version =
+"RedCreek Communications PCI linux driver version 1.32 Beta\n";
+
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/timer.h>
+#include <asm/irq.h>            /* For NR_IRQS only. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#define RC_LINUX_MODULE
+#include "rcmtl.h"
+#include "rcif.h"
+
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+
+#define NEW_MULTICAST
+#include <linux/delay.h>
+
+/* PCI/45 Configuration space values */
+#define RC_PCI45_VENDOR_ID  0x4916
+#define RC_PCI45_DEVICE_ID  0x1960
+
+#define MAX_ETHER_SIZE        1520  
+#define MAX_NMBR_RCV_BUFFERS    96
+#define RC_POSTED_BUFFERS_LOW_MARK MAX_NMBR_RCV_BUFFERS-16
+#define BD_SIZE 3           /* Bucket Descriptor size */
+#define BD_LEN_OFFSET 2     /* Bucket Descriptor offset to length field */
+
+
+/* RedCreek LAN device Target ID */
+#define RC_LAN_TARGET_ID  0x10 
+/* RedCreek's OSM default LAN receive Initiator */
+#define DEFAULT_RECV_INIT_CONTEXT  0xA17  
+
+
+static U32 DriverControlWord =  0;
+
+static void rc_timer(unsigned long);
+
+/*
+ * Driver Private Area, DPA.
+ */
+typedef struct
+{
+
+     /* 
+      *    pointer to the device structure which is part
+      * of the interface to the Linux kernel.
+      */
+      struct device *dev;            
+     
+     char devname[8];                /* "ethN" string */
+     U8     id;                        /* the AdapterID */
+     U32    pci_addr;               /* the pci address of the adapter */
+     U32    bus;
+     U32    function;
+     struct timer_list timer;        /*  timer */
+     struct enet_statistics  stats; /* the statistics structure */
+     struct device *next;            /* points to the next RC adapter */
+     unsigned long numOutRcvBuffers;/* number of outstanding receive buffers*/
+     unsigned char shutdown;
+     unsigned char reboot;
+     unsigned char nexus;
+     PU8    PLanApiPA;             /* Pointer to Lan Api Private Area */
+
+}
+DPA, *PDPA;
+
+#define MAX_ADAPTERS 32
+
+static PDPA  PCIAdapters[MAX_ADAPTERS] = 
+{
+     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+
+static int RCscan(void);
+static struct device 
+*RCfound_device(struct device *, int, int, int, int, int, int);
+
+static int RCprobe1(struct device *);
+static int RCopen(struct device *);
+static int RC_xmit_packet(struct sk_buff *, struct device *);
+static void RCinterrupt(int, void *, struct pt_regs *);
+static int RCclose(struct device *dev);
+static struct enet_statistics *RCget_stats(struct device *);
+static int RCioctl(struct device *, struct ifreq *, int);
+static int RCconfig(struct device *, struct ifmap *);
+static void RCxmit_callback(U32, U16, PU32, U16);
+static void RCrecv_callback(U32, U8, U32, PU32, U16);
+static void RCreset_callback(U32, U32, U32, U16);
+static void RCreboot_callback(U32, U32, U32, U16);
+static int RC_allocate_and_post_buffers(struct device *, int);
+
+
+/* A list of all installed RC devices, for removing the driver module. */
+static struct device *root_RCdev = NULL;
+
+#ifdef MODULE
+int init_module(void)
+#else
+int rcpci_probe(struct netdevice *dev)
+#endif
+{
+     int cards_found;
+
+     printk(version);
+
+     root_RCdev = NULL;
+     cards_found = RCscan();
+#ifdef MODULE     
+     return cards_found ? 0 : -ENODEV;
+#else
+     return -1;
+#endif          
+}
+
+static int RCscan(void)
+{
+     int cards_found = 0;
+     struct device *dev = 0;
+
+     if (pcibios_present()) 
+     {
+          static int pci_index = 0;
+          unsigned char pci_bus, pci_device_fn;
+          int scan_status;
+          int board_index = 0;
+
+          for (;pci_index < 0xff; pci_index++) 
+          {
+               unsigned char pci_irq_line;
+               unsigned short pci_command, vendor, device, class;
+               unsigned int pci_ioaddr;
+
+
+               scan_status =  
+                    (pcibios_find_device (RC_PCI45_VENDOR_ID, 
+                                          RC_PCI45_DEVICE_ID, 
+                                          pci_index, 
+                                          &pci_bus, 
+                                          &pci_device_fn));
+#ifdef RCDEBUG
+               printk("rc scan_status = 0x%X\n", scan_status);
+#endif
+               if (scan_status != PCIBIOS_SUCCESSFUL)
+                    break;
+               pcibios_read_config_word(pci_bus, 
+                                        pci_device_fn, 
+                                        PCI_VENDOR_ID, &vendor);
+               pcibios_read_config_word(pci_bus, 
+                                        pci_device_fn,
+                                        PCI_DEVICE_ID, &device);
+               pcibios_read_config_byte(pci_bus, 
+                                        pci_device_fn,
+                                        PCI_INTERRUPT_LINE, &pci_irq_line);
+               pcibios_read_config_dword(pci_bus, 
+                                         pci_device_fn,
+                                         PCI_BASE_ADDRESS_0, &pci_ioaddr);
+               pcibios_read_config_word(pci_bus, 
+                                        pci_device_fn,
+                                        PCI_CLASS_DEVICE, &class);
+
+               pci_ioaddr &= ~0xf;
+
+#ifdef RCDEBUG
+               printk("rc: Found RedCreek PCI adapter\n");
+               printk("rc: pci class = 0x%x  0x%x \n", class, class>>8);
+               printk("rc: pci_bus = %d,  pci_device_fn = %d\n", pci_bus, pci_device_fn);
+               printk("rc: pci_irq_line = 0x%x \n", pci_irq_line);
+               printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr);
+#endif
+
+#if 0
+               if (check_region(pci_ioaddr, 32768))
+               {
+                    printk("rc: check_region failed\n");
+                    continue;
+               }
+               else
+               {
+                    printk("rc: check_region passed\n");
+               }
+#endif
+               
+                /*
+                 * Get and check the bus-master and latency values.
+                 * Some PCI BIOSes fail to set the master-enable bit.
+                 */
+
+                pcibios_read_config_word(pci_bus, 
+                                         pci_device_fn,
+                                         PCI_COMMAND, 
+                                         &pci_command);
+                if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+                     printk("rc: PCI Master Bit has not been set!\n");
+                            
+                     pci_command |= PCI_COMMAND_MASTER;
+                     pcibios_write_config_word(pci_bus, 
+                                               pci_device_fn,
+                                               PCI_COMMAND, 
+                                               pci_command);
+                }
+                if ( ! (pci_command & PCI_COMMAND_MEMORY)) {
+                /*
+                 * If the BIOS did not set the memory enable bit, what else
+                 * did it not initialize?  Skip this adapter.
+                 */
+                     printk("rc: Adapter %d, PCI Memory Bit has not been set!\n",
+                         cards_found);
+                     printk("rc: Bios problem? \n");
+                     continue;
+                }
+                    
+               dev = RCfound_device(dev, pci_ioaddr, pci_irq_line,
+                                    pci_bus, pci_device_fn,
+                                    board_index++, cards_found);
+
+               if (dev) {
+                    dev = 0;
+                    cards_found++;
+               }
+          }
+     }
+     printk("rc: found %d cards \n", cards_found);
+     return cards_found;
+}
+
+static struct device *
+RCfound_device(struct device *dev, int memaddr, int irq, 
+               int bus, int function, int product_index, int card_idx)
+{
+     int dev_size = 32768;        
+     unsigned long *vaddr=0;
+     PDPA pDpa;
+     int init_status;
+
+     /* 
+      * Allocate and fill new device structure. 
+      * We need enough for struct device plus DPA plus the LAN API private
+      * area, which requires a minimum of 16KB.  The top of the allocated
+      * area will be assigned to struct device; the next chunk will be
+      * assigned to DPA; and finally, the rest will be assigned to the
+      * the LAN API layer.
+      */
+     dev = (struct device *) kmalloc(dev_size, GFP_DMA | GFP_KERNEL |GFP_ATOMIC);
+     memset(dev, 0, dev_size);
+#ifdef RCDEBUG
+     printk("rc: dev = 0x%08X\n", (uint)dev);
+#endif 
+
+     /*
+      * dev->priv will point to the start of DPA.
+      */
+     dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15);
+     pDpa = dev->priv;
+     dev->name = pDpa->devname;
+
+     pDpa->dev = dev;            /* this is just for easy reference */
+     pDpa->function = function;
+     pDpa->bus = bus;
+     pDpa->id = card_idx;        /* the device number */
+     pDpa->pci_addr = memaddr;
+     PCIAdapters[card_idx] = pDpa;
+#ifdef RCDEBUG
+     printk("rc: pDpa = 0x%x, id = %d \n", (uint)pDpa, (uint)pDpa->id);
+#endif
+
+     /*
+      * Save the starting address of the LAN API private area.  We'll
+      * pass that to InitRCApiMsgLayer().
+      */
+     pDpa->PLanApiPA = (void *)(((long)pDpa + sizeof(DPA) + 0xff) & ~0xff);
+#ifdef RCDEBUG
+     printk("rc: pDpa->PLanApiPA = 0x%x\n", (uint)pDpa->PLanApiPA);
+#endif
+    
+     /* The adapter is accessable through memory-access read/write, not
+      * I/O read/write.  Thus, we need to map it to some virtual address
+      * area in order to access the registers are normal memory.
+      */
+     vaddr = (ulong *) ioremap(memaddr, 32768);
+#ifdef RCDEBUG
+     printk("rc: RCfound_device: 0x%x, priv = 0x%x, vaddr = 0x%x\n", 
+            (uint)dev, (uint)dev->priv, (uint)vaddr);
+#endif
+     dev->base_addr = (unsigned long)vaddr;
+     dev->irq = irq;
+     dev->interrupt = 0;
+
+     /*
+      * Request a shared interrupt line.
+      */
+     if ( request_irq(dev->irq, (void *)RCinterrupt,
+                      SA_INTERRUPT|SA_SHIRQ, "RedCreek VPN Adapter", dev) )
+     {
+          printk( "RC PCI 45: %s: unable to get IRQ %d\n", (PU8)dev->name, (uint)dev->irq );
+          iounmap(vaddr);
+          kfree(dev);
+           return 0;
+     }
+
+     init_status = InitRCApiMsgLayer(pDpa->id, dev->base_addr, 
+                                     pDpa->PLanApiPA, pDpa->PLanApiPA,
+                                     (PFNTXCALLBACK)RCxmit_callback,
+                                     (PFNRXCALLBACK)RCrecv_callback,
+                                     (PFNCALLBACK)RCreboot_callback);
+#ifdef RCDEBUG
+     printk("rc: msg initted: status = 0x%x\n", init_status);
+#endif
+     if (init_status)
+     {
+          printk("rc: Unable to initialize msg layer\n");
+          free_irq(dev->irq, dev);
+          vfree(vaddr);
+          kfree(dev);
+          return 0;
+     }
+     if (RCGetMAC(pDpa->id, dev->dev_addr, NULL))
+     {
+          printk("rc: Unable to get adapter MAC\n");
+          free_irq(dev->irq, dev);
+          vfree(vaddr);
+          kfree(dev);
+          return 0;
+     }
+
+     DriverControlWord |= WARM_REBOOT_CAPABLE;
+     RCReportDriverCapability(pDpa->id, DriverControlWord);
+
+     dev->init = RCprobe1;
+     ether_setup(dev);            /* linux kernel interface */
+
+     pDpa->next = root_RCdev;
+     root_RCdev = dev;
+
+     if (register_netdev(dev) != 0) /* linux kernel interface */
+     {
+          printk("rc: unable to register device \n");
+          free_irq(dev->irq, dev);
+          vfree(vaddr);
+          kfree(dev);
+          return 0;
+     }
+     return dev;
+}
+
+static int RCprobe1(struct device *dev)
+{
+     dev->open = RCopen;
+     dev->hard_start_xmit = RC_xmit_packet;
+     dev->stop = RCclose;
+     dev->get_stats = RCget_stats;
+     dev->do_ioctl = RCioctl;
+     dev->set_config = RCconfig;
+     return 0;
+}
+
+static int
+RCopen(struct device *dev)
+{
+    int post_buffers = MAX_NMBR_RCV_BUFFERS;
+    PDPA pDpa = (PDPA) dev->priv;
+    int count = 0;
+    int requested = 0;
+
+#ifdef RCDEBUG
+    printk("rc: RCopen\n");
+#endif
+    RCEnableAdapterInterrupts(pDpa->id);
+
+    if (pDpa->nexus)
+    {
+       /* This is not the first time RCopen is called.  Thus,
+        * the interface was previously opened and later closed
+        * by RCclose().  RCclose() does a Shutdown; to wake up
+        * the adapter, a reset is mandatory before we can post
+        * receive buffers.  However, if the adapter initiated 
+        * a reboot while the interface was closed -- and interrupts
+        * were turned off -- we need will need to reinitialize
+        * the adapter, rather than simply waking it up.  
+        */
+        printk("rc: Waking up adapter...\n");
+        RCResetLANCard(pDpa->id,0,0,0);
+    }
+    else
+    {
+       pDpa->nexus = 1;
+    }
+
+    while(post_buffers)
+    {
+        if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
+            requested = MAX_NMBR_POST_BUFFERS_PER_MSG;
+        else
+            requested = post_buffers;
+        count = RC_allocate_and_post_buffers(dev, requested);
+
+        if ( count < requested )
+        {
+             /*
+              * Check to see if we were able to post any buffers at all.
+              */
+             if (post_buffers == MAX_NMBR_RCV_BUFFERS)
+             {
+                  printk("rc: Error RCopen: not able to allocate any buffers\r\n");
+                  return(-ENOMEM);                    
+             }
+             printk("rc: Warning RCopen: not able to allocate all requested buffers\r\n");
+             break;            /* we'll try to post more buffers later */
+        }
+        else
+             post_buffers -= count;
+    }
+    pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers;
+    pDpa->shutdown = 0;        /* just in case */
+#ifdef RCDEBUG
+    printk("rc: RCopen: posted %d buffers\n", (uint)pDpa->numOutRcvBuffers);
+#endif
+    MOD_INC_USE_COUNT;
+    return 0;
+}
+
+static int
+RC_xmit_packet(struct sk_buff *skb, struct device *dev)
+{
+
+     PDPA pDpa = (PDPA) dev->priv;
+     singleTCB tcb;
+     psingleTCB ptcb = &tcb;
+     RC_RETURN status = 0;
+    
+     if (dev->tbusy || pDpa->shutdown || pDpa->reboot)
+     {
+#ifdef RCDEBUG
+          printk("rc: RC_xmit_packet: tbusy!\n");
+#endif
+          return 1;
+     }
+      
+     if ( skb->len <= 0 ) 
+     {
+          printk("RC_xmit_packet: skb->len less than 0!\n");
+          return 0;
+     }
+
+     /*
+      * The user is free to reuse the TCB after RCSendPacket() returns, since
+      * the function copies the necessary info into its own private space.  Thus,
+      * our TCB can be a local structure.  The skb, on the other hand, will be
+      * freed up in our interrupt handler.
+      */
+     ptcb->bcount = 1;
+     /* 
+      * we'll get the context when the adapter interrupts us to tell us that
+      * the transmision is done. At that time, we can free skb.
+      */
+     ptcb->b.context = (U32)skb;    
+     ptcb->b.scount = 1;
+     ptcb->b.size = skb->len;
+     ptcb->b.addr = (U32)skb->data;
+
+#ifdef RCDEBUG
+     printk("rc: RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", 
+            (uint)skb, (uint)pDpa, (uint)pDpa->id, (uint)ptcb);
+#endif
+     if ( (status = RCSendPacket(pDpa->id, (U32)NULL, (PRCTCB)ptcb))
+          != RC_RTN_NO_ERROR)
+     {
+#ifdef RCDEBUG
+          printk("rc: RC send error 0x%x\n", (uint)status);
+#endif
+          dev->tbusy = 1;
+     }
+     else
+     {
+          dev->trans_start = jiffies;
+          //       dev->tbusy = 0;
+     }
+     /*
+      * That's it!
+      */
+     return 0;
+}
+
+/*
+ * RCxmit_callback()
+ *
+ * The transmit callback routine. It's called by RCProcMsgQ()
+ * because the adapter is done with one or more transmit buffers and
+ * it's returning them to us, or we asked the adapter to return the
+ * outstanding transmit buffers by calling RCResetLANCard() with 
+ * RC_RESOURCE_RETURN_PEND_TX_BUFFERS flag. 
+ * All we need to do is free the buffers.
+ */
+static void 
+RCxmit_callback(U32 Status, 
+                U16 PcktCount, 
+                PU32 BufferContext, 
+                U16 AdapterID)
+{
+    struct sk_buff *skb;
+    PDPA pDpa;
+    struct device *dev;
+
+    pDpa = PCIAdapters[AdapterID];
+    if (!pDpa)
+    {
+        printk("rc: Fatal error: xmit callback, !pDpa\n");
+        return;
+    }
+    dev = pDpa->dev;
+
+        // printk("xmit_callback: Status = 0x%x\n", (uint)Status);
+    if (Status != RC_REPLY_STATUS_SUCCESS)
+    {
+        printk("rc: xmit_callback: Status = 0x%x\n", (uint)Status);
+    }
+#ifdef RCDEBUG
+    if (pDpa->shutdown || pDpa->reboot)
+        printk("rc: xmit callback: shutdown||reboot\n");
+#endif
+
+#ifdef RCDEBUG     
+    printk("rc: xmit_callback: PcktCount = %d, BC = 0x%x\n", 
+            (uint)PcktCount, (uint)BufferContext);
+#endif
+    while (PcktCount--)
+    {
+        skb = (struct sk_buff *)(BufferContext[0]);
+#ifdef RCDEBUG
+        printk("rc: skb = 0x%x\n", (uint)skb);
+#endif
+        BufferContext++;
+        dev_kfree_skb(skb);
+    }
+    dev->tbusy = 0;
+
+}
+
+static void
+RCreset_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID)
+{
+     PDPA pDpa;
+     struct device *dev;
+     
+     pDpa = PCIAdapters[AdapterID];
+     dev = pDpa->dev;
+#ifdef RCDEBUG
+      printk("rc: RCreset_callback Status 0x%x\n", (uint)Status);
+#endif
+      /*
+       * Check to see why we were called.
+       */
+      if (pDpa->shutdown)
+      {
+           printk("rc: Shutting down interface\n");
+           pDpa->shutdown = 0;
+           pDpa->reboot = 0;
+           MOD_DEC_USE_COUNT; 
+      }
+      else if (pDpa->reboot)
+      {
+           printk("rc: reboot, shutdown adapter\n");
+           /*
+            * We don't set any of the flags in RCShutdownLANCard()
+            * and we don't pass a callback routine to it.
+            * The adapter will have already initiated the reboot by
+            * the time the function returns.
+            */
+                  RCDisableAdapterInterrupts(pDpa->id);
+           RCShutdownLANCard(pDpa->id,0,0,0);
+           printk("rc: scheduling timer...\n");
+           init_timer(&pDpa->timer);
+           pDpa->timer.expires = RUN_AT((30*HZ)/10); /* 3 sec. */
+           pDpa->timer.data = (unsigned long)dev;
+           pDpa->timer.function = &rc_timer;    /* timer handler */
+           add_timer(&pDpa->timer);
+      }
+
+
+
+}
+
+static void
+RCreboot_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID)
+{
+     PDPA pDpa;
+    
+     pDpa = PCIAdapters[AdapterID];
+#ifdef RCDEBUG
+     printk("rc: RCreboot: rcv buffers outstanding = %d\n", 
+            (uint)pDpa->numOutRcvBuffers);
+#endif
+     if (pDpa->shutdown)
+     {
+          printk("rc: skipping reboot sequence -- shutdown already initiated\n");
+          return;
+     }
+     pDpa->reboot = 1;
+     /*
+      * OK, we reset the adapter and ask it to return all
+      * outstanding transmit buffers as well as the posted
+      * receive buffers.  When the adapter is done returning
+      * those buffers, it will call our RCreset_callback() 
+      * routine.  In that routine, we'll call RCShutdownLANCard()
+      * to tell the adapter that it's OK to start the reboot and
+      * schedule a timer callback routine to execute 3 seconds 
+      * later; this routine will reinitialize the adapter at that time.
+      */
+     RCResetLANCard(pDpa->id, 
+                    RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | 
+                    RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0,
+                    (PFNCALLBACK)RCreset_callback);
+}
+
+
+int broadcast_packet(unsigned char * address)
+{
+    int i;
+    for (i=0; i<6; i++)
+        if (address[i] != 0xff) return 0;
+
+    return 1;
+}
+
+/*
+ * RCrecv_callback()
+ * 
+ * The receive packet callback routine.  This is called by
+ * RCProcMsgQ() after the adapter posts buffers which have been
+ * filled (one ethernet packet per buffer).
+ */
+static void
+RCrecv_callback(U32  Status, 
+                U8   PktCount, 
+                U32  BucketsRemain, 
+                PU32 PacketDescBlock, 
+                U16  AdapterID)
+{
+
+     U32 len, count;
+     PDPA pDpa;
+     struct sk_buff *skb;
+     struct device *dev;
+     singleTCB tcb;
+     psingleTCB ptcb = &tcb;
+
+
+          pDpa = PCIAdapters[AdapterID];
+          dev = pDpa->dev;
+
+          ptcb->bcount = 1;
+
+#ifdef RCDEBUG
+          printk("rc: RCrecv_callback: 0x%x, 0x%x, 0x%x\n",
+                 (uint)PktCount, (uint)BucketsRemain, (uint)PacketDescBlock);
+#endif
+        
+#ifdef RCDEBUG
+          if ((pDpa->shutdown || pDpa->reboot) && !Status)
+               printk("shutdown||reboot && !Status: PktCount = %d\n",PktCount);
+#endif
+
+          if ( (Status != RC_REPLY_STATUS_SUCCESS) || pDpa->shutdown)
+          {
+               /*
+                * Free whatever buffers the adapter returned, but don't
+                * pass them to the kernel.
+                */
+        
+                    if (!pDpa->shutdown && !pDpa->reboot)
+                         printk("rc: RCrecv error: status = 0x%x\n", (uint)Status);
+                    else
+                         printk("rc: Returning %d buffers, status = 0x%x\n", 
+                                PktCount, (uint)Status);
+               /*
+                * TO DO: check the nature of the failure and put the adapter in
+                * failed mode if it's a hard failure.  Send a reset to the adapter
+                * and free all outstanding memory.
+                */
+               if (Status == RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER)
+               {
+#ifdef RCDEBUG
+                    printk("RCrecv status ABORT NO DATA TRANSFER\n");
+#endif
+               }
+               /* check for reset status: RC_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */ 
+               if (PacketDescBlock)
+               {
+                    while(PktCount--)
+                    {
+                         skb = (struct sk_buff *)PacketDescBlock[0];
+#ifdef RCDEBUG
+                         printk("free skb 0x%p\n", skb);
+#endif
+                         dev_kfree_skb(skb);
+                         pDpa->numOutRcvBuffers--;
+                         PacketDescBlock += BD_SIZE; /* point to next context field */
+                    }
+               }
+               return;
+          }
+          else
+          {
+               while(PktCount--)
+               {
+                    skb = (struct sk_buff *)PacketDescBlock[0];
+#ifdef RCDEBUG
+                    if (pDpa->shutdown)
+                         printk("shutdown: skb=0x%x\n", (uint)skb);
+
+                    printk("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", (uint)skb,
+                           (uint)skb->data[0], (uint)skb->data[1], (uint)skb->data[2],
+                           (uint)skb->data[3], (uint)skb->data[4], (uint)skb->data[5]);
+#endif
+                    if ( (memcmp(dev->dev_addr, skb->data, 6)) &&
+                         (!broadcast_packet(skb->data)))
+                    {
+                         /*
+                          * Re-post the buffer to the adapter.  Since the adapter usually
+                          * return 1 to 2 receive buffers at a time, it's not too inefficient
+                          * post one buffer at a time but ... may be that should be 
+                          * optimized at some point.
+                          */
+                         ptcb->b.context = (U32)skb;    
+                         ptcb->b.scount = 1;
+                         ptcb->b.size = MAX_ETHER_SIZE;
+                         ptcb->b.addr = (U32)skb->data;
+
+                         if ( RCPostRecvBuffers(pDpa->id, (PRCTCB)ptcb ) != RC_RTN_NO_ERROR)
+                         {
+                              printk("rc: RCrecv_callback: post buffer failed!\n");
+                              dev_kfree_skb(skb);
+                         }
+                         else
+                         {
+                              pDpa->numOutRcvBuffers++;
+                         }
+                    }
+                    else
+                    {
+                         len = PacketDescBlock[2];
+                         skb->dev = dev;
+                         skb_put( skb, len ); /* adjust length and tail */
+                         skb->protocol = eth_type_trans(skb, dev);
+                         netif_rx(skb);    /* send the packet to the kernel */
+                         dev->last_rx = jiffies;
+                    }
+                    pDpa->numOutRcvBuffers--;
+                    PacketDescBlock += BD_SIZE; /* point to next context field */
+               }
+          } 
+    
+          /*
+           * Replenish the posted receive buffers. 
+           * DO NOT replenish buffers if the driver has already
+           * initiated a reboot or shutdown!
+           */
+
+          if (!pDpa->shutdown && !pDpa->reboot)
+          {
+               count = RC_allocate_and_post_buffers(dev, 
+                                                    MAX_NMBR_RCV_BUFFERS-pDpa->numOutRcvBuffers);
+               pDpa->numOutRcvBuffers += count;
+          }
+
+}
+
+/*
+ * RCinterrupt()
+ * 
+ * Interrupt handler. 
+ * This routine sets up a couple of pointers and calls
+ * RCProcMsgQ(), which in turn process the message and
+ * calls one of our callback functions.
+ */
+static void 
+RCinterrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+     PDPA pDpa;
+     struct device *dev = (struct device *)(dev_id);
+
+     pDpa = (PDPA) (dev->priv);
+     
+     if (pDpa->shutdown)
+          printk("rc: shutdown: service irq\n");
+
+#ifdef RCDEBUG
+     printk("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", 
+            (uint)pDpa, (uint)dev, (uint)pDpa->id);
+     printk("dev = 0x%x\n", (uint)dev);
+#endif
+     if (dev->interrupt)
+          printk("%s: Re-entering the interrupt handler.\n", dev->name);
+     dev->interrupt = 1;
+
+     RCProcMsgQ(pDpa->id);
+     dev->interrupt = 0;
+
+     return;
+}
+
+#define REBOOT_REINIT_RETRY_LIMIT 10
+static void rc_timer(unsigned long data)
+{
+     struct device *dev = (struct device *)data;
+     PDPA pDpa = (PDPA) (dev->priv);
+     int init_status;
+     static int retry = 0;
+     int post_buffers = MAX_NMBR_RCV_BUFFERS;
+     int count = 0;
+     int requested = 0;
+
+     if (pDpa->reboot)
+     {
+
+          init_status = InitRCApiMsgLayer(pDpa->id, dev->base_addr, 
+                                          pDpa->PLanApiPA, pDpa->PLanApiPA,
+                                          (PFNTXCALLBACK)RCxmit_callback,
+                                          (PFNRXCALLBACK)RCrecv_callback,
+                                          (PFNCALLBACK)RCreboot_callback);
+
+          switch(init_status)
+          {
+          case RC_RTN_NO_ERROR:
+               pDpa->reboot = 0;
+               pDpa->shutdown = 0;        /* just in case */
+               RCReportDriverCapability(pDpa->id, DriverControlWord);
+               RCEnableAdapterInterrupts(pDpa->id);
+
+               if (dev->flags & IFF_UP)
+               {
+                    while(post_buffers)
+                    {
+                         if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
+                              requested = MAX_NMBR_POST_BUFFERS_PER_MSG;
+                         else
+                              requested = post_buffers;
+                         count = RC_allocate_and_post_buffers(dev, requested);
+                         post_buffers -= count;
+                         if ( count < requested )
+                              break;
+                    }
+                    pDpa->numOutRcvBuffers = 
+                         MAX_NMBR_RCV_BUFFERS - post_buffers;
+                    printk("rc: posted %d buffers \r\n", 
+                           (uint)pDpa->numOutRcvBuffers);
+               }
+               printk("rc: Initialization done.\n");
+               return;
+          case RC_RTN_FREE_Q_EMPTY:
+               retry++;
+               printk("rc: inbound free q emtpy\n");
+               break;
+          default:
+               retry++;
+               printk("rc: unexpected bad status after reboot\n");    
+               break;
+          }
+
+          if (retry > REBOOT_REINIT_RETRY_LIMIT)
+          {
+               printk("rc: unable to reinitialize adapter after reboot\n");
+               printk("rc: decrementing driver and closing interface\n");
+               RCDisableAdapterInterrupts(pDpa->id);
+               dev->flags &= ~IFF_UP;
+               MOD_DEC_USE_COUNT; 
+          }
+          else
+          {
+               printk("rc: rescheduling timer...\n");
+               init_timer(&pDpa->timer);
+               pDpa->timer.expires = RUN_AT((30*HZ)/10); /* 3 sec. */
+               pDpa->timer.data = (unsigned long)dev;
+               pDpa->timer.function = &rc_timer;    /* timer handler */
+               add_timer(&pDpa->timer);
+          }
+     }
+     else
+     {
+          printk("rc: timer??\n");
+     }
+}
+
+static int
+RCclose(struct device *dev)
+{
+
+     PDPA pDpa = (PDPA) dev->priv;
+
+#ifdef RCDEBUG
+     printk("rc: RCclose\r\n");
+#endif
+     if (pDpa->reboot)
+     {
+          printk("rc: skipping reset -- adapter already in reboot mode\n");
+          dev->flags &= ~IFF_UP;
+          pDpa->shutdown = 1;
+          return 0;
+     }
+#ifdef RCDEBUG
+     printk("rc: receive buffers outstanding: %d\n", 
+            (uint)pDpa->numOutRcvBuffers);
+#endif
+
+     pDpa->shutdown = 1;
+
+     /*
+      * We can't allow the driver to be unloaded until the adapter returns
+      * all posted receive buffers.  It doesn't hurt to tell the adapter
+      * to return all posted receive buffers and outstanding xmit buffers,
+      * even if there are none.
+      */
+
+     RCShutdownLANCard(pDpa->id, 
+                       RC_RESOURCE_RETURN_POSTED_RX_BUCKETS | 
+                       RC_RESOURCE_RETURN_PEND_TX_BUFFERS,0,
+                       (PFNCALLBACK)RCreset_callback);
+
+     dev->flags &= ~IFF_UP;
+     return 0;
+}
+
+static struct enet_statistics *
+RCget_stats(struct device *dev)
+{
+    RCLINKSTATS    RCstats;
+   
+    PDPA pDpa = dev->priv;
+
+    if (!pDpa)
+    {
+        printk("rc: RCget_stats: !pDpa\n");
+        return 0;
+    }
+    else if (!(dev->flags & IFF_UP))    
+    {
+#ifdef RCDEBUG
+        printk("rc: RCget_stats: device down\n");
+#endif
+        return 0;
+    }
+
+    memset(&RCstats, 0, sizeof(RCLINKSTATS));
+    if ( (RCGetLinkStatistics(pDpa->id, &RCstats, (void *)0)) == RC_RTN_NO_ERROR )
+    {
+#ifdef RCDEBUG
+        printk("rc: TX_good 0x%x\n", (uint)RCstats.TX_good);
+        printk("rc: TX_maxcol 0x%x\n", (uint)RCstats.TX_maxcol);
+        printk("rc: TX_latecol 0x%x\n", (uint)RCstats.TX_latecol);
+        printk("rc: TX_urun 0x%x\n", (uint)RCstats.TX_urun);
+        printk("rc: TX_crs 0x%x\n", (uint)RCstats.TX_crs);
+        printk("rc: TX_def 0x%x\n", (uint)RCstats.TX_def);
+        printk("rc: TX_singlecol 0x%x\n", (uint)RCstats.TX_singlecol);
+        printk("rc: TX_multcol 0x%x\n", (uint)RCstats.TX_multcol);
+        printk("rc: TX_totcol 0x%x\n", (uint)RCstats.TX_totcol);
+
+        printk("rc: Rcv_good 0x%x\n", (uint)RCstats.Rcv_good);
+        printk("rc: Rcv_CRCerr 0x%x\n", (uint)RCstats.Rcv_CRCerr);
+        printk("rc: Rcv_alignerr 0x%x\n", (uint)RCstats.Rcv_alignerr);
+        printk("rc: Rcv_reserr 0x%x\n", (uint)RCstats.Rcv_reserr);
+        printk("rc: Rcv_orun 0x%x\n", (uint)RCstats.Rcv_orun);
+        printk("rc: Rcv_cdt 0x%x\n", (uint)RCstats.Rcv_cdt);
+        printk("rc: Rcv_runt 0x%x\n", (uint)RCstats.Rcv_runt);
+#endif
+
+        pDpa->stats.rx_packets = RCstats.Rcv_good; /* total packets received    */
+        pDpa->stats.tx_packets = RCstats.TX_good; /* total packets transmitted    */
+
+        pDpa->stats.rx_errors = 
+            RCstats.Rcv_CRCerr +
+            RCstats.Rcv_alignerr + 
+            RCstats.Rcv_reserr + 
+            RCstats.Rcv_orun + 
+            RCstats.Rcv_cdt + 
+            RCstats.Rcv_runt; /* bad packets received        */
+
+        pDpa->stats.tx_errors = 
+            RCstats.TX_urun + 
+            RCstats.TX_crs + 
+            RCstats.TX_def + 
+            RCstats.TX_totcol; /* packet transmit problems    */
+
+        /*
+         * This needs improvement.
+         */
+        pDpa->stats.rx_dropped = 0;        /* no space in linux buffers    */
+        pDpa->stats.tx_dropped = 0;        /* no space available in linux    */
+        pDpa->stats.multicast = 0;        /* multicast packets received    */
+        pDpa->stats.collisions = RCstats.TX_totcol;
+
+        /* detailed rx_errors: */
+        pDpa->stats.rx_length_errors = 0;
+        pDpa->stats.rx_over_errors = RCstats.Rcv_orun; /* receiver ring buff overflow    */
+        pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr;    /* recved pkt with crc error    */
+        pDpa->stats.rx_frame_errors = 0; /* recv'd frame alignment error */
+        pDpa->stats.rx_fifo_errors = 0; /* recv'r fifo overrun        */
+        pDpa->stats.rx_missed_errors = 0; /* receiver missed packet    */
+
+        /* detailed tx_errors */
+        pDpa->stats.tx_aborted_errors = 0;
+        pDpa->stats.tx_carrier_errors = 0;
+        pDpa->stats.tx_fifo_errors = 0;
+        pDpa->stats.tx_heartbeat_errors = 0;
+        pDpa->stats.tx_window_errors = 0;
+
+        return ((struct enet_statistics *)&(pDpa->stats));
+    }
+    return 0;
+}
+
+static int RCioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+    RCuser_struct RCuser;
+    PDPA pDpa = dev->priv;
+
+#if RCDEBUG
+    printk("RCioctl: cmd = 0x%x\n", cmd);
+#endif
+    switch (cmd)  {
+        case RCU_PROTOCOL_REV:
+             /*
+              * Assign user protocol revision, to tell user-level
+              * controller program whether or not it's in sync.
+              */
+             rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV;
+             break;
+  
+
+        case RCU_COMMAND:
+        {
+            if(copy_from_user(&RCuser, rq->ifr_data, sizeof(RCuser)))
+               return -EFAULT;
+        
+#ifdef RCDEBUG
+            printk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd);
+#endif
+  
+            switch(RCuser.cmd)
+            {
+                case RCUC_GETFWVER:
+                    printk("RC GETFWVER\n");
+                    RCUD_GETFWVER = &RCuser.RCUS_GETFWVER;
+                    RCGetFirmwareVer(pDpa->id, (PU8) &RCUD_GETFWVER->FirmString, NULL);
+                    break;
+                case RCUC_GETINFO:
+                    printk("RC GETINFO\n");
+                    RCUD_GETINFO = &RCuser.RCUS_GETINFO;
+                    RCUD_GETINFO -> mem_start = dev->base_addr;
+                    RCUD_GETINFO -> mem_end = dev->base_addr + 32768;
+                    RCUD_GETINFO -> base_addr = pDpa->pci_addr;
+                    RCUD_GETINFO -> irq = dev->irq;
+                    break;
+                case RCUC_GETIPANDMASK:
+                    printk("RC GETIPANDMASK\n");
+                    RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK;
+                    RCGetRavlinIPandMask(pDpa->id, (PU32) &RCUD_GETIPANDMASK->IpAddr,
+                        (PU32) &RCUD_GETIPANDMASK->NetMask, NULL);
+                    break;
+                case RCUC_GETLINKSTATISTICS:
+                    printk("RC GETLINKSTATISTICS\n");
+                    RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS;
+                    RCGetLinkStatistics(pDpa->id, (P_RCLINKSTATS) &RCUD_GETLINKSTATISTICS->StatsReturn, NULL);
+                    break;
+                case RCUC_GETLINKSTATUS:
+                    printk("RC GETLINKSTATUS\n");
+                    RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS;
+                    RCGetLinkStatus(pDpa->id, (PU32) &RCUD_GETLINKSTATUS->ReturnStatus, NULL);
+                    break;
+                case RCUC_GETMAC:
+                    printk("RC GETMAC\n");
+                    RCUD_GETMAC = &RCuser.RCUS_GETMAC;
+                    RCGetMAC(pDpa->id, (PU8) &RCUD_GETMAC->mac, NULL);
+                    break;
+                case RCUC_GETSPEED:
+                    printk("RC GETSPEED\n");
+                    if (!(dev->flags & IFF_UP))    
+                    {
+                        printk("RCioctl, GETSPEED error: interface down\n");
+                        return -ENODATA;
+                    }
+                    RCUD_GETSPEED = &RCuser.RCUS_GETSPEED;
+                    RCGetLinkSpeed(pDpa->id, (PU32) &RCUD_GETSPEED->LinkSpeedCode, NULL);
+                    printk("RC speed = 0x%ld\n", RCUD_GETSPEED->LinkSpeedCode);
+                    break;
+                default:
+                    printk("RC command default\n");
+                    RCUD_DEFAULT = &RCuser.RCUS_DEFAULT;
+                    RCUD_DEFAULT -> rc = 0x11223344;
+                    break;
+            }
+            copy_to_user(rq->ifr_data, &RCuser, sizeof(RCuser));
+            break;
+        }   /* RCU_COMMAND */ 
+
+        default:
+            printk("RC default\n");
+            rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678;
+            break;
+    }
+    return 0;
+}
+
+static int RCconfig(struct device *dev, struct ifmap *map)
+{
+     /*
+      * To be completed ...
+      */
+      printk("rc: RCconfig\n");
+      return 0;
+      if (dev->flags & IFF_UP)    /* can't act on a running interface */
+           return -EBUSY;
+
+     /* Don't allow changing the I/O address */
+     if (map->base_addr != dev->base_addr) {
+          printk(KERN_WARNING "RC pci45: Change I/O address not implemented\n");
+          return -EOPNOTSUPP;
+     }
+     return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+     PDPA pDpa;
+     struct device *next;
+
+
+#ifdef RCDEBUG
+     printk("rc: RC cleanup_module\n");
+     printk("rc: root_RCdev = 0x%x\n", (uint)root_RCdev);
+#endif
+
+
+     while (root_RCdev)
+     {
+          pDpa = (PDPA) root_RCdev->priv;
+#ifdef RCDEBUG
+          printk("rc: cleanup 0x%08X\n", (uint)root_RCdev);
+#endif
+          printk("Adapter reset: 0x%x\n", RCResetAdapter(pDpa->id));
+          unregister_netdev(root_RCdev);
+          next = pDpa->next;
+
+          vfree((unsigned long *)root_RCdev->base_addr); 
+          free_irq( root_RCdev->irq, root_RCdev );
+          kfree(root_RCdev);
+          root_RCdev = next;
+     }
+}
+#endif
+
+
+static int
+RC_allocate_and_post_buffers(struct device *dev, int numBuffers)
+{
+
+     int i;
+     PDPA pDpa = (PDPA)dev->priv;
+     PU32 p;
+     psingleB pB;
+     struct sk_buff *skb;
+     RC_RETURN status;
+
+     if (!numBuffers)
+          return 0;
+     else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
+     {
+#ifdef RCDEBUG
+          printk("rc: Too many buffers requested!\n");
+          printk("rc: attempting to allocate only 32 buffers\n");
+#endif
+          numBuffers = 32;
+     }
+    
+     p = (PU32) kmalloc(sizeof(U32) + numBuffers*sizeof(singleB), GFP_ATOMIC);
+
+#ifdef RCDEBUG
+     printk("rc: TCB = 0x%x\n", (uint)p);
+#endif
+
+     if (!p)
+     {
+          printk("rc: RCopen: unable to allocate TCB\n");
+          return 0;
+     }
+
+     p[0] = 0;                              /* Buffer Count */
+     pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */
+
+#ifdef RCDEBUG
+     printk("rc: p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint)p[0], (uint)p, (uint)pB);
+     printk("rc: pB = 0x%x\n", (uint)pB);
+#endif
+
+     for (i=0; i<numBuffers; i++)
+     {
+          skb = dev_alloc_skb(MAX_ETHER_SIZE+2);
+          if (!skb)
+          {
+               printk("rc: Doh! RCopen: unable to allocate enough skbs!\n");
+               if (*p != 0)        /* did we allocate any buffers at all? */
+               {
+#ifdef RCDEBUG
+                    printk("rc: will post only %d buffers \n", (uint)(*p));
+#endif
+                    break;
+               }
+               else 
+               {
+                    kfree(p);    /* Free the TCB */
+                    return 0;
+               }
+          }
+#ifdef RCDEBUG
+          printk("post 0x%x\n", (uint)skb);
+#endif
+          skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
+          pB->context = (U32)skb;
+          pB->scount = 1;        /* segment count */
+          pB->size = MAX_ETHER_SIZE;
+          pB->addr = (U32)skb->data;
+          p[0]++;
+          pB++;
+     }
+
+     if ( (status = RCPostRecvBuffers(pDpa->id, (PRCTCB)p )) != RC_RTN_NO_ERROR)
+     {
+          printk("rc: Post buffer failed with error code 0x%x!\n", status);
+          pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */
+          while(p[0])
+          {
+               skb = (struct sk_buff *)pB->context;
+#ifdef RCDEBUG
+               printk("rc: freeing 0x%x\n", (uint)skb);
+#endif
+               dev_kfree_skb(skb);
+               p[0]--;
+               pB++;
+          }
+#ifdef RCDEBUG
+           printk("rc: freed all buffers, p[0] = %ld\n", p[0]);
+#endif
+     }
+     kfree(p);
+     return(p[0]);                /* return the number of posted buffers */
+}
index 13a020869b0e1b4f7493a98b189d49dd6bf11269..118a0e1ec53c393ba48e70f318504262ef3493a0 100644 (file)
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_INET
-/* Entire module is for IP only */
 #include <linux/module.h>
-
 #include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_INET
+/* Entire module is for IP only */
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/string.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/termios.h>
@@ -72,7 +74,6 @@
 #include <net/tcp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <linux/errno.h>
 #include <linux/timer.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -758,4 +759,52 @@ __initfunc(void slhc_install(void))
 }
 
 #endif /* MODULE */
+#else /* CONFIG_INET */
+EXPORT_SYMBOL(slhc_init);
+EXPORT_SYMBOL(slhc_free);
+EXPORT_SYMBOL(slhc_remember);
+EXPORT_SYMBOL(slhc_compress);
+EXPORT_SYMBOL(slhc_uncompress);
+EXPORT_SYMBOL(slhc_toss);
+
+int
+slhc_toss(struct slcompress *comp)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss");
+  return -EINVAL;
+}
+int
+slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress");
+  return -EINVAL;
+}
+int
+slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
+       unsigned char *ocp, unsigned char **cpp, int compress_cid)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress");
+  return -EINVAL;
+}
+
+int
+slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
+  return -EINVAL;
+}
+
+void
+slhc_free(struct slcompress *comp)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
+  return;
+}
+struct slcompress *
+slhc_init(int rslots, int tslots)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
+  return NULL;
+}
+
 #endif /* CONFIG_INET */
index fead49fcb6bdaded4d33f37d048aa972126e6d07..53e3b211509858a1a247ba1b3c587f1fb8062988 100644 (file)
@@ -64,18 +64,7 @@ static const int multicast_filter_limit = 32;
 
 #define PKT_BUF_SZ             1536                    /* Size of each temporary Rx buffer.*/
 
-/* Include files, designed to support most kernel versions 2.0.0 and later. */
-#include <linux/version.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/timer.h>
@@ -115,7 +104,6 @@ static const int multicast_filter_limit = 32;
 #define RUN_AT(x) (jiffies + (x))
 
 #if (LINUX_VERSION_CODE >= 0x20100)
-char kernel_version[] = UTS_RELEASE;
 #else
 #ifndef __alpha__
 #define ioremap vremap
index 3411fd1892d6189eb9afff90e7f4f2b647904303..410121e2eaf068c7d7872abec0d2bb9edb932593 100644 (file)
@@ -63,17 +63,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  ((2000*HZ)/1000)
 
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
-#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -93,13 +83,10 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #include <linux/skbuff.h>
 
 /* Kernel compatibility defines, most common to the PCCard package. */
-#include <linux/version.h>             /* Evil, but neccessary */
+#include <linux/version.h>             /* Evil and unneccessary */
 
 #define RUN_AT(x) (jiffies + (x))
 
-#if (LINUX_VERSION_CODE >= 0x20100)
-char kernel_version[] = UTS_RELEASE;
-#endif
 #if (LINUX_VERSION_CODE < 0x20123)
 #define test_and_set_bit(val, addr) set_bit(val, addr)
 #endif
@@ -214,7 +201,7 @@ See Packet Engines confidential appendix (prototype chips only).
 static void yellowfin_timer(unsigned long data);
 
 enum capability_flags {HasMII=1, FullTxStatus=2};
-struct chip_info {
+static struct chip_info {
        u16     vendor_id, device_id, device_id_mask, pci_flags;
        const char *name;
        void (*media_timer)(unsigned long data);
index 32188af9e7379835c683d00b24b01a9e8cd90180..77760949cb5023bd913821903fb5dfc47373f7c6 100644 (file)
@@ -54,8 +54,10 @@ static long read_polled(struct parport *port, char *buf,
        unsigned int count = 0;
        unsigned char z=0;
        unsigned char Byte=0;
+       unsigned long igiveupat=jiffies+5*HZ;
 
-       for (i=0; ; i++) {
+       for (i=0; time_before(jiffies, igiveupat); i++) {
+              /* if(current->need_resched) schedule(); */
                parport_write_control(port, parport_read_control(port) | 2); /* AutoFeed high */
                if (parport_wait_peripheral(port, 0x40, 0)) {
 #ifdef DEBUG_PROBE
index 0bd37f65f27f499a103500c93d09fdde70398fe0..0f3daef14b570f53097fe4fd104dd4c56f3f2aee 100644 (file)
@@ -19,6 +19,7 @@ mainmenu_option next_comment
 comment 'SCSI low-level drivers'
 
 dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
+dep_tristate 'ACARD SCSI support' CONFIG_SCSI_ACARD $CONFIG_SCSI
 dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
@@ -34,19 +35,21 @@ fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
 dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
+dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI
+
 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
 if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then
     bool '  Omit FlashPoint support' CONFIG_SCSI_OMIT_FLASHPOINT
 fi
 dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
-dep_tristate 'EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
-dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
 dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support' CONFIG_SCSI_EATA $CONFIG_SCSI
   if [ "$CONFIG_SCSI_EATA" != "n" ]; then
     bool '  enable tagged command queueing' CONFIG_SCSI_EATA_TAGGED_QUEUE
     bool '  enable elevator sorting' CONFIG_SCSI_EATA_LINKED_COMMANDS
     int  '  maximum number of queued commands' CONFIG_SCSI_EATA_MAX_TAGS 16
   fi
+dep_tristate 'EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
+dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
 dep_tristate 'Future Domain 16xx SCSI/AHA 2920 support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
 if [ "$CONFIG_MCA" = "y" ]; then
   if [ "$CONFIG_SCSI" = "y" ]; then
@@ -68,6 +71,9 @@ if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
                "Port CONFIG_SCSI_G_NCR5380_PORT \
                Memory CONFIG_SCSI_G_NCR5380_MEM" Port
 fi
+if [ "$CONFIG_PCI" = "y" ]; then
+  dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI
+fi
 dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
   dep_tristate 'NCR53c7,8xx SCSI support'  CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI
@@ -100,6 +106,9 @@ if [ "$CONFIG_MCA" = "y" ]; then
      bool '  Reset SCSI-devices at boottime' CONFIG_IBMMCA_SCSI_DEV_RESET
   fi
 fi
+if [ "$CONFIG_MCA" = "y" ]; then
+  dep_tristate 'NCR MCA 53C9x SCSI support' CONFIG_SCSI_MCA_53C9X $CONFIG_SCSI
+fi
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
 dep_tristate 'PCI2000 support' CONFIG_SCSI_PCI2000 $CONFIG_SCSI
 dep_tristate 'PCI2220i support' CONFIG_SCSI_PCI2220I $CONFIG_SCSI
@@ -107,6 +116,7 @@ dep_tristate 'PSI240i support' CONFIG_SCSI_PSI240I $CONFIG_SCSI
 dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
   dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
+  dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
 fi
 dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
index f3be0cf18015dcebc95f8f3d3787a0bd1b3ad2d5..a27394de6901bb3198f5b3cd3f8bcb834399ac2f 100644 (file)
@@ -195,6 +195,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_MCA_53C9X),y)
+L_OBJS += NCR53C9x.o mca_53c9x.o
+else
+  ifeq ($(CONFIG_SCSI_MCA_53C9X),m)
+  M_OBJS += NCR53C9x.o mca_53c9x.o
+  endif
+endif
+
 ifeq ($(CONFIG_CYBERSTORM_SCSI),y)
 L_OBJS += NCR53C9x.o cyberstorm.o
 else
@@ -276,6 +284,29 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_ACARD),y)
+L_OBJS += atp870u.o
+else
+  ifeq ($(CONFIG_SCSI_ACARD),m)
+  M_OBJS += atp870u.o
+  endif
+endif
+
+ifeq ($(CONFIG_SCSI_INITIO),y)
+L_OBJS += initio.o
+else
+  ifeq ($(CONFIG_SCSI_INITIO),m)
+  M_OBJS += initio.o
+  endif
+endif
+
+ifeq ($(CONFIG_SCSI_QLOGIC_FC),y)
+L_OBJS += qlogicfc.o 
+else
+  ifeq ($(CONFIG_SCSI_QLOGIC_FC),m)   
+  M_OBJS += qlogicfc.o 
+  endif
+endif
 
 ifeq ($(CONFIG_SCSI_AHA152X),y)
 L_OBJS += aha152x.o
@@ -539,6 +570,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_MEGARAID),y)
+L_OBJS += megaraid.o
+else
+  ifeq ($(CONFIG_SCSI_MEGARAID),m)
+  M_OBJS += megaraid.o
+  endif
+endif
+
 ifeq ($(CONFIG_BLK_DEV_IDESCSI),y)
 L_OBJS += ide-scsi.o
 else
@@ -574,6 +613,15 @@ include $(TOPDIR)/Rules.make
 53c7xx.o : 53c7xx_d.h 53c7xx.c
        $(CC) $(CFLAGS) -c 53c7xx.c
 
+initio.o: ini9100u.c i91uscsi.c
+       $(CC) $(CFLAGS) -c ini9100u.c -o ini9100u.o
+       $(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o
+       $(LD) -r -o initio.o ini9100u.o i91uscsi.o
+       rm -f ini9100u.o i91uscsi.o
+
+megaraid.o: megaraid.c
+       $(CC) $(CFLAGS) -c megaraid.c
+
 scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
                scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o scsi_queue.o
        $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o \
index bba8f70de590d447d910b6a349f5ec4baa5c61c1..3aff27f322d3b2fab10dc071336327f5bc15279c 100644 (file)
@@ -1919,7 +1919,7 @@ part2:
                spin_lock_irq(&io_request_lock);
                
                if (time_after_eq(jiffies, timeout)) {
-                       printk("scsi%d: timeout at NCR5380.c:%d\n", __LINE__);
+                       printk("scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__);
                        NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
                        return -1;
                }
index f3b693255dfe58b2c5837ad5fc4b451a95afe56c..c997cba65b4b29baafe7595f5554121a0aa75e32 100644 (file)
@@ -6,6 +6,9 @@
  *
  * Most DMA dependencies put in driver specific files by 
  * Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * Set up to use GETREG/SETREG (preprocessor macros in NCR53c9x.h) by
+ * Tymm Twillman (tymm@coe.missouri.edu)
  */
 
 /* TODO:
@@ -27,6 +30,7 @@
 #include <linux/blk.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+
 #include <linux/init.h>
 
 #include "scsi.h"
@@ -297,7 +301,7 @@ extern inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
        esp->espcmdlog[esp->espcmdent] = cmd;
        esp->espcmdent = (esp->espcmdent + 1) & 31;
 #endif
-       eregs->esp_cmd = cmd;
+       SETREG(eregs->esp_cmnd, cmd);
 }
 
 /* How we use the various Linux SCSI data structures for operation.
@@ -400,7 +404,7 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
         */
        esp->max_period = ((35 * esp->ccycle) / 1000);
        if(esp->erev == fast) {
-               version = eregs->esp_uid;
+               version = GETREG(eregs->esp_uid);
                family_code = (version & 0xf8) >> 3;
 #ifdef SYMBIOS_HACK
                if (version == 0 && family_code == 0)
@@ -432,25 +436,25 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
        }
 
        /* Reload the configuration registers */
-       eregs->esp_cfact = esp->cfact;
-       eregs->esp_stp   = 0;
-       eregs->esp_soff  = 0;
-       eregs->esp_timeo = esp->neg_defp;
+       SETREG(eregs->esp_cfact, esp->cfact);
+       SETREG(eregs->esp_stp, 0);
+       SETREG(eregs->esp_soff, 0);
+       SETREG(eregs->esp_timeo, esp->neg_defp);
        esp->max_period = (esp->max_period + 3)>>2;
        esp->min_period = (esp->min_period + 3)>>2;
 
-       eregs->esp_cfg1  = esp->config1;
+       SETREG(eregs->esp_cfg1, esp->config1);
        switch(esp->erev) {
        case esp100:
                /* nothing to do */
                break;
        case esp100a:
-               eregs->esp_cfg2 = esp->config2;
+               SETREG(eregs->esp_cfg2, esp->config2);
                break;
        case esp236:
                /* Slow 236 */
-               eregs->esp_cfg2 = esp->config2;
-               eregs->esp_cfg3 = esp->config3[0];
+               SETREG(eregs->esp_cfg2, esp->config2);
+               SETREG(eregs->esp_cfg3, esp->config3[0]);
                break;
        case fashme:
                esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
@@ -458,7 +462,7 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
        case fas216:        
        case fas236:
                /* Fast 236 or HME */
-               eregs->esp_cfg2 = esp->config2;
+               SETREG(eregs->esp_cfg2, esp->config2);
                for(i=0; i<8; i++) {
                        if(esp->erev == fashme)
                                esp->config3[i] |=
@@ -466,7 +470,7 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
                        else
                                esp->config3[i] |= ESP_CONFIG3_FCLK;
                }
-               eregs->esp_cfg3 = esp->config3[0];
+               SETREG(eregs->esp_cfg3, esp->config3[0]);
                if(esp->erev == fashme) {
                        esp->radelay = 80;
                } else {
@@ -478,10 +482,10 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
                break;
        case fas100a:
                /* Fast 100a */
-               eregs->esp_cfg2 = esp->config2;
+               SETREG(eregs->esp_cfg2, esp->config2);
                for(i=0; i<8; i++)
                        esp->config3[i] |= ESP_CONFIG3_FCLOCK;
-               eregs->esp_cfg3 = esp->config3[0];
+               SETREG(eregs->esp_cfg3, esp->config3[0]);
                esp->radelay = 32;
                break;
        default:
@@ -490,7 +494,7 @@ static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
        };
 
        /* Eat any bitrot in the chip */
-       trash = eregs->esp_intrpt;
+       trash = GETREG(eregs->esp_intrpt);
        udelay(100);
 }
 
@@ -507,13 +511,13 @@ inline void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
        esp_reset_esp(esp, eregs);
 
        /* Reset the SCSI bus, but tell ESP not to generate an irq */
-       eregs->esp_cfg1 |= ESP_CONFIG1_SRRDISAB;
+       SETREG(eregs->esp_cfg1, GETREG(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB);
        esp_cmd(esp, eregs, ESP_CMD_RS);
        udelay(400);
-       eregs->esp_cfg1 = esp->config1;
+       SETREG(eregs->esp_cfg1, esp->config1);
 
        /* Eat any bitrot in the chip and we are done... */
-       trash = eregs->esp_intrpt;
+       trash = GETREG(eregs->esp_intrpt);
 }
 
 /* Allocate structure and insert basic data such as SCSI chip frequency
@@ -650,19 +654,21 @@ void esp_initialize(struct NCR_ESP *esp)
        /* Probe the revision of this esp */
        esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
        esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
-       eregs->esp_cfg2 = esp->config2;
+       SETREG(eregs->esp_cfg2, esp->config2);
 #ifndef SYMBIOS_HACK
-       if((eregs->esp_cfg2 & ~(ESP_CONFIG2_MAGIC)) !=
+       if((GETREG(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) !=
           (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
                printk("NCR53C90(esp100) detected\n");
                esp->erev = esp100;
        } else {
 #endif
-               eregs->esp_cfg2 = esp->config2 = 0;
-               eregs->esp_cfg3 = 0;
-               eregs->esp_cfg3 = esp->config3[0] = 5;
+               esp->config2 = 0;
+               SETREG(eregs->esp_cfg2, esp->config2);
+               SETREG(eregs->esp_cfg3, 0);
+               esp->config3[0] = 5;
+               SETREG(eregs->esp_cfg3, esp->config3[0]);
 #ifndef SYMBIOS_HACK
-               if(eregs->esp_cfg3 != 5) {
+               if(GETREG(eregs->esp_cfg3) != 5) {
                        printk("NCR53C90A(esp100a) detected\n");
                        esp->erev = esp100a;
                } else {
@@ -673,19 +679,21 @@ void esp_initialize(struct NCR_ESP *esp)
                        
                        for(target=0; target<8; target++)
                                esp->config3[target] = 0;
-                       eregs->esp_cfg3 = 0;
+                       SETREG(eregs->esp_cfg3, 0);
 #ifndef SYMBIOS_HACK
                        if(ccf > ESP_CCF_F5) {
 #endif
                                printk("NCR53C9XF(espfast) detected\n");
                                esp->erev = fast;
-                               eregs->esp_cfg2 = esp->config2 = 0;
+                               esp->config2 = 0;
+                               SETREG(eregs->esp_cfg2, esp->config2);
                                esp->sync_defp = SYNC_DEFP_FAST;
 #ifndef SYMBIOS_HACK
                        } else {
                                printk("NCR53C9x(esp236) detected\n");
                                esp->erev = esp236;
-                               eregs->esp_cfg2 = esp->config2 = 0;
+                               esp->config2 = 0;
+                               SETREG(eregs->esp_cfg2, esp->config2);
                        }
                }
 #endif
@@ -1193,14 +1201,14 @@ after_nego_msg_built:
 
        /* HME sucks... */
        if(esp->erev == fashme)
-               eregs->esp_busid = (target & 0xf) |
-                       (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
+               SETREG(eregs->esp_busid, (target & 0xf) |
+                       (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT));
        else
-               eregs->esp_busid = (target & 7);
-       eregs->esp_soff = SDptr->sync_max_offset;
-       eregs->esp_stp  = SDptr->sync_min_period;
+               SETREG(eregs->esp_busid, (target & 7));
+       SETREG(eregs->esp_soff, SDptr->sync_max_offset);
+       SETREG(eregs->esp_stp, SDptr->sync_min_period);
        if(esp->erev > esp100a)
-               eregs->esp_cfg3 = esp->config3[target];
+               SETREG(eregs->esp_cfg3, esp->config3[target]);
 
        i = (cmdp - esp->esp_command);
 
@@ -1209,7 +1217,7 @@ after_nego_msg_built:
                int j = 0;
 
                for(;j<i;j++)
-                       eregs->esp_fdata = esp->esp_command[j];
+                       SETREG(eregs->esp_fdata, esp->esp_command[j]);
                the_esp_command &= ~ESP_CMD_DMA;
 
                /* Tell ESP to "go". */
@@ -1219,16 +1227,16 @@ after_nego_msg_built:
                        esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* Grrr! */
 
                        /* Set up the HME counters */
-                       eregs->esp_tclow = i;
-                       eregs->esp_tcmed = 0;
-                       eregs->fas_rlo = 0;
-                       eregs->fas_rhi = 0;
+                       SETREG(eregs->esp_tclow, i);
+                       SETREG(eregs->esp_tcmed, 0);
+                       SETREG(eregs->fas_rlo, 0);
+                       SETREG(eregs->fas_rhi, 0);
                        esp_cmd(esp, eregs, the_esp_command);
                        esp->dma_init_write(esp, esp->esp_command_dvma, 16);
                } else {
                        /* Set up the ESP counters */
-                       eregs->esp_tclow = i;
-                       eregs->esp_tcmed = 0;
+                       SETREG(eregs->esp_tclow, i);
+                       SETREG(eregs->esp_tcmed, 0);
                        esp->dma_init_write(esp, esp->esp_command_dvma, i);
 
                        /* Tell ESP to "go". */
@@ -1341,7 +1349,8 @@ static inline void esp_dump_state(struct NCR_ESP *esp,
        ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
                esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
        ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
-               esp->esp_id, eregs->esp_status, eregs->esp_sstep, eregs->esp_intrpt));
+               esp->esp_id, GETREG(eregs->esp_status), 
+               GETREG(eregs->esp_sstep), GETREG(eregs->esp_intrpt)));
 #ifdef DEBUG_ESP_CMDS
        printk("esp%d: last ESP cmds [", esp->esp_id);
        i = (esp->espcmdent - 1) & 31;
@@ -1549,20 +1558,23 @@ static inline void hme_fifo_hwbug_workaround(struct NCR_ESP *esp,
                return;
        } else {
                unsigned long count = 0;
-               unsigned long fcnt = eregs->esp_fflags & ESP_FF_FBYTES;
+               unsigned long fcnt = GETREG(eregs->esp_fflags) & ESP_FF_FBYTES;
 
                /* The HME stores bytes in multiples of 2 in the fifo. */
                ESPHME(("hme_fifo[fcnt=%d", (int)fcnt));
                while(fcnt) {
-                       esp->hme_fifo_workaround_buffer[count++] = eregs->esp_fdata;
-                       esp->hme_fifo_workaround_buffer[count++] = eregs->esp_fdata;
+                       esp->hme_fifo_workaround_buffer[count++] = 
+                        GETREG(eregs->esp_fdata);
+                       esp->hme_fifo_workaround_buffer[count++] = 
+                        GETREG(eregs->esp_fdata);
                        ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1]));
                        fcnt--;
                }
-               if(eregs->esp_status2 & ESP_STAT2_F1BYTE) {
+               if(GETREG(eregs->esp_status2) & ESP_STAT2_F1BYTE) {
                        ESPHME(("<poke_byte>"));
-                       eregs->esp_fdata = 0;
-                       esp->hme_fifo_workaround_buffer[count++] = eregs->esp_fdata;
+                       SETREG(eregs->esp_fdata, 0);
+                       esp->hme_fifo_workaround_buffer[count++] = 
+                        GETREG(eregs->esp_fdata);
                        ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1]));
                        ESPHME(("CMD_FLUSH"));
                        esp_cmd(esp, eregs, ESP_CMD_FLUSH);
@@ -1579,8 +1591,8 @@ static inline void hme_fifo_push(struct NCR_ESP *esp, struct ESP_regs *eregs,
 {
        esp_cmd(esp, eregs, ESP_CMD_FLUSH);
        while(count) {
-               eregs->esp_fdata = *bytes++;
-               eregs->esp_fdata = 0;
+               SETREG(eregs->esp_fdata, *bytes++);
+               SETREG(eregs->esp_fdata, 0);
                count--;
        }
 }
@@ -1596,7 +1608,7 @@ static inline int skipahead1(struct NCR_ESP *esp, struct ESP_regs *eregs,
 
        if(esp->dma_irq_p(esp)) {
                /* Yes, we are able to save an interrupt. */
-               esp->sreg = eregs->esp_status;
+               esp->sreg = GETREG(eregs->esp_status);
                if(esp->erev == fashme) {
                        /* This chip is really losing. */
                        ESPHME(("HME["));
@@ -1608,7 +1620,7 @@ static inline int skipahead1(struct NCR_ESP *esp, struct ESP_regs *eregs,
                        ESPHME(("fifo_workaround]"));
                        hme_fifo_hwbug_workaround(esp, eregs);
                }
-               esp->ireg = eregs->esp_intrpt;
+               esp->ireg = GETREG(eregs->esp_intrpt);
                esp->sreg &= ~(ESP_STAT_INTR);
                if(!(esp->ireg & ESP_INTR_SR))
                        return 0;
@@ -1630,7 +1642,7 @@ static inline int skipahead2(struct NCR_ESP *esp,
                return 0;
        if(esp->dma_irq_p(esp)) {
                /* Yes, we are able to save an interrupt. */
-               esp->sreg = eregs->esp_status;
+               esp->sreg = GETREG(eregs->esp_status);
                if(esp->erev == fashme) {
                        /* This chip is really losing. */
                        ESPHME(("HME["));
@@ -1643,7 +1655,7 @@ static inline int skipahead2(struct NCR_ESP *esp,
                        ESPHME(("fifo_workaround]"));
                        hme_fifo_hwbug_workaround(esp, eregs);
                }
-               esp->ireg = eregs->esp_intrpt;
+               esp->ireg = GETREG(eregs->esp_intrpt);
                esp->sreg &= ~(ESP_STAT_INTR);
                if(!(esp->ireg & ESP_INTR_SR))
                        return 0;
@@ -1658,18 +1670,18 @@ static inline int skipahead2(struct NCR_ESP *esp,
 /* Misc. esp helper routines. */
 static inline void esp_setcount(struct ESP_regs *eregs, int cnt, int hme)
 {
-       eregs->esp_tclow = (cnt & 0xff);
-       eregs->esp_tcmed = ((cnt >> 8) & 0xff);
+       SETREG(eregs->esp_tclow, (cnt & 0xff));
+       SETREG(eregs->esp_tcmed, ((cnt >> 8) & 0xff));
        if(hme) {
-               eregs->fas_rlo = 0;
-               eregs->fas_rhi = 0;
+               SETREG(eregs->fas_rlo, 0);
+               SETREG(eregs->fas_rhi, 0);
        }
 }
 
 static inline int esp_getcount(struct ESP_regs *eregs)
 {
-       return (((eregs->esp_tclow)&0xff) |
-               (((eregs->esp_tcmed)&0xff) << 8));
+       return (((GETREG(eregs->esp_tclow))&0xff) |
+               (((GETREG(eregs->esp_tcmed))&0xff) << 8));
 }
 
 static inline int fcount(struct NCR_ESP *esp, struct ESP_regs *eregs)
@@ -1677,7 +1689,7 @@ static inline int fcount(struct NCR_ESP *esp, struct ESP_regs *eregs)
        if(esp->erev == fashme)
                return esp->hme_fifo_workaround_count;
        else
-               return eregs->esp_fflags & ESP_FF_FBYTES;
+               return GETREG(eregs->esp_fflags) & ESP_FF_FBYTES;
 }
 
 static inline int fnzero(struct NCR_ESP *esp, struct ESP_regs *eregs)
@@ -1685,7 +1697,7 @@ static inline int fnzero(struct NCR_ESP *esp, struct ESP_regs *eregs)
        if(esp->erev == fashme)
                return 0;
        else
-               return eregs->esp_fflags & ESP_FF_ONOTZERO;
+               return GETREG(eregs->esp_fflags) & ESP_FF_ONOTZERO;
 }
 
 /* XXX speculative nops unnecessary when continuing amidst a data phase
@@ -1719,8 +1731,8 @@ static inline int esp100_sync_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs,
 {
        /* Do not touch this piece of code. */
        if((!(esp->erev == esp100)) ||
-          (!(sreg_datainp((esp->sreg = eregs->esp_status)) && !fifocnt) &&
-           !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {
+          (!(sreg_datainp((esp->sreg = GETREG(eregs->esp_status))) && !fifocnt)
+           && !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {
                if(sp->SCp.phase == in_dataout)
                        esp_cmd(esp, eregs, ESP_CMD_FLUSH);
                return 0;
@@ -1747,7 +1759,7 @@ static inline int esp100_reconnect_hwbug(struct NCR_ESP *esp,
 
        if(esp->erev != esp100)
                return 0;
-       junk = eregs->esp_intrpt;
+       junk = GETREG(eregs->esp_intrpt);
 
        if(junk & ESP_INTR_SR)
                return 1;
@@ -1772,7 +1784,7 @@ static inline int reconnect_target(struct NCR_ESP *esp, struct ESP_regs *eregs)
                 */
                targ = esp->hme_fifo_workaround_buffer[0];
        } else {
-               it = eregs->esp_fdata;
+               it = GETREG(eregs->esp_fdata);
                if(!(it & me))
                        return -1;
                it &= ~me;
@@ -1796,7 +1808,7 @@ static inline int reconnect_lun(struct NCR_ESP *esp, struct ESP_regs *eregs)
        if(esp->erev == fashme)
                lun = esp->hme_fifo_workaround_buffer[1];
        else
-               lun = eregs->esp_fdata;
+               lun = GETREG(eregs->esp_fdata);
        if(esp->sreg & ESP_STAT_PERR)
                return 0;
        if((lun & 0x40) || !(lun & 0x80))
@@ -1811,13 +1823,13 @@ static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs,
                               Scsi_Cmnd *sp)
 {
        Scsi_Device *dp = sp->device;
-       eregs->esp_soff = dp->sync_max_offset;
-       eregs->esp_stp  = dp->sync_min_period;
+       SETREG(eregs->esp_soff, dp->sync_max_offset);
+       SETREG(eregs->esp_stp, dp->sync_min_period);
        if(esp->erev > esp100a)
-               eregs->esp_cfg3 = esp->config3[sp->target];
+               SETREG(eregs->esp_cfg3, esp->config3[sp->target]);
        if(esp->erev == fashme)
-               eregs->esp_busid = (sp->target & 0xf) |
-                       (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
+               SETREG(eregs->esp_busid, (sp->target & 0xf) |
+                       (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT));
        esp->current_SC = sp;
 }
 
@@ -1839,7 +1851,8 @@ static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 static inline int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
        /* Must be very careful with the fifo on the HME */
-       if((esp->erev != fashme) || !(eregs->esp_status2 & ESP_STAT2_FEMPTY))
+       if((esp->erev != fashme) || !(GETREG(eregs->esp_status2) & 
+        ESP_STAT2_FEMPTY))
                esp_cmd(esp, eregs, ESP_CMD_FLUSH);
        esp_maybe_nop(esp, eregs);
        esp_cmd(esp, eregs, ESP_CMD_TI);
@@ -1961,7 +1974,7 @@ static inline int esp_do_data_finale(struct NCR_ESP *esp,
         * will move and count 16-bit quantities during wide data.
         * SMCC _and_ Qlogic can both bite me.
         */
-       fifocnt = eregs->esp_fflags & ESP_FF_FBYTES;
+       fifocnt = GETREG(eregs->esp_fflags) & ESP_FF_FBYTES;
        if(esp->erev != fashme)
                ecount = esp_getcount(eregs);
        bytes_sent = esp->current_transfer_size;
@@ -2360,16 +2373,18 @@ static int esp_do_phase_determine(struct NCR_ESP *esp,
                        if(esp->do_pio_cmds){
                                esp_advance_phase(SCptr, in_status);
                                esp_cmd(esp, eregs, ESP_CMD_ICCSEQ);
-                               while(!(esp->eregs->esp_status & ESP_STAT_INTR));
-                               esp->esp_command[0] = eregs->esp_fdata;
-                               while(!(esp->eregs->esp_status & ESP_STAT_INTR));
-                               esp->esp_command[1] = eregs->esp_fdata;
+                               while(!(GETREG(esp->eregs->esp_status)
+                                & ESP_STAT_INTR));
+                               esp->esp_command[0] = GETREG(eregs->esp_fdata);
+                               while(!(GETREG(esp->eregs->esp_status)
+                                & ESP_STAT_INTR));
+                               esp->esp_command[1] = GETREG(eregs->esp_fdata);
                        } else {                                
                                if(esp->erev != fashme) {
                                        esp->esp_command[0] = 0xff;
                                        esp->esp_command[1] = 0xff;
-                                       eregs->esp_tclow = 2;
-                                       eregs->esp_tcmed = 0;
+                                       SETREG(eregs->esp_tclow, 2);
+                                       SETREG(eregs->esp_tcmed, 0);
                                        esp->dma_init_read(esp, esp->esp_command_dvma, 2);
                                        esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ);
                                } else {
@@ -2456,11 +2471,11 @@ static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs)
        int cmd_bytes_sent, fcnt;
 
        if(esp->erev != fashme)
-               esp->seqreg = (eregs->esp_sstep & ESP_STEP_VBITS);
+               esp->seqreg = (GETREG(eregs->esp_sstep) & ESP_STEP_VBITS);
        if(esp->erev == fashme)
                fcnt = esp->hme_fifo_workaround_count;
        else
-               fcnt = (eregs->esp_fflags & ESP_FF_FBYTES);
+               fcnt = (GETREG(eregs->esp_fflags) & ESP_FF_FBYTES);
        cmd_bytes_sent = esp->dma_bytes_sent(esp, fcnt);
        if(esp->dma_invalidate)
                esp->dma_invalidate(esp);
@@ -2695,9 +2710,9 @@ static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs)
        esp_print_seqreg(esp->seqreg);
        printk("\n");
        printk("esp%d: New -- ", esp->esp_id);
-       esp->sreg = eregs->esp_status;
-       esp->seqreg = eregs->esp_sstep;
-       esp->ireg = eregs->esp_intrpt;
+       esp->sreg = GETREG(eregs->esp_status);
+       esp->seqreg = GETREG(eregs->esp_sstep);
+       esp->ireg = GETREG(eregs->esp_intrpt);
        esp_print_ireg(esp->ireg);
        printk(" ");
        esp_print_statreg(esp->sreg);
@@ -2931,10 +2946,11 @@ static inline int check_multibyte_msg(struct NCR_ESP *esp,
                                        esp->config3[SCptr->target] |= bit;
                                else
                                        esp->config3[SCptr->target] &= ~bit;
-                               eregs->esp_cfg3 = esp->config3[SCptr->target];
+                               SETREG(eregs->esp_cfg3,
+                                esp->config3[SCptr->target]);
                        }
-                       eregs->esp_soff = SDptr->sync_min_period;
-                       eregs->esp_stp  = SDptr->sync_max_offset;
+                       SETREG(eregs->esp_soff, SDptr->sync_min_period);
+                       SETREG(eregs->esp_stp, SDptr->sync_max_offset);
 
                        ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
                                SDptr->sync_max_offset,
@@ -2949,15 +2965,16 @@ static inline int check_multibyte_msg(struct NCR_ESP *esp,
                        ESPSDTR(("unaccaptable sync nego, forcing async\n"));
                        SDptr->sync_max_offset = 0;
                        SDptr->sync_min_period = 0;
-                       eregs->esp_soff = 0;
-                       eregs->esp_stp = 0;
+                       SETREG(eregs->esp_soff, 0);
+                       SETREG(eregs->esp_stp, 0);
                        if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
                                if((esp->erev == fas100a) || (esp->erev == fashme))
                                        bit = ESP_CONFIG3_FAST;
                                else
                                        bit = ESP_CONFIG3_FSCSI;
                                esp->config3[SCptr->target] &= ~bit;
-                               eregs->esp_cfg3 = esp->config3[SCptr->target];
+                               SETREG(eregs->esp_cfg3,
+                                esp->config3[SCptr->target]);
                        }
                }
 
@@ -3007,7 +3024,7 @@ static inline int check_multibyte_msg(struct NCR_ESP *esp,
                                /* Pure paranoia. */
                                esp->config3[SCptr->target] &= ~(ESP_CONFIG3_EWIDE);
                        }
-                       eregs->esp_cfg3 = esp->config3[SCptr->target];
+                       SETREG(eregs->esp_cfg3, esp->config3[SCptr->target]);
 
                        /* Regardless, next try for sync transfers. */
                        build_sync_nego_msg(esp, esp->sync_defp, 15);
@@ -3038,7 +3055,8 @@ static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs)
                                message_out = MSG_PARITY_ERROR;
                                esp_cmd(esp, eregs, ESP_CMD_FLUSH);
                        } else if(esp->erev != fashme &&
-                                 (it = (eregs->esp_fflags & ESP_FF_FBYTES))!=1) {
+                                 (it = (GETREG(eregs->esp_fflags)
+                                 & ESP_FF_FBYTES))!=1) {
                                /* We certainly dropped the ball somewhere. */
                                message_out = INITIATOR_ERROR;
                                esp_cmd(esp, eregs, ESP_CMD_FLUSH);
@@ -3046,7 +3064,7 @@ static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs)
                                if(esp->erev == fashme)
                                        it = esp->hme_fifo_workaround_buffer[0];
                                else
-                                       it = eregs->esp_fdata;
+                                       it = GETREG(eregs->esp_fdata);
                                esp_advance_phase(SCptr, in_msgincont);
                        } else {
                                /* it is ok and we want it */
@@ -3055,7 +3073,7 @@ static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs)
                                                esp->hme_fifo_workaround_buffer[0];
                                else
                                        it = esp->cur_msgin[esp->msgin_ctr] =
-                                               eregs->esp_fdata;
+                                               GETREG(eregs->esp_fdata);
                                esp->msgin_ctr++;
                        }
                } else {
@@ -3096,7 +3114,7 @@ static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs)
                esp_advance_phase(SCptr, in_the_dark);
                esp->msgin_len = 0;
        }
-       esp->sreg = eregs->esp_status;
+       esp->sreg = GETREG(eregs->esp_status);
        esp->sreg &= ~(ESP_STAT_INTR);
        if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
                esp_cmd(esp, eregs, ESP_CMD_MOK);
@@ -3123,7 +3141,7 @@ static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs)
                esp->dma_init_write(esp, esp->esp_command_dvma, i);
        } else {
                esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-               eregs->esp_fdata = *esp->esp_scmdp++;
+               SETREG(eregs->esp_fdata, *esp->esp_scmdp++);
                esp->esp_scmdleft--;
                esp_cmd(esp, eregs, ESP_CMD_TI);
        }
@@ -3154,14 +3172,14 @@ static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs)
                if(esp->erev == fashme)
                        hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 1);
                else
-                       eregs->esp_fdata = esp->cur_msgout[0];
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
                esp_cmd(esp, eregs, ESP_CMD_TI);
                break;
 
        case 2:
                if(esp->do_pio_cmds){
-                       eregs->esp_fdata = esp->cur_msgout[0];
-                       eregs->esp_fdata = esp->cur_msgout[1];
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[1]);
                        esp_cmd(esp, eregs, ESP_CMD_TI);
                } else {
                        esp->esp_command[0] = esp->cur_msgout[0];
@@ -3180,10 +3198,10 @@ static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs)
        case 4:
                esp->snip = 1;
                if(esp->do_pio_cmds){
-                       eregs->esp_fdata = esp->cur_msgout[0];
-                       eregs->esp_fdata = esp->cur_msgout[1];
-                       eregs->esp_fdata = esp->cur_msgout[2];
-                       eregs->esp_fdata = esp->cur_msgout[3];
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[1]);
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[2]);
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[3]);
                        esp_cmd(esp, eregs, ESP_CMD_TI);
                } else {
                        esp->esp_command[0] = esp->cur_msgout[0];
@@ -3204,18 +3222,18 @@ static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs)
        case 5:
                esp->snip = 1;
                if(esp->do_pio_cmds){
-                       eregs->esp_fdata = esp->cur_msgout[0];
-                       eregs->esp_fdata = esp->cur_msgout[1];
-                       eregs->esp_fdata = esp->cur_msgout[2];
-                       eregs->esp_fdata = esp->cur_msgout[3];
-                       eregs->esp_fdata = esp->cur_msgout[4];
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[1]);
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[2]);
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[3]);
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[4]);
                        esp_cmd(esp, eregs, ESP_CMD_TI);
                } else {
-                       esp->esp_command[0] = esp->cur_msgout[0];
-                       esp->esp_command[1] = esp->cur_msgout[1];
-                       esp->esp_command[2] = esp->cur_msgout[2];
-                       esp->esp_command[3] = esp->cur_msgout[3];
-                       esp->esp_command[4] = esp->cur_msgout[4];
+                       SETREG(esp->esp_command[0], esp->cur_msgout[0]);
+                       SETREG(esp->esp_command[1], esp->cur_msgout[1]);
+                       SETREG(esp->esp_command[2], esp->cur_msgout[2]);
+                       SETREG(esp->esp_command[3], esp->cur_msgout[3]);
+                       SETREG(esp->esp_command[4], esp->cur_msgout[4]);
                        if(esp->erev == fashme) {
                                hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 5);
                                esp_cmd(esp, eregs, ESP_CMD_TI);
@@ -3234,7 +3252,7 @@ static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs)
                if(esp->erev == fashme) {
                        hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 1);
                } else {
-                       eregs->esp_fdata = esp->cur_msgout[0];
+                       SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
                }
                esp->msgout_len = 1;
                esp_cmd(esp, eregs, ESP_CMD_TI);
@@ -3383,11 +3401,11 @@ inline void esp_handle(struct NCR_ESP *esp)
                esp->dma_irq_entry(esp);
 
        /* Check for errors. */
-       esp->sreg = eregs->esp_status;
+       esp->sreg = GETREG(eregs->esp_status);
        esp->sreg &= (~ESP_STAT_INTR);
        if(esp->erev == fashme) {
-               esp->sreg2 = eregs->esp_status2;
-               esp->seqreg = (eregs->esp_sstep & ESP_STEP_VBITS);
+               esp->sreg2 = GETREG(eregs->esp_status2);
+               esp->seqreg = (GETREG(eregs->esp_sstep) & ESP_STEP_VBITS);
        }
        if(esp->sreg & (ESP_STAT_SPAM)) {
                /* Gross error, could be due to one of:
@@ -3461,7 +3479,7 @@ inline void esp_handle(struct NCR_ESP *esp)
                }
        }
 
-       esp->ireg = eregs->esp_intrpt;   /* Unlatch intr and stat regs */
+       esp->ireg = GETREG(eregs->esp_intrpt);   /* Unlatch intr and stat regs */
 
        /* This cannot be done until this very moment. -DaveM */
        synchronize_irq();
@@ -3674,7 +3692,7 @@ repeat:
 }
 #else
 /* For SMP we only service one ESP on the list list at our IRQ level! */
-static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 {
        struct NCR_ESP *esp;
 
index 4d2a787171a1048ffc3a536d627b502cc6cb6dd4..175b6552abdeeae82d184b3330ac070562e6c8e9 100644 (file)
@@ -1,4 +1,4 @@
-/* NCR53C9x.c:  Defines and structures for the NCR53C9x generic driver.
+/* NCR53C9x.h:  Defines and structures for the NCR53C9x generic driver.
  *
  * Originaly esp.h:  Defines and structures for the Sparc ESP 
  *                   (Enhanced SCSI Processor) driver under Linux.
@@ -6,6 +6,8 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *
  * Generalization by Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * More generalization (for i386 stuff) by Tymm Twillman (tymm@computer.org)
  */
 
 #ifndef NCR53C9X_H
 /* All the ESP registers are one byte each and are accessed longwords
  * apart with a big-endian ordering to the bytes.
  */
+/*
+ * On intel, we must use inb() and outb() for register access, and the registers
+ *  are consecutive; no padding.
+ */ 
+
+#ifndef __i386__
+#define SETREG(reg, val) (reg = val)
+#define GETREG(reg)      (reg)
 
 struct ESP_regs {
                                 /* Access    Description              Offset */
@@ -140,7 +151,7 @@ struct ESP_regs {
                                 EREGS_PAD(fdpad);
     volatile unchar esp_fdata;  /* rw  FIFO data bits                 0x08   */
                                 EREGS_PAD(cbpad);
-    volatile unchar esp_cmd;    /* rw  SCSI command bits              0x0c   */
+    volatile unchar esp_cmnd;    /* rw  SCSI command bits              0x0c   */
                                 EREGS_PAD(stpad);
     volatile unchar esp_status; /* ro  ESP status register            0x10   */
 #define esp_busid   esp_status  /* wo  Bus ID for select/reselect     0x10   */
@@ -178,6 +189,52 @@ struct ESP_regs {
 #define fas_rhi     esp_fgrnd   /* rw  HME extended counter           0x3c  */
 };
 
+#else
+#define SETREG(reg, val) outb(val, reg)
+#define GETREG(reg)      inb(reg)
+
+struct ESP_regs {
+#ifdef CONFIG_MCA
+    unsigned int slot;
+#endif
+    unsigned int io_addr;
+                                  /* Access    Description              Offset */
+#define esp_tclow   io_addr      /* rw  Low bits of the transfer count 0x00   */
+#define esp_tcmed   io_addr + 1  /* rw  Mid bits of the transfer count 0x04   */
+#define esp_fdata   io_addr + 2  /* rw  FIFO data bits                 0x08   */
+#define esp_cmnd     io_addr + 3  /* rw  SCSI command bits              0x0c   */
+#define esp_status  io_addr + 4  /* ro  ESP status register            0x10   */
+#define esp_busid    esp_status   /* wo  Bus ID for select/reselect     0x10   */
+#define esp_intrpt  io_addr + 5  /* ro  Kind of interrupt              0x14   */
+#define esp_timeo    esp_intrpt   /* wo  Timeout value for select/resel 0x14   */
+#define esp_sstep   io_addr + 6  /* ro  Sequence step register         0x18   */
+#define esp_stp      esp_sstep    /* wo  Transfer period per sync       0x18   */
+#define esp_fflags  io_addr + 7  /* ro  Bits of current FIFO info      0x1c   */
+#define esp_soff     esp_fflags   /* wo  Sync offset                    0x1c   */
+#define esp_cfg1    io_addr + 8  /* rw  First configuration register   0x20   */
+#define esp_cfact   io_addr + 9  /* wo  Clock conversion factor        0x24   */
+#define esp_status2  esp_cfact    /* ro  HME status2 register           0x24   */
+#define esp_ctest   io_addr + 10 /* wo  Chip test register             0x28   */
+#define esp_cfg2    io_addr + 11 /* rw  Second configuration register  0x2c   */
+
+    /* The following is only found on the 53C9X series SCSI chips */
+#define esp_cfg3    io_addr + 12 /* rw  Third configuration register   0x30  */
+#define esp_hole    io_addr + 13 /* hole in register map               0x34  */
+
+    /* The following is found on all chips except the NCR53C90 (ESP100) */
+#define esp_tchi    io_addr + 14 /* rw  High bits of transfer count    0x38  */
+#define esp_uid      esp_tchi     /* ro  Unique ID code                 0x38  */
+#define fas_rlo      esp_tchi     /* rw  HME extended counter           0x38  */
+#define esp_fgrnd   io_addr + 15 /* rw  Data base for fifo             0x3c  */
+#define fas_rhi      esp_fgrnd    /* rw  HME extended counter           0x3c  */
+};
+
+#ifndef save_and_cli
+#define save_and_cli(flags)  save_flags(flags); cli();
+#endif
+
+#endif
+
 /* Various revisions of the ESP board. */
 enum esp_rev {
   esp100     = 0x00,  /* NCR53C90 - very broken */
@@ -195,7 +252,11 @@ enum esp_rev {
 struct NCR_ESP {
   struct NCR_ESP *next;                   /* Next ESP on probed or NULL */
   struct ESP_regs *eregs;                /* All esp registers */
+#ifndef __i386__
   struct Linux_DMA *dma;                  /* Who I do transfers with. */
+#else
+  int dma;
+#endif
   void *dregs;                           /* And his registers. */
   struct Scsi_Host *ehost;                /* Backpointer to SCSI Host */
 
@@ -273,6 +334,10 @@ struct NCR_ESP {
   int diff;                               /* Differential SCSI bus? */
   int bursts;                             /* Burst sizes our DVMA supports */
 
+#ifdef CONFIG_MCA
+  int slot;                              /* MCA slot the adapter occupies */
+#endif
+
   /* Our command queues, only one cmd lives in the current_SC queue. */
   Scsi_Cmnd *issue_SC;           /* Commands to be issued */
   Scsi_Cmnd *current_SC;         /* Who is currently working the bus */
index 078b64ae6dab2adf7b8c26240a8ac70e5d642701..7dfa6ef35105790b038dc42e435bc7eb5061715c 100644 (file)
@@ -354,7 +354,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.4"
+#define AIC7XXX_C_VERSION  "5.1.6"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -579,7 +579,8 @@ static const char *board_names[] = {
   "Adaptec AIC-7890/1 Ultra2 SCSI host adapter",        /* AIC_7890 */
   "Adaptec AHA-294X Ultra2 SCSI host adapter",          /* AIC_7890 */
   "Adaptec AIC-7896/7 Ultra2 SCSI host adapter",        /* AIC_7896 */
-  "Adaptec AHA-394X Ultra2 SCSI host adapter"           /* AIC_7897 */
+  "Adaptec AHA-394X Ultra2 SCSI host adapter",          /* AIC_7897 */
+  "Adaptec PCMCIA SCSI controller",                     /* card bus stuff */
 };
 
 /*
@@ -941,7 +942,6 @@ struct aic7xxx_scb {
         struct aic7xxx_scb    *q_next;        /* next scb in queue */
         volatile scb_flag_type flags;         /* current state of scb */
         struct hw_scatterlist *sg_list;       /* SG list in adapter format */
-        void                  *kmalloc_ptr;
         unsigned char          tag_action;
         unsigned char          sg_count;
         unsigned char          sense_cmd[6];  /*
@@ -952,6 +952,7 @@ struct aic7xxx_scb {
                                            * don't have to calculate anything
                                            * during underflow/overflow/stat code
                                            */
+        void                  *kmalloc_ptr;
 };
 
 /*
@@ -1029,84 +1030,68 @@ struct aic7xxx_host {
    *  This is the first 64 bytes in the host struct
    */
 
-  struct Scsi_Host        *host;             /* pointer to scsi host */
-  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
-  int                      host_no;          /* SCSI host number */
-  unsigned long            base;             /* card base address */
-  volatile unsigned char  *maddr;            /* memory mapped address */
-  unsigned long            mbase;            /* I/O memory address */
+  /*
+   * We are grouping things here....first, items that get either read or
+   * written with nearly every interrupt
+   */
   volatile ahc_flag_type   flags;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
-  spinlock_t               spin_lock;
-#endif
-  volatile unsigned char   cpu_lock_count[NR_CPUS];
-  ahc_chip                 chip;             /* chip type */
   ahc_feature              features;         /* chip features */
-  unsigned long            last_reset;
+  unsigned long            base;             /* card base address */
+  volatile unsigned char  *maddr;            /* memory mapped address */
   unsigned long            isr_count;        /* Interrupt count */
   unsigned long            spurious_int;
-  struct target_cmd       *targetcmds;
-  unsigned int             num_targetcmds;
+  scb_data_type           *scb_data;
+  struct aic7xxx_cmd_queue {
+    Scsi_Cmnd *head;
+    Scsi_Cmnd *tail;
+  } completeq;
+
+  /*
+   * Things read/written on nearly every entry into aic7xxx_queue()
+   */
+  volatile scb_queue_type  waiting_scbs;
   unsigned short           discenable;       /* Targets allowed to disconnect */
   unsigned short           tagenable;        /* Targets using tagged I/O */
   unsigned short           orderedtag;       /* Ordered Q tags allowed */
-  volatile unsigned char   activescbs;       /* active scbs */
-  volatile unsigned char   max_activescbs;
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
   volatile unsigned char   qoutfifonext;
+  volatile unsigned char   activescbs;       /* active scbs */
+  volatile unsigned char   max_activescbs;
   volatile unsigned char   qinfifonext;
 
-  /*
-   * MAX_TARGETS is currently == 16, so that makes these entries the next
-   * 64 bytes
-   */
-
 #define  DEVICE_PRESENT                 0x01
 #define  BUS_DEVICE_RESET_PENDING       0x02
-#define  DEVICE_TIMEOUT                 0x04
+#define  DEVICE_RESET_DELAY             0x04
 #define  DEVICE_PRINT_SDTR              0x08
 #define  DEVICE_PRINT_WDTR              0x10
-#define  DEVICE_SUCCESS                 0x20
-#define  DEVICE_TAGGED_SUCCESS          0x40
+#define  DEVICE_WAS_BUSY                0x20
 #define  DEVICE_SCANNED                 0x80
   volatile unsigned char   dev_flags[MAX_TARGETS];
   volatile unsigned char   dev_active_cmds[MAX_TARGETS];
   volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
   unsigned char            dev_commands_sent[MAX_TARGETS];
 
-  /*
-   * The next 128 (or 256 on 64 bit machines)....
-   */
-  Scsi_Cmnd               *dev_wdtr_cmnd[MAX_TARGETS];
-  Scsi_Cmnd               *dev_sdtr_cmnd[MAX_TARGETS];
-
-  /*
-   * The next 64.... 
-   */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+  spinlock_t               spin_lock;
+  volatile unsigned char   cpu_lock_count[NR_CPUS];
+#endif
 
-  long                     dev_last_reset[MAX_TARGETS];
+  unsigned short           dev_timer_active; /* Which devs have a timer set */
 
-  /*
-   * The next 64....
-   */
+#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
+  Scsi_Cmnd               *dev_wdtr_cmnd[MAX_TARGETS];
+  Scsi_Cmnd               *dev_sdtr_cmnd[MAX_TARGETS];
+#endif
 
-  unsigned char            dev_mid_level_queue_depth[MAX_TARGETS];
   unsigned char            dev_last_queue_full[MAX_TARGETS];
   unsigned char            dev_last_queue_full_count[MAX_TARGETS];
   unsigned char            dev_max_queue_depth[MAX_TARGETS];
 
-  /*
-   * The next 128....
-   */
-
   volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
 
-  /*
-   *
-   */
-
-  struct timer_list        dev_timer[MAX_TARGETS];
+  unsigned long            dev_expires[MAX_TARGETS];
+  struct timer_list        dev_timer;
 
   /*
    * The next 64....
@@ -1120,16 +1105,6 @@ struct aic7xxx_host {
   unsigned char            msg_len;          /* Length of message */
   unsigned char            msg_index;        /* Index into msg_buf array */
   transinfo_type           transinfo[MAX_TARGETS];
-  volatile scb_queue_type  waiting_scbs;     /*
-                                              * SCBs waiting for space in
-                                              * the QINFIFO.
-                                              */
-  scb_data_type           *scb_data;
-
-  struct aic7xxx_cmd_queue {
-    Scsi_Cmnd *head;
-    Scsi_Cmnd *tail;
-  } completeq;
 
 
   /*
@@ -1170,6 +1145,12 @@ struct aic7xxx_host {
   struct seeprom_config    sc;
   unsigned short           sc_type;
   unsigned short           sc_size;
+  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
+  struct Scsi_Host        *host;             /* pointer to scsi host */
+  int                      host_no;          /* SCSI host number */
+  unsigned long            mbase;            /* I/O memory address */
+  unsigned long            last_reset;
+  ahc_chip                 chip;             /* chip type */
 
   /*
    * Statistics Kept:
@@ -1189,16 +1170,22 @@ struct aic7xxx_host {
    * proc stats code is enabled.
    */
   struct aic7xxx_xferstats {
-    long xfers;                              /* total xfer count */
     long w_total;                            /* total writes */
-    long w_total512;                         /* 512 byte blocks written */
     long r_total;                            /* total reads */
-    long r_total512;                         /* 512 byte blocks read */
 #ifdef AIC7XXX_PROC_STATS
+    long xfers;                              /* total xfer count */
+    long w_total512;                         /* 512 byte blocks written */
+    long r_total512;                         /* 512 byte blocks read */
     long w_bins[10];                         /* binned write */
     long r_bins[10];                         /* binned reads */
 #endif /* AIC7XXX_PROC_STATS */
   } stats[MAX_TARGETS][MAX_LUNS];            /* [(channel << 3)|target][lun] */
+
+#if 0
+  struct target_cmd       *targetcmds;
+  unsigned int             num_targetcmds;
+#endif
+
 };
 
 /*
@@ -1282,11 +1269,9 @@ static unsigned int aic7xxx_no_reset = 0;
  */
 static int aic7xxx_reverse_scan = 0;
 /*
- * This setting enables a hack to fix the IRQ settings on buggy 7895
- * MB controller setups:
- *    -1 == Disable this hack
- *     0 == Use the Channel A IRQ for both channels
- *     1 == Use the Channel B IRQ for both channels
+ * Should we force EXTENDED translation on a controller.
+ *     0 == Use whatever is in the SEEPROM or default to off
+ *     1 == Use whatever is in the SEEPROM or default to on
  */
 static unsigned int aic7xxx_extended = 0;
 /*
@@ -1511,6 +1496,21 @@ mdelay(int milliseconds)
   for(i=0; i<milliseconds; i++)
     udelay(1000);
 }
+
+static inline int
+time_after_eq(unsigned long a, unsigned long b)
+{
+  return((long)((a) - (b)) >= 0L);
+}
+
+static inline int
+timer_pending(struct timer_list *timer)
+{
+  return( timer->prev != NULL );
+}
+
+#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075
+
 #endif
 
 static inline unsigned char
@@ -1950,7 +1950,10 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
   {
     printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
   }
+#if 0
   download_consts[TMODE_NUMCMDS] = p->num_targetcmds;
+#endif
+  download_consts[TMODE_NUMCMDS] = 0;
   cur_patch = &sequencer_patches[0];
   downloaded = 0;
   skip_addr = 0;
@@ -2873,6 +2876,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     {
       char *buffer;
       
+      p->dev_flags[tindex] |= DEVICE_PRESENT;
       if(cmd->use_sg)
       {
         struct scatterlist *sg;
@@ -2914,23 +2918,34 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         p->needsdtr_copy |= (1<<tindex);
 
         if (p->flags & AHC_SEEPROM_FOUND)
+        {
           p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
-        else if (p->features & AHC_ULTRA2)
-          p->transinfo[tindex].goal_period =
-            aic7xxx_syncrates[AHC_SYNCRATE_ULTRA2].period;
-        else if (p->features & AHC_ULTRA)
-          p->transinfo[tindex].goal_period =
-            aic7xxx_syncrates[AHC_SYNCRATE_ULTRA].period;
-        else
-          p->transinfo[tindex].goal_period =
-            aic7xxx_syncrates[AHC_SYNCRATE_FAST].period;
-
-        if (p->features & AHC_ULTRA2)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-        else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+          p->transinfo[tindex].goal_offset = p->transinfo[tindex].user_offset;
+        }
         else
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+        {
+          if (p->features & AHC_ULTRA2)
+          {
+            p->transinfo[tindex].goal_period =
+              aic7xxx_syncrates[AHC_SYNCRATE_ULTRA2].period;
+          }
+          else if (p->features & AHC_ULTRA)
+          {
+            p->transinfo[tindex].goal_period =
+              aic7xxx_syncrates[AHC_SYNCRATE_ULTRA].period;
+          }
+          else
+          {
+            p->transinfo[tindex].goal_period =
+              aic7xxx_syncrates[AHC_SYNCRATE_FAST].period;
+          }
+          if (p->features & AHC_ULTRA2)
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+          else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+          else
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+        }
       }
       else
       {
@@ -3077,11 +3092,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 #endif /* AIC7XXX_PROC_STATS */
 
       sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
-      sp->xfers++;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if ( (sp->xfers > 16) && (aic7xxx_verbose > 0xffff) )
-        aic7xxx_verbose &= 0xffff;
-#endif
 
       /*
        * For block devices, cmd->request.cmd is always == either READ or
@@ -3093,16 +3103,26 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
            (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
       {
         sp->w_total++;
-        sp->w_total512 += (actual >> 9);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if ( (sp->w_total > 16) && (aic7xxx_verbose > 0xffff) )
+          aic7xxx_verbose &= 0xffff;
+#endif
 #ifdef AIC7XXX_PROC_STATS
+        sp->xfers++;
+        sp->w_total512 += (actual >> 9);
         ptr = sp->w_bins;
 #endif /* AIC7XXX_PROC_STATS */
       }
       else
       {
         sp->r_total++;
-        sp->r_total512 += (actual >> 9);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if ( (sp->r_total > 16) && (aic7xxx_verbose > 0xffff) )
+          aic7xxx_verbose &= 0xffff;
+#endif
 #ifdef AIC7XXX_PROC_STATS
+        sp->xfers++;
+        sp->r_total512 += (actual >> 9);
         ptr = sp->r_bins;
 #endif /* AIC7XXX_PROC_STATS */
       }
@@ -3401,39 +3421,24 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
 
     for (i = min_target; i <= max_target; i++)
     {
+      if ( i == p->scsi_id )
+      {
+        continue;
+      }
       if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
         printk(INFO_LEAD "Cleaning up status information "
           "and delayed_scbs.\n", p->host_no, channel, i, lun);
-      if ( !(p->dev_flags[i] & DEVICE_TAGGED_SUCCESS) &&
-            (p->dev_active_cmds[i]) &&
-            (p->tagenable & (0x01 << i)) )
-      {
-        printk(INFO_LEAD "Device appears to be choking on tagged commands.\n",
-          p->host_no, channel, i, lun);
-        printk(INFO_LEAD "Will use untagged I/O instead.\n", p->host_no,
-          channel, i, lun);
-        p->dev_max_queue_depth[i] = 1;
-        p->dev_temp_queue_depth[i] = 1;
-        p->tagenable &= ~(0x01 << i);
-        p->orderedtag &= ~(0x01 << i);
-      }
       p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
       if ( tag == SCB_LIST_NULL )
       {
-        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
-        p->dev_last_reset[i] = jiffies;
+        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR |
+                           DEVICE_RESET_DELAY;
+        p->dev_expires[i] = jiffies + (4 * HZ);
+        p->dev_timer_active |= (0x01 << i);
         p->dev_last_queue_full_count[i] = 0;
         p->dev_last_queue_full[i] = 0;
         p->dev_temp_queue_depth[i] =
           p->dev_max_queue_depth[i];
-  /*
-   * In case this isn't a full bus reset, we want to add a 4 second timer in
-   * here so that we can delay all re-sent commands for this device for the
-   * 4 seconds and then have our timer routine pick them back up.
-   */
-        del_timer(&p->dev_timer[i]);
-        p->dev_timer[i].expires = jiffies + (4 * HZ);
-        add_timer(&p->dev_timer[i]);
       }
       for(j=0; j<MAX_LUNS; j++)
       {
@@ -3480,8 +3485,14 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
             "delayed_scbs queue!\n", p->host_no, channel, i, lun);
         scbq_init(&p->delayed_scbs[i]);
       }
-      if ( p->delayed_scbs[i].head == NULL )
-        del_timer(&p->dev_timer[i]);
+      if ( !(p->dev_timer_active & (0x01 << p->scsi_id)) ||
+            time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
+      {
+        del_timer(&p->dev_timer);
+        p->dev_timer.expires = p->dev_expires[i];
+        add_timer(&p->dev_timer);
+        p->dev_timer_active |= (0x01 << p->scsi_id);
+      }
     }
   }
 
@@ -3993,38 +4004,17 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
     tindex = TARGET_INDEX(scb->cmd);
     if ( !scb->tag_action && (p->tagenable & (1<<tindex)) )
     {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Reducing Queue depth for untagged command.\n",
-               p->host_no, CTL_OF_SCB(scb));
-#endif
       p->dev_temp_queue_depth[tindex] = 1;
     }
     if ( (p->dev_active_cmds[tindex] >=
           p->dev_temp_queue_depth[tindex]) ||
-         time_after_eq(p->dev_last_reset[tindex], jiffies - 4 * HZ) )
+         (p->dev_flags[tindex] & (DEVICE_RESET_DELAY|DEVICE_WAS_BUSY)) )
     {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Moving SCB to Delayed Queue.\n",
-               p->host_no, CTL_OF_SCB(scb));
-#endif
       scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-      if ( !timer_pending(&p->dev_timer[tindex]) &&
-           !(p->dev_active_cmds[tindex]) )
-      {
-        p->dev_timer[tindex].expires = p->dev_last_reset[tindex] + (4 * HZ);
-        add_timer(&p->dev_timer[tindex]);
-      }
     }
     else
     {
         scb->flags &= ~SCB_WAITINGQ;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-        if (aic7xxx_verbose > 0xffff)
-          printk(INFO_LEAD "Sending command %d/0x%x to QINFIFO\n", p->host_no,
-                 CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
-#endif
         p->dev_active_cmds[tindex]++;
         p->activescbs++;
         if ( !(scb->tag_action) )
@@ -4037,16 +4027,6 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
   }
   if (sent)
   {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-    if (aic7xxx_verbose > 0xffff)
-    {
-      printk(INFO_LEAD "Sending commands to QINFIFO\n", p->host_no,
-             -1, -1, -1);
-      if ( (p->isr_count < 16) && (aic7xxx_panic_on_abort) &&
-           (p->flags & AHC_PAGESCBS) )
-        aic7xxx_check_scbs(p, "While sending commands to QINFIFO");
-    }
-#endif
     if (p->features & AHC_QUEUE_REGS)
       aic_outb(p, p->qinfifonext, HNSCB_QOFF);
     else
@@ -4147,12 +4127,18 @@ aic7xxx_timer(struct aic7xxx_host *p)
 #else
   spin_lock_irqsave(&io_request_lock, cpu_flags);
 #endif
+  p->dev_timer_active &= ~(0x01 << p->scsi_id);
   for(i=0; i<MAX_TARGETS; i++)
   {
-    if ( timer_pending(&p->dev_timer[i]) && 
-         time_before_eq(p->dev_timer[i].expires, jiffies) )
+    if ( i == p->scsi_id )
     {
-      del_timer(&p->dev_timer[i]);
+      continue;
+    }
+    if ( (p->dev_timer_active & (0x01 << i)) &&
+         time_after_eq(jiffies, p->dev_expires[i]) )
+    {
+      p->dev_timer_active &= ~(0x01 << i);
+      p->dev_flags[i] &= ~(DEVICE_RESET_DELAY|DEVICE_WAS_BUSY);
       p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
       j = 0;
       while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
@@ -4172,7 +4158,27 @@ aic7xxx_timer(struct aic7xxx_host *p)
          */
       }
     }
+    else if ( p->dev_timer_active & (0x01 << i) )
+    {
+      if ( p->dev_timer_active & (0x01 << p->scsi_id) )
+      {
+        if ( time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
+        {
+          p->dev_timer.expires = p->dev_expires[i];
+        }
+      }
+      else
+      {
+        p->dev_timer.expires = p->dev_expires[i];
+        p->dev_timer_active |= (0x01 << p->scsi_id);
+      }
+    }
+  }
+  if ( p->dev_timer_active & (0x01 << p->scsi_id) )
+  {
+    add_timer(&p->dev_timer);
   }
+
   aic7xxx_run_waiting_queues(p);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)   
   DRIVER_UNLOCK
@@ -4447,8 +4453,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
              (scb->tag_action) &&
             !(scb->flags & SCB_MSGOUT_BITS) )
         {
-          if ((scb->tag_action == MSG_ORDERED_Q_TAG) &&
-              (p->dev_flags[tindex] & DEVICE_TAGGED_SUCCESS))
+          if (scb->tag_action == MSG_ORDERED_Q_TAG)
           {
             /*
              * OK...the device seems able to accept tagged commands, but
@@ -4469,8 +4474,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
             aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
           }
-          else if ( (scb->tag_action == MSG_SIMPLE_Q_TAG) &&
-                   !(p->dev_flags[tindex] & DEVICE_TAGGED_SUCCESS) )
+          else if (scb->tag_action == MSG_SIMPLE_Q_TAG)
           {
             unsigned char i, reset = 0;
             struct aic7xxx_scb *scbp;
@@ -4885,17 +4889,29 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               p->activescbs--;
               scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
                   
-              if ( !timer_pending(&p->dev_timer[tindex]) ) 
+              if ( !(p->dev_timer_active & (0x01 << tindex)) ) 
               {
+                p->dev_timer_active |= (0x01 << tindex);
                 if ( p->dev_active_cmds[tindex] )
                 {
-                  p->dev_timer[tindex].expires = jiffies + (HZ * 2);
-                  add_timer(&p->dev_timer[tindex]);
+                  p->dev_expires[tindex] = jiffies + HZ;
                 }
                 else
                 {
-                  p->dev_timer[tindex].expires = jiffies + (HZ / 2);
-                  add_timer(&p->dev_timer[tindex]);
+                  p->dev_expires[tindex] = jiffies + (HZ / 10);
+                }
+                if ( !(p->dev_timer_active & (0x01 << p->scsi_id)) )
+                {
+                  p->dev_timer.expires = p->dev_expires[tindex];
+                  p->dev_timer_active |= (0x01 << p->scsi_id);
+                  add_timer(&p->dev_timer);
+                }
+                else if ( time_after_eq(p->dev_timer.expires,
+                                        p->dev_expires[tindex]) )
+                {
+                  del_timer(&p->dev_timer);
+                  p->dev_timer.expires = p->dev_expires[tindex];
+                  add_timer(&p->dev_timer);
                 }
               }
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
@@ -4937,6 +4953,10 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                   p->dev_last_queue_full[tindex] = 0;
                   p->dev_last_queue_full_count[tindex] = 0;
                 }
+                else
+                {
+                  p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
+                }
               }
               break;
             }
@@ -5255,50 +5275,61 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         {
           maxsync = AHC_SYNCRATE_FAST;
         }
-  
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-        if (aic7xxx_verbose > 0xffff)
-        {
-          printk(INFO_LEAD "Finished receipt of SDTR, parsing %d/%d\n",
-                 p->host_no, CTL_OF_SCB(scb), period, offset);
-          syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
-          printk(INFO_LEAD "After find_syncrate() %d/%d\n",
-                 p->host_no, CTL_OF_SCB(scb), period, offset);
-          aic7xxx_validate_offset(p, syncrate, &offset,
-                                  target_scsirate & WIDEXFER);
-          printk(INFO_LEAD "After validate_offset() %d/%d\n",
-                 p->host_no, CTL_OF_SCB(scb), period, offset);
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-          printk(INFO_LEAD "Final values of Period/Offset as set: %d/%d\n",
-                 p->host_no, CTL_OF_SCB(scb), period, offset);
-        }
-        else
+        /*
+         * We might have a device that is starting negotiation with us
+         * before we can start up negotiation with it....be prepared to
+         * have a device ask for a higher speed then we want to give it
+         * in that case
+         */
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
         {
-          syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
-          aic7xxx_validate_offset(p, syncrate, &offset,
-                                  target_scsirate & WIDEXFER);
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+          {
+            /*
+             * Not only is the device starting this up, but it also hasn't
+             * been scanned yet, so this would likely be our TUR or our
+             * INQUIRY command at scan time, so we need to use the
+             * settings from the SEEPROM if they existed.  Of course, even
+             * if we didn't find a SEEPROM, we stuffed default values into
+             * the user settings anyway, so use those in all cases.
+             */
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            p->transinfo[tindex].goal_offset =
+              p->transinfo[tindex].user_offset;
+            p->needsdtr_copy |= target_mask;
+          }
+          if ( !p->transinfo[tindex].goal_offset )
+            period = 255;
+          if ( p->transinfo[tindex].goal_period > period )
+            period = p->transinfo[tindex].goal_period;
         }
-#else
+  
         syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
         aic7xxx_validate_offset(p, syncrate, &offset,
                                 target_scsirate & WIDEXFER);
         aic7xxx_set_syncrate(p, syncrate, target, channel, period,
                              offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-#endif
 
-        if (offset == 0)
+        /*
+         * Did we drop to async?  If so, are we sending a reply?  If we are,
+         * then we have to make sure that the reply value reflects the proper
+         * settings so we need to set the goal values according to what
+         * we need to send.
+         */
+        if ( (offset == 0) || (offset != saved_offset) ||
+             ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
         {
-          /*
-           * Uhh ohh, things fell through to async....update the goal
-           * items and the needsdtr_copy to reflect this...
-           */
           aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                 offset, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
-          p->needsdtr_copy &= ~target_mask;
+                               offset, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          if ( offset == 0 )
+          {
+            p->needsdtr_copy &= ~target_mask;
+          }
         }
+        
         /*
          * Did we start this, if not, or if we went to low and had to
          * go async, then send an SDTR back to the target
@@ -5313,32 +5344,6 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         }
         else
         {
-          /*
-           * Send a reply SDTR back.  Even if we sent the first one, it
-           * is valid to send another one out immediately to re-negotiate
-           * things, and a few devices don't like getting rejects after
-           * we already sent them one SDTR.  Just send an SDTR for async
-           * this time if need be (or for the correct params if we didn't
-           * start all of this).  If this is a Reject Reply type message,
-           * then we've put the async settings into the goal area for
-           * future reference (when we get the AWAITING_MSG interrupt).
-           * If this is a case where we are responding to the target's
-           * initiated SDTR, then leave our own goal and user values in
-           * place (unless the device hasn't been scanned yet, in which
-           * case, put the user values into the goal values so we don't
-           * send out an Async message).
-           */
-          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
-          {
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
-            p->needwdtr_copy |= target_mask;
-            p->needsdtr_copy |= target_mask;
-          }
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_SDTR;
           aic_outb(p, HOST_MSG, MSG_OUT);
@@ -5407,12 +5412,12 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
              * it contacted us first, mark it as such and copy the user stuff
              * over to the goal stuff.
              */
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
             p->transinfo[tindex].goal_period =
               p->transinfo[tindex].user_period;
             p->transinfo[tindex].goal_offset =
               p->transinfo[tindex].user_offset;
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
             p->needwdtr_copy |= target_mask;
             p->needsdtr_copy |= target_mask;
           }
@@ -5432,6 +5437,8 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
             {
               p->needwdtr_copy &= ~target_mask;
               bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              aic7xxx_set_width(p, target, channel, lun, bus_width,
+                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
               break;
             }
           }
@@ -6241,12 +6248,6 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
             aic7xxx_calculate_residual(p, scb);
           }
           cmd->result |= (aic7xxx_error(cmd) << 16);
-          if (scb->tag_action)
-            p->dev_flags[TARGET_INDEX(cmd)] |= 
-               DEVICE_TAGGED_SUCCESS | DEVICE_SUCCESS | DEVICE_PRESENT;
-          else
-            p->dev_flags[TARGET_INDEX(cmd)] |= 
-               DEVICE_SUCCESS | DEVICE_PRESENT;
           aic7xxx_done(p, scb);
           break;
       }      
@@ -6392,7 +6393,6 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
   target_mask = (1 << tindex);
 
   device->queue_depth = default_depth;
-  p->dev_mid_level_queue_depth[tindex] = 3;
   p->dev_temp_queue_depth[tindex] = 1;
   p->dev_max_queue_depth[tindex] = 1;
   p->tagenable &= ~target_mask;
@@ -6457,7 +6457,6 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
         }
         p->dev_max_queue_depth[tindex] = device->queue_depth;
         p->dev_temp_queue_depth[tindex] = device->queue_depth;
-        p->dev_mid_level_queue_depth[tindex] = device->queue_depth;
         p->tagenable |= target_mask;
         p->orderedtag |= target_mask;
         device->tagged_queue = 1;
@@ -7461,6 +7460,10 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
   p->completeq.tail = NULL;
   scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
+  init_timer(&p->dev_timer);
+  p->dev_timer.data = (unsigned long)p;
+  p->dev_timer.function = (void *)aic7xxx_timer;
+  p->dev_timer_active = 0;
 
   for (i = 0; i < NUMBER(p->untagged_scbs); i++)
   {
@@ -7479,16 +7482,12 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
     p->dev_commands_sent[i] = 0;
     p->dev_flags[i] = 0;
     p->dev_active_cmds[i] = 0;
-    p->dev_last_reset[i] = jiffies;
     p->dev_last_queue_full[i] = 0;
     p->dev_last_queue_full_count[i] = 0;
     p->dev_max_queue_depth[i] = 1;
     p->dev_temp_queue_depth[i] = 1;
-    p->dev_mid_level_queue_depth[i] = 3;
+    p->dev_expires[i] = 0;
     scbq_init(&p->delayed_scbs[i]);
-    init_timer(&p->dev_timer[i]);
-    p->dev_timer[i].data = (unsigned long)p;
-    p->dev_timer[i].function = (void *)aic7xxx_timer;
   }
 
   printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
@@ -8156,6 +8155,21 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
           have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                       scarray, p->sc_size, C46);
       }
+      if (!have_seeprom)
+      {
+        p->sc_size = 128;
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                    scarray, p->sc_size, p->sc_type);
+        if (!have_seeprom)
+        {
+          if(p->sc_type == C46)
+            have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                        scarray, p->sc_size, C56_66);
+          else
+            have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                        scarray, p->sc_size, C46);
+        }
+      }
       break;
   }
 
@@ -8187,7 +8201,8 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
       sc->adapter_control &= ~CFAUTOTERM;
       sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
     }
-    p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
+    if (aic7xxx_extended)
+      p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
   }
   else
   {
@@ -8341,7 +8356,8 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
       }
       else if (sc->device_flags[i] & CFNEWULTRAFORMAT)
       {
-        if ( (sc->device_flags[i] & (CFSYNCHISULTRA | CFXFER)) == 0x03 )
+        if ( ((sc->device_flags[i] & (CFSYNCHISULTRA | CFXFER)) == 0x03) &&
+             !(p->features & AHC_ULTRA2) )
         {
           sc->device_flags[i] &= ~CFXFER;
           sc->device_flags[i] |= CFSYNCHISULTRA;
@@ -8622,12 +8638,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
         current_p = current_p->next;
       current_p->next = temp_p;
     }
-    if (aic7xxx_extended)
-    {
-      temp_p->flags |= AHC_EXTEND_TRANS_A;
-      if (temp_p->flags & AHC_MULTI_CHANNEL)
-        temp_p->flags |= AHC_EXTEND_TRANS_B;
-    }
 
     switch (type)
     {
@@ -8846,6 +8856,10 @@ aic7xxx_detect(Scsi_Host_Template *template)
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
        AHC_AIC7896_FE,                                      23,
        32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                      24,
+       32, C46 },
     };
 
     unsigned short command;
@@ -9327,9 +9341,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
             aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
           }
 
-          if (aic7xxx_extended)
-            temp_p->flags |= AHC_EXTEND_TRANS_A;
-
           if ( list_p == NULL )
           {
             list_p = current_p = temp_p;
@@ -10096,8 +10107,6 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
                 "message buffer\n", p->host_no, CTL_OF_SCB(scb));
         scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
         aic7xxx_error(scb->cmd) = DID_RESET;
-        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
-                ~DEVICE_SUCCESS;
         p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
                 BUS_DEVICE_RESET_PENDING;
         /* Send the abort message to the active SCB. */
@@ -10118,8 +10127,6 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
                 "in use\n", p->host_no, CTL_OF_SCB(scb));
         scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
         aic7xxx_error(scb->cmd) = DID_RESET;
-        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
-                ~DEVICE_SUCCESS;
         p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
                 BUS_DEVICE_RESET_PENDING;
         return(SCSI_RESET_ERROR);
@@ -10147,7 +10154,6 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
          */
     scb->hscb->control |= MK_MESSAGE;
     scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-    p->dev_flags[TARGET_INDEX(scb->cmd)] &= ~DEVICE_SUCCESS;
     p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
         BUS_DEVICE_RESET_PENDING;
     if (hscb_index != SCB_LIST_NULL)
@@ -10227,7 +10233,7 @@ aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
     {
       mask = (0x01 << i);
       printk(INFO_LEAD "dev_flags=0x%x, WDTR:%c/%c/%c, SDTR:%c/%c/%c,"
-             " q_depth=%d:%d:%d\n",
+             " q_depth=%d:%d\n",
         p->host_no, 0, i, 0, p->dev_flags[i],
         (p->wdtr_pending & mask) ? 'Y' : 'N',
         (p->needwdtr & mask) ? 'Y' : 'N',
@@ -10236,7 +10242,7 @@ aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
         (p->needsdtr & mask) ? 'Y' : 'N',
         (p->needsdtr_copy & mask) ? 'Y' : 'N',
         p->dev_active_cmds[i],
-        p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+        p->dev_max_queue_depth[i] );
       printk(INFO_LEAD "targ_scsirate=0x%x", p->host_no, 0, i, 0,
              aic_inb(p, TARG_SCSIRATE + i));
       if (p->features & AHC_ULTRA2)
@@ -10877,7 +10883,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
   {
     action = HOST_RESET;
   }
-  if ( ((jiffies - p->dev_last_reset[tindex]) < (HZ * 3)) &&
+  if ( (p->dev_flags[tindex] & DEVICE_RESET_DELAY) &&
        !(action & (HOST_RESET | BUS_RESET)))
   {
     if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
@@ -10960,9 +10966,25 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
         p->msg_len = 0;
       }
       aic7xxx_run_done_queue(p, TRUE);
+      /*
+       * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
+       * in need of being re-started, so send it on through to aic7xxx_queue
+       * and let it set until the delay is over.  This keeps it from dying
+       * entirely and avoids getting a bogus dead command back through the
+       * mid-level code due to too many retries.
+       */
+      if ( flags & SCSI_RESET_SYNCHRONOUS )
+      {
+        cmd->result = DID_RESET << 16;
+        cmd->done(cmd);
+      }
       p->flags &= ~AHC_IN_RESET;
-      /*  We can't rely on run_waiting_queues to unpause the sequencer for
-       *  PCI based controllers since we use AAP */
+      /*
+       * We can't rely on run_waiting_queues to unpause the sequencer for
+       * PCI based controllers since we use AAP.  NOTE: this also sets
+       * the timer for the one command we might have queued in the case
+       * of a synch reset.
+       */
       aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
index d3d1b1ea36a324cb4ed16e5f15095d3c46161067..3e6e4c678fb775291dfb4e112e6663310444d78f 100644 (file)
@@ -132,7 +132,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   {
     for (lun = 0; lun < MAX_LUNS; lun++)
     {
-      if (p->stats[target][lun].xfers != 0)
+      if (p->stats[target][lun].r_total != 0)
 #ifdef AIC7XXX_PROC_STATS
         size += 512;
 #else
@@ -278,7 +278,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
     for (lun = 0; lun < MAX_LUNS; lun++)
     {
       sp = &p->stats[target][lun];
-      if (sp->xfers == 0)
+      if (sp->r_total == 0)
       {
         continue;
       }
@@ -331,11 +331,11 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
                       p->transinfo[target].cur_period,
                       p->transinfo[target].cur_offset,
                       p->transinfo[target].cur_width);
+#ifdef AIC7XXX_PROC_STATS
       size += sprintf(BLS, "    Total transfers %ld (%ld read;%ld written)\n",
           sp->xfers, sp->r_total, sp->w_total);
       size += sprintf(BLS, "      blks(512) rd=%ld; blks(512) wr=%ld\n",
           sp->r_total512, sp->w_total512);
-#ifdef AIC7XXX_PROC_STATS
       size += sprintf(BLS, "%s\n", HDRB);
       size += sprintf(BLS, " Reads:");
       for (i = 0; i < NUMBER(sp->r_bins); i++)
@@ -348,6 +348,9 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
       {
         size += sprintf(BLS, "%6ld ", sp->w_bins[i]);
       }
+#else
+      size += sprintf(BLS, "    Total transfers: %ld/%ld read/written)\n",
+          sp->r_total, sp->w_total);
 #endif /* AIC7XXX_PROC_STATS */
       size += sprintf(BLS, "\n\n");
     }
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
new file mode 100644 (file)
index 0000000..96280a8
--- /dev/null
@@ -0,0 +1,2037 @@
+/* $Id: atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $
+ *  linux/kernel/atp870u.c
+ *
+ *  Copyright (C) 1997 Wu Ching Chen
+ *  2.1.x update (C) 1998  Krzysztof G. Baranowski
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/pci.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+
+
+#include "atp870u.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_atp870u = {
+    PROC_SCSI_ATP870U, 7, "atp870u",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+void mydlyu(unsigned int);
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $";
+*/
+
+static unsigned char admaxu=1,host_idu[2],chip_veru[2],scam_on[2],global_map[2];
+static unsigned short int active_idu[2],wide_idu[2],sync_idu,ultra_map[2];
+static int  workingu[2]={0,0};
+static Scsi_Cmnd *querequ[2][qcnt],*curr_req[2][16];
+static unsigned char devspu[2][16] = {{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+                               0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},
+                              {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+                               0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}};
+static unsigned char dirctu[2][16],last_cmd[2],in_snd[2],in_int[2];
+static unsigned char ata_cdbu[2][16];
+static unsigned int ioportu[2]={0,0};
+static unsigned int irqnumu[2]={0,0};
+static unsigned short int pciportu[2];
+static unsigned long prdaddru[2][16],tran_lenu[2][16],last_lenu[2][16];
+static unsigned char prd_tableu[2][16][1024];
+static unsigned char *prd_posu[2][16];
+static unsigned char quhdu[2],quendu[2];
+static unsigned char devtypeu[2][16] = {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+                                { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+static struct Scsi_Host * atp_host[2]={NULL,NULL};
+
+static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned short int tmpcip,id;
+    unsigned char      i,j,h,tarid,lun;
+    unsigned char  *prd;
+    Scsi_Cmnd *workrequ;
+    unsigned int workportu,tmport;
+    unsigned long adrcntu,k;
+    int      errstus;
+
+    for ( h=0; h < 2; h++ )
+    {
+       if ( ( irq & 0x0f ) == irqnumu[h] )
+       {
+          goto irq_numok;
+       }
+    }
+    return;
+irq_numok:
+    in_int[h]=1;
+    workportu=ioportu[h];
+    tmport=workportu;
+
+    if ( workingu[h] != 0 )
+    {
+       tmport += 0x1f;
+       j=inb(tmport);
+       tmpcip=pciportu[h];
+       if ((inb(tmpcip) & 0x08) != 0)
+       {
+         tmpcip += 0x2;
+         while((inb(tmpcip) & 0x08) != 0);
+       }
+       tmpcip=pciportu[h];
+       outb(0x00,tmpcip);
+       tmport -=0x08;
+       i=inb(tmport);
+       if ((j & 0x40) == 0)
+       {
+         if ((last_cmd[h] & 0x40) == 0)
+         {
+            last_cmd[h]=0xff;
+         }
+       }
+       else
+       {
+         last_cmd[h] |= 0x40;
+       }
+       tmport -= 0x02;
+       tarid=inb(tmport);
+       tmport += 0x02;
+       if ((tarid & 0x40) != 0)
+       {
+         tarid=(tarid & 0x07) | 0x08;
+       }
+       else
+       {
+         tarid &= 0x07;
+       }
+       if ( i == 0x85 )
+       {
+         if (wide_idu[h] != 0)
+         {
+            tmport=workportu+0x1b;
+            j=inb(tmport) & 0x0e;
+            j |= 0x01;
+            outb(j,tmport);
+         }
+         if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) &&
+             (in_snd[h] == 0))
+         {
+            send_s870(h);
+         }
+         in_int[h]=0;
+         return;
+       }
+       if ( i == 0x21 )
+       {
+         tmport -= 0x05;
+         adrcntu=0;
+         ((unsigned char *)&adrcntu)[2]=inb(tmport++);
+         ((unsigned char *)&adrcntu)[1]=inb(tmport++);
+         ((unsigned char *)&adrcntu)[0]=inb(tmport);
+         k=last_lenu[h][tarid];
+         k -= adrcntu;
+         tran_lenu[h][tarid]= k;
+         last_lenu[h][tarid]=adrcntu;
+         tmport -= 0x04;
+         outb(0x41,tmport);
+         tmport += 0x08;
+         outb(0x08,tmport);
+         in_int[h]=0;
+         return ;
+       }
+
+       if ((i == 0x80) || (i == 0x8f))
+       {
+         lun=0;
+         tmport -= 0x07;
+         j=inb(tmport);
+         if ( j == 0x44 )
+         {
+            tmport += 0x0d;
+            lun=inb(tmport) & 0x07;
+         }
+         else
+         {
+            if ( j == 0x41 )
+            {
+               tmport += 0x02;
+               adrcntu=0;
+               ((unsigned char *)&adrcntu)[2]=inb(tmport++);
+               ((unsigned char *)&adrcntu)[1]=inb(tmport++);
+               ((unsigned char *)&adrcntu)[0]=inb(tmport);
+               k=last_lenu[h][tarid];
+               k -= adrcntu;
+               tran_lenu[h][tarid]= k;
+               last_lenu[h][tarid]=adrcntu;
+               tmport += 0x04;
+               outb(0x08,tmport);
+               in_int[h]=0;
+               return ;
+            }
+            else
+            {
+               outb(0x46,tmport);
+               dirctu[h][tarid]=0x00;
+               tmport += 0x02;
+               outb(0x00,tmport++);
+               outb(0x00,tmport++);
+               outb(0x00,tmport++);
+               tmport+=0x03;
+               outb(0x08,tmport);
+               in_int[h]=0;
+               return;
+            }
+         }
+         tmport=workportu + 0x10;
+         outb(0x45,tmport);
+         tmport += 0x06;
+         tarid=inb(tmport);
+         if ((tarid & 0x10) != 0)
+         {
+            tarid=(tarid & 0x07) | 0x08;
+         }
+         else
+         {
+            tarid &= 0x07;
+         }
+         workrequ=curr_req[h][tarid];
+         tmport=workportu + 0x0f;
+         outb(lun,tmport);
+         tmport += 0x02;
+         outb(devspu[h][tarid],tmport++);
+         adrcntu=tran_lenu[h][tarid];
+         k=last_lenu[h][tarid];
+         outb(((unsigned char *)&k)[2],tmport++);
+         outb(((unsigned char *)&k)[1],tmport++);
+         outb(((unsigned char *)&k)[0],tmport++);
+         j=tarid;
+         if ( tarid > 7 )
+         {
+            j = (j & 0x07) | 0x40;
+         }
+         j |= dirctu[h][tarid];
+         outb(j,tmport++);
+         outb(0x80,tmport);
+         tmport=workportu + 0x1b;
+         j=inb(tmport) & 0x0e;
+         id=1;
+         id=id << tarid;
+         if ((id & wide_idu[h]) != 0)
+         {
+            j |= 0x01;
+         }
+         outb(j,tmport);
+         if ( last_lenu[h][tarid] == 0 )
+         {
+            tmport=workportu + 0x18;
+            outb(0x08,tmport);
+            in_int[h]=0;
+            return ;
+         }
+         prd=prd_posu[h][tarid];
+         while ( adrcntu != 0 )
+         {
+              id=((unsigned short int *)(prd))[2];
+              if ( id == 0 )
+              {
+                 k=0x10000;
+              }
+              else
+              {
+                 k=id;
+              }
+              if ( k > adrcntu )
+              {
+                 ((unsigned short int *)(prd))[2] =(unsigned short int)
+                                                    (k - adrcntu);
+                 ((unsigned long *)(prd))[0] += adrcntu;
+                 adrcntu=0;
+                 prd_posu[h][tarid]=prd;
+              }
+              else
+              {
+                 adrcntu -= k;
+                 prdaddru[h][tarid] += 0x08;
+                 prd += 0x08;
+                 if ( adrcntu == 0 )
+                 {
+                    prd_posu[h][tarid]=prd;
+                 }
+              }
+         }
+         tmpcip=pciportu[h] + 0x04;
+         outl(prdaddru[h][tarid],tmpcip);
+         tmpcip -= 0x02;
+         outb(0x06,tmpcip);
+         outb(0x00,tmpcip);
+         tmpcip -= 0x02;
+         tmport=workportu + 0x18;
+         if ( dirctu[h][tarid] != 0 )
+         {
+            outb(0x08,tmport);
+            outb(0x01,tmpcip);
+            in_int[h]=0;
+            return;
+         }
+         outb(0x08,tmport);
+         outb(0x09,tmpcip);
+         in_int[h]=0;
+         return;
+       }
+
+       workrequ=curr_req[h][tarid];
+       if ( i == 0x42 )
+       {
+         errstus=0x02;
+         workrequ->result=errstus;
+         goto go_42;
+       }
+       if ( i == 0x16 )
+       {
+         errstus=0;
+         tmport -= 0x08;
+         errstus=inb(tmport);
+         workrequ->result=errstus;
+/*       if ( errstus == 0x02 )
+         {
+            tmport +=0x10;
+            if ((inb(tmport) & 0x80) != 0)
+            {
+               printk(" autosense ");
+            }
+            tmport -=0x09;
+            outb(0,tmport);
+            tmport=workportu+0x3a;
+            outb((unsigned char)(inb(tmport) | 0x10),tmport);
+            tmport -= 0x39;
+
+            outb(0x08,tmport++);
+            outb(0x7f,tmport++);
+            outb(0x03,tmport++);
+            outb(0x00,tmport++);
+            outb(0x00,tmport++);
+            outb(0x00,tmport++);
+            outb(0x0e,tmport++);
+            outb(0x00,tmport);
+            tmport+=0x07;
+            outb(0x00,tmport++);
+            tmport++;
+            outb(devspu[h][workrequ->target],tmport++);
+            outb(0x00,tmport++);
+            outb(0x00,tmport++);
+            outb(0x0e,tmport++);
+            tmport+=0x03;
+            outb(0x09,tmport);
+            tmport+=0x07;
+            i=0;
+            adrcntu=(unsigned long)(&workrequ->sense_buffer[0]);
+get_sens:
+            j=inb(tmport);
+            if ((j & 0x01) != 0)
+            {
+               tmport-=0x06;
+               (unsigned char)(((caddr_t) adrcntu)[i++])=inb(tmport);
+               tmport+=0x06;
+               goto get_sens;
+            }
+            if ((j & 0x80) == 0)
+            {
+               goto get_sens;
+            }
+            if ((j & 0x40) == 0)
+            {
+               tmport-=0x08;
+               i=inb(tmport);
+            }
+            tmport=workportu+0x3a;
+            outb((unsigned char)(inb(tmport) & 0xef),tmport);
+            tmport=workportu+0x01;
+            outb(0x2c,tmport);
+            tmport += 0x15;
+            outb(0x80,tmport);
+         }   */
+go_42:
+         (*workrequ->scsi_done)(workrequ);
+         curr_req[h][tarid]=0;
+         workingu[h]--;
+         if (wide_idu[h] != 0)
+         {
+            tmport=workportu+0x1b;
+            j=inb(tmport) & 0x0e;
+            j |= 0x01;
+            outb(j,tmport);
+         }
+         if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) &&
+             (in_snd[h] == 0))
+         {
+            send_s870(h);
+         }
+         in_int[h]=0;
+         return;
+       }
+   if ( i == 0x4f )
+   {
+      i=0x89;
+   }
+   i &= 0x0f;
+   if ( i == 0x09 )
+   {
+      tmpcip=tmpcip+4;
+      outl(prdaddru[h][tarid],tmpcip);
+      tmpcip=tmpcip-2;
+      outb(0x06,tmpcip);
+      outb(0x00,tmpcip);
+      tmpcip=tmpcip-2;
+      tmport=workportu+0x10;
+      outb(0x41,tmport);
+      dirctu[h][tarid]=0x00;
+      tmport += 0x08;
+      outb(0x08,tmport);
+      outb(0x09,tmpcip);
+      in_int[h]=0;
+      return;
+   }
+   if ( i == 0x08 )
+   {
+      tmpcip=tmpcip+4;
+      outl(prdaddru[h][tarid],tmpcip);
+      tmpcip=tmpcip-2;
+      outb(0x06,tmpcip);
+      outb(0x00,tmpcip);
+      tmpcip=tmpcip-2;
+      tmport=workportu+0x10;
+      outb(0x41,tmport);
+      tmport += 0x05;
+      outb((unsigned char)(inb(tmport) | 0x20),tmport);
+      dirctu[h][tarid]=0x20;
+      tmport += 0x03;
+      outb(0x08,tmport);
+      outb(0x01,tmpcip);
+      in_int[h]=0;
+      return;
+   }
+   tmport -= 0x07;
+   if ( i == 0x0a )
+   {
+      outb(0x30,tmport);
+   }
+   else
+   {
+      outb(0x46,tmport);
+   }
+   dirctu[h][tarid]=0x00;
+   tmport += 0x02;
+   outb(0x00,tmport++);
+   outb(0x00,tmport++);
+   outb(0x00,tmport++);
+   tmport+=0x03;
+   outb(0x08,tmport);
+   in_int[h]=0;
+   return;
+  }
+  else
+  {
+     tmport=workportu+0x17;
+     inb(tmport);
+     workingu[h]=0;
+     in_int[h]=0;
+     return;
+  }
+}
+
+int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done)(Scsi_Cmnd *))
+{
+    unsigned char i,h;
+    unsigned long flags;
+    unsigned short int m;
+    unsigned int tmport;
+
+    for( h=0; h <= admaxu; h++ )
+    {
+       if ( req_p->host == atp_host[h] )
+       {
+         goto host_ok;
+       }
+    }
+    return 0;
+host_ok:
+   if ( req_p->channel != 0 )
+   {
+      req_p->result = 0x00040000;
+      done(req_p);
+      return 0;
+   }
+   m=1;
+   m=  m << req_p->target;
+   if ( ( m & active_idu[h] ) == 0 )
+   {
+      req_p->result = 0x00040000;
+      done(req_p);
+      return 0;
+   }
+   if (done)
+   {
+      req_p->scsi_done = done;
+   }
+   else
+   {
+      printk("atp870u_queuecommand: done can't be NULL\n");
+      req_p->result = 0;
+      done(req_p);
+      return 0;
+   }
+   quendu[h]++;
+   if ( quendu[h] >= qcnt )
+   {
+      quendu[h]=0;
+   }
+   wait_que_empty:
+     if ( quhdu[h] == quendu[h] )
+     {
+       goto wait_que_empty;
+     }
+     save_flags(flags);
+     cli();
+     querequ[h][quendu[h]]=req_p;
+     if ( quendu[h] == 0 )
+     {
+       i=qcnt-1;
+     }
+     else
+     {
+       i=quendu[h]-1;
+     }
+     tmport = ioportu[h]+0x1c;
+     restore_flags(flags);
+     if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0))
+     {
+        send_s870(h);
+     }
+     return 0;
+}
+
+void mydlyu(unsigned int dlycnt )
+{
+    unsigned int i ;
+    for ( i = 0 ; i < dlycnt ; i++ )
+    {
+       inb(0x80);
+    }
+}
+
+void send_s870(unsigned char h)
+{
+     unsigned int  tmport;
+     Scsi_Cmnd *workrequ;
+     unsigned long flags;
+     unsigned int   i;
+     unsigned char  j,tarid;
+     unsigned char  *prd;
+     unsigned short int   tmpcip,w;
+     unsigned long  l,bttl;
+     unsigned int workportu;
+     struct scatterlist * sgpnt;
+
+       save_flags(flags);
+       cli();
+       if ( in_snd[h] != 0 )
+       {
+          restore_flags(flags);
+          return;
+       }
+       in_snd[h]=1;
+       if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0))
+       {
+          last_cmd[h] &= 0x0f;
+          workrequ=curr_req[h][last_cmd[h]];
+          goto cmd_subp;
+       }
+       workingu[h]++;
+       j=quhdu[h];
+       quhdu[h]++;
+       if ( quhdu[h] >= qcnt )
+       {
+          quhdu[h]=0;
+       }
+       workrequ=querequ[h][quhdu[h]];
+       if ( curr_req[h][workrequ->target] == 0 )
+       {
+          curr_req[h][workrequ->target]=workrequ;
+          last_cmd[h]=workrequ->target;
+          goto cmd_subp;
+       }
+       quhdu[h]=j;
+       workingu[h]--;
+       in_snd[h]=0;
+       restore_flags(flags);
+       return ;
+cmd_subp:
+   workportu=ioportu[h];
+   tmport=workportu+0x1f;
+   if ((inb(tmport) & 0xb0) != 0)
+   {
+      goto abortsnd;
+   }
+   tmport=workportu+0x1c;
+   if ( inb(tmport) == 0 )
+   {
+      goto oktosend;
+   }
+abortsnd:
+   last_cmd[h] |= 0x40;
+   in_snd[h]=0;
+   restore_flags(flags);
+   return;
+oktosend:
+   memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len);
+   if ( ata_cdbu[h][0] == 0x25 )
+   {
+      if ( workrequ->request_bufflen > 8 )
+      {
+        workrequ->request_bufflen=0x08;
+      }
+   }
+   if ( ata_cdbu[h][0] == 0x12 )
+   {
+      if ( workrequ->request_bufflen > 0x24 )
+      {
+        workrequ->request_bufflen = 0x24;
+        ata_cdbu[h][4]=0x24;
+      }
+   }
+
+   tmport=workportu+0x1b;
+   j=inb(tmport) & 0x0e;
+   tarid=workrequ->target;
+   w=1;
+   w = w << tarid;
+   if ((w & wide_idu[h]) != 0)
+   {
+      j |= 0x01;
+   }
+   outb(j,tmport);
+   tmport=workportu;
+   outb(workrequ->cmd_len,tmport++);
+   outb(0x2c,tmport++);
+   outb(0xcf,tmport++);
+   for ( i=0 ; i < workrequ->cmd_len ; i++ )
+   {
+       outb(ata_cdbu[h][i],tmport++);
+   }
+   tmport=workportu+0x0f;
+   outb(0x00,tmport);
+   tmport+=0x02;
+   outb(devspu[h][tarid],tmport++);
+   if (workrequ->use_sg)
+   {
+
+     l=0;
+     sgpnt = (struct scatterlist *) workrequ->request_buffer;
+     for(i=0; i<workrequ->use_sg; i++)
+     {
+       if(sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER)
+       {
+        panic("Foooooooood fight!");
+       }
+       l += sgpnt[i].length;
+     }
+   }
+   else
+   {
+     l=workrequ->request_bufflen;
+   }
+   outb((unsigned char)(((unsigned char *)(&l))[2]),tmport++);
+   outb((unsigned char)(((unsigned char *)(&l))[1]),tmport++);
+   outb((unsigned char)(((unsigned char *)(&l))[0]),tmport++);
+   j=tarid;
+   last_lenu[h][j]=l;
+   tran_lenu[h][j]=0;
+   if ((j & 0x08) != 0)
+   {
+      j=(j & 0x07) | 0x40;
+   }
+   if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+       (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
+   {
+      outb((unsigned char)(j | 0x20),tmport++);
+   }
+   else
+   {
+      outb(j,tmport++);
+   }
+   outb(0x80,tmport);
+   tmport=workportu + 0x1c;
+   dirctu[h][tarid]=0;
+   if ( l == 0 )
+   {
+      if ( inb(tmport) == 0 )
+      {
+        tmport=workportu+0x18;
+        outb(0x08,tmport);
+      }
+      else
+      {
+       last_cmd[h] |= 0x40;
+      }
+      in_snd[h]=0;
+      restore_flags(flags);
+      return;
+   }
+   tmpcip=pciportu[h];
+   prd=&prd_tableu[h][tarid][0];
+   prd_posu[h][tarid]=prd;
+   if (workrequ->use_sg)
+   {
+     sgpnt = (struct scatterlist *) workrequ->request_buffer;
+     i=0;
+     for(j=0; j<workrequ->use_sg; j++)
+     {
+       (unsigned long)(((unsigned long *)(prd))[i >> 1])=(unsigned long)sgpnt[j].address;
+       (unsigned short int)(((unsigned short int *)(prd))[i+2])=sgpnt[j].length;
+       (unsigned short int)(((unsigned short int *)(prd))[i+3])=0;
+       i +=0x04;
+     }
+     (unsigned short int)(((unsigned short int *)(prd))[i-1])=0x8000;
+   }
+   else
+   {
+     bttl=(unsigned long)workrequ->request_buffer;
+     l=workrequ->request_bufflen;
+     i=0;
+     while ( l > 0x10000 )
+     {
+       (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x0000;
+       (unsigned short int)(((unsigned short int *)(prd))[i+2])=0x0000;
+       (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
+       l -= 0x10000;
+       bttl += 0x10000;
+       i += 0x04;
+     }
+     (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x8000;
+     (unsigned short int)(((unsigned short int *)(prd))[i+2])=l;
+     (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
+   }
+   tmpcip=tmpcip+4;
+   prdaddru[h][tarid]=(unsigned long)&prd_tableu[h][tarid][0];
+   outl(prdaddru[h][tarid],tmpcip);
+   tmpcip=tmpcip-2;
+   outb(0x06,tmpcip);
+   outb(0x00,tmpcip);
+   tmpcip=tmpcip-2;
+   if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+       (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
+   {
+      dirctu[h][tarid]=0x20;
+      if ( inb(tmport) == 0 )
+      {
+        tmport=workportu+0x18;
+        outb(0x08,tmport);
+        outb(0x01,tmpcip);
+      }
+      else
+      {
+        last_cmd[h] |= 0x40;
+      }
+      in_snd[h]=0;
+      restore_flags(flags);
+      return;
+   }
+   if ( inb(tmport) == 0 )
+   {
+      tmport=workportu+0x18;
+      outb(0x08,tmport);
+      outb(0x09,tmpcip);
+   }
+   else
+   {
+      last_cmd[h] |= 0x40;
+   }
+   in_snd[h]=0;
+   restore_flags(flags);
+   return;
+
+}
+
+static void internal_done(Scsi_Cmnd * SCpnt)
+{
+       SCpnt->SCp.Status++;
+}
+
+int atp870u_command(Scsi_Cmnd * SCpnt)
+{
+
+    atp870u_queuecommand(SCpnt, internal_done);
+
+    SCpnt->SCp.Status = 0;
+    while (!SCpnt->SCp.Status)
+       barrier();
+    return SCpnt->result;
+}
+
+unsigned char fun_scam ( unsigned char host,unsigned short int * val )
+{
+    unsigned int  tmport ;
+    unsigned short int  i,k;
+    unsigned char     j;
+
+    tmport = ioportu[host]+0x1c;
+    outw(*val,tmport);
+FUN_D7:
+    for ( i=0; i < 10; i++ )        /* stable >= bus settle delay(400 ns)  */
+    {
+       k=inw(tmport);
+       j= (unsigned char)(k >> 8);
+       if ((k & 0x8000) != 0)       /* DB7 all release?    */
+       {
+          goto  FUN_D7;
+       }
+    }
+    *val |= 0x4000;                /* assert DB6           */
+    outw(*val,tmport);
+    *val &= 0xdfff;                /* assert DB5           */
+    outw(*val,tmport);
+FUN_D5:
+    for ( i=0; i < 10; i++ )       /* stable >= bus settle delay(400 ns) */
+    {
+       if ((inw(tmport) & 0x2000) != 0)   /* DB5 all release?  */
+       {
+         goto  FUN_D5;
+       }
+    }
+    *val |= 0x8000;                 /* no DB4-0, assert DB7    */
+    *val &= 0xe0ff;
+    outw(*val,tmport);
+    *val &= 0xbfff;                 /* release DB6             */
+    outw(*val,tmport);
+FUN_D6:
+    for ( i=0; i < 10; i++ )        /* stable >= bus settle delay(400 ns)  */
+    {
+       if ((inw(tmport) & 0x4000) != 0)   /* DB6 all release?  */
+       {
+         goto  FUN_D6;
+       }
+    }
+
+    return j;
+}
+
+void tscam( unsigned char host )
+{
+
+    unsigned int  tmport ;
+    unsigned char  i,j,k;
+    unsigned long  n;
+    unsigned short int m,assignid_map,val;
+    unsigned char  mbuf[33],quintet[2];
+    static unsigned char g2q_tab[8]={ 0x38,0x31,0x32,0x2b,0x34,0x2d,0x2e,0x27 };
+
+
+    for ( i=0; i < 0x10; i++ )
+    {
+       mydlyu(0xffff);
+    }
+
+    tmport = ioportu[host]+1;
+    outb(0x08,tmport++);
+    outb(0x7f,tmport);
+    tmport = ioportu[host]+0x11;
+    outb(0x20,tmport);
+
+    if ((scam_on[host] & 0x40) == 0)
+    {
+       return;
+    }
+
+    m=1;
+    m <<= host_idu[host];
+    j=16;
+    if ( chip_veru[host] < 4 )
+    {
+       m |= 0xff00;
+       j=8;
+    }
+    assignid_map=m;
+    tmport = ioportu[host]+0x02;
+    outb(0x02,tmport++);       /* 2*2=4ms,3EH 2/32*3E=3.9ms */
+    outb(0,tmport++);
+    outb(0,tmport++);
+    outb(0,tmport++);
+    outb(0,tmport++);
+    outb(0,tmport++);
+    outb(0,tmport++);
+
+    for ( i = 0 ; i < j ; i ++ )
+    {
+       m=1;
+       m=m<<i;
+       if ( ( m & assignid_map ) != 0 )
+       {
+          continue;
+       }
+    tmport = ioportu[host]+0x0f;
+    outb(0,tmport++);
+    tmport += 0x02;
+    outb(0,tmport++);
+    outb(0,tmport++);
+    outb(0,tmport++);
+    if ( i > 7 )
+    {
+       k=(i & 0x07) | 0x40;
+    }
+    else
+    {
+       k=i;
+    }
+    outb(k,tmport++);
+    tmport = ioportu[host]+0x1b;
+    if ( chip_veru[host] == 4 )
+    {
+       outb((unsigned char)((inb(tmport) & 0x0e) | 0x01),tmport);
+    }
+    else
+    {
+       outb((unsigned char)(inb(tmport) & 0x0e),tmport);
+    }
+wait_rdyok:
+    tmport = ioportu[host]+0x18;
+    outb(0x09,tmport);
+    tmport += 0x07;
+
+    while ((inb(tmport) & 0x80) == 0x00);
+    tmport -= 0x08;
+    k=inb(tmport);
+    if ( k != 0x16 )
+    {
+       if ((k == 0x85) || (k == 0x42))
+       {
+         continue;
+       }
+       tmport = ioportu[host]+0x10;
+       outb(0x41,tmport);
+       goto wait_rdyok;
+    }
+    assignid_map |= m;
+
+    }
+    tmport = ioportu[host]+0x02;
+    outb(0x7f,tmport);
+    tmport = ioportu[host]+0x1b;
+    outb(0x02,tmport);
+
+    outb(0,0x80);
+
+    val=0x0080;      /* bsy  */
+    tmport = ioportu[host]+0x1c;
+    outw(val,tmport);
+    val |=0x0040;    /* sel  */
+    outw(val,tmport);
+    val |=0x0004;    /* msg  */
+    outw(val,tmport);
+    inb(0x80);               /* 2 deskew delay(45ns*2=90ns) */
+    val &=0x007f;    /* no bsy */
+    outw(val,tmport);
+    mydlyu(0xffff);  /* recommanded SCAM selection response time */
+    mydlyu(0xffff);
+    val &=0x00fb;    /* after 1ms no msg */
+    outw(val,tmport);
+wait_nomsg:
+    if ((inb(tmport) & 0x04) != 0)
+    {
+       goto wait_nomsg;
+    }
+    outb(1,0x80);
+    mydlyu(100);
+    for ( n=0; n < 0x30000; n++ )
+    {
+       if ((inb(tmport) & 0x80) != 0)     /* bsy ? */
+       {
+          goto wait_io;
+       }
+    }
+    goto  TCM_SYNC;
+wait_io:
+    for ( n=0; n < 0x30000; n++ )
+    {
+       if ((inb(tmport) & 0x81) == 0x0081)
+       {
+          goto wait_io1;
+       }
+    }
+    goto  TCM_SYNC;
+wait_io1:
+    inb(0x80);
+    val |=0x8003;    /* io,cd,db7  */
+    outw(val,tmport);
+    inb(0x80);
+    val &=0x00bf;    /* no sel    */
+    outw(val,tmport);
+    outb(2,0x80);
+TCM_SYNC:
+    mydlyu(0x800);
+    if ((inb(tmport) & 0x80) == 0x00)   /* bsy ? */
+    {
+       outw(0,tmport--);
+       outb(0,tmport);
+       tmport=ioportu[host] + 0x15;
+       outb(0,tmport);
+       tmport += 0x03;
+       outb(0x09,tmport);
+       tmport += 0x07;
+       while ((inb(tmport) & 0x80) == 0);
+       tmport -= 0x08;
+       inb(tmport);
+       return;
+    }
+
+    val &= 0x00ff;              /* synchronization  */
+    val |= 0x3f00;
+    fun_scam(host,&val);
+    outb(3,0x80);
+    val &= 0x00ff;              /* isolation        */
+    val |= 0x2000;
+    fun_scam(host,&val);
+    outb(4,0x80);
+    i=8;
+    j=0;
+TCM_ID:
+    if ((inw(tmport) & 0x2000) == 0)
+    {
+       goto TCM_ID;
+    }
+    outb(5,0x80);
+    val &= 0x00ff;              /* get ID_STRING */
+    val |= 0x2000;
+    k=fun_scam(host,&val);
+    if ((k & 0x03) == 0)
+    {
+       goto TCM_5;
+    }
+    mbuf[j] <<= 0x01;
+    mbuf[j] &= 0xfe;
+    if ((k & 0x02) != 0)
+    {
+       mbuf[j] |= 0x01;
+    }
+    i--;
+    if ( i > 0 )
+    {
+       goto TCM_ID;
+    }
+    j++;
+    i=8;
+    goto TCM_ID;
+
+TCM_5:                      /* isolation complete..  */
+/*    mbuf[32]=0;
+    printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
+    i=15;
+    j=mbuf[0];
+    if ((j & 0x20) != 0)     /* bit5=1:ID upto 7      */
+    {
+       i=7;
+    }
+    if ((j & 0x06) == 0)     /* IDvalid?             */
+    {
+       goto  G2Q5;
+    }
+    k=mbuf[1];
+small_id:
+    m=1;
+    m <<= k;
+    if ((m & assignid_map) == 0)
+    {
+       goto G2Q_QUIN;
+    }
+    if ( k > 0 )
+    {
+       k--;
+       goto small_id;
+    }
+G2Q5:                        /* srch from max acceptable ID#  */
+    k=i;                     /* max acceptable ID#            */
+G2Q_LP:
+    m=1;
+    m <<= k;
+    if ((m & assignid_map) == 0)
+    {
+       goto G2Q_QUIN;
+    }
+    if ( k > 0 )
+    {
+       k--;
+       goto G2Q_LP;
+    }
+G2Q_QUIN:                    /* k=binID#,       */
+    assignid_map |= m;
+    if ( k < 8 )
+    {
+       quintet[0]=0x38;       /* 1st dft ID<8   */
+    }
+    else
+    {
+       quintet[0]=0x31;       /* 1st  ID>=8     */
+    }
+    k &= 0x07;
+    quintet[1]=g2q_tab[k];
+
+    val &= 0x00ff;            /* AssignID 1stQuintet,AH=001xxxxx  */
+    m=quintet[0] << 8;
+    val |= m;
+    fun_scam(host,&val);
+    val &= 0x00ff;            /* AssignID 2ndQuintet,AH=001xxxxx */
+    m=quintet[1] << 8;
+    val |= m;
+    fun_scam(host,&val);
+
+    goto TCM_SYNC;
+
+}
+
+void is870(unsigned long host,unsigned int wkport )
+{
+    unsigned int  tmport ;
+    unsigned char i,j,k,rmb;
+    unsigned short int m;
+    static unsigned char mbuf[512];
+    static unsigned char satn[9] = { 0,0,0,0,0,0,0,6,6 };
+    static unsigned char inqd[9] = { 0x12,0,0,0,0x24,0,0,0x24,6 };
+    static unsigned char synn[6] = { 0x80,1,3,1,0x19,0x0e };
+    static unsigned char synu[6] = { 0x80,1,3,1,0x0c,0x0e };
+    static unsigned char synw[6] = { 0x80,1,3,1,0x0c,0x07 };
+    static unsigned char wide[6] = { 0x80,1,2,3,1,0 };
+
+    sync_idu=0;
+    tmport=wkport+0x3a;
+    outb((unsigned char)(inb(tmport) | 0x10),tmport);
+
+    for ( i = 0 ; i < 16 ; i ++ )
+    {
+       if ((chip_veru[host] != 4) && (i > 7))
+       {
+          break;
+       }
+       m=1;
+       m=m<<i;
+       if ( ( m & active_idu[host] ) != 0 )
+       {
+          continue;
+       }
+       if ( i == host_idu[host] )
+       {
+          printk("         ID: %2d  Host Adapter\n",host_idu[host]);
+          continue;
+       }
+       if ( chip_veru[host] == 4 )
+       {
+          tmport=wkport+0x1b;
+          j=(inb(tmport) & 0x0e) | 0x01;
+          outb(j,tmport);
+       }
+    tmport=wkport+1;
+    outb(0x08,tmport++);
+    outb(0x7f,tmport++);
+    outb(satn[0],tmport++);
+    outb(satn[1],tmport++);
+    outb(satn[2],tmport++);
+    outb(satn[3],tmport++);
+    outb(satn[4],tmport++);
+    outb(satn[5],tmport++);
+    tmport+=0x06;
+    outb(0,tmport);
+    tmport+=0x02;
+    outb(devspu[host][i],tmport++);
+    outb(0,tmport++);
+    outb(satn[6],tmport++);
+    outb(satn[7],tmport++);
+    j=i;
+    if ((j & 0x08) != 0)
+    {
+       j=(j & 0x07) | 0x40;
+    }
+    outb(j,tmport);
+    tmport+=0x03;
+    outb(satn[8],tmport);
+    tmport+=0x07;
+
+    while ((inb(tmport) & 0x80) == 0x00);
+    tmport-=0x08;
+    if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+    {
+       continue;
+    }
+    while ( inb(tmport) != 0x8e );
+    active_idu[host] |= m;
+
+    tmport=wkport+0x10;
+    outb(0x30,tmport);
+    tmport=wkport+0x04;
+    outb(0x00,tmport);
+
+phase_cmd:
+    tmport=wkport+0x18;
+    outb(0x08,tmport);
+    tmport+=0x07;
+    while ((inb(tmport) & 0x80) == 0x00);
+    tmport-=0x08;
+    j=inb(tmport);
+    if ( j != 0x16 )
+    {
+       tmport=wkport+0x10;
+       outb(0x41,tmport);
+       goto phase_cmd;
+    }
+sel_ok:
+       tmport=wkport+3;
+       outb(inqd[0],tmport++);
+       outb(inqd[1],tmport++);
+       outb(inqd[2],tmport++);
+       outb(inqd[3],tmport++);
+       outb(inqd[4],tmport++);
+       outb(inqd[5],tmport);
+       tmport+=0x07;
+       outb(0,tmport);
+       tmport+=0x02;
+       outb(devspu[host][i],tmport++);
+       outb(0,tmport++);
+       outb(inqd[6],tmport++);
+       outb(inqd[7],tmport++);
+       tmport+=0x03;
+       outb(inqd[8],tmport);
+       tmport+=0x07;
+       while ((inb(tmport) & 0x80) == 0x00);
+       tmport-=0x08;
+       if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+       {
+         continue;
+       }
+       while ( inb(tmport) != 0x8e );
+       if ( chip_veru[host] == 4 )
+       {
+         tmport=wkport+0x1b;
+         j=inb(tmport) & 0x0e;
+         outb(j,tmport);
+       }
+       tmport=wkport+0x18;
+       outb(0x08,tmport);
+       tmport += 0x07;
+       j=0;
+rd_inq_data:
+       k=inb(tmport);
+       if ((k & 0x01) != 0 )
+       {
+         tmport-=0x06;
+         mbuf[j++]=inb(tmport);
+         tmport+=0x06;
+         goto rd_inq_data;
+       }
+       if ((k & 0x80) == 0 )
+       {
+         goto rd_inq_data;
+       }
+       tmport-=0x08;
+       j=inb(tmport);
+       if ( j == 0x16 )
+       {
+         goto inq_ok;
+       }
+    tmport=wkport+0x10;
+    outb(0x46,tmport);
+    tmport+=0x02;
+    outb(0,tmport++);
+    outb(0,tmport++);
+    outb(0,tmport++);
+    tmport+=0x03;
+    outb(0x08,tmport);
+    tmport+=0x07;
+    while ((inb(tmport) & 0x80) == 0x00);
+    tmport-=0x08;
+    if (inb(tmport) != 0x16)
+    {
+       goto sel_ok;
+    }
+inq_ok:
+     mbuf[36]=0;
+     printk("         ID: %2d  %s\n",i,&mbuf[8]);
+     devtypeu[host][i]=mbuf[0];
+     rmb=mbuf[1];
+     if ( chip_veru[host] != 4 )
+     {
+       goto not_wide;
+     }
+     if ((mbuf[7] & 0x60) == 0)
+     {
+       goto not_wide;
+     }
+     if ((global_map[host] & 0x20) == 0)
+     {
+       goto not_wide;
+     }
+     tmport=wkport+0x1b;
+     j=(inb(tmport) & 0x0e) | 0x01;
+     outb(j,tmport);
+    tmport=wkport+3;
+    outb(satn[0],tmport++);
+    outb(satn[1],tmport++);
+    outb(satn[2],tmport++);
+    outb(satn[3],tmport++);
+    outb(satn[4],tmport++);
+    outb(satn[5],tmport++);
+    tmport+=0x06;
+    outb(0,tmport);
+    tmport+=0x02;
+    outb(devspu[host][i],tmport++);
+    outb(0,tmport++);
+    outb(satn[6],tmport++);
+    outb(satn[7],tmport++);
+    tmport+=0x03;
+    outb(satn[8],tmport);
+    tmport+=0x07;
+
+    while ((inb(tmport) & 0x80) == 0x00);
+    tmport-=0x08;
+    if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+    {
+       continue;
+    }
+    while ( inb(tmport) != 0x8e );
+try_wide:
+    j=0;
+    tmport=wkport+0x14;
+    outb(0x05,tmport);
+    tmport += 0x04;
+    outb(0x20,tmport);
+    tmport+=0x07;
+
+    while ((inb(tmport) & 0x80) == 0 )
+    {
+       if ((inb(tmport) & 0x01) != 0 )
+       {
+         tmport-=0x06;
+         outb(wide[j++],tmport);
+         tmport+=0x06;
+       }
+    }
+    tmport-=0x08;
+    while ((inb(tmport) & 0x80) == 0x00);
+    j=inb(tmport) & 0x0f;
+    if ( j == 0x0f )
+    {
+       goto widep_in;
+    }
+    if ( j == 0x0a )
+    {
+       goto widep_cmd;
+    }
+    if ( j == 0x0e )
+    {
+       goto try_wide;
+    }
+    continue;
+widep_out:
+    tmport=wkport+0x18;
+    outb(0x20,tmport);
+    tmport+=0x07;
+    while ((inb(tmport) & 0x80) == 0 )
+    {
+       if ((inb(tmport) & 0x01) != 0 )
+       {
+          tmport-=0x06;
+          outb(0,tmport);
+          tmport+=0x06;
+       }
+    }
+    tmport-=0x08;
+    j=inb(tmport) & 0x0f;
+    if ( j == 0x0f )
+    {
+       goto widep_in;
+    }
+    if ( j == 0x0a )
+    {
+       goto widep_cmd;
+    }
+    if ( j == 0x0e )
+    {
+       goto widep_out;
+    }
+    continue;
+widep_in:
+    tmport=wkport+0x14;
+    outb(0xff,tmport);
+    tmport += 0x04;
+    outb(0x20,tmport);
+    tmport+=0x07;
+    k=0;
+widep_in1:
+    j=inb(tmport);
+    if ((j & 0x01) != 0)
+    {
+       tmport-=0x06;
+       mbuf[k++]=inb(tmport);
+       tmport+=0x06;
+       goto widep_in1;
+    }
+    if ((j & 0x80) == 0x00)
+    {
+       goto widep_in1;
+    }
+    tmport-=0x08;
+    j=inb(tmport) & 0x0f;
+    if ( j == 0x0f )
+    {
+       goto widep_in;
+    }
+    if ( j == 0x0a )
+    {
+       goto widep_cmd;
+    }
+    if ( j == 0x0e )
+    {
+       goto widep_out;
+    }
+    continue;
+widep_cmd:
+    tmport=wkport+0x10;
+    outb(0x30,tmport);
+    tmport=wkport+0x14;
+    outb(0x00,tmport);
+    tmport+=0x04;
+    outb(0x08,tmport);
+    tmport+=0x07;
+    while ((inb(tmport) & 0x80) == 0x00);
+    tmport-=0x08;
+    j=inb(tmport);
+    if ( j != 0x16 )
+    {
+       if ( j == 0x4e )
+       {
+         goto widep_out;
+       }
+       continue;
+    }
+    if ( mbuf[0] != 0x01 )
+    {
+       goto not_wide;
+    }
+    if ( mbuf[1] != 0x02 )
+    {
+       goto not_wide;
+    }
+    if ( mbuf[2] != 0x03 )
+    {
+       goto not_wide;
+    }
+    if ( mbuf[3] != 0x01 )
+    {
+       goto not_wide;
+    }
+    m=1;
+    m = m << i;
+    wide_idu[host] |= m;
+not_wide:
+    if ((devtypeu[host][i] == 0x00) || (devtypeu[host][i] == 0x07))
+    {
+       goto set_sync;
+    }
+    continue;
+set_sync:
+    tmport=wkport+0x1b;
+    j=inb(tmport) & 0x0e;
+    if ((m & wide_idu[host]) != 0 )
+    {
+       j |= 0x01;
+    }
+    outb(j,tmport);
+    tmport=wkport+3;
+    outb(satn[0],tmport++);
+    outb(satn[1],tmport++);
+    outb(satn[2],tmport++);
+    outb(satn[3],tmport++);
+    outb(satn[4],tmport++);
+    outb(satn[5],tmport++);
+    tmport+=0x06;
+    outb(0,tmport);
+    tmport+=0x02;
+    outb(devspu[host][i],tmport++);
+    outb(0,tmport++);
+    outb(satn[6],tmport++);
+    outb(satn[7],tmport++);
+    tmport+=0x03;
+    outb(satn[8],tmport);
+    tmport+=0x07;
+
+    while ((inb(tmport) & 0x80) == 0x00);
+    tmport-=0x08;
+    if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
+    {
+       continue;
+    }
+    while ( inb(tmport) != 0x8e);
+try_sync:
+    j=0;
+    tmport=wkport+0x14;
+    outb(0x06,tmport);
+    tmport += 0x04;
+    outb(0x20,tmport);
+    tmport+=0x07;
+
+    while ((inb(tmport) & 0x80) == 0 )
+    {
+       if ((inb(tmport) & 0x01) != 0 )
+       {
+         tmport-=0x06;
+         if ( rmb != 0 )
+         {
+            outb(synn[j++],tmport);
+         }
+         else
+         {
+            if ((m & wide_idu[host]) != 0)
+            {
+               outb(synw[j++],tmport);
+            }
+            else
+            {
+               if ((m & ultra_map[host]) != 0)
+               {
+                  outb(synu[j++],tmport);
+               }
+               else
+               {
+                  outb(synn[j++],tmport);
+               }
+            }
+         }
+         tmport+=0x06;
+       }
+    }
+    tmport-=0x08;
+    while ((inb(tmport) & 0x80) == 0x00);
+    j=inb(tmport) & 0x0f;
+    if ( j == 0x0f )
+    {
+       goto phase_ins;
+    }
+    if ( j == 0x0a )
+    {
+       goto phase_cmds;
+    }
+    if ( j == 0x0e )
+    {
+       goto try_sync;
+    }
+    continue;
+phase_outs:
+    tmport=wkport+0x18;
+    outb(0x20,tmport);
+    tmport+=0x07;
+    while ((inb(tmport) & 0x80) == 0x00)
+    {
+      if ((inb(tmport) & 0x01) != 0x00)
+      {
+        tmport-=0x06;
+        outb(0x00,tmport);
+        tmport+=0x06;
+      }
+    }
+    tmport-=0x08;
+    j=inb(tmport);
+    if ( j == 0x85 )
+    {
+       goto tar_dcons;
+    }
+    j &= 0x0f;
+    if ( j == 0x0f )
+    {
+       goto phase_ins;
+    }
+    if ( j == 0x0a )
+    {
+       goto phase_cmds;
+    }
+    if ( j == 0x0e )
+    {
+       goto phase_outs;
+    }
+    continue;
+phase_ins:
+    tmport=wkport+0x14;
+    outb(0xff,tmport);
+    tmport += 0x04;
+    outb(0x20,tmport);
+    tmport+=0x07;
+    k=0;
+phase_ins1:
+    j=inb(tmport);
+    if ((j & 0x01) != 0x00)
+    {
+       tmport-=0x06;
+       mbuf[k++]=inb(tmport);
+       tmport+=0x06;
+       goto phase_ins1;
+    }
+    if ((j & 0x80) == 0x00)
+    {
+       goto phase_ins1;
+    }
+    tmport-=0x08;
+    while ((inb(tmport) & 0x80) == 0x00);
+    j=inb(tmport);
+    if ( j == 0x85 )
+    {
+       goto tar_dcons;
+    }
+    j &= 0x0f;
+    if ( j == 0x0f )
+    {
+       goto phase_ins;
+    }
+    if ( j == 0x0a )
+    {
+       goto phase_cmds;
+    }
+    if ( j == 0x0e )
+    {
+       goto phase_outs;
+    }
+    continue;
+phase_cmds:
+    tmport=wkport+0x10;
+    outb(0x30,tmport);
+tar_dcons:
+    tmport=wkport+0x14;
+    outb(0x00,tmport);
+    tmport+=0x04;
+    outb(0x08,tmport);
+    tmport+=0x07;
+    while ((inb(tmport) & 0x80) == 0x00);
+    tmport-=0x08;
+    j=inb(tmport);
+    if ( j != 0x16 )
+    {
+       continue;
+    }
+    if ( mbuf[0] != 0x01 )
+    {
+       continue;
+    }
+    if ( mbuf[1] != 0x03 )
+    {
+       continue;
+    }
+    if ( mbuf[4] == 0x00 )
+    {
+       continue;
+    }
+    if ( mbuf[3] > 0x64 )
+    {
+       continue;
+    }
+    if ( mbuf[4] > 0x0c )
+    {
+       mbuf[4]=0x0c;
+    }
+    devspu[host][i] = mbuf[4];
+    if ((mbuf[3] < 0x0d) && (rmb == 0))
+    {
+       j=0xa0;
+       goto set_syn_ok;
+    }
+    if ( mbuf[3] < 0x1a )
+    {
+       j=0x20;
+       goto set_syn_ok;
+    }
+    if ( mbuf[3] < 0x33 )
+    {
+       j=0x40;
+       goto set_syn_ok;
+    }
+    if ( mbuf[3] < 0x4c )
+    {
+       j=0x50;
+       goto set_syn_ok;
+    }
+    j=0x60;
+set_syn_ok:
+    devspu[host][i] = (devspu[host][i] & 0x0f) | j;
+   }
+   tmport=wkport+0x3a;
+   outb((unsigned char)(inb(tmport) & 0xef),tmport);
+}
+
+/* return non-zero on detection */
+int atp870u_detect(Scsi_Host_Template * tpnt)
+{
+    unsigned char irq,h,k;
+    unsigned long flags;
+    unsigned int base_io,error,tmport;
+    unsigned short index = 0;
+    unsigned char pci_bus[3], pci_device_fn[3], chip_ver[3],host_id;
+    struct Scsi_Host * shpnt = NULL;
+    int count = 0;
+    static unsigned short devid[7]={0x8002,0x8010,0x8020,0x8030,0x8040,0x8050,0};
+       static struct pci_dev *pdev = NULL;
+
+    printk("aec671x_detect: \n");
+    if (!pci_present())
+    {
+       printk("   NO BIOS32 SUPPORT.\n");
+       return count;
+    }
+
+    tpnt->proc_dir = &proc_scsi_atp870u;
+
+    for ( h = 0 ; h < 2 ; h++ )
+    {
+      active_idu[h]=0;
+      wide_idu[h]=0;
+      host_idu[h]=0x07;
+      quhdu[h]=0;
+      quendu[h]=0;
+      pci_bus[h]=0;
+      pci_device_fn[h]=0xff;
+      chip_ver[h]=0;
+      last_cmd[h]=0xff;
+      in_snd[h]=0;
+      in_int[h]=0;
+      for ( k = 0 ; k < qcnt ; k++ )
+      {
+         querequ[h][k]=0;
+      }
+      for ( k = 0 ; k < 16 ; k++ )
+      {
+         curr_req[h][k]=0;
+      }
+    }
+    h=0;
+    while ( devid[h] != 0 )
+    {
+      pci_find_device(0x1191,devid[h],pdev);
+      if (pdev == NULL); {
+         h++;
+         index=0;
+         continue;
+       }
+       chip_ver[2]=0;
+          
+       /* To avoid messing with the things below...  */
+       pci_device_fn[2] =  pdev->devfn;
+       pci_bus[2] = pdev->bus->number;
+
+       if ( devid[h] == 0x8002 )
+       {
+         error = pci_read_config_byte(pdev,0x08,&chip_ver[2]);
+         if ( chip_ver[2] < 2 )
+         {
+            goto nxt_devfn;
+         }
+       }
+       if ( devid[h] == 0x8010 )
+       {
+         chip_ver[2]=0x04;
+       }
+       if ( pci_device_fn[2] < pci_device_fn[0] )
+       {
+         pci_bus[1]=pci_bus[0];
+         pci_device_fn[1]=pci_device_fn[0];
+         chip_ver[1]=chip_ver[0];
+         pci_bus[0]=pci_bus[2];
+         pci_device_fn[0]=pci_device_fn[2];
+         chip_ver[0]=chip_ver[2];
+       }
+       else if ( pci_device_fn[2] < pci_device_fn[1] )
+       {
+         pci_bus[1]=pci_bus[2];
+         pci_device_fn[1]=pci_device_fn[2];
+         chip_ver[1]=chip_ver[2];
+       }
+nxt_devfn:
+       index++;
+       if ( index > 3 )
+       {
+         index=0;
+         h++;
+       }
+    }
+    for ( h=0; h < 2; h++ )
+    {
+    if ( pci_device_fn[h] == 0xff )
+    {
+       return count;
+    }
+
+    pdev->devfn = pci_device_fn[h];
+    pdev->bus->number = pci_bus[h];
+
+    /* Found an atp870u/w. */
+    error = pci_read_config_dword(pdev,0x10,&base_io);
+    error += pci_read_config_byte(pdev,0x3c,&irq);
+    error += pci_read_config_byte(pdev,0x49,&host_id);
+
+    base_io &= 0xfffffff8;
+    printk("   ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d    IO:%x, IRQ:%d.\n"
+                            ,h,base_io,irq);
+    ioportu[h]=base_io;
+    pciportu[h]=base_io + 0x20;
+    irqnumu[h]=irq;
+    host_id &= 0x07;
+    host_idu[h]=host_id;
+    chip_veru[h]=chip_ver[h];
+
+    tmport=base_io+0x22;
+    scam_on[h]=inb(tmport);
+    tmport += 0x0b;
+    global_map[h]=inb(tmport++);
+    ultra_map[h]=inw(tmport);
+    if ( ultra_map[h] == 0 )
+    {
+       scam_on[h]=0x00;
+       global_map[h]=0x20;
+       ultra_map[h]=0xffff;
+    }
+
+    shpnt = scsi_register(tpnt,4);
+
+    save_flags(flags);
+    cli();
+    if (request_irq(irq,atp870u_intr_handle, 0, "atp870u", NULL))
+    {
+       printk("Unable to allocate IRQ for Acard controller.\n");
+       goto unregister;
+    }
+
+    tmport=base_io+0x3a;
+    k=(inb(tmport) & 0xf3) | 0x10;
+    outb(k,tmport);
+    outb((k & 0xdf),tmport);
+    mydlyu(0x8000);
+    outb(k,tmport);
+    mydlyu(0x8000);
+    tmport=base_io;
+    outb((host_id | 0x08),tmport);
+    tmport += 0x18;
+    outb(0,tmport);
+    tmport += 0x07;
+    while ((inb(tmport) & 0x80) == 0);
+    tmport -= 0x08;
+    inb(tmport);
+    tmport = base_io +1;
+    outb(8,tmport++);
+    outb(0x7f,tmport);
+    tmport = base_io + 0x11;
+    outb(0x20,tmport);
+
+    tscam(h);
+    is870(h,base_io);
+    tmport=base_io+0x3a;
+    outb((inb(tmport) & 0xef),tmport);
+
+    atp_host[h] = shpnt;
+    if ( chip_ver[h] == 4 )
+    {
+       shpnt->max_id = 16;
+    }
+    shpnt->this_id = host_id;
+    shpnt->unique_id = base_io;
+    shpnt->io_port = base_io;
+    shpnt->n_io_port = 0x40;  /* Number of bytes of I/O space used */
+    shpnt->irq = irq;
+    restore_flags(flags);
+    request_region(base_io, 0x40,"atp870u");  /* Register the IO ports that we use */
+    count++;
+    index++;
+    continue;
+unregister:
+    scsi_unregister(shpnt);
+    restore_flags(flags);
+    index++;
+    continue;
+    }
+
+    return count;
+}
+
+/* The abort command does not leave the device in a clean state where
+   it is available to be used again.  Until this gets worked out, we will
+   leave it commented out.  */
+
+int atp870u_abort(Scsi_Cmnd * SCpnt)
+{
+    unsigned char h,j;
+    unsigned int  tmport;
+/*    printk(" atp870u_abort: \n");   */
+    for ( h=0; h <= admaxu; h++ )
+    {
+       if ( SCpnt->host == atp_host[h] )
+       {
+          goto find_adp;
+       }
+    }
+    panic("Abort host not found !");
+find_adp:
+    printk(" workingu=%x last_cmd=%x ",workingu[h],last_cmd[h]);
+    printk(" quhdu=%x quendu=%x ",quhdu[h],quendu[h]);
+    tmport=ioportu[h];
+    for ( j=0; j < 0x17; j++)
+    {
+       printk(" r%2x=%2x",j,inb(tmport++));
+    }
+    tmport += 0x05;
+    printk(" r1c=%2x",inb(tmport));
+    tmport += 0x03;
+    printk(" r1f=%2x in_snd=%2x ",inb(tmport),in_snd[h]);
+    tmport++;
+    printk(" r20=%2x",inb(tmport));
+    tmport += 0x02;
+    printk(" r22=%2x \n",inb(tmport));
+    return (SCSI_ABORT_SNOOZE);
+}
+
+int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{
+    unsigned char h;
+    /*
+     * See if a bus reset was suggested.
+     */
+/*    printk("atp870u_reset: \n");    */
+    for( h=0; h <= admaxu; h++ )
+    {
+       if ( SCpnt->host == atp_host[h] )
+       {
+         goto find_host;
+       }
+    }
+    panic("Reset bus host not found !");
+find_host:
+/*    SCpnt->result = 0x00080000;
+    SCpnt->scsi_done(SCpnt);
+    workingu[h]=0;
+    quhdu[h]=0;
+    quendu[h]=0;
+    return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);  */
+    return (SCSI_RESET_SNOOZE);
+}
+
+const char *
+atp870u_info(struct Scsi_Host *notused)
+{
+  static char buffer[128];
+
+  strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V1.0 ");
+
+  return buffer;
+}
+
+int
+atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
+{
+  return (-ENOSYS);  /* Currently this is a no-op */
+}
+
+#define BLS buffer + len + size
+int
+atp870u_proc_info(char *buffer, char **start, off_t offset, int length,
+    int hostno, int inout)
+{
+  struct Scsi_Host *HBAptr;
+  static u8 buff[512];
+  int  i;
+  int  size = 0;
+  int  len = 0;
+  off_t begin = 0;
+  off_t pos = 0;
+
+  HBAptr = NULL;
+  for (i = 0; i < 2; i++)
+  {
+    if ((HBAptr = atp_host[i]) != NULL)
+    {
+      if (HBAptr->host_no == hostno)
+      {
+       break;
+      }
+      HBAptr = NULL;
+    }
+  }
+
+  if (HBAptr == NULL)
+  {
+    size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno);
+    len += size; pos = begin + len; size = 0;
+    goto stop_output;
+  }
+
+  if (inout == TRUE) /* Has data been written to the file? */
+  {
+    return (atp870u_set_info(buffer, length, HBAptr));
+  }
+
+  if (offset == 0)
+  {
+    memset(buff, 0, sizeof(buff));
+  }
+
+  size += sprintf(BLS, "ACARD AEC-671X Driver Version: 1.0\n");
+  len += size; pos = begin + len; size = 0;
+
+  size += sprintf(BLS, "\n");
+  size += sprintf(BLS, "Adapter Configuration:\n");
+  size += sprintf(BLS, "               Base IO: %#.4lx\n", HBAptr->io_port);
+  size += sprintf(BLS, "                   IRQ: %d\n", HBAptr->irq);
+  len += size; pos = begin + len; size = 0;
+
+stop_output:
+  *start = buffer + (offset - begin);  /* Start of wanted data */
+  len -= (offset - begin);     /* Start slop */
+  if (len > length)
+  {
+    len = length;              /* Ending slop */
+  }
+
+  return (len);
+}
+
+#include "sd.h"
+
+int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int * ip)
+{
+  int heads, sectors, cylinders;
+
+  heads = 64;
+  sectors = 32;
+  cylinders = disk->capacity / (heads * sectors);
+
+  if ( cylinders > 1024 )
+  {
+    heads = 255;
+    sectors = 63;
+    cylinders = disk->capacity / (heads * sectors);
+  }
+
+  ip[0] = heads;
+  ip[1] = sectors;
+  ip[2] = cylinders;
+
+  return 0;
+}
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = ATP870U;
+
+#include "scsi_module.c"
+#endif
+
diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h
new file mode 100644 (file)
index 0000000..64cb56b
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _ATP870U_H
+
+/* $Id: atp870u.h,v 1.0 1997/05/07 15:09:00 root Exp root $
+ *
+ * Header file for the ACARD 870U/W driver for Linux
+ *
+ * $Log: atp870u.h,v $
+ * Revision 1.0  1997/05/07  15:09:00  root
+ * Initial revision
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+
+/* I/O Port */
+
+#define MAX_CDB 12
+#define MAX_SENSE 14
+
+int atp870u_detect(Scsi_Host_Template *);
+int atp870u_command(Scsi_Cmnd *);
+int atp870u_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int atp870u_abort(Scsi_Cmnd *);
+int atp870u_reset(Scsi_Cmnd *, unsigned int);
+int atp870u_biosparam(Disk *, kdev_t, int*);
+void send_s870(unsigned char);
+
+#define qcnt            32
+#define ATP870U_SCATTER 127
+#define ATP870U_CMDLUN 1
+
+#ifndef NULL
+        #define NULL 0
+#endif
+
+extern struct proc_dir_entry proc_scsi_atp870u;
+
+extern const char *atp870u_info(struct Scsi_Host *);
+
+extern int atp870u_proc_info(char *, char **, off_t, int, int, int);
+
+#define ATP870U {                                              \
+       next:                           NULL,                   \
+       module:                         NULL,                   \
+       proc_dir:                       &proc_scsi_atp870u,     \
+       proc_info:                      atp870u_proc_info,      \
+       name:                           NULL,                   \
+       detect:                         atp870u_detect,         \
+       release:                        NULL,                   \
+       info:                           atp870u_info,           \
+       command:                        atp870u_command,        \
+        queuecommand:                  atp870u_queuecommand,   \
+        eh_strategy_handler:           NULL,                   \
+        eh_abort_handler:              NULL,                   \
+        eh_device_reset_handler:       NULL,                   \
+        eh_bus_reset_handler:          NULL,                   \
+        eh_host_reset_handler:         NULL,                   \
+       abort:                          atp870u_abort,          \
+       reset:                          atp870u_reset,          \
+       slave_attach:                   NULL,                   \
+       bios_param:                     atp870u_biosparam,      \
+       can_queue:                      qcnt,                   \
+       this_id:                        1,                      \
+       sg_tablesize:                   ATP870U_SCATTER,        \
+       cmd_per_lun:                    ATP870U_CMDLUN,         \
+       present:                        0,                      \
+       unchecked_isa_dma:              0,                      \
+       use_clustering:                 ENABLE_CLUSTERING,      \
+       use_new_eh_code:                0                       \
+}
+#endif
index f17f0bdd52488fdb6ad72684529410c606292809..aaa23937aae1cab78f4ed9d5075871f56fc8a73a 100644 (file)
@@ -472,11 +472,9 @@ int fd_mcs_detect( Scsi_Host_Template *tpnt )
        /* *************************************************** */           
 #endif
 
-#if 0
        /* IBM/ANSI scsi scan ordering */
        /* Stick this back in when the scsi.c changes are there */
-       shpnt->reverse_scan = 1;
-#endif
+       shpnt->reverse_ordering = 1;
        
 
        /* saving info */
index 2a32b19e65d5f431cebfe06f7fd74d70728ffa59..71a8414cda31e6fdb7b6c7d6489b6a8c4f819265 100644 (file)
 #include "atari_scsi.h"
 #endif
 
+#ifdef CONFIG_MAC_SCSI_OLD
+#include "mac_scsi.h"
+#endif
+
+#ifdef CONFIG_MAC_SCSI
+#include "mac_scsinew.h"
+#endif
+
+#ifdef CONFIG_SCSI_MAC_ESP
+#include "mac_esp.h"
+#endif
+
 #ifdef CONFIG_SCSI_ADVANSYS
 #include "advansys.h"
 #endif
 #include "qlogicisp.h"
 #endif
 
+#ifdef CONFIG_SCSI_QLOGIC_FC
+#include "qlogicfc.h"
+#endif
+
 #ifdef CONFIG_SCSI_SEAGATE
 #include "seagate.h"
 #endif
 #include "wd7000.h"
 #endif
 
+#ifdef CONFIG_SCSI_MCA_53C9X
+#include "mca_53c9x.h"
+#endif
+
 #ifdef CONFIG_SCSI_IBMMCA
 #include "ibmmca.h"
 #endif
 #include "AM53C974.h"
 #endif
 
+#ifdef CONFIG_SCSI_MEGARAID
+#include "megaraid.h"
+#endif
+
+#ifdef CONFIG_SCSI_ACARD
+#include "atp870u.h"
+#endif
+
 #ifdef CONFIG_SCSI_SUNESP
 #include "esp.h"
 #endif
 #include "pluto.h"
 #endif
 
+#ifdef CONFIG_SCSI_INITIO
+#include "ini9100u.h"
+#endif
+
 #ifdef CONFIG_SCSI_DEBUG
 #include "scsi_debug.h"
 #endif
@@ -366,6 +398,18 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #endif
 #endif
 
+#ifdef CONFIG_MAC
+#ifdef CONFIG_MAC_SCSI_OLD
+       MAC_SCSI,
+#endif
+#ifdef CONFIG_SCSI_MAC_ESP
+        SCSI_MAC_ESP,
+#endif
+#ifdef CONFIG_MAC_SCSI
+       MAC_NCR5380,
+#endif
+#endif
+
 #ifdef CONFIG_MVME16x_SCSI
        MVME16x_SCSI,
 #endif
@@ -426,6 +470,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_QLOGIC_ISP
     QLOGICISP,
 #endif
+#ifdef CONFIG_SCSI_QLOGIC_FC
+    QLOGICFC,
+#endif
 #ifdef CONFIG_SCSI_PAS16
     MV_PAS16,
 #endif
@@ -453,6 +500,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_7000FASST
     WD7000,
 #endif
+#ifdef CONFIG_SCSI_MCA_53C9X
+    MCA_53C9X,
+#endif
 #ifdef CONFIG_SCSI_IBMMCA
     IBMMCA,
 #endif
@@ -465,12 +515,21 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_AM53C974
     AM53C974,
 #endif
+#ifdef CONFIG_SCSI_MEGARAID
+    MEGARAID,
+#endif
+#ifdef CONFIG_SCSI_ACARD
+    ATP870U,
+#endif
 #ifdef CONFIG_SCSI_SUNESP
     SCSI_SPARC_ESP,
 #endif
 #ifdef CONFIG_SCSI_GDTH
     GDTH,
 #endif
+#ifdef CONFIG_SCSI_INITIO
+    INI9100U,
+#endif
 #ifdef CONFIG_SCSI_QLOGICPTI
     QLOGICPTI,
 #endif
index b70cac30f5cd20f9232d6c4f536bda5d477bdf5e..393d03f4e38399b2afe9d6724a1123ca973f5d15 100644 (file)
@@ -382,7 +382,14 @@ struct Scsi_Host
      * Host has rejected a command because it was busy.
      */
     unsigned host_blocked:1;
+    
+    /*
+     * Host uses correct SCSI ordering not PC ordering. The bit is
+     * set for the minority of drivers whose authors actually read the spec ;)
+     */
 
+    unsigned reverse_ordering:1;
+    
     void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
 
     /*
diff --git a/drivers/scsi/i91uscsi.c b/drivers/scsi/i91uscsi.c
new file mode 100644 (file)
index 0000000..56c268b
--- /dev/null
@@ -0,0 +1,2776 @@
+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * Copyright (c) 1998 Bas Vermeulen <bvermeul@blackstar.xs4all.nl>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ ************************************************************************
+    Module: i91uscsi.c
+    Description: PCI I/F for INI-910 SCSI Bus Master Controller
+    Revision History:
+       11/09/94 Tim Chen, Initiali Version 0.90A
+       01/17/95 TC, release ver 1.01
+       02/09/95 TC  modify ReadPCIConfig, try both mechanisms;
+       02/15/95 TC  add support for INI-9100W
+       06/04/96 HC, Change to fit LINUX from jaspci.c
+       11/18/96 HC, Port for tulip
+       07/08/98 hc, Support 0002134A
+        07/23/98 wh, Change the abort_srb routine.
+       09/16/98 hl, Support ALPHA, Rewrite the returnNumberAdapters    <01>
+       12/09/98 bv, Removed unused code, changed tul_se2_wait to
+                    use udelay(30) and tul_do_pause to enable 
+                    interrupts for >= 2.1.95
+       12/13/98 bv, Use spinlocks instead of cli() for serialized
+                    access to HCS_Semaph, HCS_FirstAvail and HCS_LastAvail
+                    members of the HCS structure.
+**********************************************************************/
+
+#define DEBUG_INTERRUPT 0
+#define DEBUG_QUEUE     0
+#define DEBUG_STATE     0
+#define INT_DISC       0
+
+
+#ifndef CVT_LINUX_VERSION
+#define        CVT_LINUX_VERSION(V,P,S)        (V * 65536 + P * 256 + S)
+#endif
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/blk.h>
+#include <asm/io.h>
+
+#include "i91uscsi.h"
+
+/*--- external functions --*/
+static void tul_se2_wait(void);
+
+/*--- forward refrence ---*/
+static SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun);
+static SCB *tul_find_done_scb(HCS * pCurHcb);
+
+static int tulip_main(HCS * pCurHcb);
+
+static int tul_next_state(HCS * pCurHcb);
+static int tul_state_1(HCS * pCurHcb);
+static int tul_state_2(HCS * pCurHcb);
+static int tul_state_3(HCS * pCurHcb);
+static int tul_state_4(HCS * pCurHcb);
+static int tul_state_5(HCS * pCurHcb);
+static int tul_state_6(HCS * pCurHcb);
+static int tul_state_7(HCS * pCurHcb);
+static int tul_xfer_data_in(HCS * pCurHcb);
+static int tul_xfer_data_out(HCS * pCurHcb);
+static int tul_xpad_in(HCS * pCurHcb);
+static int tul_xpad_out(HCS * pCurHcb);
+static int tul_status_msg(HCS * pCurHcb);
+
+static int tul_msgin(HCS * pCurHcb);
+static int tul_msgin_sync(HCS * pCurHcb);
+static int tul_msgin_accept(HCS * pCurHcb);
+static int tul_msgout_reject(HCS * pCurHcb);
+static int tul_msgin_extend(HCS * pCurHcb);
+
+static int tul_msgout_ide(HCS * pCurHcb);
+static int tul_msgout_abort_targ(HCS * pCurHcb);
+static int tul_msgout_abort_tag(HCS * pCurHcb);
+
+static int tul_bus_device_reset(HCS * pCurHcb);
+static void tul_select_atn(HCS * pCurHcb, SCB * pCurScb);
+static void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb);
+static void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb);
+static int int_tul_busfree(HCS * pCurHcb);
+int int_tul_scsi_rst(HCS * pCurHcb);
+static int int_tul_bad_seq(HCS * pCurHcb);
+static int int_tul_resel(HCS * pCurHcb);
+static int tul_sync_done(HCS * pCurHcb);
+static int wdtr_done(HCS * pCurHcb);
+static int wait_tulip(HCS * pCurHcb);
+static int tul_wait_done_disc(HCS * pCurHcb);
+static int tul_wait_disc(HCS * pCurHcb);
+static void tulip_scsi(HCS * pCurHcb);
+static int tul_post_scsi_rst(HCS * pCurHcb);
+
+static void tul_se2_ew_en(WORD CurBase);
+static void tul_se2_ew_ds(WORD CurBase);
+static int tul_se2_rd_all(WORD CurBase);
+static void tul_se2_update_all(WORD CurBase);  /* setup default pattern */
+static void tul_read_eeprom(WORD CurBase);
+
+                               /* ---- EXTERNAL VARIABLES ---- */
+HCS tul_hcs[MAX_SUPPORTED_ADAPTERS];
+                               /* ---- INTERNAL VARIABLES ---- */
+static INI_ADPT_STRUCT i91u_adpt[MAX_SUPPORTED_ADAPTERS];
+
+/*NVRAM nvram, *nvramp = &nvram; */
+static NVRAM i91unvram;
+static NVRAM *i91unvramp;
+
+
+
+static UCHAR i91udftNvRam[64] =
+{
+/*----------- header -----------*/
+       0x25, 0xc9,             /* Signature    */
+       0x40,                   /* Size         */
+       0x01,                   /* Revision     */
+       /* -- Host Adapter Structure -- */
+       0x95,                   /* ModelByte0   */
+       0x00,                   /* ModelByte1   */
+       0x00,                   /* ModelInfo    */
+       0x01,                   /* NumOfCh      */
+       NBC1_DEFAULT,           /* BIOSConfig1  */
+       0,                      /* BIOSConfig2  */
+       0,                      /* HAConfig1    */
+       0,                      /* HAConfig2    */
+       /* SCSI channel 0 and target Structure  */
+       7,                      /* SCSIid       */
+       NCC1_DEFAULT,           /* SCSIconfig1  */
+       0,                      /* SCSIconfig2  */
+       0x10,                   /* NumSCSItarget */
+
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+
+       /* SCSI channel 1 and target Structure  */
+       7,                      /* SCSIid       */
+       NCC1_DEFAULT,           /* SCSIconfig1  */
+       0,                      /* SCSIconfig2  */
+       0x10,                   /* NumSCSItarget */
+
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0};                  /*      - CheckSum -            */
+
+
+static UCHAR tul_rate_tbl[8] = /* fast 20      */
+{
+                               /* nanosecond devide by 4 */
+       12,                     /* 50ns,  20M   */
+       18,                     /* 75ns,  13.3M */
+       25,                     /* 100ns, 10M   */
+       31,                     /* 125ns, 8M    */
+       37,                     /* 150ns, 6.6M  */
+       43,                     /* 175ns, 5.7M  */
+       50,                     /* 200ns, 5M    */
+       62                      /* 250ns, 4M    */
+};
+
+extern int tul_num_ch;
+
+
+static void tul_do_pause(unsigned amount)
+{                              /* Pause for amount*10 milliseconds */
+       unsigned long the_time = jiffies + amount;      /* 0.01 seconds per jiffy */
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       /*
+        * We need to release the io_request_lock 
+        * to make sure that the jiffies are updated
+        */
+       spin_unlock_irq(&io_request_lock);
+
+       while (time_before_eq(jiffies, the_time));
+
+       /*
+        * Acquire the io_request_lock again
+        */
+       spin_lock_irq(&io_request_lock);
+#else
+       while (jiffies < the_time);
+#endif
+}
+
+/*-- forward reference --*/
+
+/*******************************************************************
+       Use memeory refresh time        ~ 15us * 2
+********************************************************************/
+void tul_se2_wait()
+{
+#if 1
+       udelay(30);
+#else
+       UCHAR readByte;
+
+       readByte = TUL_RD(0, 0x61);
+       if ((readByte & 0x10) == 0x10) {
+               for (;;) {
+                       readByte = TUL_RD(0, 0x61);
+                       if ((readByte & 0x10) == 0x10)
+                               break;
+               }
+               for (;;) {
+                       readByte = TUL_RD(0, 0x61);
+                       if ((readByte & 0x10) != 0x10)
+                               break;
+               }
+       } else {
+               for (;;) {
+                       readByte = TUL_RD(0, 0x61);
+                       if ((readByte & 0x10) == 0x10)
+                               break;
+               }
+               for (;;) {
+                       readByte = TUL_RD(0, 0x61);
+                       if ((readByte & 0x10) != 0x10)
+                               break;
+               }
+       }
+#endif
+}
+
+
+/******************************************************************
+ Input: instruction for  Serial E2PROM
+
+ EX: se2_rd(0 call se2_instr() to send address and read command
+
+        StartBit  OP_Code   Address                Data
+        --------- --------  ------------------     -------
+        1         1 , 0     A5,A4,A3,A2,A1,A0      D15-D0
+
+                +-----------------------------------------------------
+                |
+ CS -----+
+                       +--+  +--+  +--+  +--+  +--+
+                       ^  |  ^  |  ^  |  ^  |  ^  |
+                       |  |  |  |  |  |  |  |  |  |
+ CLK -------+  +--+  +--+  +--+  +--+  +--
+ (leading edge trigger)
+
+                +--1-----1--+
+                | SB    OP  |  OP    A5    A4
+ DI  ----+           +--0------------------
+ (address and cmd sent to nvram)
+
+        -------------------------------------------+
+                                                                                               |
+ DO                                             +---
+ (data sent from nvram)
+
+
+******************************************************************/
+void tul_se2_instr(WORD CurBase, UCHAR instr)
+{
+       int i;
+       UCHAR b;
+
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO);     /* cs+start bit */
+       tul_se2_wait();
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK | SE2DO);    /* +CLK */
+       tul_se2_wait();
+
+       for (i = 0; i < 8; i++) {
+               if (instr & 0x80)
+                       b = SE2CS | SE2DO;      /* -CLK+dataBit */
+               else
+                       b = SE2CS;      /* -CLK */
+               TUL_WR(CurBase + TUL_NVRAM, b);
+               tul_se2_wait();
+               TUL_WR(CurBase + TUL_NVRAM, b | SE2CLK);        /* +CLK */
+               tul_se2_wait();
+               instr <<= 1;
+       }
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK */
+       tul_se2_wait();
+       return;
+}
+
+
+/******************************************************************
+ Function name  : tul_se2_ew_en
+ Description    : Enable erase/write state of serial EEPROM
+******************************************************************/
+void tul_se2_ew_en(WORD CurBase)
+{
+       tul_se2_instr(CurBase, 0x30);   /* EWEN */
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* -CS  */
+       tul_se2_wait();
+       return;
+}
+
+
+/************************************************************************
+ Disable erase/write state of serial EEPROM
+*************************************************************************/
+void tul_se2_ew_ds(WORD CurBase)
+{
+       tul_se2_instr(CurBase, 0);      /* EWDS */
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* -CS  */
+       tul_se2_wait();
+       return;
+}
+
+
+/******************************************************************
+       Input  :address of Serial E2PROM
+       Output :value stored in  Serial E2PROM
+*******************************************************************/
+USHORT tul_se2_rd(WORD CurBase, ULONG adr)
+{
+       UCHAR instr, readByte;
+       USHORT readWord;
+       int i;
+
+       instr = (UCHAR) (adr | 0x80);
+       tul_se2_instr(CurBase, instr);  /* READ INSTR */
+       readWord = 0;
+
+       for (i = 15; i >= 0; i--) {
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);    /* +CLK */
+               tul_se2_wait();
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK */
+
+               /* sample data after the following edge of clock  */
+               readByte = TUL_RD(CurBase, TUL_NVRAM);
+               readByte &= SE2DI;
+               readWord += (readByte << i);
+               tul_se2_wait(); /* 6/20/95 */
+       }
+
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* no chip select */
+       tul_se2_wait();
+       return readWord;
+}
+
+
+/******************************************************************
+ Input: new value in  Serial E2PROM, address of Serial E2PROM
+*******************************************************************/
+void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
+{
+       UCHAR readByte;
+       UCHAR instr;
+       int i;
+
+       instr = (UCHAR) (adr | 0x40);
+       tul_se2_instr(CurBase, instr);  /* WRITE INSTR */
+       for (i = 15; i >= 0; i--) {
+               if (writeWord & 0x8000)
+                       TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO);     /* -CLK+dataBit 1 */
+               else
+                       TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK+dataBit 0 */
+               tul_se2_wait();
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);    /* +CLK */
+               tul_se2_wait();
+               writeWord <<= 1;
+       }
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK */
+       tul_se2_wait();
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* -CS  */
+       tul_se2_wait();
+
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* +CS  */
+       tul_se2_wait();
+
+       for (;;) {
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);    /* +CLK */
+               tul_se2_wait();
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK */
+               tul_se2_wait();
+               if ((readByte = TUL_RD(CurBase, TUL_NVRAM)) & SE2DI)
+                       break;  /* write complete */
+       }
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* -CS */
+       return;
+}
+
+
+/***********************************************************************
+ Read SCSI H/A configuration parameters from serial EEPROM
+************************************************************************/
+int tul_se2_rd_all(WORD CurBase)
+{
+       int i;
+       ULONG chksum = 0;
+       USHORT *np;
+
+       i91unvramp = &i91unvram;
+       np = (USHORT *) i91unvramp;
+       for (i = 0; i < 32; i++) {
+               *np++ = tul_se2_rd(CurBase, i);
+       }
+
+/*--------------------Is signature "ini" ok ? ----------------*/
+       if (i91unvramp->NVM_Signature != INI_SIGNATURE)
+               return -1;
+/*---------------------- Is ckecksum ok ? ----------------------*/
+       np = (USHORT *) i91unvramp;
+       for (i = 0; i < 31; i++)
+               chksum += *np++;
+       if (i91unvramp->NVM_CheckSum != (USHORT) chksum)
+               return -1;
+       return 1;
+}
+
+
+/***********************************************************************
+ Update SCSI H/A configuration parameters from serial EEPROM
+************************************************************************/
+void tul_se2_update_all(WORD CurBase)
+{                              /* setup default pattern */
+       int i;
+       ULONG chksum = 0;
+       USHORT *np, *np1;
+
+       i91unvramp = &i91unvram;
+       /* Calculate checksum first */
+       np = (USHORT *) i91udftNvRam;
+       for (i = 0; i < 31; i++)
+               chksum += *np++;
+       *np = (USHORT) chksum;
+       tul_se2_ew_en(CurBase); /* Enable write  */
+
+       np = (USHORT *) i91udftNvRam;
+       np1 = (USHORT *) i91unvramp;
+       for (i = 0; i < 32; i++, np++, np1++) {
+               if (*np != *np1) {
+                       tul_se2_wr(CurBase, i, *np);
+               }
+       }
+
+       tul_se2_ew_ds(CurBase); /* Disable write   */
+       return;
+}
+
+/*************************************************************************
+ Function name  : read_eeprom
+**************************************************************************/
+void tul_read_eeprom(WORD CurBase)
+{
+       UCHAR gctrl;
+
+       i91unvramp = &i91unvram;
+/*------Enable EEProm programming ---*/
+       gctrl = TUL_RD(CurBase, TUL_GCTRL);
+       TUL_WR(CurBase + TUL_GCTRL, gctrl | TUL_GCTRL_EEPROM_BIT);
+       if (tul_se2_rd_all(CurBase) != 1) {
+               tul_se2_update_all(CurBase);    /* setup default pattern */
+               tul_se2_rd_all(CurBase);        /* load again  */
+       }
+/*------ Disable EEProm programming ---*/
+       gctrl = TUL_RD(CurBase, TUL_GCTRL);
+       TUL_WR(CurBase + TUL_GCTRL, gctrl & ~TUL_GCTRL_EEPROM_BIT);
+}                              /* read_eeprom */
+
+int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
+                              BYTE bBus, BYTE bDevice)
+{
+       int i, j;
+
+       for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {
+               if (i91u_adpt[i].ADPT_BIOS < wBIOS)
+                       continue;
+               if (i91u_adpt[i].ADPT_BIOS == wBIOS) {
+                       if (i91u_adpt[i].ADPT_BASE == wBASE)
+                               if (i91u_adpt[i].ADPT_Bus != 0xFF)
+                                       return (FAILURE);
+                               else if (i91u_adpt[i].ADPT_BASE < wBASE)
+                                       continue;
+               }
+               for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
+                       i91u_adpt[j].ADPT_BASE = i91u_adpt[j - 1].ADPT_BASE;
+                       i91u_adpt[j].ADPT_INTR = i91u_adpt[j - 1].ADPT_INTR;
+                       i91u_adpt[j].ADPT_BIOS = i91u_adpt[j - 1].ADPT_BIOS;
+                       i91u_adpt[j].ADPT_Bus = i91u_adpt[j - 1].ADPT_Bus;
+                       i91u_adpt[j].ADPT_Device = i91u_adpt[j - 1].ADPT_Device;
+               }
+               i91u_adpt[i].ADPT_BASE = wBASE;
+               i91u_adpt[i].ADPT_INTR = bInterrupt;
+               i91u_adpt[i].ADPT_BIOS = wBIOS;
+               i91u_adpt[i].ADPT_Bus = bBus;
+               i91u_adpt[i].ADPT_Device = bDevice;
+               return (SUCCESSFUL);
+       }
+       return (FAILURE);
+}
+
+void init_i91uAdapter_table(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {  /* Initialize adapter structure */
+               i91u_adpt[i].ADPT_BIOS = 0xffff;
+               i91u_adpt[i].ADPT_BASE = 0xffff;
+               i91u_adpt[i].ADPT_INTR = 0xff;
+               i91u_adpt[i].ADPT_Bus = 0xff;
+               i91u_adpt[i].ADPT_Device = 0xff;
+       }
+       return;
+}
+
+void tul_stop_bm(HCS * pCurHcb)
+{
+
+       if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {   /* if DMA xfer is pending, abort DMA xfer */
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+               /* wait Abort DMA xfer done */
+               while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+}
+
+/***************************************************************************/
+void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
+{
+       pCurHcb->HCS_Base = i91u_adpt[ch_idx].ADPT_BASE;        /* Supply base address  */
+       pCurHcb->HCS_BIOS = i91u_adpt[ch_idx].ADPT_BIOS;        /* Supply BIOS address  */
+       pCurHcb->HCS_Intr = i91u_adpt[ch_idx].ADPT_INTR;        /* Supply interrupt line */
+       return;
+}
+
+/***************************************************************************/
+int tul_reset_scsi(HCS * pCurHcb, int seconds)
+{
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_BUS);
+
+       while (!((pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt)) & TSS_SCSIRST_INT));
+       /* reset tulip chip */
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, 0);
+
+       /* Stall for a while, wait for target's firmware ready,make it 2 sec ! */
+       /* SONY 5200 tape drive won't work if only stall for 1 sec */
+       tul_do_pause(seconds * 100);
+
+       TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+
+       return (SCSI_RESET_SUCCESS);
+}
+
+/***************************************************************************/
+int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int seconds)
+{
+       int i;
+       WORD *pwFlags;
+       BYTE *pbHeads;
+       SCB *pTmpScb, *pPrevScb = NULL;
+
+       pCurHcb->HCS_NumScbs = tul_num_scb;
+       pCurHcb->HCS_Semaph = 1;
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       pCurHcb->HCS_SemaphLock = SPIN_LOCK_UNLOCKED;
+#endif
+       pCurHcb->HCS_JSStatus0 = 0;
+       pCurHcb->HCS_Scb = scbp;
+       pCurHcb->HCS_NxtPend = scbp;
+       pCurHcb->HCS_NxtAvail = scbp;
+       for (i = 0, pTmpScb = scbp; i < tul_num_scb; i++, pTmpScb++) {
+               pTmpScb->SCB_TagId = i;
+               if (i != 0)
+                       pPrevScb->SCB_NxtScb = pTmpScb;
+               pPrevScb = pTmpScb;
+       }
+       pPrevScb->SCB_NxtScb = NULL;
+       pCurHcb->HCS_ScbEnd = pTmpScb;
+       pCurHcb->HCS_FirstAvail = scbp;
+       pCurHcb->HCS_LastAvail = pPrevScb;
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       pCurHcb->HCS_AvailLock = SPIN_LOCK_UNLOCKED;
+#endif
+       pCurHcb->HCS_FirstPend = NULL;
+       pCurHcb->HCS_LastPend = NULL;
+       pCurHcb->HCS_FirstBusy = NULL;
+       pCurHcb->HCS_LastBusy = NULL;
+       pCurHcb->HCS_FirstDone = NULL;
+       pCurHcb->HCS_LastDone = NULL;
+       pCurHcb->HCS_ActScb = NULL;
+       pCurHcb->HCS_ActTcs = NULL;
+
+       tul_read_eeprom(pCurHcb->HCS_Base);
+/*---------- get H/A configuration -------------*/
+       if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8)
+               pCurHcb->HCS_MaxTar = 8;
+       else
+               pCurHcb->HCS_MaxTar = 16;
+
+       pCurHcb->HCS_Config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1;
+
+       pCurHcb->HCS_SCSI_ID = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID;
+       pCurHcb->HCS_IdMask = ~(1 << pCurHcb->HCS_SCSI_ID);
+
+#if CHK_PARITY
+       /* Enable parity error response */
+       TUL_WR(pCurHcb->HCS_Base + TUL_PCMD, TUL_RD(pCurHcb->HCS_Base, TUL_PCMD) | 0x40);
+#endif
+
+       /* Mask all the interrupt       */
+       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+
+       tul_stop_bm(pCurHcb);
+       /* --- Initialize the tulip --- */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_CHIP);
+
+       /* program HBA's SCSI ID        */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId, pCurHcb->HCS_SCSI_ID << 4);
+
+       /* Enable Initiator Mode ,phase latch,alternate sync period mode,
+          disable SCSI reset */
+       if (pCurHcb->HCS_Config & HCC_EN_PAR)
+               pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
+       else
+               pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_SConf1);
+
+       /* Enable HW reselect           */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, 0);
+
+       /* selection time out = 250 ms */
+       TUL_WR(pCurHcb->HCS_Base + TUL_STimeOut, 153);
+
+/*--------- Enable SCSI terminator -----*/
+       TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, (pCurHcb->HCS_Config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)));
+       TUL_WR(pCurHcb->HCS_Base + TUL_GCTRL1,
+              ((pCurHcb->HCS_Config & HCC_AUTO_TERM) >> 4) | (TUL_RD(pCurHcb->HCS_Base, TUL_GCTRL1) & 0xFE));
+
+       for (i = 0,
+            pwFlags = (WORD *) & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config),
+            pbHeads = pbBiosAdr + 0x180;
+            i < pCurHcb->HCS_MaxTar;
+            i++, pwFlags++) {
+               pCurHcb->HCS_Tcs[i].TCS_Flags = *pwFlags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+               if (pCurHcb->HCS_Tcs[i].TCS_Flags & TCF_EN_255)
+                       pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+               else
+                       pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
+               pCurHcb->HCS_Tcs[i].TCS_JS_Period = 0;
+               pCurHcb->HCS_Tcs[i].TCS_SConfig0 = pCurHcb->HCS_SConf1;
+               pCurHcb->HCS_Tcs[i].TCS_DrvHead = *pbHeads++;
+               if (pCurHcb->HCS_Tcs[i].TCS_DrvHead == 255)
+                       pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+               else
+                       pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
+               pCurHcb->HCS_Tcs[i].TCS_DrvSector = *pbHeads++;
+               pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;
+               pCurHcb->HCS_ActTags[i] = 0;
+               pCurHcb->HCS_MaxTags[i] = 0xFF;
+       }                       /* for                          */
+       printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d\n",
+              pCurHcb->HCS_Base, pCurHcb->HCS_Intr,
+              pCurHcb->HCS_BIOS, pCurHcb->HCS_SCSI_ID);
+/*------------------- reset SCSI Bus ---------------------------*/
+       if (pCurHcb->HCS_Config & HCC_SCSI_RESET) {
+               printk("i91u: Reset SCSI Bus ... \n");
+               tul_reset_scsi(pCurHcb, seconds);
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCFG1, 0x17);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SIntEnable, 0xE9);
+       return (0);
+}
+
+/***************************************************************************/
+SCB *tul_alloc_scb(HCS * hcsp)
+{
+       SCB *pTmpScb;
+       ULONG flags;
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
+#else
+       save_flags(flags);
+       cli();
+#endif
+       if ((pTmpScb = hcsp->HCS_FirstAvail) != NULL) {
+#if DEBUG_QUEUE
+               printk("find scb at %08lx\n", (ULONG) pTmpScb);
+#endif
+               if ((hcsp->HCS_FirstAvail = pTmpScb->SCB_NxtScb) == NULL)
+                       hcsp->HCS_LastAvail = NULL;
+               pTmpScb->SCB_NxtScb = NULL;
+               pTmpScb->SCB_Status = SCB_RENT;
+       }
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
+#else
+       restore_flags(flags);
+#endif
+       return (pTmpScb);
+}
+
+/***************************************************************************/
+void tul_release_scb(HCS * hcsp, SCB * scbp)
+{
+       ULONG flags;
+
+#if DEBUG_QUEUE
+       printk("Release SCB %lx; ", (ULONG) scbp);
+#endif
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
+#else
+       save_flags(flags);
+       cli();
+#endif
+       scbp->SCB_Srb = 0;
+       scbp->SCB_Status = 0;
+       scbp->SCB_NxtScb = NULL;
+       if (hcsp->HCS_LastAvail != NULL) {
+               hcsp->HCS_LastAvail->SCB_NxtScb = scbp;
+               hcsp->HCS_LastAvail = scbp;
+       } else {
+               hcsp->HCS_FirstAvail = scbp;
+               hcsp->HCS_LastAvail = scbp;
+       }
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
+#else
+       restore_flags(flags);
+#endif
+}
+
+/***************************************************************************/
+void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+       printk("Append pend SCB %lx; ", (ULONG) scbp);
+#endif
+       scbp->SCB_Status = SCB_PEND;
+       scbp->SCB_NxtScb = NULL;
+       if (pCurHcb->HCS_LastPend != NULL) {
+               pCurHcb->HCS_LastPend->SCB_NxtScb = scbp;
+               pCurHcb->HCS_LastPend = scbp;
+       } else {
+               pCurHcb->HCS_FirstPend = scbp;
+               pCurHcb->HCS_LastPend = scbp;
+       }
+}
+
+/***************************************************************************/
+void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+       printk("Push pend SCB %lx; ", (ULONG) scbp);
+#endif
+       scbp->SCB_Status = SCB_PEND;
+       if ((scbp->SCB_NxtScb = pCurHcb->HCS_FirstPend) != NULL) {
+               pCurHcb->HCS_FirstPend = scbp;
+       } else {
+               pCurHcb->HCS_FirstPend = scbp;
+               pCurHcb->HCS_LastPend = scbp;
+       }
+}
+
+/***************************************************************************/
+SCB *tul_find_first_pend_scb(HCS * pCurHcb)
+{
+       SCB *pFirstPend;
+
+
+       pFirstPend = pCurHcb->HCS_FirstPend;
+       while (pFirstPend != NULL) {
+               if (pFirstPend->SCB_Opcode != ExecSCSI) {
+                       return (pFirstPend);
+               }
+               if (pFirstPend->SCB_TagMsg == 0) {
+                       if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] == 0) &&
+                           !(pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
+                               return (pFirstPend);
+                       }
+               } else {
+                       if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] >=
+                         pCurHcb->HCS_MaxTags[pFirstPend->SCB_Target]) |
+                           (pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
+                               pFirstPend = pFirstPend->SCB_NxtScb;
+                               continue;
+                       }
+                       return (pFirstPend);
+               }
+               pFirstPend = pFirstPend->SCB_NxtScb;
+       }
+
+
+       return (pFirstPend);
+}
+/***************************************************************************/
+SCB *tul_pop_pend_scb(HCS * pCurHcb)
+{
+       SCB *pTmpScb;
+
+       if ((pTmpScb = pCurHcb->HCS_FirstPend) != NULL) {
+               if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
+                       pCurHcb->HCS_LastPend = NULL;
+               pTmpScb->SCB_NxtScb = NULL;
+       }
+#if DEBUG_QUEUE
+       printk("Pop pend SCB %lx; ", (ULONG) pTmpScb);
+#endif
+       return (pTmpScb);
+}
+
+
+/***************************************************************************/
+void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
+{
+       SCB *pTmpScb, *pPrevScb;
+
+#if DEBUG_QUEUE
+       printk("unlink pend SCB %lx; ", (ULONG) pCurScb);
+#endif
+
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;
+       while (pTmpScb != NULL) {
+               if (pCurScb == pTmpScb) {       /* Unlink this SCB              */
+                       if (pTmpScb == pCurHcb->HCS_FirstPend) {
+                               if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
+                                       pCurHcb->HCS_LastPend = NULL;
+                       } else {
+                               pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                               if (pTmpScb == pCurHcb->HCS_LastPend)
+                                       pCurHcb->HCS_LastPend = pPrevScb;
+                       }
+                       pTmpScb->SCB_NxtScb = NULL;
+                       break;
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+       return;
+}
+/***************************************************************************/
+void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+       printk("append busy SCB %lx; ", (ULONG) scbp);
+#endif
+       if (scbp->SCB_TagMsg)
+               pCurHcb->HCS_ActTags[scbp->SCB_Target]++;
+       else
+               pCurHcb->HCS_Tcs[scbp->SCB_Target].TCS_Flags |= TCF_BUSY;
+       scbp->SCB_Status = SCB_BUSY;
+       scbp->SCB_NxtScb = NULL;
+       if (pCurHcb->HCS_LastBusy != NULL) {
+               pCurHcb->HCS_LastBusy->SCB_NxtScb = scbp;
+               pCurHcb->HCS_LastBusy = scbp;
+       } else {
+               pCurHcb->HCS_FirstBusy = scbp;
+               pCurHcb->HCS_LastBusy = scbp;
+       }
+}
+
+/***************************************************************************/
+SCB *tul_pop_busy_scb(HCS * pCurHcb)
+{
+       SCB *pTmpScb;
+
+
+       if ((pTmpScb = pCurHcb->HCS_FirstBusy) != NULL) {
+               if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+                       pCurHcb->HCS_LastBusy = NULL;
+               pTmpScb->SCB_NxtScb = NULL;
+               if (pTmpScb->SCB_TagMsg)
+                       pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+               else
+                       pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+       }
+#if DEBUG_QUEUE
+       printk("Pop busy SCB %lx; ", (ULONG) pTmpScb);
+#endif
+       return (pTmpScb);
+}
+
+/***************************************************************************/
+void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
+{
+       SCB *pTmpScb, *pPrevScb;
+
+#if DEBUG_QUEUE
+       printk("unlink busy SCB %lx; ", (ULONG) pCurScb);
+#endif
+
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
+       while (pTmpScb != NULL) {
+               if (pCurScb == pTmpScb) {       /* Unlink this SCB              */
+                       if (pTmpScb == pCurHcb->HCS_FirstBusy) {
+                               if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+                                       pCurHcb->HCS_LastBusy = NULL;
+                       } else {
+                               pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                               if (pTmpScb == pCurHcb->HCS_LastBusy)
+                                       pCurHcb->HCS_LastBusy = pPrevScb;
+                       }
+                       pTmpScb->SCB_NxtScb = NULL;
+                       if (pTmpScb->SCB_TagMsg)
+                               pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+                       else
+                               pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+                       break;
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+       return;
+}
+
+/***************************************************************************/
+SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun)
+{
+       SCB *pTmpScb, *pPrevScb;
+       WORD scbp_tarlun;
+
+
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
+       while (pTmpScb != NULL) {
+               scbp_tarlun = (pTmpScb->SCB_Lun << 8) | (pTmpScb->SCB_Target);
+               if (scbp_tarlun == tarlun) {    /* Unlink this SCB              */
+                       break;
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+#if DEBUG_QUEUE
+       printk("find busy SCB %lx; ", (ULONG) pTmpScb);
+#endif
+       return (pTmpScb);
+}
+
+/***************************************************************************/
+void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+       printk("append done SCB %lx; ", (ULONG) scbp);
+#endif
+
+       scbp->SCB_Status = SCB_DONE;
+       scbp->SCB_NxtScb = NULL;
+       if (pCurHcb->HCS_LastDone != NULL) {
+               pCurHcb->HCS_LastDone->SCB_NxtScb = scbp;
+               pCurHcb->HCS_LastDone = scbp;
+       } else {
+               pCurHcb->HCS_FirstDone = scbp;
+               pCurHcb->HCS_LastDone = scbp;
+       }
+}
+
+/***************************************************************************/
+SCB *tul_find_done_scb(HCS * pCurHcb)
+{
+       SCB *pTmpScb;
+
+
+       if ((pTmpScb = pCurHcb->HCS_FirstDone) != NULL) {
+               if ((pCurHcb->HCS_FirstDone = pTmpScb->SCB_NxtScb) == NULL)
+                       pCurHcb->HCS_LastDone = NULL;
+               pTmpScb->SCB_NxtScb = NULL;
+       }
+#if DEBUG_QUEUE
+       printk("find done SCB %lx; ", (ULONG) pTmpScb);
+#endif
+       return (pTmpScb);
+}
+
+/***************************************************************************/
+int tul_abort_srb(HCS * pCurHcb, ULONG srbp)
+{
+       ULONG flags;
+       SCB *pTmpScb, *pPrevScb;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       save_flags(flags);
+       cli();
+#endif
+
+       if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+               /* disable Jasmin SCSI Int        */
+               tulip_main(pCurHcb);
+
+               pCurHcb->HCS_Semaph = 1;
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+               restore_flags(flags);
+#endif
+
+               return SCSI_ABORT_SNOOZE;
+       }
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;    /* Check Pend queue */
+       while (pTmpScb != NULL) {
+               /* 07/27/98 */
+               if (pTmpScb->SCB_Srb == (unsigned char *) srbp) {
+                       if (pTmpScb == pCurHcb->HCS_ActScb) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+                               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+                               restore_flags(flags);
+#endif
+                               return SCSI_ABORT_BUSY;
+                       } else if (pTmpScb == pCurHcb->HCS_FirstPend) {
+                               if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
+                                       pCurHcb->HCS_LastPend = NULL;
+                       } else {
+                               pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                               if (pTmpScb == pCurHcb->HCS_LastPend)
+                                       pCurHcb->HCS_LastPend = pPrevScb;
+                       }
+                       pTmpScb->SCB_HaStat = HOST_ABORTED;
+                       pTmpScb->SCB_Flags |= SCF_DONE;
+                       if (pTmpScb->SCB_Flags & SCF_POST)
+                               (*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+                       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+                       restore_flags(flags);
+#endif
+                       return SCSI_ABORT_SUCCESS;
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;    /* Check Busy queue */
+       while (pTmpScb != NULL) {
+
+               if (pTmpScb->SCB_Srb == (unsigned char *) srbp) {
+
+                       if (pTmpScb == pCurHcb->HCS_ActScb) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+                               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+                               restore_flags(flags);
+#endif
+                               return SCSI_ABORT_BUSY;
+                       } else if (pTmpScb->SCB_TagMsg == 0) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+                               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+                               restore_flags(flags);
+#endif
+                               return SCSI_ABORT_BUSY;
+                       } else {
+                               pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+                               if (pTmpScb == pCurHcb->HCS_FirstBusy) {
+                                       if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+                                               pCurHcb->HCS_LastBusy = NULL;
+                               } else {
+                                       pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                                       if (pTmpScb == pCurHcb->HCS_LastBusy)
+                                               pCurHcb->HCS_LastBusy = pPrevScb;
+                               }
+                               pTmpScb->SCB_NxtScb = NULL;
+
+
+                               pTmpScb->SCB_HaStat = HOST_ABORTED;
+                               pTmpScb->SCB_Flags |= SCF_DONE;
+                               if (pTmpScb->SCB_Flags & SCF_POST)
+                                       (*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+                               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+                               restore_flags(flags);
+#endif
+                               return SCSI_ABORT_SUCCESS;
+                       }
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       restore_flags(flags);
+#endif
+       return (SCSI_ABORT_NOT_RUNNING);
+}
+
+/***************************************************************************/
+int tul_bad_seq(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+
+       printk("tul_bad_seg c=%d\n", pCurHcb->HCS_Index);
+
+       if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
+               tul_unlink_busy_scb(pCurHcb, pCurScb);
+               pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+               pCurScb->SCB_TaStat = 0;
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       tul_stop_bm(pCurHcb);
+
+       tul_reset_scsi(pCurHcb, 8);     /* 7/29/98 */
+
+       return (tul_post_scsi_rst(pCurHcb));
+}
+
+/************************************************************************/
+int tul_device_reset(HCS * pCurHcb, ULONG pSrb, unsigned int target, unsigned int ResetFlags)
+{
+       ULONG flags;
+       SCB *pScb;
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       save_flags(flags);
+       cli();
+#endif
+
+       if (ResetFlags & SCSI_RESET_ASYNCHRONOUS) {
+
+               if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+                       /* disable Jasmin SCSI Int        */
+                       tulip_main(pCurHcb);
+
+                       pCurHcb->HCS_Semaph = 1;
+                       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+                       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+                       restore_flags(flags);
+#endif
+
+                       return SCSI_RESET_SNOOZE;
+               }
+               pScb = pCurHcb->HCS_FirstBusy;  /* Check Busy queue */
+               while (pScb != NULL) {
+                       if (pScb->SCB_Srb == (unsigned char *) pSrb)
+                               break;
+                       pScb = pScb->SCB_NxtScb;
+               }
+               if (pScb == NULL) {
+                       printk("Unable to Reset - No SCB Found\n");
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+                       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+                       restore_flags(flags);
+#endif
+                       return SCSI_RESET_NOT_RUNNING;
+               }
+       }
+       if ((pScb = tul_alloc_scb(pCurHcb)) == NULL) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+               restore_flags(flags);
+#endif
+               return SCSI_RESET_NOT_RUNNING;
+       }
+       pScb->SCB_Opcode = BusDevRst;
+       pScb->SCB_Flags = SCF_POST;
+       pScb->SCB_Target = target;
+       pScb->SCB_Mode = 0;
+
+       pScb->SCB_Srb = 0;
+       if (ResetFlags & SCSI_RESET_SYNCHRONOUS) {
+               pScb->SCB_Srb = (unsigned char *) pSrb;
+       }
+       tul_push_pend_scb(pCurHcb, pScb);       /* push this SCB to Pending queue */
+
+       if (pCurHcb->HCS_Semaph == 1) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+               /* disable Jasmin SCSI Int        */
+               pCurHcb->HCS_Semaph = 0;
+
+               tulip_main(pCurHcb);
+
+               pCurHcb->HCS_Semaph = 1;
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+       }
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       restore_flags(flags);
+#endif
+       return SCSI_RESET_PENDING;
+}
+
+int tul_reset_scsi_bus(HCS * pCurHcb)
+{
+       ULONG flags;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       save_flags(flags);
+       cli();
+#endif
+       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+       pCurHcb->HCS_Semaph = 0;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       restore_flags(flags);
+#endif
+
+       tul_stop_bm(pCurHcb);
+
+       tul_reset_scsi(pCurHcb, 2);     /* 7/29/98 */
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       save_flags(flags);
+       cli();
+#endif
+       tul_post_scsi_rst(pCurHcb);
+
+       tulip_main(pCurHcb);
+
+       pCurHcb->HCS_Semaph = 1;
+       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       restore_flags(flags);
+#endif
+       return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
+}
+
+/************************************************************************/
+void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
+{
+       ULONG flags;
+
+       pCurScb->SCB_Mode = 0;
+
+       pCurScb->SCB_SGIdx = 0;
+       pCurScb->SCB_SGMax = pCurScb->SCB_SGLen;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       save_flags(flags);
+       cli();
+#endif
+
+       tul_append_pend_scb(pCurHcb, pCurScb);  /* Append this SCB to Pending queue */
+
+/* VVVVV 07/21/98 */
+       if (pCurHcb->HCS_Semaph == 1) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+               /* disable Jasmin SCSI Int        */
+               pCurHcb->HCS_Semaph = 0;
+
+               tulip_main(pCurHcb);
+
+               pCurHcb->HCS_Semaph = 1;
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+       }
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+#else
+       restore_flags(flags);
+#endif
+       return;
+}
+
+/***************************************************************************/
+int tul_isr(HCS * pCurHcb)
+{
+       /* Enter critical section       */
+
+       if (TUL_RD(pCurHcb->HCS_Base, TUL_Int) & TSS_INT_PENDING) {
+               if (pCurHcb->HCS_Semaph == 1) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+                       /* Disable Tulip SCSI Int */
+                       pCurHcb->HCS_Semaph = 0;
+
+                       tulip_main(pCurHcb);
+
+                       pCurHcb->HCS_Semaph = 1;
+                       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/***************************************************************************/
+int tulip_main(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+
+       for (;;) {
+
+               tulip_scsi(pCurHcb);    /* Call tulip_scsi              */
+
+               while ((pCurScb = tul_find_done_scb(pCurHcb)) != NULL) {        /* find done entry */
+                       if (pCurScb->SCB_TaStat == QUEUE_FULL) {
+                               pCurHcb->HCS_MaxTags[pCurScb->SCB_Target] =
+                                   pCurHcb->HCS_ActTags[pCurScb->SCB_Target] - 1;
+                               pCurScb->SCB_TaStat = 0;
+                               tul_append_pend_scb(pCurHcb, pCurScb);
+                               continue;
+                       }
+                       if (!(pCurScb->SCB_Mode & SCM_RSENS)) {         /* not in auto req. sense mode */
+                               if (pCurScb->SCB_TaStat == 2) {
+
+                                       /* clr sync. nego flag */
+
+                                       if (pCurScb->SCB_Flags & SCF_SENSE) {
+                                               BYTE len;
+                                               len = pCurScb->SCB_SenseLen;
+                                               if (len == 0)
+                                                       len = 1;
+                                               pCurScb->SCB_BufLen = pCurScb->SCB_SenseLen;
+                                               pCurScb->SCB_BufPtr = pCurScb->SCB_SensePtr;
+                                               pCurScb->SCB_Flags &= ~(SCF_SG | SCF_DIR);      /* for xfer_data_in */
+/*                      pCurScb->SCB_Flags |= SCF_NO_DCHK;      */
+                                               /* so, we won't report worng direction in xfer_data_in,
+                                                  and won't report HOST_DO_DU in state_6 */
+                                               pCurScb->SCB_Mode = SCM_RSENS;
+                                               pCurScb->SCB_Ident &= 0xBF;     /* Disable Disconnect */
+                                               pCurScb->SCB_TagMsg = 0;
+                                               pCurScb->SCB_TaStat = 0;
+                                               pCurScb->SCB_CDBLen = 6;
+                                               pCurScb->SCB_CDB[0] = SCSICMD_RequestSense;
+                                               pCurScb->SCB_CDB[1] = 0;
+                                               pCurScb->SCB_CDB[2] = 0;
+                                               pCurScb->SCB_CDB[3] = 0;
+                                               pCurScb->SCB_CDB[4] = len;
+                                               pCurScb->SCB_CDB[5] = 0;
+                                               tul_push_pend_scb(pCurHcb, pCurScb);
+                                               break;
+                                       }
+                               }
+                       } else {        /* in request sense mode */
+
+                               if (pCurScb->SCB_TaStat == 2) {         /* check contition status again after sending
+                                                                          requset sense cmd 0x3 */
+                                       pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+                               }
+                               pCurScb->SCB_TaStat = 2;
+                       }
+                       pCurScb->SCB_Flags |= SCF_DONE;
+                       if (pCurScb->SCB_Flags & SCF_POST) {
+                               (*pCurScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pCurScb);
+                       }
+               }               /* while */
+
+               /* find_active: */
+               if (TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0) & TSS_INT_PENDING)
+                       continue;
+
+               if (pCurHcb->HCS_ActScb) {      /* return to OS and wait for xfer_done_ISR/Selected_ISR */
+                       return 1;       /* return to OS, enable interrupt */
+               }
+               /* Check pending SCB            */
+               if (tul_find_first_pend_scb(pCurHcb) == NULL) {
+                       return 1;       /* return to OS, enable interrupt */
+               }
+       }                       /* End of for loop */
+       /* statement won't reach here */
+}
+
+
+
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+
+/***************************************************************************/
+void tulip_scsi(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+       TCS *pCurTcb;
+
+       /* make sure to service interrupt asap */
+
+       if ((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0)) & TSS_INT_PENDING) {
+
+               pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
+               pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
+               pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+               if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {     /* SCSI bus reset detected      */
+                       int_tul_scsi_rst(pCurHcb);
+                       return;
+               }
+               if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) {       /* if selected/reselected interrupt */
+                       if (int_tul_resel(pCurHcb) == 0)
+                               tul_next_state(pCurHcb);
+                       return;
+               }
+               if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {
+                       int_tul_busfree(pCurHcb);
+                       return;
+               }
+               if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {        /* BUS disconnection            */
+                       int_tul_busfree(pCurHcb);       /* unexpected bus free or sel timeout */
+                       return;
+               }
+               if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {      /* func complete or Bus service */
+                       if ((pCurScb = pCurHcb->HCS_ActScb) != NULL)
+                               tul_next_state(pCurHcb);
+                       return;
+               }
+       }
+       if (pCurHcb->HCS_ActScb != NULL)
+               return;
+
+       if ((pCurScb = tul_find_first_pend_scb(pCurHcb)) == NULL)
+               return;
+
+       /* program HBA's SCSI ID & target SCSI ID */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId,
+            (pCurHcb->HCS_SCSI_ID << 4) | (pCurScb->SCB_Target & 0x0F));
+       if (pCurScb->SCB_Opcode == ExecSCSI) {
+               pCurTcb = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+
+               if (pCurScb->SCB_TagMsg)
+                       pCurTcb->TCS_DrvFlags |= TCF_DRV_EN_TAG;
+               else
+                       pCurTcb->TCS_DrvFlags &= ~TCF_DRV_EN_TAG;
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
+               if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {        /* do wdtr negotiation          */
+                       tul_select_atn_stop(pCurHcb, pCurScb);
+               } else {
+                       if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {   /* do sync negotiation          */
+                               tul_select_atn_stop(pCurHcb, pCurScb);
+                       } else {
+                               if (pCurScb->SCB_TagMsg)
+                                       tul_select_atn3(pCurHcb, pCurScb);
+                               else
+                                       tul_select_atn(pCurHcb, pCurScb);
+                       }
+               }
+               if (pCurScb->SCB_Flags & SCF_POLL) {
+                       while (wait_tulip(pCurHcb) != -1) {
+                               if (tul_next_state(pCurHcb) == -1)
+                                       break;
+                       }
+               }
+       } else if (pCurScb->SCB_Opcode == BusDevRst) {
+               tul_select_atn_stop(pCurHcb, pCurScb);
+               pCurScb->SCB_NxtStat = 8;
+               if (pCurScb->SCB_Flags & SCF_POLL) {
+                       while (wait_tulip(pCurHcb) != -1) {
+                               if (tul_next_state(pCurHcb) == -1)
+                                       break;
+                       }
+               }
+       } else if (pCurScb->SCB_Opcode == AbortCmd) {
+               ULONG srbp;
+
+               srbp = (ULONG) pCurScb->SCB_Srb;
+/* 08/03/98 */
+               if (tul_abort_srb(pCurHcb, srbp) != 0) {
+
+
+                       tul_unlink_pend_scb(pCurHcb, pCurScb);
+
+                       tul_release_scb(pCurHcb, pCurScb);
+               } else {
+                       pCurScb->SCB_Opcode = BusDevRst;
+                       tul_select_atn_stop(pCurHcb, pCurScb);
+                       pCurScb->SCB_NxtStat = 8;
+               }
+
+/* 08/03/98 */
+       } else {
+               tul_unlink_pend_scb(pCurHcb, pCurScb);
+               pCurScb->SCB_HaStat = 0x16;     /* bad command */
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       return;
+}
+
+
+/***************************************************************************/
+int tul_next_state(HCS * pCurHcb)
+{
+       int next;
+
+       next = pCurHcb->HCS_ActScb->SCB_NxtStat;
+       for (;;) {
+               switch (next) {
+               case 1:
+                       next = tul_state_1(pCurHcb);
+                       break;
+               case 2:
+                       next = tul_state_2(pCurHcb);
+                       break;
+               case 3:
+                       next = tul_state_3(pCurHcb);
+                       break;
+               case 4:
+                       next = tul_state_4(pCurHcb);
+                       break;
+               case 5:
+                       next = tul_state_5(pCurHcb);
+                       break;
+               case 6:
+                       next = tul_state_6(pCurHcb);
+                       break;
+               case 7:
+                       next = tul_state_7(pCurHcb);
+                       break;
+               case 8:
+                       return (tul_bus_device_reset(pCurHcb));
+               default:
+                       return (tul_bad_seq(pCurHcb));
+               }
+               if (next <= 0)
+                       return next;
+       }
+}
+
+
+/***************************************************************************/
+/* sTate after selection with attention & stop */
+int tul_state_1(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+#if DEBUG_STATE
+       printk("-s1-");
+#endif
+
+       tul_unlink_pend_scb(pCurHcb, pCurScb);
+       tul_append_busy_scb(pCurHcb, pCurScb);
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+       /* ATN on */
+       if (pCurHcb->HCS_Phase == MSG_OUT) {
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, (TSC_EN_BUS_IN | TSC_HW_RESELECT));
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
+
+               if (pCurScb->SCB_TagMsg) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
+               }
+               if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {
+
+                       pCurTcb->TCS_Flags |= TCF_WDTR_DONE;
+
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);       /* Extended msg length */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);       /* Sync request */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);       /* Start from 16 bits */
+               } else if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {
+
+                       pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
+
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);       /* extended msg length */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);       /* sync request */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);      /* REQ/ACK offset */
+               }
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               if (wait_tulip(pCurHcb) == -1)
+                       return (-1);
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
+       return (3);
+}
+
+
+/***************************************************************************/
+/* state after selection with attention */
+/* state after selection with attention3 */
+int tul_state_2(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+#if DEBUG_STATE
+       printk("-s2-");
+#endif
+
+       tul_unlink_pend_scb(pCurHcb, pCurScb);
+       tul_append_busy_scb(pCurHcb, pCurScb);
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+
+       if (pCurHcb->HCS_JSStatus1 & TSS_CMD_PH_CMP) {
+               return (4);
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
+       return (3);
+}
+
+/***************************************************************************/
+/* state before CDB xfer is done */
+int tul_state_3(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+       int i;
+
+#if DEBUG_STATE
+       printk("-s3-");
+#endif
+       for (;;) {
+               switch (pCurHcb->HCS_Phase) {
+               case CMD_OUT:   /* Command out phase            */
+                       for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                       if (wait_tulip(pCurHcb) == -1)
+                               return (-1);
+                       if (pCurHcb->HCS_Phase == CMD_OUT) {
+                               return (tul_bad_seq(pCurHcb));
+                       }
+                       return (4);
+
+               case MSG_IN:    /* Message in phase             */
+                       pCurScb->SCB_NxtStat = 3;
+                       if (tul_msgin(pCurHcb) == -1)
+                               return (-1);
+                       break;
+
+               case STATUS_IN: /* Status phase                 */
+                       if (tul_status_msg(pCurHcb) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_OUT:   /* Message out phase            */
+                       if (pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {
+
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);         /* msg nop */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                               if (wait_tulip(pCurHcb) == -1)
+                                       return (-1);
+
+                       } else {
+                               pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
+
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);       /* ext. msg len */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);       /* sync request */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);      /* REQ/ACK offset */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                               if (wait_tulip(pCurHcb) == -1)
+                                       return (-1);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7));
+
+                       }
+                       break;
+
+               default:
+                       return (tul_bad_seq(pCurHcb));
+               }
+       }
+}
+
+
+/***************************************************************************/
+int tul_state_4(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+#if DEBUG_STATE
+       printk("-s4-");
+#endif
+       if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_NO_XF) {
+               return (6);     /* Go to state 6                */
+       }
+       for (;;) {
+               if (pCurScb->SCB_BufLen == 0)
+                       return (6);     /* Go to state 6                */
+
+               switch (pCurHcb->HCS_Phase) {
+
+               case STATUS_IN: /* Status phase                 */
+                       if ((pCurScb->SCB_Flags & SCF_DIR) != 0) {      /* if direction bit set then report data underrun */
+                               pCurScb->SCB_HaStat = HOST_DO_DU;
+                       }
+                       if ((tul_status_msg(pCurHcb)) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_IN:    /* Message in phase             */
+                       pCurScb->SCB_NxtStat = 0x4;
+                       if (tul_msgin(pCurHcb) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_OUT:   /* Message out phase            */
+                       if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
+                               pCurScb->SCB_BufLen = 0;
+                               pCurScb->SCB_HaStat = HOST_DO_DU;
+                               if (tul_msgout_ide(pCurHcb) == -1)
+                                       return (-1);
+                               return (6);     /* Go to state 6                */
+                       } else {
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);         /* msg nop */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                               if (wait_tulip(pCurHcb) == -1)
+                                       return (-1);
+                       }
+                       break;
+
+               case DATA_IN:   /* Data in phase                */
+                       return (tul_xfer_data_in(pCurHcb));
+
+               case DATA_OUT:  /* Data out phase               */
+                       return (tul_xfer_data_out(pCurHcb));
+
+               default:
+                       return (tul_bad_seq(pCurHcb));
+               }
+       }
+}
+
+
+/***************************************************************************/
+/* state after dma xfer done or phase change before xfer done */
+int tul_state_5(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       long cnt, xcnt;         /* cannot use unsigned !! code: if (xcnt < 0) */
+
+#if DEBUG_STATE
+       printk("-s5-");
+#endif
+/*------ get remaining count -------*/
+
+       cnt = TUL_RDLONG(pCurHcb->HCS_Base, TUL_SCnt0) & 0x0FFFFFF;
+
+       if (TUL_RD(pCurHcb->HCS_Base, TUL_XCmd) & 0x20) {
+               /* ----------------------- DATA_IN ----------------------------- */
+               /* check scsi parity error */
+               if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
+                       pCurScb->SCB_HaStat = HOST_DO_DU;
+               }
+               if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {   /* DMA xfer pending, Send STOP  */
+                       /* tell Hardware  scsi xfer has been terminated */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, TUL_RD(pCurHcb->HCS_Base, TUL_XCtrl) | 0x80);
+                       /* wait until DMA xfer not pending */
+                       while (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND);
+               }
+       } else {
+/*-------- DATA OUT -----------*/
+               if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0) {
+                       if (pCurHcb->HCS_ActTcs->TCS_JS_Period & TSC_WIDE_SCSI)
+                               cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F) << 1;
+                       else
+                               cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F);
+               }
+               if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {   /* if DMA xfer is pending, abort DMA xfer */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT);
+                       /* wait Abort DMA xfer done */
+                       while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+               }
+               if ((cnt == 1) && (pCurHcb->HCS_Phase == DATA_OUT)) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                       if (wait_tulip(pCurHcb) == -1) {
+                               return (-1);
+                       }
+                       cnt = 0;
+               } else {
+                       if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0)
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+               }
+       }
+
+       if (cnt == 0) {
+               pCurScb->SCB_BufLen = 0;
+               return (6);     /* Go to state 6                */
+       }
+       /* Update active data pointer */
+       xcnt = (long) pCurScb->SCB_BufLen - cnt;        /* xcnt== bytes already xferred */
+       pCurScb->SCB_BufLen = (U32) cnt;        /* cnt == bytes left to be xferred */
+       if (pCurScb->SCB_Flags & SCF_SG) {
+               register SG *sgp;
+               ULONG i;
+
+               sgp = &pCurScb->SCB_SGList[pCurScb->SCB_SGIdx];
+               for (i = pCurScb->SCB_SGIdx; i < pCurScb->SCB_SGMax; sgp++, i++) {
+                       xcnt -= (long) sgp->SG_Len;
+                       if (xcnt < 0) {         /* this sgp xfer half done */
+                               xcnt += (long) sgp->SG_Len;     /* xcnt == bytes xferred in this sgp */
+                               sgp->SG_Ptr += (U32) xcnt;      /* new ptr to be xfer */
+                               sgp->SG_Len -= (U32) xcnt;      /* new len to be xfer */
+                               pCurScb->SCB_BufPtr += ((U32) (i - pCurScb->SCB_SGIdx) << 3);
+                               /* new SG table ptr */
+                               pCurScb->SCB_SGLen = (BYTE) (pCurScb->SCB_SGMax - i);
+                               /* new SG table len */
+                               pCurScb->SCB_SGIdx = (WORD) i;
+                               /* for next disc and come in this loop */
+                               return (4);     /* Go to state 4                */
+                       }
+                       /* else (xcnt >= 0 , i.e. this sgp already xferred */
+               }               /* for */
+               return (6);     /* Go to state 6                */
+       } else {
+               pCurScb->SCB_BufPtr += (U32) xcnt;
+       }
+       return (4);             /* Go to state 4                */
+}
+
+/***************************************************************************/
+/* state after Data phase */
+int tul_state_6(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+#if DEBUG_STATE
+       printk("-s6-");
+#endif
+       for (;;) {
+               switch (pCurHcb->HCS_Phase) {
+               case STATUS_IN: /* Status phase                 */
+                       if ((tul_status_msg(pCurHcb)) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_IN:    /* Message in phase             */
+                       pCurScb->SCB_NxtStat = 6;
+                       if ((tul_msgin(pCurHcb)) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_OUT:   /* Message out phase            */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);         /* msg nop */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                       if (wait_tulip(pCurHcb) == -1)
+                               return (-1);
+                       break;
+
+               case DATA_IN:   /* Data in phase                */
+                       return (tul_xpad_in(pCurHcb));
+
+               case DATA_OUT:  /* Data out phase               */
+                       return (tul_xpad_out(pCurHcb));
+
+               default:
+                       return (tul_bad_seq(pCurHcb));
+               }
+       }
+}
+
+/***************************************************************************/
+int tul_state_7(HCS * pCurHcb)
+{
+       int cnt, i;
+
+#if DEBUG_STATE
+       printk("-s7-");
+#endif
+       /* flush SCSI FIFO */
+       cnt = TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F;
+       if (cnt) {
+               for (i = 0; i < cnt; i++)
+                       TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+       }
+       switch (pCurHcb->HCS_Phase) {
+       case DATA_IN:           /* Data in phase                */
+       case DATA_OUT:          /* Data out phase               */
+               return (tul_bad_seq(pCurHcb));
+       default:
+               return (6);     /* Go to state 6                */
+       }
+}
+
+/***************************************************************************/
+int tul_xfer_data_in(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+       if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DOUT) {
+               return (6);     /* wrong direction */
+       }
+       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_IN);    /* 7/25/95 */
+
+       if (pCurScb->SCB_Flags & SCF_SG) {      /* S/G xfer */
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_IN);
+       } else {
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_IN);
+       }
+       pCurScb->SCB_NxtStat = 0x5;
+       return (0);             /* return to OS, wait xfer done , let jas_isr come in */
+}
+
+
+/***************************************************************************/
+int tul_xfer_data_out(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+       if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DIN) {
+               return (6);     /* wrong direction */
+       }
+       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_OUT);
+
+       if (pCurScb->SCB_Flags & SCF_SG) {      /* S/G xfer */
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_OUT);
+       } else {
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_OUT);
+       }
+
+       pCurScb->SCB_NxtStat = 0x5;
+       return (0);             /* return to OS, wait xfer done , let jas_isr come in */
+}
+
+
+/***************************************************************************/
+int tul_xpad_in(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+
+       if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
+               pCurScb->SCB_HaStat = HOST_DO_DU;       /* over run             */
+       }
+       for (;;) {
+               if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
+                       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+               else
+                       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if ((wait_tulip(pCurHcb)) == -1) {
+                       return (-1);
+               }
+               if (pCurHcb->HCS_Phase != DATA_IN) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                       return (6);
+               }
+               TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+       }
+}
+
+int tul_xpad_out(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+
+       if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
+               pCurScb->SCB_HaStat = HOST_DO_DU;       /* over run             */
+       }
+       for (;;) {
+               if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
+                       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+               else
+                       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               if ((wait_tulip(pCurHcb)) == -1) {
+                       return (-1);
+               }
+               if (pCurHcb->HCS_Phase != DATA_OUT) {   /* Disable wide CPU to allow read 16 bits */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                       return (6);
+               }
+       }
+}
+
+
+/***************************************************************************/
+int tul_status_msg(HCS * pCurHcb)
+{                              /* status & MSG_IN */
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       BYTE msg;
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_CMD_COMP);
+       if ((wait_tulip(pCurHcb)) == -1) {
+               return (-1);
+       }
+       /* get status */
+       pCurScb->SCB_TaStat = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+
+       if (pCurHcb->HCS_Phase == MSG_OUT) {
+               if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
+               } else {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);
+               }
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               return (wait_tulip(pCurHcb));
+       }
+       if (pCurHcb->HCS_Phase == MSG_IN) {
+               msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+               if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {   /* Parity error                 */
+                       if ((tul_msgin_accept(pCurHcb)) == -1)
+                               return (-1);
+                       if (pCurHcb->HCS_Phase != MSG_OUT)
+                               return (tul_bad_seq(pCurHcb));
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                       return (wait_tulip(pCurHcb));
+               }
+               if (msg == 0) { /* Command complete             */
+
+                       if ((pCurScb->SCB_TaStat & 0x18) == 0x10) {     /* No link support              */
+                               return (tul_bad_seq(pCurHcb));
+                       }
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+                       return tul_wait_done_disc(pCurHcb);
+
+               }
+               if ((msg == MSG_LINK_COMP) || (msg == MSG_LINK_FLAG)) {
+                       if ((pCurScb->SCB_TaStat & 0x18) == 0x10)
+                               return (tul_msgin_accept(pCurHcb));
+               }
+       }
+       return (tul_bad_seq(pCurHcb));
+}
+
+
+/***************************************************************************/
+/* scsi bus free */
+int int_tul_busfree(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+       if (pCurScb != NULL) {
+               if (pCurScb->SCB_Status & SCB_SELECT) {         /* selection timeout */
+                       tul_unlink_pend_scb(pCurHcb, pCurScb);
+                       pCurScb->SCB_HaStat = HOST_SEL_TOUT;
+                       tul_append_done_scb(pCurHcb, pCurScb);
+               } else {        /* Unexpected bus free          */
+                       tul_unlink_busy_scb(pCurHcb, pCurScb);
+                       pCurScb->SCB_HaStat = HOST_BUS_FREE;
+                       tul_append_done_scb(pCurHcb, pCurScb);
+               }
+               pCurHcb->HCS_ActScb = NULL;
+               pCurHcb->HCS_ActTcs = NULL;
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+       return (-1);
+}
+
+
+/***************************************************************************/
+/* scsi bus reset */
+int int_tul_scsi_rst(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+       int i;
+
+       /* if DMA xfer is pending, abort DMA xfer */
+       if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & 0x01) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+               /* wait Abort DMA xfer done */
+               while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & 0x04) == 0);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+       }
+       /* Abort all active & disconnected scb */
+       while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
+               pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       pCurHcb->HCS_ActScb = NULL;
+       pCurHcb->HCS_ActTcs = NULL;
+
+       /* clr sync nego. done flag */
+       for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
+               pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+       }
+       return (-1);
+}
+
+
+/***************************************************************************/
+/* scsi reselection */
+int int_tul_resel(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+       TCS *pCurTcb;
+       BYTE tag, msg = 0;
+       BYTE tar, lun;
+
+       if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
+               if (pCurScb->SCB_Status & SCB_SELECT) {         /* if waiting for selection complete */
+                       pCurScb->SCB_Status &= ~SCB_SELECT;
+               }
+               pCurHcb->HCS_ActScb = NULL;
+       }
+       /* --------- get target id---------------------- */
+       tar = TUL_RD(pCurHcb->HCS_Base, TUL_SBusId);
+       /* ------ get LUN from Identify message----------- */
+       lun = TUL_RD(pCurHcb->HCS_Base, TUL_SIdent) & 0x0F;
+       /* 07/22/98 from 0x1F -> 0x0F */
+       pCurTcb = &pCurHcb->HCS_Tcs[tar];
+       pCurHcb->HCS_ActTcs = pCurTcb;
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
+
+
+       /* ------------- tag queueing ? ------------------- */
+       if (pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG) {
+               if ((tul_msgin_accept(pCurHcb)) == -1)
+                       return (-1);
+               if (pCurHcb->HCS_Phase != MSG_IN)
+                       goto no_tag;
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if ((wait_tulip(pCurHcb)) == -1)
+                       return (-1);
+               msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);     /* Read Tag Message    */
+
+               if ((msg < MSG_STAG) || (msg > MSG_OTAG))       /* Is simple Tag      */
+                       goto no_tag;
+
+               if ((tul_msgin_accept(pCurHcb)) == -1)
+                       return (-1);
+
+               if (pCurHcb->HCS_Phase != MSG_IN)
+                       goto no_tag;
+
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if ((wait_tulip(pCurHcb)) == -1)
+                       return (-1);
+               tag = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);     /* Read Tag ID       */
+               pCurScb = pCurHcb->HCS_Scb + tag;
+               if ((pCurScb->SCB_Target != tar) || (pCurScb->SCB_Lun != lun)) {
+                       return tul_msgout_abort_tag(pCurHcb);
+               }
+               if (pCurScb->SCB_Status != SCB_BUSY) {  /* 03/24/95             */
+                       return tul_msgout_abort_tag(pCurHcb);
+               }
+               pCurHcb->HCS_ActScb = pCurScb;
+               if ((tul_msgin_accept(pCurHcb)) == -1)
+                       return (-1);
+       } else {                /* No tag               */
+             no_tag:
+               if ((pCurScb = tul_find_busy_scb(pCurHcb, tar | (lun << 8))) == NULL) {
+                       return tul_msgout_abort_targ(pCurHcb);
+               }
+               pCurHcb->HCS_ActScb = pCurScb;
+               if (!(pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG)) {
+                       if ((tul_msgin_accept(pCurHcb)) == -1)
+                               return (-1);
+               }
+       }
+       return 0;
+}
+
+
+/***************************************************************************/
+int int_tul_bad_seq(HCS * pCurHcb)
+{                              /* target wrong phase           */
+       SCB *pCurScb;
+       int i;
+
+       tul_reset_scsi(pCurHcb, 10);
+
+       while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
+               pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
+               pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);;
+       }
+       return (-1);
+}
+
+
+/***************************************************************************/
+int tul_msgout_abort_targ(HCS * pCurHcb)
+{
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+       if (tul_msgin_accept(pCurHcb) == -1)
+               return (-1);
+       if (pCurHcb->HCS_Phase != MSG_OUT)
+               return (tul_bad_seq(pCurHcb));
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+
+       return tul_wait_disc(pCurHcb);
+}
+
+/***************************************************************************/
+int tul_msgout_abort_tag(HCS * pCurHcb)
+{
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+       if (tul_msgin_accept(pCurHcb) == -1)
+               return (-1);
+       if (pCurHcb->HCS_Phase != MSG_OUT)
+               return (tul_bad_seq(pCurHcb));
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT_TAG);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+
+       return tul_wait_disc(pCurHcb);
+
+}
+
+/***************************************************************************/
+int tul_msgin(HCS * pCurHcb)
+{
+       TCS *pCurTcb;
+
+       for (;;) {
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if ((wait_tulip(pCurHcb)) == -1)
+                       return (-1);
+
+               switch (TUL_RD(pCurHcb->HCS_Base, TUL_SFifo)) {
+               case MSG_DISC:  /* Disconnect msg */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+
+                       return tul_wait_disc(pCurHcb);
+
+               case MSG_SDP:
+               case MSG_RESTORE:
+               case MSG_NOP:
+                       tul_msgin_accept(pCurHcb);
+                       break;
+
+               case MSG_REJ:   /* Clear ATN first              */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal,
+                              (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
+                       pCurTcb = pCurHcb->HCS_ActTcs;
+                       if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {   /* do sync nego */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+                       }
+                       tul_msgin_accept(pCurHcb);
+                       break;
+
+               case MSG_EXTEND:        /* extended msg */
+                       tul_msgin_extend(pCurHcb);
+                       break;
+
+               case MSG_IGNOREWIDE:
+                       tul_msgin_accept(pCurHcb);
+                       break;
+
+                       /* get */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+                       if (wait_tulip(pCurHcb) == -1)
+                               return -1;
+
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);       /* put pad  */
+                       TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);   /* get IGNORE field */
+                       TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);   /* get pad */
+
+                       tul_msgin_accept(pCurHcb);
+                       break;
+
+               case MSG_COMP:
+                       {
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+                               return tul_wait_done_disc(pCurHcb);
+                       }
+               default:
+                       tul_msgout_reject(pCurHcb);
+                       break;
+               }
+               if (pCurHcb->HCS_Phase != MSG_IN)
+                       return (pCurHcb->HCS_Phase);
+       }
+       /* statement won't reach here */
+}
+
+
+
+
+/***************************************************************************/
+int tul_msgout_reject(HCS * pCurHcb)
+{
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+
+       if ((tul_msgin_accept(pCurHcb)) == -1)
+               return (-1);
+
+       if (pCurHcb->HCS_Phase == MSG_OUT) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_REJ);         /* Msg reject           */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               return (wait_tulip(pCurHcb));
+       }
+       return (pCurHcb->HCS_Phase);
+}
+
+
+
+/***************************************************************************/
+int tul_msgout_ide(HCS * pCurHcb)
+{
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_IDE);         /* Initiator Detected Error */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+       return (wait_tulip(pCurHcb));
+}
+
+
+/***************************************************************************/
+int tul_msgin_extend(HCS * pCurHcb)
+{
+       BYTE len, idx;
+
+       if (tul_msgin_accept(pCurHcb) != MSG_IN)
+               return (pCurHcb->HCS_Phase);
+
+       /* Get extended msg length      */
+       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+       if (wait_tulip(pCurHcb) == -1)
+               return (-1);
+
+       len = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+       pCurHcb->HCS_Msg[0] = len;
+       for (idx = 1; len != 0; len--) {
+
+               if ((tul_msgin_accept(pCurHcb)) != MSG_IN)
+                       return (pCurHcb->HCS_Phase);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if (wait_tulip(pCurHcb) == -1)
+                       return (-1);
+               pCurHcb->HCS_Msg[idx++] = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+       }
+       if (pCurHcb->HCS_Msg[1] == 1) {         /* if it's synchronous data transfer request */
+               if (pCurHcb->HCS_Msg[0] != 3)   /* if length is not right */
+                       return (tul_msgout_reject(pCurHcb));
+               if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_SYNC_NEGO) {        /* Set OFFSET=0 to do async, nego back */
+                       pCurHcb->HCS_Msg[3] = 0;
+               } else {
+                       if ((tul_msgin_sync(pCurHcb) == 0) &&
+                           (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SYNC_DONE)) {
+                               tul_sync_done(pCurHcb);
+                               return (tul_msgin_accept(pCurHcb));
+                       }
+               }
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+               if ((tul_msgin_accept(pCurHcb)) != MSG_OUT)
+                       return (pCurHcb->HCS_Phase);
+               /* sync msg out */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+
+               tul_sync_done(pCurHcb);
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[3]);
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               return (wait_tulip(pCurHcb));
+       }
+       if ((pCurHcb->HCS_Msg[0] != 2) || (pCurHcb->HCS_Msg[1] != 3))
+               return (tul_msgout_reject(pCurHcb));
+       /* if it's WIDE DATA XFER REQ   */
+       if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) {
+               pCurHcb->HCS_Msg[2] = 0;
+       } else {
+               if (pCurHcb->HCS_Msg[2] > 2)    /* > 32 bits            */
+                       return (tul_msgout_reject(pCurHcb));
+               if (pCurHcb->HCS_Msg[2] == 2) {         /* == 32                */
+                       pCurHcb->HCS_Msg[2] = 1;
+               } else {
+                       if ((pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) == 0) {
+                               wdtr_done(pCurHcb);
+                               if ((pCurHcb->HCS_ActTcs->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)
+                                       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+                               return (tul_msgin_accept(pCurHcb));
+                       }
+               }
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+
+       if (tul_msgin_accept(pCurHcb) != MSG_OUT)
+               return (pCurHcb->HCS_Phase);
+       /* WDTR msg out                 */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+       return (wait_tulip(pCurHcb));
+}
+
+/***************************************************************************/
+int tul_msgin_sync(HCS * pCurHcb)
+{
+       char default_period;
+
+       default_period = tul_rate_tbl[pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SCSI_RATE];
+       if (pCurHcb->HCS_Msg[3] > MAX_OFFSET) {
+               pCurHcb->HCS_Msg[3] = MAX_OFFSET;
+               if (pCurHcb->HCS_Msg[2] < default_period) {
+                       pCurHcb->HCS_Msg[2] = default_period;
+                       return 1;
+               }
+               if (pCurHcb->HCS_Msg[2] >= 59) {        /* Change to async              */
+                       pCurHcb->HCS_Msg[3] = 0;
+               }
+               return 1;
+       }
+       /* offset requests asynchronous transfers ? */
+       if (pCurHcb->HCS_Msg[3] == 0) {
+               return 0;
+       }
+       if (pCurHcb->HCS_Msg[2] < default_period) {
+               pCurHcb->HCS_Msg[2] = default_period;
+               return 1;
+       }
+       if (pCurHcb->HCS_Msg[2] >= 59) {
+               pCurHcb->HCS_Msg[3] = 0;
+               return 1;
+       }
+       return 0;
+}
+
+
+/***************************************************************************/
+int wdtr_done(HCS * pCurHcb)
+{
+       pCurHcb->HCS_ActTcs->TCS_Flags &= ~TCF_SYNC_DONE;
+       pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_WDTR_DONE;
+
+       pCurHcb->HCS_ActTcs->TCS_JS_Period = 0;
+       if (pCurHcb->HCS_Msg[2]) {      /* if 16 bit */
+               pCurHcb->HCS_ActTcs->TCS_JS_Period |= TSC_WIDE_SCSI;
+       }
+       pCurHcb->HCS_ActTcs->TCS_SConfig0 &= ~TSC_ALT_PERIOD;
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+
+       return 1;
+}
+
+/***************************************************************************/
+int tul_sync_done(HCS * pCurHcb)
+{
+       int i;
+
+       pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_SYNC_DONE;
+
+       if (pCurHcb->HCS_Msg[3]) {
+               pCurHcb->HCS_ActTcs->TCS_JS_Period |= pCurHcb->HCS_Msg[3];
+               for (i = 0; i < 8; i++) {
+                       if (tul_rate_tbl[i] >= pCurHcb->HCS_Msg[2])     /* pick the big one */
+                               break;
+               }
+               pCurHcb->HCS_ActTcs->TCS_JS_Period |= (i << 4);
+               pCurHcb->HCS_ActTcs->TCS_SConfig0 |= TSC_ALT_PERIOD;
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+
+       return (-1);
+}
+
+
+int tul_post_scsi_rst(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+       TCS *pCurTcb;
+       int i;
+
+       pCurHcb->HCS_ActScb = 0;
+       pCurHcb->HCS_ActTcs = 0;
+       pCurHcb->HCS_Flags = 0;
+
+       while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
+               pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       /* clear sync done flag         */
+       pCurTcb = &pCurHcb->HCS_Tcs[0];
+       for (i = 0; i < pCurHcb->HCS_MaxTar; pCurTcb++, i++) {
+               pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+               /* Initialize the sync. xfer register values to an asyn xfer */
+               pCurTcb->TCS_JS_Period = 0;
+               pCurTcb->TCS_SConfig0 = pCurHcb->HCS_SConf1;
+               pCurHcb->HCS_ActTags[0] = 0;    /* 07/22/98 */
+               pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;     /* 07/22/98 */
+       }                       /* for */
+
+       return (-1);
+}
+
+/***************************************************************************/
+void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb)
+{
+       pCurScb->SCB_Status |= SCB_SELECT;
+       pCurScb->SCB_NxtStat = 0x1;
+       pCurHcb->HCS_ActScb = pCurScb;
+       pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SELATNSTOP);
+       return;
+}
+
+
+/***************************************************************************/
+void tul_select_atn(HCS * pCurHcb, SCB * pCurScb)
+{
+       int i;
+
+       pCurScb->SCB_Status |= SCB_SELECT;
+       pCurScb->SCB_NxtStat = 0x2;
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
+       for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
+       pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+       pCurHcb->HCS_ActScb = pCurScb;
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN);
+       return;
+}
+
+/***************************************************************************/
+void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb)
+{
+       int i;
+
+       pCurScb->SCB_Status |= SCB_SELECT;
+       pCurScb->SCB_NxtStat = 0x2;
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
+       for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
+       pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+       pCurHcb->HCS_ActScb = pCurScb;
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN3);
+       return;
+}
+
+/***************************************************************************/
+/* SCSI Bus Device Reset */
+int tul_bus_device_reset(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+       SCB *pTmpScb, *pPrevScb;
+       BYTE tar;
+
+       if (pCurHcb->HCS_Phase != MSG_OUT) {
+               return (int_tul_bad_seq(pCurHcb));      /* Unexpected phase             */
+       }
+       tul_unlink_pend_scb(pCurHcb, pCurScb);
+       tul_release_scb(pCurHcb, pCurScb);
+
+
+       tar = pCurScb->SCB_Target;      /* target                       */
+       pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
+       /* clr sync. nego & WDTR flags  07/22/98 */
+
+       /* abort all SCB with same target */
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;    /* Check Busy queue */
+       while (pTmpScb != NULL) {
+
+               if (pTmpScb->SCB_Target == tar) {
+                       /* unlink it */
+                       if (pTmpScb == pCurHcb->HCS_FirstBusy) {
+                               if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+                                       pCurHcb->HCS_LastBusy = NULL;
+                       } else {
+                               pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                               if (pTmpScb == pCurHcb->HCS_LastBusy)
+                                       pCurHcb->HCS_LastBusy = pPrevScb;
+                       }
+                       pTmpScb->SCB_HaStat = HOST_ABORTED;
+                       tul_append_done_scb(pCurHcb, pTmpScb);
+               }
+               /* Previous haven't change      */
+               else {
+                       pPrevScb = pTmpScb;
+               }
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_DEVRST);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+
+       return tul_wait_disc(pCurHcb);
+
+}
+
+/***************************************************************************/
+int tul_msgin_accept(HCS * pCurHcb)
+{
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+       return (wait_tulip(pCurHcb));
+}
+
+/***************************************************************************/
+int wait_tulip(HCS * pCurHcb)
+{
+
+       while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
+                & TSS_INT_PENDING));
+
+       pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+       pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
+       pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
+
+       if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) {       /* if SCSI bus reset detected   */
+               return (int_tul_resel(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {     /* if selected/reselected timeout interrupt */
+               return (int_tul_busfree(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {     /* if SCSI bus reset detected   */
+               return (int_tul_scsi_rst(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {        /* BUS disconnection            */
+               if (pCurHcb->HCS_Flags & HCF_EXPECT_DONE_DISC) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+                       tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
+                       pCurHcb->HCS_ActScb->SCB_HaStat = 0;
+                       tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
+                       pCurHcb->HCS_ActScb = NULL;
+                       pCurHcb->HCS_ActTcs = NULL;
+                       pCurHcb->HCS_Flags &= ~HCF_EXPECT_DONE_DISC;
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+                       return (-1);
+               }
+               if (pCurHcb->HCS_Flags & HCF_EXPECT_DISC) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+                       pCurHcb->HCS_ActScb = NULL;
+                       pCurHcb->HCS_ActTcs = NULL;
+                       pCurHcb->HCS_Flags &= ~HCF_EXPECT_DISC;
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+                       return (-1);
+               }
+               return (int_tul_busfree(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {
+               return (pCurHcb->HCS_Phase);
+       }
+       return (pCurHcb->HCS_Phase);
+}
+/***************************************************************************/
+int tul_wait_disc(HCS * pCurHcb)
+{
+
+       while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
+                & TSS_INT_PENDING));
+
+
+       pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+
+       if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {     /* if SCSI bus reset detected   */
+               return (int_tul_scsi_rst(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {        /* BUS disconnection            */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+               pCurHcb->HCS_ActScb = NULL;
+               return (-1);
+       }
+       return (tul_bad_seq(pCurHcb));
+}
+
+/***************************************************************************/
+int tul_wait_done_disc(HCS * pCurHcb)
+{
+
+
+       while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
+                & TSS_INT_PENDING));
+
+       pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+
+
+       if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {     /* if SCSI bus reset detected   */
+               return (int_tul_scsi_rst(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {        /* BUS disconnection            */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+               tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
+
+               tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
+               pCurHcb->HCS_ActScb = NULL;
+               return (-1);
+       }
+       return (tul_bad_seq(pCurHcb));
+}
+
+/**************************** EOF *********************************/
diff --git a/drivers/scsi/i91uscsi.h b/drivers/scsi/i91uscsi.h
new file mode 100644 (file)
index 0000000..b3a2253
--- /dev/null
@@ -0,0 +1,857 @@
+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ **************************************************************************/
+
+#include <linux/config.h>
+
+#define ULONG   unsigned long
+#define USHORT  unsigned short
+#define UCHAR   unsigned char
+#define BYTE    unsigned char
+#define WORD    unsigned short
+#define DWORD   unsigned long
+#define UBYTE   unsigned char
+#define UWORD   unsigned short
+#define UDWORD  unsigned long
+#ifdef ALPHA
+#define U32     unsigned int
+#else
+#define U32     unsigned long
+#endif
+
+#ifndef NULL
+#define NULL     0             /* zero          */
+#endif
+#ifndef TRUE
+#define TRUE     (1)           /* boolean true  */
+#endif
+#ifndef FALSE
+#define FALSE    (0)           /* boolean false */
+#endif
+#ifndef FAILURE
+#define FAILURE  (-1)
+#endif
+
+#define TOTAL_SG_ENTRY         32
+#define MAX_SUPPORTED_ADAPTERS  8
+#define MAX_OFFSET             15
+#define MAX_TARGETS            16
+
+#define INI_VENDOR_ID   0x1101 /* Initio's PCI vendor ID       */
+#define I950_DEVICE_ID 0x9500  /* Initio's inic-950 product ID   */
+#define I940_DEVICE_ID 0x9400  /* Initio's inic-940 product ID   */
+#define I935_DEVICE_ID 0x9401  /* Initio's inic-935 product ID   */
+
+#define        _I91USCSI_H
+
+typedef struct {
+       unsigned short base;
+       unsigned short vec;
+} i91u_config;
+
+/***************************************/
+/*  Tulip Configuration Register Set */
+/***************************************/
+#define TUL_PVID        0x00   /* Vendor ID                    */
+#define TUL_PDID        0x02   /* Device ID                    */
+#define TUL_PCMD        0x04   /* Command                      */
+#define TUL_PSTUS       0x06   /* Status                       */
+#define TUL_PRID        0x08   /* Revision number              */
+#define TUL_PPI         0x09   /* Programming interface        */
+#define TUL_PSC         0x0A   /* Sub Class                    */
+#define TUL_PBC         0x0B   /* Base Class                   */
+#define TUL_PCLS        0x0C   /* Cache line size              */
+#define TUL_PLTR        0x0D   /* Latency timer                */
+#define TUL_PHDT        0x0E   /* Header type                  */
+#define TUL_PBIST       0x0F   /* BIST                         */
+#define TUL_PBAD        0x10   /* Base address                 */
+#define TUL_PBAD1       0x14   /* Base address                 */
+#define TUL_PBAD2       0x18   /* Base address                 */
+#define TUL_PBAD3       0x1C   /* Base address                 */
+#define TUL_PBAD4       0x20   /* Base address                 */
+#define TUL_PBAD5       0x24   /* Base address                 */
+#define TUL_PRSVD       0x28   /* Reserved                     */
+#define TUL_PRSVD1      0x2C   /* Reserved                     */
+#define TUL_PRAD        0x30   /* Expansion ROM base address   */
+#define TUL_PRSVD2      0x34   /* Reserved                     */
+#define TUL_PRSVD3      0x38   /* Reserved                     */
+#define TUL_PINTL       0x3C   /* Interrupt line               */
+#define TUL_PINTP       0x3D   /* Interrupt pin                */
+#define TUL_PIGNT       0x3E   /* MIN_GNT                      */
+#define TUL_PMGNT       0x3F   /* MAX_GNT                      */
+
+/************************/
+/*  Jasmin Register Set */
+/************************/
+#define TUL_HACFG0      0x40   /* H/A Configuration Register 0         */
+#define TUL_HACFG1      0x41   /* H/A Configuration Register 1         */
+#define TUL_HACFG2      0x42   /* H/A Configuration Register 2         */
+
+#define TUL_SDCFG0      0x44   /* SCSI Device Configuration 0          */
+#define TUL_SDCFG1      0x45   /* SCSI Device Configuration 1          */
+#define TUL_SDCFG2      0x46   /* SCSI Device Configuration 2          */
+#define TUL_SDCFG3      0x47   /* SCSI Device Configuration 3          */
+
+#define TUL_GINTS       0x50   /* Global Interrupt Status Register     */
+#define TUL_GIMSK       0x52   /* Global Interrupt MASK Register       */
+#define TUL_GCTRL       0x54   /* Global Control Register              */
+#define TUL_GCTRL_EEPROM_BIT    0x04
+#define TUL_GCTRL1      0x55   /* Global Control Register              */
+#define TUL_DMACFG      0x5B   /* DMA configuration                    */
+#define TUL_NVRAM       0x5D   /* Non-volatile RAM port                */
+
+#define TUL_SCnt0       0x80   /* 00 R/W Transfer Counter Low          */
+#define TUL_SCnt1       0x81   /* 01 R/W Transfer Counter Mid          */
+#define TUL_SCnt2       0x82   /* 02 R/W Transfer Count High           */
+#define TUL_SFifoCnt    0x83   /* 03 R   FIFO counter                  */
+#define TUL_SIntEnable  0x84   /* 03 W   Interrupt enble               */
+#define TUL_SInt        0x84   /* 04 R   Interrupt Register            */
+#define TUL_SCtrl0      0x85   /* 05 W   Control 0                     */
+#define TUL_SStatus0    0x85   /* 05 R   Status 0                      */
+#define TUL_SCtrl1      0x86   /* 06 W   Control 1                     */
+#define TUL_SStatus1    0x86   /* 06 R   Status 1                      */
+#define TUL_SConfig     0x87   /* 07 W   Configuration                 */
+#define TUL_SStatus2    0x87   /* 07 R   Status 2                      */
+#define TUL_SPeriod     0x88   /* 08 W   Sync. Transfer Period & Offset */
+#define TUL_SOffset     0x88   /* 08 R   Offset                        */
+#define TUL_SScsiId     0x89   /* 09 W   SCSI ID                       */
+#define TUL_SBusId      0x89   /* 09 R   SCSI BUS ID                   */
+#define TUL_STimeOut    0x8A   /* 0A W   Sel/Resel Time Out Register   */
+#define TUL_SIdent      0x8A   /* 0A R   Identify Message Register     */
+#define TUL_SAvail      0x8A   /* 0A R   Availiable Counter Register   */
+#define TUL_SData       0x8B   /* 0B R/W SCSI data in/out              */
+#define TUL_SFifo       0x8C   /* 0C R/W FIFO                          */
+#define TUL_SSignal     0x90   /* 10 R/W SCSI signal in/out            */
+#define TUL_SCmd        0x91   /* 11 R/W Command                       */
+#define TUL_STest0      0x92   /* 12 R/W Test0                         */
+#define TUL_STest1      0x93   /* 13 R/W Test1                         */
+#define TUL_SCFG1      0x94    /* 14 R/W Configuration                 */
+
+#define TUL_XAddH       0xC0   /*DMA Transfer Physical Address         */
+#define TUL_XAddW       0xC8   /*DMA Current Transfer Physical Address */
+#define TUL_XCntH       0xD0   /*DMA Transfer Counter                  */
+#define TUL_XCntW       0xD4   /*DMA Current Transfer Counter          */
+#define TUL_XCmd        0xD8   /*DMA Command Register                  */
+#define TUL_Int         0xDC   /*Interrupt Register                    */
+#define TUL_XStatus     0xDD   /*DMA status Register                   */
+#define TUL_Mask        0xE0   /*Interrupt Mask Register               */
+#define TUL_XCtrl       0xE4   /*DMA Control Register                  */
+#define TUL_XCtrl1      0xE5   /*DMA Control Register 1                */
+#define TUL_XFifo       0xE8   /*DMA FIFO                              */
+
+#define TUL_WCtrl       0xF7   /*Bus master wait state control         */
+#define TUL_DCtrl       0xFB   /*DMA delay control                     */
+
+/*----------------------------------------------------------------------*/
+/*   bit definition for Command register of Configuration Space Header  */
+/*----------------------------------------------------------------------*/
+#define BUSMS           0x04   /* BUS MASTER Enable                    */
+#define IOSPA           0x01   /* IO Space Enable                      */
+
+/*----------------------------------------------------------------------*/
+/* Command Codes of Tulip SCSI Command register                         */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_RESEL    0x80   /* Enable Reselection                   */
+#define TSC_CMD_COMP    0x84   /* Command Complete Sequence            */
+#define TSC_SEL         0x01   /* Select Without ATN Sequence          */
+#define TSC_SEL_ATN     0x11   /* Select With ATN Sequence             */
+#define TSC_SEL_ATN_DMA 0x51   /* Select With ATN Sequence with DMA    */
+#define TSC_SEL_ATN3    0x31   /* Select With ATN3 Sequence            */
+#define TSC_SEL_ATNSTOP 0x12   /* Select With ATN and Stop Sequence    */
+#define TSC_SELATNSTOP  0x1E   /* Select With ATN and Stop Sequence    */
+
+#define TSC_SEL_ATN_DIRECT_IN   0x95   /* Select With ATN Sequence     */
+#define TSC_SEL_ATN_DIRECT_OUT  0x15   /* Select With ATN Sequence     */
+#define TSC_SEL_ATN3_DIRECT_IN  0xB5   /* Select With ATN3 Sequence    */
+#define TSC_SEL_ATN3_DIRECT_OUT 0x35   /* Select With ATN3 Sequence    */
+#define TSC_XF_DMA_OUT_DIRECT   0x06   /* DMA Xfer Infomation out      */
+#define TSC_XF_DMA_IN_DIRECT    0x86   /* DMA Xfer Infomation in       */
+
+#define TSC_XF_DMA_OUT  0x43   /* DMA Xfer Infomation out              */
+#define TSC_XF_DMA_IN   0xC3   /* DMA Xfer Infomation in               */
+#define TSC_XF_FIFO_OUT 0x03   /* FIFO Xfer Infomation out             */
+#define TSC_XF_FIFO_IN  0x83   /* FIFO Xfer Infomation in              */
+
+#define TSC_MSG_ACCEPT  0x0F   /* Message Accept                       */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Control 0 Register                     */
+/*----------------------------------------------------------------------*/
+#define TSC_RST_SEQ     0x20   /* Reset sequence counter               */
+#define TSC_FLUSH_FIFO  0x10   /* Flush FIFO                           */
+#define TSC_ABT_CMD     0x04   /* Abort command (sequence)             */
+#define TSC_RST_CHIP    0x02   /* Reset SCSI Chip                      */
+#define TSC_RST_BUS     0x01   /* Reset SCSI Bus                       */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Control 1 Register                     */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_SCAM     0x80   /* Enable SCAM                          */
+#define TSC_TIMER       0x40   /* Select timeout unit                  */
+#define TSC_EN_SCSI2    0x20   /* SCSI-2 mode                          */
+#define TSC_PWDN        0x10   /* Power down mode                      */
+#define TSC_WIDE_CPU    0x08   /* Wide CPU                             */
+#define TSC_HW_RESELECT 0x04   /* Enable HW reselect                   */
+#define TSC_EN_BUS_OUT  0x02   /* Enable SCSI data bus out latch       */
+#define TSC_EN_BUS_IN   0x01   /* Enable SCSI data bus in latch        */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Configuration Register                 */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_LATCH    0x80   /* Enable phase latch                   */
+#define TSC_INITIATOR   0x40   /* Initiator mode                       */
+#define TSC_EN_SCSI_PAR 0x20   /* Enable SCSI parity                   */
+#define TSC_DMA_8BIT    0x10   /* Alternate dma 8-bits mode            */
+#define TSC_DMA_16BIT   0x08   /* Alternate dma 16-bits mode           */
+#define TSC_EN_WDACK    0x04   /* Enable DACK while wide SCSI xfer     */
+#define TSC_ALT_PERIOD  0x02   /* Alternate sync period mode           */
+#define TSC_DIS_SCSIRST 0x01   /* Disable SCSI bus reset us            */
+
+#define TSC_INITDEFAULT (TSC_INITIATOR | TSC_EN_LATCH | TSC_ALT_PERIOD | TSC_DIS_SCSIRST)
+
+#define TSC_WIDE_SCSI   0x80   /* Enable Wide SCSI                     */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI signal Register                        */
+/*----------------------------------------------------------------------*/
+#define TSC_RST_ACK     0x00   /* Release ACK signal                   */
+#define TSC_RST_ATN     0x00   /* Release ATN signal                   */
+#define TSC_RST_BSY     0x00   /* Release BSY signal                   */
+
+#define TSC_SET_ACK     0x40   /* ACK signal                           */
+#define TSC_SET_ATN     0x08   /* ATN signal                           */
+
+#define TSC_REQI        0x80   /* REQ signal                           */
+#define TSC_ACKI        0x40   /* ACK signal                           */
+#define TSC_BSYI        0x20   /* BSY signal                           */
+#define TSC_SELI        0x10   /* SEL signal                           */
+#define TSC_ATNI        0x08   /* ATN signal                           */
+#define TSC_MSGI        0x04   /* MSG signal                           */
+#define TSC_CDI         0x02   /* C/D signal                           */
+#define TSC_IOI         0x01   /* I/O signal                           */
+
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 0 Register                      */
+/*----------------------------------------------------------------------*/
+#define TSS_INT_PENDING 0x80   /* Interrupt pending            */
+#define TSS_SEQ_ACTIVE  0x40   /* Sequencer active             */
+#define TSS_XFER_CNT    0x20   /* Transfer counter zero        */
+#define TSS_FIFO_EMPTY  0x10   /* FIFO empty                   */
+#define TSS_PAR_ERROR   0x08   /* SCSI parity error            */
+#define TSS_PH_MASK     0x07   /* SCSI phase mask              */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 1 Register                      */
+/*----------------------------------------------------------------------*/
+#define TSS_STATUS_RCV  0x08   /* Status received              */
+#define TSS_MSG_SEND    0x40   /* Message sent                 */
+#define TSS_CMD_PH_CMP  0x20   /* command phase done              */
+#define TSS_DATA_PH_CMP 0x10   /* Data phase done              */
+#define TSS_STATUS_SEND 0x08   /* Status sent                  */
+#define TSS_XFER_CMP    0x04   /* Transfer completed           */
+#define TSS_SEL_CMP     0x02   /* Selection completed          */
+#define TSS_ARB_CMP     0x01   /* Arbitration completed        */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 2 Register                      */
+/*----------------------------------------------------------------------*/
+#define TSS_CMD_ABTED   0x80   /* Command aborted              */
+#define TSS_OFFSET_0    0x40   /* Offset counter zero          */
+#define TSS_FIFO_FULL   0x20   /* FIFO full                    */
+#define TSS_TIMEOUT_0   0x10   /* Timeout counter zero         */
+#define TSS_BUSY_RLS    0x08   /* Busy release                 */
+#define TSS_PH_MISMATCH 0x04   /* Phase mismatch               */
+#define TSS_SCSI_BUS_EN 0x02   /* SCSI data bus enable         */
+#define TSS_SCSIRST     0x01   /* SCSI bus reset in progress   */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Interrupt Register                     */
+/*----------------------------------------------------------------------*/
+#define TSS_RESEL_INT   0x80   /* Reselected interrupt         */
+#define TSS_SEL_TIMEOUT 0x40   /* Selected/reselected timeout  */
+#define TSS_BUS_SERV    0x20
+#define TSS_SCSIRST_INT 0x10   /* SCSI bus reset detected      */
+#define TSS_DISC_INT    0x08   /* Disconnected interrupt       */
+#define TSS_SEL_INT     0x04   /* Select interrupt             */
+#define TSS_SCAM_SEL    0x02   /* SCAM selected                */
+#define TSS_FUNC_COMP   0x01
+
+/*----------------------------------------------------------------------*/
+/* SCSI Phase Codes.                                                    */
+/*----------------------------------------------------------------------*/
+#define DATA_OUT        0
+#define DATA_IN         1      /* 4                            */
+#define CMD_OUT         2
+#define STATUS_IN       3      /* 6                            */
+#define MSG_OUT         6      /* 3                            */
+#define MSG_IN          7
+
+
+
+/*----------------------------------------------------------------------*/
+/* Command Codes of Tulip xfer Command register                         */
+/*----------------------------------------------------------------------*/
+#define TAX_X_FORC      0x02
+#define TAX_X_ABT       0x04
+#define TAX_X_CLR_FIFO  0x08
+
+#define TAX_X_IN        0x21
+#define TAX_X_OUT       0x01
+#define TAX_SG_IN       0xA1
+#define TAX_SG_OUT      0x81
+
+/*----------------------------------------------------------------------*/
+/* Tulip Interrupt Register                                             */
+/*----------------------------------------------------------------------*/
+#define XCMP            0x01
+#define FCMP            0x02
+#define XABT            0x04
+#define XERR            0x08
+#define SCMP            0x10
+#define IPEND           0x80
+
+/*----------------------------------------------------------------------*/
+/* Tulip DMA Status Register                                            */
+/*----------------------------------------------------------------------*/
+#define XPEND           0x01   /* Transfer pending             */
+#define FEMPTY          0x02   /* FIFO empty                   */
+
+
+
+/*----------------------------------------------------------------------*/
+/* bit definition for TUL_GCTRL                                         */
+/*----------------------------------------------------------------------*/
+#define EXTSG           0x80
+#define EXTAD           0x60
+#define SEG4K           0x08
+#define EEPRG           0x04
+#define MRMUL           0x02
+
+/*----------------------------------------------------------------------*/
+/* bit definition for TUL_NVRAM                                         */
+/*----------------------------------------------------------------------*/
+#define SE2CS           0x08
+#define SE2CLK          0x04
+#define SE2DO           0x02
+#define SE2DI           0x01
+
+
+/************************************************************************/
+/*              Scatter-Gather Element Structure                        */
+/************************************************************************/
+typedef struct SG_Struc {
+       U32 SG_Ptr;             /* Data Pointer */
+       U32 SG_Len;             /* Data Length */
+} SG;
+
+/***********************************************************************
+               SCSI Control Block
+************************************************************************/
+typedef struct Scsi_Ctrl_Blk {
+       struct Scsi_Ctrl_Blk *SCB_NxtScb;
+       UBYTE SCB_Status;       /*4 */
+       UBYTE SCB_NxtStat;      /*5 */
+       UBYTE SCB_Mode;         /*6 */
+       UBYTE SCB_Msgin;        /*7 SCB_Res0 */
+       UWORD SCB_SGIdx;        /*8 */
+       UWORD SCB_SGMax;        /*A */
+#ifdef ALPHA
+       U32 SCB_Reserved[2];    /*C */
+#else
+       U32 SCB_Reserved[3];    /*C */
+#endif
+
+       U32 SCB_XferLen;        /*18 Current xfer len           */
+       U32 SCB_TotXLen;        /*1C Total xfer len             */
+       U32 SCB_PAddr;          /*20 SCB phy. Addr. */
+
+       UBYTE SCB_Opcode;       /*24 SCB command code */
+       UBYTE SCB_Flags;        /*25 SCB Flags */
+       UBYTE SCB_Target;       /*26 Target Id */
+       UBYTE SCB_Lun;          /*27 Lun */
+       U32 SCB_BufPtr;         /*28 Data Buffer Pointer */
+       U32 SCB_BufLen;         /*2C Data Allocation Length */
+       UBYTE SCB_SGLen;        /*30 SG list # */
+       UBYTE SCB_SenseLen;     /*31 Sense Allocation Length */
+       UBYTE SCB_HaStat;       /*32 */
+       UBYTE SCB_TaStat;       /*33 */
+       UBYTE SCB_CDBLen;       /*34 CDB Length */
+       UBYTE SCB_Ident;        /*35 Identify */
+       UBYTE SCB_TagMsg;       /*36 Tag Message */
+       UBYTE SCB_TagId;        /*37 Queue Tag */
+       UBYTE SCB_CDB[12];      /*38 */
+       U32 SCB_SGPAddr;        /*44 SG List/Sense Buf phy. Addr. */
+       U32 SCB_SensePtr;       /*48 Sense data pointer */
+       void (*SCB_Post) (BYTE *, BYTE *);      /*4C POST routine */
+       unsigned char *SCB_Srb; /*50 SRB Pointer */
+       SG SCB_SGList[TOTAL_SG_ENTRY];  /*54 Start of SG list */
+} SCB;
+
+/* Bit Definition for SCB_Status */
+#define SCB_RENT        0x01
+#define SCB_PEND        0x02
+#define SCB_CONTIG      0x04   /* Contigent Allegiance */
+#define SCB_SELECT      0x08
+#define SCB_BUSY        0x10
+#define SCB_DONE        0x20
+
+
+/* Opcodes of SCB_Opcode */
+#define ExecSCSI        0x1
+#define BusDevRst       0x2
+#define AbortCmd        0x3
+
+
+/* Bit Definition for SCB_Mode */
+#define SCM_RSENS       0x01   /* request sense mode */
+
+
+/* Bit Definition for SCB_Flags */
+#define SCF_DONE        0x01
+#define SCF_POST        0x02
+#define SCF_SENSE       0x04
+#define SCF_DIR         0x18
+#define SCF_NO_DCHK     0x00
+#define SCF_DIN         0x08
+#define SCF_DOUT        0x10
+#define SCF_NO_XF       0x18
+#define SCF_WR_VF       0x20   /* Write verify turn on         */
+#define SCF_POLL        0x40
+#define SCF_SG          0x80
+
+/* Error Codes for SCB_HaStat */
+#define HOST_SEL_TOUT   0x11
+#define HOST_DO_DU      0x12
+#define HOST_BUS_FREE   0x13
+#define HOST_BAD_PHAS   0x14
+#define HOST_INV_CMD    0x16
+#define HOST_ABORTED    0x1A   /* 07/21/98 */
+#define HOST_SCSI_RST   0x1B
+#define HOST_DEV_RST    0x1C
+
+/* Error Codes for SCB_TaStat */
+#define TARGET_CHKCOND  0x02
+#define TARGET_BUSY     0x08
+#define QUEUE_FULL     0x28
+
+/* SCSI MESSAGE */
+#define MSG_COMP        0x00
+#define MSG_EXTEND      0x01
+#define MSG_SDP         0x02
+#define MSG_RESTORE     0x03
+#define MSG_DISC        0x04
+#define MSG_IDE         0x05
+#define MSG_ABORT       0x06
+#define MSG_REJ         0x07
+#define MSG_NOP         0x08
+#define MSG_PARITY      0x09
+#define MSG_LINK_COMP   0x0A
+#define MSG_LINK_FLAG   0x0B
+#define MSG_DEVRST      0x0C
+#define MSG_ABORT_TAG   0x0D
+
+/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */
+#define MSG_STAG        0x20
+#define MSG_HTAG        0x21
+#define MSG_OTAG        0x22
+
+#define MSG_IGNOREWIDE  0x23
+
+#define MSG_IDENT   0x80
+
+/***********************************************************************
+               Target Device Control Structure
+**********************************************************************/
+
+typedef struct Tar_Ctrl_Struc {
+       UWORD TCS_Flags;        /* 0 */
+       UBYTE TCS_JS_Period;    /* 2 */
+       UBYTE TCS_SConfig0;     /* 3 */
+
+       UWORD TCS_DrvFlags;     /* 4 */
+       UBYTE TCS_DrvHead;      /* 6 */
+       UBYTE TCS_DrvSector;    /* 7 */
+} TCS;
+
+/***********************************************************************
+               Target Device Control Structure
+**********************************************************************/
+
+/* Bit Definition for TCF_Flags */
+#define TCF_SCSI_RATE           0x0007
+#define TCF_EN_DISC             0x0008
+#define TCF_NO_SYNC_NEGO        0x0010
+#define TCF_NO_WDTR             0x0020
+#define TCF_EN_255              0x0040
+#define TCF_EN_START            0x0080
+#define TCF_WDTR_DONE           0x0100
+#define TCF_SYNC_DONE           0x0200
+#define TCF_BUSY                0x0400
+
+
+/* Bit Definition for TCF_DrvFlags */
+#define TCF_DRV_BUSY            0x01   /* Indicate target busy(driver) */
+#define TCF_DRV_EN_TAG          0x0800
+#define TCF_DRV_255_63          0x0400
+
+typedef struct I91u_Adpt_Struc {
+       UWORD ADPT_BIOS;        /* 0 */
+       UWORD ADPT_BASE;        /* 1 */
+       UBYTE ADPT_Bus;         /* 2 */
+       UBYTE ADPT_Device;      /* 3 */
+       UBYTE ADPT_INTR;        /* 4 */
+} INI_ADPT_STRUCT;
+
+
+/***********************************************************************
+             Host Adapter Control Structure
+************************************************************************/
+typedef struct Ha_Ctrl_Struc {
+       UWORD HCS_Base;         /* 00 */
+       UWORD HCS_BIOS;         /* 02 */
+       UBYTE HCS_Intr;         /* 04 */
+       UBYTE HCS_SCSI_ID;      /* 05 */
+       UBYTE HCS_MaxTar;       /* 06 */
+       UBYTE HCS_NumScbs;      /* 07 */
+
+       UBYTE HCS_Flags;        /* 08 */
+       UBYTE HCS_Index;        /* 09 */
+       UBYTE HCS_HaId;         /* 0A */
+       UBYTE HCS_Config;       /* 0B */
+       UWORD HCS_IdMask;       /* 0C */
+       UBYTE HCS_Semaph;       /* 0E */
+       UBYTE HCS_Phase;        /* 0F */
+       UBYTE HCS_JSStatus0;    /* 10 */
+       UBYTE HCS_JSInt;        /* 11 */
+       UBYTE HCS_JSStatus1;    /* 12 */
+       UBYTE HCS_SConf1;       /* 13 */
+
+       UBYTE HCS_Msg[8];       /* 14 */
+       SCB *HCS_NxtAvail;      /* 1C */
+       SCB *HCS_Scb;           /* 20 */
+       SCB *HCS_ScbEnd;        /* 24 */
+       SCB *HCS_NxtPend;       /* 28 */
+       SCB *HCS_NxtContig;     /* 2C */
+       SCB *HCS_ActScb;        /* 30 */
+       TCS *HCS_ActTcs;        /* 34 */
+
+       SCB *HCS_FirstAvail;    /* 38 */
+       SCB *HCS_LastAvail;     /* 3C */
+       SCB *HCS_FirstPend;     /* 40 */
+       SCB *HCS_LastPend;      /* 44 */
+       SCB *HCS_FirstBusy;     /* 48 */
+       SCB *HCS_LastBusy;      /* 4C */
+       SCB *HCS_FirstDone;     /* 50 */
+       SCB *HCS_LastDone;      /* 54 */
+       UBYTE HCS_MaxTags[16];  /* 58 */
+       UBYTE HCS_ActTags[16];  /* 68 */
+       TCS HCS_Tcs[MAX_TARGETS];       /* 78 */
+       ULONG pSRB_head;        /* SRB save queue header     */
+       ULONG pSRB_tail;        /* SRB save queue tail       */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spinlock_t HCS_AvailLock;
+       spinlock_t HCS_SemaphLock;
+       spinlock_t pSRB_lock;   /* SRB queue lock            */
+#endif
+} HCS;
+
+/* Bit Definition for HCB_Config */
+#define HCC_SCSI_RESET          0x01
+#define HCC_EN_PAR              0x02
+#define HCC_ACT_TERM1           0x04
+#define HCC_ACT_TERM2           0x08
+#define HCC_AUTO_TERM           0x10
+#define HCC_EN_PWR              0x80
+
+/* Bit Definition for HCB_Flags */
+#define HCF_EXPECT_DISC         0x01
+#define HCF_EXPECT_SELECT       0x02
+#define HCF_EXPECT_RESET        0x10
+#define HCF_EXPECT_DONE_DISC    0x20
+
+/******************************************************************
+       Serial EEProm
+*******************************************************************/
+
+typedef struct _NVRAM_SCSI {   /* SCSI channel configuration   */
+       UCHAR NVM_ChSCSIID;     /* 0Ch -> Channel SCSI ID       */
+       UCHAR NVM_ChConfig1;    /* 0Dh -> Channel config 1      */
+       UCHAR NVM_ChConfig2;    /* 0Eh -> Channel config 2      */
+       UCHAR NVM_NumOfTarg;    /* 0Fh -> Number of SCSI target */
+       /* SCSI target configuration    */
+       UCHAR NVM_Targ0Config;  /* 10h -> Target 0 configuration */
+       UCHAR NVM_Targ1Config;  /* 11h -> Target 1 configuration */
+       UCHAR NVM_Targ2Config;  /* 12h -> Target 2 configuration */
+       UCHAR NVM_Targ3Config;  /* 13h -> Target 3 configuration */
+       UCHAR NVM_Targ4Config;  /* 14h -> Target 4 configuration */
+       UCHAR NVM_Targ5Config;  /* 15h -> Target 5 configuration */
+       UCHAR NVM_Targ6Config;  /* 16h -> Target 6 configuration */
+       UCHAR NVM_Targ7Config;  /* 17h -> Target 7 configuration */
+       UCHAR NVM_Targ8Config;  /* 18h -> Target 8 configuration */
+       UCHAR NVM_Targ9Config;  /* 19h -> Target 9 configuration */
+       UCHAR NVM_TargAConfig;  /* 1Ah -> Target A configuration */
+       UCHAR NVM_TargBConfig;  /* 1Bh -> Target B configuration */
+       UCHAR NVM_TargCConfig;  /* 1Ch -> Target C configuration */
+       UCHAR NVM_TargDConfig;  /* 1Dh -> Target D configuration */
+       UCHAR NVM_TargEConfig;  /* 1Eh -> Target E configuration */
+       UCHAR NVM_TargFConfig;  /* 1Fh -> Target F configuration */
+} NVRAM_SCSI;
+
+typedef struct _NVRAM {
+/*----------header ---------------*/
+       USHORT NVM_Signature;   /* 0,1: Signature */
+       UCHAR NVM_Size;         /* 2:   Size of data structure */
+       UCHAR NVM_Revision;     /* 3:   Revision of data structure */
+       /* ----Host Adapter Structure ---- */
+       UCHAR NVM_ModelByte0;   /* 4:   Model number (byte 0) */
+       UCHAR NVM_ModelByte1;   /* 5:   Model number (byte 1) */
+       UCHAR NVM_ModelInfo;    /* 6:   Model information         */
+       UCHAR NVM_NumOfCh;      /* 7:   Number of SCSI channel */
+       UCHAR NVM_BIOSConfig1;  /* 8:   BIOS configuration 1  */
+       UCHAR NVM_BIOSConfig2;  /* 9:   BIOS configuration 2  */
+       UCHAR NVM_HAConfig1;    /* A:   Hoat adapter configuration 1 */
+       UCHAR NVM_HAConfig2;    /* B:   Hoat adapter configuration 2 */
+       NVRAM_SCSI NVM_SCSIInfo[2];
+       UCHAR NVM_reserved[10];
+       /* ---------- CheckSum ----------       */
+       USHORT NVM_CheckSum;    /* 0x3E, 0x3F: Checksum of NVRam        */
+} NVRAM, *PNVRAM;
+
+/* Bios Configuration for nvram->BIOSConfig1                            */
+#define NBC1_ENABLE             0x01   /* BIOS enable                  */
+#define NBC1_8DRIVE             0x02   /* Support more than 2 drives   */
+#define NBC1_REMOVABLE          0x04   /* Support removable drive      */
+#define NBC1_INT19              0x08   /* Intercept int 19h            */
+#define NBC1_BIOSSCAN           0x10   /* Dynamic BIOS scan            */
+#define NBC1_LUNSUPPORT         0x40   /* Support LUN                  */
+
+/* HA Configuration Byte 1                                              */
+#define NHC1_BOOTIDMASK 0x0F   /* Boot ID number               */
+#define NHC1_LUNMASK    0x70   /* Boot LUN number              */
+#define NHC1_CHANMASK   0x80   /* Boot Channel number          */
+
+/* Bit definition for nvram->SCSIconfig1                                */
+#define NCC1_BUSRESET           0x01   /* Reset SCSI bus at power up   */
+#define NCC1_PARITYCHK          0x02   /* SCSI parity enable           */
+#define NCC1_ACTTERM1           0x04   /* Enable active terminator 1   */
+#define NCC1_ACTTERM2           0x08   /* Enable active terminator 2   */
+#define NCC1_AUTOTERM           0x10   /* Enable auto terminator       */
+#define NCC1_PWRMGR             0x80   /* Enable power management      */
+
+/* Bit definition for SCSI Target configuration byte                    */
+#define NTC_DISCONNECT          0x08   /* Enable SCSI disconnect       */
+#define NTC_SYNC                0x10   /* SYNC_NEGO                    */
+#define NTC_NO_WDTR             0x20   /* SYNC_NEGO                    */
+#define NTC_1GIGA               0x40   /* 255 head / 63 sectors (64/32) */
+#define NTC_SPINUP              0x80   /* Start disk drive             */
+
+/*      Default NVRam values                                            */
+#define INI_SIGNATURE           0xC925
+#define NBC1_DEFAULT            (NBC1_ENABLE)
+#define NCC1_DEFAULT            (NCC1_BUSRESET | NCC1_AUTOTERM | NCC1_PARITYCHK)
+#define NTC_DEFAULT             (NTC_NO_WDTR | NTC_1GIGA | NTC_DISCONNECT)
+
+/* SCSI related definition                                              */
+#define DISC_NOT_ALLOW          0x80   /* Disconnect is not allowed    */
+#define DISC_ALLOW              0xC0   /* Disconnect is allowed        */
+#define SCSICMD_RequestSense    0x03
+
+
+/*----------------------------------------------------------------------*/
+/*                              PCI                                     */
+/*----------------------------------------------------------------------*/
+#define PCI_FUNCTION_ID         0xB1
+#define PCI_BIOS_PRESENT        0x01
+#define FIND_PCI_DEVICE         0x02
+#define FIND_PCI_CLASS_CODE     0x03
+#define GENERATE_SPECIAL_CYCLE  0x06
+#define READ_CONFIG_BYTE        0x08
+#define READ_CONFIG_WORD        0x09
+#define READ_CONFIG_DWORD       0x0A
+#define WRITE_CONFIG_BYTE       0x0B
+#define WRITE_CONFIG_WORD       0x0C
+#define WRITE_CONFIG_DWORD      0x0D
+
+#define SUCCESSFUL              0x00
+#define FUNC_NOT_SUPPORTED      0x81
+#define BAD_VENDOR_ID           0x83   /* Bad vendor ID                */
+#define DEVICE_NOT_FOUND        0x86   /* PCI device not found         */
+#define BAD_REGISTER_NUMBER     0x87
+
+#define MAX_PCI_DEVICES         21     /* Maximum devices supportted   */
+
+#define MAX_PCI_CHANL           4
+
+typedef struct _BIOS32_ENTRY_STRUCTURE {
+       DWORD Signatures;       /* Should be "_32_"             */
+       DWORD BIOS32Entry;      /* 32-bit physical address      */
+       BYTE Revision;          /* Revision level, should be 0  */
+       BYTE Length;            /* Multiply of 16, should be 1  */
+       BYTE CheckSum;          /* Checksum of whole structure  */
+       BYTE Reserved[5];       /* Reserved                     */
+} BIOS32_ENTRY_STRUCTURE, *PBIOS32_ENTRY_STRUCTURE;
+
+typedef struct {
+       union {
+               unsigned int eax;
+               struct {
+                       unsigned short ax;
+               } word;
+               struct {
+                       unsigned char al;
+                       unsigned char ah;
+               } byte;
+       } eax;
+       union {
+               unsigned int ebx;
+               struct {
+                       unsigned short bx;
+               } word;
+               struct {
+                       unsigned char bl;
+                       unsigned char bh;
+               } byte;
+       } ebx;
+       union {
+               unsigned int ecx;
+               struct {
+                       unsigned short cx;
+               } word;
+               struct {
+                       unsigned char cl;
+                       unsigned char ch;
+               } byte;
+       } ecx;
+       union {
+               unsigned int edx;
+               struct {
+                       unsigned short dx;
+               } word;
+               struct {
+                       unsigned char dl;
+                       unsigned char dh;
+               } byte;
+       } edx;
+       union {
+               unsigned int edi;
+               struct {
+                       unsigned short di;
+               } word;
+       } edi;
+       union {
+               unsigned int esi;
+               struct {
+                       unsigned short si;
+               } word;
+       } esi;
+} REGS;
+
+typedef union {                        /* Union define for mechanism 1 */
+       struct {
+               unsigned char RegNum;
+               unsigned char FcnNum:3;
+               unsigned char DeviceNum:5;
+               unsigned char BusNum;
+               unsigned char Reserved:7;
+               unsigned char Enable:1;
+       } sConfigAdr;
+       unsigned long lConfigAdr;
+} CONFIG_ADR;
+
+typedef union {                        /* Union define for mechanism 2 */
+       struct {
+               unsigned char RegNum;
+               unsigned char DeviceNum;
+               unsigned short Reserved;
+       } sHostAdr;
+       unsigned long lHostAdr;
+} HOST_ADR;
+
+typedef struct _HCSinfo {
+       ULONG base;
+       UCHAR vec;
+       UCHAR bios;             /* High byte of BIOS address */
+       USHORT BaseAndBios;     /* high byte: pHcsInfo->bios,low byte:pHcsInfo->base */
+} HCSINFO;
+
+#define TUL_RD(x,y)             (UCHAR)(inb(  (int)((ULONG)(x+y)) ))
+#define TUL_RDLONG(x,y)         (ULONG)(inl((int)((ULONG)(x+y)) ))
+#define TUL_WR(     adr,data)   outb( (UCHAR)(data), (int)(adr))
+#define TUL_WRSHORT(adr,data)   outw( (UWORD)(data), (int)(adr))
+#define TUL_WRLONG( adr,data)   outl( (ULONG)(data), (int)(adr))
+
+#define SCSI_ABORT_SNOOZE 0
+#define SCSI_ABORT_SUCCESS 1
+#define SCSI_ABORT_PENDING 2
+#define SCSI_ABORT_BUSY 3
+#define SCSI_ABORT_NOT_RUNNING 4
+#define SCSI_ABORT_ERROR 5
+
+#define SCSI_RESET_SNOOZE 0
+#define SCSI_RESET_PUNT 1
+#define SCSI_RESET_SUCCESS 2
+#define SCSI_RESET_PENDING 3
+#define SCSI_RESET_WAKEUP 4
+#define SCSI_RESET_NOT_RUNNING 5
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS         0x01
+#define SCSI_RESET_ASYNCHRONOUS                0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET   0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET  0x08
+
+#define SCSI_RESET_BUS_RESET 0x100
+#define SCSI_RESET_HOST_RESET 0x200
+#define SCSI_RESET_ACTION   0xff
diff --git a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c
new file mode 100644 (file)
index 0000000..d3c6d2a
--- /dev/null
@@ -0,0 +1,1169 @@
+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * Copyright (c) 1998 Bas Vermeulen <bvermeul@blackstar.xs4all.nl>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This is the Linux low-level SCSI driver for Initio INI-9X00U/UW SCSI host
+ * adapters
+ *
+ * 08/06/97 hc - v1.01h
+ *             - Support inic-940 and inic-935
+ * 09/26/97 hc - v1.01i
+ *             - Make correction from J.W. Schultz suggestion
+ * 10/13/97 hc - Support reset function
+ * 10/21/97 hc - v1.01j
+ *             - Support 32 LUN (SCSI 3)
+ * 01/14/98 hc - v1.01k
+ *             - Fix memory allocation problem
+ * 03/04/98 hc - v1.01l
+ *             - Fix tape rewind which will hang the system problem
+ *             - Set can_queue to tul_num_scb
+ * 06/25/98 hc - v1.01m
+ *             - Get it work for kernel version >= 2.1.75
+ *             - Dynamic assign SCSI bus reset holding time in init_tulip()
+ * 07/02/98 hc - v1.01n
+ *             - Support 0002134A
+ * 08/07/98 hc  - v1.01o
+ *             - Change the tul_abort_srb routine to use scsi_done. <01>
+ * 09/07/98 hl  - v1.02
+ *              - Change the INI9100U define and proc_dir_entry to
+ *                reflect the newer Kernel 2.1.118, but the v1.o1o
+ *                should work with Kernel 2.1.118.
+ * 09/20/98 wh  - v1.02a
+ *              - Support Abort command.
+ *              - Handle reset routine.
+ * 09/21/98 hl  - v1.03
+ *              - remove comments.
+ * 12/09/98 bv - v1.03a
+ *             - Removed unused code
+ * 12/13/98 bv - v1.03b
+ *             - Remove cli() locking for kernels >= 2.1.95. This uses
+ *               spinlocks to serialize access to the pSRB_head and
+ *               pSRB_tail members of the HCS structure.
+ **************************************************************************/
+
+#define CVT_LINUX_VERSION(V,P,S)        (V * 65536 + P * 256 + S)
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+#include <stdarg.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
+#include <linux/bios32.h>
+#endif
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
+#include <linux/init.h>
+#endif
+#include <linux/blk.h>
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "ini9100u.h"
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
+#else
+
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "sd.h"
+#include "hosts.h"
+#include <linux/malloc.h>
+#include "ini9100u.h"
+#endif
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93)
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+#endif
+
+#ifdef DEBUG_i91u
+unsigned int i91u_debug = DEBUG_DEFAULT;
+#endif
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = INI9100U;
+#include "scsi_module.c"
+#endif
+
+char *i91uCopyright = "Copyright (C) 1996-98";
+char *i91uInitioName = "by Initio Corporation";
+char *i91uProductName = "INI-9X00U/UW";
+char *i91uVersion = "v1.03b";
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+struct proc_dir_entry proc_scsi_ini9100u =
+{
+       PROC_SCSI_INI9100U, 7, "INI9100U",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2,
+       0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+#endif
+
+#define TULSZ(sz)     (sizeof(sz) / sizeof(sz[0]))
+#define TUL_RDWORD(x,y)         (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+
+/* set by i91_setup according to the command line */
+static int setup_called = 0;
+
+static int tul_num_ch = 4;     /* Maximum 4 adapters           */
+static int tul_num_scb;
+static int tul_tag_enable = 1;
+static SCB *tul_scb;
+
+#ifdef DEBUG_i91u
+static int setup_debug = 0;
+#endif
+
+static char *setup_str = (char *) NULL;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr0(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr1(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr2(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr3(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr4(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr5(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr6(int irq, void *dev_id, struct pt_regs *);
+static void i91u_intr7(int irq, void *dev_id, struct pt_regs *);
+#else
+static void i91u_intr0(int irq, struct pt_regs *);
+static void i91u_intr1(int irq, struct pt_regs *);
+static void i91u_intr2(int irq, struct pt_regs *);
+static void i91u_intr3(int irq, struct pt_regs *);
+static void i91u_intr4(int irq, struct pt_regs *);
+static void i91u_intr5(int irq, struct pt_regs *);
+static void i91u_intr6(int irq, struct pt_regs *);
+static void i91u_intr7(int irq, struct pt_regs *);
+#endif
+
+static void i91u_panic(char *msg);
+
+static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
+
+                               /* ---- EXTERNAL FUNCTIONS ---- */
+                                       /* Get total number of adapters */
+extern void init_i91uAdapter_table(void);
+extern int Addi91u_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE);
+extern int tul_ReturnNumberOfAdapters(void);
+extern void get_tulipPCIConfig(HCS * pHCB, int iChannel_index);
+extern int init_tulip(HCS * pHCB, SCB * pSCB, int tul_num_scb, BYTE * pbBiosAdr, int reset_time);
+extern SCB *tul_alloc_scb(HCS * pHCB);
+extern int tul_abort_srb(HCS * pHCB, Scsi_Cmnd * pSRB);
+extern void tul_exec_scb(HCS * pHCB, SCB * pSCB);
+extern void tul_release_scb(HCS * pHCB, SCB * pSCB);
+extern void tul_stop_bm(HCS * pHCB);
+extern int tul_reset_scsi(HCS * pCurHcb, int seconds);
+extern int tul_isr(HCS * pHCB);
+extern int tul_reset(HCS * pHCB, Scsi_Cmnd * pSRB, unsigned char target);
+extern int tul_reset_scsi_bus(HCS * pCurHcb);
+extern int tul_device_reset(HCS * pCurHcb, ULONG pSrb, unsigned int target, unsigned int ResetFlags);
+                               /* ---- EXTERNAL VARIABLES ---- */
+extern HCS tul_hcs[];
+
+/*
+ *  queue services:
+ */
+/*****************************************************************************
+ Function name  : i91uAppendSRBToQueue
+ Description    : This function will push current request into save list
+ Input          : pSRB  -       Pointer to SCSI request block.
+                 pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : None.
+*****************************************************************************/
+static void i91uAppendSRBToQueue(HCS * pHCB, Scsi_Cmnd * pSRB)
+{
+       ULONG flags;
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&(pHCB->pSRB_lock), flags);
+#else
+       save_flags(flags);
+       cli();
+#endif
+
+       pSRB->next = NULL;      /* Pointer to next              */
+
+       if (pHCB->pSRB_head == NULL)
+               pHCB->pSRB_head = pSRB;
+       else
+               pHCB->pSRB_tail->next = pSRB;   /* Pointer to next              */
+       pHCB->pSRB_tail = pSRB;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);
+#else
+       restore_flags(flags);
+#endif
+       return;
+}
+
+/*****************************************************************************
+ Function name  : i91uPopSRBFromQueue
+ Description    : This function will pop current request from save list
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static Scsi_Cmnd *i91uPopSRBFromQueue(HCS * pHCB)
+{
+       Scsi_Cmnd *pSRB;
+       ULONG flags;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&(pHCB->pSRB_lock), flags);
+#else
+       save_flags(flags);
+       cli();
+#endif
+
+       if ((pSRB = pHCB->pSRB_head) != NULL) {
+               pHCB->pSRB_head = pHCB->pSRB_head->next;
+               pSRB->next = NULL;
+       }
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);
+#else
+       restore_flags(flags);
+#endif
+
+       return (pSRB);
+}
+
+/* called from init/main.c */
+
+void i91u_setup(char *str, int *ints)
+{
+       if (setup_called)
+               i91u_panic("i91u: i91u_setup called twice.\n");
+
+       setup_called = ints[0];
+       setup_str = str;
+
+#ifdef DEBUG_i91u
+       setup_debug = ints[0] >= 1 ? ints[1] : DEBUG_DEFAULT;
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93)
+int tul_NewReturnNumberOfAdapters(void)
+{
+       struct pci_dev *pDev = NULL;    /* Start from none              */
+       int iAdapters = 0;
+       long dRegValue;
+       WORD wBIOS;
+
+       init_i91uAdapter_table();
+
+       while ((pDev = pci_find_device(INI_VENDOR_ID, I950_DEVICE_ID, pDev)) != NULL) {
+               pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
+               wBIOS = (UWORD) (dRegValue & 0xFF);
+               if (((dRegValue & 0xFF00) >> 8) == 0xFF)
+                       dRegValue = 0;
+               wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
+               if (Addi91u_into_Adapter_table(wBIOS,
+                                       (pDev->base_address[0] & 0xFFFE),
+                                              pDev->irq,
+                                              pDev->bus->number,
+                                              (pDev->devfn >> 3)
+                   ) == 0)
+                       iAdapters++;
+       }
+       while ((pDev = pci_find_device(INI_VENDOR_ID, I940_DEVICE_ID, pDev)) != NULL) {
+               pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
+               wBIOS = (UWORD) (dRegValue & 0xFF);
+               if (((dRegValue & 0xFF00) >> 8) == 0xFF)
+                       dRegValue = 0;
+               wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
+               if (Addi91u_into_Adapter_table(wBIOS,
+                                       (pDev->base_address[0] & 0xFFFE),
+                                              pDev->irq,
+                                              pDev->bus->number,
+                                              (pDev->devfn >> 3)
+                   ) == 0)
+                       iAdapters++;
+       }
+       while ((pDev = pci_find_device(INI_VENDOR_ID, I935_DEVICE_ID, pDev)) != NULL) {
+               pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
+               wBIOS = (UWORD) (dRegValue & 0xFF);
+               if (((dRegValue & 0xFF00) >> 8) == 0xFF)
+                       dRegValue = 0;
+               wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
+               if (Addi91u_into_Adapter_table(wBIOS,
+                                       (pDev->base_address[0] & 0xFFFE),
+                                              pDev->irq,
+                                              pDev->bus->number,
+                                              (pDev->devfn >> 3)
+                   ) == 0)
+                       iAdapters++;
+       }
+       while ((pDev = pci_find_device(INI_VENDOR_ID, 0x0002, pDev)) != NULL) {
+               pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
+               wBIOS = (UWORD) (dRegValue & 0xFF);
+               if (((dRegValue & 0xFF00) >> 8) == 0xFF)
+                       dRegValue = 0;
+               wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
+               if (Addi91u_into_Adapter_table(wBIOS,
+                                       (pDev->base_address[0] & 0xFFFE),
+                                              pDev->irq,
+                                              pDev->bus->number,
+                                              (pDev->devfn >> 3)
+                   ) == 0)
+                       iAdapters++;
+       }
+
+       return (iAdapters);
+}
+
+#else                          /* <01> */
+
+/*****************************************************************************
+ Function name : tul_ReturnNumberOfAdapters
+ Description   : This function will scan PCI bus to get all Orchid card
+ Input         : None.
+ Output                : None.
+ Return                : SUCCESSFUL    - Successful scan
+                 ohterwise     - No drives founded
+*****************************************************************************/
+int tul_ReturnNumberOfAdapters(void)
+{
+       unsigned int i, iAdapters;
+       unsigned int dRegValue;
+       unsigned short command;
+       WORD wBIOS, wBASE;
+       BYTE bPCIBusNum, bInterrupt, bPCIDeviceNum;
+       struct {
+               unsigned short vendor_id;
+               unsigned short device_id;
+       } const i91u_pci_devices[] =
+       {
+               {INI_VENDOR_ID, I935_DEVICE_ID},
+               {INI_VENDOR_ID, I940_DEVICE_ID},
+               {INI_VENDOR_ID, I950_DEVICE_ID},
+               {INI_VENDOR_ID, I920_DEVICE_ID}
+       };
+
+
+       iAdapters = 0;
+       /*
+        * PCI-bus probe.
+        */
+       if (pcibios_present()) {
+#ifdef MMAPIO
+               unsigned long page_offset, base;
+#endif
+
+#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
+               struct pci_dev *pdev = NULL;
+#else
+               int index;
+               unsigned char pci_bus, pci_devfn;
+#endif
+
+               bPCIBusNum = 0;
+               bPCIDeviceNum = 0;
+               init_i91uAdapter_table();
+               for (i = 0; i < TULSZ(i91u_pci_devices); i++) {
+#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
+                       pdev = NULL;
+                       while ((pdev = pci_find_device(i91u_pci_devices[i].vendor_id,
+                                          i91u_pci_devices[i].device_id,
+                                                      pdev)))
+#else
+                       index = 0;
+                       while (!(pcibios_find_device(i91u_pci_devices[i].vendor_id,
+                                          i91u_pci_devices[i].device_id,
+                                        index++, &pci_bus, &pci_devfn)))
+#endif
+                       {
+                               if (i == 0) {
+                                       /*
+                                          printk("i91u: The RAID controller is not supported by\n");
+                                          printk("i91u:         this driver, we are ignoring it.\n");
+                                        */
+                               } else {
+                                       /*
+                                        * Read sundry information from PCI BIOS.
+                                        */
+#if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
+                                       bPCIBusNum = pdev->bus->number;
+                                       bPCIDeviceNum = pdev->devfn;
+                                       dRegValue = pdev->base_address[0];
+                                       if (dRegValue == -1) {  /* Check return code            */
+                                               printk("\n\ri91u: tulip read configuration error.\n");
+                                               return (0);     /* Read configuration space error  */
+                                       }
+                                       /* <02> read from base address + 0x50 offset to get the wBIOS balue. */
+                                       wBASE = (WORD) dRegValue;
+
+                                       /* Now read the interrupt line  */
+                                       dRegValue = pdev->irq;
+                                       bInterrupt = dRegValue & 0xFF;  /* Assign interrupt line      */
+                                       pci_read_config_word(pdev, PCI_COMMAND, &command);
+                                       pci_write_config_word(pdev, PCI_COMMAND,
+                                                             command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
+
+#else
+                                       bPCIBusNum = pci_bus;
+                                       bPCIDeviceNum = pci_devfn;
+                                       pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
+                                                            &dRegValue);
+                                       if (dRegValue == -1) {  /* Check return code            */
+                                               printk("\n\ri91u: tulip read configuration error.\n");
+                                               return (0);     /* Read configuration space error  */
+                                       }
+                                       /* <02> read from base address + 0x50 offset to get the wBIOS balue. */
+                                       wBASE = (WORD) dRegValue;
+
+                                       /* Now read the interrupt line  */
+                                       pcibios_read_config_dword(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
+                                                            &dRegValue);
+                                       bInterrupt = dRegValue & 0xFF;  /* Assign interrupt line      */
+                                       pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
+                                       pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND,
+                                                                 command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
+#endif
+                                       wBASE &= PCI_BASE_ADDRESS_IO_MASK;
+                                       wBIOS = TUL_RDWORD(wBASE, 0x50);
+
+#ifdef MMAPIO
+                                       base = wBASE & PAGE_MASK;
+                                       page_offset = wBASE - base;
+
+                                       /*
+                                        * replace the next line with this one if you are using 2.1.x:
+                                        * temp_p->maddr = ioremap(base, page_offset + 256);
+                                        */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,0)
+                                       wBASE = ioremap(base, page_offset + 256);
+#else
+                                       wBASE = (WORD) vremap(base, page_offset + 256);
+#endif
+                                       if (wBASE) {
+                                               wBASE += page_offset;
+                                       }
+#endif
+
+                                       if (Addi91u_into_Adapter_table(wBIOS, wBASE, bInterrupt, bPCIBusNum,
+                                                  bPCIDeviceNum) == 0x0)
+                                               iAdapters++;
+                               }
+                       }       /* while(pdev=....) */
+               }               /* for PCI_DEVICES */
+       }                       /* PCI BIOS present */
+       return (iAdapters);
+}
+#endif
+
+int i91u_detect(Scsi_Host_Template * tpnt)
+{
+       SCB *pSCB;
+       HCS *pHCB;
+       struct Scsi_Host *hreg;
+       unsigned long i;        /* 01/14/98                     */
+       int ok = 0, iAdapters;
+       ULONG dBiosAdr;
+       BYTE *pbBiosAdr;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+       tpnt->proc_dir = &proc_scsi_ini9100u;
+#endif
+
+       if (setup_called) {     /* Setup by i91u_setup          */
+               printk("i91u: processing commandline: ");
+
+#ifdef DEBUG_i91u
+               if (setup_called > 1) {
+                       printk("\ni91u: %s\n", setup_str);
+                       printk("i91u: usage: i91u[=<DEBUG>]\n");
+                       i91u_panic("i91u panics in line %d", __LINE__);
+               }
+               i91u_debug = setup_debug;
+#endif
+       }
+       /* Get total number of adapters in the motherboard */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93)
+#ifdef CONFIG_PCI
+       iAdapters = tul_NewReturnNumberOfAdapters();
+#else
+       iAdapters = tul_ReturnNumberOfAdapters();
+#endif
+#else
+       iAdapters = tul_ReturnNumberOfAdapters();
+#endif
+
+       if (iAdapters == 0)     /* If no tulip founded, return */
+               return (0);
+
+       tul_num_ch = (iAdapters > tul_num_ch) ? tul_num_ch : iAdapters;
+       /* Update actually channel number */
+       if (tul_tag_enable) {   /* 1.01i                  */
+               tul_num_scb = MAX_TARGETS * i91u_MAXQUEUE;
+       } else {
+               tul_num_scb = MAX_TARGETS + 3;  /* 1-tape, 1-CD_ROM, 1- extra */
+       }                       /* Update actually SCBs per adapter */
+
+       /* Get total memory needed for HCS */
+       i = tul_num_ch * sizeof(HCS);
+       memset((unsigned char *) &tul_hcs[0], 0, i);    /* Initialize tul_hcs 0 */
+       /* Get total memory needed for SCB */
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+       for (; tul_num_scb >= MAX_TARGETS + 3; tul_num_scb--) {
+               i = tul_num_ch * tul_num_scb * sizeof(SCB);
+               if ((tul_scb = (SCB *) kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)
+                       break;
+       }
+#else
+       i = tul_num_ch * tul_num_scb * sizeof(SCB);
+       tul_scb = (SCB *) scsi_init_malloc(i, GFP_ATOMIC | GFP_DMA);
+#endif
+       if (tul_scb == NULL) {
+               printk("i91u: SCB memory allocation error\n");
+               return (0);
+       }
+       memset((unsigned char *) tul_scb, 0, i);
+
+       pSCB = tul_scb;
+       for (i = 0; i < tul_num_ch * tul_num_scb; i++, pSCB++) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+               pSCB->SCB_SGPAddr = (U32) VIRT_TO_BUS(&pSCB->SCB_SGList[0]);
+#else
+               pSCB->SCB_SGPAddr = (U32) (&pSCB->SCB_SGList[0]);
+#endif
+       }
+
+       for (i = 0, pHCB = &tul_hcs[0];         /* Get pointer for control block */
+            i < tul_num_ch;
+            i++, pHCB++) {
+               pHCB->pSRB_head = NULL;         /* Initial SRB save queue       */
+               pHCB->pSRB_tail = NULL;         /* Initial SRB save queue       */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+               pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED;   /* SRB save queue lock */
+#endif
+               request_region(pHCB->HCS_Base, 0x100, "i91u");  /* Register */
+
+               get_tulipPCIConfig(pHCB, i);
+
+               dBiosAdr = pHCB->HCS_BIOS;
+               dBiosAdr = (dBiosAdr << 4);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+               pbBiosAdr = phys_to_virt(dBiosAdr);
+#endif
+
+               init_tulip(pHCB, tul_scb + (i * tul_num_scb), tul_num_scb, pbBiosAdr, 10);
+               pHCB->HCS_Index = i;    /* 7/29/98 */
+               hreg = scsi_register(tpnt, sizeof(HCS));
+               hreg->io_port = pHCB->HCS_Base;
+               hreg->n_io_port = 0xff;
+               hreg->can_queue = tul_num_scb;  /* 03/05/98                      */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+               hreg->unique_id = pHCB->HCS_Base;
+               hreg->max_id = pHCB->HCS_MaxTar;
+#endif
+               hreg->max_lun = 32;     /* 10/21/97                     */
+               hreg->irq = pHCB->HCS_Intr;
+               hreg->this_id = pHCB->HCS_SCSI_ID;      /* Assign HCS index           */
+               hreg->base = (UCHAR *) pHCB;
+               hreg->sg_tablesize = TOTAL_SG_ENTRY;    /* Maximun support is 32 */
+
+               /* Initial tulip chip           */
+               switch (i) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+               case 0:
+                       ok = request_irq(pHCB->HCS_Intr, i91u_intr0, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+                       break;
+               case 1:
+                       ok = request_irq(pHCB->HCS_Intr, i91u_intr1, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+                       break;
+               case 2:
+                       ok = request_irq(pHCB->HCS_Intr, i91u_intr2, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+                       break;
+               case 3:
+                       ok = request_irq(pHCB->HCS_Intr, i91u_intr3, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+                       break;
+               case 4:
+                       ok = request_irq(pHCB->HCS_Intr, i91u_intr4, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+                       break;
+               case 5:
+                       ok = request_irq(pHCB->HCS_Intr, i91u_intr5, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+                       break;
+               case 6:
+                       ok = request_irq(pHCB->HCS_Intr, i91u_intr6, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+                       break;
+               case 7:
+                       ok = request_irq(pHCB->HCS_Intr, i91u_intr7, SA_INTERRUPT | SA_SHIRQ, "i91u", NULL);
+                       break;
+               default:
+                       i91u_panic("i91u: Too many host adapters\n");
+                       break;
+               }
+               if (ok < 0) {
+                       if (ok == -EINVAL) {
+                               printk("i91u: bad IRQ %d.\n", pHCB->HCS_Intr);
+                               printk("         Contact author.\n");
+                       } else if (ok == -EBUSY)
+                               printk("i91u: IRQ %d already in use. Configure another.\n",
+                                      pHCB->HCS_Intr);
+                       else {
+                               printk("\ni91u: Unexpected error code on requesting IRQ %d.\n",
+                                      pHCB->HCS_Intr);
+                               printk("         Contact author.\n");
+                       }
+                       i91u_panic("i91u: driver needs an IRQ.\n");
+               }
+#endif
+       }
+
+       tpnt->this_id = -1;
+       tpnt->can_queue = 1;
+
+       return 1;
+}
+
+static void i91uBuildSCB(HCS * pHCB, SCB * pSCB, Scsi_Cmnd * SCpnt)
+{                              /* Create corresponding SCB     */
+       struct scatterlist *pSrbSG;
+       SG *pSG;                /* Pointer to SG list           */
+       int i;
+       long TotalLen;
+
+       pSCB->SCB_Post = i91uSCBPost;   /* i91u's callback routine      */
+       pSCB->SCB_Srb = SCpnt;
+       pSCB->SCB_Opcode = ExecSCSI;
+       pSCB->SCB_Flags = SCF_POST;     /* After SCSI done, call post routine */
+       pSCB->SCB_Target = SCpnt->target;
+       pSCB->SCB_Lun = SCpnt->lun;
+       pSCB->SCB_Ident = SCpnt->lun | DISC_ALLOW;
+       pSCB->SCB_Flags |= SCF_SENSE;   /* Turn on auto request sense   */
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+       pSCB->SCB_SensePtr = (U32) VIRT_TO_BUS(SCpnt->sense_buffer);
+#else
+       pSCB->SCB_SensePtr = (U32) (SCpnt->sense_buffer);
+#endif
+
+       pSCB->SCB_SenseLen = SENSE_SIZE;
+
+       pSCB->SCB_CDBLen = SCpnt->cmd_len;
+       pSCB->SCB_HaStat = 0;
+       pSCB->SCB_TaStat = 0;
+       memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, SCpnt->cmd_len);
+
+       if (SCpnt->device->tagged_supported) {  /* Tag Support                  */
+               pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG;    /* Do simple tag only   */
+       } else {
+               pSCB->SCB_TagMsg = 0;   /* No tag support               */
+       }
+
+       if (SCpnt->use_sg) {
+               pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
+               if (SCpnt->use_sg == 1) {       /* If only one entry in the list *//*      treat it as regular I/O */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+                       pSCB->SCB_BufPtr = (U32) VIRT_TO_BUS(pSrbSG->address);
+#else
+                       pSCB->SCB_BufPtr = (U32) (pSrbSG->address);
+#endif
+                       TotalLen = pSrbSG->length;
+                       pSCB->SCB_SGLen = 0;
+               } else {        /* Assign SG physical address   */
+                       pSCB->SCB_BufPtr = pSCB->SCB_SGPAddr;
+                       pSCB->SCB_Flags |= SCF_SG;      /* Turn on SG list flag       */
+                       for (i = 0, TotalLen = 0, pSG = &pSCB->SCB_SGList[0];   /* 1.01g */
+                            i < SCpnt->use_sg;
+                            i++, pSG++, pSrbSG++) {
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+                               pSG->SG_Ptr = (U32) VIRT_TO_BUS(pSrbSG->address);
+#else
+                               pSG->SG_Ptr = (U32) (pSrbSG->address);
+#endif
+                               TotalLen += pSG->SG_Len = pSrbSG->length;
+                       }
+                       pSCB->SCB_SGLen = i;
+               }
+               pSCB->SCB_BufLen = (SCpnt->request_bufflen > TotalLen) ?
+                   TotalLen : SCpnt->request_bufflen;
+       } else {                /* Non SG                       */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+               pSCB->SCB_BufPtr = (U32) VIRT_TO_BUS(SCpnt->request_buffer);
+#else
+               pSCB->SCB_BufPtr = (U32) (SCpnt->request_buffer);
+#endif
+               pSCB->SCB_BufLen = SCpnt->request_bufflen;
+               pSCB->SCB_SGLen = 0;
+       }
+
+       return;
+}
+
+/* 
+ *  Queue a command and setup interrupts for a free bus.
+ */
+int i91u_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+       register SCB *pSCB;
+       HCS *pHCB;              /* Point to Host adapter control block */
+
+       if (SCpnt->lun > 16) {  /* 07/22/98 */
+
+               SCpnt->result = (DID_TIME_OUT << 16);
+               done(SCpnt);    /* Notify system DONE           */
+               return (0);
+       }
+       pHCB = (HCS *) SCpnt->host->base;
+
+       SCpnt->scsi_done = done;
+       /* Get free SCSI control block  */
+       if ((pSCB = tul_alloc_scb(pHCB)) == NULL) {
+               i91uAppendSRBToQueue(pHCB, SCpnt);      /* Buffer this request  */
+               return (0);
+       }
+       i91uBuildSCB(pHCB, pSCB, SCpnt);
+       tul_exec_scb(pHCB, pSCB);       /* Start execute SCB            */
+       return (0);
+}
+
+/*
+ *  We only support command in interrupt-driven fashion
+ */
+int i91u_command(Scsi_Cmnd * SCpnt)
+{
+       printk("i91u: interrupt driven driver; use i91u_queue()\n");
+       return -1;
+}
+
+/*
+ *  Abort a queued command
+ *  (commands that are on the bus can't be aborted easily)
+ */
+int i91u_abort(Scsi_Cmnd * SCpnt)
+{
+       HCS *pHCB;
+
+       pHCB = (HCS *) SCpnt->host->base;
+       return tul_abort_srb(pHCB, SCpnt);
+}
+
+/*
+ *  Reset registers, reset a hanging bus and
+ *  kill active and disconnected commands for target w/o soft reset
+ */
+int i91u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{                              /* I need Host Control Block Information */
+       HCS *pHCB;
+
+       pHCB = (HCS *) SCpnt->host->base;
+
+       if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
+               return tul_reset_scsi_bus(pHCB);
+       else
+               return tul_device_reset(pHCB, (ULONG) SCpnt, SCpnt->target, reset_flags);
+}
+
+/*
+ * Return the "logical geometry"
+ */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+int i91u_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
+#else
+int i91u_biosparam(Scsi_Disk * disk, int dev, int *info_array)
+#endif
+{
+       HCS *pHcb;              /* Point to Host adapter control block */
+       TCS *pTcb;
+
+       pHcb = (HCS *) disk->device->host->base;
+       pTcb = &pHcb->HCS_Tcs[disk->device->id];
+
+       if (pTcb->TCS_DrvHead) {
+               info_array[0] = pTcb->TCS_DrvHead;
+               info_array[1] = pTcb->TCS_DrvSector;
+               info_array[2] = disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
+       } else {
+               if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
+                       info_array[0] = 255;
+                       info_array[1] = 63;
+                       info_array[2] = disk->capacity / 255 / 63;
+               } else {
+                       info_array[0] = 64;
+                       info_array[1] = 32;
+                       info_array[2] = disk->capacity >> 11;
+               }
+       }
+
+#if defined(DEBUG_BIOSPARAM)
+       if (i91u_debug & debug_biosparam) {
+               printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
+                      info_array[0], info_array[1], info_array[2]);
+               printk("WARNING: check, if the bios geometry is correct.\n");
+       }
+#endif
+
+       return 0;
+}
+
+/*****************************************************************************
+ Function name  : i91uSCBPost
+ Description    : This is callback routine be called when tulip finish one
+                       SCSI command.
+ Input          : pHCB  -       Pointer to host adapter control block.
+                 pSCB  -       Pointer to SCSI control block.
+ Output         : None.
+ Return         : None.
+*****************************************************************************/
+static void i91uSCBPost(BYTE * pHcb, BYTE * pScb)
+{
+       Scsi_Cmnd *pSRB;        /* Pointer to SCSI request block */
+       HCS *pHCB;
+       SCB *pSCB;
+
+       pHCB = (HCS *) pHcb;
+       pSCB = (SCB *) pScb;
+       if ((pSRB = pSCB->SCB_Srb) == 0) {
+               printk("i91uSCBPost: SRB pointer is empty\n");
+
+               tul_release_scb(pHCB, pSCB);    /* Release SCB for current channel */
+               return;
+       }
+       switch (pSCB->SCB_HaStat) {
+       case 0x0:
+       case 0xa:               /* Linked command complete without error and linked normally */
+       case 0xb:               /* Linked command complete without error interrupt generated */
+               pSCB->SCB_HaStat = 0;
+               break;
+
+       case 0x11:              /* Selection time out-The initiator selection or target
+                                  reselection was not complete within the SCSI Time out period */
+               pSCB->SCB_HaStat = 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 SCRD interrupt */
+               pSCB->SCB_HaStat = DID_RESET;
+               break;
+
+       case 0x1a:              /* SCB Aborted. 07/21/98 */
+               pSCB->SCB_HaStat = DID_ABORT;
+               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 0x16:              /* Invalid SCB Operation Code. */
+
+       default:
+               printk("ini9100u: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
+               pSCB->SCB_HaStat = DID_ERROR;   /* Couldn't find any better */
+               break;
+       }
+
+       pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
+
+       if (pSRB == NULL) {
+               printk("pSRB is NULL\n");
+       }
+       pSRB->scsi_done(pSRB);  /* Notify system DONE           */
+       if ((pSRB = i91uPopSRBFromQueue(pHCB)) != NULL)
+               /* Find the next pending SRB    */
+       {                       /* Assume resend will success   */
+               /* Reuse old SCB                */
+               i91uBuildSCB(pHCB, pSCB, pSRB);         /* Create corresponding SCB     */
+
+               tul_exec_scb(pHCB, pSCB);       /* Start execute SCB            */
+       } else {                /* No Pending SRB               */
+               tul_release_scb(pHCB, pSCB);    /* Release SCB for current channel */
+       }
+       return;
+}
+
+/*
+ * Interrupts handler (main routine of the driver)
+ */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr0(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr0(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       unsigned long flags;
+#endif
+
+       if (tul_hcs[0].HCS_Intr != irqno)
+               return;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+       tul_isr(&tul_hcs[0]);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr1(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr1(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       unsigned long flags;
+#endif
+
+       if (tul_hcs[1].HCS_Intr != irqno)
+               return;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+       tul_isr(&tul_hcs[1]);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr2(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr2(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       unsigned long flags;
+#endif
+
+       if (tul_hcs[2].HCS_Intr != irqno)
+               return;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+       tul_isr(&tul_hcs[2]);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr3(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr3(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       unsigned long flags;
+#endif
+
+       if (tul_hcs[3].HCS_Intr != irqno)
+               return;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+       tul_isr(&tul_hcs[3]);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr4(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr4(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       unsigned long flags;
+#endif
+
+       if (tul_hcs[4].HCS_Intr != irqno)
+               return;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+       tul_isr(&tul_hcs[4]);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr5(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr5(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       unsigned long flags;
+#endif
+
+       if (tul_hcs[5].HCS_Intr != irqno)
+               return;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+       tul_isr(&tul_hcs[5]);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr6(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr6(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       unsigned long flags;
+#endif
+
+       if (tul_hcs[6].HCS_Intr != irqno)
+               return;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+       tul_isr(&tul_hcs[6]);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
+static void i91u_intr7(int irqno, void *dev_id, struct pt_regs *regs)
+#else
+static void i91u_intr7(int irqno, struct pt_regs *regs)
+#endif
+{
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       unsigned long flags;
+#endif
+
+       if (tul_hcs[7].HCS_Intr != irqno)
+               return;
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+       tul_isr(&tul_hcs[7]);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+}
+
+/* 
+ * Dump the current driver status and panic...
+ */
+static void i91u_panic(char *msg)
+{
+       printk("\ni91u_panic: %s\n", msg);
+       panic("i91u panic");
+}
diff --git a/drivers/scsi/ini9100u.h b/drivers/scsi/ini9100u.h
new file mode 100644 (file)
index 0000000..d80cebb
--- /dev/null
@@ -0,0 +1,334 @@
+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *************************************************************************
+ *
+ * Module: ini9100u.h
+ * Description: INI-9100U/UW LINUX device driver header
+ * Revision History:
+ * 06/18/96 Harry Chen, Initial Version 1.00A (Beta)
+ * 06/23/98 hc - v1.01k
+ *             - Get it work for kernel version >= 2.1.75
+ * 12/09/98 bv - v1.03a
+ *             - Removed unused code
+ * 12/13/98 bv - v1.03b
+ *             - Add spinlocks to HCS structure.
+*******************************************************************************/
+
+#ifndef        CVT_LINUX_VERSION
+#define        CVT_LINUX_VERSION(V,P,S)        (((V) * 65536) + ((P) * 256) + (S))
+#endif
+
+#ifndef        LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#include "sd.h"
+
+extern int i91u_detect(Scsi_Host_Template *);
+extern int i91u_command(Scsi_Cmnd *);
+extern int i91u_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+extern int i91u_abort(Scsi_Cmnd *);
+extern int i91u_reset(Scsi_Cmnd *, unsigned int);
+
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1, 3, 0)
+extern int i91u_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */
+extern struct proc_dir_entry proc_scsi_ini9100u;
+#else
+extern int i91u_biosparam(Disk *, int, int *); /*for linux v1.13 */
+#endif
+
+#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.03b"
+
+#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0)
+#define INI9100U       { \
+               NULL, \
+               NULL, \
+               i91u_REVID, \
+               i91u_detect, \
+               NULL, \
+               NULL, \
+               i91u_command, \
+               i91u_queue, \
+               i91u_abort, \
+               i91u_reset, \
+               NULL, \
+               i91u_biosparam, \
+               1, \
+               7, \
+               SG_ALL, \
+               1, \
+               0, \
+               0, \
+               ENABLE_CLUSTERING \
+}
+#else
+
+#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2, 1, 75)
+#define INI9100U       { \
+               NULL, \
+               NULL, \
+               &proc_scsi_ini9100u, \
+               NULL, \
+               i91u_REVID, \
+               i91u_detect, \
+               NULL, \
+               NULL, \
+               i91u_command, \
+               i91u_queue, \
+               i91u_abort, \
+               i91u_reset, \
+               NULL, \
+               i91u_biosparam, \
+               1, \
+               7, \
+               SG_ALL, \
+               1, \
+               0, \
+               0, \
+               ENABLE_CLUSTERING \
+}
+#else                          /* Version >= 2.1.75 */
+#define INI9100U       { \
+       next:           NULL,                                           \
+       module:         NULL,                                           \
+       proc_dir:       &proc_scsi_ini9100u, \
+       proc_info:      NULL,                           \
+       name:           i91u_REVID, \
+       detect:         i91u_detect, \
+       release:        NULL, \
+       info:           NULL,                                   \
+       command:        i91u_command, \
+       queuecommand:   i91u_queue, \
+       eh_strategy_handler: NULL, \
+       eh_abort_handler: NULL, \
+       eh_device_reset_handler: NULL, \
+       eh_bus_reset_handler: NULL, \
+       eh_host_reset_handler: NULL, \
+       abort:          i91u_abort, \
+       reset:          i91u_reset, \
+       slave_attach:   NULL, \
+       bios_param:     i91u_biosparam, \
+       can_queue:      1, \
+       this_id:        1, \
+       sg_tablesize:   SG_ALL, \
+       cmd_per_lun:    1, \
+       present:        0, \
+       unchecked_isa_dma: 0, \
+       use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 0 \
+}
+#endif
+#endif
+
+
+#define VIRT_TO_BUS(i)  (unsigned int) virt_to_bus((void *)(i))
+#define ULONG   unsigned long
+#define USHORT  unsigned short
+#define UCHAR   unsigned char
+#define BYTE    unsigned char
+#define WORD    unsigned short
+#define DWORD   unsigned long
+#define UBYTE   unsigned char
+#define UWORD   unsigned short
+#define UDWORD  unsigned long
+#ifdef ALPHA
+#define U32   unsigned int
+#else
+#define U32   unsigned long
+#endif
+
+#ifndef NULL
+#define NULL     0             /* zero          */
+#endif
+#ifndef TRUE
+#define TRUE     (1)           /* boolean true  */
+#endif
+#ifndef FALSE
+#define FALSE    (0)           /* boolean false */
+#endif
+#ifndef FAILURE
+#define FAILURE  (-1)
+#endif
+
+#define i91u_MAXQUEUE          2
+#define TOTAL_SG_ENTRY         32
+#define MAX_TARGETS            16
+#define SENSE_SIZE             14
+
+#define INI_VENDOR_ID   0x1101 /* Initio's PCI vendor ID       */
+#define I950_DEVICE_ID 0x9500  /* Initio's inic-950 product ID   */
+#define I940_DEVICE_ID 0x9400  /* Initio's inic-940 product ID   */
+#define I935_DEVICE_ID 0x9401  /* Initio's inic-935 product ID   */
+#define I920_DEVICE_ID 0x0002  /* Initio's other product ID      */
+
+/************************************************************************/
+/*              Scatter-Gather Element Structure                        */
+/************************************************************************/
+typedef struct SG_Struc {
+       U32 SG_Ptr;             /* Data Pointer */
+       U32 SG_Len;             /* Data Length */
+} SG;
+
+/***********************************************************************
+               SCSI Control Block
+************************************************************************/
+typedef struct Scsi_Ctrl_Blk {
+       U32 SCB_InitioReserved[9];      /* 0 */
+
+       UBYTE SCB_Opcode;       /*24 SCB command code */
+       UBYTE SCB_Flags;        /*25 SCB Flags */
+       UBYTE SCB_Target;       /*26 Target Id */
+       UBYTE SCB_Lun;          /*27 Lun */
+       U32 SCB_BufPtr;         /*28 Data Buffer Pointer */
+       U32 SCB_BufLen;         /*2C Data Allocation Length */
+       UBYTE SCB_SGLen;        /*30 SG list # */
+       UBYTE SCB_SenseLen;     /*31 Sense Allocation Length */
+       UBYTE SCB_HaStat;       /*32 */
+       UBYTE SCB_TaStat;       /*33 */
+       UBYTE SCB_CDBLen;       /*34 CDB Length */
+       UBYTE SCB_Ident;        /*35 Identify */
+       UBYTE SCB_TagMsg;       /*36 Tag Message */
+       UBYTE SCB_TagId;        /*37 Queue Tag */
+       UBYTE SCB_CDB[12];      /*38 */
+       U32 SCB_SGPAddr;        /*44 SG List/Sense Buf phy. Addr. */
+       U32 SCB_SensePtr;       /*48 Sense data pointer */
+       void (*SCB_Post) (BYTE *, BYTE *);      /*4C POST routine */
+       Scsi_Cmnd *SCB_Srb;     /*50 SRB Pointer */
+       SG SCB_SGList[TOTAL_SG_ENTRY];  /*54 Start of SG list */
+} SCB;
+
+/* Opcodes of SCB_Opcode */
+#define ExecSCSI        0x1
+#define BusDevRst       0x2
+#define AbortCmd        0x3
+
+/* Bit Definition for SCB_Flags */
+#define SCF_DONE        0x01
+#define SCF_POST        0x02
+#define SCF_SENSE       0x04
+#define SCF_DIR         0x18
+#define SCF_NO_DCHK     0x00
+#define SCF_DIN         0x08
+#define SCF_DOUT        0x10
+#define SCF_NO_XF       0x18
+#define SCF_POLL        0x40
+#define SCF_SG          0x80
+
+/* Error Codes for SCB_HaStat */
+#define HOST_SEL_TOUT   0x11
+#define HOST_DO_DU      0x12
+#define HOST_BUS_FREE   0x13
+#define HOST_BAD_PHAS   0x14
+#define HOST_INV_CMD    0x16
+#define HOST_SCSI_RST   0x1B
+#define HOST_DEV_RST    0x1C
+
+/* Error Codes for SCB_TaStat */
+#define TARGET_CHKCOND  0x02
+#define TARGET_BUSY     0x08
+
+/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */
+#define MSG_STAG        0x20
+#define MSG_HTAG        0x21
+#define MSG_OTAG        0x22
+
+/***********************************************************************
+               Target Device Control Structure
+**********************************************************************/
+
+typedef struct Tar_Ctrl_Struc {
+       ULONG TCS_InitioReserved;       /* 0 */
+
+       UWORD TCS_DrvFlags;     /* 4 */
+       UBYTE TCS_DrvHead;      /* 6 */
+       UBYTE TCS_DrvSector;    /* 7 */
+} TCS;
+
+/***********************************************************************
+               Target Device Control Structure
+**********************************************************************/
+/* Bit Definition for TCF_DrvFlags */
+#define TCF_DRV_255_63          0x0400
+
+/***********************************************************************
+             Host Adapter Control Structure
+************************************************************************/
+typedef struct Ha_Ctrl_Struc {
+       UWORD HCS_Base;         /* 00 */
+       UWORD HCS_BIOS;         /* 02 */
+       UBYTE HCS_Intr;         /* 04 */
+       UBYTE HCS_SCSI_ID;      /* 05 */
+       UBYTE HCS_MaxTar;       /* 06 */
+       UBYTE HCS_NumScbs;      /* 07 */
+
+       UBYTE HCS_Flags;        /* 08 */
+       UBYTE HCS_Index;        /* 09 */
+       UBYTE HCS_Reserved[2];  /* 0a */
+       ULONG HCS_InitioReserved[27];   /* 0C */
+       TCS HCS_Tcs[16];        /* 78 -> 16 Targets */
+       Scsi_Cmnd *pSRB_head;   /* SRB save queue header     */
+       Scsi_Cmnd *pSRB_tail;   /* SRB save queue tail       */
+#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
+       spinlock_t HCS_AvailLock;
+       spinlock_t HCS_SemaphLock;
+       spinlock_t pSRB_lock;
+#endif
+} HCS;
+
+/* Bit Definition for HCB_Flags */
+#define HCF_EXPECT_RESET        0x10
+
+/* SCSI related definition                                              */
+#define DISC_NOT_ALLOW          0x80   /* Disconnect is not allowed    */
+#define DISC_ALLOW              0xC0   /* Disconnect is allowed        */
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
new file mode 100644 (file)
index 0000000..9e6fa65
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * 68k mac 53c9[46] scsi driver
+ *
+ * copyright (c) 1998, David Weis weisd3458@uni.edu
+ *
+ * debugging on Quadra 800 and 660AV Michael Schmitz, Dave Kilzer 7/98
+ *
+ * based loosely on cyber_esp.c
+ */
+
+/* these are unused for now */
+#define myreadl(addr) (*(volatile unsigned int *) (addr))
+#define mywritel(b, addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "NCR53C9x.h"
+#include "mac_esp.h"
+
+#include "../../arch/m68k/mac/via6522.h"  /* huh? */
+
+#include <asm/io.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+
+#include <asm/pgtable.h>
+
+#include <asm/macintosh.h>
+
+extern inline void esp_handle(struct NCR_ESP *esp);
+extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+
+static int  dma_bytes_sent(struct NCR_ESP * esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP * esp);
+static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length);
+static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length);
+static void dma_ints_off(struct NCR_ESP * esp);
+static void dma_ints_on(struct NCR_ESP * esp);
+static int  dma_irq_p(struct NCR_ESP * esp);
+static int  dma_irq_p_quick(struct NCR_ESP * esp);
+static void dma_led_off(struct NCR_ESP * esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write);
+static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write);
+
+
+static int esp_dafb_dma_irq_p(struct NCR_ESP * espdev);
+static int esp_iosb_dma_irq_p(struct NCR_ESP * espdev);
+
+static int esp_initialized = 0;
+
+static int setup_num_esps = -1;
+static int setup_disconnect = -1;
+static int setup_nosync = -1;
+static int setup_can_queue = -1;
+static int setup_cmd_per_lun = -1;
+static int setup_sg_tablesize = -1;
+#ifdef SUPPORT_TAGS
+static int setup_use_tagged_queuing = -1;
+#endif
+static int setup_hostid = -1;
+
+/*
+ * Experimental ESP inthandler; check macints.c to make sure dev_id is 
+ * set up properly!
+ */
+
+void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+       struct NCR_ESP *esp = (struct NCR_ESP *) dev_id;
+       int irq_p = 0;
+
+       /* Handle the one ESP interrupt showing at this IRQ level. */
+       if(((esp)->irq & 0xff) == irq) {
+       /*
+        * Debug ..
+        */
+               irq_p = esp->dma_irq_p(esp);
+               printk("mac_esp: irq_p %x current %p disconnected %p\n",
+                       irq_p, esp->current_SC, esp->disconnected_SC);
+                       
+               /*
+                * Mac: if we're here, it's an ESP interrupt for sure!
+                */
+               if((esp->current_SC || esp->disconnected_SC)) {
+                       esp->dma_ints_off(esp);
+
+                       ESPIRQ(("I%d(", esp->esp_id));
+                       esp_handle(esp);
+                       ESPIRQ((")"));
+
+                       esp->dma_ints_on(esp);
+               }
+       }
+}
+
+/*
+ * Debug hooks; use for playing with the interrupt flag testing and interrupt
+ * acknowledge on the various machines
+ */
+
+void scsi_esp_polled(int irq, void *dev_id, struct pt_regs *pregs)
+{
+       if (esp_initialized == 0)
+               return;
+
+       mac_esp_intr(irq, dev_id, pregs);
+}
+
+void fake_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: got irq\n");
+#endif
+
+       mac_esp_intr(irq, dev_id, pregs);
+}
+
+void fake_drq(int irq, void *dev_id, struct pt_regs *pregs)
+{
+       printk("mac_esp: got drq\n");
+}
+
+#define DRIVER_SETUP
+
+/*
+ * Function : mac_scsi_setup(char *str, int *ints)
+ *
+ * Purpose : booter command line initialization of the overrides array,
+ *
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ *     equal to the number of ints.
+ *
+ * Currently unused in the new driver; need to add settable parameters to the 
+ * detect function.
+ *
+ */
+
+void mac_esp_setup(char *str, int *ints) {
+#ifdef DRIVER_SETUP
+       /* Format of mac53c9x parameter is:
+        *   mac53c9x=<num_esps>,<disconnect>,<nosync>,<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
+        * Negative values mean don't change.
+        */
+       
+       /* Grmbl... the standard parameter parsing can't handle negative numbers
+        * :-( So let's do it ourselves!
+        */
+
+       int i = ints[0]+1, fact;
+
+       while( str && (isdigit(*str) || *str == '-') && i <= 10) {
+               if (*str == '-')
+                       fact = -1, ++str;
+               else
+                       fact = 1;
+               ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
+               if ((str = strchr( str, ',' )) != NULL)
+                       ++str;
+       }
+       ints[0] = i-1;
+       
+       if (ints[0] < 1) {
+               printk( "mac_esp_setup: no arguments!\n" );
+               return;
+       }
+
+       if (ints[0] >= 1) {
+               if (ints[1] > 0)
+                       /* no limits on this, just > 0 */
+               if (ints[1] >= 0 && ints[1] <= 2)
+                       setup_num_esps = ints[1];
+               else if (ints[1] > 2)
+                       printk( "mac_esp_setup: invalid number of hosts %d !\n", ints[1] );
+       }
+       if (ints[0] >= 2) {
+               if (ints[2] > 0)
+                       setup_disconnect = ints[2];
+       }
+       if (ints[0] >= 3) {
+               if (ints[3] >= 0) {
+                       setup_nosync = ints[3];
+               }
+       }
+       if (ints[0] >= 4) {
+               if (ints[4] > 0)
+                       /* no limits on this, just > 0 */
+                       setup_can_queue = ints[4];
+       }
+       if (ints[0] >= 5) {
+               if (ints[5] > 0)
+                       setup_cmd_per_lun = ints[5];
+       }
+       if (ints[0] >= 6) {
+               if (ints[6] >= 0) {
+                       setup_sg_tablesize = ints[6];
+                       /* Must be <= SG_ALL (255) */
+                       if (setup_sg_tablesize > SG_ALL)
+                               setup_sg_tablesize = SG_ALL;
+               }
+       }
+       if (ints[0] >= 7) {
+               /* Must be between 0 and 7 */
+               if (ints[7] >= 0 && ints[7] <= 7)
+                       setup_hostid = ints[7];
+               else if (ints[7] > 7)
+                       printk( "mac_esp_setup: invalid host ID %d !\n", ints[7] );
+       }
+#ifdef SUPPORT_TAGS
+       if (ints[0] >= 8) {
+               if (ints[8] >= 0)
+                       setup_use_tagged_queuing = !!ints[8];
+       }
+#endif
+#endif
+}
+
+/*
+ * ESP address 'detection'
+ */
+
+unsigned long get_base(int chip_num)
+{
+       /*
+        * using the chip_num and mac model, figure out where the
+        * chips are mapped
+        */
+
+       unsigned long io_base = 0x50f00000;
+       unsigned int second_offset = 0x402;
+       unsigned long scsi_loc = 0;
+
+       switch (macintosh_config->scsi_type) {
+
+       /* 950, 900, 700 */
+       case MAC_SCSI_QUADRA2:
+               scsi_loc =  io_base + 0xf000 + ((chip_num == 0) ? 0 : second_offset);
+               break;
+
+       /* av's */
+       case MAC_SCSI_QUADRA3:
+               scsi_loc = io_base + 0x18000 + ((chip_num == 0) ? 0 : second_offset);
+               break;
+
+       /* most quadra/centris models are like this */  
+       case MAC_SCSI_QUADRA:
+               scsi_loc = io_base + 0x10000;
+               break;
+
+       default:
+               printk("mac_esp: get_base: hit default!\n");
+               scsi_loc = io_base + 0x10000;
+               break;
+
+       } /* switch */
+
+       printk("mac_esp: io base at 0x%lx\n", scsi_loc);
+
+       return scsi_loc;
+}
+
+/*
+ * Model dependent ESP setup
+ */
+
+int mac_esp_detect(Scsi_Host_Template * tpnt)
+{
+       int quick = 0;
+       int chipnum, chipspresent = 0;
+#if 0
+       unsigned long timeout;
+#endif
+
+       /* what do we have in this machine... */
+       if (MACHW_PRESENT(MAC_SCSI_96)) {
+               chipspresent ++;
+       }
+
+       if (MACHW_PRESENT(MAC_SCSI_96_2)) {
+               chipspresent ++;
+       }
+
+       /* number of ESPs present ? */
+       if (setup_num_esps >= 0) {
+         if (chipspresent >= setup_num_esps)
+           chipspresent = setup_num_esps;
+         else
+           printk("mac_esp_detect: num_hosts detected %d setup %d \n",
+                  chipspresent, setup_num_esps);
+       }
+
+       /* TODO: add disconnect / nosync flags */
+
+       /* setup variables */
+       tpnt->can_queue =
+         (setup_can_queue > 0) ? setup_can_queue : 7;
+       tpnt->cmd_per_lun =
+         (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : 1;
+       tpnt->sg_tablesize = 
+         (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_ALL;
+
+       if (setup_hostid >= 0)
+         tpnt->this_id = setup_hostid;
+       else {
+         /* use 7 as default */
+         tpnt->this_id = 7;
+       }
+
+#ifdef SUPPORT_TAGS
+       if (setup_use_tagged_queuing < 0)
+               setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
+#endif
+
+       for (chipnum = 0; chipnum < chipspresent; chipnum ++) {
+               struct NCR_ESP * esp;
+
+               esp = esp_allocate(tpnt, (void *) NULL);
+               esp->eregs = (struct ESP_regs *) get_base(chipnum);
+
+               esp->dma_irq_p = &esp_dafb_dma_irq_p;
+               if (chipnum == 0) {
+
+                       if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
+                               /* most machines except those below :-) */
+                               quick = 1;
+                               esp->dma_irq_p = &esp_iosb_dma_irq_p;
+                       } else if (macintosh_config->scsi_type == MAC_SCSI_QUADRA3) {
+                               /* mostly av's */
+                               quick = 0;
+                       } else {
+                               /* q950, 900, 700 */
+                               quick = 1;
+                               writel(0x1d1, 0xf9800024);
+                               esp->dregs = (void *) 0xf9800024;
+                       }
+
+               } else { /* chipnum */
+
+                       quick = 1;
+                       writel(0x1d1, 0xf9800028);
+                       esp->dregs = (void *) 0xf9800028;
+
+               } /* chipnum == 0 */
+
+
+               /* use pio for command bytes; pio for message/data: TBI */
+               esp->do_pio_cmds = 1;
+
+               /* various functions */
+               esp->dma_bytes_sent = &dma_bytes_sent;
+               esp->dma_can_transfer = &dma_can_transfer;
+               esp->dma_dump_state = &dma_dump_state;
+               esp->dma_init_read = NULL;
+               esp->dma_init_write = NULL;
+               esp->dma_ints_off = &dma_ints_off;
+               esp->dma_ints_on = &dma_ints_on;
+
+               esp->dma_ports_p = &dma_ports_p;
+
+
+               /* Optional functions */
+               esp->dma_barrier = NULL;
+               esp->dma_drain = NULL;
+               esp->dma_invalidate = NULL;
+               esp->dma_irq_entry = NULL;
+               esp->dma_irq_exit = NULL;
+               esp->dma_led_on = NULL;
+               esp->dma_led_off = NULL;
+               esp->dma_poll = NULL;
+               esp->dma_reset = NULL;
+
+               /* SCSI chip speed */
+               /* below esp->cfreq = 40000000; */
+
+
+               if (quick) {
+                       /* 'quick' means there's handshake glue logic like in the 5380 case */
+                       esp->dma_setup = &dma_setup_quick;
+               } else {
+                       esp->dma_setup = &dma_setup;
+               }
+
+               if (chipnum == 0) {
+
+                       esp->irq = IRQ_MAC_SCSI;
+
+                       request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp);
+                       request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp);
+
+                       if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
+                               esp->cfreq = 16500000;
+                       } else {
+                               esp->cfreq = 25000000;
+                       }
+
+
+               } else { /* chipnum == 1 */
+
+                       esp->irq = IRQ_MAC_SCSIDRQ;
+
+                       request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp);
+
+                       esp->cfreq = 25000000;
+
+               }
+
+               if (quick) {
+                       printk("esp: using quick version\n");
+               }
+
+               printk("esp: addr at 0x%p\n", esp->eregs);
+
+               esp->scsi_id = 7;
+               esp->diff = 0;
+
+               esp_initialize(esp);
+
+       } /* for chipnum */
+
+       if (chipspresent)
+               printk("\nmac_esp: %d esp controllers found\n", chipspresent);
+
+       esp_initialized = chipspresent;
+
+       return chipspresent;
+}
+
+/*
+ * I've been wondering what this is supposed to do, for some time. Talking 
+ * to Allen Briggs: These machines have an extra register someplace where the
+ * DRQ pin of the ESP can be monitored. That isn't useful for determining 
+ * anything else (such as reselect interrupt or other magic) though. 
+ * Maybe make the semantics should be changed like 
+ * if (esp->current_SC)
+ *     ... check DRQ flag ...
+ * else 
+ *     ... disconnected, check pending VIA interrupt ...
+ *
+ * There's a problem with using the dabf flag or mac_irq_pending() here: both
+ * seem to return 1 even though no interrupt is currently pending, resulting
+ * in esp_exec_cmd() holding off the next command, and possibly infinite loops
+ * in esp_intr(). 
+ * Short term fix: just use esp_status & ESP_STAT_INTR here, as long as we
+ * use simple PIO. The DRQ status will be important when implementing pseudo
+ * DMA mode (set up ESP transfer count, return, do a batch of bytes in PIO or 
+ * 'hardware handshake' mode upon DRQ).
+ * If you plan on changing this (i.e. to save the esp_status register access in 
+ * favor of a VIA register access or a shadow register for the IFR), make sure
+ * to try a debug version of this first to monitor what registers would be a good
+ * indicator of the ESP interrupt.
+ */
+
+static int esp_dafb_dma_irq_p(struct NCR_ESP * esp)
+{
+       unsigned int ret;
+       int sreg = esp->eregs->esp_status;
+
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: esp_dafb_dma_irq_p dafb %d irq %d\n", 
+               readl(esp->dregs), mac_irq_pending(IRQ_MAC_SCSI));
+#endif
+
+       sreg &= ESP_STAT_INTR;
+
+       /*
+        * maybe working; this is essentially what's used for iosb_dma_irq_p
+        */
+       if (sreg)
+               return 1;
+       else
+               return 0;
+
+       /*
+        * didn't work ...
+        */
+#if 0
+       if (esp->current_SC)
+               ret = readl(esp->dregs) & 0x200;
+       else if (esp->disconnected_SC)
+               ret = 1; /* sreg ?? */
+       else
+               ret = mac_irq_pending(IRQ_MAC_SCSI);
+
+       return(ret);
+#endif
+
+}
+
+/*
+ * See above: testing mac_irq_pending always returned 8 (SCSI IRQ) regardless 
+ * of the actual ESP status.
+ */
+
+static int esp_iosb_dma_irq_p(struct NCR_ESP * esp)
+{
+       int ret  = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ);
+       int sreg = esp->eregs->esp_status;
+
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", 
+               mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), 
+               sreg, esp->current_SC, esp->disconnected_SC);
+#endif
+
+       sreg &= ESP_STAT_INTR;
+
+       if (sreg)
+               return (sreg);
+       else
+               return 0;
+}
+
+/*
+ * This seems to be OK for PIO at least ... usually 0 after PIO.
+ */
+
+static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count)
+{
+
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: dma bytes sent = %x\n", fifo_count);
+#endif
+
+       return fifo_count;
+}
+
+/*
+ * dma_can_transfer is used to switch between DMA and PIO, if DMA (pseudo)
+ * is ever implemented. Returning 0 here will use PIO.
+ */
+
+static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd * sp)
+{
+       unsigned long sz = sp->SCp.this_residual;
+#if 0  /* no DMA yet; make conditional */
+       if (sz > 0x10000000) {
+               sz = 0x10000000;
+       }
+       printk("mac_esp: dma can transfer = 0lx%x\n", sz);
+#else
+
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: pio to transfer = %ld\n", sz);
+#endif
+
+       sz = 0;
+#endif
+       return sz;
+}
+
+/*
+ * Not yet ...
+ */
+
+static void dma_dump_state(struct NCR_ESP * esp)
+{
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: dma_dump_state: called\n");
+#endif
+#if 0
+       ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
+               esp->esp_id, ((struct mac_dma_registers *)
+               (esp->dregs))->cond_reg));
+#endif
+}
+
+/*
+ * DMA setup: should be used to set up the ESP transfer count for pseudo
+ * DMA transfers; need a DRQ transfer function to do the actual transfer
+ */
+
+static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length)
+{
+       printk("mac_esp: dma_init_read\n");
+}
+
+
+static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length)
+{
+       printk("mac_esp: dma_init_write\n");
+}
+
+
+static void dma_ints_off(struct NCR_ESP * esp)
+{
+       mac_turnoff_irq(esp->irq);
+}
+
+
+static void dma_ints_on(struct NCR_ESP * esp)
+{
+       mac_turnon_irq(esp->irq);
+}
+
+/*
+ * generic dma_irq_p(), unused
+ */
+
+static int dma_irq_p(struct NCR_ESP * esp)
+{
+       int i = esp->eregs->esp_status;
+
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: dma_irq_p status %d\n", i);
+#endif
+
+       return (i & ESP_STAT_INTR);
+}
+
+static int dma_irq_p_quick(struct NCR_ESP * esp)
+{
+       /*
+        * Copied from iosb_dma_irq_p()
+        */
+       int ret  = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ);
+       int sreg = esp->eregs->esp_status;
+
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", 
+               mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), 
+               sreg, esp->current_SC, esp->disconnected_SC);
+#endif
+
+       sreg &= ESP_STAT_INTR;
+
+       if (sreg)
+               return (sreg);
+       else
+               return 0;
+
+}
+
+static void dma_led_off(struct NCR_ESP * esp)
+{
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: dma_led_off: called\n");
+#endif
+}
+
+
+static void dma_led_on(struct NCR_ESP * esp)
+{
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: dma_led_on: called\n");
+#endif
+}
+
+
+static int dma_ports_p(struct NCR_ESP * esp)
+{
+       return 0;
+}
+
+
+static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write)
+{
+
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: dma_setup\n");
+#endif
+
+       if (write) {
+               dma_init_read(esp, (char *) addr, count);
+       } else {
+               dma_init_write(esp, (char *) addr, count);
+       }
+}
+
+
+static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write)
+{
+#ifdef DEBUG_MAC_ESP
+       printk("mac_esp: dma_setup_quick\n");
+#endif
+}
diff --git a/drivers/scsi/mac_esp.h b/drivers/scsi/mac_esp.h
new file mode 100644 (file)
index 0000000..9de3186
--- /dev/null
@@ -0,0 +1,41 @@
+
+/*
+mac_esp.h
+
+copyright 1997 David Weis, weisd3458@uni.edu
+*/
+
+
+#include "NCR53C9x.h"
+
+#ifndef MAC_ESP_H
+#define MAC_ESP_H
+
+/* #define DEBUG_MAC_ESP */
+
+extern int mac_esp_detect(struct SHT *);
+extern const char *esp_info(struct Scsi_Host *);
+extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int esp_command(Scsi_Cmnd *);
+extern int esp_abort(Scsi_Cmnd *);
+extern int esp_reset(Scsi_Cmnd *, unsigned int);
+
+
+#define SCSI_MAC_ESP      { proc_dir:          &proc_scsi_esp, \
+                           name:               "Mac 53C9x SCSI", \
+                           detect:             mac_esp_detect, \
+                           release:            NULL, \
+                           info:               esp_info, \
+                           /* command:         esp_command, */ \
+                           queuecommand:       esp_queue, \
+                           abort:              esp_abort, \
+                           reset:              esp_reset, \
+                           can_queue:          7, \
+                           this_id:            7, \
+                           sg_tablesize:       SG_ALL, \
+                           cmd_per_lun:        1, \
+                           use_clustering:     DISABLE_CLUSTERING, \
+                           use_new_eh_code:    0 }
+
+#endif /* MAC_ESP_H */
+
diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c
new file mode 100644 (file)
index 0000000..9755f8e
--- /dev/null
@@ -0,0 +1,476 @@
+/* mca_53c9x.c: Driver for the SCSI adapter found on NCR 35xx
+ *  (and maybe some other) Microchannel machines
+ *
+ * Code taken mostly from Cyberstorm SCSI drivers
+ *   Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org)
+ *
+ * The CyberStorm SCSI driver (and this driver) is based on David S. Miller's
+ *   ESP driver  * for the Sparc computers. 
+ * 
+ * Special thanks to Ken Stewart at Symbios (LSI) for helping with info on
+ *  the 86C01.  I was on the brink of going ga-ga...
+ *
+ * Also thanks to Jesper Skov for helping me with info on how the Amiga
+ *  does things...
+ */
+
+/*
+ * This is currently only set up to use one 53c9x card at a time; it could be 
+ *  changed fairly easily to detect/use more than one, but I'm not too sure how
+ *  many cards that use the 53c9x on MCA systems there are (if, in fact, there
+ *  are cards that use them, other than the one built into some NCR systems)...
+ *  If anyone requests this, I'll throw it in, otherwise it's not worth the
+ *  effort.
+ */
+
+/*
+ * Info on the 86C01 MCA interface chip at the bottom, if you care enough to
+ *  look.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "NCR53C9x.h"
+#include "mca_53c9x.h"
+
+#include <asm/dma.h>
+#include <linux/mca.h>
+#include <asm/irq.h>
+#include <asm/mca_dma.h>
+
+#include <asm/pgtable.h>
+
+static int  dma_bytes_sent(struct NCR_ESP *, int);
+static int  dma_can_transfer(struct NCR_ESP *, Scsi_Cmnd *);
+static void dma_dump_state(struct NCR_ESP *);
+static void dma_init_read(struct NCR_ESP *, __u32, int);
+static void dma_init_write(struct NCR_ESP *, __u32, int);
+static void dma_ints_off(struct NCR_ESP *);
+static void dma_ints_on(struct NCR_ESP *);
+static int  dma_irq_p(struct NCR_ESP *);
+static int  dma_ports_p(struct NCR_ESP *);
+static void dma_setup(struct NCR_ESP *, __u32, int, int);
+static void dma_led_on(struct NCR_ESP *);
+static void dma_led_off(struct NCR_ESP *);
+
+/* This is where all commands are put before they are trasfered to the 
+ *  53c9x via PIO.
+ */
+
+volatile unsigned char cmd_buffer[16];
+
+/*
+ * We keep the structure that is used to access the registers on the 53c9x
+ *  here.
+ */
+
+static struct ESP_regs eregs;
+
+/***************************************************************** Detection */
+int mca_esp_detect(Scsi_Host_Template *tpnt)
+{
+       struct NCR_ESP *esp;
+       static int io_port_by_pos[] = MCA_53C9X_IO_PORTS;
+       int mca_53c9x_ids[] = MCA_53C9X_IDS;
+       int *id_to_check = mca_53c9x_ids;
+       int slot;
+       int pos[3];
+       unsigned int tmp_io_addr;
+       unsigned char tmp_byte;
+
+
+       if (!MCA_bus)
+               return 0;
+
+       while (*id_to_check) { 
+               if ((slot = mca_find_adapter(*id_to_check, 0)) !=
+                 MCA_NOTFOUND) 
+               {
+                       esp = esp_allocate(tpnt, (void *) NULL);
+
+                       pos[0] = mca_read_stored_pos(slot, 2);
+                       pos[1] = mca_read_stored_pos(slot, 3);
+                       pos[2] = mca_read_stored_pos(slot, 4);
+
+                       esp->eregs = &eregs;
+
+                       /*
+                        * IO port base is given in the first (non-ID) pos
+                        *  register, like so:
+                        *
+                        *  Bits 3  2  1       IO base
+                        * ----------------------------
+                        *       0  0  0       <disabled>
+                        *       0  0  1       0x0240
+                        *       0  1  0       0x0340
+                        *       0  1  1       0x0400
+                        *       1  0  0       0x0420
+                        *       1  0  1       0x3240
+                        *       1  1  0       0x8240
+                        *       1  1  1       0xA240
+                        */
+
+                       tmp_io_addr =
+                         io_port_by_pos[(pos[0] & 0x0E) >> 1];
+
+                       esp->eregs->io_addr = tmp_io_addr + 0x10;
+
+                       if (esp->eregs->io_addr == 0x0000) { 
+                               printk("Adapter is disabled.\n");
+                               break;
+                       }
+
+                       /*
+                        * IRQ is specified in bits 4 and 5:
+                        *
+                        *  Bits  4  5        IRQ
+                        * -----------------------
+                        *        0  0         3
+                        *        0  1         5
+                        *        1  0         7
+                        *        1  1         9
+                        */
+
+                       esp->irq = ((pos[0] & 0x30) >> 3) + 3;
+
+                       /*
+                        * DMA channel is in the low 3 bits of the second
+                        *  POS register
+                        */
+
+                       esp->dma = pos[1] & 7;
+                       esp->slot = slot;
+
+                       if (request_irq(esp->irq, esp_intr, 0,
+                        "NCR 53c9x SCSI", esp_intr))
+                       {
+                               printk("Unable to request IRQ %d.\n", esp->irq);
+                               return 0;
+                       }
+
+                       if (request_dma(esp->dma, "NCR 53c9x SCSI")) {
+                               printk("Unable to request DMA channel %d.\n",
+                                esp->dma);
+                               free_irq(esp->irq, esp_intr);
+                               return 0;
+                       }
+
+                       request_region(tmp_io_addr, 32, "NCR 53c9x SCSI");
+
+                       /*
+                        * 86C01 handles DMA, IO mode, from address
+                        *  (base + 0x0a)
+                        */
+
+                       mca_disable_dma(esp->dma);
+                       mca_set_dma_io(esp->dma, tmp_io_addr + 0x0a);
+                       mca_enable_dma(esp->dma);
+                       /* Tell the 86C01 to give us interrupts */
+
+                       tmp_byte = inb(tmp_io_addr + 0x02) | 0x40;
+                       outb(tmp_byte, tmp_io_addr + 0x02); 
+
+                       /*
+                        * Scsi ID -- general purpose register, hi
+                        *  2 bits; add 4 to this number to get the
+                        *  ID
+                        */
+
+                       esp->scsi_id = ((pos[2] & 0xC0) >> 6) + 4;
+
+                       /* Do command transfer with programmed I/O */
+
+                       esp->do_pio_cmds = 1;
+
+                       /* Required functions */
+
+                       esp->dma_bytes_sent = &dma_bytes_sent;
+                       esp->dma_can_transfer = &dma_can_transfer;
+                       esp->dma_dump_state = &dma_dump_state;
+                       esp->dma_init_read = &dma_init_read;
+                       esp->dma_init_write = &dma_init_write;
+                       esp->dma_ints_off = &dma_ints_off;
+                       esp->dma_ints_on = &dma_ints_on;
+                       esp->dma_irq_p = &dma_irq_p;
+                       esp->dma_ports_p = &dma_ports_p;
+                       esp->dma_setup = &dma_setup;
+
+                       /* Optional functions */
+
+                       esp->dma_barrier = 0;
+                       esp->dma_drain = 0;
+                       esp->dma_invalidate = 0;
+                       esp->dma_irq_entry = 0;
+                       esp->dma_irq_exit = 0;
+                       esp->dma_led_on = dma_led_on;
+                       esp->dma_led_off = dma_led_off;
+                       esp->dma_poll = 0;
+                       esp->dma_reset = 0;
+
+                       /* Set the command buffer */
+
+                       esp->esp_command = (volatile unsigned char*)
+                         cmd_buffer;
+                       esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+
+                       /* SCSI chip speed */
+
+                       esp->cfreq = 25000000;
+
+                       /* Differential SCSI? I think not. */
+
+                       esp->diff = 0;
+
+                       esp_initialize(esp);
+
+                       printk(" Adapter found in slot %2d: io port 0x%x "
+                         "irq %d dma channel %d\n", slot + 1, tmp_io_addr,
+                          esp->irq, esp->dma);
+
+                       mca_set_adapter_name(slot, "NCR 53C9X SCSI Adapter");
+                       mca_mark_as_used(slot);
+
+                       break;
+               }
+    
+               id_to_check++;
+       }
+
+       return esps_in_use;
+}
+
+
+/******************************************************************* Release */
+
+int mca_esp_release(struct Scsi_Host *host)
+{
+       struct NCR_ESP *esp = (struct NCR_ESP *)host->hostdata;
+       unsigned char tmp_byte;
+
+
+       /*
+        * Tell the 86C01 to stop sending interrupts
+        */
+
+       tmp_byte = inb(esp->eregs->io_addr - 0x0E);
+       tmp_byte &= ~0x40;
+       outb(tmp_byte, esp->eregs->io_addr - 0x0E);
+
+       free_irq(esp->irq, esp_intr);
+       free_dma(esp->dma);
+
+       mca_mark_as_unused(esp->eregs->slot);
+
+       return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+       /* Ask the 53c9x.  It knows. */
+
+       return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+       /* 
+        * The MCA dma channels can only do up to 128K bytes at a time.
+         *  (16 bit mode)
+        */
+
+       unsigned long sz = sp->SCp.this_residual;
+       if(sz > 0x20000)
+               sz = 0x20000;
+       return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+       /*
+        * Doesn't quite match up to the other drivers, but we do what we
+        *  can.
+        */
+
+       ESPLOG(("esp%d: dma channel <%d>\n", esp->esp_id, esp->dma));
+       ESPLOG(("bytes left to dma: %d\n", mca_get_dma_residue(esp->dma)));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+       unsigned long flags;
+
+
+       save_flags(flags);
+       cli();
+
+       mca_disable_dma(esp->dma);
+       mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_16 |
+         MCA_DMA_MODE_IO);
+       mca_set_dma_addr(esp->dma, addr);
+       mca_set_dma_count(esp->dma, length / 2); /* !!! */
+       mca_enable_dma(esp->dma);
+
+       restore_flags(flags);
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+       unsigned long flags;
+
+
+       save_flags(flags);
+       cli();
+
+       mca_disable_dma(esp->dma);
+       mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_WRITE |
+         MCA_DMA_MODE_16 | MCA_DMA_MODE_IO);
+       mca_set_dma_addr(esp->dma, addr);
+       mca_set_dma_count(esp->dma, length / 2); /* !!! */
+       mca_enable_dma(esp->dma);
+
+       restore_flags(flags);
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+       /*
+        * Tell the 'C01 to shut up.  All interrupts are routed through it.
+        */
+
+       outb(inb(esp->eregs->io_addr - 0x0E) & ~0x40,
+        esp->eregs->io_addr - 0x0E);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+       /*
+        * Ok.  You can speak again.
+        */
+
+       outb(inb(esp->eregs->io_addr - 0x0E) | 0x40,
+        esp->eregs->io_addr - 0x0E);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+       /*
+        * DaveM says that this should return a "yes" if there is an interrupt
+        *  or a DMA error occurred.  I copied the Amiga driver's semantics,
+        *  though, because it seems to work and we can't really tell if
+        *  a DMA error happened.  This gives the "yes" if the scsi chip
+        *  is sending an interrupt and no DMA activity is taking place
+        */
+
+       return (!(inb(esp->eregs->io_addr - 0x04) & 1) &&
+        !(inb(esp->eregs->io_addr - 0x04) & 2) ); 
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+       /*
+        * Check to see if interrupts are enabled on the 'C01 (in case abort
+        *  is entered multiple times, so we only do the abort once)
+        */
+
+       return (inb(esp->eregs->io_addr - 0x0E) & 0x40) ? 1:0;
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+       if(write){
+               dma_init_write(esp, addr, count);
+       } else {
+               dma_init_read(esp, addr, count);
+       }
+}
+
+/*
+ * These will not play nicely with other disk controllers that try to use the
+ *  disk active LED... but what can you do?  Don't answer that.
+ *
+ * Stolen shamelessly from ibmmca.c -- IBM Microchannel SCSI adapter driver
+ *
+ */
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+       outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR);
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+       outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR);
+}
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = MCA_53C9X;
+#include "scsi_module.c"
+#endif
+
+/*
+ * OK, here's the goods I promised.  The NCR 86C01 is an MCA interface chip 
+ *  that handles enabling/diabling IRQ, dma interfacing, IO port selection
+ *  and other fun stuff.  It takes up 16 addresses, and the chip it is
+ *  connnected to gets the following 16.  Registers are as follows:
+ *
+ * Offsets 0-1 : Card ID
+ *
+ * Offset    2 : Mode enable register --
+ *                Bit    7 : Data Word width (1 = 16, 0 = 8)
+ *               Bit    6 : IRQ enable (1 = enabled)
+ *                Bits 5,4 : IRQ select
+ *                              0  0 : IRQ 3
+ *                             0  1 : IRQ 5
+ *                             1  0 : IRQ 7
+ *                             1  1 : IRQ 9
+ *                Bits 3-1 : Base Address
+ *                           0  0  0 : <disabled>
+ *                          0  0  1 : 0x0240
+ *                          0  1  0 : 0x0340
+ *                                  0  1  1 : 0x0400
+ *                          1  0  0 : 0x0420
+ *                          1  0  1 : 0x3240
+ *                          1  1  0 : 0x8240
+ *                          1  1  1 : 0xA240
+ *               Bit    0 : Card enable (1 = enabled)
+ *
+ * Offset    3 : DMA control register --
+ *                Bit    7 : DMA enable (1 = enabled)
+ *                Bits 6,5 : Preemt Count Select (transfers to complete after
+ *                            'C01 has been preempted on MCA bus)
+ *                              0  0 : 0
+ *                              0  1 : 1
+ *                              1  0 : 3
+ *                              1  1 : 7
+ *  (all these wacky numbers; I'm sure there's a reason somewhere)
+ *                Bit    4 : Fairness enable (1 = fair bus priority)
+ *                Bits 3-0 : Arbitration level (0-15 consecutive)
+ * 
+ * Offset    4 : General purpose register
+ *                Bits 7-3 : User definable (here, 7,6 are SCSI ID)
+ *                Bits 2-0 : reserved
+ *
+ * Offset   10 : DMA decode register (used for IO based DMA; also can do
+ *                PIO through this port)
+ *
+ * Offset   12 : Status
+ *                Bits 7-2 : reserved
+ *                Bit    1 : DMA pending (1 = pending)
+ *                Bit    0 : IRQ pending (0 = pending)
+ *
+ * Exciting, huh?  
+ *
+ */                
diff --git a/drivers/scsi/mca_53c9x.h b/drivers/scsi/mca_53c9x.h
new file mode 100644 (file)
index 0000000..57d1d3f
--- /dev/null
@@ -0,0 +1,66 @@
+/* mca_53c94.h: Defines and structures for the SCSI adapter found on NCR 35xx
+ *  (and maybe some other) Microchannel machines.
+ *
+ * Code taken mostly from Cyberstorm SCSI drivers
+ *   Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org)
+ *   1998
+ */
+
+#include "NCR53C9x.h"
+
+#ifndef MCA_53C9X_H
+#define MCA_53C9X_H
+
+/*
+ * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk
+ *  activity LED on and off
+ */
+
+#define PS2_SYS_CTR    0x92
+
+extern int mca_esp_detect(struct SHT *);
+extern int mca_esp_release(struct Scsi_Host *);
+extern const char *esp_info(struct Scsi_Host *);
+extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int esp_command(Scsi_Cmnd *);
+extern int esp_abort(Scsi_Cmnd *);
+extern int esp_reset(Scsi_Cmnd *, unsigned int);
+extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
+                        int hostno, int inout);
+
+
+#define MCA_53C9X         { proc_dir:          &proc_scsi_esp, \
+                           name:               "NCR 53c9x SCSI", \
+                           detect:             mca_esp_detect, \
+                           release:            mca_esp_release, \
+                           queuecommand:       esp_queue, \
+                           abort:              esp_abort, \
+                           reset:              esp_reset, \
+                           can_queue:          7, \
+                           sg_tablesize:       SG_ALL, \
+                           cmd_per_lun:        1, \
+                            unchecked_isa_dma:  1, \
+                           use_clustering:     DISABLE_CLUSTERING }
+
+/* Ports the ncr's 53c94 can be put at; indexed by pos register value */
+
+#define MCA_53C9X_IO_PORTS {                             \
+                         0x0000, 0x0240, 0x0340, 0x0400, \
+                        0x0420, 0x3240, 0x8240, 0xA240, \
+                       }
+                       
+/*
+ * Supposedly there were some cards put together with the 'c9x and 86c01.  If
+ *   they have different ID's from the ones on the 3500 series machines, 
+ *   you can add them here and hopefully things will work out.
+ */
+                       
+#define MCA_53C9X_IDS {          \
+                         0x7F4C, \
+                        0x0000, \
+                        }
+
+#endif /* MCA_53C9X_H */
+
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
new file mode 100644 (file)
index 0000000..0a9dc47
--- /dev/null
@@ -0,0 +1,1353 @@
+/*===================================================================
+ *
+ *                    Linux MegaRAID device driver
+ * 
+ * Copyright 1998 American Megatrends Inc.
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ * Version : 0.92
+ * 
+ * Description: Linux device driver for AMI MegaRAID controller
+ *
+ * History:
+ *
+ * Version 0.90:
+ *     Works and has been tested with the MegaRAID 428 controller, and
+ *     the MegaRAID 438 controller.  Probably works with the 466 also,
+ *     but not tested.
+ *
+ * Version 0.91:
+ *     Aligned mailbox area on 16-byte boundry.
+ *     Added schedule() at the end to properly clean up.
+ *     Made improvements for conformity to linux driver standards.
+ *
+ * Version 0.92:
+ *     Added support for 2.1 kernels.
+ *         Reads from pci_dev struct, so it's not dependent on pcibios.
+ *         Added some missing virt_to_bus() translations.
+ *     Added support for SMP.
+ *         Changed global cli()'s to spinlocks for 2.1, and simulated
+ *          spinlocks for 2.0.
+ *     Removed setting of SA_INTERRUPT flag when requesting Irq.
+ *
+ * Version 0.92ac:
+ *     Small changes to the comments/formatting. Plus a couple of
+ *     added notes. Returned to the authors. No actual code changes
+ *     save printk levels.
+ *     8 Oct 98        Alan Cox <alan.cox@linux.org>
+ *
+ *     Merged with 2.1.131 source tree.
+ *     12 Dec 98       K. Baranowski <kgb@knm.org.pl>
+ *
+ * BUGS:
+ *     Tested with 2.1.90, but unfortunately there is a bug in pci.c which
+ *     fails to detect our controller.  Does work with 2.1.118--don't know
+ *     which kernel in between it was fixed in.
+ *     With SMP enabled under 2.1.118 with more than one processor, gets an
+ *     error message "scsi_end_request: buffer-list destroyed" under heavy
+ *     IO, but doesn't seem to affect operation, or data integrity.  The
+ *     message doesn't occur without SMP enabled, or with one proccessor with
+ *     SMP enabled, or under any combination under 2.0 kernels.
+ *
+ *===================================================================*/
+#define QISR 1
+
+#define CRLFSTR "\n"
+
+#define MULTIQ 1
+
+#include <linux/version.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+
+#if LINUX_VERSION_CODE >= 0x20100
+char kernel_version[] = UTS_RELEASE;
+
+/* originally ported by Dell Corporation; updated, released, and maintained by
+   American Megatrends */
+MODULE_AUTHOR("American Megatrends Inc."); 
+MODULE_DESCRIPTION("AMI MegaRAID driver");    
+#endif
+#endif
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/blk.h>
+#include <linux/wait.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>      /* for kmalloc() */
+#if LINUX_VERSION_CODE < 0x20100
+#include <linux/bios32.h>
+#else
+#include <asm/spinlock.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+
+#include "megaraid.h"
+
+/*================================================================
+ *
+ *                          #Defines
+ *
+ *================================================================*/
+
+#if LINUX_VERSION_CODE < 0x020100
+#define ioremap vremap
+#define iounmap vfree
+
+/* simulate spin locks */
+typedef struct {volatile char lock;} spinlock_t;
+#define spin_lock_init(x) { (x)->lock = 0;}
+#define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\
+                                        (x)->lock=1; save_flags(flags);\
+                                        cli();}
+#define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);}
+
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020100
+#define queue_task_irq(a,b)     queue_task(a,b)
+#define queue_task_irq_off(a,b) queue_task(a,b)
+#endif
+
+#define MAX_SERBUF 160
+#define COM_BASE 0x2f8
+
+#define ENQUEUE(obj,type,list,next) \
+{ type **node; long cpuflag; \
+  spin_lock_irqsave(&mega_lock,cpuflag);\
+  for(node=&(list); *node; node=(type **)&(*node)->##next); \
+  (*node) = obj; \
+  (*node)->##next = NULL; \
+  spin_unlock_irqrestore(&mega_lock,cpuflag);\
+};
+
+#define DEQUEUE(obj,type,list,next) \
+{ long cpuflag; \
+  spin_lock_irqsave(&mega_lock,cpuflag);\
+  if ((obj=list) != NULL) {\
+    list = (type *)(list)->##next; \
+  } \
+  spin_unlock_irqrestore(&mega_lock,cpuflag);\
+};
+
+u_long RDINDOOR(mega_host_config *megaCfg)
+{
+  return readl(megaCfg->base + 0x20);
+}
+
+void WRINDOOR(mega_host_config *megaCfg, u_long value)
+{
+  writel(value,megaCfg->base+0x20);
+}
+
+u_long RDOUTDOOR(mega_host_config *megaCfg)
+{
+  return readl(megaCfg->base+0x2C);
+}
+
+void WROUTDOOR(mega_host_config *megaCfg, u_long value)
+{
+  writel(value,megaCfg->base+0x2C);
+}
+
+/*================================================================
+ *
+ *                    Function prototypes
+ *
+ *================================================================*/
+static int  MegaIssueCmd(mega_host_config *megaCfg,
+                        u_char *mboxData,
+                        mega_scb *scb,
+                        int intr);
+static int  build_sglist(mega_host_config *megaCfg, mega_scb *scb, 
+                        u_long *buffer, u_long *length);
+
+static void mega_runque(void *);
+static void mega_rundoneq(void);
+static void mega_cmd_done(mega_host_config *,mega_scb *, int);
+
+/* set SERDEBUG to 1 to enable serial debugging */
+#define SERDEBUG 0
+#if SERDEBUG
+static void ser_init(void);
+static void ser_puts(char *str);
+static void ser_putc(char c);
+static int  ser_printk(const char *fmt, ...);
+#endif
+
+/*================================================================
+ *
+ *                    Global variables
+ *
+ *================================================================*/
+static int               numCtlrs = 0;
+static mega_host_config *megaCtlrs[4] = { 0 };
+
+/* Change this to 0 if you want to see the raw drives */
+static int use_raid   = 1;
+
+/* Queue of pending/completed SCBs */
+static mega_scb  *qPending   = NULL;
+static Scsi_Cmnd *qCompleted = NULL;
+
+volatile static spinlock_t mega_lock;
+static struct tq_struct runq = {0,0,mega_runque,NULL};
+
+struct proc_dir_entry proc_scsi_megaraid = {
+  PROC_SCSI_MEGARAID, 8, "megaraid",
+  S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+#if SERDEBUG
+static char strbuf[MAX_SERBUF+1];
+
+static void ser_init()
+{
+    unsigned port=COM_BASE;
+
+    outb(0x80,port+3);
+    outb(0,port+1);
+    /* 9600 Baud, if 19200: outb(6,port) */
+    outb(12, port);
+    outb(3,port+3);
+    outb(0,port+1);
+}
+
+static void ser_puts(char *str)
+{
+    char *ptr;
+
+    ser_init();
+    for (ptr=str;*ptr;++ptr)
+        ser_putc(*ptr);
+}
+
+static void ser_putc(char c)
+{
+    unsigned port=COM_BASE;
+
+    while ((inb(port+5) & 0x20)==0);
+    outb(c,port);
+    if (c==0x0a)
+    {
+        while ((inb(port+5) & 0x20)==0);
+        outb(0x0d,port);
+    }
+}
+
+static int ser_printk(const char *fmt, ...)
+{
+    va_list args;
+    int i;
+    long flags;
+
+    spin_lock_irqsave(mega_lock,flags);
+    va_start(args,fmt);
+    i = vsprintf(strbuf,fmt,args);
+    ser_puts(strbuf);
+    va_end(args);
+    spin_unlock_irqrestore(&mega_lock,flags);
+
+    return i;
+}
+
+#define TRACE(a)    { ser_printk a;}
+
+#else
+#define TRACE(A)
+#endif
+
+void callDone(Scsi_Cmnd *SCpnt)
+{
+  if (SCpnt->result) {
+    TRACE(("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, 
+          SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, 
+          SCpnt->result));
+  }
+  SCpnt->scsi_done(SCpnt);
+}
+
+/*-------------------------------------------------------------------------
+ *
+ *                      Local functions
+ *
+ *-------------------------------------------------------------------------*/
+
+/*================================================
+ * Initialize SCB structures
+ *================================================*/
+static void initSCB(mega_host_config *megaCfg)
+{
+  int idx;
+
+  for(idx=0; idx<megaCfg->max_cmds; idx++) {
+    megaCfg->scbList[idx].idx    = -1;
+    megaCfg->scbList[idx].flag   = 0;
+    megaCfg->scbList[idx].sgList = NULL;
+    megaCfg->scbList[idx].SCpnt  = NULL;
+  }
+}
+
+/*===========================
+ * Allocate a SCB structure
+ *===========================*/
+static mega_scb *allocateSCB(mega_host_config *megaCfg,Scsi_Cmnd *SCpnt)
+{
+  int        idx;
+  long       flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
+  for(idx=0; idx<megaCfg->max_cmds; idx++) {
+    if (megaCfg->scbList[idx].idx < 0) {
+
+      /* Set Index and SCB pointer */ 
+      megaCfg->scbList[idx].flag  = 0;
+      megaCfg->scbList[idx].idx   = idx;
+      megaCfg->scbList[idx].SCpnt = SCpnt;
+      megaCfg->scbList[idx].next  = NULL;
+      spin_unlock_irqrestore(&mega_lock,flags);
+
+      if (megaCfg->scbList[idx].sgList == NULL) {
+       megaCfg->scbList[idx].sgList =
+                  kmalloc(sizeof(mega_sglist)*MAX_SGLIST,GFP_ATOMIC|GFP_DMA);
+      }
+
+      return &megaCfg->scbList[idx];
+    }
+  }
+  spin_unlock_irqrestore(&mega_lock,flags);
+
+  printk(KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
+  
+  return NULL;
+}
+
+/*=======================
+ * Free a SCB structure
+ *=======================*/
+static void freeSCB(mega_scb *scb)
+{
+  long flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
+  scb->flag  = 0;
+  scb->idx   = -1;
+  scb->next  = NULL;
+  scb->SCpnt = NULL;
+  spin_unlock_irqrestore(&mega_lock,flags);
+}
+
+/* Run through the list of completed requests */
+static void mega_rundoneq()
+{
+  mega_host_config *megaCfg;
+  Scsi_Cmnd        *SCpnt;
+  long              islogical;
+
+  while(1) {
+    DEQUEUE(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+    if (SCpnt == NULL) return;
+
+    megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+
+    /* Check if we're allowing access to RAID drives or physical
+     *  if use_raid == 1 and this wasn't a disk on the max channel or
+     *  if use_raid == 0 and this was a disk on the max channel
+     *  then fail.
+     */
+    islogical = (SCpnt->channel == megaCfg->host->max_channel) ? 1 : 0;
+    if (SCpnt->cmnd[0] == INQUIRY &&
+       ((((u_char*)SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
+       (islogical != use_raid)) {
+       SCpnt->result = 0xF0;
+    }
+
+    /* Convert result to error */
+    switch(SCpnt->result) {
+    case 0x00: case 0x02:
+      SCpnt->result |= (DID_OK << 16);
+      break;
+    case 0x8:
+      SCpnt->result |= (DID_BUS_BUSY << 16);
+      break;
+    default:
+      SCpnt->result |= (DID_BAD_TARGET << 16);
+      break;
+    }
+
+    /* Callback */
+    callDone(SCpnt);
+  }
+}
+
+/* Add command to the list of completed requests */
+static void mega_cmd_done(mega_host_config *megaCfg,mega_scb *pScb, int status)
+{
+  pScb->SCpnt->result = status;
+  ENQUEUE(pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+  freeSCB(pScb);
+}
+
+/*----------------------------------------------------
+ * Process pending queue list
+ *
+ * Run as a scheduled task 
+ *----------------------------------------------------*/
+static void mega_runque(void *dummy)
+{
+  mega_host_config *megaCfg;
+  mega_scb         *pScb;
+  long              flags;
+
+  /* Take care of any completed requests */
+  mega_rundoneq();
+
+  DEQUEUE(pScb,mega_scb,qPending,next);
+
+  if (pScb) {
+    megaCfg = (mega_host_config *)pScb->SCpnt->host->hostdata;
+
+    if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR|PENDING)) {
+      TRACE(("%.08lx %.02x <%d.%d.%d> intr%d busy%d isr%d pending%d\n",
+            pScb->SCpnt->serial_number,
+            pScb->SCpnt->cmnd[0],
+            pScb->SCpnt->channel,
+            pScb->SCpnt->target,
+            pScb->SCpnt->lun,
+            intr_count,
+            megaCfg->mbox->busy,
+            (megaCfg->flag & IN_ISR)  ? 1 : 0,
+            (megaCfg->flag & PENDING) ? 1 : 0));
+    }
+
+    if (MegaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) {
+      /* We're BUSY... come back later */
+      spin_lock_irqsave(&mega_lock,flags);
+      pScb->next = qPending;
+      qPending   = pScb;
+      spin_unlock_irqrestore(&mega_lock,flags);
+
+      if (!(megaCfg->flag & PENDING)) { /* If PENDING, irq will schedule task */
+          queue_task(&runq, &tq_scheduler);
+      }
+    }
+  }
+}
+
+/*-------------------------------------------------------------------
+ *
+ *                 Build a SCB from a Scsi_Cmnd
+ *
+ * Returns a SCB pointer, or NULL
+ * If NULL is returned, the scsi_done function MUST have been called
+ *
+ *-------------------------------------------------------------------*/
+static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt)
+{
+  mega_scb      *pScb;
+  mega_mailbox  *mbox;
+  mega_passthru *pthru;
+  long           seg;
+
+  /* We don't support multi-luns */
+  if (SCpnt->lun != 0) {
+    SCpnt->result = (DID_BAD_TARGET << 16);
+    callDone(SCpnt);
+    return NULL;
+  }
+
+  /*-----------------------------------------------------
+   *
+   *               Logical drive commands
+   *
+   *-----------------------------------------------------*/
+  if (SCpnt->channel == megaCfg->host->max_channel) {
+    switch(SCpnt->cmnd[0]) {
+    case TEST_UNIT_READY:
+      memset(SCpnt->request_buffer, 0, SCpnt->request_bufflen);
+      SCpnt->result = (DID_OK << 16);
+      callDone(SCpnt);
+      return NULL;
+
+    case MODE_SENSE:
+      memset(SCpnt->request_buffer, 0, SCpnt->cmnd[4]);
+      SCpnt->result = (DID_OK << 16);
+      callDone(SCpnt);
+      return NULL;
+
+    case READ_CAPACITY:
+    case INQUIRY:
+      /* Allocate a SCB and initialize passthru */
+      if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) {
+       SCpnt->result = (DID_ERROR << 16);
+       callDone(SCpnt);
+       return NULL;
+      }
+      pthru = &pScb->pthru;
+      mbox  = (mega_mailbox *)&pScb->mboxData;
+
+      memset(mbox,  0, sizeof(pScb->mboxData));
+      memset(pthru, 0, sizeof(mega_passthru));
+      pthru->timeout      = 0;
+      pthru->ars          = 0;
+      pthru->islogical    = 1;
+      pthru->logdrv       = SCpnt->target;
+      pthru->cdblen       = SCpnt->cmd_len;
+      pthru->dataxferaddr = virt_to_bus(SCpnt->request_buffer);
+      pthru->dataxferlen  = SCpnt->request_bufflen;
+      memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+      /* Initialize mailbox area */
+      mbox->cmd      = MEGA_MBOXCMD_PASSTHRU;
+      mbox->xferaddr = virt_to_bus(pthru);
+
+      return pScb;
+
+    case READ_6:
+    case WRITE_6:
+    case READ_10:
+    case WRITE_10:
+      /* Allocate a SCB and initialize mailbox */
+      if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) {
+       SCpnt->result = (DID_ERROR << 16);
+       callDone(SCpnt);
+       return NULL;
+      }
+      mbox = (mega_mailbox *)&pScb->mboxData;
+
+      memset(mbox, 0, sizeof(pScb->mboxData));
+      mbox->logdrv = SCpnt->target;
+      mbox->cmd    = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ?
+       MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE;
+      
+      /* 6-byte */
+      if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) {
+       mbox->numsectors = 
+         (u_long)SCpnt->cmnd[4];
+       mbox->lba = 
+         ((u_long)SCpnt->cmnd[1] << 16) |
+         ((u_long)SCpnt->cmnd[2] << 8) |
+         (u_long)SCpnt->cmnd[3];
+       mbox->lba &= 0x1FFFFF;
+      }
+      
+      /* 10-byte */
+      if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
+       mbox->numsectors = 
+         (u_long)SCpnt->cmnd[8] |
+         ((u_long)SCpnt->cmnd[7] << 8);
+       mbox->lba =
+         ((u_long)SCpnt->cmnd[2] << 24) |
+         ((u_long)SCpnt->cmnd[3] << 16) |
+         ((u_long)SCpnt->cmnd[4] << 8) |
+         (u_long)SCpnt->cmnd[5];
+      }
+      
+      /* Calculate Scatter-Gather info */
+      mbox->numsgelements = build_sglist(megaCfg, pScb, 
+                                        (u_long*)&mbox->xferaddr,
+                                        (u_long*)&seg);
+
+      return pScb;
+      
+    default:
+      SCpnt->result = (DID_BAD_TARGET << 16);
+      callDone(SCpnt);
+      return NULL;
+    }
+  }
+  /*-----------------------------------------------------
+   *
+   *               Passthru drive commands
+   *
+   *-----------------------------------------------------*/
+  else {
+    /* Allocate a SCB and initialize passthru */
+    if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) {
+      SCpnt->result = (DID_ERROR << 16);
+      callDone(SCpnt);
+      return NULL;
+    }
+    pthru = &pScb->pthru;
+    mbox  = (mega_mailbox *)pScb->mboxData;
+    
+    memset(mbox,  0, sizeof(pScb->mboxData));
+    memset(pthru, 0, sizeof(mega_passthru));
+    pthru->timeout   = 0;
+    pthru->ars       = 0;
+    pthru->islogical = 0;
+    pthru->channel   = SCpnt->channel;
+    pthru->target    = SCpnt->target;
+    pthru->cdblen    = SCpnt->cmd_len;
+    memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+   
+    pthru->numsgelements = build_sglist(megaCfg, pScb,
+                                       (u_long *)&pthru->dataxferaddr,
+                                       (u_long *)&pthru->dataxferlen);
+    
+    /* Initialize mailbox */
+    mbox->cmd      = MEGA_MBOXCMD_PASSTHRU;
+    mbox->xferaddr = virt_to_bus(pthru);
+
+    return pScb;
+  }
+  return NULL;
+}
+
+/*--------------------------------------------------------------------
+ * Interrupt service routine
+ *--------------------------------------------------------------------*/
+static void megaraid_isr(int irq, void *devp, struct pt_regs *regs)
+{
+  mega_host_config *megaCfg;
+  u_char            byte, idx, sIdx;
+  u_long            dword;
+  mega_mailbox     *mbox;
+  mega_scb         *pScb;
+  long              flags;
+  int               qCnt, qStatus;
+
+  megaCfg = (mega_host_config *)devp;
+  mbox    = (mega_mailbox *)megaCfg->mbox;
+
+  if (megaCfg->host->irq == irq) {
+    spin_lock_irqsave(&mega_lock,flags);
+
+    if (megaCfg->flag & IN_ISR) {
+      TRACE(("ISR called reentrantly!!\n"));
+    }
+
+    megaCfg->flag |= IN_ISR;
+
+    /* Check if a valid interrupt is pending */
+    if (megaCfg->flag & BOARD_QUARTZ) {
+        dword = RDOUTDOOR(megaCfg);
+        if (dword != 0x10001234) {
+            /* Spurious interrupt */
+            megaCfg->flag &= ~IN_ISR;
+            spin_unlock_irqrestore(&mega_lock,flags);
+            return;
+        }
+        WROUTDOOR(megaCfg,dword);
+    } else {
+        byte = READ_PORT(megaCfg->host->io_port, INTR_PORT);
+        if ((byte & VALID_INTR_BYTE) == 0) {
+          /* Spurious interrupt */
+          megaCfg->flag &= ~IN_ISR;
+          spin_unlock_irqrestore(&mega_lock,flags);
+          return;
+        }
+        WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte);
+    }
+    
+    qCnt    = mbox->numstatus;
+    qStatus = mbox->status;
+
+    if (qCnt > 1) {TRACE(("ISR: Received %d status\n", qCnt))
+        printk(KERN_DEBUG "Got numstatus = %d\n",qCnt);
+    }
+    
+    for(idx=0; idx<qCnt; idx++) {
+      sIdx = mbox->completed[idx];
+      if (sIdx > 0) {
+       pScb = &megaCfg->scbList[sIdx-1];
+        spin_unlock_irqrestore(&mega_lock,flags); /* locks within cmd_done */
+       mega_cmd_done(megaCfg,&megaCfg->scbList[sIdx-1], qStatus);
+        spin_lock_irqsave(&mega_lock,flags);
+      }
+    }
+    if (megaCfg->flag & BOARD_QUARTZ) {
+        WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox)|0x2);
+        while (RDINDOOR(megaCfg) & 0x02);
+    } else {
+        CLEAR_INTR(megaCfg->host->io_port);
+    }
+
+    megaCfg->flag &= ~IN_ISR;
+    megaCfg->flag &= ~PENDING;
+
+    spin_unlock_irqrestore(&mega_lock,flags);
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    mega_runque(NULL);
+    spin_unlock_irqrestore(&io_request_lock,flags);              
+
+#if 0
+    /* Queue as a delayed ISR routine */
+    queue_task_irq_off(&runq, &tq_immediate);
+    mark_bh(IMMEDIATE_BH);
+    spin_unlock_irqrestore(&mega_lock,flags);
+#endif
+
+  }
+}
+
+/*==================================================*/
+/* Wait until the controller's mailbox is available */
+/*==================================================*/
+static int busyWaitMbox(mega_host_config *megaCfg)
+{
+  mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox;
+  long          counter;
+
+  for(counter=0; counter<0xFFFFFF; counter++) {
+    if (!mbox->busy) return 0;
+  }
+  return -1;
+}
+
+/*=====================================================
+ * Post a command to the card
+ *
+ * Arguments:
+ *   mega_host_config *megaCfg - Controller structure
+ *   u_char *mboxData - Mailbox area, 16 bytes
+ *   mega_scb *pScb   - SCB posting (or NULL if N/A)
+ *   int intr         - if 1, interrupt, 0 is blocking
+ *=====================================================*/
+static int MegaIssueCmd(mega_host_config *megaCfg,
+                       u_char *mboxData,
+                       mega_scb *pScb,
+                       int intr)
+{
+  mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox;
+  long          flags;
+  u_char        byte;
+  u_long        cmdDone;
+
+  mboxData[0x1] = (pScb ? pScb->idx+1 : 0x00);  /* Set cmdid */
+  mboxData[0xF] = 1;                            /* Set busy */
+
+  /* one bad report of problem when issuing a command while pending.
+   * Wasn't able to duplicate, but it doesn't really affect performance
+   * anyway, so don't allow command while PENDING
+   */
+  if (megaCfg->flag & PENDING) {
+    return -1;
+  }
+
+  /* Wait until mailbox is free */
+  if (busyWaitMbox(megaCfg)) {
+    if (pScb) {
+      TRACE(("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number,
+            pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun));
+    }
+    return -1;
+  }
+
+  /* Copy mailbox data into host structure */
+  spin_lock_irqsave(&mega_lock,flags);
+  memset(mbox, 0, sizeof(mega_mailbox));
+  memcpy(mbox, mboxData, 16);
+  spin_unlock_irqrestore(&mega_lock,flags);
+
+  /* Kick IO */
+  megaCfg->flag |= PENDING;
+  if (intr) {
+    /* Issue interrupt (non-blocking) command */
+    if (megaCfg->flag & BOARD_QUARTZ) {
+        mbox->mraid_poll = 0; 
+        mbox->mraid_ack = 0; 
+        WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1);
+    } else {
+        ENABLE_INTR(megaCfg->host->io_port);
+        ISSUE_COMMAND(megaCfg->host->io_port);
+    }
+  }
+  else {      /* Issue non-ISR (blocking) command */
+
+    if (megaCfg->flag & BOARD_QUARTZ) {
+
+      mbox->mraid_poll = 0; 
+      mbox->mraid_ack = 0; 
+      WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1);
+
+      while((cmdDone=RDOUTDOOR(megaCfg)) != 0x10001234);
+      WROUTDOOR(megaCfg, cmdDone);
+
+      if (pScb) {
+       mega_cmd_done(megaCfg,pScb, mbox->status);
+       mega_rundoneq();
+      }
+
+      WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox) | 0x2);
+      while(RDINDOOR(megaCfg) & 0x2);
+
+      megaCfg->flag &= ~PENDING;
+    }
+    else {
+      DISABLE_INTR(megaCfg->host->io_port);
+      ISSUE_COMMAND(megaCfg->host->io_port);
+      
+      while(!((byte=READ_PORT(megaCfg->host->io_port,INTR_PORT))&INTR_VALID));
+      WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte);
+      
+      ENABLE_INTR(megaCfg->host->io_port);
+      CLEAR_INTR(megaCfg->host->io_port);
+      
+      if (pScb) {
+       mega_cmd_done(megaCfg,pScb, mbox->status);
+       mega_rundoneq();
+      }
+      megaCfg->flag &= ~PENDING;
+    }
+  }
+
+  return 0;
+}
+
+/*-------------------------------------------------------------------
+ * Copies data to SGLIST
+ *-------------------------------------------------------------------*/
+static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, 
+                       u_long *buffer, u_long *length)
+{
+  struct scatterlist *sgList;
+  int idx;
+
+  /* Scatter-gather not used */
+  if (scb->SCpnt->use_sg == 0) {
+    *buffer = virt_to_bus(scb->SCpnt->request_buffer);
+    *length = (u_long)scb->SCpnt->request_bufflen;
+    return 0;
+  }
+
+  sgList = (struct scatterlist *)scb->SCpnt->buffer;
+  if (scb->SCpnt->use_sg == 1) {
+    *buffer = virt_to_bus(sgList[0].address);
+    *length = (u_long)sgList[0].length;
+    return 0;
+  }
+
+  /* Copy Scatter-Gather list info into controller structure */
+  for(idx=0; idx<scb->SCpnt->use_sg; idx++) {
+    scb->sgList[idx].address = virt_to_bus(sgList[idx].address);
+    scb->sgList[idx].length  = (u_long)sgList[idx].length;
+  }
+  
+  /* Reset pointer and length fields */
+  *buffer = virt_to_bus(scb->sgList);
+  *length = 0;
+
+  /* Return count of SG requests */
+  return scb->SCpnt->use_sg;
+}
+    
+/*--------------------------------------------------------------------
+ * Initializes the adress of the controller's mailbox register
+ *  The mailbox register is used to issue commands to the card.
+ *  Format of the mailbox area:
+ *   00 01 command
+ *   01 01 command id
+ *   02 02 # of sectors
+ *   04 04 logical bus address
+ *   08 04 physical buffer address
+ *   0C 01 logical drive #
+ *   0D 01 length of scatter/gather list
+ *   0E 01 reserved
+ *   0F 01 mailbox busy
+ *   10 01 numstatus byte
+ *   11 01 status byte
+ *--------------------------------------------------------------------*/
+static int mega_register_mailbox(mega_host_config *megaCfg, u_long paddr)
+{
+  /* align on 16-byte boundry */
+  megaCfg->mbox = &megaCfg->mailbox;
+  megaCfg->mbox = (mega_mailbox *) ((((ulong)megaCfg->mbox) + 16)&0xfffffff0);
+  paddr = (paddr+16)&0xfffffff0;
+
+  /* Register mailbox area with the firmware */
+  if (megaCfg->flag & BOARD_QUARTZ) {
+  }
+  else {
+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT0, paddr         & 0xFF);
+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT1, (paddr >>  8) & 0xFF);
+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF);
+    WRITE_PORT(megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF);
+    WRITE_PORT(megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE);
+    
+    CLEAR_INTR(megaCfg->host->io_port);
+    ENABLE_INTR(megaCfg->host->io_port);
+  }
+  return 0;
+}
+
+/*-------------------------------------------------------------------
+ * Issue an adapter info query to the controller
+ *-------------------------------------------------------------------*/
+static int mega_i_query_adapter(mega_host_config *megaCfg)
+{
+  mega_RAIDINQ *adapterInfo;
+  mega_mailbox *mbox;
+  u_char        mboxData[16];
+  u_long        paddr;
+
+  spin_lock_init(&mega_lock);
+  /* Initialize adapter inquiry */
+  paddr = virt_to_bus(megaCfg->mega_buffer);
+  mbox  = (mega_mailbox *)mboxData;
+
+  memset((void *)megaCfg->mega_buffer, 0, sizeof(megaCfg->mega_buffer));
+  memset(mbox, 0, 16);
+
+  /* Initialize mailbox registers */
+  mbox->cmd      = MEGA_MBOXCMD_ADAPTERINQ;
+  mbox->xferaddr = paddr;
+
+  /* Issue a blocking command to the card */
+  MegaIssueCmd(megaCfg, mboxData, NULL, 0);
+  
+  /* Initialize host/local structures with Adapter info */
+  adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer;
+  megaCfg->host->max_channel = adapterInfo->AdpInfo.ChanPresent;
+  megaCfg->host->max_id      = adapterInfo->AdpInfo.MaxTargPerChan;
+  megaCfg->numldrv           = adapterInfo->LogdrvInfo.NumLDrv;
+
+#if 0
+  printk(KERN_DEBUG "---- Logical drive info ----\n");
+  for(i=0; i<megaCfg->numldrv; i++) {
+    printk(KERN_DEBUG "%d: size: %ld prop: %x state: %x\n",i,
+          adapterInfo->LogdrvInfo.LDrvSize[i],
+          adapterInfo->LogdrvInfo.LDrvProp[i],
+          adapterInfo->LogdrvInfo.LDrvState[i]);
+  }
+  printk(KERN_DEBUG "---- Physical drive info ----\n");
+  for(i=0; i<MAX_PHYSICAL_DRIVES; i++) {
+    if (i && !(i % 8)) printk("\n");
+    printk("%d: %x   ", i, adapterInfo->PhysdrvInfo.PDrvState[i]);
+  }
+  printk("\n");
+#endif
+
+  megaCfg->max_cmds = adapterInfo->AdpInfo.MaxConcCmds;
+
+#ifdef HP            /* use HP firmware and bios version encoding */
+      sprintf(megaCfg->fwVer,"%c%d%d.%d%d",
+          adapterInfo->AdpInfo.FwVer[2],
+          adapterInfo->AdpInfo.FwVer[1] >> 8,
+          adapterInfo->AdpInfo.FwVer[1] & 0x0f,
+          adapterInfo->AdpInfo.FwVer[2] >> 8,
+          adapterInfo->AdpInfo.FwVer[2] & 0x0f);
+      sprintf(megaCfg->biosVer,"%c%d%d.%d%d",
+          adapterInfo->AdpInfo.BiosVer[2],
+          adapterInfo->AdpInfo.BiosVer[1] >> 8,
+          adapterInfo->AdpInfo.BiosVer[1] & 0x0f,
+          adapterInfo->AdpInfo.BiosVer[2] >> 8,
+          adapterInfo->AdpInfo.BiosVer[2] & 0x0f);
+#else
+      memcpy(megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4);
+      megaCfg->fwVer[4] = 0;
+
+      memcpy(megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4);
+      megaCfg->biosVer[4] = 0;
+#endif
+
+  printk(KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR,
+        megaCfg->fwVer,
+        megaCfg->biosVer,
+        megaCfg->numldrv);
+  return 0;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ *                      Driver interface functions
+ *
+ *-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------
+ * Returns data to be displayed in /proc/scsi/megaraid/X
+ *----------------------------------------------------------*/
+int megaraid_proc_info(char *buffer, char **start, off_t offset,
+                      int length, int inode, int inout)
+{
+  *start = buffer;
+  return 0;
+}
+
+int findCard(Scsi_Host_Template *pHostTmpl, 
+            u_short pciVendor, u_short pciDev,
+            long flag)
+{
+  mega_host_config *megaCfg;
+  struct Scsi_Host *host;
+  u_char            pciBus, pciDevFun, megaIrq;
+  u_long            megaBase;
+  u_short           pciIdx = 0;
+
+#if LINUX_VERSION_CODE < 0x20100
+  while(!pcibios_find_device(pciVendor, pciDev, pciIdx,&pciBus,&pciDevFun)) {
+#else
+  struct pci_dev   *pdev=pci_devices;
+
+  while((pdev = pci_find_device(pciVendor, pciDev, pdev))) {
+    pciBus = pdev->bus->number;
+    pciDevFun = pdev->devfn;
+#endif
+    printk(KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n",
+          pciVendor, 
+          pciDev, 
+          pciIdx, pciBus, 
+          PCI_SLOT(pciDevFun), 
+          PCI_FUNC(pciDevFun));
+    
+    /* Read the base port and IRQ from PCI */
+#if LINUX_VERSION_CODE < 0x20100
+    pcibios_read_config_dword(pciBus, pciDevFun,
+                            PCI_BASE_ADDRESS_0,
+                            (u_int *)&megaBase);
+    pcibios_read_config_byte(pciBus, pciDevFun,                               
+                            PCI_INTERRUPT_LINE,
+                            &megaIrq);
+#else
+    megaBase = pdev->base_address[0];
+    megaIrq = pdev->irq;
+#endif
+    pciIdx++;
+
+    if (flag & BOARD_QUARTZ) {
+      megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
+      megaBase = (long) ioremap(megaBase,128);
+    }
+    else {
+      megaBase &= PCI_BASE_ADDRESS_IO_MASK;
+      megaBase += 0x10;
+    }
+
+    /* Initialize SCSI Host structure */
+    host    = scsi_register(pHostTmpl, sizeof(mega_host_config));
+    megaCfg = (mega_host_config *)host->hostdata;
+    memset(megaCfg, 0, sizeof(mega_host_config));
+
+    printk(KERN_INFO " scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, 
+          host->host_no, (u_int)megaBase, megaIrq);
+    
+    /* Copy resource info into structure */
+    megaCfg->flag            = flag;
+    megaCfg->host            = host;
+    megaCfg->base            = megaBase;
+    megaCfg->host->irq       = megaIrq;
+    megaCfg->host->io_port   = megaBase;
+    megaCfg->host->n_io_port = 16;
+    megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
+    megaCtlrs[numCtlrs++]    = megaCfg;
+
+    if (flag != BOARD_QUARTZ) {
+      /* Request our IO Range */
+      if (check_region(megaBase, 16)) {
+       printk(KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR);
+       scsi_unregister(host);
+       continue;
+      }
+      request_region(megaBase, 16, "megaraid");
+    }
+
+    /* Request our IRQ */
+    if (request_irq(megaIrq, megaraid_isr, SA_SHIRQ, 
+                   "megaraid", megaCfg)) {
+      printk(KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR,
+            megaIrq);
+      scsi_unregister(host);
+      continue;
+    }
+
+    mega_register_mailbox(megaCfg, virt_to_bus((void*)&megaCfg->mailbox));
+    mega_i_query_adapter(megaCfg);
+
+    /* Initialize SCBs */
+    initSCB(megaCfg);
+
+  }
+  return pciIdx;
+}
+
+/*---------------------------------------------------------
+ * Detects if a megaraid controller exists in this system
+ *---------------------------------------------------------*/
+int megaraid_detect(Scsi_Host_Template *pHostTmpl)
+{
+  int count = 0;
+
+  pHostTmpl->proc_dir = &proc_scsi_megaraid;
+
+#if LINUX_VERSION_CODE < 0x20100
+  if (!pcibios_present()) 
+    {
+      printk(KERN_WARNING "megaraid: PCI bios not present." CRLFSTR);
+      return 0;
+    }
+#endif
+
+  count += findCard(pHostTmpl, 0x101E, 0x9010, 0);
+  count += findCard(pHostTmpl, 0x101E, 0x9060, 0);
+  count += findCard(pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+
+  return count;
+}
+
+/*---------------------------------------------------------------------
+ * Release the controller's resources
+ *---------------------------------------------------------------------*/
+int megaraid_release(struct Scsi_Host *pSHost)
+{
+  mega_host_config *megaCfg;
+  mega_mailbox         *mbox;
+  u_char                mboxData[16];
+
+  megaCfg = (mega_host_config*)pSHost->hostdata;
+  mbox    = (mega_mailbox *)mboxData;
+
+  /* Flush cache to disk */
+  memset(mbox, 0, 16);
+  mboxData[0] = 0xA;
+
+  /* Issue a blocking (interrupts disabled) command to the card */
+  MegaIssueCmd(megaCfg, mboxData, NULL, 0);
+
+  schedule();
+
+  /* Free our resources */
+  if (megaCfg->flag & BOARD_QUARTZ) {
+      iounmap((void *)megaCfg->base);
+  } else {
+      release_region(megaCfg->host->io_port, 16);
+  }
+  free_irq(megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise
+                                            extra interrupt is generated */
+  scsi_unregister(pSHost);
+
+  return 0;
+}
+
+/*----------------------------------------------
+ * Get information about the card/driver 
+ *----------------------------------------------*/
+const char *megaraid_info(struct Scsi_Host *pSHost)
+{
+  static char           buffer[512];
+  mega_host_config  *megaCfg;
+  mega_RAIDINQ          *adapterInfo;
+
+  megaCfg     = (mega_host_config *)pSHost->hostdata;
+  adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer;
+
+  sprintf(buffer, "AMI MegaRAID %s %d commands %d targs %d chans",
+         megaCfg->fwVer,
+         adapterInfo->AdpInfo.MaxConcCmds,
+         megaCfg->host->max_id,
+         megaCfg->host->max_channel);
+  return buffer;
+}
+
+/*-----------------------------------------------------------------
+ * Perform a SCSI command
+ * Mailbox area:
+ *   00 01 command
+ *   01 01 command id
+ *   02 02 # of sectors
+ *   04 04 logical bus address
+ *   08 04 physical buffer address
+ *   0C 01 logical drive #
+ *   0D 01 length of scatter/gather list
+ *   0E 01 reserved
+ *   0F 01 mailbox busy
+ *   10 01 numstatus byte
+ *   11 01 status byte 
+ *-----------------------------------------------------------------*/
+int megaraid_queue(Scsi_Cmnd *SCpnt, void (*pktComp)(Scsi_Cmnd *))
+{
+  mega_host_config *megaCfg;
+  mega_scb         *pScb;
+
+  megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+
+  if (!(megaCfg->flag & (1L << SCpnt->channel))) {
+    printk(KERN_INFO "scsi%d: scanning channel %c for devices.\n",
+          megaCfg->host->host_no,
+          SCpnt->channel + 'A');
+    megaCfg->flag |= (1L << SCpnt->channel);
+  }
+
+  SCpnt->scsi_done = pktComp;
+
+  /* Allocate and build a SCB request */
+  if ((pScb = mega_build_cmd(megaCfg, SCpnt)) != NULL) {
+    /* Add SCB to the head of the pending queue */
+    ENQUEUE(pScb, mega_scb, qPending, next);
+
+    /* Issue the command to the card */
+      mega_runque(NULL);
+  }
+
+  return 0;
+}
+
+/*----------------------------------------------------------------------
+ * Issue a blocking command to the controller
+ *
+ * Note - this isnt 2.0.x SMP safe
+ *----------------------------------------------------------------------*/
+volatile static int internal_done_flag    = 0;
+volatile static int internal_done_errcode = 0;
+
+static void internal_done(Scsi_Cmnd *SCpnt)
+{
+  internal_done_errcode = SCpnt->result;
+  internal_done_flag++;
+}
+
+/*
+ *     This seems dangerous in an SMP environment because 
+ *     while spinning on internal_done_flag in 2.0.x SMP
+ *     no IRQ's will be taken, including those that might
+ *     be needed to clear this.
+ *
+ *     I think this should be using a wait queue ?
+ *                             -- AC
+ */
+int megaraid_command(Scsi_Cmnd *SCpnt)
+{
+  internal_done_flag = 0;
+
+  /* Queue command, and wait until it has completed */
+  megaraid_queue(SCpnt, internal_done);
+
+  while(!internal_done_flag)
+    barrier();
+
+  return internal_done_errcode;
+}
+
+/*---------------------------------------------------------------------
+ * Abort a previous SCSI request
+ *---------------------------------------------------------------------*/
+int megaraid_abort(Scsi_Cmnd *SCpnt)
+{
+  mega_host_config *megaCfg;
+  int       idx;
+  long      flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
+
+  megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+
+  TRACE(("ABORT!!! %.08lx %.02x <%d.%d.%d>\n",
+        SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, 
+        SCpnt->lun));
+  /*
+   * Walk list of SCBs for any that are still outstanding
+   */
+  for(idx=0; idx<megaCfg->max_cmds; idx++) {
+    if (megaCfg->scbList[idx].idx >= 0) {
+      if (megaCfg->scbList[idx].SCpnt == SCpnt) {
+       freeSCB(&megaCfg->scbList[idx]);
+
+       SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24);
+       callDone(SCpnt);
+      }
+    }
+  }
+  spin_unlock_irqrestore(&mega_lock,flags);
+  return SCSI_ABORT_SNOOZE;
+}
+
+/*---------------------------------------------------------------------
+ * Reset a previous SCSI request
+ *---------------------------------------------------------------------*/
+int megaraid_reset(Scsi_Cmnd *SCpnt, unsigned int rstflags)
+{
+  mega_host_config *megaCfg;
+  int       idx;
+  long      flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
+
+  megaCfg = (mega_host_config *)SCpnt->host->hostdata;
+
+  TRACE(("RESET: %.08lx %.02x <%d.%d.%d>\n",
+        SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, 
+        SCpnt->lun));
+
+  /*
+   * Walk list of SCBs for any that are still outstanding
+   */
+  for(idx=0; idx<megaCfg->max_cmds; idx++) {
+    if (megaCfg->scbList[idx].idx >= 0) {
+      SCpnt = megaCfg->scbList[idx].SCpnt;
+      freeSCB(&megaCfg->scbList[idx]);
+      SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24);
+      callDone(SCpnt);
+    }
+  }
+  spin_unlock_irqrestore(&mega_lock,flags);
+  return SCSI_RESET_PUNT;
+} 
+
+/*-------------------------------------------------------------
+ * Return the disk geometry for a particular disk
+ * Input:
+ *   Disk *disk - Disk geometry
+ *   kdev_t dev - Device node
+ *   int *geom  - Returns geometry fields
+ *     geom[0] = heads
+ *     geom[1] = sectors
+ *     geom[2] = cylinders
+ *-------------------------------------------------------------*/
+int megaraid_biosparam(Disk *disk, kdev_t dev, int *geom)
+{
+  int                   heads, sectors, cylinders;
+  mega_host_config *megaCfg;
+
+  /* Get pointer to host config structure */
+  megaCfg = (mega_host_config *)disk->device->host->hostdata;
+
+  /* Default heads (64) & sectors (32) */
+  heads     = 64;
+  sectors   = 32;
+  cylinders = disk->capacity / (heads * sectors);
+
+  /* Handle extended translation size for logical drives > 1Gb */
+  if (disk->capacity >= 0x200000) {
+    heads     = 255;
+    sectors   = 63;
+    cylinders = disk->capacity / (heads * sectors);
+  }
+
+  /* return result */
+  geom[0] = heads;
+  geom[1] = sectors;
+  geom[2] = cylinders;
+
+  return 0;
+}
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = MEGARAID;
+
+#include "scsi_module.c"
+#endif
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
new file mode 100644 (file)
index 0000000..5442407
--- /dev/null
@@ -0,0 +1,282 @@
+#ifndef __MEGARAID_H__
+#define __MEGARAID_H__
+
+#define IN_ISR                  0x80000000L
+#define NO_INTR                 0x40000000L
+#define IN_TIMEOUT              0x20000000L
+#define PENDING                 0x10000000L
+#define BOARD_QUARTZ            0x08000000L
+
+#define SCB_ACTIVE 0x1
+#define SCB_WAITQ  0x2
+#define SCB_ISSUED 0x4
+
+#define SCB_FREE                -1
+#define SCB_RESET               -2
+#define SCB_ABORT               -3
+#define SCB_LOCKED              -4
+
+#define MEGA_CMD_TIMEOUT        10
+
+#define MAX_SGLIST              20
+#define MAX_COMMANDS            254
+
+#define MAX_LOGICAL_DRIVES      8
+#define MAX_CHANNEL             5
+#define MAX_TARGET              15
+#define MAX_PHYSICAL_DRIVES     MAX_CHANNEL*MAX_TARGET
+
+#define INQUIRY_DATA_SIZE       0x24
+#define MAX_CDB_LEN             0x0A
+#define MAX_REQ_SENSE_LEN       0x20
+
+#define INTR_VALID              0x40
+
+/* Mailbox commands */
+#define MEGA_MBOXCMD_LREAD      0x01
+#define MEGA_MBOXCMD_LWRITE     0x02
+#define MEGA_MBOXCMD_PASSTHRU   0x03
+#define MEGA_MBOXCMD_ADAPTERINQ 0x05
+
+/* Offsets into Mailbox */
+#define COMMAND_PORT       0x00
+#define COMMAND_ID_PORT    0x01
+#define SG_LIST_PORT0      0x08
+#define SG_LIST_PORT1      0x09
+#define SG_LIST_PORT2      0x0a
+#define SG_LIST_PORT3      0x0b
+#define SG_ELEMENT_PORT    0x0d
+#define NO_FIRED_PORT      0x0f
+
+/* I/O Port offsets */
+#define I_CMD_PORT         0x00
+#define I_ACK_PORT         0x00
+#define I_TOGGLE_PORT      0x01
+#define INTR_PORT          0x0a
+
+#define MAILBOX_SIZE       70
+#define MBOX_BUSY_PORT     0x00
+#define MBOX_PORT0         0x04
+#define MBOX_PORT1         0x05
+#define MBOX_PORT2         0x06
+#define MBOX_PORT3         0x07
+#define ENABLE_MBOX_REGION 0x0B
+
+/* I/O Port Values */
+#define ISSUE_BYTE         0x10
+#define ACK_BYTE           0x08
+#define ENABLE_INTR_BYTE   0xc0
+#define DISABLE_INTR_BYTE  0x00
+#define VALID_INTR_BYTE    0x40
+#define MBOX_BUSY_BYTE     0x10
+#define ENABLE_MBOX_BYTE   0x00
+
+/* Setup some port macros here */
+#define WRITE_MAILBOX(base,offset,value)   *(base+offset)=value
+#define READ_MAILBOX(base,offset)          *(base+offset)
+
+#define WRITE_PORT(base,offset,value)      outb_p(value,base+offset)
+#define READ_PORT(base,offset)             inb_p(base+offset)
+
+#define ISSUE_COMMAND(base)   WRITE_PORT(base,I_CMD_PORT,ISSUE_BYTE)
+#define CLEAR_INTR(base)      WRITE_PORT(base,I_ACK_PORT,ACK_BYTE)
+#define ENABLE_INTR(base)     WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE)
+#define DISABLE_INTR(base)    WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE)
+
+/* Define AMI's PCI codes */
+#undef PCI_VENDOR_ID_AMI
+#undef PCI_DEVICE_ID_AMI_MEGARAID
+
+#ifndef PCI_VENDOR_ID_AMI
+#define PCI_VENDOR_ID_AMI          0x101E
+#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010
+#endif
+
+#define PCI_CONF_BASE_ADDR_OFFSET  0x10
+#define PCI_CONF_IRQ_OFFSET        0x3c
+
+#if LINUX_VERSION_CODE < 0x20100
+#define MEGARAID \
+  { NULL,                               /* Next                      */\
+    NULL,                               /* Usage Count Pointer       */\
+    NULL,                               /* /proc Directory Entry     */\
+    megaraid_proc_info,                 /* /proc Info Function       */\
+    "MegaRAID",                         /* Driver Name               */\
+    megaraid_detect,                    /* Detect Host Adapter       */\
+    megaraid_release,                   /* Release Host Adapter      */\
+    megaraid_info,                      /* Driver Info Function      */\
+    megaraid_command,                   /* Command Function          */\
+    megaraid_queue,                     /* Queue Command Function    */\
+    megaraid_abort,                     /* Abort Command Function    */\
+    megaraid_reset,                     /* Reset Command Function    */\
+    NULL,                               /* Slave Attach Function     */\
+    megaraid_biosparam,                 /* Disk BIOS Parameters      */\
+    1,                                  /* # of cmds that can be\
+                                           outstanding at any time */\
+    7,                                  /* HBA Target ID             */\
+    MAX_SGLIST,                         /* Scatter/Gather Table Size */\
+    1,                                  /* SCSI Commands per LUN     */\
+    0,                                  /* Present                   */\
+    0,                                  /* Default Unchecked ISA DMA */\
+    ENABLE_CLUSTERING }                 /* Enable Clustering         */
+#else
+#define MEGARAID \
+  {\
+    name:            "MegaRAID",               /* Driver Name               */\
+    proc_info:        megaraid_proc_info,      /* /proc driver info         */\
+    detect:           megaraid_detect,         /* Detect Host Adapter       */\
+    release:          megaraid_release,        /* Release Host Adapter      */\
+    info:             megaraid_info,           /* Driver Info Function      */\
+    command:          megaraid_command,        /* Command Function          */\
+    queuecommand:     megaraid_queue,          /* Queue Command Function    */\
+    abort:            megaraid_abort,          /* Abort Command Function    */\
+    reset:            megaraid_reset,          /* Reset Command Function    */\
+    bios_param:       megaraid_biosparam,      /* Disk BIOS Parameters      */\
+    can_queue:        255,                     /* Can Queue                 */\
+    this_id:          7,                       /* HBA Target ID             */\
+    sg_tablesize:     MAX_SGLIST,              /* Scatter/Gather Table Size */\
+    cmd_per_lun:      1,                       /* SCSI Commands per LUN     */\
+    present:          0,                       /* Present                   */\
+    unchecked_isa_dma:0,                       /* Default Unchecked ISA DMA */\
+    use_clustering:   ENABLE_CLUSTERING       /* Enable Clustering         */\
+  }
+#endif
+
+/* Structures */
+typedef struct _mega_ADP_INFO
+{
+  u_char    MaxConcCmds;
+  u_char    RbldRate;
+  u_char    MaxTargPerChan;
+  u_char    ChanPresent;
+  u_char    FwVer[4];
+  u_short   AgeOfFlash;
+  u_char    ChipSet;
+  u_char    DRAMSize;
+  u_char    CacheFlushInterval;
+  u_char    BiosVer[4];
+  u_char    resvd[7];
+} mega_ADP_INFO;
+
+typedef struct _mega_LDRV_INFO
+{
+  u_char   NumLDrv;
+  u_char   resvd[3];
+  u_long   LDrvSize[MAX_LOGICAL_DRIVES];
+  u_char   LDrvProp[MAX_LOGICAL_DRIVES];
+  u_char   LDrvState[MAX_LOGICAL_DRIVES];
+} mega_LDRV_INFO;
+
+typedef struct _mega_PDRV_INFO
+{
+  u_char   PDrvState[MAX_PHYSICAL_DRIVES];
+  u_char   resvd;
+} mega_PDRV_INFO;
+
+// RAID inquiry: Mailbox command 0x5
+typedef struct _mega_RAIDINQ
+{
+  mega_ADP_INFO    AdpInfo;
+  mega_LDRV_INFO   LogdrvInfo;
+  mega_PDRV_INFO   PhysdrvInfo;
+} mega_RAIDINQ;
+
+// Passthrough command: Mailbox command 0x3
+typedef struct mega_passthru
+{
+  u_char            timeout:3;              /* 0=6sec/1=60sec/2=10min/3=3hrs */
+  u_char            ars:1;
+  u_char            reserved:3;
+  u_char            islogical:1;
+  u_char            logdrv;                 /* if islogical == 1 */
+  u_char            channel;                /* if islogical == 0 */
+  u_char            target;                 /* if islogical == 0 */
+  u_char            queuetag;               /* unused */
+  u_char            queueaction;            /* unused */
+  u_char            cdb[MAX_CDB_LEN];
+  u_char            cdblen;
+  u_char            reqsenselen;
+  u_char            reqsensearea[MAX_REQ_SENSE_LEN];
+  u_char            numsgelements;
+  u_char            scsistatus;
+  u_long            dataxferaddr;
+  u_long            dataxferlen;
+} mega_passthru;
+
+typedef struct _mega_mailbox
+{
+  /* 0x0 */ u_char    cmd;
+  /* 0x1 */ u_char    cmdid;
+  /* 0x2 */ u_short   numsectors;
+  /* 0x4 */ u_long    lba;
+  /* 0x8 */ u_long    xferaddr;
+  /* 0xC */ u_char    logdrv;
+  /* 0xD */ u_char    numsgelements;
+  /* 0xE */ u_char    resvd;
+  /* 0xF */ u_char    busy;
+  /* 0x10*/ u_char    numstatus;
+  /* 0x11*/ u_char    status;
+  /* 0x12*/ u_char    completed[46];
+            u_char    mraid_poll;
+            u_char    mraid_ack;
+            u_char    pad[16];
+} mega_mailbox;
+
+typedef struct _mega_sglist
+{
+  u_long     address;
+  u_long     length;
+} mega_sglist;
+
+/* Queued command data */
+typedef struct _mega_scb mega_scb;
+
+struct _mega_scb
+{
+  int             idx;
+  u_long          flag;
+  Scsi_Cmnd      *SCpnt;
+  u_char          mboxData[16];
+  mega_passthru   pthru;
+  mega_sglist    *sgList;
+  mega_scb       *next;
+};
+
+/* Per-controller data */
+typedef struct _mega_host_config
+{
+  u_char               numldrv;
+  u_long               flag;
+  u_long               base;
+
+  struct tq_struct     megaTq;
+
+  /* Host adapter parameters */
+  u_char               fwVer[7];
+  u_char               biosVer[7];
+
+  struct Scsi_Host     *host;
+
+  /* The following must be DMA-able!! */
+  volatile mega_mailbox *mbox;
+  volatile mega_mailbox mailbox;
+  volatile u_char       mega_buffer[2*1024L];
+
+  u_char                max_cmds;
+  mega_scb              scbList[MAX_COMMANDS];
+} mega_host_config;
+
+extern struct proc_dir_entry proc_scsi_megaraid;
+
+const char *megaraid_info( struct Scsi_Host * );
+int        megaraid_detect( Scsi_Host_Template * );
+int        megaraid_release(struct Scsi_Host *);
+int        megaraid_command( Scsi_Cmnd * );
+int        megaraid_abort( Scsi_Cmnd * );
+int        megaraid_reset( Scsi_Cmnd *, unsigned int); 
+int        megaraid_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
+int        megaraid_biosparam( Disk *, kdev_t, int * );
+int        megaraid_proc_info( char *buffer, char **start, off_t offset,
+                              int length, int hostno, int inout );
+
+#endif
index 91e26cd1d4bed66ed23975a5228b7614d13a2297..c58dd39b2abd6d376164876f7404aa33f7560124 100644 (file)
@@ -159,8 +159,10 @@ int ppa_biosparam(Disk *, kdev_t, int *);
                release:                        ppa_release,            \
                command:                        ppa_command,            \
                queuecommand:                   ppa_queuecommand,       \
-               abort:                          ppa_abort,              \
-               reset:                          ppa_reset,              \
+               eh_abort_handler:               ppa_abort,              \
+               eh_device_reset_handler:        NULL,                   \
+               eh_bus_reset_handler:           ppa_reset,              \
+               eh_host_reset_handler:          ppa_reset,              \
                bios_param:                     ppa_biosparam,          \
                this_id:                        -1,                     \
                sg_tablesize:                   SG_ALL,                 \
index f56fdda55ceeb70b9804e777749d612668aa29e4..67fde6e8ac0a58625e5502184c9e0a48292e6352 100644 (file)
@@ -523,9 +523,18 @@ static void scan_scsis (struct Scsi_Host *shpnt,
 
   }
   else {
+    /* Actual LUN. PC ordering is 0->n IBM/spec ordering is n->0 */
+    int order_dev;
+    
     for (channel = 0; channel <= shpnt->max_channel; channel++) {
       for (dev = 0; dev < shpnt->max_id; ++dev) {
-        if (shpnt->this_id != dev) {
+        if( shpnt->reverse_ordering)
+               /* Shift to scanning 15,14,13... or 7,6,5,4, */
+               order_dev = shpnt->max_channel-dev-1;
+        else
+               order_dev = dev;
+               
+        if (shpnt->this_id != order_dev) {
 
           /*
            * We need the for so our continue, etc. work fine. We put this in
@@ -536,7 +545,7 @@ static void scan_scsis (struct Scsi_Host *shpnt,
                          max_scsi_luns : shpnt->max_lun);
          sparse_lun = 0;
           for (lun = 0; lun < max_dev_lun; ++lun) {
-            if (!scan_scsis_single (channel, dev, lun, &max_dev_lun,
+            if (!scan_scsis_single (channel, order_dev, lun, &max_dev_lun,
                                    &sparse_lun, &SDpnt, SCpnt, shpnt,
                                    scsi_result)
                && !sparse_lun)
@@ -2745,7 +2754,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
         {
             if(SDpnt->host->hostt == tpnt 
                && SDpnt->host->hostt->module
-               && SDpnt->host->hostt->module->usecount) return;
+               && GET_USE_COUNT(SDpnt->host->hostt->module)) return;
             /* 
              * FIXME(eric) - We need to find a way to notify the
              * low level driver that we are shutting down - via the
@@ -3034,7 +3043,7 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
     /*
      * If we are busy, this is not going to fly.
      */
-    if(tpnt->module->usecount != 0) return 0;
+    if(GET_USE_COUNT(tpnt->module) != 0) return 0;
 
     /*
      * Next, detach the devices from the driver.
index caea148966a5dfc7e7f5b07cf1e701fe567f1737..c5d77d4a049f432361521c963ffa1ebf3bc354b4 100644 (file)
@@ -27,10 +27,7 @@ Thu Dec  3 17:25:31 1998  Al Viro (viro@math.psu.edu)
                the directory we remove is the same as parent (BUG: we
                serve mountpoints later) or if it lives on a different
                device.
-       * sysvfs/namei.c (sysv_rmdir):
-               Bugectomy: old check for victim being busy (inode->i_count)
-               wasn't replaced (with checking dentry->d_count) and escaped
-               Linus in the last round of changes. Shot and buried.
+       * sysv/namei.c (sysv_rmdir):    See sysv/CHANGES
 
 Fri Dec  4 00:54:12 1998  AV
 
@@ -66,9 +63,114 @@ Fri Dec  4 10:30:58 1998  AV
        * kernel/ksyms.c: Added VFS_rmdir to export list (for NFSD).
        * nfsd/vfs.c: Fixed rmdir handling.
 
-       Remaining problems with rmdir:
-               UMSDOS_rename is broken. Call it with the dest. existing and
-               being an empty directory and you've got EBUSY. At least it
-               doesn't do any harm, so that will wait several days till rename
-               cleanup.
-       TODO: unlink handling in NFSD does no tests.
+Tue Dec  8 05:55:08 1998  AV
+       * vfat/namei.c: Fixed the bug in vfat_rename() introduced in the
+               first round of rmdir fixes.
+
+Wed Dec  9 03:06:10 1998  AV
+       * namei.c (do_rename): part of fs-independent checks had been moved
+               here (sticky bit handling, type mismatches). Cases of
+               the source or target being append-only or immutable also went
+               here - if we check it for parent we could as well do it for
+               children.
+       * {affs,ext2,minix,sysv,ufs}/namei.c (do_*_rename):
+               Removed tests that went to VFS, it simplified the code big way.
+               Fixed a race in check for empty target - we should check for
+               extra owners _before_ checking for emptiness, not after it.
+       * {ext2,ufs}/namei.c (do_*_rename):
+               VERY nasty bug shot: if somebody mkdired /tmp/cca01234, went
+               there, rmdired '.', waited till somebody created a file with
+               the same name and said mv . /tmp/goodbye_sticky_bit... Well,
+               goodbye sticky bit. Down, not across!
+       * {minix,sysv}/namei.c (do_*_rename):
+               Incorrect check for other owners (i_count instead of d_count).
+               Fixed.
+       * vfat: Looks like the changes above fixed a bug in VFAT - this beast
+               used to allow renaming file over directory and vice versa.
+
+Wed Dec  9 08:00:27 1998  AV
+       * namei.c (VFS_rename): New function. It gets the same arguments as
+               ->rename() method, does all checks and applies fs-specific
+               rmdir() method. It should be called with semaphores down
+               on both parents.
+       * include/linux/fs.h: Added VFS_rename
+       * kernel/ksyms.c: Added VFS_rename to export list (for NFSD).
+       * nfsd/vfs.c: Changed rename handling (switched to VFS_rename).
+
+Wed Dec  9 18:16:27 1998  AV
+       * namei.c (do_unlink): handling of sticky bit went here.
+       * {affs,ext2,minix,qnx4,sysv,ufs}/namei.c (*_unlink):
+               removed handling of sticky bit.
+       * qnx4/namei.c (qnx4_unlink):
+               Yet another inode leak. Fixed.
+
+Thu Dec 10 04:55:26 1998  AV
+       * {ext2,minix,sysv,ufs}/namei.c (*_mknod):
+               removed meaningless code handling attempts to mknod symlinks
+               and directories. VFS protects us from _that_ and if this code
+               would ever be called we'ld get a filesystem corruption.
+
+Thu Dec 10 16:58:50 1998  AV
+       * namei.c (do_rename): Fixed dentry leak that had been introduced by
+               the first round of rmdir fixes.
+
+Fri Dec 11 14:57:17 1998  AV
+       * msdos/namei.c (msdos_rmdir): Fixed race in emptiness check.
+
+Sat Dec 12 19:59:57 1998  AV
+       * msdos/namei.c (msdos_mkdir): Fixed the evil breakage introduced by
+               the changes of rmdir locking scheme. We shouldn't call
+               msdos_rmdir from there.
+
+Sun Dec 13 02:05:16 1998  AV
+       * namei.c (do_unlink):
+               Added new function: vfs_unlink, with the same arguments as
+               ->unlink() method.
+       * kernel/ksyms.c: Made it exported.
+       * include/linux/fs.h: Added prototype.
+       * nfsd/vfs.c: Changed handling of unlink (switched to vfs_unlink)
+       * {ext2,ufs}/namei.c (*_unlink): moved handling of imm./append-only to
+               VFS.
+
+Wed Dec 16 06:10:04 1998  AV
+       * namei.c (may_create, may_delete): New inline functions.
+               They check whether creation/deletion is permitted.
+               Checks from other places of namei.c went there.
+               Looks like originally I misread permission-related stuff
+               both here and in nfsd. In particular, checks for
+               immutable are done in permission(). D'oh.
+       * unlink on directory should return -EISDIR, not -EPERM as it used to
+               do. Fixed.
+       * rmdir of immutable/append-only directory shouldn't be allowed. Fixed.
+
+Remains unfixed:
+       * UMSDOS_rename is broken. Call it with the dest. existing and being an
+               empty directory and you've got EBUSY. At least it doesn't do
+               any harm, so that will wait several days till rename cleanup.
+               Sigh... It will wait a bit more. Problems with fat-derived
+               filesystems are much worse than I thought. Idea of changing
+               inode under dentry is broken by design - guess where the
+               semaphore sits, for one.
+       * umsdos: weird. rename() shouldn't return -EEXIST. BTW, manpage
+               for rename(2) is obviously bogus - it mentions EEXIST and
+               on the next line (correctly) says that EINVAL should be
+               returned. Under the same conditions.
+       * rename's handling of races is, erm, not optimal. Looks like I know
+               what to do, but this thing needs some more cleanup - we can
+               take care of almost all races in VFS and be much more graceful
+               wrt locking. Moreover, it would give strong lookup atomicity.
+               But it's a lot of changes to lookup and dcache code, so it will
+               go after the fs drivers' cleanup.
+       * hfs allows mknod. Only for regular files ;-/ IMHO it's bogus.
+       * affs allows HARD links to directories. VFS is, to put it politely,
+               not too ready to cope with _that_. And I'm not sure it should
+               be - looks like they are pretty much similar to symlinks.
+       * truncate doesn't give a damn about IO errors and disk overflows (on
+               braindead filesystems). I've submitted a patch to Linus, but
+               looks like it wasn't applied.
+       * msdos: shouldn't we treat SYS as IMMUTABLE? Makes sense, IMHO.
+       * minix, qnx and sysv do NOT allow to mkdir sticky directories.
+       * {minix,sysv}/namei.c (do_{minix,syv}_{rename,unlink}):
+               Stuff related to retries still needs cleanup/fixing.
+               Looks like I've found an extremely low-probability race
+               there...
index 6114e1414db26635fbde2516f6cba5556a24e44c..a18c23a0f05a419bb7409d3c7cf1422de7f43d9c 100644 (file)
@@ -241,10 +241,6 @@ affs_unlink(struct inode *dir, struct dentry *dentry)
                goto unlink_done;
 
        inode  = dentry->d_inode;
-       retval = -EPERM;
-       if (current->fsuid != inode->i_uid &&
-           current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
-               goto unlink_done;
 
        if ((retval = affs_remove_header(bh,inode)) < 0)
                goto unlink_done;
@@ -563,29 +559,21 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
                retval = 0;
                goto end_rename;
        }
-       if (new_inode && S_ISDIR(new_inode->i_mode)) {
-               retval = -EISDIR;
-               if (!S_ISDIR(old_inode->i_mode))
-                       goto end_rename;
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
-               if (new_dentry->d_count > 1)
-                       shrink_dcache_parent(new_dentry);
-               retval = -ENOTEMPTY;
-               if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
-                       goto end_rename;
-               retval = -EBUSY;
-               if (new_dentry->d_count > 1)
-                       goto end_rename;
-       }
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -ENOTDIR;
-               if (new_inode && !S_ISDIR(new_inode->i_mode))
-                       goto end_rename;
                retval = -EINVAL;
                if (is_subdir(new_dentry, old_dentry))
                        goto end_rename;
+               if (new_inode) {
+                       if (new_dentry->d_count > 1)
+                               shrink_dcache_parent(new_dentry);
+                       retval = -EBUSY;
+                       if (new_dentry->d_count > 1)
+                               goto end_rename;
+                       retval = -ENOTEMPTY;
+                       if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
+                               goto end_rename;
+               }
+
                if (affs_parent_ino(old_inode) != old_dir->i_ino)
                        goto end_rename;
        }
index 8dd3fa6d17dade5bffb64fad96c0f1ebb4ccdd47..1faa42235c42715695b8e664f9df30b7e9e7c038 100644 (file)
@@ -4,7 +4,7 @@
 
 O_TARGET := coda.o
 O_OBJS   := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o coda_linux.o\
-            symlink.o pioctl.o sysctl.o stats.o
+            symlink.o pioctl.o sysctl.o 
 M_OBJS   := $(O_TARGET)
 
 # If you want debugging output, please uncomment the following line.
index 946e88758564bfcb0b1831c929545552adc2e238..1c3b11199703bbef7b4afb7ec21f5cf811726b65 100644 (file)
@@ -306,11 +306,12 @@ static void coda_flag_children(struct dentry *parent, int flag)
        return; 
 }
 
-void coda_purge_children(struct inode *inode)
+void coda_flag_inode_children(struct inode *inode, int flag)
 {
        struct list_head *alias;
        struct dentry *alias_de;
 
+       ENTRY;
        if ( !inode ) 
                return; 
 
@@ -324,7 +325,7 @@ void coda_purge_children(struct inode *inode)
        alias = inode->i_dentry.next; 
        while ( alias != &inode->i_dentry ) {
                alias_de = list_entry(alias, struct dentry, d_alias);
-               coda_flag_children(alias_de, C_PURGE);
+               coda_flag_children(alias_de, flag);
                shrink_dcache_parent(alias_de);
                alias = alias->next;
        }
index 4da714208a5926c78067e5d0429912f8aec583bb..22f791df52ee0dfc1c003f39e67c3da8f7d7e145 100644 (file)
@@ -40,7 +40,7 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
        else if (S_ISSOCK(inode->i_mode))
                inode->i_op = NULL;
         else {
-                printk ("coda_read_inode: what's this? i_mode = %o\n", 
+                printk ("coda_fill_inode: what's this? i_mode = %o\n", 
                        inode->i_mode);
                 inode->i_op = NULL;
         }
@@ -68,7 +68,8 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
 
        error = venus_getattr(sb, fid, &attr);
        if ( error ) {
-           CDEBUG(D_CNODE, "coda_cnode_make: coda_getvattr returned %d for %s.\n", 
+           CDEBUG(D_CNODE, 
+                  "coda_cnode_make: coda_getvattr returned %d for %s.\n", 
                   error, coda_f2s(fid));
            *inode = NULL;
            return error;
@@ -92,8 +93,7 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
                INIT_LIST_HEAD(&(cnp->c_volrootlist));
        } else {
                cnp->c_flags = 0;
-               CDEBUG(D_CNODE, "coda_cnode make on initialized"
-                      "inode %ld, %s!\n",
+               printk("coda_cnode make on initialized inode %ld, %s!\n",
                       (*inode)->i_ino, coda_f2s(&cnp->c_fid));
        }
 
index b7500ed6547a1bc1e7ba938c779ed818eb35e0d9..5344baaeab1bfdbdf7a9eff6f73a2980c6ae28a9 100644 (file)
@@ -44,8 +44,8 @@ char * coda_f2s(ViceFid *f)
 /* recognize special .CONTROL name */
 int coda_iscontrol(const char *name, size_t length)
 {
-       if ((CFS_CONTROLLEN == length) && 
-           (strncmp(name, CFS_CONTROL, CFS_CONTROLLEN) == 0))
+       if ((CODA_CONTROLLEN == length) && 
+           (strncmp(name, CODA_CONTROL, CODA_CONTROLLEN) == 0))
                return 1;
        return 0;
 }
@@ -104,7 +104,7 @@ void coda_load_creds(struct coda_cred *cred)
         cred->cr_suid = (vuid_t) current->suid;
         cred->cr_fsuid = (vuid_t) current->fsuid;
 
-        cred->cr_gid = (vgid_t) current->gid;
+        cred->cr_groupid = (vgid_t) current->gid;
         cred->cr_egid = (vgid_t) current->egid;
         cred->cr_sgid = (vgid_t) current->sgid;
         cred->cr_fsgid = (vgid_t) current->fsgid;
@@ -144,6 +144,11 @@ unsigned short coda_flags_to_cflags(unsigned short flags)
                coda_flags |= C_O_TRUNC;
        }
 
+       if ( flags & O_CREAT )  { 
+               CDEBUG(D_FILE, "--> C_O_CREAT added\n");
+               coda_flags |= C_O_CREAT;
+       }
+
        if ( flags & O_EXCL ) {
                coda_flags |= C_O_EXCL;
                CDEBUG(D_FILE, "--> C_O_EXCL added\n");
index dc4734d0bec913467fa1392629af73bd90fc0e8d..5f13d8ca992e51f47fdadc4b9845d8270b17554c 100644 (file)
@@ -45,16 +45,15 @@ static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
 /* dentry ops */
 static int coda_dentry_revalidate(struct dentry *de);
 static void coda_dentry_delete(struct dentry *);
+
 /* support routines */
 static int coda_venus_readdir(struct file *filp, void *dirent, 
                              filldir_t filldir);
 int coda_fsync(struct file *, struct dentry *dentry);
-static int coda_refresh_inode(struct dentry *dentry);
 
 int coda_crossvol_rename = 0;
 int coda_hasmknod = 0;
 
-
 struct dentry_operations coda_dentry_operations =
 {
        coda_dentry_revalidate, /* revalidate */
@@ -119,24 +118,24 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
        size_t length = entry->d_name.len;
        
         ENTRY;
-        CDEBUG(D_INODE, "name %s, len %d in ino %ld\n", 
-              name, length, dir->i_ino);
-
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk("coda_lookup: inode is NULL or not a directory\n");
-               return -ENOTDIR;
-       }
 
        dircnp = ITOC(dir);
 
-       if ( length > CFS_MAXNAMLEN ) {
+       if ( length > CODA_MAXNAMLEN ) {
                printk("name too long: lookup, %s (%*s)\n", 
                       coda_f2s(&dircnp->c_fid), length, name);
                return -ENAMETOOLONG;
        }
-       
-       CDEBUG(D_INODE, "lookup: %*s in %s\n", length, name, 
-              coda_f2s(&dircnp->c_fid));
+
+
+       if (!dir || !S_ISDIR(dir->i_mode)) {
+               printk("coda_lookup: inode is NULL or not a directory\n");
+               return -ENOTDIR;
+       }
+
+
+        CDEBUG(D_INODE, "name %s, len %d in ino %ld, fid %s\n", 
+              name, length, dir->i_ino, coda_f2s(&dircnp->c_fid));
 
         /* control object, create inode on the fly */
         if (coda_isroot(dir) && coda_iscontrol(name, length)) {
@@ -152,8 +151,8 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
 
        res_inode = NULL;
        if (!error) {
-               if (type & CFS_NOCACHE) {
-                       type &= (~CFS_NOCACHE);
+               if (type & CODA_NOCACHE) {
+                       type &= (~CODA_NOCACHE);
                        CDEBUG(D_INODE, "dropme set for %s\n", 
                               coda_f2s(&resfid));
                        dropme = 1;
@@ -184,7 +183,7 @@ exit:
 
 int coda_permission(struct inode *inode, int mask)
 {
-        struct coda_inode_info *cp;
+        struct coda_inode_info *cp = ITOC(inode);
         int error;
  
         ENTRY;
@@ -192,7 +191,6 @@ int coda_permission(struct inode *inode, int mask)
        coda_permission_stat.count++;
 
         if ( mask == 0 ) {
-                EXIT;
                 return 0;
         }
 
@@ -204,7 +202,6 @@ int coda_permission(struct inode *inode, int mask)
        }
 
         cp = ITOC(inode);
-        CHECK_CNODE(cp);
 
         CDEBUG(D_INODE, "mask is %o\n", mask);
         error = venus_access(inode->i_sb, &(cp->c_fid), mask);
@@ -247,9 +244,8 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
                return -EPERM;
 
        dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
 
-        if ( length > CFS_MAXNAMLEN ) {
+        if ( length > CODA_MAXNAMLEN ) {
                printk("name too long: create, %s(%s)\n", 
                       coda_f2s(&dircnp->c_fid), name);
                return -ENAMETOOLONG;
@@ -304,9 +300,8 @@ static int coda_mknod(struct inode *dir, struct dentry *de, int mode, int rdev)
                return -EPERM;
 
        dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
 
-        if ( length > CFS_MAXNAMLEN ) {
+        if ( length > CODA_MAXNAMLEN ) {
                printk("name too long: mknod, %s(%s)\n", 
                       coda_f2s(&dircnp->c_fid), name);
                return -ENAMETOOLONG;
@@ -353,14 +348,13 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
                return -ENOENT;
        }
 
-        if ( len > CFS_MAXNAMLEN )
+        if ( len > CODA_MAXNAMLEN )
                 return -ENAMETOOLONG;
 
        if (coda_isroot(dir) && coda_iscontrol(name, len))
                return -EPERM;
 
         dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
 
        CDEBUG(D_INODE, "mkdir %s (len %d) in %s, mode %o.\n", 
               name, len, coda_f2s(&(dircnp->c_fid)), mode);
@@ -410,12 +404,11 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
 
         dir_cnp = ITOC(dir_inode);
         cnp = ITOC(inode);
-        CHECK_CNODE(cnp);
 
        CDEBUG(D_INODE, "old: fid: %s\n", coda_f2s(&(cnp->c_fid)));
        CDEBUG(D_INODE, "directory: %s\n", coda_f2s(&(dir_cnp->c_fid)));
 
-        if ( len > CFS_MAXNAMLEN ) {
+        if ( len > CODA_MAXNAMLEN ) {
                 printk("coda_link: name too long. \n");
                 return -ENAMETOOLONG;
         }
@@ -428,8 +421,9 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
                ++inode->i_count;
                d_instantiate(de, inode);
                inode->i_nlink++;
-       } else {
+       } else  {
                d_drop(de);
+               return error;
        }
 
         CDEBUG(D_INODE, "link result %d\n",error);
@@ -453,11 +447,11 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
        if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
                return -EPERM;
 
-       if ( len > CFS_MAXNAMLEN )
+       if ( len > CODA_MAXNAMLEN )
                 return -ENAMETOOLONG;
 
        symlen = strlen(symname);
-       if ( symlen > CFS_MAXPATHLEN )
+       if ( symlen > CODA_MAXPATHLEN )
                 return -ENAMETOOLONG;
 
         CDEBUG(D_INODE, "symname: %s, length: %d\n", symname, symlen);
@@ -467,10 +461,10 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
         * an inode for the entry we have to drop it. 
         */
        d_drop(de);
-
        error = venus_symlink(dir_inode->i_sb, &(dir_cnp->c_fid), name, len, 
                              symname, symlen);
 
+       /* mtime is no good anymore */
        if ( !error ) {
                dir_cnp->c_flags |= C_VATTR;
        }
@@ -483,7 +477,7 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
 /* destruction routines: unlink, rmdir */
 int coda_unlink(struct inode *dir, struct dentry *de)
 {
-        struct coda_inode_info *dircnp;
+        struct coda_inode_info *dircnp = ITOC(dir);
         int error;
        const char *name = de->d_name.name;
        int len = de->d_name.len;
@@ -491,25 +485,18 @@ int coda_unlink(struct inode *dir, struct dentry *de)
        ENTRY;
        coda_vfs_stat.unlink++;
 
-        dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
-
-        CDEBUG(D_INODE, " %s in %s, ino %ld\n", name , 
+        CDEBUG(D_INODE, " %s in %s, dirino %ld\n", name , 
               coda_f2s(&(dircnp->c_fid)), dir->i_ino);
 
-        /* this file should no longer be in the namecache! */
-
         error = venus_remove(dir->i_sb, &(dircnp->c_fid), name, len);
-
         if ( error ) {
                 CDEBUG(D_INODE, "upc returned error %d\n", error);
                 return error;
         }
 
-        /* cache management */
+        /* cache management: mtime has changed, ask Venus */
        dircnp->c_flags |= C_VATTR;
        de->d_inode->i_nlink--;
-
        d_delete(de);
 
         return 0;
@@ -530,19 +517,12 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
                return -ENOENT;
        }
         dircnp = ITOC(dir);
-        CHECK_CNODE(dircnp);
 
-       if (len > CFS_MAXNAMLEN)
+       if (len > CODA_MAXNAMLEN)
                return -ENAMETOOLONG;
 
        if (!list_empty(&de->d_hash))
                return -EBUSY;
-
-       /* update i_nlink and free the inode before unlinking;
-          if rmdir fails a new lookup set i_nlink right.*/
-       if (de->d_inode->i_nlink)
-               de->d_inode->i_nlink --;
-
        error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
 
         if ( error ) {
@@ -550,6 +530,9 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
                 return error;
         }
 
+       if (de->d_inode->i_nlink)
+               de->d_inode->i_nlink --;
+
         return 0;
 }
 
@@ -569,7 +552,7 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
        ENTRY;
        coda_vfs_stat.rename++;
 
-        if ( (old_length > CFS_MAXNAMLEN) || new_length > CFS_MAXNAMLEN ) {
+        if ( (old_length > CODA_MAXNAMLEN) || new_length > CODA_MAXNAMLEN ) {
                 return -ENAMETOOLONG;
         }
 
@@ -641,8 +624,6 @@ int coda_readdir(struct file *file, void *dirent,  filldir_t filldir)
         }
 
         cnp = ITOC(inode);
-        CHECK_CNODE(cnp);
-        
         if ( !cnp->c_ovp ) {
                 CDEBUG(D_FILE, "open inode pointer = NULL.\n");
                 return -EIO;
@@ -658,8 +639,8 @@ int coda_readdir(struct file *file, void *dirent,  filldir_t filldir)
                 result = open_file.f_op->readdir(&open_file, dirent, filldir);
         }
        coda_restore_codafile(inode, file, cnp->c_ovp, &open_file);
-       return result;
         EXIT;
+       return result;
 }
 
 /* ask venus to cache the file and return the inode of the container file,
@@ -673,15 +654,17 @@ int coda_open(struct inode *i, struct file *f)
         struct inode *cont_inode = NULL;
         unsigned short flags = f->f_flags & (~O_EXCL);
        unsigned short coda_flags = coda_flags_to_cflags(flags);
+       struct coda_cred *cred;
 
         ENTRY;
        coda_vfs_stat.open++;
-        
+
         CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n", 
               f->f_dentry->d_inode->i_ino, f->f_dentry->d_count, flags);
 
         cnp = ITOC(i);
 
+
        error = venus_open(i->i_sb, &(cnp->c_fid), coda_flags, &ino, &dev); 
        if (error) {
                CDEBUG(D_FILE, "venus: dev %d, inode %ld, out->result %d\n",
@@ -700,6 +683,10 @@ int coda_open(struct inode *i, struct file *f)
                return error;
        }
 
+       CODA_ALLOC(cred, struct coda_cred *, sizeof(*cred));
+       coda_load_creds(cred);
+       f->private_data = cred;
+
         if (  cnp->c_ovp ) {
                iput(cnp->c_ovp);
                cnp->c_ovp = NULL;
@@ -722,10 +709,13 @@ int coda_release(struct inode *i, struct file *f)
         int error;
         unsigned short flags = (f->f_flags) & (~O_EXCL);
        unsigned short cflags = coda_flags_to_cflags(flags);
+       struct coda_cred *cred;
 
         ENTRY;
        coda_vfs_stat.release++;
 
+       cred = (struct coda_cred *)f->private_data;
+
         cnp =ITOC(i);
         CHECK_CNODE(cnp);
         CDEBUG(D_FILE,  
@@ -746,7 +736,10 @@ int coda_release(struct inode *i, struct file *f)
                 --cnp->c_owrite;
         }
 
-       error = venus_release(i->i_sb, &(cnp->c_fid), cflags);
+       error = venus_release(i->i_sb, &(cnp->c_fid), cflags, cred);
+
+       CODA_FREE(cred, sizeof(*cred));
+       f->private_data = NULL;
 
         CDEBUG(D_FILE, "coda_release: result: %d\n", error);
         return error;
@@ -759,96 +752,97 @@ int coda_release(struct inode *i, struct file *f)
  * beyond the current_dir pointer.
  */
 
-struct getdents_callback {
-       struct linux_dirent * current_dir;
-       struct linux_dirent * previous;
-       int count;
-       int error;
-};
+
+/* should be big enough to hold any single directory entry */
+#define DIR_BUFSIZE 2048
 
 static int coda_venus_readdir(struct file *filp, void *getdent, 
                              filldir_t filldir)
 {
-        int result = 0,  offset, count, pos, error = 0;
+        int bufsize;
+       int offset = filp->f_pos; /* offset in the directory file */
+       int count = 0;
+       int pos = 0;      /* offset in the block we read */
+       int result = 0; /* either an error or # of entries returned */
        int errfill;
-        caddr_t buff = NULL;
+        char *buff = NULL;
         struct venus_dirent *vdirent;
-        struct getdents_callback *dents_callback;
-        int string_offset;
-       int size;
-        char debug[255];
+        int string_offset = (int) (&((struct venus_dirent *)(0))->d_name);
+       int i;
 
         ENTRY;        
 
-        /* we also need the ofset of the string in the dirent struct */
-        string_offset = sizeof ( char )* 2  + sizeof(unsigned int) + 
-                        sizeof(unsigned short);
-
-        dents_callback = (struct getdents_callback *) getdent;
-
-        size = count =  dents_callback->count;
-        CODA_ALLOC(buff, void *, size);
-        if ( ! buff ) { 
+        CODA_ALLOC(buff, char *, DIR_BUFSIZE);
+        if ( !buff ) { 
                 printk("coda_venus_readdir: out of memory.\n");
                 return -ENOMEM;
         }
 
         /* we use this routine to read the file into our buffer */
-        result = read_exec(filp->f_dentry, filp->f_pos, buff, count, 1);
-        if ( result < 0) {
+        bufsize = read_exec(filp->f_dentry, filp->f_pos, buff, DIR_BUFSIZE, 1);
+        if ( bufsize < 0) {
                 printk("coda_venus_readdir: cannot read directory %d.\n",
-                      result);
-                error = result;
+                      bufsize);
+                result = bufsize;
                 goto exit;
         }
-        if ( result == 0) {
-                error = result;
+        if ( bufsize == 0) {
+                result = 0;
                 goto exit;
         }
-
+       
         /* Parse and write into user space. Filldir tells us when done! */
-        offset = filp->f_pos;
-        pos = 0;
-        CDEBUG(D_FILE, "offset %d, count %d.\n", offset, count);
+        CDEBUG(D_FILE, "buffsize: %d offset %d, count %d.\n", 
+              bufsize, offset, count);
 
-        while ( pos + string_offset < result ) {
+       i = 0;
+       result = 0; 
+        while ( pos + string_offset < bufsize && i < 1024) {
                 vdirent = (struct venus_dirent *) (buff + pos);
 
                 /* test if the name is fully in the buffer */
-                if ( pos + string_offset + (int) vdirent->d_namlen >= result ){
+                if ( pos + string_offset + (int) vdirent->d_namlen >= bufsize ){
+                       if ( result == 0 )
+                               printk("CODA: Invalid directory cfino: %ld\n", 
+                                      filp->f_dentry->d_inode->i_ino);
                         break;
                 }
-                
                 /* now we are certain that we can read the entry from buff */
 
-                /* for debugging, get the string out */
-                memcpy(debug, vdirent->d_name, vdirent->d_namlen);
-                *(debug + vdirent->d_namlen) = '\0';
-
                 /* if we don't have a null entry, copy it */
-                if ( vdirent->d_fileno ) {
+                if ( vdirent->d_fileno && vdirent->d_reclen ) {
                         int namlen  = vdirent->d_namlen;
                         off_t offs  = filp->f_pos; 
                         ino_t ino   = vdirent->d_fileno;
                         char *name  = vdirent->d_name;
-                        /* adjust count */
-                        count = dents_callback->count;
 
-                       errfill = filldir(dents_callback,  name, namlen, 
+                       errfill = filldir(getdent,  name, namlen, 
                                          offs, ino); 
-CDEBUG(D_FILE, "ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d, name %s, offset %d, count %d.\n", vdirent->d_fileno, vdirent->d_namlen, vdirent->d_reclen, vdirent->d_type, pos,  string_offset, debug, (u_int) offs, dents_callback->count);
-
-                     /* errfill means no space for filling in this round */
-                      if ( errfill < 0 ) break;
+CDEBUG(D_FILE, "entry %d: ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d, name %*s, offset %d, result: %d, errfill: %d.\n", i,vdirent->d_fileno, vdirent->d_namlen, vdirent->d_reclen, vdirent->d_type, pos,  string_offset, vdirent->d_namlen, vdirent->d_name, (u_int) offs, result, errfill);
+                       /* errfill means no space for filling in this round */
+                       if ( errfill < 0 ) {
+                               result = 0;
+                               break;
+                       }
+                        /* adjust count */
+                        result++;
                 }
                 /* next one */
-                filp->f_pos += (unsigned int) vdirent->d_reclen;
+                filp->f_pos += vdirent->d_reclen;
+               if ( filp->f_pos > filp->f_dentry->d_inode->i_size )
+                       break; 
+               if ( !vdirent->d_reclen ) {
+                       printk("CODA: Invalid directory, cfino: %ld\n", 
+                              filp->f_dentry->d_inode->i_ino);
+                       break;
+               }
                 pos += (unsigned int) vdirent->d_reclen;
+               i++;
         } 
 
 exit:
-        CODA_FREE(buff, size);
-        return error;
+        CODA_FREE(buff, DIR_BUFSIZE);
+        return result;
 }
 
 /* called when a cache lookup succeeds */
@@ -865,6 +859,10 @@ static int coda_dentry_revalidate(struct dentry *de)
                cii = ITOC(de->d_inode);
                if (cii->c_flags & C_PURGE) 
                        valid = 0;
+               if (cii->c_flags & C_FLUSH) {
+                       coda_flag_inode_children(inode, C_FLUSH);
+                       valid = 0;
+               }
        }
        return valid ||  coda_isroot(de->d_inode);
 }
@@ -890,64 +888,74 @@ static void coda_dentry_delete(struct dentry * dentry)
 }
 
 
-static int coda_refresh_inode(struct dentry *dentry)
+
+/*
+ * This is called when we want to check if the inode has
+ * changed on the server.  Coda makes this easy since the
+ * cache manager Venus issues a downcall to the kernel when this 
+ * happens 
+ */
+
+int coda_revalidate_inode(struct dentry *dentry)
 {
        struct coda_vattr attr;
-       int error;
+       int error = 0;
        int old_mode;
        ino_t old_ino;
        struct inode *inode = dentry->d_inode;
        struct coda_inode_info *cii = ITOC(inode);
 
        ENTRY;
-       
-       error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
-       if ( error ) { 
-               make_bad_inode(inode);
-               return -EIO;
-       }
+       CDEBUG(D_INODE, "revalidating: %*s/%*s\n", 
+              dentry->d_name.len, dentry->d_name.name,
+              dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
 
-       /* this inode may be lost if:
-            - it's type changed
-            - it's ino changed 
-       */
-       old_mode = inode->i_mode;
-       old_ino = inode->i_ino;
-       coda_vattr_to_iattr(inode, &attr);
+       if ( cii->c_flags == 0 )
+               return 0;
 
-       if ((inode->i_ino != old_ino) ||
-           ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT))) {
+       /* Venus closed the device .... */
+       if ( cii->c_flags & C_DYING ) { 
                make_bad_inode(inode);
-               inode->i_mode = old_mode;
                return -EIO;
        }
-       
-       cii->c_flags &= ~C_VATTR;
-       return 0;
-}
 
+       
+       if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
+               error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
+               if ( error ) { 
+                       make_bad_inode(inode);
+                       return -EIO;
+               }
 
-/*
- * This is called when we want to check if the inode has
- * changed on the server.  Coda makes this easy since the
- * cache manager Venus issues a downcall to the kernel when this 
- * happens 
- */
+               /* this inode may be lost if:
+                  - it's ino changed 
+                  - type changes must be permitted for repair and
+                  missing mount points.
+               */
+               old_mode = inode->i_mode;
+               old_ino = inode->i_ino;
+               coda_vattr_to_iattr(inode, &attr);
 
-int coda_revalidate_inode(struct dentry *dentry)
-{
-       int error = 0;
-       struct coda_inode_info *cii = ITOC(dentry->d_inode);
 
-       ENTRY;
-       CDEBUG(D_INODE, "revalidating: %*s/%*s\n", 
-              dentry->d_name.len, dentry->d_name.name,
-              dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
+               if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) {
+                       printk("Coda: inode %ld, fid %s changed type!\n",
+                              inode->i_ino, coda_f2s(&(cii->c_fid)));
+               }
 
-       if (cii->c_flags & (C_VATTR | C_PURGE)) {
-               error = coda_refresh_inode(dentry);
+               /* the following can happen when a local fid is replaced 
+                  with a global one, here we lose and declar the inode bad */
+               if (inode->i_ino != old_ino) {
+                       make_bad_inode(inode);
+                       inode->i_mode = old_mode;
+                       return -EIO;
+               }
+               
+               if ( cii->c_flags ) 
+                       coda_flag_inode_children(inode, C_FLUSH);
+               
+               cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
        }
 
-       return error;
+       return 0;
 }
 
index f215ce3140328e8082849c7627103cbe4b1554d0..9c0846b02502e89030ca02e73118f714dfb96d26 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/coda_fs_i.h>
 #include <linux/coda_cache.h>
 
-
 /* VFS super_block ops */
 static struct super_block *coda_read_super(struct super_block *, void *, int);
 static void coda_read_inode(struct inode *);
@@ -47,11 +46,6 @@ static void coda_put_super(struct super_block *);
 static int coda_statfs(struct super_block *sb, struct statfs *buf, 
                       int bufsiz);
 
-/* helper functions */
-static struct vcomm *coda_psinode2vcomm(struct inode *inode);
-static int coda_get_psdev(void *, struct inode **);
-static struct coda_sb_info *coda_psinode2sbi(struct inode *inode);
-
 /* exported operations */
 struct super_operations coda_super_operations =
 {
@@ -66,36 +60,28 @@ struct super_operations coda_super_operations =
        NULL                    /* remount_fs */
 };
 
-/*
- * globals
- */
-struct coda_sb_info coda_super_info[MAX_CODADEVS];
-
-
 static struct super_block * coda_read_super(struct super_block *sb, 
                                            void *data, int silent)
 {
         struct inode *psdev = 0, *root = 0; 
        struct coda_sb_info *sbi = NULL;
-       struct vcomm *vc = NULL;
+       struct venus_comm *vc = NULL;
         ViceFid fid;
        kdev_t dev = sb->s_dev;
         int error;
 
        ENTRY;
         MOD_INC_USE_COUNT; 
-        if (coda_get_psdev(data, &psdev))
-                goto error;
-
-        vc = coda_psinode2vcomm(psdev);
-        if ( !vc )
-               goto error;
-       vc->vc_sb = sb;
-       vc->vc_inuse = 1;
-
-       sbi = coda_psinode2sbi(psdev);
-       if ( !sbi )
-               goto error;
+
+        vc = &coda_upc_comm;
+       sbi = &coda_super_info;
+
+        if ( sbi->sbi_sb ) {
+               printk("Already mounted\n");
+               return NULL;
+       }
+
+       sbi->sbi_sb = sb;
         sbi->sbi_psdev = psdev;
        sbi->sbi_vcomm = vc;
        INIT_LIST_HEAD(&(sbi->sbi_cchead));
@@ -137,16 +123,13 @@ static struct super_block * coda_read_super(struct super_block *sb,
        EXIT;  
         return sb;
 
-error:
-EXIT;  
+ error:
+       EXIT;  
        MOD_DEC_USE_COUNT;
        if (sbi) {
                sbi->sbi_vcomm = NULL;
                sbi->sbi_root = NULL;
-       }
-       if ( vc ) {
-               vc->vc_sb = NULL;
-               vc->vc_inuse = 0;
+               sbi->sbi_sb = NULL;
        }
         if (root) {
                 iput(root);
@@ -166,7 +149,7 @@ static void coda_put_super(struct super_block *sb)
        coda_cache_clear_all(sb);
        sb_info = coda_sbp(sb);
        sb_info->sbi_vcomm->vc_inuse = 0;
-       sb_info->sbi_vcomm->vc_sb = NULL;
+       coda_super_info.sbi_sb = NULL;
        printk("Coda: Bye bye.\n");
        memset(sb_info, 0, sizeof(* sb_info));
 
@@ -288,80 +271,5 @@ int init_coda_fs(void)
        return register_filesystem(&coda_fs_type);
 }
 
-/* MODULE stuff is in psdev.c */
 
-/*  helpers */
-static struct vcomm *coda_psinode2vcomm(struct inode *inode) 
-{
-        
-       unsigned int minor = MINOR(inode->i_rdev);
-       CDEBUG(D_PSDEV,"minor %d\n", minor);
-       if ( minor < MAX_CODADEVS ) 
-             return &(psdev_vcomm[minor]);
-       else
-             return NULL;
-}
-
-static struct coda_sb_info *coda_psinode2sbi(struct inode *inode) 
-{
-       unsigned int minor = MINOR(inode->i_rdev);
 
-       CDEBUG(D_PSDEV,"minor %d\n", minor);
-       if ( (minor >= 0) && (minor < MAX_CODADEVS)) 
-               return &(coda_super_info[minor]);
-       else
-               return NULL;
-}
-
-/* name lookup for psdev passed in by mount */
-static int coda_get_psdev(void *data, struct inode **res_dev)
-{
-        char **psdev_path;
-        struct inode *psdev = 0;
-       struct dentry *ent=NULL;
-
-       if ( ! data ) { 
-               printk("coda_get_psdev: no data!\n");
-               return 1;
-       } 
-
-       psdev_path = data;
-        ent = namei((char *) *psdev_path);
-        if (IS_ERR(ent)) {
-               printk("namei error %ld for %d\n", PTR_ERR(ent), 
-                      (int) psdev_path);
-               return 1;
-        }
-       psdev = ent->d_inode;
-
-        if (!S_ISCHR(psdev->i_mode)) {
-               printk("not a character device\n");
-               return 1;
-        }
-       CDEBUG(D_PSDEV,"major %d, minor %d, count %d\n", 
-              MAJOR(psdev->i_rdev), 
-              MINOR(psdev->i_rdev), psdev->i_count);
-        
-        if (MAJOR(psdev->i_rdev) != CODA_PSDEV_MAJOR) {
-               printk("device %d not a Coda PSDEV device\n", 
-                      MAJOR(psdev->i_rdev));
-               return 1;
-        }
-
-        if (MINOR(psdev->i_rdev) >= MAX_CODADEVS) { 
-               printk("minor %d not an allocated Coda PSDEV\n", 
-                      psdev->i_rdev);
-               return 1;
-        }
-
-        if (psdev->i_count < 1) {
-               printk("coda device minor %d not open (i_count = %d)\n", 
-                      MINOR(psdev->i_rdev), psdev->i_count);
-               return 1;
-        }
-        
-        *res_dev = psdev;
-       EXIT;  
-        return 0;
-}
index 144162f5af504ba57ea79eea93ec2800c9765b06..aafc813834b940a41a61b236fc542ddbcb6ce198 100644 (file)
@@ -17,7 +17,6 @@
  *              Copyright (c) 1997 Carnegie-Mellon University
  */
 
-#include <linux/config.h> /* for CONFIG_PROC_FS */
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -34,6 +33,7 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/init.h>
+#include <linux/list.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/coda_cache.h>
 #include <linux/coda_proc.h>
 
-extern struct proc_dir_entry proc_sys_root;
-
 /* 
  * Coda stuff
  */
 extern struct file_system_type coda_fs_type;
 extern int init_coda_fs(void);
-extern int cfsnc_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
-extern int cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy);
 
 /* statistics */
-struct coda_upcallstats coda_callstats;
-int           coda_hard = 0;  /* allows signals during upcalls */
+int           coda_hard    = 0;  /* allows signals during upcalls */
 unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
-extern struct coda_sb_info coda_super_info[MAX_CODADEVS];
-struct vcomm psdev_vcomm[MAX_CODADEVS];
-
-/* queue stuff for the messages */
-static inline void init_queue(struct queue *head)
-{
-       head->forw = head;
-       head->back = head;
-}
-
-static inline struct vmsg *q_getnext(struct queue *elt)
-{
-       return (struct vmsg *)(elt->forw);
-}
-
-static inline int q_end(struct vmsg *msg, struct queue *queue)
-{
-       return (struct queue *)msg == queue;
-}
 
-static inline int q_empty(struct queue *queue)
-{
-       return queue->forw == queue;
-}
-
-/* insert before head, ie. at the tail */
-void coda_q_insert(struct queue *el, struct queue *head)
-{
-       el->forw = head->back->forw;
-       el->back = head->back;
-       head->back->forw = el;
-       head->back = el;
-}
-
-void coda_q_remove(struct queue *el)
-{
-       el->forw->back = el->back;
-       el->back->forw = el->forw;
-}
-
-static struct vcomm *coda_psdev2vcomm(struct file *file)
-{
-               unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
-       struct vcomm *vcp = NULL;
-
-       if ( (minor >= 0)  && (minor < MAX_CODADEVS) )
-               vcp = &psdev_vcomm[minor];
-       return vcp;
-}
+struct coda_sb_info coda_super_info;
+struct venus_comm coda_upc_comm;
        
 /*
  * Device operations
  */
 
-
 static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
 {
-        struct vcomm *vcp = coda_psdev2vcomm(file);
+        struct venus_comm *vcp = &coda_upc_comm;
        unsigned int mask = POLLOUT | POLLWRNORM;
 
-       if ( !vcp ) 
-               return -ENXIO;
-
        poll_wait(file, &(vcp->vc_waitq), wait);
-       if (!q_empty(&(vcp->vc_pending)))
+       if (!list_empty(&vcp->vc_pending))
                 mask |= POLLIN | POLLRDNORM;
 
        return mask;
@@ -139,54 +84,51 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
 static ssize_t coda_psdev_write(struct file *file, const char *buf, 
                                size_t count, loff_t *off)
 {
-        struct vcomm *vcp = coda_psdev2vcomm(file);
-        struct vmsg *vmp;
-       int error = 0;
-       int size;
-        u_long uniq;
-        u_long opcode;
-        u_long opcodebuf[2];
-        
-        if (!vcp)
-                return -ENXIO;
+        struct venus_comm *vcp = &coda_upc_comm;
+        struct upc_req *req = NULL;
+        struct upc_req *tmp;
+       struct list_head *lh;
+       struct coda_in_hdr hdr;
+       int error;
 
+
+       if ( !coda_upc_comm.vc_pid ) 
+               return -EIO;
         /* Peek at the opcode, uniquefier */
-       if (copy_from_user(opcodebuf, buf, 2 * sizeof(u_long)))
+       if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
                return -EFAULT;
-       opcode = opcodebuf[0];
-        uniq = opcodebuf[1];
 
-       CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld)\n", 
-              current->pid, opcode, uniq);
+       CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), count %d\n", 
+              current->pid, hdr.opcode, hdr.unique, count);
 
-        if (DOWNCALL(opcode)) {
+        if (DOWNCALL(hdr.opcode)) {
                struct super_block *sb = NULL;
                 union outputArgs *dcbuf;
-               size = sizeof(*dcbuf);
+               int size = sizeof(*dcbuf);
 
-               sb = vcp->vc_sb;
+               sb = coda_super_info.sbi_sb;
                if ( !sb ) {
                        printk("coda_psdev_write: downcall, no SB!\n");
                        return count;
                }
                CDEBUG(D_PSDEV, "handling downcall\n");
 
-               if  ( count < sizeof(struct cfs_out_hdr) ) {
+               if  ( count < sizeof(struct coda_out_hdr) ) {
                        printk("coda_downcall opc %ld uniq %ld, not enough!\n",
-                              opcode, uniq);
+                              hdr.opcode, hdr.unique);
                        return count;
                }
                CODA_ALLOC(dcbuf, union outputArgs *, size);
                if ( count > size ) {
                        printk("Coda: downcall opc %ld, uniq %ld, too much!",
-                              opcode, uniq);
+                              hdr.opcode, hdr.unique);
                        count = size;
                }
                if (copy_from_user(dcbuf, buf, count))
                        return -EFAULT;
 
                /* what downcall errors does Venus handle ? */
-               error = coda_downcall(opcode, dcbuf, sb);
+               error = coda_downcall(hdr.opcode, dcbuf, sb);
 
                if ( error) {
                        printk("psdev_write: coda_downcall error: %d\n", 
@@ -199,41 +141,41 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
 
         
         /* Look for the message on the processing queue. */
-        for (vmp = q_getnext(&(vcp->vc_processing));
-            !q_end(vmp, &(vcp->vc_processing));
-             vmp = q_getnext(&(vmp->vm_chain))) {
-               if (vmp->vm_unique == uniq) {
+       lh  = &vcp->vc_processing;
+        while ( (lh = lh->next) != &vcp->vc_processing ) {
+               tmp = list_entry(lh, struct upc_req , uc_chain);
+               if (tmp->uc_unique == hdr.unique) {
+                       req = tmp;
+                       list_del(&req->uc_chain);
+                       CDEBUG(D_PSDEV,"Eureka: uniq %ld on queue!\n", 
+                              hdr.unique);
                        break;
-                       CDEBUG(D_PSDEV,"Eureka: uniq %ld on queue!\n", uniq);
                }
        }
-        if (q_end(vmp, &(vcp->vc_processing))) {
+        if (!req) {
                printk("psdev_write: msg (%ld, %ld) not found\n", 
-                      opcode, uniq);
+                      hdr.opcode, hdr.unique);
                return(-ESRCH);
         }
 
-        /* Remove the message from the processing queue */
-        coda_q_remove(&(vmp->vm_chain));
-
         /* move data into response buffer. */
-        if (vmp->vm_outSize < count) {
+        if (req->uc_outSize < count) {
                 printk("psdev_write: too much cnt: %d, cnt: %d, opc: %ld, uniq: %ld.\n",
-                      vmp->vm_outSize, count, opcode, uniq);
-               count = vmp->vm_outSize; /* don't have more space! */
+                      req->uc_outSize, count, hdr.opcode, hdr.unique);
+               count = req->uc_outSize; /* don't have more space! */
        }
-        if (copy_from_user(vmp->vm_data, buf, count))
+        if (copy_from_user(req->uc_data, buf, count))
                return -EFAULT;
 
        /* adjust outsize. is this usefull ?? */
-        vmp->vm_outSize = count;       
-        vmp->vm_flags |= VM_WRITE;
+        req->uc_outSize = count;       
+        req->uc_flags |= REQ_WRITE;
 
        CDEBUG(D_PSDEV, 
-              "Found! Count %d for (opc,uniq)=(%ld,%ld), vmsg at %x\n", 
-               count, opcode, uniq, (int)&vmp);
+              "Found! Count %d for (opc,uniq)=(%ld,%ld), upc_req at %x\n", 
+               count, hdr.opcode, hdr.unique, (int)&req);
 
-        wake_up(&vmp->vm_sleep);
+        wake_up(&req->uc_sleep);
         return(count);  
 }
 
@@ -244,47 +186,41 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
 static ssize_t coda_psdev_read(struct file * file, char * buf, 
                               size_t count, loff_t *off)
 {
-        struct vcomm *vcp = coda_psdev2vcomm(file);
-        struct vmsg *vmp;
+        struct venus_comm *vcp = &coda_upc_comm;
+        struct upc_req *req;
        int result = count ;
 
-        if (!vcp)
-              return -ENXIO;
-        
-        /* Get message at head of request queue. */
-        if (q_empty(&(vcp->vc_pending))) {
-              return 0;        
+        CDEBUG(D_PSDEV, "count %d\n", count);
+        if (list_empty(&(vcp->vc_pending))) {
+              return -1;       
         }
     
-        vmp = q_getnext(&(vcp->vc_pending));
-        coda_q_remove(&(vmp->vm_chain));
+        req = list_entry((vcp->vc_pending.next), struct upc_req, uc_chain);
+        list_del(&(req->uc_chain));
 
         /* Move the input args into userspace */
-        if (vmp->vm_inSize <= count)
-              result = vmp->vm_inSize;
+        if (req->uc_inSize <= count)
+              result = req->uc_inSize;
 
-        if (count < vmp->vm_inSize) {
+        if (count < req->uc_inSize) {
                 printk ("psdev_read: Venus read %d bytes of %d in message\n",
-                       count, vmp->vm_inSize);
+                       count, req->uc_inSize);
         }
 
-        if ( copy_to_user(buf, vmp->vm_data, result))
+        if ( copy_to_user(buf, req->uc_data, result))
                return -EFAULT;
         
-        if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
-                printk("coda_psdev_read: bad chain");
-
         /* If request was a signal, don't enqueue */
-        if (vmp->vm_opcode == CFS_SIGNAL) {
+        if (req->uc_opcode == CODA_SIGNAL) {
                     CDEBUG(D_PSDEV, "vcread: signal msg (%d, %d)\n", 
-                              vmp->vm_opcode, vmp->vm_unique);
-              CODA_FREE(vmp->vm_data, sizeof(struct cfs_in_hdr));
-              CODA_FREE(vmp, sizeof(struct vmsg));
+                              req->uc_opcode, req->uc_unique);
+              CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
+              CODA_FREE(req, sizeof(struct upc_req));
               return count;
         }
     
-        vmp->vm_flags |= VM_READ;
-        coda_q_insert(&(vmp->vm_chain), &(vcp->vc_processing));
+        req->uc_flags |= REQ_READ;
+        list_add(&(req->uc_chain), vcp->vc_processing.prev);
 
         return result;
 }
@@ -292,85 +228,87 @@ static ssize_t coda_psdev_read(struct file * file, char * buf,
 
 static int coda_psdev_open(struct inode * inode, struct file * file)
 {
-        register struct vcomm *vcp = NULL;
+        struct venus_comm *vcp = &coda_upc_comm;
         ENTRY;
-        
-       vcp =coda_psdev2vcomm(file);
-
-        if (!vcp)
-               return -ENODEV;
+       
+       /* first opener: must be lento. Initialize & take its pid */
+       if ( file->f_flags == O_RDWR ) {
+               if ( vcp->vc_pid ) {
+                       printk("Venus pid already set to %d!!\n", vcp->vc_pid);
+                       return -1;
+               }
+               if ( vcp->vc_inuse ) {
+                       printk("psdev_open: Cannot O_RDWR while open.\n");
+                       return -1;
+               }
+       }
+       
+       vcp->vc_inuse++;
+       MOD_INC_USE_COUNT;
 
-       if (vcp->vc_inuse)
-               return -EBUSY;
 
-       memset(vcp, 0, sizeof(struct vcomm));
-       vcp->vc_inuse = 1;
-       MOD_INC_USE_COUNT;
+       if ( file->f_flags == O_RDWR ) {
+               vcp->vc_pid = current->pid;
+               vcp->vc_seq = 0;
+               INIT_LIST_HEAD(&vcp->vc_pending);
+               INIT_LIST_HEAD(&vcp->vc_processing);
+       }
 
-        init_queue(&(vcp->vc_pending));
-        init_queue(&(vcp->vc_processing));
+       CDEBUG(D_PSDEV, "inuse: %d, vc_pid %d, caller %d\n",
+              vcp->vc_inuse, vcp->vc_pid, current->pid);
 
-       memset(&coda_callstats, 0, sizeof(struct coda_upcallstats));
        EXIT;
         return 0;
 }
 
 
-static int
-coda_psdev_release(struct inode * inode, struct file * file)
+
+static int coda_psdev_release(struct inode * inode, struct file * file)
 {
-        struct vcomm *vcp;
-        struct vmsg *vmp;
-       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+        struct venus_comm *vcp = &coda_upc_comm;
+        struct upc_req *req;
+       struct list_head *lh, *next;
        ENTRY;
 
-        vcp = coda_psdev2vcomm(file);
+       if ( !vcp->vc_inuse ) {
+               printk("psdev_release: Not open.\n");
+               return -1;
+       }
+
+       vcp->vc_inuse--;
+       MOD_DEC_USE_COUNT;
+       CDEBUG(D_PSDEV, "inuse: %d, vc_pid %d, caller %d\n",
+              vcp->vc_inuse, vcp->vc_pid, current->pid);
+
+       if ( vcp->vc_pid != current->pid ) {
+               return 0;
+       }
         
-        if ( !vcp || !vcomm_open(vcp) ) {
-              printk("psdev_release: not open");
-              return 0;
-        }
-    
-       
-       /* flush the name cache so that we can unmount */
-       CDEBUG(D_PSDEV, "Flushing the cache.\n");
-       /* cfsnc_flush(); */
-       /* cfsnc_use = 0; */
-       CDEBUG(D_PSDEV, "Done.\n");
-       
-       /* if operations are in progress perhaps the kernel
-          can profit from setting the C_DYING flag on the root 
-          cnode of Coda filesystems */
-        if (coda_super_info[minor].sbi_root) {
-                struct coda_inode_info *cnp = 
-                       ITOC(coda_super_info[minor].sbi_root);
-                cnp->c_flags |= C_DYING;
-        } else 
-               vcp->vc_inuse = 0;      
-       
-    
+       vcp->vc_pid = 0;
         /* Wakeup clients so they can return. */
-        for (vmp = q_getnext(&(vcp->vc_pending));
-             !q_end(vmp, &(vcp->vc_pending));
-             vmp = q_getnext(&(vmp->vm_chain))) {          
-              /* Free signal request messages and don't wakeup cause
-                 no one is waiting. */
-              if (vmp->vm_opcode == CFS_SIGNAL) {
-                    CODA_FREE(vmp->vm_data, sizeof(struct cfs_in_hdr));
-                    CODA_FREE(vmp, (u_int)sizeof(struct vmsg));
-                    continue;
-              }
-              wake_up(&vmp->vm_sleep);
+       CDEBUG(D_PSDEV, "wake up pending clients\n");
+       lh = vcp->vc_pending.next;
+       next = lh;
+       while ( (lh = next) != &vcp->vc_pending) {
+               next = lh->next;
+               req = list_entry(lh, struct upc_req, uc_chain);
+               /* Async requests need to be freed here */
+               if (req->uc_flags & REQ_ASYNC) {
+                       CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
+                       CODA_FREE(req, (u_int)sizeof(struct upc_req));
+                       continue;
+               }
+               wake_up(&req->uc_sleep);
         }
         
-        for (vmp = q_getnext(&(vcp->vc_processing));
-             !q_end(vmp, &(vcp->vc_processing));
-             vmp = q_getnext(&(vmp->vm_chain))) {
-               wake_up(&vmp->vm_sleep);
+       lh = &vcp->vc_processing;
+       CDEBUG(D_PSDEV, "wake up processing clients\n");
+       while ( (lh = lh->next) != &vcp->vc_processing) {
+               req = list_entry(lh, struct upc_req, uc_chain);
+               wake_up(&req->uc_sleep);
         }
-        
-        mark_vcomm_closed(vcp);
-       MOD_DEC_USE_COUNT;
+       CDEBUG(D_PSDEV, "Done.\n");
+
        EXIT;
        return 0;
 }
@@ -395,94 +333,6 @@ static struct file_operations coda_psdev_fops = {
 };
 
 
-#ifdef CONFIG_PROC_FS
-
-
-struct proc_dir_entry proc_sys_coda = {
-        0, 4, "coda",
-        S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
-        0, &proc_dir_inode_operations,
-       NULL, NULL,
-       NULL,
-       NULL, NULL
-};
-
-/*
- target directory structure:
-   /proc/fs  (see linux/fs/proc/root.c)
-   /proc/fs/coda
-   /proc/fs/coda/{vfs_stats,
-
-*/
-
-
-struct proc_dir_entry proc_fs_coda = {
-        PROC_FS_CODA, 4, "coda",
-        S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
-        0, &proc_dir_inode_operations,
-       NULL, NULL,
-       NULL,
-       NULL, NULL
-};
-
-struct proc_dir_entry proc_coda_vfs =  {
-                PROC_VFS_STATS , 9, "vfs_stats",
-                S_IFREG | S_IRUGO, 1, 0, 0,
-                0, &proc_net_inode_operations,
-                coda_vfs_stats_get_info
-        };
-
-struct proc_dir_entry proc_coda_vfs_control =  {
-                0 , 9, "vfs_stats",
-                S_IFREG | S_IRUGO, 1, 0, 0,
-                0, &proc_net_inode_operations,
-                coda_vfs_stats_get_info
-        };
-
-struct proc_dir_entry proc_coda_upcall =  {
-                PROC_UPCALL_STATS , 12, "upcall_stats",
-                S_IFREG | S_IRUGO, 1, 0, 0,
-                0, &proc_net_inode_operations,
-                coda_upcall_stats_get_info
-        };
-
-struct proc_dir_entry proc_coda_upcall_control =  {
-                0 , 12, "upcall_stats",
-                S_IFREG | S_IRUGO, 1, 0, 0,
-                0, &proc_net_inode_operations,
-                coda_upcall_stats_get_info
-        };
-
-struct proc_dir_entry proc_coda_permission =  {
-                PROC_PERMISSION_STATS , 16, "permission_stats",
-                S_IFREG | S_IRUGO, 1, 0, 0,
-                0, &proc_net_inode_operations,
-                coda_permission_stats_get_info
-        };
-
-struct proc_dir_entry proc_coda_permission_control =  {
-                0 , 16, "permission_stats",
-                S_IFREG | S_IRUGO, 1, 0, 0,
-                0, &proc_net_inode_operations,
-                coda_permission_stats_get_info
-        };
-
-struct proc_dir_entry proc_coda_cache_inv =  {
-                PROC_CACHE_INV_STATS , 15, "cache_inv_stats",
-                S_IFREG | S_IRUGO, 1, 0, 0,
-                0, &proc_net_inode_operations,
-                coda_cache_inv_stats_get_info
-        };
-
-struct proc_dir_entry proc_coda_cache_inv_control =  {
-                0 , 15, "cache_inv_stats",
-                S_IFREG | S_IRUGO, 1, 0, 0,
-                0, &proc_net_inode_operations,
-                coda_cache_inv_stats_get_info
-        };
-
-#endif
-
 
 __initfunc(int init_coda(void)) 
 {
@@ -509,32 +359,11 @@ int init_coda_psdev(void)
                     CODA_PSDEV_MAJOR);
               return -EIO;
        }
-       memset(psdev_vcomm, 0, sizeof(psdev_vcomm));
-       memset(coda_super_info, 0, sizeof(coda_super_info));
-       memset(&coda_callstats, 0, sizeof(coda_callstats));
-
-       reset_coda_vfs_stats();
-       reset_coda_upcall_stats();
-       reset_coda_permission_stats();
-       reset_coda_cache_inv_stats();
-
-#ifdef CONFIG_PROC_FS
-       proc_register(&proc_root_fs,&proc_fs_coda);
-       proc_register(&proc_fs_coda,&proc_coda_vfs);
-       proc_register(&proc_fs_coda,&proc_coda_upcall);
-       proc_register(&proc_fs_coda,&proc_coda_permission);
-       proc_register(&proc_fs_coda,&proc_coda_cache_inv);
-#endif
-
-#ifdef CONFIG_SYSCTL
-       proc_register(&proc_sys_root,&proc_sys_coda);
-       proc_register(&proc_sys_coda,&proc_coda_vfs_control);
-       proc_register(&proc_sys_coda,&proc_coda_upcall_control);
-       proc_register(&proc_sys_coda,&proc_coda_permission_control);
-       proc_register(&proc_sys_coda,&proc_coda_cache_inv_control);
+       memset(&coda_upc_comm, 0, sizeof(coda_upc_comm));
+       memset(&coda_super_info, 0, sizeof(coda_super_info));
 
        coda_sysctl_init();
-#endif 
+
        return 0;
 }
 
@@ -546,7 +375,7 @@ MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
 int init_module(void)
 {
        int status;
-       printk(KERN_INFO "Coda Kernel/Venus communications (module), v4.7.1, braam@cs.cmu.edu.\n");
+       printk(KERN_INFO "Coda Kernel/Venus communications (module), v4.7.5, braam@cs.cmu.edu.\n");
 
        status = init_coda_psdev();
        if ( status ) {
@@ -572,24 +401,7 @@ void cleanup_module(void)
                 printk("coda: failed to unregister filesystem\n");
         }
         unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
-
-#if CONFIG_PROC_FS
-        coda_sysctl_clean();
-
-        proc_unregister(&proc_sys_coda, proc_coda_cache_inv_control.low_ino);
-        proc_unregister(&proc_sys_coda, proc_coda_permission_control.low_ino);
-        proc_unregister(&proc_sys_coda, proc_coda_upcall_control.low_ino);
-       proc_unregister(&proc_sys_coda, proc_coda_vfs_control.low_ino);
-       proc_unregister(&proc_sys_root, proc_sys_coda.low_ino);
-#endif
-
-#ifdef CONFIG_SYSCTL
-        proc_unregister(&proc_fs_coda, proc_coda_cache_inv.low_ino);
-        proc_unregister(&proc_fs_coda, proc_coda_permission.low_ino);
-        proc_unregister(&proc_fs_coda, proc_coda_upcall.low_ino);
-        proc_unregister(&proc_fs_coda, proc_coda_vfs.low_ino);
-       proc_unregister(&proc_root_fs, proc_fs_coda.low_ino);
-#endif 
+       coda_sysctl_clean();
 }
 
 #endif
index 1b55b8ea7f9a915b7737f12e6fb1fbfe134b3898..d4a8b2e9b3321d787cbdccec0e7fc242a07bf026 100644 (file)
@@ -30,7 +30,7 @@
 struct coda_vfs_stats          coda_vfs_stat;
 struct coda_permission_stats   coda_permission_stat;
 struct coda_cache_inv_stats    coda_cache_inv_stat;
-struct coda_upcall_stats_entry coda_upcall_stat[CFS_NCALLS];
+struct coda_upcall_stats_entry coda_upcall_stat[CODA_NCALLS];
 
 /* keep this in sync with coda.h! */
 char *coda_upcall_names[] = {
@@ -122,7 +122,7 @@ void coda_upcall_stats(int opcode, long unsigned runtime)
 {
        struct coda_upcall_stats_entry * pentry;
        
-       if ( opcode < 0 || opcode > CFS_NCALLS - 1) {
+       if ( opcode < 0 || opcode > CODA_NCALLS - 1) {
                printk("Nasty opcode %d passed to coda_upcall_stats\n",
                       opcode);
                return;
@@ -321,7 +321,7 @@ int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
        if ( offset < 320) 
                len += sprintf( buffer + len,"%-79s\n", "------\t\t    -----\t------------\t-----------------");
        pos = 320; 
-       for ( i = 0 ; i < CFS_NCALLS ; i++ ) {
+       for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
                tmplen += sprintf(tmpbuf,"%s\t%9d\t%10ld\t%10ld", 
                                  coda_upcall_names[i],
                                  coda_upcall_stat[i].count, 
index f065c027044cc46239431bf12e38d65056035278..b42555811e4951a39726a9c3a8e9d969b2ecc32c 100644 (file)
@@ -26,7 +26,8 @@
 #include <linux/coda_proc.h>
 
 static int coda_readlink(struct dentry *de, char *buffer, int length);
-static struct dentry *coda_follow_link(struct dentry *, struct dentry *, unsigned int);
+static struct dentry *coda_follow_link(struct dentry *, struct dentry *, 
+                                      unsigned int);
 
 struct inode_operations coda_symlink_inode_operations = {
        NULL,                   /* no file-operations */
@@ -64,8 +65,8 @@ static int coda_readlink(struct dentry *de, char *buffer, int length)
        coda_vfs_stat.readlink++;
 
         /* the maximum length we receive is len */
-        if ( length > CFS_MAXPATHLEN ) 
-               len = CFS_MAXPATHLEN;
+        if ( length > CODA_MAXPATHLEN ) 
+               len = CODA_MAXPATHLEN;
        else
                len = length;
        CODA_ALLOC(buf, char *, len);
@@ -85,15 +86,14 @@ static int coda_readlink(struct dentry *de, char *buffer, int length)
        return error;
 }
 
-static struct dentry *coda_follow_link(struct dentry *de, 
-                                      struct dentry *base,
+static struct dentry *coda_follow_link(struct dentry *de, struct dentry *base,
                                       unsigned int follow)
 {
        struct inode *inode = de->d_inode;
        int error;
        struct coda_inode_info *cnp;
        unsigned int len;
-       char mem[CFS_MAXPATHLEN];
+       char mem[CODA_MAXPATHLEN];
        char *path;
        ENTRY;
        CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino);
@@ -101,7 +101,7 @@ static struct dentry *coda_follow_link(struct dentry *de,
         cnp = ITOC(inode);
        coda_vfs_stat.follow_link++;
 
-       len = CFS_MAXPATHLEN;
+       len = CODA_MAXPATHLEN;
        error = venus_readlink(inode->i_sb, &(cnp->c_fid), mem, &len);
 
        if (error) {
index 36e327dce0fa585c68d53321846f000a53659691..8f3bd532a2b8d0dc22ca8959ffdaefa0d94eb3b2 100644 (file)
@@ -5,9 +5,13 @@
  * 
  * Carnegie Mellon encourages users to contribute improvements to
  * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
+ * 
+ * CODA operation statistics
+ * (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu>
+ *
  */
-/* sysctl entries for Coda! */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <linux/coda_psdev.h>
 #include <linux/coda_cache.h>
 #include <linux/coda_proc.h>
-extern int coda_debug;
-/* extern int cfsnc_use; */
-extern int coda_print_entry;
-/* extern int cfsnc_flushme; */
-extern int cfsnc_procsize;
-/* extern void cfsnc_flush(void); */
-void coda_sysctl_init(void);
-void coda_sysctl_clean(void);
-
-int coda_dointvec(ctl_table *table, int write, struct file *filp,
-                  void *buffer, size_t *lenp);
-
-struct ctl_table_header *fs_table_header, *coda_table_header;
+
+static struct ctl_table_header *fs_table_header;
+
 #define FS_CODA         1       /* Coda file system */
 
 #define CODA_DEBUG      1       /* control debugging */
@@ -52,14 +46,12 @@ struct ctl_table_header *fs_table_header, *coda_table_header;
 #define CODA_PERMISSION         8       /* permission statistics */
 #define CODA_CACHE_INV          9       /* cache invalidation statistics */
 
-
-
 static ctl_table coda_table[] = {
-       {CODA_DEBUG, "debug", &coda_debug, sizeof(int), 0644, NULL, &coda_dointvec},
-       {CODA_ENTRY, "printentry", &coda_print_entry, sizeof(int), 0644, NULL, &coda_dointvec},
-       {CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &coda_dointvec}, 
-       {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &coda_dointvec},
-       {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &coda_dointvec},
+       {CODA_DEBUG, "debug", &coda_debug, sizeof(int), 0644, NULL, &proc_dointvec},
+       {CODA_ENTRY, "printentry", &coda_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
+       {CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &proc_dointvec}, 
+       {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec},
+       {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec},
        {CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats},
        {CODA_UPCALL, "upcall_stats", NULL, 0, 0644, NULL, &do_reset_coda_upcall_stats},
        {CODA_PERMISSION, "permission_stats", NULL, 0, 0644, NULL, &do_reset_coda_permission_stats},
@@ -67,114 +59,478 @@ static ctl_table coda_table[] = {
        { 0 }
 };
 
-
 static ctl_table fs_table[] = {
        {FS_CODA, "coda",    NULL, 0, 0555, coda_table},
        {0}
 };
 
+struct coda_vfs_stats          coda_vfs_stat;
+struct coda_permission_stats   coda_permission_stat;
+struct coda_cache_inv_stats    coda_cache_inv_stat;
+struct coda_upcall_stats_entry  coda_upcall_stat[CODA_NCALLS];
+struct coda_upcallstats         coda_callstats;
+
+/* keep this in sync with coda.h! */
+char *coda_upcall_names[] = {
+       "totals      ",   /*  0 */
+       "noop        ",   /*  1 */
+       "root        ",   /*  2 */
+       "sync        ",   /*  3 */
+       "open        ",   /*  4 */
+       "close       ",   /*  5 */
+       "ioctl       ",   /*  6 */
+       "getattr     ",   /*  7 */
+       "setattr     ",   /*  8 */
+       "access      ",   /*  9 */
+       "lookup      ",   /* 10 */
+       "create      ",   /* 11 */
+       "remove      ",   /* 12 */
+       "link        ",   /* 13 */
+       "rename      ",   /* 14 */
+       "mkdir       ",   /* 15 */
+       "rmdir       ",   /* 16 */
+       "readdir     ",   /* 17 */
+       "symlink     ",   /* 18 */
+       "readlink    ",   /* 19 */
+       "fsync       ",   /* 20 */
+       "inactive    ",   /* 21 */
+       "vget        ",   /* 22 */
+       "signal      ",   /* 23 */
+       "replace     ",   /* 24 */
+       "flush       ",   /* 25 */
+       "purgeuser   ",   /* 26 */
+       "zapfile     ",   /* 27 */
+       "zapdir      ",   /* 28 */
+       "zapvnode    ",   /* 28 */
+       "purgefid    ",   /* 30 */
+       "open_by_path"    /* 31 */
+};
+
+
+void reset_coda_vfs_stats( void )
+{
+       memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
+}
+
+void reset_coda_upcall_stats( void )
+{
+       memset( &coda_upcall_stat, 0, sizeof( coda_upcall_stat ) );
+}
+
+void reset_coda_permission_stats( void )
+{
+       memset( &coda_permission_stat, 0, sizeof( coda_permission_stat ) );
+}
+
+void reset_coda_cache_inv_stats( void )
+{
+       memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
+}
+
+
+void do_time_stats( struct coda_upcall_stats_entry * pentry, 
+                   unsigned long runtime )
+{
+       
+       unsigned long time = runtime * 1000 /HZ;        /* time in ms */
+       CDEBUG(D_SPECIAL, "time: %ld\n", time);
+
+       if ( pentry->count == 0 ) {
+               pentry->time_sum = pentry->time_squared_sum = 0;
+       }
+       
+       pentry->count++;
+       pentry->time_sum += time;
+       pentry->time_squared_sum += time*time;
+}
+
+
+
+void coda_upcall_stats(int opcode, long unsigned runtime) 
+{
+       struct coda_upcall_stats_entry * pentry;
+       
+       if ( opcode < 0 || opcode > CODA_NCALLS - 1) {
+               printk("Nasty opcode %d passed to coda_upcall_stats\n",
+                      opcode);
+               return;
+       }
+               
+       pentry = &coda_upcall_stat[opcode];
+       do_time_stats(pentry, runtime);
+
+        /* fill in the totals */
+       pentry = &coda_upcall_stat[0];
+       do_time_stats(pentry, runtime);
+
+}
+
+unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry )
+{
+       return ( pentry->count == 0 ) ? 0 : pentry->time_sum / pentry->count;
+}
+
+static inline unsigned long absolute( unsigned long x )
+{
+       return x >= 0 ? x : -x;
+}
+
+static unsigned long sqr_root( unsigned long x )
+{
+       unsigned long y = x, r;
+       int n_bit = 0;
+  
+       if ( x == 0 )
+               return 0;
+       if ( x < 0)
+               x = -x;
+
+       while ( y ) {
+               y >>= 1;
+               n_bit++;
+       }
+  
+       r = 1 << (n_bit/2);
+  
+       while ( 1 ) {
+               r = (r + x/r)/2;
+               if ( r*r <= x && x < (r+1)*(r+1) )
+                       break;
+       }
+  
+       return r;
+}
+
+unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry )
+{
+       unsigned long time_avg;
+  
+       if ( pentry->count <= 1 )
+               return 0;
+  
+       time_avg = get_time_average( pentry );
+       return 
+               sqr_root( (pentry->time_squared_sum / pentry->count) - 
+                           time_avg * time_avg );
+}
+
+int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
+                            void * buffer, size_t * lenp )
+{
+       if ( write ) {
+               reset_coda_vfs_stats();
+       }
+  
+       *lenp = 0;
+       return 0;
+}
+
+int do_reset_coda_upcall_stats( ctl_table * table, int write, 
+                               struct file * filp, void * buffer, 
+                               size_t * lenp )
+{
+       if ( write ) {
+               reset_coda_upcall_stats();
+       }
+  
+       *lenp = 0;
+       return 0;
+}
+
+int do_reset_coda_permission_stats( ctl_table * table, int write, 
+                                   struct file * filp, void * buffer, 
+                                   size_t * lenp )
+{
+       if ( write ) {
+               reset_coda_permission_stats();
+       }
+  
+       *lenp = 0;
+       return 0;
+}
+
+int do_reset_coda_cache_inv_stats( ctl_table * table, int write, 
+                                  struct file * filp, void * buffer, 
+                                  size_t * lenp )
+{
+       if ( write ) {
+               reset_coda_cache_inv_stats();
+       }
+  
+       *lenp = 0;
+       return 0;
+}
+
+int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
+                            int length, int dummy )
+{
+       int len=0;
+       off_t begin;
+       struct coda_vfs_stats * ps = & coda_vfs_stat;
+  
+  /* this works as long as we are below 1024 characters! */
+       len += sprintf( buffer,
+                       "Coda VFS statistics\n"
+                       "===================\n\n"
+                       "File Operations:\n"
+                       "\tfile_read\t%9d\n"
+                       "\tfile_write\t%9d\n"
+                       "\tfile_mmap\t%9d\n"
+                       "\topen\t\t%9d\n"
+                       "\trelase\t\t%9d\n"
+                       "\tfsync\t\t%9d\n\n"
+                       "Dir Operations:\n"
+                       "\treaddir\t\t%9d\n\n"
+                       "Inode Operations\n"
+                       "\tcreate\t\t%9d\n"
+                       "\tlookup\t\t%9d\n"
+                       "\tlink\t\t%9d\n"
+                       "\tunlink\t\t%9d\n"
+                       "\tsymlink\t\t%9d\n"
+                       "\tmkdir\t\t%9d\n"
+                       "\trmdir\t\t%9d\n"
+                       "\trename\t\t%9d\n"
+                       "\tpermission\t%9d\n"
+                       "\treadpage\t%9d\n",
+
+                       /* file operations */
+                       ps->file_read,
+                       ps->file_write,
+                       ps->file_mmap,
+                       ps->open,
+                       ps->release,
+                       ps->fsync,
+
+                       /* dir operations */
+                       ps->readdir,
+                 
+                       /* inode operations */
+                       ps->create,
+                       ps->lookup,
+                       ps->link,
+                       ps->unlink,
+                       ps->symlink,
+                       ps->mkdir,
+                       ps->rmdir,
+                       ps->rename,
+                       ps->permission,
+                       ps->readpage );
+  
+       begin = offset;
+       *start = buffer + begin;
+       len -= begin;
+
+       if ( len > length )
+               len = length;
+       if ( len < 0 )
+               len = 0;
+
+       return len;
+}
+
+int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
+                               int length, int dummy )
+{
+       int len=0;
+       int i;
+       off_t begin;
+       off_t pos = 0;
+       char tmpbuf[80];
+       int tmplen = 0;
+
+       ENTRY;
+       /* this works as long as we are below 1024 characters! */
+       if ( offset < 80 ) 
+               len += sprintf( buffer,"%-79s\n",       "Coda upcall statistics");
+       if ( offset < 160) 
+               len += sprintf( buffer + len,"%-79s\n", "======================");
+       if ( offset < 240) 
+               len += sprintf( buffer + len,"%-79s\n", "upcall\t\t    count\tavg time(ms)\tstd deviation(ms)");
+       if ( offset < 320) 
+               len += sprintf( buffer + len,"%-79s\n", "------\t\t    -----\t------------\t-----------------");
+       pos = 320; 
+       for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
+               tmplen += sprintf(tmpbuf,"%s\t%9d\t%10ld\t%10ld", 
+                                 coda_upcall_names[i],
+                                 coda_upcall_stat[i].count, 
+                                 get_time_average(&coda_upcall_stat[i]),
+                                 coda_upcall_stat[i].time_squared_sum);
+               pos += 80;
+               if ( pos < offset ) 
+                       continue; 
+               len += sprintf(buffer + len, "%-79s\n", tmpbuf);
+               if ( len >= length ) 
+                       break; 
+       }
+  
+       begin = len- (pos - offset);
+       *start = buffer + begin;
+       len -= begin;
+
+       if ( len > length )
+               len = length;
+       if ( len < 0 )
+               len = 0;
+       EXIT;
+       return len;
+}
+
+int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
+                                   int length, int dummy )
+{
+       int len=0;
+       off_t begin;
+       struct coda_permission_stats * ps = & coda_permission_stat;
+  
+       /* this works as long as we are below 1024 characters! */
+       len += sprintf( buffer,
+                       "Coda permission statistics\n"
+                       "==========================\n\n"
+                       "count\t\t%9d\n"
+                       "hit count\t%9d\n",
+
+                       ps->count,
+                       ps->hit_count );
+  
+       begin = offset;
+       *start = buffer + begin;
+       len -= begin;
+
+       if ( len > length )
+               len = length;
+       if ( len < 0 )
+               len = 0;
+
+       return len;
+}
+
+int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
+                                  int length, int dummy )
+{
+       int len=0;
+       off_t begin;
+       struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
+  
+       /* this works as long as we are below 1024 characters! */
+       len += sprintf( buffer,
+                       "Coda cache invalidation statistics\n"
+                       "==================================\n\n"
+                       "flush\t\t%9d\n"
+                       "purge user\t%9d\n"
+                       "zap_dir\t\t%9d\n"
+                       "zap_file\t%9d\n"
+                       "zap_vnode\t%9d\n"
+                       "purge_fid\t%9d\n"
+                       "replace\t\t%9d\n",
+                       ps->flush,
+                       ps->purge_user,
+                       ps->zap_dir,
+                       ps->zap_file,
+                       ps->zap_vnode,
+                       ps->purge_fid,
+                       ps->replace );
+  
+       begin = offset;
+       *start = buffer + begin;
+       len -= begin;
+
+       if ( len > length )
+               len = length;
+       if ( len < 0 )
+               len = 0;
+
+       return len;
+}
+
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ target directory structure:
+   /proc/fs  (see linux/fs/proc/root.c)
+   /proc/fs/coda
+   /proc/fs/coda/{vfs_stats,
+
+*/
+
+struct proc_dir_entry proc_fs_coda = {
+        PROC_FS_CODA, 4, "coda",
+        S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+        0, &proc_dir_inode_operations,
+       NULL, NULL,
+       NULL,
+       NULL, NULL
+};
+
+struct proc_dir_entry proc_coda_vfs =  {
+                PROC_VFS_STATS , 9, "vfs_stats",
+                S_IFREG | S_IRUGO, 1, 0, 0,
+                0, &proc_net_inode_operations,
+                coda_vfs_stats_get_info
+        };
+
+struct proc_dir_entry proc_coda_upcall =  {
+                PROC_UPCALL_STATS , 12, "upcall_stats",
+                S_IFREG | S_IRUGO, 1, 0, 0,
+                0, &proc_net_inode_operations,
+                coda_upcall_stats_get_info
+        };
+
+struct proc_dir_entry proc_coda_permission =  {
+                PROC_PERMISSION_STATS , 16, "permission_stats",
+                S_IFREG | S_IRUGO, 1, 0, 0,
+                0, &proc_net_inode_operations,
+                coda_permission_stats_get_info
+        };
+
+
+struct proc_dir_entry proc_coda_cache_inv =  {
+                PROC_CACHE_INV_STATS , 15, "cache_inv_stats",
+                S_IFREG | S_IRUGO, 1, 0, 0,
+                0, &proc_net_inode_operations,
+                coda_cache_inv_stats_get_info
+        };
+
+#endif
 
 
 void coda_sysctl_init()
 {
-       fs_table_header = register_sysctl_table(fs_table, 0);
-/*     coda_table_header = register_sysctl_table(coda_table, 0);*/
-}
-
-void coda_sysctl_clean() {
-       /*unregister_sysctl_table(coda_table_header);*/
-       unregister_sysctl_table(fs_table_header);
-}
-
-int coda_dointvec(ctl_table *table, int write, struct file *filp,
-                  void *buffer, size_t *lenp)
-{
-        int *i, vleft, first=1, len, left, neg, val;
-        #define TMPBUFLEN 20
-        char buf[TMPBUFLEN], *p;
-        
-        if (!table->data || !table->maxlen || !*lenp ||
-            (filp->f_pos && !write)) {
-                *lenp = 0;
-                return 0;
-        }
-        
-        i = (int *) table->data;
-        vleft = table->maxlen / sizeof(int);
-        left = *lenp;
-        
-        for (; left && vleft--; i++, first=0) {
-                if (write) {
-                       while (left) {
-                               char c;
-                               if(get_user(c,(char *) buffer))
-                                       return -EFAULT;
-                               if (!isspace(c))
-                                       break;
-                               left--;
-                               ((char *) buffer)++;
-                       }
-                        if (!left)
-                                break;
-                        neg = 0;
-                        len = left;
-                        if (len > TMPBUFLEN-1)
-                                len = TMPBUFLEN-1;
-                        if (copy_from_user(buf, buffer, len))
-                               return -EFAULT;
-                        buf[len] = 0;
-                        p = buf;
-                        if (*p == '-' && left > 1) {
-                                neg = 1;
-                                left--, p++;
-                        }
-                        if (*p < '0' || *p > '9')
-                                break;
-                        val = simple_strtoul(p, &p, 0);
-                        len = p-buf;
-                        if ((len < left) && *p && !isspace(*p))
-                                break;
-                        if (neg)
-                                val = -val;
-                        buffer += len;
-                        left -= len;
-                        *i = val;
-                } else {
-                        p = buf;
-                        if (!first)
-                                *p++ = '\t';
-                        sprintf(p, "%d", *i);
-                        len = strlen(buf);
-                        if (len > left)
-                                len = left;
-                        if (copy_to_user(buffer, buf, len))
-                           return -EFAULT;
-                        left -= len;
-                        buffer += len;
-                }
-        }
-
-        if (!write && !first && left) {
-                if(put_user('\n', (char *) buffer))
-                       return -EFAULT;
-                left--, buffer++;
-        }
-        if (write) {
-                p = (char *) buffer;
-                while (left) {
-                       char c;
-                       if(get_user(c, p++))
-                               return -EFAULT;
-                       if (!isspace(c))
-                               break;
-                       left--;
-               }
-        }
-        if (write && first)
-                return -EINVAL;
-        *lenp -= left;
-        filp->f_pos += *lenp;
-        return 0;
+       memset(&coda_callstats, 0, sizeof(coda_callstats));
+       reset_coda_vfs_stats();
+       reset_coda_upcall_stats();
+       reset_coda_permission_stats();
+       reset_coda_cache_inv_stats();
+
+#ifdef CONFIG_PROC_FS
+       proc_register(&proc_root_fs,&proc_fs_coda);
+       proc_register(&proc_fs_coda,&proc_coda_vfs);
+       proc_register(&proc_fs_coda,&proc_coda_upcall);
+       proc_register(&proc_fs_coda,&proc_coda_permission);
+       proc_register(&proc_fs_coda,&proc_coda_cache_inv);
+#endif
+
+#ifdef CONFIG_SYSCTL
+       if ( !fs_table_header )
+               fs_table_header = register_sysctl_table(fs_table, 0);
+#endif 
 }
 
+void coda_sysctl_clean() 
+{
+
+#ifdef CONFIG_SYSCTL
+       if ( fs_table_header ) {
+               unregister_sysctl_table(fs_table_header);
+               fs_table_header = 0;
+       }
+#endif
 
+#if CONFIG_PROC_FS
+        proc_unregister(&proc_fs_coda, proc_coda_cache_inv.low_ino);
+        proc_unregister(&proc_fs_coda, proc_coda_permission.low_ino);
+        proc_unregister(&proc_fs_coda, proc_coda_upcall.low_ino);
+        proc_unregister(&proc_fs_coda, proc_coda_vfs.low_ino);
+       proc_unregister(&proc_root_fs, proc_fs_coda.low_ino);
+#endif 
+}
index dadf27c7e754eea1ee2545fa6b16e806a3abf368..ddb27c3d4b2440f3a525736de91a1f46c6fb52a3 100644 (file)
@@ -63,8 +63,8 @@ static inline int max(int a, int b)
                return b;
 }
 
-#define INSIZE(tag) sizeof(struct cfs_ ## tag ## _in)
-#define OUTSIZE(tag) sizeof(struct cfs_ ## tag ## _out)
+#define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
+#define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
 #define SIZE(tag)  max(INSIZE(tag), OUTSIZE(tag))
 
 
@@ -77,14 +77,14 @@ int venus_rootfid(struct super_block *sb, ViceFid *fidp)
        ENTRY;
 
         insize = SIZE(root);
-        UPARG(CFS_ROOT);
+        UPARG(CODA_ROOT);
 
        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
        
        if (error) {
                printk("coda_get_rootfid: error %d\n", error);
        } else {
-               *fidp = (ViceFid) outp->cfs_root.VFid;
+               *fidp = (ViceFid) outp->coda_root.VFid;
                CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n",
                       fidp->Volume, fidp->Vnode);
        }
@@ -103,13 +103,13 @@ int venus_getattr(struct super_block *sb, struct ViceFid *fid,
        ENTRY;
 
         insize = SIZE(getattr); 
-       UPARG(CFS_GETATTR);
-        inp->cfs_getattr.VFid = *fid;
+       UPARG(CODA_GETATTR);
+        inp->coda_getattr.VFid = *fid;
 
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
        
        if ( !error )
-               *attr = outp->cfs_getattr.attr;
+               *attr = outp->coda_getattr.attr;
 
         if (inp) 
                CODA_FREE(inp, insize);
@@ -125,10 +125,10 @@ int  venus_setattr(struct super_block *sb, struct ViceFid *fid,
         int insize, outsize, error;
        
        insize= SIZE(setattr);
-       UPARG(CFS_SETATTR);
+       UPARG(CODA_SETATTR);
 
-        inp->cfs_setattr.VFid = *fid;
-       inp->cfs_setattr.attr = *vattr;
+        inp->coda_setattr.VFid = *fid;
+       inp->coda_setattr.attr = *vattr;
 
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
@@ -148,10 +148,11 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid,
 
        offset = INSIZE(lookup);
         insize =  max(offset + length +1, OUTSIZE(lookup));
-       UPARG(CFS_LOOKUP);
+       UPARG(CODA_LOOKUP);
 
-        inp->cfs_lookup.VFid = *fid;
-       inp->cfs_lookup.name = offset;
+        inp->coda_lookup.VFid = *fid;
+       inp->coda_lookup.name = offset;
+       inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
         /* send Venus a null terminated string */
         memcpy((char *)(inp) + offset, name, length);
         *((char *)inp + offset + length) = '\0';
@@ -159,8 +160,8 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid,
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
        if ( !error ) {
-               *resfid = outp->cfs_lookup.VFid;
-               *type = outp->cfs_lookup.vtype;
+               *resfid = outp->coda_lookup.VFid;
+               *type = outp->coda_lookup.vtype;
        }
        if (inp) CODA_FREE(inp, insize);
                
@@ -168,17 +169,23 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid,
 }
 
 
-int venus_release(struct super_block *sb, struct ViceFid *fid, int flags)
+int venus_release(struct super_block *sb, struct ViceFid *fid, int flags,
+                 struct coda_cred *cred)
 {
         union inputArgs *inp;
         union outputArgs *outp;
         int insize, outsize, error;
        
        insize = SIZE(close);
-       UPARG(CFS_CLOSE);
-
-        inp->cfs_close.VFid = *fid;
-        inp->cfs_close.flags = flags;
+       UPARG(CODA_CLOSE);
+       
+       if ( cred ) {
+               memcpy(&(inp->ih.cred), cred, sizeof(*cred));
+       } else 
+               printk("CODA: close without valid file creds.\n");
+       
+        inp->coda_close.VFid = *fid;
+        inp->coda_close.flags = flags;
 
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
@@ -195,16 +202,16 @@ int venus_open(struct super_block *sb, struct ViceFid *fid,
         int insize, outsize, error;
        
        insize = SIZE(open);
-       UPARG(CFS_OPEN);
+       UPARG(CODA_OPEN);
 
-        inp->cfs_open.VFid = *fid;
-        inp->cfs_open.flags = flags;
+        inp->coda_open.VFid = *fid;
+        inp->coda_open.flags = flags;
 
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
        if ( !error ) {
-               *ino = outp->cfs_open.inode;
-               *dev = outp->cfs_open.dev;
+               *ino = outp->coda_open.inode;
+               *dev = outp->coda_open.dev;
        } else {
                *ino = 0;
                *dev = 0;
@@ -227,19 +234,19 @@ int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
 
        offset = INSIZE(mkdir);
        insize = max(offset + length + 1, OUTSIZE(mkdir));
-       UPARG(CFS_MKDIR);
+       UPARG(CODA_MKDIR);
 
-        inp->cfs_mkdir.VFid = *dirfid;
-        inp->cfs_mkdir.attr = *attrs;
-       inp->cfs_mkdir.name = offset;
+        inp->coda_mkdir.VFid = *dirfid;
+        inp->coda_mkdir.attr = *attrs;
+       inp->coda_mkdir.name = offset;
         /* Venus must get null terminated string */
         memcpy((char *)(inp) + offset, name, length);
         *((char *)inp + offset + length) = '\0';
         
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-       *attrs = outp->cfs_mkdir.attr;
-       *newfid = outp->cfs_mkdir.VFid;
+       *attrs = outp->coda_mkdir.attr;
+       *newfid = outp->coda_mkdir.VFid;
 
        if (inp) 
                CODA_FREE(inp, insize);
@@ -260,11 +267,11 @@ int venus_rename(struct super_block *sb, struct ViceFid *old_fid,
        offset = INSIZE(rename);
        insize = max(offset + new_length + old_length + 8,
                     OUTSIZE(rename)); 
-       UPARG(CFS_RENAME);
+       UPARG(CODA_RENAME);
 
-        inp->cfs_rename.sourceFid = *old_fid;
-        inp->cfs_rename.destFid =  *new_fid;
-        inp->cfs_rename.srcname = offset;
+        inp->coda_rename.sourceFid = *old_fid;
+        inp->coda_rename.destFid =  *new_fid;
+        inp->coda_rename.srcname = offset;
 
         /* Venus must receive an null terminated string */
         s = ( old_length & ~0x3) +4; /* round up to word boundary */
@@ -273,13 +280,13 @@ int venus_rename(struct super_block *sb, struct ViceFid *old_fid,
 
         /* another null terminated string for Venus */
         offset += s;
-        inp->cfs_rename.destname = offset;
+        inp->coda_rename.destname = offset;
         s = ( new_length & ~0x3) +4; /* round up to word boundary */
         memcpy((char *)(inp) + offset, new_name, new_length);
         *((char *)inp + offset + new_length) = '\0';
 
         CDEBUG(D_INODE, "destname in packet: %s\n", 
-              (char *)inp + (int) inp->cfs_rename.destname);
+              (char *)inp + (int) inp->coda_rename.destname);
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
        if (inp) CODA_FREE(inp, insize);
@@ -297,14 +304,14 @@ int venus_create(struct super_block *sb, struct ViceFid *dirfid,
 
         offset = INSIZE(create);
        insize = max(offset + length + 1, OUTSIZE(create));
-       UPARG(CFS_CREATE);
+       UPARG(CODA_CREATE);
 
-        inp->cfs_create.VFid = *dirfid;
-        inp->cfs_create.attr.va_mode = mode;
-        inp->cfs_create.attr.va_rdev = rdev;
-       inp->cfs_create.excl = excl;
-        inp->cfs_create.mode = mode;
-        inp->cfs_create.name = offset;
+        inp->coda_create.VFid = *dirfid;
+        inp->coda_create.attr.va_mode = mode;
+        inp->coda_create.attr.va_rdev = rdev;
+       inp->coda_create.excl = excl;
+        inp->coda_create.mode = mode;
+        inp->coda_create.name = offset;
 
         /* Venus must get null terminated string */
         memcpy((char *)(inp) + offset, name, length);
@@ -312,8 +319,8 @@ int venus_create(struct super_block *sb, struct ViceFid *dirfid,
                 
         error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
-       *attrs = outp->cfs_create.attr;
-       *newfid = outp->cfs_create.VFid;
+       *attrs = outp->coda_create.attr;
+       *newfid = outp->coda_create.VFid;
 
        if (inp) 
                CODA_FREE(inp, insize);
@@ -330,10 +337,10 @@ int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid,
 
         offset = INSIZE(rmdir);
        insize = max(offset + length + 1, OUTSIZE(rmdir));
-       UPARG(CFS_RMDIR);
+       UPARG(CODA_RMDIR);
 
-        inp->cfs_rmdir.VFid = *dirfid;
-        inp->cfs_rmdir.name = offset;
+        inp->coda_rmdir.VFid = *dirfid;
+        inp->coda_rmdir.name = offset;
         memcpy((char *)(inp) + offset, name, length);
        *((char *)inp + offset + length) = '\0';
         
@@ -352,10 +359,10 @@ int venus_remove(struct super_block *sb, struct ViceFid *dirfid,
 
         offset = INSIZE(remove);
        insize = max(offset + length + 1, OUTSIZE(remove));
-       UPARG(CFS_REMOVE);
+       UPARG(CODA_REMOVE);
 
-        inp->cfs_remove.VFid = *dirfid;
-        inp->cfs_remove.name = offset;
+        inp->coda_remove.VFid = *dirfid;
+        inp->coda_remove.name = offset;
         memcpy((char *)(inp) + offset, name, length);
        *((char *)inp + offset + length) = '\0';
         
@@ -375,18 +382,18 @@ int venus_readlink(struct super_block *sb, struct ViceFid *fid,
         char *result;
         
        insize = max(INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
-       UPARG(CFS_READLINK);
+       UPARG(CODA_READLINK);
 
-        inp->cfs_readlink.VFid = *fid;
+        inp->coda_readlink.VFid = *fid;
     
         error =  coda_upcall(coda_sbp(sb), insize, &outsize, inp);
        
        if (! error) {
-                retlen = outp->cfs_readlink.count;
+                retlen = outp->coda_readlink.count;
                if ( retlen > *length )
                        retlen = *length;
                *length = retlen;
-               result =  (char *)outp + (int)outp->cfs_readlink.data;
+               result =  (char *)outp + (int)outp->coda_readlink.data;
                memcpy(buffer, result, retlen);
                *(buffer + retlen) = '\0';
        }
@@ -409,11 +416,11 @@ int venus_link(struct super_block *sb, struct ViceFid *fid,
 
        offset = INSIZE(link);
        insize = max(offset  + len + 1, OUTSIZE(link));
-        UPARG(CFS_LINK);
+        UPARG(CODA_LINK);
 
-        inp->cfs_link.sourceFid = *fid;
-        inp->cfs_link.destFid = *dirfid;
-        inp->cfs_link.tname = offset;
+        inp->coda_link.sourceFid = *fid;
+        inp->coda_link.destFid = *dirfid;
+        inp->coda_link.tname = offset;
 
         /* make sure strings are null terminated */
         memcpy((char *)(inp) + offset, name, len);
@@ -439,20 +446,20 @@ int venus_symlink(struct super_block *sb, struct ViceFid *fid,
 
         offset = INSIZE(symlink);
        insize = max(offset + len + symlen + 8, OUTSIZE(symlink));
-       UPARG(CFS_SYMLINK);
+       UPARG(CODA_SYMLINK);
         
-        /*        inp->cfs_symlink.attr = *tva; XXXXXX */ 
-        inp->cfs_symlink.VFid = *fid;
+        /*        inp->coda_symlink.attr = *tva; XXXXXX */ 
+        inp->coda_symlink.VFid = *fid;
 
        /* Round up to word boundary and null terminate */
-        inp->cfs_symlink.srcname = offset;
+        inp->coda_symlink.srcname = offset;
         s = ( symlen  & ~0x3 ) + 4; 
         memcpy((char *)(inp) + offset, symname, symlen);
         *((char *)inp + offset + symlen) = '\0';
         
        /* Round up to word boundary and null terminate */
         offset += s;
-        inp->cfs_symlink.tname = offset;
+        inp->coda_symlink.tname = offset;
         s = (len & ~0x3) + 4;
         memcpy((char *)(inp) + offset, name, len);
         *((char *)inp + offset + len) = '\0';
@@ -473,9 +480,9 @@ int venus_fsync(struct super_block *sb, struct ViceFid *fid)
        int insize, outsize, error;
        
        insize=SIZE(fsync);
-       UPARG(CFS_FSYNC);
+       UPARG(CODA_FSYNC);
 
-        inp->cfs_fsync.VFid = *fid;
+        inp->coda_fsync.VFid = *fid;
         error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs), 
                             &outsize, inp);
 
@@ -491,10 +498,10 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
        int insize, outsize, error;
 
        insize = SIZE(access);
-       UPARG(CFS_ACCESS);
+       UPARG(CODA_ACCESS);
 
-        inp->cfs_access.VFid = *fid;
-        inp->cfs_access.flags = mask;
+        inp->coda_access.VFid = *fid;
+        inp->coda_access.flags = mask;
 
        error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
 
@@ -513,7 +520,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
        int iocsize;
 
        insize = VC_MAXMSGSIZE;
-       UPARG(CFS_IOCTL);
+       UPARG(CODA_IOCTL);
 
         /* build packet for Venus */
         if (data->vi.in_size > VC_MAXDATASIZE) {
@@ -521,21 +528,21 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
                goto exit;
         }
 
-        inp->cfs_ioctl.VFid = *fid;
+        inp->coda_ioctl.VFid = *fid;
     
         /* the cmd field was mutated by increasing its size field to
          * reflect the path and follow args. We need to subtract that
          * out before sending the command to Venus.  */
-        inp->cfs_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));   
+        inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));  
         iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
-        inp->cfs_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<     16;     
+        inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) <<    16;     
     
-        /* in->cfs_ioctl.rwflag = flag; */
-        inp->cfs_ioctl.len = data->vi.in_size;
-        inp->cfs_ioctl.data = (char *)(INSIZE(ioctl));
+        /* in->coda_ioctl.rwflag = flag; */
+        inp->coda_ioctl.len = data->vi.in_size;
+        inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
      
         /* get the data out of user space */
-        if ( copy_from_user((char*)inp + (int)inp->cfs_ioctl.data,
+        if ( copy_from_user((char*)inp + (int)inp->coda_ioctl.data,
                            data->vi.in, data->vi.in_size) ) {
                error = EINVAL;
                goto exit;
@@ -550,9 +557,9 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
        }
         
        /* Copy out the OUT buffer. */
-        if (outp->cfs_ioctl.len > data->vi.out_size) {
+        if (outp->coda_ioctl.len > data->vi.out_size) {
                 CDEBUG(D_FILE, "return len %d <= request len %d\n",
-                      outp->cfs_ioctl.len, 
+                      outp->coda_ioctl.len, 
                       data->vi.out_size);
                 error = EINVAL;
         } else {
@@ -561,7 +568,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
                if ( error ) goto exit;
 
                if (copy_to_user(data->vi.out, 
-                                (char *)outp + (int)outp->cfs_ioctl.data, 
+                                (char *)outp + (int)outp->coda_ioctl.data, 
                                 data->vi.out_size)) {
                        error = EINVAL;
                        goto exit;
@@ -579,15 +586,15 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
  * 
  */
 
-static inline unsigned long coda_waitfor_upcall(struct vmsg *vmp)
+static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
 {
        struct wait_queue       wait = { current, NULL };
        unsigned long posttime;
 
-       vmp->vm_posttime = jiffies;
+       vmp->uc_posttime = jiffies;
        posttime = jiffies;
 
-       add_wait_queue(&vmp->vm_sleep, &wait);
+       add_wait_queue(&vmp->uc_sleep, &wait);
        for (;;) {
                if ( coda_hard == 0 ) 
                        current->state = TASK_INTERRUPTIBLE;
@@ -595,7 +602,7 @@ static inline unsigned long coda_waitfor_upcall(struct vmsg *vmp)
                        current->state = TASK_UNINTERRUPTIBLE;
 
                /* got a reply */
-               if ( vmp->vm_flags & VM_WRITE )
+               if ( vmp->uc_flags & REQ_WRITE )
                        break;
 
                if ( !coda_hard && signal_pending(current) ) {
@@ -605,13 +612,13 @@ static inline unsigned long coda_waitfor_upcall(struct vmsg *vmp)
                                break;
                        /* signal is present: after timeout always return 
                           really smart idea, probably useless ... */
-                       if ( jiffies > vmp->vm_posttime + coda_timeout * HZ )
+                       if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
                                break; 
                }
                schedule();
 
        }
-       remove_wait_queue(&vmp->vm_sleep, &wait);
+       remove_wait_queue(&vmp->uc_sleep, &wait);
        current->state = TASK_RUNNING;
 
        CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n", posttime, jiffies-posttime);
@@ -635,40 +642,37 @@ static int coda_upcall(struct coda_sb_info *sbi,
                union inputArgs *buffer) 
 {
        unsigned long runtime; 
-       struct vcomm *vcommp;
+       struct venus_comm *vcommp;
        union outputArgs *out;
-       struct vmsg *vmp;
+       struct upc_req *req;
        int error = 0;
 
 ENTRY;
 
-       if (sbi->sbi_vcomm == NULL) {
-                return -ENODEV;
-       }
-       vcommp = sbi->sbi_vcomm;
-
-
-       if (!vcomm_open(vcommp))
+       vcommp = &coda_upc_comm;
+       if ( !vcommp->vc_pid ) {
+               printk("No pseudo device in upcall comms at %p\n", vcommp);
                 return -ENXIO;
+       }
 
        /* Format the request message. */
-       CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
-       vmp->vm_data = (void *)buffer;
-       vmp->vm_flags = 0;
-       vmp->vm_inSize = inSize;
-       vmp->vm_outSize = *outSize ? *outSize : inSize;
-       vmp->vm_opcode = ((union inputArgs *)buffer)->ih.opcode;
-       vmp->vm_unique = ++vcommp->vc_seq;
-        vmp->vm_sleep = NULL;
+       CODA_ALLOC(req,struct upc_req *,sizeof(struct upc_req));
+       req->uc_data = (void *)buffer;
+       req->uc_flags = 0;
+       req->uc_inSize = inSize;
+       req->uc_outSize = *outSize ? *outSize : inSize;
+       req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
+       req->uc_unique = ++vcommp->vc_seq;
+        req->uc_sleep = NULL;
        
        /* Fill in the common input args. */
-       ((union inputArgs *)buffer)->ih.unique = vmp->vm_unique;
+       ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
 
        /* Append msg to pending queue and poke Venus. */
-       coda_q_insert(&(vmp->vm_chain), &(vcommp->vc_pending));
+       list_add(&(req->uc_chain), vcommp->vc_pending.prev);
        CDEBUG(D_UPCALL, 
               "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %x.zzz.\n",
-              current->pid, vmp->vm_opcode, vmp->vm_unique, (int)vmp);
+              current->pid, req->uc_opcode, req->uc_unique, (int)req);
 
        wake_up_interruptible(&vcommp->vc_waitq);
        /* We can be interrupted while we wait for Venus to process
@@ -681,19 +685,19 @@ ENTRY;
         * ENODEV.  */
 
        /* Go to sleep.  Wake up on signals only after the timeout. */
-       runtime = coda_waitfor_upcall(vmp);
+       runtime = coda_waitfor_upcall(req);
        coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
 
        CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
-              vmp->vm_opcode, jiffies - vmp->vm_posttime, 
-              vmp->vm_unique, vmp->vm_outSize);
+              req->uc_opcode, jiffies - req->uc_posttime, 
+              req->uc_unique, req->uc_outSize);
        CDEBUG(D_UPCALL, 
-              "..process %d woken up by Venus for vmp at 0x%x, data at %x\n", 
-              current->pid, (int)vmp, (int)vmp->vm_data);
-       if (vcomm_open(vcommp)) {      /* i.e. Venus is still alive */
+              "..process %d woken up by Venus for req at 0x%x, data at %x\n", 
+              current->pid, (int)req, (int)req->uc_data);
+       if (vcommp->vc_pid) {      /* i.e. Venus is still alive */
            /* Op went through, interrupt or not... */
-           if (vmp->vm_flags & VM_WRITE) {
-               out = (union outputArgs *)vmp->vm_data;
+           if (req->uc_flags & REQ_WRITE) {
+               out = (union outputArgs *)req->uc_data;
                /* here we map positive Venus errors to kernel errors */
                if ( out->oh.result < 0 ) {
                        printk("Tell Peter: Venus returns negative error %ld, for oc %ld!\n",
@@ -704,49 +708,49 @@ ENTRY;
                CDEBUG(D_UPCALL, 
                       "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n", 
                       out->oh.unique, out->oh.opcode, out->oh.result, out);
-               *outSize = vmp->vm_outSize;
+               *outSize = req->uc_outSize;
                goto exit;
            }
-           if ( !(vmp->vm_flags & VM_READ) && signal_pending(current)) { 
+           if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) { 
                /* Interrupted before venus read it. */
                CDEBUG(D_UPCALL, 
                       "Interrupted before read:(op,un) (%d.%d), flags = %x\n",
-                      vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
-               coda_q_remove(&(vmp->vm_chain));
+                      req->uc_opcode, req->uc_unique, req->uc_flags);
+               list_del(&(req->uc_chain));
                /* perhaps the best way to convince the app to
                   give up? */
                error = -EINTR;
                goto exit;
            } 
-           if ( (vmp->vm_flags & VM_READ) && signal_pending(current) ) {
+           if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
                    /* interrupted after Venus did its read, send signal */
-                   union inputArgs *dog;
-                   struct vmsg *svmp;
+                   union inputArgs *sig_inputArgs;
+                   struct upc_req *sig_req;
                    
                    CDEBUG(D_UPCALL, 
                           "Sending Venus a signal: op = %d.%d, flags = %x\n",
-                          vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
+                          req->uc_opcode, req->uc_unique, req->uc_flags);
                    
-                   coda_q_remove(&(vmp->vm_chain));
+                   list_del(&(req->uc_chain));
                    error = -EINTR;
-                   CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
-                   CODA_ALLOC((svmp->vm_data), char *, sizeof(struct cfs_in_hdr));
+                   CODA_ALLOC(sig_req, struct upc_req *, sizeof (struct upc_req));
+                   CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
                    
-                   dog = (union inputArgs *)svmp->vm_data;
-                   dog->ih.opcode = CFS_SIGNAL;
-                   dog->ih.unique = vmp->vm_unique;
+                   sig_inputArgs = (union inputArgs *)sig_req->uc_data;
+                   sig_inputArgs->ih.opcode = CODA_SIGNAL;
+                   sig_inputArgs->ih.unique = req->uc_unique;
                    
-                   svmp->vm_flags = 0;
-                   svmp->vm_opcode = dog->ih.opcode;
-                   svmp->vm_unique = dog->ih.unique;
-                   svmp->vm_inSize = sizeof(struct cfs_in_hdr);
-                   svmp->vm_outSize = sizeof(struct cfs_in_hdr);
+                   sig_req->uc_flags = REQ_ASYNC;
+                   sig_req->uc_opcode = sig_inputArgs->ih.opcode;
+                   sig_req->uc_unique = sig_inputArgs->ih.unique;
+                   sig_req->uc_inSize = sizeof(struct coda_in_hdr);
+                   sig_req->uc_outSize = sizeof(struct coda_in_hdr);
                    CDEBUG(D_UPCALL, 
                           "coda_upcall: enqueing signal msg (%d, %d)\n",
-                          svmp->vm_opcode, svmp->vm_unique);
+                          sig_req->uc_opcode, sig_req->uc_unique);
                    
                    /* insert at head of queue! */
-                   coda_q_insert(&(svmp->vm_chain), vcommp->vc_pending.forw);
+                   list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
                    wake_up_interruptible(&vcommp->vc_waitq);
            } else {
                    printk("Coda: Strange interruption..\n");
@@ -754,12 +758,12 @@ ENTRY;
            }
        } else {        /* If venus died i.e. !VC_OPEN(vcommp) */
                printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
-                      vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
+                      req->uc_opcode, req->uc_unique, req->uc_flags);
                error = -ENODEV;
        }
 
  exit:
-       CODA_FREE(vmp, sizeof(struct vmsg));
+       CODA_FREE(req, sizeof(struct upc_req));
        if (error) 
                badclstats();
        return error;
@@ -778,26 +782,26 @@ ENTRY;
  * There are 7 cases where cache invalidations occur.  The semantics
  *  of each is listed here:
  *
- * CFS_FLUSH     -- flush all entries from the name cache and the cnode cache.
- * CFS_PURGEUSER -- flush all entries from the name cache for a specific user
+ * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
+ * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
  *                  This call is a result of token expiration.
  *
  * The next arise as the result of callbacks on a file or directory.
- * CFS_ZAPFILE   -- flush the cached attributes for a file.
+ * CODA_ZAPFILE   -- flush the cached attributes for a file.
 
- * CFS_ZAPDIR    -- flush the attributes for the dir and
+ * CODA_ZAPDIR    -- flush the attributes for the dir and
  *                  force a new lookup for all the children
                     of this dir.
 
  *
  * The next is a result of Venus detecting an inconsistent file.
- * CFS_PURGEFID  -- flush the attribute for the file
+ * CODA_PURGEFID  -- flush the attribute for the file
  *                  purge it and its children from the dcache
  *
  * The last  allows Venus to replace local fids with global ones
  * during reintegration.
  *
- * CFS_REPLACE -- replace one ViceFid with another throughout the name cache */
+ * CODA_REPLACE -- replace one ViceFid with another throughout the name cache */
 
 int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
 {
@@ -810,37 +814,38 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
 
          switch (opcode) {
 
-         case CFS_FLUSH : {
-                  clstats(CFS_FLUSH);
-                  CDEBUG(D_DOWNCALL, "CFS_FLUSH\n");
+         case CODA_FLUSH : {
+                  clstats(CODA_FLUSH);
+                  CDEBUG(D_DOWNCALL, "CODA_FLUSH\n");
                   coda_cache_clear_all(sb);
                   shrink_dcache_sb(sb);
+                  coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
                   return(0);
          }
 
-         case CFS_PURGEUSER : {
-                  struct coda_cred *cred = &out->cfs_purgeuser.cred;
-                  CDEBUG(D_DOWNCALL, "CFS_PURGEUSER\n");
+         case CODA_PURGEUSER : {
+                  struct coda_cred *cred = &out->coda_purgeuser.cred;
+                  CDEBUG(D_DOWNCALL, "CODA_PURGEUSER\n");
                   if ( !cred ) {
                           printk("PURGEUSER: null cred!\n");
                           return 0;
                   }
-                  clstats(CFS_PURGEUSER);
+                  clstats(CODA_PURGEUSER);
                   coda_cache_clear_cred(sb, cred);
                   return(0);
          }
 
-         case CFS_ZAPDIR : {
+         case CODA_ZAPDIR : {
                  struct inode *inode;
-                 ViceFid *fid = &out->cfs_zapdir.CodaFid;
+                 ViceFid *fid = &out->coda_zapdir.CodaFid;
                  CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
-                 clstats(CFS_ZAPDIR);
+                 clstats(CODA_ZAPDIR);
 
                  inode = coda_fid_to_inode(fid, sb);
                  if (inode) {
                          CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n", 
                                 inode->i_ino);
-                         coda_purge_children(inode);
+                         coda_flag_inode_children(inode, C_PURGE);
                          CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
                          coda_flag_inode(inode, C_VATTR);
                  } else 
@@ -849,10 +854,10 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
                  return(0);
          }
 
-         case CFS_ZAPFILE : {
+         case CODA_ZAPFILE : {
                  struct inode *inode;
-                 struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
-                 clstats(CFS_ZAPFILE);
+                 struct ViceFid *fid = &out->coda_zapfile.CodaFid;
+                 clstats(CODA_ZAPFILE);
                  CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
                  inode = coda_fid_to_inode(fid, sb);
                  if ( inode ) {
@@ -863,27 +868,27 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
                  return 0;
          }
 
-         case CFS_PURGEFID : {
+         case CODA_PURGEFID : {
                  struct inode *inode;
-                 ViceFid *fid = &out->cfs_purgefid.CodaFid;
+                 ViceFid *fid = &out->coda_purgefid.CodaFid;
                  CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
-                 clstats(CFS_PURGEFID);
+                 clstats(CODA_PURGEFID);
                  inode = coda_fid_to_inode(fid, sb);
                  if ( inode ) { 
                          CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n", inode->i_ino);
-                         coda_purge_children(inode);
+                         coda_flag_inode_children(inode, C_PURGE);
                          coda_purge_dentries(inode);
                  }else 
                          CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
                  return 0;
          }
 
-         case CFS_REPLACE : {
+         case CODA_REPLACE : {
                  struct inode *inode;
-                 ViceFid *oldfid = &out->cfs_replace.OldFid;
-                 ViceFid *newfid = &out->cfs_replace.NewFid;
-                 clstats(CFS_REPLACE);
-                 CDEBUG(D_DOWNCALL, "CFS_REPLACE\n");
+                 ViceFid *oldfid = &out->coda_replace.OldFid;
+                 ViceFid *newfid = &out->coda_replace.NewFid;
+                 clstats(CODA_REPLACE);
+                 CDEBUG(D_DOWNCALL, "CODA_REPLACE\n");
                  inode = coda_fid_to_inode(oldfid, sb);
                  if ( inode ) { 
                          CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n", inode->i_ino);
index 540d4ca7cfde855d93120b10b1081df962ed6ce3..cd8ec43d481d2dfbde2d0858ca0e6fe3074d695d 100644 (file)
@@ -430,19 +430,6 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
                if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
                                              EXT2_FEATURE_INCOMPAT_FILETYPE))
                        de->file_type = EXT2_FT_REG_FILE;
-       } else if (S_ISDIR(inode->i_mode)) {
-               inode->i_op = &ext2_dir_inode_operations;
-               if (dir->i_mode & S_ISGID)
-                       inode->i_mode |= S_ISGID;
-               if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
-                                             EXT2_FEATURE_INCOMPAT_FILETYPE))
-                       de->file_type = EXT2_FT_DIR;
-       }
-       else if (S_ISLNK(inode->i_mode)) {
-               inode->i_op = &ext2_symlink_inode_operations;
-               if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
-                                             EXT2_FEATURE_INCOMPAT_FILETYPE))
-                       de->file_type = EXT2_FT_SYMLINK;
        } else if (S_ISCHR(inode->i_mode)) {
                inode->i_op = &chrdev_inode_operations;
                if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
@@ -701,14 +688,6 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
        inode = dentry->d_inode;
        DQUOT_INIT(inode);
 
-       retval = -EPERM;
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               goto end_unlink;
-       if ((dir->i_mode & S_ISVTX) &&
-           current->fsuid != inode->i_uid &&
-           current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
-               goto end_unlink;
-
        retval = -EIO;
        if (le32_to_cpu(de->inode) != inode->i_ino)
                goto end_unlink;
@@ -896,17 +875,15 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
                goto end_rename;
 
        old_bh = ext2_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
-       retval = -ENOENT;
-       if (!old_bh)
-               goto end_rename;
+       /*
+        *  Check for inode number is _not_ due to possible IO errors.
+        *  We might rmdir the source, keep it as pwd of some process
+        *  and merrily kill the link to whatever was created under the
+        *  same name. Goodbye sticky bit ;-<
+        */
        old_inode = old_dentry->d_inode;
-
-       retval = -EPERM;
-       if ((old_dir->i_mode & S_ISVTX) && 
-           current->fsuid != old_inode->i_uid &&
-           current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER))
-               goto end_rename;
-       if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode))
+       retval = -ENOENT;
+       if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino)
                goto end_rename;
 
        new_inode = new_dentry->d_inode;
@@ -923,39 +900,21 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
        retval = 0;
        if (new_inode == old_inode)
                goto end_rename;
-       if (new_inode && S_ISDIR(new_inode->i_mode)) {
-               retval = -EISDIR;
-               if (!S_ISDIR(old_inode->i_mode))
-                       goto end_rename;
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
-               /* Prune any children before testing for busy */
-               if (new_dentry->d_count > 1)
-                       shrink_dcache_parent(new_dentry);
-               retval = -ENOTEMPTY;
-               if (!empty_dir (new_inode))
-                       goto end_rename;
-               retval = -EBUSY;
-               if (new_dentry->d_count > 1)
-                       goto end_rename;
-       }
-       retval = -EPERM;
-       if (new_inode) {
-               if ((new_dir->i_mode & S_ISVTX) &&
-                   current->fsuid != new_inode->i_uid &&
-                   current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER))
-                       goto end_rename;
-               if (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode))
-                       goto end_rename;
-       }
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -ENOTDIR;
-               if (new_inode && !S_ISDIR(new_inode->i_mode))
-                       goto end_rename;
                retval = -EINVAL;
                if (is_subdir(new_dentry, old_dentry))
                        goto end_rename;
+               if (new_inode) {
+                       /* Prune any children before testing for busy */
+                       if (new_dentry->d_count > 1)
+                               shrink_dcache_parent(new_dentry);
+                       retval = -EBUSY;
+                       if (new_dentry->d_count > 1)
+                               goto end_rename;
+                       retval = -ENOTEMPTY;
+                       if (!empty_dir (new_inode))
+                               goto end_rename;
+               }
                dir_bh = ext2_bread (old_inode, 0, 0, &retval);
                if (!dir_bh)
                        goto end_rename;
index 3735fbd16df717d22026c46f9e3360de75d2b72e..86f99c56d03d2f54427f478cfd1fc30b0a3008b6 100644 (file)
@@ -267,13 +267,6 @@ int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
        inode->i_op = NULL;
        if (S_ISREG(inode->i_mode))
                inode->i_op = &minix_file_inode_operations;
-       else if (S_ISDIR(inode->i_mode)) {
-               inode->i_op = &minix_dir_inode_operations;
-               if (dir->i_mode & S_ISGID)
-                       inode->i_mode |= S_ISGID;
-       }
-       else if (S_ISLNK(inode->i_mode))
-               inode->i_op = &minix_symlink_inode_operations;
        else if (S_ISCHR(inode->i_mode))
                inode->i_op = &chrdev_inode_operations;
        else if (S_ISBLK(inode->i_mode))
@@ -483,10 +476,6 @@ repeat:
                schedule();
                goto repeat;
        }
-       if ((dir->i_mode & S_ISVTX) &&
-           current->fsuid != inode->i_uid &&
-           current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
-               goto end_unlink;
        if (de->inode != inode->i_ino) {
                retval = -ENOENT;
                goto end_unlink;
@@ -642,10 +631,6 @@ start_up:
                goto end_rename;
        old_inode = old_dentry->d_inode;
        retval = -EPERM;
-       if ((old_dir->i_mode & S_ISVTX) && 
-           current->fsuid != old_inode->i_uid &&
-           current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER))
-               goto end_rename;
        new_inode = new_dentry->d_inode;
        new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
                                  new_dentry->d_name.len, &new_de);
@@ -659,32 +644,21 @@ start_up:
                retval = 0;
                goto end_rename;
        }
-       if (new_inode && S_ISDIR(new_inode->i_mode)) {
-               retval = -EISDIR;
-               if (!S_ISDIR(old_inode->i_mode))
-                       goto end_rename;
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
-               retval = -ENOTEMPTY;
-               if (!empty_dir(new_inode))
-                       goto end_rename;
-               retval = -EBUSY;
-               if (new_inode->i_count > 1)
-                       goto end_rename;
-       }
-       retval = -EPERM;
-       if (new_inode && (new_dir->i_mode & S_ISVTX) && 
-           current->fsuid != new_inode->i_uid &&
-           current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER))
-               goto end_rename;
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -ENOTDIR;
-               if (new_inode && !S_ISDIR(new_inode->i_mode))
-                       goto end_rename;
                retval = -EINVAL;
                if (is_subdir(new_dentry, old_dentry))
                        goto end_rename;
+               if (new_inode) {
+                       /* Prune any children before testing for busy */
+                       if (new_dentry->d_count > 1)
+                               shrink_dcache_parent(new_dentry);
+                       retval = -EBUSY;
+                       if (new_dentry->d_count > 1)
+                       retval = -ENOTEMPTY;
+                       if (!empty_dir(new_inode))
+                               goto end_rename;
+                       retval = -EBUSY;
+               }
                retval = -EIO;
                dir_bh = minix_bread(old_inode,0,0);
                if (!dir_bh)
index cff800a43a046af317e88b0fa4771e25c2f20a63..055d700d99a137061aaf3f17d3b8fe15d1bfc34c 100644 (file)
@@ -440,12 +440,9 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry)
        if (res < 0)
                goto rmdir_done;
        /*
-        * Check whether the directory is empty, then prune
-        * any child dentries and make sure it's not in use.
+        * Check whether the directory is not in use, then check
+        * whether it is empty.
         */
-       res = msdos_empty(inode);
-       if (res)
-               goto rmdir_done;
        res = -EBUSY;
        if (!list_empty(&dentry->d_hash)) {
 #ifdef MSDOS_DEBUG
@@ -454,6 +451,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
 #endif
                goto rmdir_done;
        }
+       res = msdos_empty(inode);
+       if (res)
+               goto rmdir_done;
 
        inode->i_nlink = 0;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -502,11 +502,14 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
 
        dir->i_nlink++;
        inode->i_nlink = 2; /* no need to mark them dirty */
-       MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
+
+#ifdef whatfor
        /*
-        * Instantiate the dentry now, in case we need to cleanup.
+        * He's dead, Jim. We don't d_instantiate anymore. Should do it
+        * from the very beginning, actually.
         */
-       d_instantiate(dentry, inode);
+       MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
+#endif
 
        if ((res = fat_add_cluster(inode)) < 0)
                goto mkdir_error;
@@ -526,8 +529,11 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
        MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
        dot->i_nlink = dir->i_nlink;
        mark_inode_dirty(dot);
+#ifdef whatfor
        MSDOS_I(inode)->i_busy = 0;
+#endif
        iput(dot);
+       d_instantiate(dentry, inode);
        res = 0;
 
 out_unlock:
@@ -536,8 +542,17 @@ out_unlock:
 
 mkdir_error:
        printk("msdos_mkdir: error=%d, attempting cleanup\n", res);
-       if (msdos_rmdir(dir,dentry) < 0)
-               fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
+       bh = NULL;
+       fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY);
+       inode->i_nlink = 0;
+       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+       dir->i_nlink--;
+       mark_inode_dirty(inode);
+       mark_inode_dirty(dir);
+       iput(inode);
+       de->name[0] = DELETED_FLAG;
+       fat_mark_buffer_dirty(sb, bh, 1);
+       fat_brelse(sb, bh);
        goto out_unlock;
 
 out_exist:
@@ -563,8 +578,6 @@ static int msdos_unlinkx( struct inode *dir, struct dentry *dentry, int nospc)
        res = -EPERM;
        if (!S_ISREG(inode->i_mode) && nospc)
                goto unlink_done;
-       if (IS_IMMUTABLE(inode))
-               goto unlink_done;
        /* N.B. check for busy files? */
 
        inode->i_nlink = 0;
index 66c92c87c7ab55c30a91ffd0b30d467245fd8cb7..7f0908387100526e291bbe33e485a0b1ef0e843d 100644 (file)
@@ -490,6 +490,77 @@ struct dentry * __namei(const char *pathname, unsigned int lookup_flags)
        return dentry;
 }
 
+/*
+ * It's inline, so penalty for filesystems that don't use sticky bit is
+ * minimal.
+ */
+static inline int check_sticky(struct inode *dir, struct inode *inode)
+{
+       if (!(dir->i_mode & S_ISVTX))
+               return 0;
+       if (inode->i_uid == current->fsuid)
+               return 0;
+       if (dir->i_uid == current->fsuid)
+               return 0;
+       return !capable(CAP_FOWNER);
+}
+
+/*
+ *     Check whether we can remove a link victim from directory dir, check
+ *  whether the type of victim is right.
+ *  1. We can't do it if dir is read-only (done in permission())
+ *  2. We should have write and exec permissions on dir
+ *  3. We can't remove anything from append-only dir
+ *  4. We can't do anything with immutable dir (done in permission())
+ *  5. If the sticky bit on dir is set we should either
+ *     a. be owner of dir, or
+ *     b. be owner of victim, or
+ *     c. have CAP_FOWNER capability
+ *  6. If the victim is append-only or immutable we can't do antyhing with
+ *     links pointing to it.
+ *  7. If we were asked to remove a directory and victim isn't one - ENOTDIR.
+ *  8. If we were asked to remove a non-directory and victim isn't one - EISDIR.
+ *  9. We can't remove a root or mountpoint.
+ */
+static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir)
+{
+       int error;
+       if (!victim->d_inode || victim->d_parent->d_inode != dir)
+               return -ENOENT;
+       error = permission(dir,MAY_WRITE | MAY_EXEC);
+       if (error)
+               return error;
+       if (IS_APPEND(dir))
+               return -EPERM;
+       if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
+           IS_IMMUTABLE(victim->d_inode))
+               return -EPERM;
+       if (isdir) {
+               if (!S_ISDIR(victim->d_inode->i_mode))
+                       return -ENOTDIR;
+               if (IS_ROOT(victim))
+                       return -EBUSY;
+               if (victim->d_mounts != victim->d_covers)
+                       return -EBUSY;
+       } else if (S_ISDIR(victim->d_inode->i_mode))
+               return -EISDIR;
+       return 0;
+}
+
+/*     Check whether we can create an object with dentry child in directory
+ *  dir.
+ *  1. We can't do it if child already exists (open has special treatment for
+ *     this case, but since we are inlined it's OK)
+ *  2. We can't do it if dir is read-only (done in permission())
+ *  3. We should have write and exec permissions on dir
+ *  4. We can't do it if dir is immutable (done in permission())
+ */
+static inline int may_create(struct inode *dir, struct dentry *child) {
+       if (child->d_inode)
+               return -EEXIST;
+       return permission(dir,MAY_WRITE | MAY_EXEC);
+}
+
 static inline struct dentry *get_parent(struct dentry *dentry)
 {
        return dget(dentry->d_parent);
@@ -599,16 +670,16 @@ struct dentry * open_namei(const char * pathname, int flag, int mode)
                        error = 0;
                        if (flag & O_EXCL)
                                error = -EEXIST;
-               } else if (IS_RDONLY(dir->d_inode))
-                       error = -EROFS;
-               else if (!dir->d_inode->i_op || !dir->d_inode->i_op->create)
-                       error = -EACCES;
-               else if ((error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC)) == 0) {
-                       DQUOT_INIT(dir->d_inode);
-                       error = dir->d_inode->i_op->create(dir->d_inode, dentry, mode);
-                       /* Don't check for write permission, don't truncate */
-                       acc_mode = 0;
-                       flag &= ~O_TRUNC;
+               } else if ((error = may_create(dir->d_inode, dentry)) == 0) {
+                       if (!dir->d_inode->i_op || !dir->d_inode->i_op->create)
+                               error = -EACCES;
+                       else {
+                               DQUOT_INIT(dir->d_inode);
+                               error = dir->d_inode->i_op->create(dir->d_inode, dentry, mode);
+                               /* Don't check for write permission, don't truncate */
+                               acc_mode = 0;
+                               flag &= ~O_TRUNC;
+                       }
                }
                unlock_dir(dir);
                if (error)
@@ -705,30 +776,20 @@ struct dentry * do_mknod(const char * filename, int mode, dev_t dev)
        if (IS_ERR(dir))
                goto exit;
 
-       retval = ERR_PTR(-EEXIST);
-       if (dentry->d_inode)
-               goto exit_lock;
-
-       retval = ERR_PTR(-EROFS);
-       if (IS_RDONLY(dir->d_inode))
-               goto exit_lock;
-
-       error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
-       retval = ERR_PTR(error);
+       error = may_create(dir->d_inode, dentry);
        if (error)
                goto exit_lock;
 
-       retval = ERR_PTR(-EPERM);
+       error = -EPERM;
        if (!dir->d_inode->i_op || !dir->d_inode->i_op->mknod)
                goto exit_lock;
 
        DQUOT_INIT(dir->d_inode);
        error = dir->d_inode->i_op->mknod(dir->d_inode, dentry, mode, dev);
+exit_lock:
        retval = ERR_PTR(error);
        if (!error)
                retval = dget(dentry);
-
-exit_lock:
        unlock_dir(dir);
 exit:
        dput(dentry);
@@ -790,15 +851,7 @@ static inline int do_mkdir(const char * pathname, int mode)
        if (IS_ERR(dir))
                goto exit_dput;
 
-       error = -EEXIST;
-       if (dentry->d_inode)
-               goto exit_lock;
-
-       error = -EROFS;
-       if (IS_RDONLY(dir->d_inode))
-               goto exit_lock;
-
-       error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
+       error = may_create(dir->d_inode, dentry);
        if (error)
                goto exit_lock;
 
@@ -865,66 +918,19 @@ static inline void double_unlock(struct dentry *d1, struct dentry *d2)
        dput(d2);
 }
 
-/*
- * It's inline, so penalty for filesystems that don't use sticky bit is
- * minimal.
- */
 
-static inline int check_sticky(struct inode *dir, struct inode *inode)
-{
-       if (!(dir->i_mode & S_ISVTX))
-               return 0;
-       if (inode->i_uid == current->fsuid)
-               return 0;
-       if (dir->i_uid == current->fsuid)
-               return 0;
-       return !capable(CAP_FOWNER);
-}
 
-int VFS_rmdir(struct inode *dir, struct dentry *dentry)
+int vfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
-       if (IS_RDONLY(dir))
-               return -EROFS;
-
-       error = permission(dir,MAY_WRITE | MAY_EXEC);
+       error = may_delete(dir, dentry, 1);
        if (error)
                return error;
 
-       /*
-        * A subdirectory cannot be removed from an append-only directory.
-        */
-       if (IS_APPEND(dir))
-               return -EPERM;
-       /*
-        * Check the sticky bit.
-        */
-       if (check_sticky(dir, dentry->d_inode))
-               return -EPERM;
-
-       /* Disallow removals of mountpoints. */
-       if (dentry->d_mounts != dentry->d_covers)
-               return -EBUSY;
-
        if (!dir->i_op || !dir->i_op->rmdir)
                return -EPERM;
-       /*
-        * I suspect that these two checks are atavisms copied from minixfs
-        * and it looks like they can be dropped. Anyway, it will be simpler
-        * to drop them from here and even if those checks are needed they
-        * belong to VFS.
-        */
-       if (dir == dentry->d_inode)
-               return -EPERM;
-       if (dir->i_dev != dentry->d_inode->i_dev)
-               return -EPERM;
-       /*
-        * Non-directories can't be rmdir'd. It may confuse the heck of
-        * NFS and CODA. Testing it in VFS is the Right Thing (tm), anyway.
-        */
-       if (!S_ISDIR(dentry->d_inode->i_mode))
-               return -ENOTDIR;
+
        DQUOT_INIT(dir);
 
        /*
@@ -970,6 +976,9 @@ static inline int do_rmdir(const char * name)
        error = -ENOENT;
        if (!dentry->d_inode)
                goto exit_dput;
+
+       dir = dget(dentry->d_parent);
+
        /*
         * The dentry->d_count stuff confuses d_delete() enough to
         * not kill the inode from under us while it is locked. This
@@ -977,14 +986,9 @@ static inline int do_rmdir(const char * name)
         * in the inode, not in the dentry..
         */
        dentry->d_count++;
-       dir = dget(dentry->d_parent);
        double_lock(dir, dentry);
 
-       /*
-        * Check that dentry still sits where it did and do the real stuff.
-        */
-       if (dentry->d_parent == dir)
-               error = VFS_rmdir(dir->d_inode, dentry);
+       error = vfs_rmdir(dir->d_inode, dentry);
 
        double_unlock(dentry, dir);
 exit_dput:
@@ -1009,6 +1013,25 @@ asmlinkage int sys_rmdir(const char * pathname)
        return error;
 }
 
+int vfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+       int error;
+
+       error = may_delete(dir, dentry, 0);
+       if (error)
+               goto exit_lock;
+
+       if (!dir->i_op || !dir->i_op->unlink)
+               goto exit_lock;
+
+       DQUOT_INIT(dir);
+
+       error = dir->i_op->unlink(dir, dentry);
+
+exit_lock:
+       return error;
+}
+
 static inline int do_unlink(const char * name)
 {
        int error;
@@ -1025,42 +1048,8 @@ static inline int do_unlink(const char * name)
        if (IS_ERR(dir))
                goto exit_dput;
 
-       error = -ENOENT;
-       if (!dentry->d_inode)
-               goto exit_lock;
-
-       /* Mount point? */
-       error = -EBUSY;
-       if (dentry == dir)
-               goto exit_lock;
-
-       error = -EROFS;
-       if (IS_RDONLY(dir->d_inode))
-               goto exit_lock;
-
-       error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
-       if (error)
-               goto exit_lock;
-
-       /*
-        * A directory can't be unlink'ed.
-        * A file cannot be removed from an append-only directory.
-        */
-       error = -EPERM;
-       if (S_ISDIR(dentry->d_inode->i_mode))
-               goto exit_lock;
-
-       if (IS_APPEND(dir->d_inode))
-               goto exit_lock;
-
-       if (!dir->d_inode->i_op || !dir->d_inode->i_op->unlink)
-               goto exit_lock;
+       error = vfs_unlink(dir->d_inode, dentry);
 
-       DQUOT_INIT(dir->d_inode);
-
-       error = dir->d_inode->i_op->unlink(dir->d_inode, dentry);
-
-exit_lock:
         unlock_dir(dir);
 exit_dput:
        dput(dentry);
@@ -1101,15 +1090,7 @@ static inline int do_symlink(const char * oldname, const char * newname)
        if (IS_ERR(dir))
                goto exit_dput;
 
-       error = -EEXIST;
-       if (dentry->d_inode)
-               goto exit_lock;
-
-       error = -EROFS;
-       if (IS_RDONLY(dir->d_inode))
-               goto exit_lock;
-
-       error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
+       error = may_create(dir->d_inode, dentry);
        if (error)
                goto exit_lock;
 
@@ -1185,22 +1166,14 @@ static inline int do_link(const char * oldname, const char * newname)
        if (!inode)
                goto exit_lock;
 
-       error = -EEXIST;
-       if (new_dentry->d_inode)
-               goto exit_lock;
-
-       error = -EROFS;
-       if (IS_RDONLY(dir->d_inode))
+       error = may_create(dir->d_inode, new_dentry);
+       if (error)
                goto exit_lock;
 
        error = -EXDEV;
        if (dir->d_inode->i_dev != inode->i_dev)
                goto exit_lock;
 
-       error = permission(dir->d_inode, MAY_WRITE | MAY_EXEC);
-       if (error)
-               goto exit_lock;
-
        /*
         * A link to an append-only or immutable file cannot be created.
         */
@@ -1247,6 +1220,38 @@ asmlinkage int sys_link(const char * oldname, const char * newname)
        return error;
 }
 
+int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+              struct inode *new_dir, struct dentry *new_dentry)
+{
+       int error;
+       int isdir;
+
+       isdir = S_ISDIR(old_dentry->d_inode->i_mode);
+
+       error = may_delete(old_dir, old_dentry, isdir); /* XXX */
+       if (error)
+               return error;
+
+       if (new_dir->i_dev != old_dir->i_dev)
+               return -EXDEV;
+
+       if (!new_dentry->d_inode)
+               error = may_create(new_dir, new_dentry);
+       else
+               error = may_delete(new_dir, new_dentry, isdir);
+       if (error)
+               return error;
+
+       if (!old_dir->i_op || !old_dir->i_op->rename)
+               return -EPERM;
+
+       DQUOT_INIT(old_dir);
+       DQUOT_INIT(new_dir);
+       error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+
+       return error;
+}
+
 static inline int do_rename(const char * oldname, const char * newname)
 {
        int error;
@@ -1279,43 +1284,9 @@ static inline int do_rename(const char * oldname, const char * newname)
 
        double_lock(new_dir, old_dir);
 
-       error = permission(old_dir->d_inode,MAY_WRITE | MAY_EXEC);
-       if (error)
-               goto exit_lock;
-       error = permission(new_dir->d_inode,MAY_WRITE | MAY_EXEC);
-       if (error)
-               goto exit_lock;
-
-       /* Disallow moves of mountpoints. */
-       error = -EBUSY;
-       if (old_dir == old_dentry || new_dir == new_dentry)
-               goto exit_lock;
-
-       error = -EXDEV;
-       if (new_dir->d_inode->i_dev != old_dir->d_inode->i_dev)
-               goto exit_lock;
-
-       error = -EROFS;
-       if (IS_RDONLY(new_dir->d_inode) || IS_RDONLY(old_dir->d_inode))
-               goto exit_lock;
+       error = vfs_rename(old_dir->d_inode, old_dentry,
+                          new_dir->d_inode, new_dentry);
 
-       /*
-        * A file cannot be removed from an append-only directory.
-        */
-       error = -EPERM;
-       if (IS_APPEND(old_dir->d_inode))
-               goto exit_lock;
-
-       error = -EPERM;
-       if (!old_dir->d_inode->i_op || !old_dir->d_inode->i_op->rename)
-               goto exit_lock;
-
-       DQUOT_INIT(old_dir->d_inode);
-       DQUOT_INIT(new_dir->d_inode);
-       error = old_dir->d_inode->i_op->rename(old_dir->d_inode, old_dentry,
-                                              new_dir->d_inode, new_dentry);
-
-exit_lock:
        double_unlock(new_dir, old_dir);
        dput(new_dentry);
 exit_old:
index 87810f32c614667d9067324febbf8eadf48d42e7..9798050c520533c6862ef18b108380a514b6b26a 100644 (file)
@@ -996,13 +996,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
            (tlen == 1 || (tlen == 2 && tname[1] == '.'))))
                goto out;
 
-       err = -EXDEV;
-       if (fdir->i_dev != tdir->i_dev)
-               goto out_nfserr;
-       err = -EPERM;
-       if (!fdir->i_op || !fdir->i_op->rename)
-               goto out_nfserr;
-
        odentry = lookup_dentry(fname, dget(fdentry), 0);
        err = PTR_ERR(odentry);
        if (IS_ERR(odentry))
@@ -1019,9 +1012,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
        /* N.B. check for parent changes after locking?? */
 
-       DQUOT_INIT(fdir);
-       DQUOT_INIT(tdir);
-       err = fdir->i_op->rename(fdir, odentry, tdir, ndentry);
+       err = vfs_rename(fdir, odentry, tdir, ndentry);
        if (!err && EX_ISSYNC(tfhp->fh_export)) {
                write_inode_now(fdir);
                write_inode_now(tdir);
@@ -1072,24 +1063,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        if (IS_ERR(rdentry))
                goto out_nfserr;
 
-       /*
-        * FIXME!!
-        *
-        * This should do a double-lock on both rdentry and the parent
-        *
-        * Moreover, it should do checks *both* for unlink and rmdir
-        * cases. AV
-        */
        if (type != S_IFDIR) {
                /* It's UNLINK */
                err = fh_lock_parent(fhp, rdentry);
                if (err)
                        goto out;
 
-               DQUOT_INIT(dirp);
-               err = -EPERM;
-               if (dirp->i_op && dirp->i_op->unlink)
-                       err = dirp->i_op->unlink(dirp, rdentry);
+               err = vfs_unlink(dirp, rdentry);
+
                DQUOT_DROP(dirp);
                fh_unlock(fhp);
 
@@ -1107,7 +1088,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
 
                err = -ENOENT;
                if (rdentry->d_parent->d_inode == dirp)
-                       err = VFS_rmdir(dirp, rdentry);
+                       err = vfs_rmdir(dirp, rdentry);
 
                rdentry->d_count--;
                DQUOT_DROP(dirp);
index 17df1d30ca15fd7c31fe7a516cc93b3eb97c73d4..884800970278b517c4707bccc99ae85c9e264ac7 100644 (file)
@@ -29,15 +29,16 @@ if [ "$CONFIG_NLS" = "y" ]; then
   tristate 'Codepage 866 (Cyrillic/Russian)'       CONFIG_NLS_CODEPAGE_866
   tristate 'Codepage 869 (Greek)'                  CONFIG_NLS_CODEPAGE_869
   tristate 'Codepage 874 (Thai)'                   CONFIG_NLS_CODEPAGE_874
-  tristate 'NLS ISO 8859-1 (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1
-  tristate 'NLS ISO 8859-2 (Latin 2; Slavic/Central European)' CONFIG_NLS_ISO8859_2
-  tristate 'NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish)' CONFIG_NLS_ISO8859_3
-  tristate 'NLS ISO 8859-4 (Latin 4; Estonian, Latvian, Lithuanian)' CONFIG_NLS_ISO8859_4
-  tristate 'NLS ISO 8859-5 (Cyrillic)'             CONFIG_NLS_ISO8859_5
-  tristate 'NLS ISO 8859-6 (Arabic)'               CONFIG_NLS_ISO8859_6
-  tristate 'NLS ISO 8859-7 (Modern Greek)'         CONFIG_NLS_ISO8859_7
-  tristate 'NLS ISO 8859-8 (Hebrew)'               CONFIG_NLS_ISO8859_8
-  tristate 'NLS ISO 8859-9 (Latin 5; Turkey)'      CONFIG_NLS_ISO8859_9
-  tristate 'NLS KOI8-R (Russian)'                  CONFIG_NLS_KOI8_R
+  tristate 'NLS ISO 8859-1  (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1
+  tristate 'NLS ISO 8859-2  (Latin 2; Slavic/Central European)' CONFIG_NLS_ISO8859_2
+  tristate 'NLS ISO 8859-3  (Latin 3; Esperanto, Galician, Maltese, Turkish)' CONFIG_NLS_ISO8859_3
+  tristate 'NLS ISO 8859-4  (Latin 4; Estonian, Latvian, Lithuanian)' CONFIG_NLS_ISO8859_4
+  tristate 'NLS ISO 8859-5  (Cyrillic)'             CONFIG_NLS_ISO8859_5
+  tristate 'NLS ISO 8859-6  (Arabic)'               CONFIG_NLS_ISO8859_6
+  tristate 'NLS ISO 8859-7  (Modern Greek)'         CONFIG_NLS_ISO8859_7
+  tristate 'NLS ISO 8859-8  (Hebrew)'               CONFIG_NLS_ISO8859_8
+  tristate 'NLS ISO 8859-9  (Latin 5; Turkey)'      CONFIG_NLS_ISO8859_9
+  tristate 'NLS ISO 8859-15 (Latin 9; Western European with Euro)' CONFIG_NLS_ISO8859_15
+  tristate 'NLS KOI8-R (Russian)'                   CONFIG_NLS_KOI8_R
   endmenu
 fi
index 4f51a5f9d29245620f27b0e40116aae8dff5bd88..879fef8ff6f000d3eb67b86cbc3dd08405186dc4 100644 (file)
@@ -286,6 +286,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_NLS_ISO8859_15),y)
+NLS += nls_iso8859-15.o
+else
+  ifeq ($(CONFIG_NLS_ISO8859_15),m)
+  M_OBJS += nls_iso8859-15.o
+  endif
+endif
+
 ifeq ($(CONFIG_NLS_KOI8_R),y)
 NLS += nls_koi8-r.o
 else
index 9654c8ec25770d18e0ae5031b5854b1f3e8cc6e9..b6483a1d67ed04ea08c043e8d50fa5f904129b49 100644 (file)
@@ -429,6 +429,9 @@ int init_nls(void)
 #ifdef CONFIG_NLS_ISO8859_9
        init_nls_iso8859_9();
 #endif
+#ifdef CONFIG_NLS_ISO8859_15
+       init_nls_iso8859_15();
+#endif
 #ifdef CONFIG_NLS_CODEPAGE_437
        init_nls_cp437();
 #endif
diff --git a/fs/nls/nls_iso8859-15.c b/fs/nls/nls_iso8859-15.c
new file mode 100644 (file)
index 0000000..33478bf
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * linux/fs/nls_iso8859-15.c
+ *
+ * Charset iso8859-15 translation tables.
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+       /* 0x00*/
+       {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+       {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+       {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+       {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+       /* 0x10*/
+       {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+       {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+       {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+       {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+       /* 0x20*/
+       {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+       {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+       {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+       {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+       /* 0x30*/
+       {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+       {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+       {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+       {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+       /* 0x40*/
+       {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+       {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+       {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+       {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+       /* 0x50*/
+       {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+       {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+       {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+       {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+       /* 0x60*/
+       {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+       {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+       {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+       {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+       /* 0x70*/
+       {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+       {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+       {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+       {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+       /* 0x80*/
+       {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+       {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+       {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+       {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+       /* 0x90*/
+       {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+       {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+       {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+       {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+       /* 0xa0*/
+       {0xa0, 0x00}, {0xa1, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+       {0xac, 0x20}, {0xa5, 0x00}, {0x60, 0x01}, {0xa7, 0x00},
+       {0x61, 0x01}, {0xa9, 0x00}, {0xaa, 0x00}, {0xab, 0x00},
+       {0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0xaf, 0x00},
+       /* 0xb0*/
+       {0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+       {0x7d, 0x01}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+       {0x7e, 0x01}, {0xb9, 0x00}, {0xba, 0x00}, {0xbb, 0x00},
+       {0x52, 0x01}, {0x53, 0x01}, {0x78, 0x01}, {0xbf, 0x00},
+       /* 0xc0*/
+       {0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+       {0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00},
+       {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+       {0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+       /* 0xd0*/
+       {0xd0, 0x00}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+       {0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+       {0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+       {0xdc, 0x00}, {0xdd, 0x00}, {0xde, 0x00}, {0xdf, 0x00},
+       /* 0xe0*/
+       {0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+       {0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00},
+       {0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+       {0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+       /* 0xf0*/
+       {0xf0, 0x00}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+       {0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+       {0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+       {0xfc, 0x00}, {0xfd, 0x00}, {0xfe, 0x00}, {0xff, 0x00},
+};
+
+static unsigned char page00[256] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+       0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+       0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+       0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+       0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+       0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+       0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+       0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+       0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+       0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */
+       0x00, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+       0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+       0x00, 0xb9, 0xba, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0xb8-0xbf */
+       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+       0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+       0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+       0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+       0x00, 0x00, 0xbc, 0xbd, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+       0xa6, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+       0xbe, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb8, 0x00, /* 0x78-0x7f */
+
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+       0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+       page00, page01, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+
+       page20, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+       NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
+};
+
+static void inc_use_count(void)
+{
+       MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+       "iso8859-15",
+       page_uni2charset,
+       charset2uni,
+       inc_use_count,
+       dec_use_count,
+       NULL
+};
+
+int init_nls_iso8859_15(void)
+{
+       return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+       return init_nls_iso8859_15();
+}
+
+
+void cleanup_module(void)
+{
+       unregister_nls(&table);
+       return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
index f96cf96f22cfc43aa239715842bd977d1da49601..8eef1f77adb03526156b844c17a3639f599312af 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
+#include <linux/swapctl.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/signal.h>
@@ -371,6 +372,28 @@ static int get_meminfo(char * buffer)
                i.freeswap >> 10);
 }
 
+static int get_swapstats(char * buffer)
+{
+       unsigned long *w = swapstats.kswap_wakeups;
+       
+       return sprintf(buffer,
+                      "ProcFreeTry:    %8lu\n"
+                      "ProcFreeSucc:   %8lu\n"
+                      "ProcShrinkTry:  %8lu\n"
+                      "ProcShrinkSucc: %8lu\n"
+                      "KswapFreeTry:   %8lu\n"
+                      "KswapFreeSucc:  %8lu\n"
+                      "KswapWakeups:   %8lu %lu %lu %lu\n",
+                      swapstats.gfp_freepage_attempts,
+                      swapstats.gfp_freepage_successes,
+                      swapstats.gfp_shrink_attempts,
+                      swapstats.gfp_shrink_successes,
+                      swapstats.kswap_freepage_attempts,
+                      swapstats.kswap_freepage_successes,
+                      w[0], w[1], w[2], w[3]
+                      );
+}
+
 static int get_version(char * buffer)
 {
        extern char *linux_banner;
@@ -1257,6 +1280,9 @@ static long get_root_array(char * page, int type, char **start,
                case PROC_MEMINFO:
                        return get_meminfo(page);
 
+               case PROC_SWAPSTATS:
+                       return get_swapstats(page);
+
 #ifdef CONFIG_PCI_OLD_PROC
                case PROC_PCI:
                        return get_pci_list(page);
@@ -1342,7 +1368,7 @@ static long get_root_array(char * page, int type, char **start,
 static int process_unauthorized(int type, int pid)
 {
        struct task_struct *p;
-       uid_t euid;     /* Save the euid keep the lock short */
+       uid_t euid=0;   /* Save the euid keep the lock short */
                
        read_lock(&tasklist_lock);
        
index 5fec42bb57f3426ef64cedcc96bbaa526443e719..1d6e4b737f6300d1e1fca7dfbecc46454c2b96c7 100644 (file)
@@ -493,6 +493,11 @@ static struct proc_dir_entry proc_root_meminfo = {
        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_array_inode_operations
 };
+static struct proc_dir_entry proc_root_swapstats = {
+       PROC_SWAPSTATS, 9, "swapstats",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_array_inode_operations
+};
 static struct proc_dir_entry proc_root_kmsg = {
        PROC_KMSG, 4, "kmsg",
        S_IFREG | S_IRUSR, 1, 0, 0,
@@ -648,6 +653,7 @@ __initfunc(void proc_root_init(void))
        proc_register(&proc_root, &proc_root_loadavg);
        proc_register(&proc_root, &proc_root_uptime);
        proc_register(&proc_root, &proc_root_meminfo);
+       proc_register(&proc_root, &proc_root_swapstats);
        proc_register(&proc_root, &proc_root_kmsg);
        proc_register(&proc_root, &proc_root_version);
        proc_register(&proc_root, &proc_root_cpuinfo);
index 5479bf8e1bb91c0a11cbe025c853904330b8140f..267ecb1107d6969048ea6ae6b76928e7a56717d8 100644 (file)
@@ -219,17 +219,12 @@ int qnx4_unlink(struct inode *dir, struct dentry *dentry)
        if (bh == NULL) {
                return -ENOENT;
        }
-       if ((inode = iget(dir->i_sb, ino)) == NULL) {
-               QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
-               retval = -EACCES;
+       inode = dentry->d_inode;
+       if (inode->i_ino != ino) {
+               retval = -EIO;
                goto end_unlink;
        }
        retval = -EPERM;
-       if ((dir->i_mode & S_ISVTX) &&
-           current->fsuid != inode->i_uid &&
-           current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) {
-               goto end_unlink;
-       }
        if (!inode->i_nlink) {
                QNX4DEBUG(("Deleting nonexistent file (%s:%lu), %d\n",
                           kdevname(inode->i_dev),
index 293af753415ba5c30b3a3c3307afa411f1444027..77c0a20bd3a2c2c180e7eecb7cebe2b2ccdfbc18 100644 (file)
@@ -18,3 +18,23 @@ Tue Jan 27 1998   Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
 Wed Feb  4 1998   Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
        *    namei.c: removed static subdir(); is_subdir() from dcache.c
                      is used instead. Cosmetic changes.
+
+Thu Dec  3 1998   Al Viro (viro@math.psu.edu)
+       *    namei.c (sysv_rmdir):
+                     Bugectomy: old check for victim being busy
+                     (inode->i_count) wasn't replaced (with checking
+                     dentry->d_count) and escaped Linus in the last round
+                     of changes. Shot and buried.
+
+Wed Dec  9 1998   AV
+       *    namei.c (do_sysv_rename):
+                      Fixed incorrect check for other owners + race.
+                      Removed checks that went to VFS.
+       *    namei.c (sysv_unlink):
+                      Removed checks that went to VFS.
+
+Thu Dec 10 1998   AV
+       *    namei.c (do_mknod):
+                       Removed dead code - mknod is never asked to
+                       create a symlink or directory. Incidentially,
+                       it wouldn't do it right if it would be called.
index 0fcc9292064c607bb505e161113816441ffe40ea..c7277f1a1bfc519c6a32ee72c17afbc617f24948 100644 (file)
@@ -254,13 +254,6 @@ int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
        inode->i_op = NULL;
        if (S_ISREG(inode->i_mode))
                inode->i_op = &sysv_file_inode_operations;
-       else if (S_ISDIR(inode->i_mode)) {
-               inode->i_op = &sysv_dir_inode_operations;
-               if (dir->i_mode & S_ISGID)
-                       inode->i_mode |= S_ISGID;
-       }
-       else if (S_ISLNK(inode->i_mode))
-               inode->i_op = &sysv_symlink_inode_operations;
        else if (S_ISCHR(inode->i_mode))
                inode->i_op = &chrdev_inode_operations;
        else if (S_ISBLK(inode->i_mode))
@@ -469,10 +462,6 @@ repeat:
                schedule();
                goto repeat;
        }
-       if ((dir->i_mode & S_ISVTX) &&
-           current->fsuid != inode->i_uid &&
-           current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
-               goto end_unlink;
        if (de->inode != inode->i_ino) {
                retval = -ENOENT;
                goto end_unlink;
@@ -628,10 +617,6 @@ start_up:
                goto end_rename;
        old_inode = old_dentry->d_inode;        /* don't cross mnt-points */
        retval = -EPERM;
-       if ((old_dir->i_mode & S_ISVTX) && 
-           current->fsuid != old_inode->i_uid &&
-           current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER))
-               goto end_rename;
        new_inode = new_dentry->d_inode;
        new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name,
                                new_dentry->d_name.len, &new_de);
@@ -645,32 +630,20 @@ start_up:
                retval = 0;
                goto end_rename;
        }
-       if (new_inode && S_ISDIR(new_inode->i_mode)) {
-               retval = -EISDIR;
-               if (!S_ISDIR(old_inode->i_mode))
-                       goto end_rename;
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
-               retval = -ENOTEMPTY;
-               if (!empty_dir(new_inode))
-                       goto end_rename;
-               retval = -EBUSY;
-               if (new_inode->i_count > 1)
-                       goto end_rename;
-       }
-       retval = -EPERM;
-       if (new_inode && (new_dir->i_mode & S_ISVTX) && 
-           current->fsuid != new_inode->i_uid &&
-           current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER))
-               goto end_rename;
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -ENOTDIR;
-               if (new_inode && !S_ISDIR(new_inode->i_mode))
-                       goto end_rename;
                retval = -EINVAL;
                if (is_subdir(new_dentry, old_dentry))
                        goto end_rename;
+               if (new_inode) {
+                       if (new_dentry->d_count > 1)
+                               shrink_dcache_parent(new_dentry);
+                       retval = -EBUSY;
+                       if (new_dentry->d_count > 1)
+                               goto end_rename;
+                       retval = -ENOTEMPTY;
+                       if (!empty_dir(new_inode))
+                               goto end_rename;
+               }
                retval = -EIO;
                dir_bh = sysv_file_bread(old_inode, 0, 0);
                if (!dir_bh)
index 76d0ef8e019f692bb80d525a6c694d92412c73c5..c20f2293ec10175419cf44a2c6faa871c81acd33 100644 (file)
@@ -475,13 +475,6 @@ int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
        inode->i_op = NULL;
        if (S_ISREG(inode->i_mode))
                inode->i_op = &ufs_file_inode_operations;
-       else if (S_ISDIR(inode->i_mode)) {
-               inode->i_op = &ufs_dir_inode_operations;
-               if (dir->i_mode & S_ISGID)
-                       inode->i_mode |= S_ISGID;
-       }
-       else if (S_ISLNK(inode->i_mode))
-               inode->i_op = &ufs_symlink_inode_operations;
        else if (S_ISCHR(inode->i_mode))
                inode->i_op = &chrdev_inode_operations;
        else if (S_ISBLK(inode->i_mode))
@@ -751,14 +744,6 @@ int ufs_unlink(struct inode * dir, struct dentry *dentry)
        if (inode->i_sb->dq_op)
                inode->i_sb->dq_op->initialize (inode, -1);
 
-       retval = -EPERM;
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               goto end_unlink;
-       if ((dir->i_mode & S_ISVTX) &&
-           current->fsuid != inode->i_uid &&
-           current->fsuid != dir->i_uid && !fsuser())
-               goto end_unlink;
-
        retval = -EIO;
        if (SWAB32(de->d_ino) != inode->i_ino)
                goto end_unlink;
@@ -958,20 +943,13 @@ static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
        old_bh = ufs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
        UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(old_de->d_ino),
                SWAB16(old_de->d_reclen), ufs_get_de_namlen(old_de), old_de->d_name))
-           
+
+       /* Arrrgh. See comments in ext2 */
        retval = -ENOENT;
-       if (!old_bh)
+       if (!old_bh || SWAB32(old_de->d_ino) != old_inode->i_ino)
                goto end_rename;
        old_inode = old_dentry->d_inode;
 
-       retval = -EPERM;
-       if ((old_dir->i_mode & S_ISVTX) && 
-           current->fsuid != old_inode->i_uid &&
-           current->fsuid != old_dir->i_uid && !fsuser())
-               goto end_rename;
-       if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode))
-               goto end_rename;
-
        new_inode = new_dentry->d_inode;
        UFSD(("name %s, len %u\n", new_dentry->d_name.name, new_dentry->d_name.len)) 
        new_bh = ufs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de);
@@ -987,36 +965,21 @@ static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
        retval = 0;
        if (new_inode == old_inode)
                goto end_rename;
-       if (new_inode && S_ISDIR(new_inode->i_mode)) {
-               retval = -EISDIR;
-               if (!S_ISDIR(old_inode->i_mode))
-                       goto end_rename;
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
-               retval = -ENOTEMPTY;
-               if (!ufs_empty_dir (new_inode))
-                       goto end_rename;
-               retval = -EBUSY;
-               if (new_dentry->d_count > 1)
-                       goto end_rename;
-       }
-       retval = -EPERM;
-       if (new_inode) {
-               if ((new_dir->i_mode & S_ISVTX) &&
-                   current->fsuid != new_inode->i_uid &&
-                   current->fsuid != new_dir->i_uid && !fsuser())
-                       goto end_rename;
-               if (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode))
-                       goto end_rename;
-       }
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -ENOTDIR;
-               if (new_inode && !S_ISDIR(new_inode->i_mode))
-                       goto end_rename;
                retval = -EINVAL;
                if (is_subdir(new_dentry, old_dentry))
                        goto end_rename;
+               if (new_inode) {
+                       if (new_dentry->d_count > 1)
+                               shrink_dcache_parent(new_dentry);
+                       retval = -EBUSY;
+                       if (new_dentry->d_count > 1)
+                               goto end_rename;
+                       retval = -ENOTEMPTY;
+                       if (!ufs_empty_dir (new_inode))
+                               goto end_rename;
+               }
+
                dir_bh = ufs_bread (old_inode, 0, 0, &retval);
                if (!dir_bh)
                        goto end_rename;
index 41740fd425888512563d1155495386dafde7fe66..6516fb57dd403418475a94e313cb82475a027eb4 100644 (file)
@@ -108,7 +108,7 @@ void check_inode (struct inode *inode)
                } else if (inode->i_op == &umsdos_symlink_inode_operations) {
                        printk (" (i_op is umsdos_symlink_inode_operations)\n");
                } else {
-                       printk ((" (i_op is UNKNOWN: %p)\n", inode->i_op));
+                       printk (" (i_op is UNKNOWN: %p)\n", inode->i_op);
                }
        } else {
                printk (KERN_DEBUG "*   inode is NULL\n");
index 18dc5c2941b706667591d9f3004ee75cac3d1ac7..c77443e84b59eb3e31cb89f4a49773ed3639de78 100644 (file)
@@ -1808,6 +1808,10 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
 
        if (res == 0) {
                drop_replace_inodes(old_dentry, new_inode);
+               list_del(&old_dentry->d_alias);
+               iput(old_dentry->d_inode);
+               d_instantiate(old_dentry, new_inode);
+
                d_move(old_dentry, new_dentry);
                put_new_inode = 0;
        }
index 933470e1c82cb53b0bfb26917fe58bef26a01b4a..e3b69926719df63f0737e6af8f25a184b0d8390b 100644 (file)
@@ -237,7 +237,7 @@ extern __inline int hard_smp_processor_id(void)
  *     processes are run.
  */
  
-#define PROC_CHANGE_PENALTY    15              /* Schedule penalty */
+#define PROC_CHANGE_PENALTY    10              /* Schedule penalty */
 
 #define SMP_FROM_INT           1
 #define SMP_FROM_SYSCALL       2
index fc607fdbadacec4619fd1d9ffc9ba6f3416e4bba..e549b02e7c94b6b08f4843b49ce283a7dbc41aba 100644 (file)
@@ -30,7 +30,7 @@ int coda_cache_check(struct inode *inode, int mask);
 
 /* for downcalls and attributes and lookups */
 void coda_flag_inode(struct inode *inode, int flag);
-void coda_flag_alias_children(struct inode *inode, int flag);
+void coda_flag_inode_children(struct inode *inode, int flag);
 
 
 /*
index 83980b26ece591cc47344b7be14c4a05a960a5eb..baa136b97b014b28991715b9d65f40a811230d7e 100644 (file)
@@ -33,12 +33,12 @@ struct coda_inode_info {
 };
 
 /* flags */
-#define C_VATTR       0x1         /* Validity of vattr in the cnode */
-#define C_SYMLINK     0x2         /* Validity of symlink pointer in the cnode */
-#define C_DYING       0x4        /* Set for outstanding cnodes from venus (which died) */
-#define C_PURGE      0x8
+#define C_VATTR       0x1   /* Validity of vattr in inode */
+#define C_PURGE       0x8
 #define C_ZAPDIR      0x10
+#define C_DYING       0x4   /* from venus (which died) */
 #define C_INITED      0x20
+#define C_FLUSH       0x2   /* used after a flush */
 
 int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *);
 int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
index 98407f73bd69b17e5b29ca45de03cdb8fe87f1eb..50af4c367eaefaec2b2aa4668fe4e816727f96ab 100644 (file)
@@ -71,9 +71,13 @@ int coda_inode_grab(dev_t dev, ino_t ino, struct inode **ind);
 #define NB_SFS_SIZ 0x895440
 
 /* cache.c */
-void coda_purge_children(struct inode *);
+void coda_purge_children(struct inode *, int);
 void coda_purge_dentries(struct inode *);
 
+/* sysctl.h */
+void coda_sysctl_init(void);
+void coda_sysctl_clean(void);
+
 
 /* debugging masks */
 #define D_SUPER     1   /* print results returned by Venus */ 
index 7b827e8c3e171c26a60745de6e95ed647ce574a0..2aca579b2aa3c4c6f9bd710c867d0e76d33d184e 100644 (file)
@@ -4,16 +4,8 @@
 #define CODA_PSDEV_MAJOR 67
 #define MAX_CODADEVS  5           /* how many do we allow */
 
-extern struct vcomm psdev_vcomm[];
-
-/* queue stuff; the rest is static to psdev.c */
-struct queue {
-    struct queue *forw, *back;
-};
-void coda_q_insert(struct queue *el, struct queue *q);
-void coda_q_remove(struct queue *q);
-
-
+extern struct venus_comm coda_upc_comm;
+extern struct coda_sb_info coda_super_info;
 #define CODA_SUPER_MAGIC       0x73757245
 
 struct coda_sb_info
@@ -21,31 +13,23 @@ struct coda_sb_info
        struct inode *      sbi_psdev;     /* /dev/cfs? Venus/kernel device */
        struct inode *      sbi_ctlcp;     /* control magic file */
        int                 sbi_refct;
-       struct vcomm *      sbi_vcomm;
+       struct venus_comm *      sbi_vcomm;
        struct inode *      sbi_root;
+       struct super_block *sbi_sb;
        struct list_head    sbi_cchead;
        struct list_head    sbi_volroothead;
 };
 
 /* communication pending/processing queues queues */
-struct vcomm {
+struct venus_comm {
        u_long              vc_seq;
        struct wait_queue  *vc_waitq; /* Venus wait queue */
-       struct queue        vc_pending;
-       struct queue        vc_processing;
-       struct super_block *vc_sb;
+       struct list_head    vc_pending;
+       struct list_head    vc_processing;
        int                 vc_inuse;
+       pid_t               vc_pid;   /* Venus pid */
 };
 
-static inline int vcomm_open(struct vcomm *vcp)
-{
-        return ((vcp)->vc_pending.forw != NULL);
-}
-
-static inline void mark_vcomm_closed(struct vcomm *vcp)
-{
-        (vcp)->vc_pending.forw = NULL;
-}
 
 static inline struct coda_sb_info *coda_sbp(struct super_block *sb)
 {
@@ -100,18 +84,22 @@ int venus_fsync(struct super_block *sb, struct ViceFid *fid);
 /* messages between coda filesystem in kernel and Venus */
 extern int coda_hard;
 extern unsigned long coda_timeout;
-struct vmsg {
-       struct queue        vm_chain;
-       caddr_t         vm_data;
-       u_short         vm_flags;
-       u_short             vm_inSize;  /* Size is at most 5000 bytes */
-       u_short         vm_outSize;
-       u_short         vm_opcode;  /* copied from data to save lookup */
-       int                     vm_unique;
-       struct wait_queue  *vm_sleep;   /* process' wait queue */
-       unsigned long       vm_posttime;
+struct upc_req {
+       struct list_head    uc_chain;
+       caddr_t             uc_data;
+       u_short             uc_flags;
+       u_short             uc_inSize;  /* Size is at most 5000 bytes */
+       u_short             uc_outSize;
+       u_short             uc_opcode;  /* copied from data to save lookup */
+       int                 uc_unique;
+       struct wait_queue  *uc_sleep;   /* process' wait queue */
+       unsigned long       uc_posttime;
 };
 
+#define REQ_ASYNC  0x1
+#define REQ_READ   0x2
+#define REQ_WRITE  0x4
+
 
 /*
  * Statistics
index 686044e247945c17880fe911bc86f1a980792a5b..b8018949052e18b12077fca82d480f49d62790aa 100644 (file)
@@ -559,6 +559,13 @@ struct super_block {
        } u;
 };
 
+/*
+ * VFS helper functions..
+ */
+extern int vfs_rmdir(struct inode *, struct dentry *);
+extern int vfs_unlink(struct inode *, struct dentry *);
+extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+
 /*
  * This is the "filldir" function type, used by readdir() to let
  * the kernel specify what kind of dirent layout it wants to have.
@@ -776,7 +783,6 @@ extern int get_write_access(struct inode *inode);
 extern void put_write_access(struct inode *inode);
 extern struct dentry * open_namei(const char * pathname, int flag, int mode);
 extern struct dentry * do_mknod(const char * filename, int mode, dev_t dev);
-extern int VFS_rmdir(struct inode *dir, struct dentry *dentry);
 extern int do_pipe(int *);
 
 /* fs/dcache.c -- generic fs support functions */
index fe760799f6a58855066bae693d53ed3c22a3bcb9..26b862f1333f0523572d4a7d61c2ae7aaba54abf 100644 (file)
@@ -11,6 +11,7 @@
 extern unsigned long max_mapnr;
 extern unsigned long num_physpages;
 extern void * high_memory;
+extern int page_cluster;
 
 #include <asm/page.h>
 #include <asm/atomic.h>
index aa27407730e5709006b1bb9100e15da46e3144b7..c0bd15b486c8a77037602c8f8555a62b873bf21a 100644 (file)
@@ -52,7 +52,8 @@ enum root_directory_inos {
        PROC_STRAM,
        PROC_SOUND,
        PROC_MTRR, /* whether enabled or not */
-       PROC_FS
+       PROC_FS,
+       PROC_SWAPSTATS
 };
 
 enum pid_directory_inos {
@@ -170,6 +171,7 @@ enum scsi_directory_inos {
        PROC_SCSI_PAS16,
        PROC_SCSI_QLOGICFAS,
        PROC_SCSI_QLOGICISP,
+       PROC_SCSI_QLOGICFC,
        PROC_SCSI_SEAGATE,
        PROC_SCSI_T128,
        PROC_SCSI_NCR53C7xx,
@@ -183,7 +185,9 @@ enum scsi_directory_inos {
        PROC_SCSI_AM53C974,
        PROC_SCSI_SSC,
        PROC_SCSI_NCR53C406A,
+       PROC_SCSI_MEGARAID,
        PROC_SCSI_PPA,
+       PROC_SCSI_ATP870U,
        PROC_SCSI_ESP,
        PROC_SCSI_QLOGICPTI,
        PROC_SCSI_AMIGA7XX,
@@ -198,6 +202,7 @@ enum scsi_directory_inos {
        PROC_SCSI_MESH,
        PROC_SCSI_53C94,
        PROC_SCSI_PLUTO,
+       PROC_SCSI_INI9100U,
        PROC_SCSI_SCSI_DEBUG,   
        PROC_SCSI_NOT_PRESENT,
        PROC_SCSI_FILE,                        /* I'm assuming here that we */
index c8a4405388b5fe1e6b64c0c7cd145e6f58e5c861..7ad72e102697da8effddda3f84ab342eea2390bf 100644 (file)
@@ -82,8 +82,8 @@ enum HWEVENT_opts {
 
 /* channel grouping */
 
-#define RXGROUP                0x100   /* if set, only tx when all channels clear */
-#define TXGROUP                0x200   /* if set, don't transmit simultaneously */
+#define RXGROUP                0100    /* if set, only tx when all channels clear */
+#define TXGROUP                0200    /* if set, don't transmit simultaneously */
 
 /* Tx/Rx clock sources */
 
@@ -237,6 +237,7 @@ struct scc_channel {
 
        unsigned char wreg[16];         /* Copy of last written value in WRx */
        unsigned char status;           /* Copy of R0 at last external interrupt */
+       unsigned char dcd;              /* DCD status */
 
         struct scc_kiss kiss;          /* control structure for KISS params */
         struct scc_stat stat;          /* statistical information */
index 819e346a47e4ccc7dd4bf3cf39c1ac01685d5e68..a6d13e8d9bcc61946357ad09bae55735959fb4c2 100644 (file)
@@ -14,6 +14,9 @@ struct shmid_ds {
        __kernel_ipc_pid_t      shm_cpid;       /* pid of creator */
        __kernel_ipc_pid_t      shm_lpid;       /* pid of last operator */
        unsigned short          shm_nattch;     /* no. of current attaches */
+       unsigned short          shm_unused;     /* compatibility */
+       void                    *shm_unused2;   /* ditto - used by DIPC */
+       void                    *shm_unused3;   /* unused */
 };
 
 struct shmid_kernel
index d4fcf03b8ce8681482c366c009fc72b884c3d457..9257ca698e6863325e3ea55680b0a2975a96f21f 100644 (file)
@@ -61,6 +61,15 @@ extern struct inode swapper_inode;
 extern unsigned long page_cache_size;
 extern int buffermem;
 
+struct swap_stats 
+{
+       long    proc_freepage_attempts;
+       long    proc_freepage_successes;
+       long    kswap_freepage_attempts;
+       long    kswap_freepage_successes;
+};
+extern struct swap_stats swap_stats;
+
 /* Incomplete types for prototype declarations: */
 struct task_struct;
 struct vm_area_struct;
@@ -69,6 +78,9 @@ struct sysinfo;
 /* linux/ipc/shm.c */
 extern int shm_swap (int, int);
 
+/* linux/mm/swap.c */
+extern void swap_setup (void);
+
 /* linux/mm/vmscan.c */
 extern int try_to_free_pages(unsigned int gfp_mask, int count);
 
@@ -87,6 +99,7 @@ extern void show_swap_cache_info(void);
 extern int add_to_swap_cache(struct page *, unsigned long);
 extern int swap_duplicate(unsigned long);
 extern int swap_check_entry(unsigned long);
+struct page * lookup_swap_cache(unsigned long);
 extern struct page * read_swap_cache_async(unsigned long, int);
 #define read_swap_cache(entry) read_swap_cache_async(entry, 1);
 extern int FASTCALL(swap_count(unsigned long));
index 54fb59381fdee09026b742a2dfb33d072d73097c..1b3bcbaa6eda4723286727870af9377869d2b57e 100644 (file)
@@ -22,11 +22,19 @@ extern swap_control_t swap_control;
 
 typedef struct swapstat_v1
 {
-       unsigned int    wakeups;
-       unsigned int    pages_reclaimed;
-       unsigned int    pages_shm;
-       unsigned int    pages_mmap;
-       unsigned int    pages_swap;
+       unsigned long   wakeups;
+       unsigned long   pages_reclaimed;
+       unsigned long   pages_shm;
+       unsigned long   pages_mmap;
+       unsigned long   pages_swap;
+
+       unsigned long   gfp_freepage_attempts;
+       unsigned long   gfp_freepage_successes;
+       unsigned long   gfp_shrink_attempts;
+       unsigned long   gfp_shrink_successes;
+       unsigned long   kswap_freepage_attempts;
+       unsigned long   kswap_freepage_successes;
+       unsigned long   kswap_wakeups[4];
 } swapstat_v1;
 typedef swapstat_v1 swapstat_t;
 extern swapstat_t swapstats;
index 20e3b9abfbd12f0705ea77c10cdc8e672c17cb6c..3141875a1ad0998019492fb25fd8b51cf1e7012e 100644 (file)
@@ -56,7 +56,7 @@ enum
        CTL_PROC=4,             /* Process info */
        CTL_FS=5,               /* Filesystems */
        CTL_DEBUG=6,            /* Debugging */
-       CTL_DEV=7,              /* Devices */
+       CTL_DEV=7               /* Devices */
 };
 
 
@@ -89,6 +89,14 @@ enum
        KERN_SG_BIG_BUFF=29,
        KERN_ACCT=30,           /* BSD process accounting parameters */
        KERN_PPC_L2CR=31,       /* l2cr register on PPC */
+
+       KERN_RTSIGNR=32,        /* Number of rt sigs queued */
+       KERN_RTSIGMAX=33,       /* Max queuable */
+       
+       KERN_SHMMAX=34,         /* int: Maximum shared memory segment */
+       KERN_MSGMAX=35,         /* int: Maximum size of a messege */
+       KERN_MSGMNB=36,         /* int: Maximum message queue size */
+       KERN_MSGPOOL=37         /* int: Maximum system message pool size */
 };
 
 
@@ -103,7 +111,8 @@ enum
        VM_BUFFERMEM=6,         /* struct: Set buffer memory thresholds */
        VM_PAGECACHE=7,         /* struct: Set cache memory thresholds */
        VM_PAGERDAEMON=8,       /* struct: Control kswapd behaviour */
-       VM_PGT_CACHE=9          /* struct: Set page table cache parameters */
+       VM_PGT_CACHE=9,         /* struct: Set page table cache parameters */
+       VM_PAGE_CLUSTER=10      /* int: set log2 number of pages to swap together */
 };
 
 
@@ -140,7 +149,7 @@ enum
        NET_CORE_FASTROUTE=7,
        NET_CORE_MSG_COST=8,
        NET_CORE_MSG_BURST=9,
-       NET_CORE_OPTMEM_MAX=10,
+       NET_CORE_OPTMEM_MAX=10
 };
 
 /* /proc/sys/net/ethernet */
@@ -152,7 +161,7 @@ enum
 enum
 {
        NET_UNIX_DESTROY_DELAY=1,
-       NET_UNIX_DELETE_DELAY=2,
+       NET_UNIX_DELETE_DELAY=2
 };
 
 /* /proc/sys/net/ipv4 */
@@ -198,6 +207,7 @@ enum
        NET_IPV4_ICMP_TIMEEXCEED_RATE=61,
        NET_IPV4_ICMP_PARAMPROB_RATE=62,
        NET_IPV4_ICMP_ECHOREPLY_RATE=63,
+       NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64
 };
 
 enum {
@@ -214,13 +224,13 @@ enum {
        NET_IPV4_ROUTE_REDIRECT_SILENCE=11,
        NET_IPV4_ROUTE_ERROR_COST=12,
        NET_IPV4_ROUTE_ERROR_BURST=13,
-       NET_IPV4_ROUTE_GC_ELASTICITY=14,
+       NET_IPV4_ROUTE_GC_ELASTICITY=14
 };
 
 enum
 {
        NET_PROTO_CONF_ALL=-2,
-       NET_PROTO_CONF_DEFAULT=-3,
+       NET_PROTO_CONF_DEFAULT=-3
 
        /* And device ifindices ... */
 };
@@ -237,14 +247,14 @@ enum
        NET_IPV4_CONF_RP_FILTER=8,
        NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9,
        NET_IPV4_CONF_BOOTP_RELAY=10,
-       NET_IPV4_CONF_LOG_MARTIANS=11,
+       NET_IPV4_CONF_LOG_MARTIANS=11
 };
 
 /* /proc/sys/net/ipv6 */
 enum {
        NET_IPV6_CONF=16,
        NET_IPV6_NEIGH=17,
-       NET_IPV6_ROUTE=18,
+       NET_IPV6_ROUTE=18
 };
 
 enum {
@@ -254,7 +264,7 @@ enum {
        NET_IPV6_ROUTE_GC_MIN_INTERVAL=4,
        NET_IPV6_ROUTE_GC_TIMEOUT=5,
        NET_IPV6_ROUTE_GC_INTERVAL=6,
-       NET_IPV6_ROUTE_GC_ELASTICITY=7,
+       NET_IPV6_ROUTE_GC_ELASTICITY=7
 };
 
 enum {
@@ -267,7 +277,7 @@ enum {
        NET_IPV6_DAD_TRANSMITS=7,
        NET_IPV6_RTR_SOLICITS=8,
        NET_IPV6_RTR_SOLICIT_INTERVAL=9,
-       NET_IPV6_RTR_SOLICIT_DELAY=10,
+       NET_IPV6_RTR_SOLICIT_DELAY=10
 };
 
 /* /proc/sys/net/<protocol>/neigh/<dev> */
@@ -298,7 +308,7 @@ enum {
        NET_ATALK_AARP_EXPIRY_TIME=1,
        NET_ATALK_AARP_TICK_TIME=2,
        NET_ATALK_AARP_RETRANSMIT_LIMIT=3,
-       NET_ATALK_AARP_RESOLVE_TIME=4,
+       NET_ATALK_AARP_RESOLVE_TIME=4
 };
 
 
@@ -346,7 +356,7 @@ enum {
        NET_ROSE_LINK_FAIL_TIMEOUT=7,
        NET_ROSE_MAX_VCS=8,
        NET_ROSE_WINDOW_SIZE=9,
-       NET_ROSE_NO_ACTIVITY_TIMEOUT=10,
+       NET_ROSE_NO_ACTIVITY_TIMEOUT=10
 };
 
 /* /proc/sys/net/x25 */
@@ -366,12 +376,11 @@ enum
 
 /* /proc/sys/net/decnet */
 enum {
-       NET_DECNET_DEF_T3_BROADCAST=1,
-       NET_DECNET_DEF_T3_POINTTOPOINT=2,
-       NET_DECNET_DEF_T1=3,
-       NET_DECNET_DEF_BCT1=4,
-       NET_DECNET_CACHETIMEOUT=5,
-       NET_DECNET_DEBUG_LEVEL=6
+       NET_DECNET_NODE_TYPE=1,
+       NET_DECNET_NODE_ADDRESS=2,
+       NET_DECNET_NODE_NAME=3,
+       NET_DECNET_DEFAULT_DEVICE=4,
+       NET_DECNET_DEBUG_LEVEL=255
 };
 
 /* CTL_PROC names: */
@@ -388,7 +397,7 @@ enum
        FS_MAXFILE=7,   /* int:maximum number of filedescriptors that can be allocated */
        FS_DENTRY=8,
        FS_NRSUPER=9,   /* int:current number of allocated super_blocks */
-       FS_MAXSUPER=10, /* int:maximum number of super_blocks that can be allocated */
+       FS_MAXSUPER=10  /* int:maximum number of super_blocks that can be allocated */
 };
 
 /* CTL_DEBUG names: */
@@ -396,12 +405,12 @@ enum
 /* CTL_DEV names: */
 enum {
        DEV_CDROM=1,
-       DEV_HWMON=2,
+       DEV_HWMON=2
 };
 
 /* /proc/sys/dev/cdrom */
 enum {
-       DEV_CDROM_INFO=1,
+       DEV_CDROM_INFO=1
 };
 
 #ifdef __KERNEL__
index 4a82ad4e0491a4b93c6b12bcb8f6afe026009af7..91b758f49681ced96bc2daa1905ee2b5728bb445 100644 (file)
@@ -11,7 +11,7 @@
 #define NR_CPUS 1
 #endif
 
-#define NR_TASKS       512
+#define NR_TASKS       512     /* On x86 Max 4092, or 4090 w/APM configured. */
 
 #define MAX_TASKS_PER_USER (NR_TASKS/2)
 #define MIN_TASKS_LEFT_FOR_ROOT 4
index fd25e9f7f70c141bc93c44473b386711b4f35555..2c8d20a621dfd3d4d574bb26af347a44d207d75d 100644 (file)
@@ -281,7 +281,7 @@ extern void ax25_output(ax25_cb *, int, struct sk_buff *);
 extern void ax25_kick(ax25_cb *);
 extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
 extern void ax25_queue_xmit(struct sk_buff *);
-extern void ax25_check_iframes_acked(ax25_cb *, unsigned short);
+extern int  ax25_check_iframes_acked(ax25_cb *, unsigned short);
 
 /* ax25_route.c */
 extern void ax25_rt_device_down(struct device *);
index aaee2d2c74e64dd6f951d86ebe1b8c0d9626b8d1..9459d9fbc1a339e535cd1b12dd7b25962f124187 100644 (file)
@@ -90,6 +90,7 @@ extern void ecard_init(void);
 extern void smp_setup(char *str, int *ints);
 #ifdef __i386__
 extern void ioapic_pirq_setup(char *str, int *ints);
+extern void ioapic_setup(char *str, int *ints);
 #endif
 extern void no_scroll(char *str, int *ints);
 extern void kbd_reset_setup(char *str, int *ints);
@@ -541,6 +542,7 @@ static struct kernel_param cooked_params[] __initdata = {
        { "nosmp", smp_setup },
        { "maxcpus=", smp_setup },
 #ifdef __i386__
+       { "noapic", ioapic_setup },
        { "pirq=", ioapic_pirq_setup },
 #endif
 #endif
index e3866e1f04eb9bc27f72c4a9006787406a96c19e..9aa69359d9cfe9b47d08a91bd6cc2ef7b6e2b0a0 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -126,6 +126,8 @@ found:
        return (unsigned int) shp->u.shm_perm.seq * SHMMNI + id;
 }
 
+int shmmax = SHMMAX;
+
 asmlinkage int sys_shmget (key_t key, int size, int shmflg)
 {
        struct shmid_kernel *shp;
@@ -133,7 +135,7 @@ asmlinkage int sys_shmget (key_t key, int size, int shmflg)
 
        down(&current->mm->mmap_sem);
        lock_kernel();
-       if (size < 0 || size > SHMMAX) {
+       if (size < 0 || size > shmmax) {
                err = -EINVAL;
        } else if (key == IPC_PRIVATE) {
                err = newseg(key, shmflg, size);
@@ -228,7 +230,7 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
                if (!buf)
                        goto out;
                shminfo.shmmni = SHMMNI;
-               shminfo.shmmax = SHMMAX;
+               shminfo.shmmax = shmmax;
                shminfo.shmmin = SHMMIN;
                shminfo.shmall = SHMALL;
                shminfo.shmseg = SHMSEG;
index b249985cb56692b712ee0bcbee1ff0cd957f8e52..9e3dedb90ba705681408a132a2359526c2773b30 100644 (file)
@@ -172,7 +172,9 @@ EXPORT_SYMBOL(shrink_dcache_parent);
 EXPORT_SYMBOL(find_inode_number);
 EXPORT_SYMBOL(is_subdir);
 EXPORT_SYMBOL(get_unused_fd);
-EXPORT_SYMBOL(VFS_rmdir);
+EXPORT_SYMBOL(vfs_rmdir);
+EXPORT_SYMBOL(vfs_unlink);
+EXPORT_SYMBOL(vfs_rename);
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
index 892476023ef9ca49bebb4e48172399c854453b69..65f12e633f827718fe1411a49f4b1e2d7e1bc5f5 100644 (file)
@@ -28,8 +28,8 @@
 
 static kmem_cache_t *signal_queue_cachep;
 
-static int nr_queued_signals;
-static int max_queued_signals = 1024;
+int nr_queued_signals;
+int max_queued_signals = 1024;
 
 void __init signals_init(void)
 {
index 12455ee07ddb19e6d353140ef9352ce5215a606c..ad23a8d5fa815653d72375e9a1c5a0b676922388 100644 (file)
@@ -216,6 +216,8 @@ static ctl_table vm_table[] = {
         &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
        {VM_PGT_CACHE, "pagetable_cache", 
         &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
+       {VM_PAGE_CLUSTER, "page-cluster", 
+        &page_cluster, sizeof(int), 0600, NULL, &proc_dointvec},
        {0}
 };
 
index b48cde1052e4ae288d617c56994f1accd89bb309..9f94805c4b7cf0765eb88e7e09514754cc78a12e 100644 (file)
@@ -962,7 +962,7 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
        struct file * file = area->vm_file;
        struct dentry * dentry = file->f_dentry;
        struct inode * inode = dentry->d_inode;
-       unsigned long offset;
+       unsigned long offset, reada, i;
        struct page * page, **hash;
        unsigned long old_page, new_page;
 
@@ -1023,7 +1023,18 @@ success:
        return new_page;
 
 no_cached_page:
-       new_page = __get_free_page(GFP_USER);
+       /*
+        * Try to read in an entire cluster at once.
+        */
+       reada   = offset;
+       reada >>= PAGE_SHIFT + page_cluster;
+       reada <<= PAGE_SHIFT + page_cluster;
+
+       for (i = 1 << page_cluster; i > 0; --i, reada += PAGE_SIZE)
+               new_page = try_to_read_ahead(file, reada, new_page);
+
+       if (!new_page)
+               new_page = __get_free_page(GFP_USER);
        if (!new_page)
                goto no_page;
 
@@ -1047,11 +1058,6 @@ no_cached_page:
        if (inode->i_op->readpage(file, page) != 0)
                goto failure;
 
-       /*
-        * Do a very limited read-ahead if appropriate
-        */
-       if (PageLocked(page))
-               new_page = try_to_read_ahead(file, offset + PAGE_SIZE, 0);
        goto found_page;
 
 page_locked_wait:
@@ -1625,7 +1631,7 @@ unsigned long get_cached_page(struct inode * inode, unsigned long offset,
        if (!page) {
                if (!new)
                        goto out;
-               page_cache = get_free_page(GFP_KERNEL);
+               page_cache = get_free_page(GFP_USER);
                if (!page_cache)
                        goto out;
                page = mem_map + MAP_NR(page_cache);
index 7ceec01b917031ec0ce6995776b11eda45dbea45..a8f8a3fd5db6c5a957969e43bbbf21d7356738d1 100644 (file)
@@ -359,6 +359,38 @@ unsigned long __init free_area_init(unsigned long start_mem, unsigned long end_m
        return start_mem;
 }
 
+/* 
+ * Primitive swap readahead code. We simply read an aligned block of
+ * (1 << page_cluster) entries in the swap area. This method is chosen
+ * because it doesn't cost us any seek time.  We also make sure to queue
+ * the 'original' request together with the readahead ones...  
+ */
+void swapin_readahead(unsigned long entry)
+{
+       int i;
+       struct page *new_page;
+       unsigned long offset = SWP_OFFSET(entry);
+       struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
+       
+       offset = (offset >> page_cluster) << page_cluster;
+       
+       for (i = 1 << page_cluster; i > 0; i--) {
+             if (offset >= swapdev->max
+                             || nr_free_pages - atomic_read(&nr_async_pages) <
+                             (freepages.high + freepages.low)/2)
+                     return;
+             if (!swapdev->swap_map[offset] ||
+                 swapdev->swap_map[offset] == SWAP_MAP_BAD ||
+                 test_bit(offset, swapdev->swap_lockmap))
+                     continue;
+             new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0);
+             if (new_page != NULL)
+                     __free_page(new_page);
+             offset++;
+       }
+       return;
+}
+
 /*
  * The tests may look silly, but it essentially makes sure that
  * no other process did a swap-in on us just as we were waiting.
@@ -370,10 +402,12 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
        pte_t * page_table, unsigned long entry, int write_access)
 {
        unsigned long page;
-       struct page *page_map;
-       
-       page_map = read_swap_cache(entry);
+       struct page *page_map = lookup_swap_cache(entry);
 
+       if (!page_map) {
+               swapin_readahead(entry);
+               page_map = read_swap_cache(entry);
+       }
        if (pte_val(*page_table) != entry) {
                if (page_map)
                        free_page_and_swap_cache(page_address(page_map));
index 2dd24facc75164323f27736e9121e391706c97a7..f23fd80891b9d3ea0af35d508f6ef704fc48886b 100644 (file)
@@ -60,7 +60,7 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
        }
 
        /* Don't allow too many pending pages in flight.. */
-       if (atomic_read(&nr_async_pages) > SWAP_CLUSTER_MAX)
+       if (atomic_read(&nr_async_pages) > pager_daemon.swap_cluster)
                wait = 1;
 
        p = &swap_info[type];
index 1e2d8c36b279b9e3bbd94c334263126ee28992d0..fca90a30ba10b8ab05ed5bc688e7579ec9c9a5e9 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -39,6 +39,9 @@ freepages_t freepages = {
        144     /* freepages.high */
 };
 
+/* How many pages do we try to swap or page in/out together? */
+int page_cluster = 4; /* Default value modified in swap_setup() */
+
 /* We track the number of pages currently being asynchronously swapped
    out, so that we don't try to swap TOO many pages out at once */
 atomic_t nr_async_pages = ATOMIC_INIT(0);
@@ -77,3 +80,19 @@ pager_daemon_t pager_daemon = {
        SWAP_CLUSTER_MAX,       /* minimum number of tries */
        SWAP_CLUSTER_MAX,       /* do swap I/O in clusters of this size */
 };
+
+
+/*
+ * Perform any setup for the swap system
+ */
+
+void __init swap_setup(void)
+{
+       /* Use a smaller cluster for memory <16MB or <32MB */
+       if (num_physpages < ((16 * 1024 * 1024) >> PAGE_SHIFT))
+               page_cluster = 2;
+       else if (num_physpages < ((32 * 1024 * 1024) >> PAGE_SHIFT))
+               page_cluster = 3;
+       else
+               page_cluster = 4;
+}
index e098974b2d2acfdc47c57a16641ed2a569af7990..cd4cb10bf2f9c5ff46b4e755cce0629a7e4917f6 100644 (file)
@@ -258,7 +258,7 @@ void free_page_and_swap_cache(unsigned long addr)
  * incremented.
  */
 
-static struct page * lookup_swap_cache(unsigned long entry)
+struct page * lookup_swap_cache(unsigned long entry)
 {
        struct page *found;
        
@@ -305,7 +305,7 @@ struct page * read_swap_cache_async(unsigned long entry, int wait)
        if (found_page)
                goto out;
 
-       new_page_addr = __get_free_page(GFP_KERNEL);
+       new_page_addr = __get_free_page(GFP_USER);
        if (!new_page_addr)
                goto out;       /* Out of memory */
        new_page = mem_map + MAP_NR(new_page_addr);
index f053210e5a9d3e5ec3b058d65e395327b68bf396..2c2b01fafff32cc70e3f86e55c7b8958cfd81605 100644 (file)
@@ -417,31 +417,6 @@ out:
        return 0;
 }
 
-/*
- * We are much more aggressive about trying to swap out than we used
- * to be.  This works out OK, because we now do proper aging on page
- * contents. 
- */
-static int do_try_to_free_page(int gfp_mask)
-{
-       int i=6;
-
-       /* Always trim SLAB caches when memory gets low. */
-       kmem_cache_reap(gfp_mask);
-
-       do {
-               if (shrink_mmap(i, gfp_mask))
-                       return 1;
-               if (shm_swap(i, gfp_mask))
-                       return 1;
-               if (swap_out(i, gfp_mask))
-                       return 1;
-               shrink_dcache_memory(i, gfp_mask);
-               i--;
-       } while (i >= 0);
-       return 0;
-}
-
 /*
  * Before we start the kernel thread, print out the 
  * kswapd initialization message (otherwise the init message 
@@ -453,6 +428,8 @@ void __init kswapd_setup(void)
        int i;
        char *revision="$Revision: 1.5 $", *s, *e;
 
+       swap_setup();
+       
        if ((s = strchr(revision, ':')) &&
            (e = strchr(s, '$')))
                s++, i = e - s;
@@ -461,6 +438,44 @@ void __init kswapd_setup(void)
        printk ("Starting kswapd v%.*s\n", i, s);
 }
 
+#define free_memory(fn) \
+       count++; do { if (!--count) goto done; } while (fn)
+
+static int kswapd_free_pages(int kswapd_state)
+{
+       unsigned long end_time;
+
+       /* Always trim SLAB caches when memory gets low. */
+       kmem_cache_reap(0);
+
+       /* max one hundreth of a second */
+       end_time = jiffies + (HZ-1)/100;
+       do {
+               int priority = 7;
+               int count = pager_daemon.swap_cluster;
+
+               switch (kswapd_state) {
+                       do {
+                       default:
+                               free_memory(shrink_mmap(priority, 0));
+                               kswapd_state++;
+                       case 1:
+                               free_memory(shm_swap(priority, 0));
+                               kswapd_state++;
+                       case 2:
+                               free_memory(swap_out(priority, 0));
+                               shrink_dcache_memory(priority, 0);
+                               kswapd_state = 0;
+                       } while (--priority >= 0);
+                       return kswapd_state;
+               }
+done:
+               if (nr_free_pages > freepages.high + pager_daemon.swap_cluster)
+                       break;
+       } while (time_before_eq(jiffies,end_time));
+       return kswapd_state;
+}
+
 /*
  * The background pageout daemon.
  * Started as a kernel thread from the init process.
@@ -503,22 +518,14 @@ int kswapd(void *unused)
        init_swap_timer();
        kswapd_task = current;
        while (1) {
-               unsigned long end_time;
+               int state = 0;
 
                current->state = TASK_INTERRUPTIBLE;
                flush_signals(current);
                run_task_queue(&tq_disk);
                schedule();
                swapstats.wakeups++;
-
-               /* max one hundreth of a second */
-               end_time = jiffies + (HZ-1)/100;
-               do {
-                       if (!do_try_to_free_page(0))
-                               break;
-                       if (nr_free_pages > freepages.high + SWAP_CLUSTER_MAX)
-                               break;
-               } while (time_before_eq(jiffies,end_time));
+               state = kswapd_free_pages(state);
        }
        /* As if we could ever get here - maybe we want to make this killable */
        kswapd_task = NULL;
@@ -535,23 +542,39 @@ int kswapd(void *unused)
  * if we need more memory as part of a swap-out effort we
  * will just silently return "success" to tell the page
  * allocator to accept the allocation.
+ *
+ * We want to try to free "count" pages, and we need to 
+ * cluster them so that we get good swap-out behaviour. See
+ * the "free_memory()" macro for details.
  */
 int try_to_free_pages(unsigned int gfp_mask, int count)
 {
-       int retval = 1;
+       int retval;
 
        lock_kernel();
+
+       /* Always trim SLAB caches when memory gets low. */
+       kmem_cache_reap(gfp_mask);
+
+       retval = 1;
        if (!(current->flags & PF_MEMALLOC)) {
+               int priority;
+
                current->flags |= PF_MEMALLOC;
+       
+               priority = 8;
                do {
-                       retval = do_try_to_free_page(gfp_mask);
-                       if (!retval)
-                               break;
-                       count--;
-               } while (count > 0);
+                       free_memory(shrink_mmap(priority, gfp_mask));
+                       free_memory(shm_swap(priority, gfp_mask));
+                       free_memory(swap_out(priority, gfp_mask));
+                       shrink_dcache_memory(priority, gfp_mask);
+               } while (--priority >= 0);
+               retval = 0;
+done:
                current->flags &= ~PF_MEMALLOC;
        }
        unlock_kernel();
+
        return retval;
 }
 
index 77cb218d30fb92ade98aa2881c108501d16eb630..32d679cae71d6a29ef0f1565de6ee2da56523ca2 100644 (file)
@@ -1242,21 +1242,17 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
                return -EINVAL;
 
        /*
-        *      The write queue this time is holding sockets ready to use
+        *      The read queue this time is holding sockets ready to use
         *      hooked into the SABM we saved
         */
        do {
-               cli();
                if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
-                       if (flags & O_NONBLOCK) {
-                               sti();
+                       if (flags & O_NONBLOCK)
                                return -EWOULDBLOCK;
-                       }
+
                        interruptible_sleep_on(sk->sleep);
-                       if (signal_pending(current)) {
-                               sti();
+                       if (signal_pending(current)) 
                                return -ERESTARTSYS;
-                       }
                }
        } while (skb == NULL);
 
@@ -1264,10 +1260,10 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
        newsk->pair = NULL;
        newsk->socket = newsock;
        newsk->sleep = &newsock->wait;
-       sti();
 
        /* Now attach up the new socket */
        skb->sk = NULL;
+       skb->destructor = NULL;
        kfree_skb(skb);
        sk->ack_backlog--;
        newsock->sk    = newsk;
index 6b5e68236add8298bf8858d2dd2364892abc0e1d..4641228235be9e628df0a0bb3dfbd769ddfdf5ab 100644 (file)
@@ -19,6 +19,7 @@
  *     AX.25 036       Jonathan(G4KLX) Cloned from ax25_in.c
  *                     Joerg(DL1BKE)   Fixed it.
  *     AX.25 037       Jonathan(G4KLX) New timer architecture.
+ *                     Joerg(DL1BKE)   ax25->n2count never got reset
  */
 
 #include <linux/config.h>
@@ -47,7 +48,7 @@
 
 /*
  *     State machine for state 1, Awaiting Connection State.
- *     The handling of the timer(s) is in file ax25_timer.c.
+ *     The handling of the timer(s) is in file ax25_ds_timer.c.
  *     Handling of state 0 and connection release is in ax25.c.
  */
 static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
@@ -58,6 +59,12 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                        ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
                        break;
+                       
+               case AX25_SABME:
+                       ax25->modulus = AX25_EMODULUS;
+                       ax25->window  =  ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       break;
 
                case AX25_DISC:
                        ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
@@ -83,7 +90,7 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
 
                        /* according to DK4EG´s spec we are required to
                         * send a RR RESPONSE FINAL NR=0. Please mail
-                        * <jr@lykos.oche.de> if this causes problems
+                        * <jreuter@poboxes.com> if this causes problems
                         * with the TheNetNode DAMA Master implementation.
                         */ 
 
@@ -104,13 +111,14 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
 
 /*
  *     State machine for state 2, Awaiting Release State.
- *     The handling of the timer(s) is in file ax25_timer.c
+ *     The handling of the timer(s) is in file ax25_ds_timer.c
  *     Handling of state 0 and connection release is in ax25.c.
  */
 static int ax25_ds_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
 {
        switch (frametype) {
                case AX25_SABM:
+               case AX25_SABME:
                        ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
                        ax25_dama_off(ax25);
                        break;
@@ -157,8 +165,14 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
 
        switch (frametype) {
                case AX25_SABM:
-                       ax25->modulus   = AX25_MODULUS;
-                       ax25->window    = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+               case AX25_SABME:
+                       if (frametype == AX25_SABM) {
+                               ax25->modulus   = AX25_MODULUS;
+                               ax25->window    = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+                       } else {
+                               ax25->modulus   = AX25_EMODULUS;
+                               ax25->window    = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+                       }
                        ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
                        ax25_stop_t1timer(ax25);
                        ax25_start_t3timer(ax25);
@@ -188,8 +202,10 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                                ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
                        else
                                ax25->condition |= AX25_COND_PEER_RX_BUSY;
+
                        if (ax25_validate_nr(ax25, nr)) {
-                               ax25_check_iframes_acked(ax25, nr);
+                               if (ax25_check_iframes_acked(ax25, nr))
+                                       ax25->n2count=0;
                                if (type == AX25_COMMAND && pf)
                                        ax25_ds_enquiry_response(ax25);
                        } else {
@@ -200,13 +216,17 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
 
                case AX25_REJ:
                        ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+
                        if (ax25_validate_nr(ax25, nr)) {
+                               if (ax25->va != nr)
+                                       ax25->n2count=0;
+
                                ax25_frames_acked(ax25, nr);
                                ax25_calculate_rtt(ax25);
                                ax25_stop_t1timer(ax25);
                                ax25_start_t3timer(ax25);
-                               ax25->n2count = 0;
                                ax25_requeue_frames(ax25);
+
                                if (type == AX25_COMMAND && pf)
                                        ax25_ds_enquiry_response(ax25);
                        } else {
@@ -225,14 +245,15 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                                ax25_frames_acked(ax25, nr);
                                ax25->n2count = 0;
                        } else {
-                               ax25_check_iframes_acked(ax25, nr);
+                               if (ax25_check_iframes_acked(ax25, nr))
+                                       ax25->n2count = 0;
                        }
                        if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
                                if (pf) ax25_ds_enquiry_response(ax25);
                                break;
                        }
                        if (ns == ax25->vr) {
-                               ax25->vr = (ax25->vr + 1) % AX25_MODULUS;
+                               ax25->vr = (ax25->vr + 1) % ax25->modulus;
                                queued = ax25_rx_iframe(ax25, skb);
                                if (ax25->condition & AX25_COND_OWN_RX_BUSY)
                                        ax25->vr = ns;  /* ax25->vr - 1 */
index 841149996770106b3d96b7e937cdff1da0824b12..06135e9de491c8dfb81b7e04f5bffeededf0863b 100644 (file)
@@ -119,8 +119,10 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
                         * Check the state of the receive buffer.
                         */
                        if (ax25->sk != NULL) {
-                               if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
+                               if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && 
+                                   (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
                                        ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
+                                       ax25->condition &= ~AX25_COND_ACK_PENDING;
                                        break;
                                }
                        }
@@ -150,17 +152,11 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
        ax25_clear_queues(ax25);
 
        ax25->n2count = 0;
-
-       /* state 1 or 2 should not happen, but... */
-
-       if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2)
-               ax25->state = AX25_STATE_0;
-       else
-               ax25->state = AX25_STATE_2;
+       ax25->state = AX25_STATE_2;
 
        ax25_calculate_t1(ax25);
        ax25_start_t1timer(ax25);
-       ax25_start_t3timer(ax25);
+       ax25_stop_t3timer(ax25);
 
        if (ax25->sk != NULL) {
                ax25->sk->state     = TCP_CLOSE;
index 79fef3dcba3b0beceef7a38a562c1398b2d83775..dee4565ad9c30c76ee83e4592bd54255feb79d37 100644 (file)
@@ -389,10 +389,9 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                }
 
                ax25 = make->protinfo.ax25;
-
+               skb_set_owner_r(skb, make);
                skb_queue_head(&sk->receive_queue, skb);
 
-               skb->sk     = make;
                make->state = TCP_ESTABLISHED;
                make->pair  = sk;
 
@@ -473,6 +472,7 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
 int ax25_kiss_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
 {
        skb->sk = NULL;         /* Initially we don't know who it's for */
+       skb->destructor = NULL; /* Who initializes this, dammit?! */
 
        if ((*skb->data & 0x0F) != 0) {
                kfree_skb(skb); /* Not a KISS data frame */
index beac955e5447de6c4632b3633c6b8d0782f9b5f8..423b6690b357cd6ed7898b688374825a8e7c18c6 100644 (file)
@@ -30,6 +30,8 @@
  *                     Joerg(DL1BKE)   Fixed DAMA Slave mode: will work
  *                                     on non-DAMA interfaces like AX25L2V2
  *                                     again (this behaviour is _required_).
+ *                     Joerg(DL1BKE)   ax25_check_iframes_acked() returns a 
+ *                                     value now (for DAMA n2count handling)
  */
 
 #include <linux/config.h>
@@ -391,20 +393,23 @@ void ax25_queue_xmit(struct sk_buff *skb)
        dev_queue_xmit(skb);
 }
 
-void ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
+int ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
 {
        if (ax25->vs == nr) {
                ax25_frames_acked(ax25, nr);
                ax25_calculate_rtt(ax25);
                ax25_stop_t1timer(ax25);
                ax25_start_t3timer(ax25);
+               return 1;
        } else {
                if (ax25->va != nr) {
                        ax25_frames_acked(ax25, nr);
                        ax25_calculate_t1(ax25);
                        ax25_start_t1timer(ax25);
+                       return 1;
                }
        }
+       return 0;
 }
 
 #endif
index b4e8d140b6535daf9c85a687a0d0f4fc9ac3618a..d40b846c29b6640066851004172110112e86aa45 100644 (file)
@@ -1897,9 +1897,6 @@ __initfunc(int net_dev_init(void))
         * Some devices want to be initialized early..
         */
 
-#if defined(CONFIG_LANCE)
-       lance_init();
-#endif
 #if defined(CONFIG_SCC)
        scc_init();
 #endif
@@ -1937,11 +1934,14 @@ __initfunc(int net_dev_init(void))
         *      SLHC if present needs attaching so other people see it
         *      even if not opened.
         */
+        
+#ifdef CONFIG_INET      
 #if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \
         || defined(CONFIG_PPP) \
     || (defined(CONFIG_ISDN) && defined(CONFIG_ISDN_PPP))
        slhc_install();
 #endif 
+#endif
 
 #ifdef CONFIG_NET_PROFILE
        net_profile_init();
index af1bb4a44eda7ff0c9fa9f8d25e1d0acddba6fa2..47547e92fc701c35c60898a0ab79ef67cc4e55d5 100644 (file)
@@ -50,6 +50,8 @@
  *             Yu Tianli       :       Fixed two ugly bugs in icmp_send
  *                                     - IP option length was accounted wrongly
  *                                     - ICMP header length was not accounted at all.
+ *              Tristan Greaves :       Added sysctl option to ignore bogus broadcast
+ *                                      responses from broken routers.
  *
  * To Fix:
  *
@@ -311,6 +313,9 @@ struct icmp_err icmp_err_convert[] = {
 int sysctl_icmp_echo_ignore_all = 0;
 int sysctl_icmp_echo_ignore_broadcasts = 0;
 
+/* Control parameter - ignore bogus broadcast responses? */
+int sysctl_icmp_ignore_bogus_error_responses =0;
+
 /*
  *     ICMP control array. This specifies what to do with each ICMP.
  */
@@ -701,16 +706,19 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
         *      first check your netmask matches at both ends, if it does then
         *      get the other vendor to fix their kit.
         */
-        
-       if (inet_addr_type(iph->daddr) == RTN_BROADCAST)
+
+       if (!sysctl_icmp_ignore_bogus_error_responses)
        {
-               if (net_ratelimit())
-                       printk(KERN_WARNING "%s sent an invalid ICMP error to a broadcast.\n",
-                              in_ntoa(skb->nh.iph->saddr));
-               return; 
+       
+               if (inet_addr_type(iph->daddr) == RTN_BROADCAST)
+               {
+                       if (net_ratelimit())
+                               printk(KERN_WARNING "%s sent an invalid ICMP error to a broadcast.\n",
+                               in_ntoa(skb->nh.iph->saddr));
+                       return; 
+               }
        }
 
-
        /*
         *      Deliver ICMP message to raw sockets. Pretty useless feature?
         */
@@ -886,8 +894,10 @@ static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, int len)
 
 static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, int len)
 {
+#if 0
        if (net_ratelimit())
                printk(KERN_DEBUG "a guy asks for address mask. Who is it?\n");
+#endif         
 }
 
 /*
index c186a8953651390c476a85bd04a727a807b4b35f..ba0639714b3ac6a14f88eaccb31987fd63ba248f 100644 (file)
@@ -31,6 +31,7 @@ static int boolean_max = 1;
 /* From icmp.c */
 extern int sysctl_icmp_echo_ignore_all;
 extern int sysctl_icmp_echo_ignore_broadcasts;
+extern int sysctl_icmp_ignore_bogus_error_responses;
 
 /* From ip_fragment.c */
 extern int sysctl_ipfrag_low_thresh;
@@ -164,6 +165,9 @@ ctl_table ipv4_table[] = {
        {NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, "icmp_echo_ignore_broadcasts",
         &sysctl_icmp_echo_ignore_broadcasts, sizeof(int), 0644, NULL,
         &proc_dointvec},
+       {NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES, "icmp_ignore_bogus_error_responses",
+        &sysctl_icmp_ignore_bogus_error_responses, sizeof(int), 0644, NULL,
+        &proc_dointvec},
        {NET_IPV4_ICMP_DESTUNREACH_RATE, "icmp_destunreach_rate",
         &sysctl_icmp_destunreach_time, sizeof(int), 0644, NULL, &proc_dointvec},
        {NET_IPV4_ICMP_TIMEEXCEED_RATE, "icmp_timeexceed_rate",
index f258a356608a8a69288689ef0ea140d58e572ec7..a78f372ebb9dd6522a58a4bb064d152212d1b702 100644 (file)
@@ -43,7 +43,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/types.h>
index f58f18b749e56c15f15a9a29f20e787435004ac0..e01781556df749b5cdf30bd08b4b99a6edc4a213 100644 (file)
@@ -24,7 +24,6 @@
 
 /* #include <linux/module.h> */
 
-#include <linux/config.h>
 #include <linux/init.h>
 
 #include <net/irda/irda.h>
index 4a7607d36cab0645e010b5fc3886e841a6e60bcc..d2e876be9fdaa5928b9f9aabcfca1943be14da33 100644 (file)
@@ -23,8 +23,6 @@
  *     
  ********************************************************************/
 
-#include <linux/config.h>
-
 #include <net/irda/irda.h>
 #include <net/irda/irqueue.h>
 #include <net/irda/irlap.h>
index daecb7f50768d73f25dae5cfc6f23696c2d4d6f2..c5daad9d1c0bd7211841fe46a38c4d64ca325bce 100644 (file)
@@ -226,8 +226,8 @@ void use_config(const char * name, int len)
  */
 #define MAX2(a,b) ((a)>(b)?(a):(b))
 #define MIN2(a,b) ((a)<(b)?(a):(b))
-#define MAX5(a,b,c,d,e) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,e)))))
-#define MIN5(a,b,c,d,e) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,e)))))
+#define MAX6(a,b,c,d,e,f) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,MAX2(e,f))))))
+#define MIN6(a,b,c,d,e,f) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,MIN2(e,f))))))
 
 
 
@@ -241,11 +241,12 @@ void use_config(const char * name, int len)
  *    m|#\s*include\s*<(.*?>"|
  *    m|#\s*(?define|undef)\s*CONFIG_(\w*)|
  *    m|(?!\w)CONFIG_|
+ *    m|__SMP__|
  *
  * About 98% of the CPU time is spent here, and most of that is in
  * the 'start' paragraph.  Because the current characters are
  * in a register, the start loop usually eats 4 or 8 characters
- * per memory read.  The MAX5 and MIN5 tests dispose of most
+ * per memory read.  The MAX6 and MIN6 tests dispose of most
  * input characters with 1 or 2 comparisons.
  */
 void state_machine(const char * map)
@@ -258,13 +259,14 @@ void state_machine(const char * map)
 start:
        GETNEXT
 __start:
-       if (current > MAX5('/','\'','"','#','C')) goto start;
-       if (current < MIN5('/','\'','"','#','C')) goto start;
+       if (current > MAX6('/','\'','"','#','C','_')) goto start;
+       if (current < MIN6('/','\'','"','#','C','_')) goto start;
        CASE('/',  slash);
        CASE('\'', squote);
        CASE('"',  dquote);
        CASE('#',  pound);
        CASE('C',  cee);
+       CASE('_',  underscore);
        goto start;
 
 /* / */
@@ -398,6 +400,18 @@ cee_CONFIG_word:
                goto cee_CONFIG_word;
        use_config(map_dot, next - map_dot - 1);
        goto __start;
+
+/* __SMP__ */
+underscore:
+       GETNEXT NOTCASE('_', __start);
+       GETNEXT NOTCASE('S', __start);
+       GETNEXT NOTCASE('M', __start);
+       GETNEXT NOTCASE('P', __start);
+       GETNEXT NOTCASE('_', __start);
+       GETNEXT NOTCASE('_', __start);
+       use_config("SMP", 3);
+       goto __start;
+
     }
 }