]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.5 1.3.5
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:03 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:03 +0000 (15:10 -0500)
147 files changed:
Makefile
arch/alpha/config.in
arch/alpha/kernel/head.S
arch/alpha/lib/io.c
arch/i386/Makefile
arch/i386/boot/Makefile
arch/i386/boot/compressed/Makefile
arch/i386/boot/compressed/head.S
arch/i386/boot/tools/build.c
arch/i386/config.in
arch/i386/ibcs/Makefile [deleted file]
arch/i386/ibcs/binfmt_coff.c [deleted file]
arch/i386/ibcs/binfmt_elf.c [deleted file]
arch/i386/ibcs/emulate.c [deleted file]
arch/i386/kernel/Makefile
arch/i386/kernel/entry.S
arch/i386/kernel/head.S
arch/i386/kernel/process.c
arch/i386/kernel/setup.c
arch/i386/kernel/traps.c
arch/i386/math-emu/div_Xsig.S
arch/i386/math-emu/div_small.S
arch/i386/math-emu/fpu_asm.h
arch/i386/math-emu/mul_Xsig.S
arch/i386/math-emu/polynom_Xsig.S
arch/i386/math-emu/reg_div.S
arch/i386/math-emu/reg_norm.S
arch/i386/math-emu/reg_round.S
arch/i386/math-emu/reg_u_add.S
arch/i386/math-emu/reg_u_div.S
arch/i386/math-emu/reg_u_mul.S
arch/i386/math-emu/reg_u_sub.S
arch/i386/math-emu/round_Xsig.S
arch/i386/math-emu/shr_Xsig.S
arch/i386/math-emu/wm_shrx.S
arch/i386/math-emu/wm_sqrt.S
arch/i386/mm/init.c
arch/mips/config.in
drivers/char/console.c
drivers/char/consolemap.c
drivers/char/lp.c
drivers/char/psaux.c
drivers/char/vt.c
drivers/net/3c505.c
drivers/net/CONFIG
drivers/net/Makefile
drivers/net/Space.c
drivers/net/de4x5.c
drivers/net/de4x5.h
drivers/net/depca.c
drivers/net/depca.h
drivers/net/hp100.c [new file with mode: 0644]
drivers/net/hp100.h [new file with mode: 0644]
drivers/net/ppp.c
drivers/pci/pci.c
drivers/scsi/53c7,8xx.c
drivers/scsi/53c7,8xx.h
drivers/scsi/ChangeLog
drivers/scsi/Makefile
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/README-FIRST.aic7xxx [deleted file]
drivers/scsi/aha152x.c
drivers/scsi/aha152x.h
drivers/scsi/aha1542.c
drivers/scsi/aha1542.h
drivers/scsi/aha1740.c
drivers/scsi/aha1740.h
drivers/scsi/aic7770.c [deleted file]
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx.h
drivers/scsi/aic7xxx.seq
drivers/scsi/aic7xxx_asm.c [new file with mode: 0644]
drivers/scsi/buslogic.c
drivers/scsi/buslogic.h
drivers/scsi/constants.c
drivers/scsi/eata.c
drivers/scsi/eata.h
drivers/scsi/eata_dma.c
drivers/scsi/eata_dma.h
drivers/scsi/eata_dma_proc.c [new file with mode: 0644]
drivers/scsi/eata_dma_proc.h [new file with mode: 0644]
drivers/scsi/eata_generic.h [new file with mode: 0644]
drivers/scsi/eata_pio.c [new file with mode: 0644]
drivers/scsi/eata_pio.h [new file with mode: 0644]
drivers/scsi/eata_pio_proc.c [new file with mode: 0644]
drivers/scsi/fdomain.c
drivers/scsi/fdomain.h
drivers/scsi/g_NCR5380.h
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/in2000.c
drivers/scsi/in2000.h
drivers/scsi/pas16.c
drivers/scsi/pas16.h
drivers/scsi/qlogic.c
drivers/scsi/qlogic.h
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_debug.h
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_module.c
drivers/scsi/scsi_proc.c [new file with mode: 0644]
drivers/scsi/scsicam.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/sd_ioctl.c
drivers/scsi/seagate.c
drivers/scsi/seagate.h
drivers/scsi/sg.c
drivers/scsi/sg.h
drivers/scsi/sr.c
drivers/scsi/sr_ioctl.c
drivers/scsi/st.c
drivers/scsi/t128.h
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.h
drivers/scsi/ultrastor.c
drivers/scsi/ultrastor.h
drivers/scsi/wd7000.c
drivers/scsi/wd7000.h
fs/binfmt_elf.c
fs/devices.c
fs/proc/Makefile
fs/proc/inode.c
fs/proc/root.c
fs/proc/scsi.c [new file with mode: 0644]
include/asm-alpha/io.h
include/asm-alpha/lca.h
include/asm-i386/io.h
include/asm-i386/irq.h
include/asm-i386/system.h
include/asm-sparc/version.h [deleted file]
include/asm-sparc/wim.h [deleted file]
include/linux/elfcore.h [new file with mode: 0644]
include/linux/linkage.h
include/linux/mm.h
include/linux/pci.h
include/linux/proc_fs.h
include/linux/symtab_begin.h
include/linux/sys.h
include/linux/timex.h
kernel/ksyms.c
kernel/printk.c
mm/kmalloc.c
net/Makefile

index b53b427c349f35c6bd6f63a53dbc51d192ae704f..a2c13e8a6e4bba556247c4bfd3c32c2f99f05b23 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 4
+SUBLEVEL = 5
 
 ARCH = i386
 
@@ -236,6 +236,7 @@ clean:      archclean
 mrproper: clean
        rm -f include/linux/autoconf.h include/linux/version.h
        rm -f drivers/sound/local.h
+       rm -f drivers/scsi/aic7xxx_asm drivers/scsi/aic7xxx_seq.h
        rm -f drivers/char/uni_hash_tbl.h drivers/char/conmakehash
        rm -f .version .config* config.in config.old
        rm -f include/asm
@@ -246,6 +247,8 @@ ifdef CONFIG_MODVERSIONS
 endif
 
 distclean: mrproper
+       rm -f core `find . -name '*.orig' -print`
+
 
 backup: mrproper
        cd .. && tar cf - linux | gzip -9 > backup.gz
index e37811e9ac1daf6f66c180f608f599c41482d3e8..4a955a446156e92d8acd723ec07d39b362426f6a 100644 (file)
@@ -86,9 +86,10 @@ comment 'SCSI low-level drivers'
 bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
 bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
 bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
-bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
+bool 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX n
 bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO n
 bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
 bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
 bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
index 2cff1159a17cd6d06ac234473b67f8616a497f82..bd50d1c9803fd170c835db13185680628f995a96 100644 (file)
@@ -90,8 +90,3 @@ wrmces:
        call_pal PAL_wrmces
        ret ($26)
        .end wrmces
-
-.align 9
-.globl floppy_track_buffer
-floppy_track_buffer:
-       .space 512*2*MAX_BUFFER_SECTORS,1
index 6dae74d8cd930305e6bdfe5dce8bab37de38ae6a..00e2c87ef6a84221f4bf8ab04b211ac8bd911923 100644 (file)
@@ -99,6 +99,40 @@ void writel(unsigned int b, unsigned long addr)
        __writel(b, addr);
 }
 
+/*
+ * Read COUNT 8-bit bytes from port PORT into memory starting at
+ * SRC.
+ */
+#undef insb
+void insb (unsigned long port, void *dst, unsigned long count)
+{
+       while (((unsigned long)dst) & 0x3) {
+               if (!count)
+                       return;
+               count--;
+               *(unsigned char *) dst = inb(port);
+               ((unsigned char *) dst)++;
+       }
+
+       while (count >= 4) {
+               unsigned int w;
+               count -= 4;
+               w = inb(port);
+               w |= inb(port) << 8;
+               w |= inb(port) << 16;
+               w |= inb(port) << 24;
+               *(unsigned int *) dst = w;
+               ((unsigned int *) dst)++;
+       }
+
+       while (count) {
+               --count;
+               *(unsigned char *) dst = inb(port);
+               ((unsigned char *) dst)++;
+       }
+}
+
+
 /*
  * Read COUNT 16-bit words from port PORT into memory starting at
  * SRC.  SRC must be at least short aligned.  This is used by the
@@ -109,28 +143,28 @@ void writel(unsigned int b, unsigned long addr)
 #undef insw
 void insw (unsigned long port, void *dst, unsigned long count)
 {
-       unsigned int *ip, w;
-
        if (((unsigned long)dst) & 0x3) {
                if (((unsigned long)dst) & 0x1) {
                        panic("insw: memory not short aligned");
                }
-               *(unsigned short*)dst = inw(port);
-               dst += 2;
-               --count;
+               if (!count)
+                       return;
+               count--;
+               *(unsigned short* ) dst = inw(port);
+               ((unsigned short *) dst)++;
        }
 
-       ip = dst;
        while (count >= 2) {
-               w  = inw(port);
-               w |= inw(port) << 16;
+               unsigned int w;
                count -= 2;
-               *ip++ = w;
+               w = inw(port);
+               w |= inw(port) << 16;
+               *(unsigned int *) dst = w;
+               ((unsigned int *) dst)++;
        }
 
        if (count) {
-               w = inw(port);
-               *(unsigned short*)ip = w;
+               *(unsigned short*) dst = inw(port);
        }
 }
 
@@ -145,20 +179,32 @@ void insw (unsigned long port, void *dst, unsigned long count)
 #undef insl
 void insl (unsigned long port, void *dst, unsigned long count)
 {
-       unsigned int *ip, w;
-
        if (((unsigned long)dst) & 0x3) {
                panic("insl: memory not aligned");
        }
 
-       ip = dst;
-       while (count > 0) {
-               w  = inw(port);
+       while (count) {
                --count;
-               *ip++ = w;
+               *(unsigned int *) dst = inl(port);
+               ((unsigned int *) dst)++;
        }
 }
 
+/*
+ * Like insb but in the opposite direction.
+ * Don't worry as much about doing aligned memory transfers:
+ * doing byte reads the "slow" way isn't nearly as slow as
+ * doing byte writes the slow way (no r-m-w cycle).
+ */
+#undef outsb
+void outsb(unsigned long port, void * src, unsigned long count)
+{
+       while (count) {
+               count--;
+               outb(*(char *)src, port);
+               ((char *) src)++;
+       }
+}
 
 /*
  * Like insw but in the opposite direction.  This is used by the IDE
@@ -169,27 +215,26 @@ void insl (unsigned long port, void *dst, unsigned long count)
 #undef outsw
 void outsw (unsigned long port, void *src, unsigned long count)
 {
-       unsigned int *ip, w;
-
        if (((unsigned long)src) & 0x3) {
                if (((unsigned long)src) & 0x1) {
                        panic("outsw: memory not short aligned");
                }
                outw(*(unsigned short*)src, port);
-               src += 2;
+               ((unsigned short *) src)++;
                --count;
        }
 
-       ip = src;
        while (count >= 2) {
-               w = *ip++;
+               unsigned int w;
                count -= 2;
+               w = *(unsigned int *) src;
+               ((unsigned int *) src)++;
                outw(w >>  0, port);
                outw(w >> 16, port);
        }
 
        if (count) {
-               outw(*(unsigned short*)ip, port);
+               outw(*(unsigned short *) src, port);
        }
 }
 
@@ -203,16 +248,55 @@ void outsw (unsigned long port, void *src, unsigned long count)
 #undef outsw
 void outsl (unsigned long port, void *src, unsigned long count)
 {
-       unsigned int *ip, w;
-
        if (((unsigned long)src) & 0x3) {
                panic("outsw: memory not aligned");
        }
 
-       ip = src;
-       while (count > 0) {
-               w = *ip++;
+       while (count) {
                --count;
-               outw(w, port);
+               outl(*(unsigned int *) src, port);
+               ((unsigned int *) src)++;
+       }
+}
+
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ * This needs to be optimized.
+ */
+void memcpy_fromio(void * to, unsigned long from, unsigned long count)
+{
+       while (count) {
+               count--;
+               *(char *) to = readb(from);
+               ((char *) to)++;
+               from++;
+       }
+}
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ * This needs to be optimized.
+ */
+void memcpy_toio(unsigned long to, void * from, unsigned long count)
+{
+       while (count) {
+               count--;
+               writeb(*(char *) from, to);
+               ((char *) from)++;
+               to++;
+       }
+}
+
+/*
+ * "memset" on IO memory space.
+ * This needs to be optimized.
+ */
+void memset_io(unsigned long dst, int c, unsigned long count)
+{
+       while (count) {
+               count--;
+               writeb(c, dst);
+               dst++;
        }
 }
index 8eef1e537460685b34f32040bd8be2b52b1b192b..214094e10be358acca832fec769977cf4de32b71 100644 (file)
 #
 # ZLINKFLAGS   = -Ttext 0x1000
 # LINKFLAGS    = -Ttext 0x100000
+#
+#
+
+ifdef CONFIG_KERNEL_ELF
+
+LD=ld -m elf_i386
+CPP=$(CC) -E -D__ELF__
+OBJDUMP =objdump
+OBJDUMP_FLAGS=-k -q 
+LDFLAGS=-e startup_32 
+LDFLAGS=-e stext
+ZIMAGE_OFFSET=0x1000
+IMAGE_OFFSET=0x100000
+ZLINKFLAGS =-Ttext $(ZIMAGE_OFFSET) $(LDFLAGS)
+LINKFLAGS =-Ttext $(IMAGE_OFFSET) $(LDFLAGS)
+
+else
+
 #
 # -qmagic (we need to remove the 32 byte header for bootup purposes)
 #
 ZLINKFLAGS =-qmagic -Ttext 0xfe0
 LINKFLAGS =-qmagic -Ttext 0xfffe0
+endif
 CFLAGS := $(CFLAGS) -pipe
 
 ifdef CONFIG_M486
@@ -43,11 +62,6 @@ SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib
 ARCHIVES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(ARCHIVES)
 LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a
 
-ifdef CONFIG_IBCS
-SUBDIRS := $(SUBDIRS) arch/i386/ibcs
-DRIVERS := $(DRIVERS) arch/i386/ibcs/ibcs.o
-endif
-
 ifdef CONFIG_MATH_EMULATION
 SUBDIRS := $(SUBDIRS) arch/i386/math-emu
 DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a
index b6a5f1c157052898ddf5f2c7ac63d5e423b2c010..c0a77a028eef9325fb2e25c377f468d4348aed6d 100644 (file)
 AS86    =as86 -0 -a
 LD86    =ld86 -0
 
+ifdef CONFIG_KERNEL_ELF
+CFLAGS := $(CFLAGS) -D__BFD__
+endif
+
 zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
+ifdef CONFIG_KERNEL_ELF
+       $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(ZIMAGE_OFFSET) compressed/vmlinux > compressed/vmlinux.out
+       tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
+else
        tools/build bootsect setup compressed/vmlinux $(ROOT_DEV) > zImage
+endif
        sync
 
 compressed/vmlinux: $(TOPDIR)/vmlinux
@@ -56,5 +65,5 @@ dep:
 
 clean:
        rm -f bootsect setup
-       rm -f zImage tools/build
+       rm -f zImage tools/build compressed/vmlinux.out
        @$(MAKE) -C compressed clean
index b4e3f84823a0ad81f8f1392ea6506c8eeb876af9..cce49d9b8def3204fe15d882f41fda5496d485f4 100644 (file)
@@ -11,6 +11,12 @@ OBJECTS = $(HEAD) inflate.o unzip.o misc.o
 
 CFLAGS = -O2 -DSTDC_HEADERS
 
+ifdef CONFIG_KERNEL_ELF
+TARGET=--target elf32-i386
+INPUT_DATA=input_data
+INPUT_LEN=input_len
+endif
+
 .c.s:
        $(CC) $(CFLAGS) -S $<
 .s.o:
@@ -20,13 +26,24 @@ CFLAGS = -O2 -DSTDC_HEADERS
 
 all: vmlinux
 
-vmlinux:       piggy.o $(OBJECTS)
-               $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+vmlinux: piggy.o $(OBJECTS)
+       $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+
+head.o: head.S $(TOPDIR)/include/linux/tasks.h
+       $(CC) -traditional -c head.S
 
-head.o:        head.s
+ifdef CONFIG_KERNEL_ELF
 
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
-       $(CPP) -traditional head.S -o head.s
+# You cannot compress a file and have the kernel uncompress it, it must
+# be stdin
+piggy.o:       $(SYSTEM)
+       tmppiggy=/tmp/$$.piggy; \
+       rm -f $$tmppiggy $$tmppiggy.gz; \
+       $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) $(SYSTEM) > $$tmppiggy; \
+       gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
+       encaps $(TARGET) piggy.o $$tmppiggy.gz $(INPUT_DATA) $(INPUT_LEN); \
+       rm -f $$tmppiggy $$tmppiggy.gz
+else
 
 piggy.o:       $(SYSTEM) xtract piggyback
                ./xtract $(SYSTEM) | gzip -9 | ./piggyback > piggy.o
@@ -37,5 +54,7 @@ xtract: xtract.c
 piggyback: piggyback.c
        $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
 
+endif
+
 clean:
        rm -f xtract piggyback vmlinux
index 6035cea85907bec7c0e2326eba5002b98148423e..b0d26cb5d8096bb686325920b4ccfd6280f43930 100644 (file)
 .text
 
 #define __ASSEMBLY__
+#include <linux/linkage.h>
 #include <asm/segment.h>
 
+       .globl startup_32
 startup_32:
        cld
        cli
@@ -29,7 +31,7 @@ startup_32:
        mov %ax,%es
        mov %ax,%fs
        mov %ax,%gs
-       lss _stack_start,%esp
+       lss SYMBOL_NAME(stack_start),%esp
        xorl %eax,%eax
 1:     incl %eax               # check that A20 really IS enabled
        movl %eax,0x000000      # loop forever if it isn't
@@ -46,8 +48,8 @@ startup_32:
  * Clear BSS
  */
        xorl %eax,%eax
-       movl $__edata,%edi
-       movl $__end,%ecx
+       movl $ SYMBOL_NAME(_edata),%edi
+       movl $ SYMBOL_NAME(_end),%ecx
        subl %edi,%ecx
        cld
        rep
@@ -55,5 +57,5 @@ startup_32:
 /*
  * Do the decompression, and jump to the new kernel..
  */
-       call _decompress_kernel
+       call SYMBOL_NAME(decompress_kernel)
        ljmp $(KERNEL_CS), $0x100000
index 31277a0195348ffbb96947cc6ebe6c7a12ae496a..c50ffc2d2e35778df866d66f6501e99bf406768f 100644 (file)
 #include <fcntl.h>
 #include <linux/a.out.h>
 #include <linux/config.h>
+#include <errno.h>
 
 #define MINIX_HEADER 32
 
 #define N_MAGIC_OFFSET 1024
+#ifndef __BFD__
 static int GCC_HEADER = sizeof(struct exec);
+#endif
 
 #define SYS_SIZE DEF_SYSSIZE
 
@@ -89,7 +92,9 @@ int main(int argc, char ** argv)
        int i,c,id, sz;
        unsigned long sys_size;
        char buf[1024];
+#ifndef __BFD__
        struct exec *ex = (struct exec *)buf;
+#endif
        char major_root, minor_root;
        struct stat sb;
        unsigned char setup_sectors;
@@ -190,6 +195,7 @@ int main(int argc, char ** argv)
        
        if ((id=open(argv[3],O_RDONLY,0))<0)
                die("Unable to open 'system'");
+#ifndef __BFD__
        if (read(id,buf,GCC_HEADER) != GCC_HEADER)
                die("Unable to read header of 'system'");
        if (N_MAGIC(*ex) == ZMAGIC) {
@@ -203,6 +209,14 @@ int main(int argc, char ** argv)
                ex->a_data /1024,
                ex->a_bss  /1024);
        sz = N_SYMOFF(*ex) - GCC_HEADER + 4;
+#else
+       if (fstat (id, &sb)) {
+         perror ("fstat");
+         die ("Unable to stat 'system'");
+       }
+       sz = sb.st_size;
+       fprintf (stderr, "System is %d kB\n", sz/1024);
+#endif
        sys_size = (sz + 15) / 16;
        if (sys_size > SYS_SIZE)
                die("System is too big");
index 1cdf3e6617c2d137b5455b46c791b8d604259e3c..c3546ef00bc04fb751490329402ab9429aebe71b 100644 (file)
@@ -91,12 +91,11 @@ comment 'SCSI low-level drivers'
 
 bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y
 bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
-bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
-if [ "$CONFIG_PCI" = "y" ]; then
-  bool 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX n
-fi
+bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
+bool 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX n
 bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO n
 bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
 bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
 bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
@@ -173,6 +172,7 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then
        fi
        bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
        bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
+       bool 'HP 10/100VG PCLAN (257X series) support' CONFIG_HP100 y
        bool 'NE2000/NE1000 support' CONFIG_NE2000 y
        if [ "$CONFIG_AX25" = "y" ]; then
                bool 'Ottawa PI and PI/2 support' CONFIG_PI y
@@ -185,7 +185,7 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then
                bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
        fi
        bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
-       bool 'DE425, DE434, DE435 support' CONFIG_DE4X5 n
+       bool 'DE425, DE434, DE435, DE500 support' CONFIG_DE4X5 n
 #      bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
 #      bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
 #      bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
diff --git a/arch/i386/ibcs/Makefile b/arch/i386/ibcs/Makefile
deleted file mode 100644 (file)
index 7b81ff2..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Makefile for the iBCS emulator files
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-.S.s:
-       $(CPP) -traditional $< -o $*.s
-.c.s:
-       $(CC) $(CFLAGS) -S $<
-.s.o:
-       $(AS) -c -o $*.o $<
-.c.o:
-       $(CC) $(CFLAGS) -c $<
-
-SUBDIRS        = 
-
-OBJS  = emulate.o
-
-ibcs.o: $(OBJS)
-       $(LD) -r -o ibcs.o $(OBJS)
-       sync
-
-dep:
-       $(CPP) -M *.c > .depend
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
diff --git a/arch/i386/ibcs/binfmt_coff.c b/arch/i386/ibcs/binfmt_coff.c
deleted file mode 100644 (file)
index 1a7c760..0000000
+++ /dev/null
@@ -1,784 +0,0 @@
-/*
- * These are the functions used to load COFF IBSC style executables.
- * Information on COFF format may be obtained in either the Intel Binary
- * Compatibility Specification 2 or O'Rilley's book on COFF. The shared
- * libraries are defined only the in the Intel book.
- *
- * This file is based upon code written by Eric Youngdale for the ELF object
- * file format.
- *
- * Author: Al Longyear (longyear@sii.com)
- *
- * Latest Revision:
- *    3 February 1994
- *      Al Longyear (longyear@sii.com)
- *      Cleared first page of bss section using put_fs_byte.
- */
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <asm/segment.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/coff.h>
-#include <linux/malloc.h>
-
-asmlinkage int sys_exit (int exit_code);
-asmlinkage int sys_close (unsigned fd);
-asmlinkage int sys_open (const char *, int, int);
-asmlinkage int sys_uselib(const char * library);
-
-static int preload_library (struct linux_binprm *exe_bprm,
-                           COFF_SCNHDR * sect,
-                           struct file *fp);
-
-static int load_object (struct linux_binprm *bprm,
-                       struct pt_regs *regs,
-                       int lib_ok);
-
-/*
- *  Small procedure to test for the proper file alignment.
- */
-
-static inline int
-is_properly_aligned (COFF_SCNHDR *sect)
-{
-    long scnptr = COFF_LONG (sect->s_scnptr);
-    long vaddr  = COFF_LONG (sect->s_vaddr);
-/*
- *  Print the section information if needed
- */
-
-#ifdef COFF_DEBUG
-    printk ("%s, scnptr = %d, vaddr = %d\n",
-           sect->s_name,
-           scnptr, vaddr);
-#endif
-
-/*
- *  Return the error code if the section is not properly aligned.
- */
-
-#ifdef COFF_DEBUG
-    if (((vaddr - scnptr) & ~PAGE_MASK) != 0)
-       printk ("bad alignment in %s\n", sect->s_name);
-#endif
-    return ((((vaddr - scnptr) & ~PAGE_MASK) != 0) ? -ENOEXEC : 0);
-}
-
-/*
- *    Clear the bytes in the last page of data.
- */
-
-static
-int clear_memory (unsigned long addr, unsigned long size)
-{
-    int status;
-
-    size = (PAGE_SIZE - (addr & ~PAGE_MASK)) & ~PAGE_MASK;
-    if (size == 0)
-        status = 0;
-    else {
-      
-#ifdef COFF_DEBUG
-        printk ("un-initialized storage in last page %d\n", size);
-#endif
-
-       status = verify_area (VERIFY_WRITE,
-                             (void *) addr, size);
-#ifdef COFF_DEBUG
-       printk ("result from verify_area = %d\n", status);
-#endif
-
-       if (status >= 0)
-           while (size-- != 0)
-               put_fs_byte (0, addr++);
-    }
-    return status;
-}
-
-/*
- *  Helper function to process the load operation.
- */
-
-static int
-load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok)
-{
-    COFF_FILHDR  *coff_hdr = (COFF_FILHDR *) bprm->buf;        /* COFF Header */
-    COFF_SCNHDR  *sect_bufr;   /* Pointer to section table            */
-    COFF_SCNHDR  *text_sect;   /* Pointer to the text section         */
-    COFF_SCNHDR  *data_sect;   /* Pointer to the data section         */
-    COFF_SCNHDR  *bss_sect;    /* Pointer to the bss section          */
-    int text_count;            /* Number of text sections             */
-    int data_count;            /* Number of data sections             */
-    int bss_count;             /* Number of bss sections              */
-    int lib_count;             /* Number of lib sections              */
-    unsigned int start_addr = 0;/* Starting location for program       */
-    int status = 0;            /* Result status register              */
-    int fd = -1;               /* Open file descriptor                */
-    struct file *fp     = NULL;        /* Pointer to the file at "fd"         */
-    short int sections  = 0;   /* Number of sections in the file      */
-    short int aout_size = 0;   /* Size of the a.out header area       */
-    short int flags;           /* Flag bits from the COFF header      */
-
-#ifdef COFF_DEBUG
-    printk ("binfmt_coff entry: %s\n", bprm->filename);
-#endif
-
-/*
- *  Validate the magic value for the object file.
- */
-    do {
-       if (COFF_I386BADMAG (*coff_hdr)) {
-#ifdef COFF_DEBUG
-           printk ("bad filehdr magic\n");
-#endif
-           status = -ENOEXEC;
-           break;
-       }
-/*
- *  The object file should have 32 BIT little endian format. Do not allow
- *  it to have the 16 bit object file flag set as Linux is not able to run
- *  on the 80286/80186/8086.
- */
-       flags = COFF_SHORT (coff_hdr->f_flags);
-       if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) {
-#ifdef COFF_DEBUG
-           printk ("invalid f_flags bits\n");
-#endif
-           status = -ENOEXEC;
-           break;
-       }
-/*
- *  Extract the header information which we need.
- */
-       sections  = COFF_SHORT (coff_hdr->f_nscns);   /* Number of sections */
-       aout_size = COFF_SHORT (coff_hdr->f_opthdr);  /* Size of opt. headr */
-/*
- *  If the file is not executable then reject the execution. This means
- *  that there must not be external references.
- */
-       if ((flags & COFF_F_EXEC) == 0) {
-#ifdef COFF_DEBUG
-           printk ("not executable bit\n");
-#endif
-           status = -ENOEXEC;
-           break;
-       }
-/*
- *  There must be at least one section.
- */
-       if (sections == 0) {
-#ifdef COFF_DEBUG
-           printk ("no sections\n");
-#endif
-           status = -ENOEXEC;
-           break;
-       }
-/*
- *  Do some additional consistency checks.
- *  The system requires mapping for this loader. If you try
- *  to use a file system with no mapping, the format is not valid.
- */
-       if (!bprm->inode->i_op ||
-           !bprm->inode->i_op->default_file_ops->mmap) {
-#ifdef COFF_DEBUG
-           printk ("no mmap in fs\n");
-#endif
-           status = -ENOEXEC;
-       }
-    }
-    while (0);
-/*
- *  Allocate a buffer to hold the entire coff section list.
- */
-    if (status >= 0) {
-       int nbytes = sections * COFF_SCNHSZ;
-
-       sect_bufr = (COFF_SCNHDR *) kmalloc (nbytes, GFP_KERNEL);
-       if (0 == sect_bufr) {
-#ifdef COFF_DEBUG
-           printk ("kmalloc failed\n");
-#endif
-           status = -ENOEXEC;
-       }
-/*
- *  Read the section list from the disk file.
- */
-       else {
-            int old_fs = get_fs ();
-            set_fs (get_ds ());  /* Make it point to the proper location    */
-            status = read_exec (bprm->inode,        /* INODE for file       */
-                           aout_size + COFF_FILHSZ, /* Offset in the file   */
-                           (char *) sect_bufr,      /* Buffer for read      */
-                           nbytes);                 /* Byte count reqd.     */
-            set_fs (old_fs);                        /* Restore the selector */
-#ifdef COFF_DEBUG
-            if (status < 0)
-               printk ("read aout hdr, status = %d\n", status);
-#endif
-        }
-    }
-    else
-       sect_bufr = NULL;       /* Errors do not have a section buffer */
-/*
- *  Count the number of sections for the required types and store the location
- *  of the last section for the three primary types.
- */
-    text_count = 0;
-    data_count = 0;
-    bss_count  = 0;
-    lib_count  = 0;
-
-    text_sect = NULL;
-    data_sect = NULL;
-    bss_sect  = NULL;
-/*
- *  Loop through the sections and find the various types
- */
-    if (status >= 0) {
-       int nIndex;
-       COFF_SCNHDR *sect_ptr = sect_bufr;
-
-       for (nIndex = 0; nIndex < sections; ++nIndex) {
-           long int sect_flags = COFF_LONG (sect_ptr->s_flags);
-
-           switch (sect_flags) {
-           case COFF_STYP_TEXT:
-               text_sect = sect_ptr;
-               ++text_count;
-               status = is_properly_aligned (sect_ptr);
-               break;
-
-           case COFF_STYP_DATA:
-               data_sect = sect_ptr;
-               ++data_count;
-               status = is_properly_aligned (sect_ptr);
-               break;
-
-           case COFF_STYP_BSS:
-               bss_sect = sect_ptr;
-               ++bss_count;
-               break;
-
-           case COFF_STYP_LIB:
-#ifdef COFF_DEBUG
-               printk (".lib section found\n");
-#endif
-               ++lib_count;
-               break;
-
-           default:
-               break;
-           }
-           sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ];
-       }
-/*
- *  Ensure that there are the required sections. There must be one text
- *  sections and one each of the data and bss sections for an executable.
- *  A library may or may not have a data / bss section.
- */
-       if (text_count != 1) {
-           status = -ENOEXEC;
-#ifdef COFF_DEBUG
-           printk ("no text sections\n");
-#endif
-       }
-       else {
-           if (lib_ok) {
-               if (data_count != 1 || bss_count != 1) {
-                   status = -ENOEXEC;
-#ifdef COFF_DEBUG
-                   printk ("no .data nor .bss sections\n");
-#endif
-               }
-           }
-       }
-    }
-/*
- *  If there is no additional header then assume the file starts at
- *  the first byte of the text section. This may not be the proper place,
- *  so the best solution is to include the optional header. A shared library
- *  __MUST__ have an optional header to indicate that it is a shared library.
- */
-    if (status >= 0) {
-       if (aout_size == 0) {
-           if (!lib_ok) {
-               status = -ENOEXEC;
-#ifdef COFF_DEBUG
-               printk ("no header in library\n");
-#endif
-           }
-           start_addr = COFF_LONG (text_sect->s_vaddr);
-       }
-/*
- *  There is some header. Ensure that it is sufficient.
- */
-       else {
-           if (aout_size < COFF_AOUTSZ) {
-               status = -ENOEXEC;
-#ifdef COFF_DEBUG
-               printk ("header too small\n");
-#endif
-           }
-           else {
-               COFF_AOUTHDR *aout_hdr =        /* Pointer to a.out header */
-               (COFF_AOUTHDR *) & ((char *) coff_hdr)[COFF_FILHSZ];
-               short int aout_magic = COFF_SHORT (aout_hdr->magic); /* id */
-/*
- *  Validate the magic number in the a.out header. If it is valid then
- *  update the starting symbol location. Do not accept these file formats
- *  when loading a shared library.
- */
-               switch (aout_magic) {
-               case COFF_OMAGIC:
-               case COFF_ZMAGIC:
-               case COFF_STMAGIC:
-                   if (!lib_ok) {
-                       status = -ENOEXEC;
-#ifdef COFF_DEBUG
-                       printk ("wrong a.out header magic\n");
-#endif
-                   }
-                   start_addr = (unsigned int) COFF_LONG (aout_hdr->entry);
-                   break;
-/*
- *  Magic value for a shared library. This is valid only when loading a
- *  shared library. (There is no need for a start_addr. It won't be used.)
- */
-               case COFF_SHMAGIC:
-                   if (lib_ok) {
-#ifdef COFF_DEBUG
-                       printk ("wrong a.out header magic\n");
-#endif
-                       status = -ENOEXEC;
-                   }
-                   break;
-
-               default:
-#ifdef COFF_DEBUG
-                   printk ("wrong a.out header magic\n");
-#endif
-                   status = -ENOEXEC;
-                   break;
-               }
-           }
-       }
-    }
-/*
- *  Fetch a file pointer to the executable.
- */
-    if (status >= 0) {
-       fd = open_inode (bprm->inode, O_RDONLY);
-       if (fd < 0) {
-#ifdef COFF_DEBUG
-           printk ("can not open inode, result = %d\n", fd);
-#endif
-           status = fd;
-       }
-       else
-           fp = current->files->fd[fd];
-    }
-    else
-       fd = -1;                /* Invalidate the open file descriptor */
-/*
- *  Generate the proper values for the text fields
- *
- *  THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD
- *  SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD.
- */
-    if (status >= 0) {
-       long text_scnptr = COFF_LONG (text_sect->s_scnptr);
-       long text_size   = COFF_LONG (text_sect->s_size);
-       long text_vaddr  = COFF_LONG (text_sect->s_vaddr);
-
-       long data_scnptr;
-       long data_size;
-       long data_vaddr;
-
-       long bss_size;
-       long bss_vaddr;
-/*
- *  Generate the proper values for the data fields
- */
-       if (data_sect != NULL) {
-           data_scnptr = COFF_LONG (data_sect->s_scnptr);
-           data_size   = COFF_LONG (data_sect->s_size);
-           data_vaddr  = COFF_LONG (data_sect->s_vaddr);
-       }
-       else {
-           data_scnptr = 0;
-           data_size   = 0;
-           data_vaddr  = 0;
-       }
-/*
- *  Generate the proper values for the bss fields
- */
-       if (bss_sect != NULL) {
-           bss_size  = COFF_LONG (bss_sect->s_size);
-           bss_vaddr = COFF_LONG (bss_sect->s_vaddr);
-       }
-       else {
-           bss_size  = 0;
-           bss_vaddr = 0;
-       }
-/*
- *  Flush the executable from memory. At this point the executable is
- *  committed to being defined or a segmentation violation will occur.
- */
-       if (lib_ok) {
-#ifdef COFF_DEBUG
-           printk ("flushing executable\n");
-#endif
-           flush_old_exec (bprm);
-/*
- *  Define the initial locations for the various items in the new process
- */
-           current->mm->mmap        = NULL;
-           current->mm->rss         = 0;
-/*
- *  Construct the parameter and environment string table entries.
- */
-           bprm->p += change_ldt (0, bprm->page);
-           bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
-           bprm->p  = (unsigned long) create_tables ((char *) bprm->p,
-                                                     bprm->argc,
-                                                     bprm->envc,
-                                                     1);
-/*
- *  Do the end processing once the stack has been constructed
- */
-           current->mm->start_code  = text_vaddr & PAGE_MASK;
-           current->mm->end_code    = text_vaddr + text_size;
-           current->mm->end_data    = data_vaddr + data_size;
-           current->mm->start_brk   =
-           current->mm->brk         = bss_vaddr + bss_size;
-           current->suid            =
-           current->euid            = bprm->e_uid;
-           current->sgid            =
-           current->egid            = bprm->e_gid;
-           current->executable      = bprm->inode; /* Store inode for file  */
-           ++bprm->inode->i_count;             /* Count the open inode  */
-           regs->eip                = start_addr;  /* Current EIP register  */
-           regs->esp                =
-           current->mm->start_stack = bprm->p;
-       }
-/*
- *   Map the text pages
- */
-
-#ifdef COFF_DEBUG
-       printk (".text: vaddr = %d, size = %d, scnptr = %d\n",
-                text_vaddr,
-                text_size,
-                text_scnptr);
-#endif
-       status = do_mmap (fp,
-                         text_vaddr & PAGE_MASK,
-                         text_size + (text_vaddr & ~PAGE_MASK),
-                         PROT_READ | PROT_EXEC,
-                         MAP_FIXED | MAP_SHARED,
-                         text_scnptr & PAGE_MASK);
-
-       status = (status == (text_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
-/*
- *   Map the data pages
- */
-       if (status >= 0 && data_size != 0) {
-#ifdef COFF_DEBUG
-           printk (".data: vaddr = %d, size = %d, scnptr = %d\n",
-                    data_vaddr,
-                    data_size,
-                    data_scnptr);
-#endif
-           status = do_mmap (fp,
-                             data_vaddr & PAGE_MASK,
-                             data_size + (data_vaddr & ~PAGE_MASK),
-                             PROT_READ | PROT_WRITE | PROT_EXEC,
-                             MAP_FIXED | MAP_PRIVATE,
-                             data_scnptr & PAGE_MASK);
-
-           status = (status == (data_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
-       }
-/*
- *   Construct the bss data for the process. The bss ranges from the
- *   end of the data (which may not be on a page boundary) to the end
- *   of the bss section. Allocate any necessary pages for the data.
- */
-       if (status >= 0 && bss_size != 0) {
-#ifdef COFF_DEBUG
-           printk (".bss: vaddr = %d, size = %d\n",
-                    bss_vaddr,
-                    bss_size);
-#endif
-           zeromap_page_range (PAGE_ALIGN (bss_vaddr),
-                               PAGE_ALIGN (bss_size),
-                               PAGE_COPY);
-
-           status = clear_memory (bss_vaddr, bss_size);
-       }
-/*
- *  Load any shared library for the executable.
- */
-       if (status >= 0 && lib_ok && lib_count != 0) {
-           int nIndex;
-           COFF_SCNHDR *sect_ptr = sect_bufr;
-/*
- *  Find the library sections. (There should be at least one. It was counted
- *  earlier.) This will eventually recurse to our code and load the shared
- *  library with our own procedures.
- */
-           for (nIndex = 0; nIndex < sections; ++nIndex) {
-               long int sect_flags = COFF_LONG (sect_ptr->s_flags);
-               if (sect_flags == COFF_STYP_LIB) {
-                   status = preload_library (bprm, sect_ptr, fp);
-                   if (status != 0)
-                       break;
-               }
-           sect_ptr = (COFF_SCNHDR *) &((char *) sect_ptr) [COFF_SCNHSZ];
-           }
-       }
-/*
- *   Generate any needed trap for this process. If an error occurred then
- *   generate a segmentation violation. If the process is being debugged
- *   then generate the load trap. (Note: If this is a library load then
- *   do not generate the trap here. Pass the error to the caller who
- *   will do it for the process in the outer lay of this procedure call.)
- */
-       if (lib_ok) {
-           if (status < 0)
-               send_sig (SIGSEGV, current, 0); /* Generate the error trap  */
-           else {
-               if (current->flags & PF_PTRACED)
-                   send_sig (SIGTRAP, current, 0);
-           }
-           status = 0;         /* We are committed. It can't fail */
-       }
-    }
-/*
- *  Do any cleanup processing
- */
-    if (fd >= 0)
-       sys_close (fd);         /* Close unused code file      */
-
-    if (sect_bufr != NULL)
-       kfree (sect_bufr);      /* Release section list buffer */
-/*
- *  Return the completion status.
- */
-#ifdef COFF_DEBUG
-    printk ("binfmt_coff: result = %d\n", status);
-#endif
-    return (status);
-}
-
-/*
- *  This procedure will load the library listed in the file name given
- *  as the parameter. The result will be non-zero should something fail
- *  to load.
- */
-
-static int
-preload_this_library (struct linux_binprm *exe_bprm, char *lib_name)
-{
-    int   status;
-    int   old_fs = get_fs();
-/*
- *  If debugging then print "we have arrived"
- */
-#ifdef COFF_DEBUG
-    printk ("%s loading shared library %s\n",
-           exe_bprm->filename,
-           lib_name);
-#endif
-/*
- *  Change the FS register to the proper kernel address space and attempt
- *  to load the library. The library name is allocated from the kernel
- *  pool.
- */
-    set_fs (get_ds ());
-    status = sys_uselib (lib_name);
-    set_fs (old_fs);
-/*
- *  Return the success/failure to the caller.
- */
-    return (status);
-}
-
-/*
- *  This procedure is called to load a library section. The various
- *  libraries are loaded from the list given in the section data.
- */
-
-static int
-preload_library (struct linux_binprm *exe_bprm,
-                COFF_SCNHDR * sect, struct file *fp)
-{
-    int status = 0;            /* Completion status                  */
-    long nbytes;               /* Count of bytes in the header area  */
-/*
- *  Fetch the size of the section. There must be enough room for at least
- *  one entry.
- */
-    nbytes = COFF_LONG (sect->s_size);
-    if (nbytes < COFF_SLIBSZ) {
-       status = -ENOEXEC;
-#ifdef COFF_DEBUG
-       printk ("library section too small\n");
-#endif
-    }
-/*
- *  Allocate a buffer to hold the section data
- */
-    else {
-       COFF_SLIBHD *phdr;
-       char *buffer = (char *) kmalloc (nbytes, GFP_KERNEL);
-
-        if (0 == buffer) {
-           status = -ENOEXEC;
-#ifdef COFF_DEBUG
-           printk ("kmalloc failed\n");
-#endif
-       }
-       else {
-           int old_fs   = get_fs ();
-/*
- *  Read the section data from the disk file.
- */
-           set_fs (get_ds ());   /* Make it point to the proper location    */
-           status = read_exec (exe_bprm->inode,     /* INODE for file       */
-                           COFF_LONG (sect->s_scnptr), /* Disk location     */
-                           buffer,                     /* Buffer for read   */
-                           nbytes);                    /* Byte count reqd.  */
-           set_fs (old_fs);                         /* Restore the selector */
-/*
- *  Check the result. The value returned is the byte count actually read.
- */
-           if (status >= 0 && status != nbytes) {
-#ifdef COFF_DEBUG
-               printk ("read of lib section was short\n");
-#endif
-               status = -ENOEXEC;
-           }
-       }
-/*
- *  At this point, go through the list of libraries in the data area.
- */
-       phdr = (COFF_SLIBHD *) buffer;
-       while (status >= 0 && nbytes > COFF_SLIBSZ) {
-           int entry_size  = COFF_LONG (phdr->sl_entsz)   * sizeof (long);
-           int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
-/*
- *  Validate the sizes of the various items. I don't trust the linker!!
- */
-           if ((unsigned) header_size >= (unsigned) nbytes ||
-               entry_size <= 0 ||
-               (unsigned) entry_size <= (unsigned) header_size) {
-               status = -ENOEXEC;
-#ifdef COFF_DEBUG
-               printk ("header count is invalid\n");
-#endif
-           }
-/*
- *  Load the library. Stop the load process on the first error.
- */
-           else {
-               status = preload_this_library (exe_bprm,
-                                              &((char *) phdr)[header_size]);
-#ifdef COFF_DEBUG
-               printk ("preload_this_library result = %d\n", status);
-#endif
-           }
-/*
- *  Point to the next library in the section data.
- */
-           nbytes -= entry_size;
-           phdr = (COFF_SLIBHD *) &((char *) phdr)[entry_size];
-       }
-/*
- *  Release the space for the library list.
- */
-       if (buffer != NULL)
-           kfree (buffer);
-    }
-/*
- *  Return the resulting status to the caller.
- */
-    return (status);
-}
-
-/*
- *  This procedure is called by the main load sequence. It will load
- *  the executable and prepare it for execution. It provides the additional
- *  parameters used by the recursive coff loader and tells the loader that
- *  this is the main executable. How simple it is . . . .
- */
-
-int
-load_coff_binary (struct linux_binprm *bprm, struct pt_regs *regs)
-{
-    return (load_object (bprm, regs, 1));
-}
-
-/*
- *   Load the image for any shared library.
- *
- *   This is called when we need to load a library based upon a file name.
- */
-
-int
-load_coff_library (int fd)
-{
-    struct linux_binprm *bprm;  /* Parameters for the load operation   */
-    int    status;              /* Status of the request               */
-/*
- *  Read the first portion of the file.
- */
-    bprm = (struct linux_binprm *) kmalloc (sizeof (struct linux_binprm),
-                                           GFP_KERNEL);
-    if (0 == bprm) {
-#ifdef COFF_DEBUG
-       printk ("kmalloc failed\n");
-#endif
-        status = -ENOEXEC;
-    }
-    else {
-        struct file         *file;  /* Pointer to the file table           */
-        struct pt_regs       regs;  /* Register work area                  */
-        int old_fs = get_fs ();     /* Previous FS register value          */
-
-        memset (bprm, '\0', sizeof (struct linux_binprm));
-
-       file           = current->files->fd[fd];
-       bprm->inode    = file->f_inode;   /* The only item _really_ needed */
-       bprm->filename = "";              /* Make it a legal string        */
-/*
- *  Read the section list from the disk file.
- */
-       set_fs (get_ds ());   /* Make it point to the proper location    */
-       status = read_exec (bprm->inode,         /* INODE for file       */
-                           0L,                  /* Offset in the file   */
-                           bprm->buf,           /* Buffer for read      */
-                           sizeof (bprm->buf)); /* Size of the buffer   */
-       set_fs (old_fs);                         /* Restore the selector */
-/*
- *  Try to load the library.
- */
-       status = load_object (bprm, &regs, 0);
-/*
- *  Release the work buffer and return the result.
- */
-       kfree (bprm);                 /* Release the buffer area */
-    }
-/*
- *  Return the result of the load operation
- */
-    return (status);
-}
diff --git a/arch/i386/ibcs/binfmt_elf.c b/arch/i386/ibcs/binfmt_elf.c
deleted file mode 100644 (file)
index d386342..0000000
+++ /dev/null
@@ -1,655 +0,0 @@
-/*
- * linux/fs/binfmt_elf.c
- *
- * These are the functions used to load ELF format executables as used
- * on SVr4 machines.  Information on the format may be found in the book
- * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
- * Tools".
- *
- * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
- */
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/shm.h>
-#include <linux/personality.h>
-
-#include <asm/segment.h>
-
-asmlinkage int sys_exit(int exit_code);
-asmlinkage int sys_close(unsigned fd);
-asmlinkage int sys_open(const char *, int, int);
-asmlinkage int sys_brk(unsigned long);
-
-#define DLINFO_ITEMS 8
-
-#include <linux/elf.h>
-
-/* We need to explicitly zero any fractional pages
-   after the data section (i.e. bss).  This would
-   contain the junk from the file that should not
-   be in memory */
-
-static void padzero(int elf_bss){
-  unsigned int fpnt, nbyte;
-  
-  if(elf_bss & 0xfff) {
-    
-    nbyte = (PAGE_SIZE - (elf_bss & 0xfff)) & 0xfff;
-    if(nbyte){
-      verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
-      
-      fpnt = elf_bss;
-      while(fpnt & 0xfff) put_fs_byte(0, fpnt++);
-    };
-  };
-}
-
-unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs)
-{
-       unsigned long *argv,*envp, *dlinfo;
-       unsigned long * sp;
-       struct vm_area_struct *mpnt;
-
-       mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
-       if (mpnt) {
-               mpnt->vm_task = current;
-               mpnt->vm_start = PAGE_MASK & (unsigned long) p;
-               mpnt->vm_end = TASK_SIZE;
-               mpnt->vm_page_prot = PAGE_COPY;
-               mpnt->vm_flags = VM_STACK_FLAGS;
-               mpnt->vm_ops = NULL;
-               mpnt->vm_inode = NULL;
-               mpnt->vm_offset = 0;
-               mpnt->vm_pte = 0;
-               insert_vm_struct(current, mpnt);
-       }
-       sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
-       if(exec) sp -= DLINFO_ITEMS*2;
-       dlinfo = sp;
-       sp -= envc+1;
-       envp = sp;
-       sp -= argc+1;
-       argv = sp;
-       if (!ibcs) {
-               put_fs_long((unsigned long)envp,--sp);
-               put_fs_long((unsigned long)argv,--sp);
-       }
-
-       /* The constant numbers (0-9) that we are writing here are
-          described in the header file sys/auxv.h on at least
-          some versions of SVr4 */
-       if(exec) { /* Put this here for an ELF program interpreter */
-         struct elf_phdr * eppnt;
-         eppnt = (struct elf_phdr *) exec->e_phoff;
-         put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++);
-         put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
-         put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
-         put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
-         put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++);
-         put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
-         put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
-         put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
-       };
-
-       put_fs_long((unsigned long)argc,--sp);
-       current->mm->arg_start = (unsigned long) p;
-       while (argc-->0) {
-               put_fs_long((unsigned long) p,argv++);
-               while (get_fs_byte(p++)) /* nothing */ ;
-       }
-       put_fs_long(0,argv);
-       current->mm->arg_end = current->mm->env_start = (unsigned long) p;
-       while (envc-->0) {
-               put_fs_long((unsigned long) p,envp++);
-               while (get_fs_byte(p++)) /* nothing */ ;
-       }
-       put_fs_long(0,envp);
-       current->mm->env_end = (unsigned long) p;
-       return sp;
-}
-
-
-/* This is much more generalized than the library routine read function,
-   so we keep this separate.  Technically the library read function
-   is only provided so that we can read a.out libraries that have
-   an ELF header */
-
-static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
-                            struct inode * interpreter_inode)
-{
-        struct file * file;
-       struct elf_phdr *elf_phdata  =  NULL;
-       struct elf_phdr *eppnt;
-       unsigned int len;
-       unsigned int load_addr;
-       int elf_exec_fileno;
-       int elf_bss;
-       int old_fs, retval;
-       unsigned int last_bss;
-       int error;
-       int i, k;
-       
-       elf_bss = 0;
-       last_bss = 0;
-       error = load_addr = 0;
-       
-       /* First of all, some simple consistency checks */
-       if((interp_elf_ex->e_type != ET_EXEC && 
-           interp_elf_ex->e_type != ET_DYN) || 
-          (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) ||
-          (!interpreter_inode->i_op || 
-           !interpreter_inode->i_op->default_file_ops->mmap)){
-               return 0xffffffff;
-       };
-       
-       /* Now read in all of the header information */
-       
-       if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) 
-           return 0xffffffff;
-       
-       elf_phdata =  (struct elf_phdr *) 
-               kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL);
-       if(!elf_phdata) return 0xffffffff;
-       
-       old_fs = get_fs();
-       set_fs(get_ds());
-       retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata,
-                          sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-       set_fs(old_fs);
-       
-       elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
-       if (elf_exec_fileno < 0) return 0xffffffff;
-       file = current->files->fd[elf_exec_fileno];
-
-       eppnt = elf_phdata;
-       for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
-         if(eppnt->p_type == PT_LOAD) {
-           error = do_mmap(file, 
-                           eppnt->p_vaddr & 0xfffff000,
-                           eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
-                           PROT_READ | PROT_WRITE | PROT_EXEC,
-                           MAP_PRIVATE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0),
-                           eppnt->p_offset & 0xfffff000);
-           
-           if(!load_addr && interp_elf_ex->e_type == ET_DYN)
-             load_addr = error;
-           k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
-           if(k > elf_bss) elf_bss = k;
-           if(error < 0 && error > -1024) break;  /* Real error */
-           k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
-           if(k > last_bss) last_bss = k;
-         }
-       
-       /* Now use mmap to map the library into memory. */
-
-       
-       sys_close(elf_exec_fileno);
-       if(error < 0 && error > -1024) {
-               kfree(elf_phdata);
-               return 0xffffffff;
-       }
-
-       padzero(elf_bss);
-       len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */
-
-       /* Map the last of the bss segment */
-       if (last_bss > len)
-         do_mmap(NULL, len, last_bss-len,
-                 PROT_READ|PROT_WRITE|PROT_EXEC,
-                 MAP_FIXED|MAP_PRIVATE, 0);
-       kfree(elf_phdata);
-
-       return ((unsigned int) interp_elf_ex->e_entry) + load_addr;
-}
-
-static unsigned int load_aout_interp(struct exec * interp_ex,
-                            struct inode * interpreter_inode)
-{
-  int retval;
-  unsigned int elf_entry;
-  
-  current->mm->brk = interp_ex->a_bss +
-    (current->mm->end_data = interp_ex->a_data +
-     (current->mm->end_code = interp_ex->a_text));
-  elf_entry = interp_ex->a_entry;
-  
-  
-  if (N_MAGIC(*interp_ex) == OMAGIC) {
-    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
-           PROT_READ|PROT_WRITE|PROT_EXEC,
-           MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode, 32, (char *) 0, 
-                      interp_ex->a_text+interp_ex->a_data);
-  } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
-    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
-           PROT_READ|PROT_WRITE|PROT_EXEC,
-           MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode,
-                      N_TXTOFF(*interp_ex) ,
-                      (char *) N_TXTADDR(*interp_ex),
-                      interp_ex->a_text+interp_ex->a_data);
-  } else
-    retval = -1;
-  
-  if(retval >= 0)
-    do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) & 
-           0xfffff000, interp_ex->a_bss,
-           PROT_READ|PROT_WRITE|PROT_EXEC,
-           MAP_FIXED|MAP_PRIVATE, 0);
-  if(retval < 0) return 0xffffffff;
-  return elf_entry;
-}
-
-/*
- * These are the functions used to load ELF style executables and shared
- * libraries.  There is no binary dependent code anywhere else.
- */
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
-       struct elfhdr elf_ex;
-       struct elfhdr interp_elf_ex;
-       struct file * file;
-       struct exec interp_ex;
-       struct inode *interpreter_inode;
-       unsigned int load_addr;
-       unsigned int interpreter_type = INTERPRETER_NONE;
-       int i;
-       int old_fs;
-       int error;
-       struct elf_phdr * elf_ppnt, *elf_phdata;
-       int elf_exec_fileno;
-       unsigned int elf_bss, k, elf_brk;
-       int retval;
-       char * elf_interpreter;
-       unsigned int elf_entry;
-       int status;
-       unsigned int start_code, end_code, end_data;
-       unsigned int elf_stack;
-       char passed_fileno[6];
-       
-       status = 0;
-       load_addr = 0;
-       elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
-       
-       if (elf_ex.e_ident[0] != 0x7f ||
-           strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
-               return  -ENOEXEC;
-       
-       
-       /* First of all, some simple consistency checks */
-       if(elf_ex.e_type != ET_EXEC || 
-          (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
-          (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
-           !bprm->inode->i_op->default_file_ops->mmap)){
-               return -ENOEXEC;
-       };
-       
-       /* Now read in all of the header information */
-       
-       elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * 
-                                                elf_ex.e_phnum, GFP_KERNEL);
-       
-       old_fs = get_fs();
-       set_fs(get_ds());
-       retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
-                          elf_ex.e_phentsize * elf_ex.e_phnum);
-       set_fs(old_fs);
-       if (retval < 0) {
-               kfree (elf_phdata);
-               return retval;
-       }
-       
-       elf_ppnt = elf_phdata;
-       
-       elf_bss = 0;
-       elf_brk = 0;
-       
-       elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
-
-       if (elf_exec_fileno < 0) {
-               kfree (elf_phdata);
-               return elf_exec_fileno;
-       }
-       
-       file = current->files->fd[elf_exec_fileno];
-       
-       elf_stack = 0xffffffff;
-       elf_interpreter = NULL;
-       start_code = 0;
-       end_code = 0;
-       end_data = 0;
-       
-       old_fs = get_fs();
-       set_fs(get_ds());
-       
-       for(i=0;i < elf_ex.e_phnum; i++){
-               if(elf_ppnt->p_type == PT_INTERP) {
-                       /* This is the program interpreter used for shared libraries - 
-                          for now assume that this is an a.out format binary */
-                       
-                       elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, 
-                                                          GFP_KERNEL);
-                       
-                       retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
-                                          elf_ppnt->p_filesz);
-#if 0
-                       printk("Using ELF interpreter %s\n", elf_interpreter);
-#endif
-                       if(retval >= 0)
-                               retval = namei(elf_interpreter, &interpreter_inode);
-                       if(retval >= 0)
-                               retval = read_exec(interpreter_inode,0,bprm->buf,128);
-                       
-                       if(retval >= 0){
-                               interp_ex = *((struct exec *) bprm->buf);               /* exec-header */
-                               interp_elf_ex = *((struct elfhdr *) bprm->buf);   /* exec-header */
-                               
-                       };
-                       if(retval < 0) {
-                         kfree (elf_phdata);
-                         kfree(elf_interpreter);
-                         return retval;
-                       };
-               };
-               elf_ppnt++;
-       };
-       
-       set_fs(old_fs);
-       
-       /* Some simple consistency checks for the interpreter */
-       if(elf_interpreter){
-               interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-               if(retval < 0) {
-                       kfree(elf_interpreter);
-                       kfree(elf_phdata);
-                       return -ELIBACC;
-               };
-               /* Now figure out which format our binary is */
-               if((N_MAGIC(interp_ex) != OMAGIC) && 
-                  (N_MAGIC(interp_ex) != ZMAGIC) &&
-                  (N_MAGIC(interp_ex) != QMAGIC)) 
-                 interpreter_type = INTERPRETER_ELF;
-
-               if (interp_elf_ex.e_ident[0] != 0x7f ||
-                   strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
-                 interpreter_type &= ~INTERPRETER_ELF;
-
-               if(!interpreter_type)
-                 {
-                   kfree(elf_interpreter);
-                   kfree(elf_phdata);
-                   return -ELIBBAD;
-                 };
-       }
-       
-       /* OK, we are done with that, now set up the arg stuff,
-          and then start this sucker up */
-       
-       if (!bprm->sh_bang) {
-               char * passed_p;
-               
-               if(interpreter_type == INTERPRETER_AOUT) {
-                 sprintf(passed_fileno, "%d", elf_exec_fileno);
-                 passed_p = passed_fileno;
-               
-                 if(elf_interpreter) {
-                   bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
-                   bprm->argc++;
-                 };
-               };
-               if (!bprm->p) {
-                       if(elf_interpreter) {
-                             kfree(elf_interpreter);
-                       }
-                       kfree (elf_phdata);
-                       return -E2BIG;
-               }
-       }
-       
-       /* OK, This is the point of no return */
-       flush_old_exec(bprm);
-
-       current->mm->end_data = 0;
-       current->mm->end_code = 0;
-       current->mm->start_mmap = ELF_START_MMAP;
-       current->mm->mmap = NULL;
-       elf_entry = (unsigned int) elf_ex.e_entry;
-       
-       /* Do this so that we can load the interpreter, if need be.  We will
-          change some of these later */
-       current->mm->rss = 0;
-       bprm->p += change_ldt(0, bprm->page);
-       current->mm->start_stack = bprm->p;
-       
-       /* Now we do a little grungy work by mmaping the ELF image into
-          the correct location in memory.  At this point, we assume that
-          the image should be loaded at fixed address, not at a variable
-          address. */
-       
-       old_fs = get_fs();
-       set_fs(get_ds());
-       
-       elf_ppnt = elf_phdata;
-       for(i=0;i < elf_ex.e_phnum; i++){
-               
-               if(elf_ppnt->p_type == PT_INTERP) {
-                       /* Set these up so that we are able to load the interpreter */
-                 /* Now load the interpreter into user address space */
-                 set_fs(old_fs);
-
-                 if(interpreter_type & 1) elf_entry = 
-                   load_aout_interp(&interp_ex, interpreter_inode);
-
-                 if(interpreter_type & 2) elf_entry = 
-                   load_elf_interp(&interp_elf_ex, interpreter_inode);
-
-                 old_fs = get_fs();
-                 set_fs(get_ds());
-
-                 iput(interpreter_inode);
-                 kfree(elf_interpreter);
-                       
-                 if(elf_entry == 0xffffffff) { 
-                   printk("Unable to load interpreter\n");
-                   kfree(elf_phdata);
-                   send_sig(SIGSEGV, current, 0);
-                   return 0;
-                 };
-               };
-               
-               
-               if(elf_ppnt->p_type == PT_LOAD) {
-                       error = do_mmap(file,
-                                       elf_ppnt->p_vaddr & 0xfffff000,
-                                       elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff),
-                                       PROT_READ | PROT_WRITE | PROT_EXEC,
-                                       MAP_FIXED | MAP_PRIVATE,
-                                       elf_ppnt->p_offset & 0xfffff000);
-                       
-#ifdef LOW_ELF_STACK
-                       if((elf_ppnt->p_vaddr & 0xfffff000) < elf_stack) 
-                               elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
-#endif
-                       
-                       if(!load_addr) 
-                         load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
-                       k = elf_ppnt->p_vaddr;
-                       if(k > start_code) start_code = k;
-                       k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
-                       if(k > elf_bss) elf_bss = k;
-                       if((elf_ppnt->p_flags | PROT_WRITE) && end_code <  k)
-                               end_code = k; 
-                       if(end_data < k) end_data = k; 
-                       k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
-                       if(k > elf_brk) elf_brk = k;                 
-                     };
-               elf_ppnt++;
-       };
-       set_fs(old_fs);
-       
-       kfree(elf_phdata);
-       
-       if(interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
-
-               /* The following 3 lines need a little bit of work if we are loading
-          an iBCS2 binary.  We should initially load it this way, and if
-          we get a lcall7, then we should look to see if the iBCS2 execution
-          profile is present.  If it is, then switch to that, otherwise
-          bomb. */
-       current->personality = PER_LINUX;
-       current->lcall7 = no_lcall7;
-       current->signal_map = current->signal_invmap = ident_map;
-
-       current->executable = bprm->inode;
-       bprm->inode->i_count++;
-#ifdef LOW_ELF_STACK
-       current->start_stack = p = elf_stack - 4;
-#endif
-       bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
-       bprm->p = (unsigned long) 
-         create_elf_tables((char *)bprm->p,
-                       bprm->argc,
-                       bprm->envc,
-                       (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
-                       load_addr,    
-                       (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
-       if(interpreter_type == INTERPRETER_AOUT)
-         current->mm->arg_start += strlen(passed_fileno) + 1;
-       current->mm->start_brk = current->mm->brk = elf_brk;
-       current->mm->end_code = end_code;
-       current->mm->start_code = start_code;
-       current->mm->end_data = end_data;
-       current->mm->start_stack = bprm->p;
-       current->suid = current->euid = bprm->e_uid;
-       current->sgid = current->egid = bprm->e_gid;
-
-       /* Calling sys_brk effectively mmaps the pages that we need for the bss and break
-          sections */
-       current->mm->brk = (elf_bss + 0xfff) & 0xfffff000;
-       sys_brk((elf_brk + 0xfff) & 0xfffff000);
-
-       padzero(elf_bss);
-
-       /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
-          and some applications "depend" upon this behavior.
-          Since we do not have the power to recompile these, we
-          emulate the SVr4 behavior.  Sigh.  */
-       error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
-                       MAP_FIXED | MAP_PRIVATE, 0);
-
-       regs->eip = elf_entry;          /* eip, magic happens :-) */
-       regs->esp = bprm->p;                    /* stack pointer */
-       if (current->flags & PF_PTRACED)
-               send_sig(SIGTRAP, current, 0);
-       return 0;
-}
-
-/* This is really simpleminded and specialized - we are loading an
-   a.out library that is given an ELF header. */
-
-static int load_elf_library(int fd){
-        struct file * file;
-       struct elfhdr elf_ex;
-       struct elf_phdr *elf_phdata  =  NULL;
-       struct  inode * inode;
-       unsigned int len;
-       int elf_bss;
-       int old_fs, retval;
-       unsigned int bss;
-       int error;
-       int i,j, k;
-       
-       len = 0;
-       file = current->files->fd[fd];
-       inode = file->f_inode;
-       elf_bss = 0;
-       
-       set_fs(KERNEL_DS);
-       if (file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)) != sizeof(elf_ex)) {
-               sys_close(fd);
-               return -EACCES;
-       }
-       set_fs(USER_DS);
-       
-       if (elf_ex.e_ident[0] != 0x7f ||
-           strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
-               return -ENOEXEC;
-       
-       /* First of all, some simple consistency checks */
-       if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
-          (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
-          (!inode->i_op ||
-           !inode->i_op->default_file_ops->mmap)){
-               return -ENOEXEC;
-       };
-       
-       /* Now read in all of the header information */
-       
-       if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) 
-               return -ENOEXEC;
-       
-       elf_phdata =  (struct elf_phdr *) 
-               kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
-       
-       old_fs = get_fs();
-       set_fs(get_ds());
-       retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
-                          sizeof(struct elf_phdr) * elf_ex.e_phnum);
-       set_fs(old_fs);
-       
-       j = 0;
-       for(i=0; i<elf_ex.e_phnum; i++)
-               if((elf_phdata + i)->p_type == PT_LOAD) j++;
-       
-       if(j != 1)  {
-               kfree(elf_phdata);
-               return -ENOEXEC;
-       };
-       
-       while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-       
-       /* Now use mmap to map the library into memory. */
-       error = do_mmap(file,
-                       elf_phdata->p_vaddr & 0xfffff000,
-                       elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
-                       PROT_READ | PROT_WRITE | PROT_EXEC,
-                       MAP_FIXED | MAP_PRIVATE,
-                       elf_phdata->p_offset & 0xfffff000);
-
-       k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
-       if(k > elf_bss) elf_bss = k;
-       
-       sys_close(fd);
-       if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
-               kfree(elf_phdata);
-               return error;
-       }
-
-       padzero(elf_bss);
-
-       len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
-       bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
-       if (bss > len)
-         do_mmap(NULL, len, bss-len,
-                 PROT_READ|PROT_WRITE|PROT_EXEC,
-                 MAP_FIXED|MAP_PRIVATE, 0);
-       kfree(elf_phdata);
-       return 0;
-}
-
-struct linux_binfmt elf_format = { NULL, load_elf_binary, load_elf_library };
diff --git a/arch/i386/ibcs/emulate.c b/arch/i386/ibcs/emulate.c
deleted file mode 100644 (file)
index dc3b3d5..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- *  linux/abi/emulate.c
- *
- *  Copyright (C) 1993  Linus Torvalds
- */
-
-/*
- * Yes, sir, this file is completely empty, waiting for some real code..
- * I still copyright it, silly me.
- */
index 58b983c4a3db0a2420ef04fce922c9e6a721fb70..068f36ff5adcec584a2450a7528538188793a0cd 100644 (file)
@@ -13,8 +13,8 @@
        $(AS) -o $*.o $<
 .c.o:
        $(CC) $(CFLAGS) -c $<
-.S.s:
-       $(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
+#.S.s:
+#      $(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
 .S.o:
        $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
@@ -23,10 +23,11 @@ OBJS  = process.o signal.o entry.o traps.o irq.o vm86.o bios32.o ptrace.o \
 
 all: kernel.o head.o
 
-head.o: head.s
+#head.o: head.s
 
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
-       $(CPP) -traditional -o $*.s $<
+head.o: head.S $(TOPDIR)/include/linux/tasks.h
+       $(CC) -D__ASSEMBLY__ -traditional -c $*.S -o $*.o
+#      $(CPP) -traditional -o $*.s $<
 
 kernel.o: $(OBJS)
        $(LD) -r -o kernel.o $(OBJS)
index a700c6ec674791ecb0d6602f886bf2fe0b06e044..bd64d74ba9b968e321d7abcf6f8b2ddd6dad0140 100644 (file)
@@ -41,6 +41,7 @@
  */
 
 #include <linux/sys.h>
+#include <linux/linkage.h>
 #include <asm/segment.h>
 
 EBX            = 0x00
@@ -82,15 +83,6 @@ exec_domain  = 60
 
 ENOSYS = 38
 
-.globl _system_call,_lcall7
-.globl _device_not_available, _coprocessor_error
-.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
-.globl _double_fault,_coprocessor_segment_overrun
-.globl _invalid_TSS,_segment_not_present,_stack_segment
-.globl _general_protection,_reserved
-.globl _alignment_check,_page_fault
-.globl ret_from_sys_call, _sys_call_table
-
 #define SAVE_ALL \
        cld; \
        push %gs; \
@@ -113,7 +105,7 @@ ENOSYS = 38
 #define RESTORE_ALL \
        cmpw $(KERNEL_CS),CS(%esp); \
        je 1f;   \
-       movl _current,%eax; \
+       movl SYMBOL_NAME(current),%eax; \
        movl dbgreg7(%eax),%ebx; \
        movl %ebx,%db7; \
 1:     popl %ebx; \
@@ -130,8 +122,7 @@ ENOSYS = 38
        addl $4,%esp; \
        iret
 
-.align 4
-_lcall7:
+ENTRY(lcall7)
        pushfl                  # We get a different stack layout with call gates,
        pushl %eax              # which has to be cleaned up later..
        SAVE_ALL
@@ -142,7 +133,7 @@ _lcall7:
        movl %edx,EIP(%esp)     # Now we move them to their "normal" places
        movl %ecx,CS(%esp)      #
        movl %esp,%eax
-       movl _current,%edx
+       movl SYMBOL_NAME(current),%edx
        pushl %eax
        movl exec_domain(%edx),%edx     # Get the execution domain
        movl 4(%edx),%edx       # Get the lcall7 handler for the domain
@@ -150,30 +141,30 @@ _lcall7:
        popl %eax
        jmp ret_from_sys_call
 
-.align 4
+       ALIGN
 handle_bottom_half:
        pushfl
-       incl _intr_count
+       incl SYMBOL_NAME(intr_count)
        sti
-       call _do_bottom_half
+       call SYMBOL_NAME(do_bottom_half)
        popfl
-       decl _intr_count
+       decl SYMBOL_NAME(intr_count)
        jmp 9f
-.align 4
+       ALIGN
 reschedule:
        pushl $ret_from_sys_call
-       jmp _schedule
-.align 4
-_system_call:
+       jmp SYMBOL_NAME(schedule)
+
+ENTRY(system_call)
        pushl %eax                      # save orig_eax
        SAVE_ALL
        movl $-ENOSYS,EAX(%esp)
        cmpl $(NR_syscalls),%eax
        jae ret_from_sys_call
-       movl _sys_call_table(,%eax,4),%eax
+       movl SYMBOL_NAME(sys_call_table)(,%eax,4),%eax
        testl %eax,%eax
        je ret_from_sys_call
-       movl _current,%ebx
+       movl SYMBOL_NAME(current),%ebx
        andl $~CF_MASK,EFLAGS(%esp)     # clear carry - assume no errors
        movl $0,errno(%ebx)
        movl %db6,%edx
@@ -188,25 +179,26 @@ _system_call:
        movl %edx,EAX(%esp)
        orl $(CF_MASK),EFLAGS(%esp)     # set carry to indicate error
        jmp ret_from_sys_call
-.align 4
-1:     call _syscall_trace
+       ALIGN
+1:     call SYMBOL_NAME(syscall_trace)
        movl ORIG_EAX(%esp),%eax
-       call _sys_call_table(,%eax,4)
+       call SYMBOL_NAME(sys_call_table)(,%eax,4)
        movl %eax,EAX(%esp)             # save the return value
-       movl _current,%eax
+       movl SYMBOL_NAME(current),%eax
        movl errno(%eax),%edx
        negl %edx
        je 1f
        movl %edx,EAX(%esp)
        orl $(CF_MASK),EFLAGS(%esp)     # set carry to indicate error
-1:     call _syscall_trace
+1:     call SYMBOL_NAME(syscall_trace)
 
-       .align 4,0x90
+       ALIGN
+       .globl ret_from_sys_call
 ret_from_sys_call:
-       cmpl $0,_intr_count
+       cmpl $0,SYMBOL_NAME(intr_count)
        jne 2f
-9:     movl _bh_mask,%eax
-       andl _bh_active,%eax
+9:     movl SYMBOL_NAME(bh_mask),%eax
+       andl SYMBOL_NAME(bh_active),%eax
        jne handle_bottom_half
        movl EFLAGS(%esp),%eax          # check VM86 flag: CS/SS are
        testl $(VM_MASK),%eax           # different then
@@ -217,10 +209,10 @@ ret_from_sys_call:
        orl $(IF_MASK),%eax             # these just try to make sure
        andl $~NT_MASK,%eax             # the program doesn't do anything
        movl %eax,EFLAGS(%esp)          # stupid
-       cmpl $0,_need_resched
+       cmpl $0,SYMBOL_NAME(need_resched)
        jne reschedule
-       movl _current,%eax
-       cmpl _task,%eax                 # task[0] cannot have signals
+       movl SYMBOL_NAME(current),%eax
+       cmpl SYMBOL_NAME(task),%eax     # task[0] cannot have signals
        je 2f
        cmpl $0,state(%eax)             # state
        jne reschedule
@@ -232,33 +224,32 @@ ret_from_sys_call:
        andl signal(%eax),%ecx
        jne signal_return
 2:     RESTORE_ALL
-.align 4
+       ALIGN
 signal_return:
        movl %esp,%ecx
        pushl %ecx
        testl $(VM_MASK),EFLAGS(%ecx)
        jne v86_signal_return
        pushl %ebx
-       call _do_signal
+       call SYMBOL_NAME(do_signal)
        popl %ebx
        popl %ebx
        RESTORE_ALL
-.align 4
+       ALIGN
 v86_signal_return:
-       call _save_v86_state
+       call SYMBOL_NAME(save_v86_state)
        movl %eax,%esp
        pushl %eax
        pushl %ebx
-       call _do_signal
+       call SYMBOL_NAME(do_signal)
        popl %ebx
        popl %ebx
        RESTORE_ALL
 
-.align 4
-_divide_error:
+ENTRY(divide_error)
        pushl $0                # no error code
-       pushl $_do_divide_error
-.align 4,0x90
+       pushl $ SYMBOL_NAME(do_divide_error)
+       ALIGN
 error_code:
        push %fs
        push %es
@@ -287,7 +278,7 @@ error_code:
        movl $(USER_DS),%edx
        mov %dx,%fs
        pushl %eax
-       movl _current,%eax
+       movl SYMBOL_NAME(current),%eax
        movl %db6,%edx
        movl %edx,dbgreg6(%eax)  # save current hardware debugging status
        popl %eax
@@ -295,253 +286,235 @@ error_code:
        addl $8,%esp
        jmp ret_from_sys_call
 
-.align 4
-_coprocessor_error:
+ENTRY(coprocessor_error)
        pushl $0
-       pushl $_do_coprocessor_error
+       pushl $ SYMBOL_NAME(do_coprocessor_error)
        jmp error_code
 
-.align 4
-_device_not_available:
+ENTRY(device_not_available)
        pushl $-1               # mark this as an int
        SAVE_ALL
        pushl $ret_from_sys_call
        movl %cr0,%eax
        testl $0x4,%eax                 # EM (math emulation bit)
-       je _math_state_restore
+       je SYMBOL_NAME(math_state_restore)
        pushl $0                # temporary storage for ORIG_EIP
-       call _math_emulate
+       call  SYMBOL_NAME(math_emulate)
        addl $4,%esp
        ret
 
-.align 4
-_debug:
+ENTRY(debug)
        pushl $0
-       pushl $_do_debug
+       pushl $ SYMBOL_NAME(do_debug)
        jmp error_code
 
-.align 4
-_nmi:
+ENTRY(nmi)
        pushl $0
-       pushl $_do_nmi
+       pushl $ SYMBOL_NAME(do_nmi)
        jmp error_code
 
-.align 4
-_int3:
+ENTRY(int3)
        pushl $0
-       pushl $_do_int3
+       pushl $ SYMBOL_NAME(do_int3)
        jmp error_code
 
-.align 4
-_overflow:
+ENTRY(overflow)
        pushl $0
-       pushl $_do_overflow
+       pushl $ SYMBOL_NAME(do_overflow)
        jmp error_code
 
-.align 4
-_bounds:
+ENTRY(bounds)
        pushl $0
-       pushl $_do_bounds
+       pushl $ SYMBOL_NAME(do_bounds)
        jmp error_code
 
-.align 4
-_invalid_op:
+ENTRY(invalid_op)
        pushl $0
-       pushl $_do_invalid_op
+       pushl $ SYMBOL_NAME(do_invalid_op)
        jmp error_code
 
-.align 4
-_coprocessor_segment_overrun:
+ENTRY(coprocessor_segment_overrun)
        pushl $0
-       pushl $_do_coprocessor_segment_overrun
+       pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
        jmp error_code
 
-.align 4
-_reserved:
+ENTRY(reserved)
        pushl $0
-       pushl $_do_reserved
+       pushl $ SYMBOL_NAME(do_reserved)
        jmp error_code
 
-.align 4
-_double_fault:
-       pushl $_do_double_fault
+ENTRY(double_fault)
+       pushl $ SYMBOL_NAME(do_double_fault)
        jmp error_code
 
-.align 4
-_invalid_TSS:
-       pushl $_do_invalid_TSS
+ENTRY(invalid_TSS)
+       pushl $ SYMBOL_NAME(do_invalid_TSS)
        jmp error_code
 
-.align 4
-_segment_not_present:
-       pushl $_do_segment_not_present
+ENTRY(segment_not_present)
+       pushl $ SYMBOL_NAME(do_segment_not_present)
        jmp error_code
 
-.align 4
-_stack_segment:
-       pushl $_do_stack_segment
+ENTRY(stack_segment)
+       pushl $ SYMBOL_NAME(do_stack_segment)
        jmp error_code
 
-.align 4
-_general_protection:
-       pushl $_do_general_protection
+ENTRY(general_protection)
+       pushl $ SYMBOL_NAME(do_general_protection)
        jmp error_code
 
-.align 4
-_alignment_check:
-       pushl $_do_alignment_check
+ENTRY(alignment_check)
+       pushl $ SYMBOL_NAME(do_alignment_check)
        jmp error_code
 
-.align 4
-_page_fault:
-       pushl $_do_page_fault
+ENTRY(page_fault)
+       pushl $ SYMBOL_NAME(do_page_fault)
        jmp error_code
 
 .data
-.align 4
-_sys_call_table:
-       .long _sys_setup                /* 0 */
-       .long _sys_exit
-       .long _sys_fork
-       .long _sys_read
-       .long _sys_write
-       .long _sys_open                 /* 5 */
-       .long _sys_close
-       .long _sys_waitpid
-       .long _sys_creat
-       .long _sys_link
-       .long _sys_unlink               /* 10 */
-       .long _sys_execve
-       .long _sys_chdir
-       .long _sys_time
-       .long _sys_mknod
-       .long _sys_chmod                /* 15 */
-       .long _sys_chown
-       .long _sys_break
-       .long _sys_stat
-       .long _sys_lseek
-       .long _sys_getpid               /* 20 */
-       .long _sys_mount
-       .long _sys_umount
-       .long _sys_setuid
-       .long _sys_getuid
-       .long _sys_stime                /* 25 */
-       .long _sys_ptrace
-       .long _sys_alarm
-       .long _sys_fstat
-       .long _sys_pause
-       .long _sys_utime                /* 30 */
-       .long _sys_stty
-       .long _sys_gtty
-       .long _sys_access
-       .long _sys_nice
-       .long _sys_ftime                /* 35 */
-       .long _sys_sync
-       .long _sys_kill
-       .long _sys_rename
-       .long _sys_mkdir
-       .long _sys_rmdir                /* 40 */
-       .long _sys_dup
-       .long _sys_pipe
-       .long _sys_times
-       .long _sys_prof
-       .long _sys_brk                  /* 45 */
-       .long _sys_setgid
-       .long _sys_getgid
-       .long _sys_signal
-       .long _sys_geteuid
-       .long _sys_getegid              /* 50 */
-       .long _sys_acct
-       .long _sys_phys
-       .long _sys_lock
-       .long _sys_ioctl
-       .long _sys_fcntl                /* 55 */
-       .long _sys_mpx
-       .long _sys_setpgid
-       .long _sys_ulimit
-       .long _sys_olduname
-       .long _sys_umask                /* 60 */
-       .long _sys_chroot
-       .long _sys_ustat
-       .long _sys_dup2
-       .long _sys_getppid
-       .long _sys_getpgrp              /* 65 */
-       .long _sys_setsid
-       .long _sys_sigaction
-       .long _sys_sgetmask
-       .long _sys_ssetmask
-       .long _sys_setreuid             /* 70 */
-       .long _sys_setregid
-       .long _sys_sigsuspend
-       .long _sys_sigpending
-       .long _sys_sethostname
-       .long _sys_setrlimit            /* 75 */
-       .long _sys_getrlimit
-       .long _sys_getrusage
-       .long _sys_gettimeofday
-       .long _sys_settimeofday
-       .long _sys_getgroups            /* 80 */
-       .long _sys_setgroups
-       .long _old_select
-       .long _sys_symlink
-       .long _sys_lstat
-       .long _sys_readlink             /* 85 */
-       .long _sys_uselib
-       .long _sys_swapon
-       .long _sys_reboot
-       .long _old_readdir
-       .long _old_mmap                 /* 90 */
-       .long _sys_munmap
-       .long _sys_truncate
-       .long _sys_ftruncate
-       .long _sys_fchmod
-       .long _sys_fchown               /* 95 */
-       .long _sys_getpriority
-       .long _sys_setpriority
-       .long _sys_profil
-       .long _sys_statfs
-       .long _sys_fstatfs              /* 100 */
-       .long _sys_ioperm
-       .long _sys_socketcall
-       .long _sys_syslog
-       .long _sys_setitimer
-       .long _sys_getitimer            /* 105 */
-       .long _sys_newstat
-       .long _sys_newlstat
-       .long _sys_newfstat
-       .long _sys_uname
-       .long _sys_iopl                 /* 110 */
-       .long _sys_vhangup
-       .long _sys_idle
-       .long _sys_vm86
-       .long _sys_wait4
-       .long _sys_swapoff              /* 115 */
-       .long _sys_sysinfo
-       .long _sys_ipc
-       .long _sys_fsync
-       .long _sys_sigreturn
-       .long _sys_clone                /* 120 */
-       .long _sys_setdomainname
-       .long _sys_newuname
-       .long _sys_modify_ldt
-       .long _sys_adjtimex
-       .long _sys_mprotect             /* 125 */
-       .long _sys_sigprocmask
-       .long _sys_create_module
-       .long _sys_init_module
-       .long _sys_delete_module
-       .long _sys_get_kernel_syms      /* 130 */
-       .long _sys_quotactl
-       .long _sys_getpgid
-       .long _sys_fchdir
-       .long _sys_bdflush
-       .long _sys_sysfs                /* 135 */
-       .long _sys_personality
-       .long 0                         /* for afs_syscall */
-       .long _sys_setfsuid
-       .long _sys_setfsgid
-       .long _sys_llseek               /* 140 */
-       .long _sys_getdents
-       .long _sys_select
-       .long _sys_flock
+ENTRY(sys_call_table)
+       .long SYMBOL_NAME(sys_setup)            /* 0 */
+       .long SYMBOL_NAME(sys_exit)
+       .long SYMBOL_NAME(sys_fork)
+       .long SYMBOL_NAME(sys_read)
+       .long SYMBOL_NAME(sys_write)
+       .long SYMBOL_NAME(sys_open)             /* 5 */
+       .long SYMBOL_NAME(sys_close)
+       .long SYMBOL_NAME(sys_waitpid)
+       .long SYMBOL_NAME(sys_creat)
+       .long SYMBOL_NAME(sys_link)
+       .long SYMBOL_NAME(sys_unlink)           /* 10 */
+       .long SYMBOL_NAME(sys_execve)
+       .long SYMBOL_NAME(sys_chdir)
+       .long SYMBOL_NAME(sys_time)
+       .long SYMBOL_NAME(sys_mknod)
+       .long SYMBOL_NAME(sys_chmod)            /* 15 */
+       .long SYMBOL_NAME(sys_chown)
+       .long SYMBOL_NAME(sys_break)
+       .long SYMBOL_NAME(sys_stat)
+       .long SYMBOL_NAME(sys_lseek)
+       .long SYMBOL_NAME(sys_getpid)           /* 20 */
+       .long SYMBOL_NAME(sys_mount)
+       .long SYMBOL_NAME(sys_umount)
+       .long SYMBOL_NAME(sys_setuid)
+       .long SYMBOL_NAME(sys_getuid)
+       .long SYMBOL_NAME(sys_stime)            /* 25 */
+       .long SYMBOL_NAME(sys_ptrace)
+       .long SYMBOL_NAME(sys_alarm)
+       .long SYMBOL_NAME(sys_fstat)
+       .long SYMBOL_NAME(sys_pause)
+       .long SYMBOL_NAME(sys_utime)            /* 30 */
+       .long SYMBOL_NAME(sys_stty)
+       .long SYMBOL_NAME(sys_gtty)
+       .long SYMBOL_NAME(sys_access)
+       .long SYMBOL_NAME(sys_nice)
+       .long SYMBOL_NAME(sys_ftime)            /* 35 */
+       .long SYMBOL_NAME(sys_sync)
+       .long SYMBOL_NAME(sys_kill)
+       .long SYMBOL_NAME(sys_rename)
+       .long SYMBOL_NAME(sys_mkdir)
+       .long SYMBOL_NAME(sys_rmdir)            /* 40 */
+       .long SYMBOL_NAME(sys_dup)
+       .long SYMBOL_NAME(sys_pipe)
+       .long SYMBOL_NAME(sys_times)
+       .long SYMBOL_NAME(sys_prof)
+       .long SYMBOL_NAME(sys_brk)              /* 45 */
+       .long SYMBOL_NAME(sys_setgid)
+       .long SYMBOL_NAME(sys_getgid)
+       .long SYMBOL_NAME(sys_signal)
+       .long SYMBOL_NAME(sys_geteuid)
+       .long SYMBOL_NAME(sys_getegid)          /* 50 */
+       .long SYMBOL_NAME(sys_acct)
+       .long SYMBOL_NAME(sys_phys)
+       .long SYMBOL_NAME(sys_lock)
+       .long SYMBOL_NAME(sys_ioctl)
+       .long SYMBOL_NAME(sys_fcntl)            /* 55 */
+       .long SYMBOL_NAME(sys_mpx)
+       .long SYMBOL_NAME(sys_setpgid)
+       .long SYMBOL_NAME(sys_ulimit)
+       .long SYMBOL_NAME(sys_olduname)
+       .long SYMBOL_NAME(sys_umask)            /* 60 */
+       .long SYMBOL_NAME(sys_chroot)
+       .long SYMBOL_NAME(sys_ustat)
+       .long SYMBOL_NAME(sys_dup2)
+       .long SYMBOL_NAME(sys_getppid)
+       .long SYMBOL_NAME(sys_getpgrp)          /* 65 */
+       .long SYMBOL_NAME(sys_setsid)
+       .long SYMBOL_NAME(sys_sigaction)
+       .long SYMBOL_NAME(sys_sgetmask)
+       .long SYMBOL_NAME(sys_ssetmask)
+       .long SYMBOL_NAME(sys_setreuid)         /* 70 */
+       .long SYMBOL_NAME(sys_setregid)
+       .long SYMBOL_NAME(sys_sigsuspend)
+       .long SYMBOL_NAME(sys_sigpending)
+       .long SYMBOL_NAME(sys_sethostname)
+       .long SYMBOL_NAME(sys_setrlimit)        /* 75 */
+       .long SYMBOL_NAME(sys_getrlimit)
+       .long SYMBOL_NAME(sys_getrusage)
+       .long SYMBOL_NAME(sys_gettimeofday)
+       .long SYMBOL_NAME(sys_settimeofday)
+       .long SYMBOL_NAME(sys_getgroups)        /* 80 */
+       .long SYMBOL_NAME(sys_setgroups)
+       .long SYMBOL_NAME(old_select)
+       .long SYMBOL_NAME(sys_symlink)
+       .long SYMBOL_NAME(sys_lstat)
+       .long SYMBOL_NAME(sys_readlink)         /* 85 */
+       .long SYMBOL_NAME(sys_uselib)
+       .long SYMBOL_NAME(sys_swapon)
+       .long SYMBOL_NAME(sys_reboot)
+       .long SYMBOL_NAME(old_readdir)
+       .long SYMBOL_NAME(old_mmap)             /* 90 */
+       .long SYMBOL_NAME(sys_munmap)
+       .long SYMBOL_NAME(sys_truncate)
+       .long SYMBOL_NAME(sys_ftruncate)
+       .long SYMBOL_NAME(sys_fchmod)
+       .long SYMBOL_NAME(sys_fchown)           /* 95 */
+       .long SYMBOL_NAME(sys_getpriority)
+       .long SYMBOL_NAME(sys_setpriority)
+       .long SYMBOL_NAME(sys_profil)
+       .long SYMBOL_NAME(sys_statfs)
+       .long SYMBOL_NAME(sys_fstatfs)          /* 100 */
+       .long SYMBOL_NAME(sys_ioperm)
+       .long SYMBOL_NAME(sys_socketcall)
+       .long SYMBOL_NAME(sys_syslog)
+       .long SYMBOL_NAME(sys_setitimer)
+       .long SYMBOL_NAME(sys_getitimer)        /* 105 */
+       .long SYMBOL_NAME(sys_newstat)
+       .long SYMBOL_NAME(sys_newlstat)
+       .long SYMBOL_NAME(sys_newfstat)
+       .long SYMBOL_NAME(sys_uname)
+       .long SYMBOL_NAME(sys_iopl)             /* 110 */
+       .long SYMBOL_NAME(sys_vhangup)
+       .long SYMBOL_NAME(sys_idle)
+       .long SYMBOL_NAME(sys_vm86)
+       .long SYMBOL_NAME(sys_wait4)
+       .long SYMBOL_NAME(sys_swapoff)          /* 115 */
+       .long SYMBOL_NAME(sys_sysinfo)
+       .long SYMBOL_NAME(sys_ipc)
+       .long SYMBOL_NAME(sys_fsync)
+       .long SYMBOL_NAME(sys_sigreturn)
+       .long SYMBOL_NAME(sys_clone)            /* 120 */
+       .long SYMBOL_NAME(sys_setdomainname)
+       .long SYMBOL_NAME(sys_newuname)
+       .long SYMBOL_NAME(sys_modify_ldt)
+       .long SYMBOL_NAME(sys_adjtimex)
+       .long SYMBOL_NAME(sys_mprotect)         /* 125 */
+       .long SYMBOL_NAME(sys_sigprocmask)
+       .long SYMBOL_NAME(sys_create_module)
+       .long SYMBOL_NAME(sys_init_module)
+       .long SYMBOL_NAME(sys_delete_module)
+       .long SYMBOL_NAME(sys_get_kernel_syms)  /* 130 */
+       .long SYMBOL_NAME(sys_quotactl)
+       .long SYMBOL_NAME(sys_getpgid)
+       .long SYMBOL_NAME(sys_fchdir)
+       .long SYMBOL_NAME(sys_bdflush)
+       .long SYMBOL_NAME(sys_sysfs)            /* 135 */
+       .long SYMBOL_NAME(sys_personality)
+       .long 0                                 /* for afs_syscall */
+       .long SYMBOL_NAME(sys_setfsuid)
+       .long SYMBOL_NAME(sys_setfsgid)
+       .long SYMBOL_NAME(sys_llseek)           /* 140 */
+       .long SYMBOL_NAME(sys_getdents)
+       .long SYMBOL_NAME(sys_select)
+       .long SYMBOL_NAME(sys_flock)
        .space (NR_syscalls-143)*4
index b3ebdfed1c39ffdbce495f4c9366d5e80e28450f..20587602a76ebd674bbb1e6550839018f6e6fcd7 100644 (file)
@@ -9,15 +9,9 @@
  */
 
 .text
-.globl _idt,_gdt,_stext,__stext
-.globl _swapper_pg_dir,_pg0
-.globl _empty_bad_page
-.globl _empty_bad_page_table
-.globl _empty_zero_page
-
-#define __ASSEMBLY__
 #include <linux/tasks.h>
 #include <linux/fd.h>
+#include <linux/linkage.h>
 #include <asm/segment.h>
 
 #define CL_MAGIC_ADDR  0x90020
@@ -29,8 +23,8 @@
  * swapper_pg_dir is the main page directory, address 0x00001000 (or at
  * address 0x00101000 for a compressed boot).
  */
-_stext:
-__stext:
+ENTRY(stext)
+ENTRY(_stext)
 startup_32:
        cld
        movl $(KERNEL_DS),%eax
@@ -43,8 +37,8 @@ startup_32:
  * Clear BSS first so that there are no surprises...
  */
        xorl %eax,%eax
-       movl $__edata,%edi
-       movl $__end,%ecx
+       movl $ SYMBOL_NAME(_edata),%edi
+       movl $ SYMBOL_NAME(_end),%ecx
        subl %edi,%ecx
        cld
        rep
@@ -72,7 +66,7 @@ startup_32:
  * is for the command line.
  */
        movl $0x90000,%esi
-       movl $_empty_zero_page,%edi
+       movl $ SYMBOL_NAME(empty_zero_page),%edi
        movl $512,%ecx
        cld
        rep
@@ -83,7 +77,7 @@ startup_32:
        stosl
        cmpw $(CL_MAGIC),CL_MAGIC_ADDR
        jne 1f
-       movl $_empty_zero_page+2048,%edi
+       movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
        movzwl CL_OFFSET,%esi
        addl $(CL_BASE_ADDR),%esi
        movl $2048,%ecx
@@ -96,7 +90,7 @@ startup_32:
  * apply at our cpl of 0 and the stack ought to be aligned already, and
  * we don't need to preserve eflags.
  */
-       movl $3,_x86
+       movl $3, SYMBOL_NAME(x86)
        pushfl                  # push EFLAGS
        popl %eax               # get EFLAGS
        movl %eax,%ecx          # save original EFLAGS
@@ -108,7 +102,7 @@ startup_32:
        xorl %ecx,%eax          # change in flags
        andl $0x40000,%eax      # check if AC bit changed
        je is386
-       movl $4,_x86
+       movl $4,SYMBOL_NAME(x86)
        movl %ecx,%eax
        xorl $0x200000,%eax     # check ID flag
        pushl %eax
@@ -125,19 +119,19 @@ isnew:    pushl %ecx              # restore original EFLAGS
        .byte 0x0f, 0xa2        # check the processor type
        movb %al, %cl           # save reg for future use
        andb $0x0f,%ah          # mask processor family
-       movb %ah, _x86
+       movb %ah,SYMBOL_NAME(x86)
        andb $0xf0, %eax        # mask model
        shrb $4, %al
-       movb %al, _x86_model
+       movb %al,SYMBOL_NAME(x86_model)
        andb $0x0f, %cl         # mask mask revision
-       movb %cl, _x86_mask
-       movl %edx, _x86_capability
+       movb %cl,SYMBOL_NAME(x86_mask)
+       movl %edx,SYMBOL_NAME(x86_capability)
        /* get vendor info */
        xorl %eax, %eax                 # call CPUID with 0 -> return vendor ID
        .byte 0x0f, 0xa2                # CPUID
-       movl %ebx, _x86_vendor_id       # lo 4 chars
-       movl %edx, _x86_vendor_id+4     # next 4 chars
-       movl %ecx, _x86_vendor_id+8     # last 4 chars
+       movl %ebx,SYMBOL_NAME(x86_vendor_id)    # lo 4 chars
+       movl %edx,SYMBOL_NAME(x86_vendor_id)+4  # next 4 chars
+       movl %ecx,SYMBOL_NAME(x86_vendor_id)+8  # last 4 chars
 
        movl %cr0,%eax          # 486+
        andl $0x80000011,%eax   # Save PG,PE,ET
@@ -172,7 +166,7 @@ is386:      pushl %ecx              # restore original EFLAGS
        pushl %eax
        pushl %eax
        cld                     # gcc2 wants the direction flag cleared at all times
-       call _start_kernel
+       call SYMBOL_NAME(start_kernel)
 L6:
        jmp L6                  # main should never return here, but
                                # just in case, we know what happens.
@@ -181,7 +175,7 @@ L6:
  * We depend on ET to be correct. This checks for 287/387.
  */
 check_x87:
-       movb $0,_hard_math
+       movb $0,SYMBOL_NAME(hard_math)
        clts
        fninit
        fstsw %ax
@@ -191,8 +185,8 @@ check_x87:
        xorl $4,%eax            /* set EM */
        movl %eax,%cr0
        ret
-.align 2
-1:     movb $1,_hard_math
+       ALIGN
+1:     movb $1,SYMBOL_NAME(hard_math)
        .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
        ret
 
@@ -212,7 +206,7 @@ setup_idt:
        movw %dx,%ax            /* selector = 0x0010 = cs */
        movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
 
-       lea _idt,%edi
+       lea SYMBOL_NAME(idt),%edi
        mov $256,%ecx
 rp_sidt:
        movl %eax,(%edi)
@@ -234,24 +228,26 @@ rp_sidt:
  * (ref: update, 25Sept92)  -- croutons@crunchy.uucp 
  * (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)
  */
-.align 2
+       ALIGN
 setup_paging:
        movl $1024*2,%ecx               /* 2 pages - swapper_pg_dir+1 page table */
        xorl %eax,%eax
-       movl $_swapper_pg_dir,%edi      /* swapper_pg_dir is at 0x1000 */
+       movl $ SYMBOL_NAME(swapper_pg_dir),%edi /* swapper_pg_dir is at 0x1000 */
        cld;rep;stosl
 /* Identity-map the kernel in low 4MB memory for ease of transition */
-       movl $_pg0+7,_swapper_pg_dir            /* set present bit/user r/w */
+/* set present bit/user r/w */
+       movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)
 /* But the real place is at 0xC0000000 */
-       movl $_pg0+7,_swapper_pg_dir+3072       /* set present bit/user r/w */
-       movl $_pg0+4092,%edi
+/* set present bit/user r/w */
+       movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)+3072
+       movl $ SYMBOL_NAME(pg0)+4092,%edi
        movl $0x03ff007,%eax            /*  4Mb - 4096 + 7 (r/w user,p) */
        std
 1:     stosl                   /* fill the page backwards - more efficient :-) */
        subl $0x1000,%eax
        jge 1b
        cld
-       movl $_swapper_pg_dir,%eax
+       movl $ SYMBOL_NAME(swapper_pg_dir),%eax
        movl %eax,%cr3                  /* cr3 - page directory start */
        movl %cr0,%eax
        orl $0x80000000,%eax
@@ -269,33 +265,33 @@ setup_paging:
  * by 2-3k.  This would be a good thing to do at some point.....
  */
 .org 0x1000
-_swapper_pg_dir:
+ENTRY(swapper_pg_dir)
 /*
  * The page tables are initialized to only 4MB here - the final page
  * tables are set up later depending on memory size.
  */
 .org 0x2000
-_pg0:
+ENTRY(pg0)
 
 .org 0x3000
-_empty_bad_page:
+ENTRY(empty_bad_page)
 
 .org 0x4000
-_empty_bad_page_table:
+ENTRY(empty_bad_page_table)
 
 .org 0x5000
-_empty_zero_page:
+ENTRY(empty_zero_page)
 
 .org 0x6000
 
 stack_start:
-       .long _init_user_stack+4096
+       .long SYMBOL_NAME(init_user_stack)+4096
        .long KERNEL_DS
 
 /* This is the default interrupt "handler" :-) */
 int_msg:
        .asciz "Unknown interrupt\n"
-.align 2
+       ALIGN
 ignore_int:
        cld
        pushl %eax
@@ -309,7 +305,7 @@ ignore_int:
        mov %ax,%es
        mov %ax,%fs
        pushl $int_msg
-       call _printk
+       call SYMBOL_NAME(printk)
        popl %eax
        pop %fs
        pop %es
@@ -322,28 +318,26 @@ ignore_int:
 /*
  * The interrupt descriptor table has room for 256 idt's
  */
-.align 4
+       ALIGN
 .word 0
 idt_descr:
        .word 256*8-1           # idt contains 256 entries
-       .long 0xc0000000+_idt
+       .long 0xc0000000+SYMBOL_NAME(idt)
 
-.align 4
-_idt:
+ENTRY(idt)
        .fill 256,8,0           # idt is uninitialized
 
-.align 4
+       ALIGN
 .word 0
 gdt_descr:
        .word (8+2*NR_TASKS)*8-1
-       .long 0xc0000000+_gdt
+       .long 0xc0000000+SYMBOL_NAME(gdt)
 
 /*
  * This gdt setup gives the kernel a 1GB address space at virtual
  * address 0xC0000000 - space enough for expansion, I hope.
  */
-.align 4
-_gdt:
+ENTRY(gdt)
        .quad 0x0000000000000000        /* NULL descriptor */
        .quad 0x0000000000000000        /* not used */
        .quad 0xc0c39a000000ffff        /* 0x10 kernel 1GB code at 0xC0000000 */
index 77254751b7ace5e5fb5d50e80bc6f4c46d2bf162..87dacbe333ba3d7b612a174528c1f96a383c2e40 100644 (file)
@@ -193,6 +193,31 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
                __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
 }
 
+/*
+ * fill in the fpu structure for a core dump..
+ */
+int dump_fpu (struct user_i387_struct* fpu)
+{
+       int fpvalid;
+
+/* Flag indicating the math stuff is valid. We don't support this for the
+   soft-float routines yet */
+       if (hard_math) {
+               if ((fpvalid = current->used_math) != 0) {
+                       if (last_task_used_math == current)
+                               __asm__("clts ; fnsave %0": :"m" (*fpu));
+                       else
+                               memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
+               }
+       } else {
+               /* we should dump the emulator state here, but we need to
+                  convert it into standard 387 format first.. */
+               fpvalid = 0;
+       }
+
+       return fpvalid;
+}
+
 /*
  * fill in the user structure for a core dump..
  */
@@ -216,20 +241,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
 
        dump->regs = *regs;
 
-/* Flag indicating the math stuff is valid. We don't support this for the
-   soft-float routines yet */
-       if (hard_math) {
-               if ((dump->u_fpvalid = current->used_math) != 0) {
-                       if (last_task_used_math == current)
-                               __asm__("clts ; fnsave %0": :"m" (dump->i387));
-                       else
-                               memcpy(&dump->i387,&current->tss.i387.hard,sizeof(dump->i387));
-               }
-       } else {
-               /* we should dump the emulator state here, but we need to
-                  convert it into standard 387 format first.. */
-               dump->u_fpvalid = 0;
-       }
+       dump->u_fpvalid = dump_fpu (&dump->i387);
 }
 
 asmlinkage int sys_fork(struct pt_regs regs)
index 5cc4c5d7d5fb3149946f05b83bfa908bbb8fce7c..d422e478e91e4d86cf3f802ee009db9871341693 100644 (file)
@@ -56,7 +56,7 @@ struct screen_info screen_info;
 unsigned char aux_device_present;
 extern int ramdisk_size;
 extern int root_mountflags;
-extern int etext, edata, end;
+extern int _etext, _edata, _end;
 
 extern char empty_zero_page[PAGE_SIZE];
 
@@ -96,11 +96,11 @@ void setup_arch(char **cmdline_p,
 #endif
        if (MOUNT_ROOT_RDONLY)
                root_mountflags |= MS_RDONLY;
-       memory_start = (unsigned long) &end;
+       memory_start = (unsigned long) &_end;
        init_task.mm->start_code = TASK_SIZE;
-       init_task.mm->end_code = TASK_SIZE + (unsigned long) &etext;
-       init_task.mm->end_data = TASK_SIZE + (unsigned long) &edata;
-       init_task.mm->brk = TASK_SIZE + (unsigned long) &end;
+       init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext;
+       init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata;
+       init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
 
        for (;;) {
                if (c == ' ' && *(unsigned long *)from == *(unsigned long *)"mem=") {
index 6dd7fc65b637b1a86eefc8f4d083396e62f960f9..f375a3cf64c638c3a3f4d46d5b9fed09b36fb7e9 100644 (file)
@@ -99,7 +99,7 @@ int kstack_depth_to_print = 24;
        unsigned long esp;
        unsigned short ss;
        unsigned long *stack, addr, module_start, module_end;
-       extern char start_kernel, etext;
+       extern char start_kernel, _etext;
 
        esp = (unsigned long) &regs->esp;
        ss = KERNEL_DS;
@@ -147,7 +147,7 @@ int kstack_depth_to_print = 24;
                 * out the call path that was taken.
                 */
                if (((addr >= (unsigned long) &start_kernel) &&
-                    (addr <= (unsigned long) &etext)) ||
+                    (addr <= (unsigned long) &_etext)) ||
                    ((addr >= module_start) && (addr <= module_end))) {
                        if (i && ((i % 8) == 0))
                                printk("\n       ");
index 67d8be9646b74b635fbc326934b72b2aa4b38908..5e2ee570a714468f4600b11342038b8b6cc0437f 100644 (file)
@@ -74,11 +74,7 @@ FPU_result_1:
 
 
 .text
-       .align 2,144
-
-.globl _div_Xsig
-
-_div_Xsig:
+ENTRY(div_Xsig)
        pushl   %ebp
        movl    %esp,%ebp
 #ifndef NON_REENTRANT_FPU
index 0225a96d4c173f8952cd2e28341efd4667d9f510..b0b7ee25dd1c03b4817792b426cb9daa95318d83 100644 (file)
 #include "fpu_asm.h"
 
 .text
-       .align 2,144
-
-.globl _div_small
-
-_div_small:
+ENTRY(div_small)
        pushl   %ebp
        movl    %esp,%ebp
 
index 8eb60148d12b40714c69728b79ebe6849d4fe962..33c008d10647fcd5ed738d9f439258741c5a1534 100644 (file)
@@ -9,9 +9,10 @@
 #ifndef _FPU_ASM_H_
 #define _FPU_ASM_H_
 
+#include <linux/linkage.h>
 #include "fpu_emu.h"
 
-#define        EXCEPTION       _exception
+#define        EXCEPTION       SYMBOL_NAME(exception)
 
 
 #define PARAM1 8(%ebp)
index 1d88d4466df8d86aae983820856058da8fae73bb..5e80762d2edad0f1647e3b31e00fb252b52051d6 100644 (file)
@@ -24,9 +24,7 @@
 #include "fpu_asm.h"
 
 .text
-       .align 2,144
-.globl _mul32_Xsig
-_mul32_Xsig:
+ENTRY(mul32_Xsig)
        pushl %ebp
        movl %esp,%ebp
        subl $16,%esp
@@ -66,9 +64,7 @@ _mul32_Xsig:
        ret
 
 
-       .align 2,144
-.globl _mul64_Xsig
-_mul64_Xsig:
+ENTRY(mul64_Xsig)
        pushl %ebp
        movl %esp,%ebp
        subl $16,%esp
@@ -121,9 +117,7 @@ _mul64_Xsig:
 
 
 
-       .align 2,144
-.globl _mul_Xsig_Xsig
-_mul_Xsig_Xsig:
+ENTRY(mul_Xsig_Xsig)
        pushl %ebp
        movl %esp,%ebp
        subl $16,%esp
index 585221f96827f6a37df7d3fcaac9ca450c53722e..19d1935b44eab74e9b1caf46bd625ae732103730 100644 (file)
@@ -36,9 +36,7 @@
 #define OVERFLOWED      -16(%ebp)      /* addition overflow flag */
 
 .text
-       .align 2,144
-.globl _polynomial_Xsig
-_polynomial_Xsig:
+ENTRY(polynomial_Xsig)
        pushl   %ebp
        movl    %esp,%ebp
        subl    $32,%esp
index 2fbc5f7c41a68d9d8fae8d08597069099eba95d7..78b10867509587f1b56a9c6474006f7ae33e0cd8 100644 (file)
 
 
 .text
-       .align 2
-
-.globl _reg_div
-_reg_div:
+ENTRY(reg_div)
        pushl   %ebp
        movl    %esp,%ebp
 #ifndef NON_REENTRANT_FPU
@@ -47,7 +44,7 @@ _reg_div:
        cmpl    EXP_UNDER,EXP(%esi)
        jg      xL_arg1_not_denormal
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
@@ -55,7 +52,7 @@ xL_arg1_not_denormal:
        cmpl    EXP_UNDER,EXP(%ebx)
        jg      xL_arg2_not_denormal
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
@@ -75,7 +72,7 @@ xL_arg2_not_denormal:
        addl    EXP_BIAS,%edx
        movl    %edx,EXP(%edi)
 
-       jmp     _divide_kernel
+       jmp     SYMBOL_NAME(divide_kernel)
 
 
 /*-----------------------------------------------------------------------*/
@@ -92,14 +89,14 @@ L_arg2_NaN:
        pushl   %edi                    /* Destination */
        pushl   %esi
        pushl   %ebx                    /* Ordering is important here */
-       call    _real_2op_NaN
+       call    SYMBOL_NAME(real_2op_NaN)
        jmp     LDiv_exit
 
 /* Invalid operations */
 L_zero_zero:
 L_inf_inf:
        pushl   %edi                    /* Destination */
-       call    _arith_invalid          /* 0/0 or Infinity/Infinity */
+       call    SYMBOL_NAME(arith_invalid) /* 0/0 or Infinity/Infinity */
        jmp     LDiv_exit
 
 L_no_NaN_arg:
@@ -126,7 +123,7 @@ L_inf_valid:
        cmpl    EXP_UNDER,EXP(%ebx)
        jg      L_copy_arg1             /* Answer is Inf */
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 #endif DENORM_OPERAND
@@ -151,7 +148,7 @@ L_arg1_not_inf:
        movb    SIGN(%esi),%al
        xorb    SIGN(%ebx),%al
        pushl   %eax                    /* lower 8 bits have the sign */
-       call    _divide_by_zero
+       call    SYMBOL_NAME(divide_by_zero)
        jmp     LDiv_exit
 
 L_arg2_not_zero:
@@ -165,7 +162,7 @@ L_arg2_not_zero:
        cmpl    EXP_UNDER,EXP(%esi)
        jg      L_return_zero           /* Answer is zero */
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 #endif DENORM_OPERAND
@@ -185,7 +182,7 @@ L_arg2_not_inf:
        cmpl    EXP_UNDER,EXP(%ebx)
        jg      L_copy_arg1             /* Answer is zero */
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 #endif DENORM_OPERAND
@@ -241,11 +238,11 @@ L_unknown_tags:
        call    EXCEPTION
 
        /* Generate a NaN for unknown tags */
-       movl    _CONST_QNaN,%eax
+       movl    SYMBOL_NAME(CONST_QNaN),%eax
        movl    %eax,(%edi)
-       movl    _CONST_QNaN+4,%eax
+       movl    SYMBOL_NAME(CONST_QNaN)+4,%eax
        movl    %eax,SIGL(%edi)
-       movl    _CONST_QNaN+8,%eax
+       movl    SYMBOL_NAME(CONST_QNaN)+8,%eax
        movl    %eax,SIGH(%edi)
        jmp     LDiv_exit               /* %eax is nz */
 #endif PARANOID
index 9b7a9d77d07b33d06c196a52b088ba2e3631ca95..6e30d46d0256dfa98ede53c8332155baeb774bc9 100644 (file)
 
 
 .text
-
-       .align 2,144
-.globl _normalize
-
-_normalize:
+ENTRY(normalize)
        pushl   %ebp
        movl    %esp,%ebp
        pushl   %ebx
@@ -34,7 +30,7 @@ _normalize:
        je      L_ok
 
        pushl   $0x220
-       call    _exception
+       call    SYMBOL_NAME(exception)
        addl    $4,%esp
 
 L_ok:
@@ -86,23 +82,20 @@ L_zero:
 
 L_underflow:
        push    %ebx
-       call    _arith_underflow
+       call    SYMBOL_NAME(arith_underflow)
        pop     %ebx
        jmp     L_exit
 
 L_overflow:
        push    %ebx
-       call    _arith_overflow
+       call    SYMBOL_NAME(arith_overflow)
        pop     %ebx
        jmp     L_exit
 
 
 
 /* Normalise without reporting underflow or overflow */
-       .align 2,144
-.globl _normalize_nuo
-
-_normalize_nuo:
+ENTRY(normalize_nuo)
        pushl   %ebp
        movl    %esp,%ebp
        pushl   %ebx
@@ -114,7 +107,7 @@ _normalize_nuo:
        je      L_ok_nuo
 
        pushl   $0x221
-       call    _exception
+       call    SYMBOL_NAME(exception)
        addl    $4,%esp
 
 L_ok_nuo:
index bd8a40dc423c28692a4e8f3a1908c7dd0929f8ed..515636f37c09287395cf2bd621cd9be4896e0656 100644 (file)
@@ -101,14 +101,12 @@ FPU_denormal:
 
 
 .text
-       .align 2,144
 .globl fpu_reg_round
 .globl fpu_reg_round_sqrt
 .globl fpu_Arith_exit
-.globl _round_reg
 
 /* Entry point when called from C */
-_round_reg:
+ENTRY(round_reg)
        pushl   %ebp
        movl    %esp,%ebp
        pushl   %esi
@@ -435,7 +433,7 @@ fpu_Arith_exit:
  */
 xL_precision_lost_up:
        push    %eax
-       call    _set_precision_flag_up
+       call    SYMBOL_NAME(set_precision_flag_up)
        popl    %eax
        jmp     xL_no_precision_loss
 
@@ -445,7 +443,7 @@ xL_precision_lost_up:
  */
 xL_precision_lost_down:
        push    %eax
-       call    _set_precision_flag_down
+       call    SYMBOL_NAME(set_precision_flag_down)
        popl    %eax
        jmp     xL_no_precision_loss
 
@@ -598,7 +596,7 @@ LNormalise_shift_done:
        /* There must be a masked underflow */
        push    %eax
        pushl   EX_Underflow
-       call    _exception
+       call    SYMBOL_NAME(exception)
        popl    %eax
        popl    %eax
        jmp     xL_Normalised
@@ -610,12 +608,12 @@ LNormalise_shift_done:
  */
 L_underflow_to_zero:
        push    %eax
-       call    _set_precision_flag_down
+       call    SYMBOL_NAME(set_precision_flag_down)
        popl    %eax
 
        push    %eax
        pushl   EX_Underflow
-       call    _exception
+       call    SYMBOL_NAME(exception)
        popl    %eax
        popl    %eax
 
@@ -628,7 +626,7 @@ L_underflow_to_zero:
 /* The operations resulted in a number too large to represent. */
 L_overflow:
        push    %edi
-       call    _arith_overflow
+       call    SYMBOL_NAME(arith_overflow)
        pop     %edi
        jmp     fpu_reg_round_exit
 
index 4410f8fd475e9d83ae28ac97bb0feb8f24bc6419..36c6f86516a03886d2ffa833291107ed2f9ed31c 100644 (file)
@@ -29,9 +29,7 @@
 #include "control_w.h"
 
 .text
-       .align 2,144
-.globl _reg_u_add
-_reg_u_add:
+ENTRY(reg_u_add)
        pushl   %ebp
        movl    %esp,%ebp
        pushl   %esi
@@ -45,7 +43,7 @@ _reg_u_add:
        cmpl    EXP_UNDER,EXP(%esi)
        jg      xOp1_not_denorm
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
@@ -53,7 +51,7 @@ xOp1_not_denorm:
        cmpl    EXP_UNDER,EXP(%edi)
        jg      xOp2_not_denorm
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
index 328e9116ec94a03de1ea1ce18a81bc662302b088..a2d3738b64c942a9a16981aaa1156e8bc1abff57 100644 (file)
@@ -69,13 +69,7 @@ FPU_ovfl_flag:
 
 
 .text
-       .align 2,144
-
-.globl _reg_u_div
-
-.globl _divide_kernel
-
-_reg_u_div:
+ENTRY(reg_u_div)
        pushl   %ebp
        movl    %esp,%ebp
 #ifndef NON_REENTRANT_FPU
@@ -95,7 +89,7 @@ _reg_u_div:
        cmpl    EXP_UNDER,%eax
        jg      xOp1_not_denorm
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
@@ -104,14 +98,14 @@ xOp1_not_denorm:
        cmpl    EXP_UNDER,%eax
        jg      xOp2_not_denorm
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
 xOp2_not_denorm:
 #endif DENORM_OPERAND
 
-_divide_kernel:
+ENTRY(divide_kernel)
 #ifdef PARANOID
 /*     testl   $0x80000000, SIGH(%esi) // Dividend */
 /*     je      L_bugged */
index 8250666bd87904cfe36e79d0ef019c334618de65..d2d69ce5ef0358e42408dd2352457e10c8cdc0d1 100644 (file)
@@ -44,10 +44,7 @@ FPU_accum_1:
 
 
 .text
-       .align 2,144
-
-.globl _reg_u_mul
-_reg_u_mul:
+ENTRY(reg_u_mul)
        pushl   %ebp
        movl    %esp,%ebp
 #ifndef NON_REENTRANT_FPU
@@ -73,7 +70,7 @@ _reg_u_mul:
        cmpl    EXP_UNDER,%eax
        jg      xOp1_not_denorm
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
@@ -82,7 +79,7 @@ xOp1_not_denorm:
        cmpl    EXP_UNDER,%eax
        jg      xOp2_not_denorm
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
index fbec17dfbff084a305629d0cead7afee45ae61cc..53a7768659e1e79dc75a32c2aba5024281c1dbb6 100644 (file)
@@ -30,9 +30,7 @@
 #include "control_w.h"
 
 .text
-       .align 2,144
-.globl _reg_u_sub
-_reg_u_sub:
+ENTRY(reg_u_sub)
        pushl   %ebp
        movl    %esp,%ebp
        pushl   %esi
@@ -46,7 +44,7 @@ _reg_u_sub:
        cmpl    EXP_UNDER,EXP(%esi)
        jg      xOp1_not_denorm
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
@@ -54,7 +52,7 @@ xOp1_not_denorm:
        cmpl    EXP_UNDER,EXP(%edi)
        jg      xOp2_not_denorm
 
-       call    _denormal_operand
+       call    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit
 
index 1637558784d9550f030b01c157edc5e2a4814cd5..f2707719c452174e5f88ef2b5ce267d0b32aeb0b 100644 (file)
 
 
 .text
-
-       .align 2,144
-.globl _round_Xsig
-
-_round_Xsig:
+ENTRY(round_Xsig)
        pushl   %ebp
        movl    %esp,%ebp
        pushl   %ebx            /* Reserve some space */
@@ -86,10 +82,7 @@ L_exit:
 
 
 
-       .align 2,144
-.globl _norm_Xsig
-
-_norm_Xsig:
+ENTRY(norm_Xsig)
        pushl   %ebp
        movl    %esp,%ebp
        pushl   %ebx            /* Reserve some space */
index d6724a204f0d3e183466f4b63e1266c8a25c8e49..1cd151cae77d543d7e82e37d354551eb8b5b8dfd 100644 (file)
 #include "fpu_asm.h"
 
 .text
-       .align 2,144
-
-       .globl  _shr_Xsig
-_shr_Xsig:
+ENTRY(shr_Xsig)
        push    %ebp
        movl    %esp,%ebp
        pushl   %esi
index bef0e1963a3581946a9e455c5b0e6e32ab9fd6cc..810ad9b776617dff9dde4350fb3410a7c52644df 100644 (file)
@@ -17,8 +17,6 @@
 #include "fpu_asm.h"
 
 .text
-       .align 2,144
-
 /*---------------------------------------------------------------------------+
  |   unsigned shrx(void *arg1, unsigned arg2)                                |
  |                                                                           |
@@ -33,9 +31,7 @@
  |   Results returned in the 64 bit arg and eax.                             |
  +---------------------------------------------------------------------------*/
 
-       .globl  _shrx
-
-_shrx:
+ENTRY(shrx)
        push    %ebp
        movl    %esp,%ebp
        pushl   %esi
@@ -113,8 +109,7 @@ L_more_than_95:
  |   part which has been shifted out of the arg.                             |
  |   Results returned in the 64 bit arg and eax.                             |
  +---------------------------------------------------------------------------*/
-       .globl  _shrxs
-_shrxs:
+ENTRY(shrxs)
        push    %ebp
        movl    %esp,%ebp
        pushl   %esi
index 4e028cb80753467b0bf5b3156e57d278b4f97b39..898fafe1666ae34df32c39f90fe3c531110b5685 100644 (file)
@@ -74,10 +74,7 @@ FPU_fsqrt_arg_0:
 
 
 .text
-       .align 2,144
-
-.globl _wm_sqrt
-_wm_sqrt:
+ENTRY(wm_sqrt)
        pushl   %ebp
        movl    %esp,%ebp
 #ifndef NON_REENTRANT_FPU
index 296595644af39ad39d64343e72095ae462359590..c4bb3ee8b3dfd2ab7cab854eada147680b827066 100644 (file)
@@ -149,7 +149,7 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
        int reservedpages = 0;
        int datapages = 0;
        unsigned long tmp;
-       extern int etext;
+       extern int _etext;
 
        end_mem &= PAGE_MASK;
        high_memory = end_mem;
@@ -185,7 +185,7 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
                if (mem_map[MAP_NR(tmp)]) {
                        if (tmp >= 0xA0000 && tmp < 0x100000)
                                reservedpages++;
-                       else if (tmp < (unsigned long) &etext)
+                       else if (tmp < (unsigned long) &_etext)
                                codepages++;
                        else
                                datapages++;
index 999775db75f91c4f648e31766f1b18ab22ce98f3..43fb922602226add85f2a192cdbf67bb4efc5c5c 100644 (file)
@@ -74,7 +74,8 @@ bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
 bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
 bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
 bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA y
+bool 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO n
 bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
 bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
 bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
index 603d7917d25a50ed88801cd3f98123e66ee460ce..7885bf0dcdac5f3d9c8bf16e08f5580b94d2ad14 100644 (file)
@@ -8,10 +8,10 @@
  *     console.c
  *
  * This module exports the console io functions:
- * 
+ *
  *     'void do_keyboard_interrupt(void)'
  *
- *     'int vc_allocate(unsigned int console)' 
+ *     'int vc_allocate(unsigned int console)'
  *     'int vc_cons_allocated(unsigned int console)'
  *     'int vc_resize(unsigned long lines, unsigned long cols)'
  *     'void vc_disallocate(unsigned int currcons)'
@@ -33,7 +33,7 @@
  *     'void scrollback(int lines)'
  *     'void scrollfront(int lines)'
  *
- *     'int con_get_font(char *data)' 
+ *     'int con_get_font(char *data)'
  *     'int con_set_font(char *data, int ch512)'
  *     'int con_adjust_height(int fontheight)'
  *
@@ -49,7 +49,7 @@
  * Hopefully this will be a rather complete VT102 implementation.
  *
  * Beeping thanks to John T Kohl.
- * 
+ *
  * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
  *   Chars, and VT100 enhancements by Peter MacDonald.
  *
@@ -234,7 +234,7 @@ struct vc_data {
        unsigned long   vc_report_mouse : 2;
        unsigned char   vc_utf          : 1;    /* Unicode UTF-8 encoding */
        unsigned char   vc_utf_count;
-                long   vc_utf_char;
+                long   vc_utf_char;
        unsigned long   vc_tab_stop[5];         /* Tab stops. 160 columns. */
        unsigned char   vc_palette[16*3];       /* Colour palette for VGA+ */
        unsigned short * vc_translate;
@@ -278,7 +278,7 @@ static struct vc {
 #define utf_char       (vc_cons[currcons].d->vc_utf_char)
 #define video_mem_start        (vc_cons[currcons].d->vc_video_mem_start)
 #define video_mem_end  (vc_cons[currcons].d->vc_video_mem_end)
-#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)    
+#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
 #define disp_ctrl      (vc_cons[currcons].d->vc_disp_ctrl)
 #define toggle_meta    (vc_cons[currcons].d->vc_toggle_meta)
 #define decscnm                (vc_cons[currcons].d->vc_decscnm)
@@ -584,7 +584,7 @@ void scrollback(int lines)
                        int count ;
                        unsigned short * d = (unsigned short *) video_mem_base;
                        unsigned short * s = (unsigned short *) last_origin;
-                       
+
                        lines += last_origin_rel;
                        /* in case the top part of the screen has been modified since
                         * the scroll wrapped, copy the top bit back to the bottom */
@@ -710,7 +710,7 @@ static void scrup(int currcons, unsigned int t, unsigned int b)
                                count--;
                                scr_writew(video_erase_char, d++);
                        }
-                        if (scr_end > last_origin)   /* we've wrapped into kept region */
+                       if (scr_end > last_origin)   /* we've wrapped into kept region */
                                __scrollback_mode = 0;
                }
                set_origin(currcons);
@@ -997,7 +997,7 @@ static void csi_m(int currcons)
                        default:
                                if (par[i] >= 30 && par[i] <= 37)
                                        color = color_table[par[i]-30]
-                                               | background; 
+                                               | background;
                                else if (par[i] >= 40 && par[i] <= 47)
                                        color = (color_table[par[i]-40]<<4)
                                                | foreground;
@@ -1326,7 +1326,7 @@ static void restore_cur(int currcons)
        need_wrap = 0;
 }
 
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, 
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
        EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
        ESpalette };
 
@@ -1437,7 +1437,7 @@ static int con_write(struct tty_struct * tty, int from_user,
                if (utf) {
                    /* Combine UTF-8 into Unicode */
                    /* Incomplete characters silently ignored */
-                   if(c > 0x7f) {   
+                   if(c > 0x7f) {
                        if (utf_count > 0 && (c & 0xc0) == 0x80) {
                                utf_char = (utf_char << 6) | (c & 0x3f);
                                utf_count--;
@@ -1483,10 +1483,10 @@ static int con_write(struct tty_struct * tty, int from_user,
                 */
                ok = (tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS
                                            : CTRL_ACTION) >> c) & 1))));
-               
+
                if (vc_state == ESnormal && ok) {
-                       /* Now try to find out how to display it */
-                       tc = conv_uni_to_pc(tc);
+                       /* Now try to find out how to display it */
+                       tc = conv_uni_to_pc(tc);
                        if ( tc == -4 )
                          {
                            /* If we got -4 (not found) then see if we have
@@ -1623,7 +1623,7 @@ static int con_write(struct tty_struct * tty, int from_user,
                                  case '=':  /* Appl. keypad */
                                        set_kbd(kbdapplic);
                                        continue;
-                               }       
+                               }
                                continue;
                        case ESnonstd:
                                if (c=='P') {   /* palette escape sequence */
@@ -2020,10 +2020,10 @@ long con_init(long kmem_start)
        console_driver.start = con_start;
        console_driver.throttle = con_throttle;
        console_driver.unthrottle = con_unthrottle;
-       
+
        if (tty_register_driver(&console_driver))
                panic("Couldn't register console driver\n");
-       
+
        con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS);
        video_page = ORIG_VIDEO_PAGE;                   /* never used */
        __scrollback_mode = 0 ;
@@ -2034,7 +2034,7 @@ long con_init(long kmem_start)
                timer_table[BLANK_TIMER].expires = jiffies+blankinterval;
                timer_active |= 1<<BLANK_TIMER;
        }
-       
+
        if (ORIG_VIDEO_MODE == 7)       /* Is this a monochrome display? */
        {
                video_mem_base = 0xb0000;
@@ -2063,44 +2063,51 @@ long con_init(long kmem_start)
                video_port_val  = 0x3d5;
                if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
                {
-                        int i ;
-
-                        video_mem_term = 0xc0000;
-
-                        if (!ORIG_VIDEO_ISVGA) {
-                                video_type = VIDEO_TYPE_EGAC;
-                                display_desc = "EGA";
-                                request_region(0x3c0,32,"ega");
-                        } else {
-                                video_type = VIDEO_TYPE_VGAC;
-                                display_desc = "VGA+";
-                                request_region(0x3c0,32,"vga+");
-
-                                /* get 64K rather than 32K of video RAM */
-                                video_mem_base = 0xa0000 ;
-                                video_mem_term = 0xb0000 ;
-                                outb_p (6, 0x3ce) ;
-                                outb_p (6, 0x3cf) ;
-
-                                /* normalise the palette registers, to point the                                 * 16 screen colours to the first 16 DAC entries */
-
-                                for (i=0; i<16; i++) {
-                                        inb_p (0x3da) ;
-                                        outb_p (i, 0x3c0) ;
-                                        outb_p (i, 0x3c0) ;
-                                }
-                                outb_p (0x20, 0x3c0) ;
-
-                                /* now set the DAC registers back to their default
-                                 * values */
-
-                                for (i=0; i<16; i++) {
+                       int i ;
+
+                       video_mem_term = 0xc0000;
+
+                       if (!ORIG_VIDEO_ISVGA) {
+                               video_type = VIDEO_TYPE_EGAC;
+                               display_desc = "EGA";
+                               request_region(0x3c0,32,"ega");
+                       } else {
+                               video_type = VIDEO_TYPE_VGAC;
+                               display_desc = "VGA+";
+                               request_region(0x3c0,32,"vga+");
+
+#ifdef VGA_CAN_DO_64KB
+                               /*
+                                * get 64K rather than 32K of video RAM.
+                                * This doesn't actually work on all "VGA"
+                                * controllers (it seems like setting MM=01
+                                * and COE=1 isn't necessarily a good idea)
+                                */
+                               video_mem_base = 0xa0000 ;
+                               video_mem_term = 0xb0000 ;
+                               outb_p (6, 0x3ce) ;
+                               outb_p (6, 0x3cf) ;
+#endif
+
+                               /* normalise the palette registers, to point the                                 * 16 screen colours to the first 16 DAC entries */
+
+                               for (i=0; i<16; i++) {
+                                       inb_p (0x3da) ;
+                                       outb_p (i, 0x3c0) ;
+                                       outb_p (i, 0x3c0) ;
+                               }
+                               outb_p (0x20, 0x3c0) ;
+
+                               /* now set the DAC registers back to their default
+                                * values */
+
+                               for (i=0; i<16; i++) {
                                        outb_p (color_table[i], 0x3c8) ;
-                                        outb_p (default_red[i], 0x3c9) ;
-                                        outb_p (default_grn[i], 0x3c9) ;
-                                        outb_p (default_blu[i], 0x3c9) ;
-                                }
-                        }
+                                       outb_p (default_red[i], 0x3c9) ;
+                                       outb_p (default_grn[i], 0x3c9) ;
+                                       outb_p (default_blu[i], 0x3c9) ;
+                               }
+                       }
                }
                else
                {
@@ -2110,7 +2117,7 @@ long con_init(long kmem_start)
                        request_region(0x3d4,2,"cga");
                }
        }
-       
+
        /* Initialize the variables used for scrolling (mostly EGA/VGA) */
 
        /* Due to kmalloc roundup allocating statically is more efficient -
@@ -2149,6 +2156,7 @@ long con_init(long kmem_start)
           can figure out the appropriate screen size should we load
           a different font */
 
+       printable = 1;
        if ( video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAC
            || video_type == VIDEO_TYPE_EGAM )
        {
@@ -2159,7 +2167,6 @@ long con_init(long kmem_start)
                       video_font_height, video_scan_lines);
        }
 
-       printable = 1;
        printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n",
                can_do_color ? "colour" : "mono",
                display_desc,
@@ -2325,7 +2332,7 @@ void update_screen(int new_console)
                console_blanked = -1;      /* no longer of the form console+1 */
        fg_console = new_console; /* this is the only (nonzero) assignment to fg_console */
                                  /* consequently, fg_console will always be allocated */
-       set_scrmem(fg_console, 0); 
+       set_scrmem(fg_console, 0);
        set_origin(fg_console);
        set_cursor(fg_console);
        set_leds();
@@ -2342,14 +2349,14 @@ int con_open(struct tty_struct *tty, struct file * filp)
        int i;
 
        idx = MINOR(tty->device) - tty->driver.minor_start;
-       
+
        i = vc_allocate(idx);
        if (i)
                return i;
 
        vt_cons[idx]->vc_num = idx;
        tty->driver_data = vt_cons[idx];
-       
+
        if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
                tty->winsize.ws_row = video_num_lines;
                tty->winsize.ws_col = video_num_columns;
@@ -2493,28 +2500,28 @@ static int set_get_font(char * arg, int set, int ch512)
 
 static int set_get_cmap(unsigned char * arg, int set) {
 #ifdef CAN_LOAD_PALETTE
-        int i;
+       int i;
 
-        /* no use to set colourmaps in less than colour VGA */
+       /* no use to set colourmaps in less than colour VGA */
 
-        if (video_type != VIDEO_TYPE_VGAC)
+       if (video_type != VIDEO_TYPE_VGAC)
                return -EINVAL;
 
-        i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
-        if (i)
+       i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
+       if (i)
                return i;
 
-        for (i=0; i<16; i++) {
-                if (set) {
+       for (i=0; i<16; i++) {
+               if (set) {
                        default_red[i] = get_user(arg++) ;
                        default_grn[i] = get_user(arg++) ;
                        default_blu[i] = get_user(arg++) ;
                } else {
                        put_user (default_red[i], arg++) ;
-                        put_user (default_grn[i], arg++) ;
-                        put_user (default_blu[i], arg++) ;
-                }
-        }
+                       put_user (default_grn[i], arg++) ;
+                       put_user (default_blu[i], arg++) ;
+               }
+       }
        if (set) {
                for (i=0; i<MAX_NR_CONSOLES; i++)
                        if (vc_cons_allocated(i)) {
@@ -2528,9 +2535,9 @@ static int set_get_cmap(unsigned char * arg, int set) {
                set_palette() ;
        }
 
-        return 0;
+       return 0;
 #else
-        return -EINVAL;
+       return -EINVAL;
 #endif
 }
 
@@ -2541,12 +2548,12 @@ static int set_get_cmap(unsigned char * arg, int set) {
 
 int con_set_cmap (unsigned char *arg)
 {
-        return set_get_cmap (arg,1);
+       return set_get_cmap (arg,1);
 }
 
 int con_get_cmap (unsigned char *arg)
 {
-        return set_get_cmap (arg,0);
+       return set_get_cmap (arg,0);
 }
 
 void reset_palette (int currcons)
@@ -2568,12 +2575,12 @@ void set_palette (void)
            vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
                return ;
 
-        for (i=j=0; i<16; i++) {
+       for (i=j=0; i<16; i++) {
                outb_p (color_table[i], dac_reg) ;
                outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
                outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
                outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
-        }
+       }
 }
 
 /*
@@ -2613,18 +2620,18 @@ int con_adjust_height(unsigned long fontheight)
 
        if (fontheight > 32 || (video_type != VIDEO_TYPE_VGAC &&
            video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM))
-               return -EINVAL;
+               return -EINVAL;
 
        if ( fontheight == video_font_height || fontheight == 0 )
                return 0;
-       
+
        video_font_height = fontheight;
 
        rows = video_scan_lines/fontheight;     /* Number of video rows we end up with */
        maxscan = rows*fontheight - 1;          /* Scan lines to actually display-1 */
 
        /* Reprogram the CRTC for the new font size
-           Note: the attempt to read the overflow register will fail
+          Note: the attempt to read the overflow register will fail
           on an EGA, but using 0xff for the previous value appears to
           be OK for EGA text modes in the range 257-512 scan lines, so I
           guess we don't need to worry about it.
@@ -2636,11 +2643,11 @@ int con_adjust_height(unsigned long fontheight)
        cli();
        outb_p( 0x07, video_port_reg );         /* CRTC overflow register */
        ovr = inb_p(video_port_val);
-       outb_p( 0x09, video_port_reg );         /* Font size register */
+       outb_p( 0x09, video_port_reg );         /* Font size register */
        fsr = inb_p(video_port_val);
-       outb_p( 0x0a, video_port_reg );         /* Cursor start */
+       outb_p( 0x0a, video_port_reg );         /* Cursor start */
        curs = inb_p(video_port_val);
-       outb_p( 0x0b, video_port_reg );         /* Cursor end */
+       outb_p( 0x0b, video_port_reg );         /* Cursor end */
        cure = inb_p(video_port_val);
        sti();
 
@@ -2655,13 +2662,13 @@ int con_adjust_height(unsigned long fontheight)
        cli();
        outb_p( 0x07, video_port_reg );         /* CRTC overflow register */
        outb_p( ovr, video_port_val );
-       outb_p( 0x09, video_port_reg );         /* Font size */
+       outb_p( 0x09, video_port_reg );         /* Font size */
        outb_p( fsr, video_port_val );
-       outb_p( 0x0a, video_port_reg );         /* Cursor start */
+       outb_p( 0x0a, video_port_reg );         /* Cursor start */
        outb_p( curs, video_port_val );
-       outb_p( 0x0b, video_port_reg );         /* Cursor end */
+       outb_p( 0x0b, video_port_reg );         /* Cursor end */
        outb_p( cure, video_port_val );
-       outb_p( 0x12, video_port_reg );         /* Vertical display limit */
+       outb_p( 0x12, video_port_reg );         /* Vertical display limit */
        outb_p( vde, video_port_val );
        sti();
 
@@ -2671,7 +2678,7 @@ int con_adjust_height(unsigned long fontheight)
          return 0;
        }
 
-       vc_resize(rows, 0);                     /* Adjust console size */
+       vc_resize(rows, 0);                     /* Adjust console size */
 
        return rows;
 }
index 424ed63b12d473302b9d8e942450fa420f8ca9a8..c757dfa67f93f394bfaa72724cc24c128942bdd5 100644 (file)
@@ -211,7 +211,7 @@ unsigned char inverse_translate(unsigned char c) {
  * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
  * unicodes explictly.
  */
-int con_set_trans_old(char * arg)
+int con_set_trans_old(unsigned char * arg)
 {
        int i;
        unsigned short *p = translations[USER_MAP];
@@ -227,7 +227,7 @@ int con_set_trans_old(char * arg)
        return 0;
 }
 
-int con_get_trans_old(char * arg)
+int con_get_trans_old(unsigned char * arg)
 {
        int i, ch;
        unsigned short *p = translations[USER_MAP];
index 00077d85b00c023b0ce6cfacaa2c2d54c156f9bd..2c2fd14481c146f1cdc7889e37fca0e510dc23bf 100644 (file)
@@ -588,7 +588,7 @@ void cleanup_module(void)
         else {
                unregister_chrdev(LP_MAJOR,"lp");
               for (offset = 0; offset < LP_NO; offset++) 
-                       if(LP_F(offset) && LP_EXIST) 
+                       if (LP_F(offset) & LP_EXIST) 
                                release_region(LP_B(offset),3);
        }
 }
index 4c4b534d17e2725da5667371fd257e61883d1672..de35137803c9a758fcc7e11323e140df7cf30588 100644 (file)
@@ -488,7 +488,7 @@ static int poll_aux_status(void)
        int retries=0;
 
        while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) {
-               if (inb_p(AUX_STATUS) & AUX_OBUF_FULL == AUX_OBUF_FULL)
+               if ((inb_p(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
                        inb_p(AUX_INPUT_PORT);
                current->state = TASK_INTERRUPTIBLE;
                current->timeout = jiffies + (5*HZ + 99) / 100;
index 613ca71afd6067477b7756c6c8efb55d394c935f..d231b977072c46c8a13ef736303b6b572e5d51b2 100644 (file)
@@ -66,8 +66,8 @@ extern unsigned int keymap_count;
  * routines to load custom translation table, EGA/VGA font and
  * VGA colour palette from console.c
  */
-extern int con_set_trans_old(char * table);
-extern int con_get_trans_old(char * table);
+extern int con_set_trans_old(unsigned char * table);
+extern int con_get_trans_old(unsigned char * table);
 extern int con_set_trans_new(unsigned short * table);
 extern int con_get_trans_new(unsigned short * table);
 extern void con_clear_unimap(struct unimapinit *ui);
@@ -1007,10 +1007,10 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
        case PIO_SCRNMAP:
                if (!perm)
                        return -EPERM;
-               return con_set_trans_old((char *)arg);
+               return con_set_trans_old((unsigned char *)arg);
 
        case GIO_SCRNMAP:
-               return con_get_trans_old((char *)arg);
+               return con_get_trans_old((unsigned char *)arg);
 
        case PIO_UNISCRNMAP:
                if (!perm)
index d00ef7ab5fdd631ab8eec0c8c594985ce669acd6..dbee4ce5c8e288e87795993bf3d25655f09f6580 100644 (file)
@@ -10,7 +10,7 @@
  *             be here without 3C505 technical reference provided by
  *             3Com.
  *
- * Version:    @(#)3c505.c     0.8     4-Jun-95
+ * Version:    @(#)3c505.c     0.8.1   26-Jun-95
  *
  * Authors:    Linux 3c505 device driver by
  *                     Craig Southeren, <craigs@ineluki.apana.org.au>
@@ -101,7 +101,7 @@ static int elp_debug = 0;
  *  3 = messages when interrupts received
  */
 
-#define        ELP_VERSION     "0.7.0"
+#define        ELP_VERSION     "0.8.1"
 
 /*****************************************************************
  *
@@ -182,7 +182,7 @@ outw_data (unsigned int val, unsigned int base_addr)
  *****************************************************************/
 
 typedef struct {
-       short got[NUM_TRANSMIT_CMDS];   /* flags for command completion */
+       volatile short got[NUM_TRANSMIT_CMDS];  /* flags for command completion */
        pcb_struct tx_pcb;      /* PCB for foreground sending */
        pcb_struct rx_pcb;      /* PCB for foreground receiving */
        pcb_struct itx_pcb;     /* PCB for background sending */
index 6f5b72751b3a02a1884560a981cbe4b7328c04b6..a91a16230bd1a86314212d0dd6d3fe96e7e494e0 100644 (file)
 #                       If you want at least one board to not autosense then
 #                       no board can autosense. For a board mix of several
 #                      types, OR the manual values [eg for a DE500 (100M) with
-#                      a DE450 (AUI) use '-DDE4X5_AUTOSENSE=(0x80|0x08)']
-#                       For full auto media/mode selection           = 0x4000
-#                       For manual TP media selection                = 0x01
-#                       For manual TP/Nway media selection (DC21041) = 0x02
-#                       For manual BNC media selection               = 0x04
-#                       For manual AUI media selection               = 0x08
-#                       For manual BNC/AUI media selection (DC21040) = 0x10
-#                       For manual 10Mb/s mode selection   (DC21140) = 0x40
-#                       For manual 100Mb/s mode selection  (DC21140) = 0x80
+#                      a DE450 (AUI) use '-DDE4X5_AUTOSENSE=(_100Mb|AUI)']
+#                       For full auto media/mode selection           = AUTO
+#                       For manual TP media selection                = TP
+#                       For manual TP/Nway media selection (DC21041) = TP_NW
+#                       For manual BNC media selection               = BNC
+#                       For manual AUI media selection               = AUI
+#                       For manual BNC/AUI media selection (DC21040) = BNC_AUI
+#                       For manual 10Mb/s mode selection   (DC21140) = _10Mb
+#                       For manual 100Mb/s mode selection  (DC21140) = _100Mb
 #                       The DC21040 will default to TP if TP_NW is specified
 #                       The DC21041 will default to BNC if BNC_AUI is specified
 #                       The DC21140 needs it's speed to be manually set to
@@ -83,5 +83,6 @@ HP_OPTS               =
 PLIP_OPTS      =
 DEPCA_OPTS     = -DDEPCA_DEBUG=1
 EWRK3_OPTS     = -DEWRK3_DEBUG=1
-DE4X5_OPTS     = -DDE4X5_DEBUG=1 -DDE4X5_AUTOSENSE=0x4000
+DE4X5_OPTS     = -DDE4X5_DEBUG=1 -DDE4X5_AUTOSENSE=AUTO
 ELP_OPTS       = -DELP_DEBUG=1 -DELP_NEED_HARD_RESET=0
+
index 8e4adc56ef746816df2dc596c31114a37946178f..b06ed7dd4e1c17abdb36454f7097976f323daf97 100644 (file)
@@ -36,6 +36,10 @@ ifdef CONFIG_NET_IPIP
 NETDRV_OBJS := $(NETDRV_OBJS) tunnel.o
 endif
 
+ifdef CONFIG_HP100
+NETDRV_OBJS := $(NETDRV_OBJS) hp100.o
+endif
+
 ifdef CONFIG_WD80x3
 NETDRV_OBJS := $(NETDRV_OBJS) wd.o
 CONFIG_8390 = CONFIG_8390
@@ -212,7 +216,7 @@ else
 MODULES := $(MODULES) de4x5.o
 endif
 de4x5.o: de4x5.c CONFIG
-       $(CC) $(CPPFLAGS) $(CFLAGS) $(DE4x5_OPTS) -c $<
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(DE4X5_OPTS) -c $<
 
 ifdef CONFIG_NI52
 NETDRV_OBJS := $(NETDRV_OBJS) ni52.o
index 1bfb24a46378df9b6e607b4dff3f0bed0c306ade..2d5a881c5d9451a4966d732ce3f386d176d41567 100644 (file)
@@ -38,6 +38,7 @@
    ethernet adaptor have the name "eth[0123...]".
    */
 
+extern int hp100_probe(struct device *dev);
 extern int ultra_probe(struct device *dev);
 extern int wd_probe(struct device *dev);
 extern int el2_probe(struct device *dev);
@@ -74,12 +75,15 @@ extern int de620_probe(struct device *);
 static int
 ethif_probe(struct device *dev)
 {
-    short base_addr = dev->base_addr;
+    u_long base_addr = dev->base_addr;
 
-    if (base_addr < 0  ||  base_addr == 1)
+    if ((base_addr == 0xffe0)  ||  (base_addr == 1))
        return 1;               /* ENXIO */
 
     if (1
+#if defined(CONFIG_HP100)
+       && hp100_probe(dev)
+#endif 
 #if defined(CONFIG_ULTRA)
        && ultra_probe(dev)
 #endif
index 6abd17d5e0ad4741dd86991655828dc736d9f656..81bedafaac39cf183b5252ab20a617ddab58f932 100644 (file)
@@ -1,4 +1,4 @@
-/*  de4x5.c: A DIGITAL DE425/DE434/DE435 ethernet driver for linux.
+/*  de4x5.c: A DIGITAL DE425/DE434/DE435/DE500 ethernet driver for Linux.
 
     Copyright 1994, 1995 Digital Equipment Corporation.
 
@@ -68,7 +68,7 @@
     0) have a copy of the loadable modules code installed on your system.
     1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
     temporary directory.
-    2) edit the  source code near  line 1945 to reflect  the I/O address and
+    2) edit the  source code near  line 2762 to reflect  the I/O address and
     IRQ you're using, or assign these when loading by:
 
                    insmod de4x5.o irq=x io=y
     pause whilst the   driver figures out   where its media went).  My tests
     using ping showed that it appears to work....
 
-    A compile time  switch to allow  Zynx  recognition has been  added. This
+    A compile time  switch to allow  Znyx  recognition has been  added. This
     "feature" is in no way supported nor tested  in this driver and the user
     may use it at his/her sole discretion.  I have had 2 conflicting reports
-    that  my driver  will or   won't  work with   Zynx. Try Donald  Becker's
+    that  my driver  will or   won't  work with   Znyx. Try Donald  Becker's
     'tulip.c' if this driver doesn't work for  you. I will not be supporting
-    Zynx cards since I have no information on them  and can't test them in a
+    Znyx cards since I have no information on them  and can't test them in a
     system.
 
     TO DO:
                          Change media autodetection to allow manual setting.
                          Completed DE500 (DC21140) support.
       0.241   18-Apr-95   Interim release without DE500 Autosense Algorithm.
+      0.242   10-May-95   Minor changes
+      0.30    12-Jun-95   Timer fix for DC21140
+                          Portability changes.
+                         Add ALPHA changes from <jestabro@ant.tay1.dec.com>.
+                         Add DE500 semi automatic autosense.
+                         Add Link Fail interrupt TP failure detection.
+                         Add timer based link change detection.
+                         Plugged a memory leak in de4x5_queue_pkt().
+      0.31    13-Jun-95   Fixed PCI stuff for 1.3.1
+      0.32    26-Jun-95   Added verify_area() calls in de4x5_ioctl() from
+                          suggestion by <heiko@colossus.escape.de>
 
     =========================================================================
 */
 
-static char *version = "de4x5.c:v0.241 4/18/95 davies@wanton.lkg.dec.com\n";
+static char *version = "de4x5.c:v0.32 6/26/95 davies@wanton.lkg.dec.com\n";
 
 #include <linux/config.h>
 #ifdef MODULE
@@ -149,6 +160,7 @@ static char *version = "de4x5.c:v0.241 4/18/95 davies@wanton.lkg.dec.com\n";
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/malloc.h>
+#include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <asm/bitops.h>
@@ -175,9 +187,17 @@ static int de4x5_debug = 1;
 #ifdef DE4X5_AUTOSENSE              /* Should be done on a per adapter basis */
 static int de4x5_autosense = DE4X5_AUTOSENSE;
 #else
-static int de4x5_autosense = AUTO;      /* Do auto media/mode sensing */
+static int de4x5_autosense = AUTO;  /* Do auto media/mode sensing */
 #endif
 
+#ifdef DE4X5_FULL_DUPLEX            /* Should be done on a per adapter basis */
+static s32 de4x5_full_duplex = 1;
+#else
+static s32 de4x5_full_duplex = 0;
+#endif
+
+#define DE4X5_NDA 0xffe0            /* No Device (I/O) Address */
+
 /*
 ** Ethernet PROM defines
 */
@@ -187,11 +207,14 @@ static int de4x5_autosense = AUTO;      /* Do auto media/mode sensing */
 /*
 ** Ethernet Info
 */
-#define PKT_BUF_SZ     1544            /* Buffer size for each Tx/Rx buffer */
+#define PKT_BUF_SZ     1536            /* Buffer size for each Tx/Rx buffer */
 #define MAX_PKT_SZ     1514            /* Maximum ethernet packet length */
 #define MAX_DAT_SZ     1500            /* Maximum ethernet data length */
 #define MIN_DAT_SZ     1               /* Minimum ethernet data length */
 #define PKT_HDR_LEN     14              /* Addresses and data length info */
+#define FAKE_FRAME_LEN  (MAX_PKT_SZ + 1)
+#define QUEUE_PKT_TIMEOUT (300)         /* Jiffies */
+
 
 #define CRC_POLYNOMIAL_BE 0x04c11db7UL   /* Ethernet CRC, big endian */
 #define CRC_POLYNOMIAL_LE 0xedb88320UL   /* Ethernet CRC, little endian */
@@ -213,6 +236,7 @@ static int de4x5_autosense = AUTO;      /* Do auto media/mode sensing */
 */
 #define PCI_MAX_BUS_NUM 8
 #define DE4X5_PCI_TOTAL_SIZE 0x80        /* I/O address extent */
+#define DE4X5_CLASS_CODE     0x00020000  /* Network controller, Ethernet */
 
 /*
 ** Memory Alignment. Each descriptor is 4 longwords long. To force a
@@ -230,7 +254,7 @@ static int de4x5_autosense = AUTO;      /* Do auto media/mode sensing */
 #define ALIGN         ALIGN32          /* Keep the DC21040 happy... */
 #define CACHE_ALIGN   CAL_16LONG
 #define DESC_SKIP_LEN DSL_0            /* Must agree with DESC_ALIGN */
-/*#define DESC_ALIGN    u_long dummy[4]; / * Must agree with DESC_SKIP_LEN */
+/*#define DESC_ALIGN    u32 dummy[4]; / * Must agree with DESC_SKIP_LEN */
 #define DESC_ALIGN
 
 #ifndef IS_NOT_DEC                     /* See README.de4x5 for using this */
@@ -242,29 +266,25 @@ static int is_not_dec = 1;
 /*
 ** DE4X5 IRQ ENABLE/DISABLE
 */
-static u_long irq_mask = IMR_SEM | IMR_RIM | IMR_RUM | IMR_TIM | IMR_TUM ;
-
-static u_long irq_en   = IMR_NIM | IMR_AIM;
-
 #define ENABLE_IRQs { \
-    imr |= irq_en;\
+    imr |= lp->irq_en;\
     outl(imr, DE4X5_IMR);                   /* Enable the IRQs */\
 }
 
 #define DISABLE_IRQs {\
     imr = inl(DE4X5_IMR);\
-    imr &= ~irq_en;\
+    imr &= ~lp->irq_en;\
     outl(imr, DE4X5_IMR);                   /* Disable the IRQs */\
 }
 
 #define UNMASK_IRQs {\
-    imr |= irq_mask;\
+    imr |= lp->irq_mask;\
     outl(imr, DE4X5_IMR);                   /* Unmask the IRQs */\
 }
 
 #define MASK_IRQs {\
     imr = inl(DE4X5_IMR);\
-    imr &= ~irq_mask;\
+    imr &= ~lp->irq_mask;\
     outl(imr, DE4X5_IMR);                   /* Mask the IRQs */\
 }
 
@@ -288,6 +308,11 @@ static u_long irq_en   = IMR_NIM | IMR_AIM;
 */
 #define RESET_SIA outl(0, DE4X5_SICR);      /* Reset SIA connectivity regs */
 
+/*
+** DE500 AUTOSENSE TIMER INTERVAL (MILLISECS)
+*/
+#define DE4X5_AUTOSENSE_MS  250
+
 /*
 ** SROM Structure
 */
@@ -303,21 +328,21 @@ struct de4x5_srom {
 /*
 ** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
 ** and have sizes of both a power of 2 and a multiple of 4.
-** A size of 256 bytes for each buffer was chosen because over 90% of
+** A size of 256 bytes for each buffer could be chosen because over 90% of
 ** all packets in our network are <256 bytes long and 64 longword alignment
-** is possible.
+** is possible. 1536 showed better 'ttcp' performance. Take your pick. 32 TX
+** descriptors are needed for machines with an ALPHA CPU.
 */
 #define NUM_RX_DESC 8                        /* Number of RX descriptors */
-#define NUM_TX_DESC                        /* Number of TX descriptors */
+#define NUM_TX_DESC 32                       /* Number of TX descriptors */
 #define BUFF_ALLOC_RETRIES 10                /* In case of memory shortage */
 #define RX_BUFF_SZ 1536                      /* Power of 2 for kmalloc and */
                                              /* Multiple of 4 for DC21040 */
-
 struct de4x5_desc {
-    volatile long status;
-    u_long des1;
-    char *buf;
-    char *next;
+    volatile s32 status;
+    u32 des1;
+    u32 buf;
+    u32 next;
     DESC_ALIGN
 };
 
@@ -338,22 +363,26 @@ struct de4x5_private {
     char setup_frame[SETUP_FRAME_LEN];       /* Holds MCA and PA info. */
     struct enet_statistics stats;            /* Public stats */
     struct {
-       unsigned long bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
-       unsigned long unicast;
-       unsigned long multicast;
-       unsigned long broadcast;
-       unsigned long excessive_collisions;
-       unsigned long tx_underruns;
-       unsigned long excessive_underruns;
+       u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
+       u_int unicast;
+       u_int multicast;
+       u_int broadcast;
+       u_int excessive_collisions;
+       u_int tx_underruns;
+       u_int excessive_underruns;
     } pktStats;
     char rxRingSize;
     char txRingSize;
-    char bus;                                /* EISA or PCI */
-    u_short chipset;                         /* DC21040, DC21041 or DC21140 */
-    long media;                              /* Media (eg TP), mode (eg 100B)*/
+    int  bus;                                /* EISA or PCI */
+    int  bus_num;                            /* PCI Bus number */
+    int  chipset;                            /* DC21040, DC21041 or DC21140 */
+    s32  irq_mask;                           /* Interrupt Mask (Enable) bits */
+    s32  irq_en;                             /* Summary interrupt bits */
+    int  media;                              /* Media (eg TP), mode (eg 100B)*/
+    int  linkProb;                           /* Possible Link Problem */
     int  autosense;                          /* Allow/disallow autosensing */
     int  tx_enable;                          /* Enable descriptor polling */
-    char lostMedia;                          /* Possibly lost media */
+    int  lostMedia;                          /* Possibly lost media */
     int  setup_f;                            /* Setup frame filtering type */
 };
 
@@ -368,7 +397,6 @@ struct de4x5_private {
 #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
                         lp->tx_old+lp->txRingSize-lp->tx_new-1:\
                          lp->tx_old               -lp->tx_new-1)
-/*#define TX_BUFFS_AVAIL ((lp->tx_ring[lp->tx_new].status)>=0 ? 1 : 0)*/
 
 /*
 ** Public Functions
@@ -384,41 +412,46 @@ static int     de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd);
 /*
 ** Private functions
 */
-static int     de4x5_hw_init(struct device *dev, short iobase);
+static int     de4x5_hw_init(struct device *dev, u_long iobase);
 static int     de4x5_init(struct device *dev);
 static int     de4x5_rx(struct device *dev);
 static int     de4x5_tx(struct device *dev);
+static int     de4x5_ast(struct device *dev);
 
 static int     autoconf_media(struct device *dev);
 static void    create_packet(struct device *dev, char *frame, int len);
-static void    dce_us_delay(u_long usec);
-static void    dce_ms_delay(u_long msec);
-static void    load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb);
+static void    dce_us_delay(u32 usec);
+static void    dce_ms_delay(u32 msec);
+static void    load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb);
 static void    dc21040_autoconf(struct device *dev);
 static void    dc21041_autoconf(struct device *dev);
 static void    dc21140_autoconf(struct device *dev);
-static long    test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec);
-static long    ping_media(struct device *dev);
-static void    reset_init_sia(struct device *dev, long sicr, long strr, long sigr);
-static int     test_ans(struct device *dev, long irqs, long irq_mask, long msec);
-static void    load_ms_timer(struct device *dev, u_long msec);
-static int     EISA_signature(char *name, long eisa_id);
-static int     DevicePresent(short iobase);
-static short   srom_rd(u_short address, u_char offset);
-static void    srom_latch(u_long command, u_short address);
-static void    srom_command(u_long command, u_short address);
-static void    srom_address(u_long command, u_short address, u_char offset);
-static short   srom_data(u_long command, u_short address);
-/*static void    srom_busy(u_long command, u_short address);*/
-static void    sendto_srom(u_long command, u_short addr);
-static long    getfrom_srom(u_short addr);
+static int     test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
+/*static int     test_sym_link(struct device *dev, u32 msec);*/
+static int     ping_media(struct device *dev);
+static void    reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr);
+static int     test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec);
+static void    load_ms_timer(struct device *dev, u32 msec);
+static int     EISA_signature(char *name, s32 eisa_id);
+static int     DevicePresent(u_long iobase);
+static short   srom_rd(u_long address, u_char offset);
+static void    srom_latch(u_int command, u_long address);
+static void    srom_command(u_int command, u_long address);
+static void    srom_address(u_int command, u_long address, u_char offset);
+static short   srom_data(u_int command, u_long address);
+/*static void    srom_busy(u_int command, u_long address);*/
+static void    sendto_srom(u_int command, u_long addr);
+static int     getfrom_srom(u_long addr);
 static void    SetMulticastFilter(struct device *dev, int num_addrs, char *addrs);
-static int     aprom_crc (struct device *dev);
+static int     get_hw_addr(struct device *dev);
 
-static void    eisa_probe(struct device *dev, short iobase);
-static void    pci_probe(struct device *dev, short iobase);
-static struct  device *alloc_device(struct device *dev, int iobase);
+static void    eisa_probe(struct device *dev, u_long iobase);
+static void    pci_probe(struct device *dev, u_long iobase);
+static struct  device *alloc_device(struct device *dev, u_long iobase);
 static char    *build_setup_frame(struct device *dev, int mode);
+static void    disable_ast(struct device *dev);
+static void    enable_ast(struct device *dev, u32 time_out);
+static void    kick_tx(struct device *dev);
 
 #ifdef MODULE
 int  init_module(void);
@@ -439,6 +472,7 @@ static int num_de4x5s = 0, num_eth = 0;
 */
 static struct bus_type {
     int bus;
+    int bus_num;
     int device;
     int chipset;
     struct de4x5_srom srom;
@@ -449,30 +483,33 @@ static struct bus_type {
 ** Miscellaneous defines...
 */
 #define RESET_DE4X5 {\
-    long i;\
+    int i;\
     i=inl(DE4X5_BMR);\
+    dce_ms_delay(1);\
     outl(i | BMR_SWR, DE4X5_BMR);\
+    dce_ms_delay(1);\
     outl(i, DE4X5_BMR);\
-    for (i=0;i<5;i++) inl(DE4X5_BMR);\
+    dce_ms_delay(1);\
+    for (i=0;i<5;i++) {inl(DE4X5_BMR); dce_ms_delay(1);}\
+    dce_ms_delay(1);\
 }
 
 \f
 
 int de4x5_probe(struct device *dev)
 {
-  int tmp = num_de4x5s, iobase = dev->base_addr;
-  int status = -ENODEV;
+  int tmp = num_de4x5s, status = -ENODEV;
+  u_long iobase = dev->base_addr;
 
   if ((iobase == 0) && loading_module){
     printk("Autoprobing is not supported when loading a module based driver.\n");
     status = -EIO;
-  } else {                              /* First probe for the Ethernet */
-                                       /* Address PROM pattern */
+  } else {
     eisa_probe(dev, iobase);
     pci_probe(dev, iobase);
 
-    if ((tmp == num_de4x5s) && (iobase != 0)) {
-      printk("%s: de4x5_probe() cannot find device at 0x%04x.\n", dev->name, 
+    if ((tmp == num_de4x5s) && (iobase != 0) && loading_module) {
+      printk("%s: de4x5_probe() cannot find device at 0x%04lx.\n", dev->name, 
                                                                       iobase);
     }
 
@@ -490,12 +527,11 @@ int de4x5_probe(struct device *dev)
 }
 
 static int
-de4x5_hw_init(struct device *dev, short iobase)
+de4x5_hw_init(struct device *dev, u_long iobase)
 {
   struct bus_type *lp = &bus;
   int tmpbus, tmpchs, i, j, status=0;
   char *tmp;
-  u_long nicsr;
 
   /* Ensure we're not sleeping */
   if (lp->chipset == DC21041) {
@@ -505,7 +541,7 @@ de4x5_hw_init(struct device *dev, short iobase)
 
   RESET_DE4X5;
 
-  if (((nicsr=inl(DE4X5_STS)) & (STS_TS | STS_RS)) == 0) {
+  if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) == 0) {
     /* 
     ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
     */
@@ -525,16 +561,16 @@ de4x5_hw_init(struct device *dev, short iobase)
 
     if (*name != '\0') {                         /* found a board signature */
       dev->base_addr = iobase;
-      
       if (lp->bus == EISA) {
-       printk("%s: %s at %#3x (EISA slot %d)", 
-              dev->name, name, (u_short)iobase, (((u_short)iobase>>12)&0x0f));
+       printk("%s: %s at %04lx (EISA slot %ld)", 
+                               dev->name, name, iobase, ((iobase>>12)&0x0f));
       } else {                                   /* PCI port address */
-       printk("%s: %s at %#3x (PCI device %d)", dev->name, name, (u_short)iobase,lp->device);
+       printk("%s: %s at %04lx (PCI bus %d, device %d)", dev->name, name,
+                                             iobase, lp->bus_num, lp->device);
       }
        
       printk(", h/w address ");
-      status = aprom_crc(dev);
+      status = get_hw_addr(dev);
       for (i = 0; i < ETH_ALEN - 1; i++) {       /* get the ethernet addr. */
        printk("%2.2x:", dev->dev_addr[i]);
       }
@@ -597,9 +633,10 @@ de4x5_hw_init(struct device *dev, short iobase)
            for (i=0; i<NUM_RX_DESC; i++) {
              lp->rx_ring[i].status = 0;
              lp->rx_ring[i].des1 = RX_BUFF_SZ;
-             lp->rx_ring[i].buf = tmp + i * RX_BUFF_SZ;
-             lp->rx_ring[i].next = NULL;
+             lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ);
+             lp->rx_ring[i].next = (u32)NULL;
            }
+           barrier();
          }
        }
 
@@ -612,15 +649,19 @@ de4x5_hw_init(struct device *dev, short iobase)
          lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
 
          /* Tell the adapter where the TX/RX rings are located. */
-         outl((long)lp->rx_ring, DE4X5_RRBA);
-         outl((long)lp->tx_ring, DE4X5_TRBA);
+         outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+         outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+
+         /* Initialise the IRQ mask and Enable/Disable */
+         lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ;
+         lp->irq_en   = IMR_NIM | IMR_AIM;
 
          lp->tx_enable = TRUE;
 
          if (dev->irq < 2) {
 #ifndef MODULE
            unsigned char irqnum;
-           u_long omr;
+           s32 omr;
            autoirq_setup(0);
            
            omr = inl(DE4X5_OMR);
@@ -698,7 +739,8 @@ de4x5_hw_init(struct device *dev, short iobase)
   } else {                            /* Incorrectly initialised hardware */
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     if (lp) {
-      kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
+      kfree_s(bus_to_virt(lp->rx_ring[0].buf),
+                                           RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
     }
     if (dev->priv) {
       kfree_s(dev->priv, sizeof(struct de4x5_private) + ALIGN);
@@ -714,9 +756,9 @@ static int
 de4x5_open(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  short iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
   int i, status = 0;
-  long imr, omr, sts;
+  s32 imr, omr, sts;
 
   /*
   ** Wake up the adapter
@@ -745,35 +787,35 @@ de4x5_open(struct device *dev)
       }
       printk("\n");
       printk("Descriptor head addresses:\n");
-      printk("\t0x%8.8lx  0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
+      printk("\t0x%8.8lx  0x%8.8lx\n",(u_long)lp->rx_ring,(u_long)lp->tx_ring);
       printk("Descriptor addresses:\nRX: ");
       for (i=0;i<lp->rxRingSize-1;i++){
        if (i < 3) {
-         printk("0x%8.8lx  ",(long)&lp->rx_ring[i].status);
+         printk("0x%8.8lx  ",(u_long)&lp->rx_ring[i].status);
        }
       }
-      printk("...0x%8.8lx\n",(long)&lp->rx_ring[i].status);
+      printk("...0x%8.8lx\n",(u_long)&lp->rx_ring[i].status);
       printk("TX: ");
       for (i=0;i<lp->txRingSize-1;i++){
        if (i < 3) {
-         printk("0x%8.8lx  ", (long)&lp->tx_ring[i].status);
+         printk("0x%8.8lx  ", (u_long)&lp->tx_ring[i].status);
        }
       }
-      printk("...0x%8.8lx\n", (long)&lp->tx_ring[i].status);
+      printk("...0x%8.8lx\n", (u_long)&lp->tx_ring[i].status);
       printk("Descriptor buffers:\nRX: ");
       for (i=0;i<lp->rxRingSize-1;i++){
        if (i < 3) {
-         printk("0x%8.8lx  ",(long)lp->rx_ring[i].buf);
+         printk("0x%8.8x  ",lp->rx_ring[i].buf);
        }
       }
-      printk("...0x%8.8lx\n",(long)lp->rx_ring[i].buf);
+      printk("...0x%8.8x\n",lp->rx_ring[i].buf);
       printk("TX: ");
       for (i=0;i<lp->txRingSize-1;i++){
        if (i < 3) {
-         printk("0x%8.8lx  ", (long)lp->tx_ring[i].buf);
+         printk("0x%8.8x  ", lp->tx_ring[i].buf);
        }
       }
-      printk("...0x%8.8lx\n", (long)lp->tx_ring[i].buf);
+      printk("...0x%8.8x\n", lp->tx_ring[i].buf);
       printk("Ring size: \nRX: %d\nTX: %d\n", 
             (short)lp->rxRingSize, 
             (short)lp->txRingSize); 
@@ -827,9 +869,9 @@ static int
 de4x5_init(struct device *dev)
 {  
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  short iobase = dev->base_addr;
-  int status = 0;
-  long i, j, bmr, omr;
+  u_long iobase = dev->base_addr;
+  int i, j, status = 0;
+  s32 bmr, omr;
 
   /* Lock out other processes whilst setting up the hardware */
   set_bit(0, (void *)&dev->tbusy);
@@ -847,8 +889,8 @@ de4x5_init(struct device *dev)
     omr = OMR_SDP | OMR_SF;
     lp->setup_f = PERFECT;
   }
-  outl((long)lp->rx_ring, DE4X5_RRBA);
-  outl((long)lp->tx_ring, DE4X5_TRBA);
+  outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+  outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
 
   lp->rx_new = lp->rx_old = 0;
   lp->tx_new = lp->tx_old = 0;
@@ -861,6 +903,8 @@ de4x5_init(struct device *dev)
     lp->tx_ring[i].status = 0;
   }
 
+  barrier();
+
   /* Build the setup frame depending on filtering mode */
   SetMulticastFilter(dev, 0, NULL);
 
@@ -872,12 +916,12 @@ de4x5_init(struct device *dev)
   outl(omr|OMR_ST, DE4X5_OMR);
 
   /* Poll for completion of setup frame (interrupts are disabled for now) */
-  for (j=0, i=0;(i<100) && (j==0);i++) {
+  for (j=0, i=jiffies;(i==jiffies) && (j==0);) {
     if (lp->tx_ring[lp->tx_new].status >= 0) j=1;
   }
   outl(omr, DE4X5_OMR);                        /* Stop everything! */
 
-  if (i == 100) {
+  if (j == 0) {
     printk("%s: Setup frame timed out, status %08x\n", dev->name, 
                                                               inl(DE4X5_STS));
     status = -EIO;
@@ -900,27 +944,63 @@ de4x5_init(struct device *dev)
 static int
 de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
 {
-  volatile struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  int status = 0;
-  u_long imr, omr, sts;
-
-  sts = inl(DE4X5_STS);
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+  int i, status = 0;
+  s32 imr, omr, sts;
 
+  /*
+  ** Clean out the TX ring asynchronously to interrupts - sometimes the
+  ** interrupts are lost by delayed descriptor status updates relative to
+  ** the irq assertion, especially with a busy PCI bus.
+  */
+  if (set_bit(0, (void*)&dev->tbusy) == 0) {
+    cli();
+    de4x5_tx(dev);
+    dev->tbusy = 0;
+    sti();
+  }
+  
   /* 
   ** Transmitter timeout, possibly serious problems.
   ** The 'lostMedia' threshold accounts for transient errors that
   ** were noticed when switching media.
   */
   if (dev->tbusy || (lp->lostMedia > LOST_MEDIA_THRESHOLD)) {
-    int tickssofar = jiffies - dev->trans_start;
-    if (tickssofar < 10 && (lp->lostMedia <= LOST_MEDIA_THRESHOLD)) {
+    u_long tickssofar = jiffies - dev->trans_start;
+    if ((tickssofar < QUEUE_PKT_TIMEOUT) &&
+       (lp->lostMedia <= LOST_MEDIA_THRESHOLD)) {
       status = -1;
     } else {
-      printk("%s: transmit timed out, status %08x, tbusy:%d, lostMedia:%d tickssofar:%d, resetting.\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, tickssofar);
-       
+      if (de4x5_debug >= 1) {
+       printk("%s: transmit timed out, status %08x, tbusy:%d, lostMedia:%d tickssofar:%ld, resetting.\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, tickssofar);
+      }
+
       /* Stop and reset the TX and RX... */
       STOP_DE4X5;
+
+      /* Re-queue any skb's. */
+      for (i=lp->tx_old; i!=lp->tx_new; i=(++i)%lp->txRingSize) {
+       if (lp->skb[i] != NULL) {
+         if (lp->skb[i]->len != FAKE_FRAME_LEN) {
+           if (lp->tx_ring[i].status == T_OWN) {
+             dev_queue_xmit(lp->skb[i], dev, SOPRI_NORMAL);
+           } else {                               /* already sent */
+             dev_kfree_skb(lp->skb[i], FREE_WRITE);
+           }
+         } else {
+           dev_kfree_skb(lp->skb[i], FREE_WRITE);
+         }
+         lp->skb[i] = NULL;
+       }
+      }
+      if (skb->len != FAKE_FRAME_LEN) {
+       dev_queue_xmit(skb, dev, SOPRI_NORMAL);
+      } else {
+       dev_kfree_skb(skb, FREE_WRITE);
+      }
+
+      /* Initialise the hardware */
       status = de4x5_init(dev);
 
       /* Unmask DE4X5 board interrupts */
@@ -949,28 +1029,31 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
     }
   } else if (skb == NULL) {
     dev_tint(dev);
+  } else if (skb->len == FAKE_FRAME_LEN) {     /* Don't TX a fake frame! */
+    dev_kfree_skb(skb, FREE_WRITE);
   } else if (skb->len > 0) {
-
-    /* 
-    ** Block a timer-based transmit from overlapping.  This could better be
-    ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well. 
-    */
-    if (set_bit(0, (void*)&dev->tbusy) != 0)
+    /* Enforce 1 process per h/w access */
+    if (set_bit(0, (void*)&dev->tbusy) != 0) { 
       printk("%s: Transmitter access conflict.\n", dev->name);
+      status = -1;                             /* Re-queue packet */
+    } else {
+      cli();
+      if (TX_BUFFS_AVAIL) {                    /* Fill in a Tx ring entry */
+       load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
+       if (lp->tx_enable) {
+         outl(POLL_DEMAND, DE4X5_TPD);        /* Start the TX */
+       }
 
-    if (TX_BUFFS_AVAIL) {                       /* Fill in a Tx ring entry */
-      load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
-      if (lp->tx_enable) {
-       outl(POLL_DEMAND, DE4X5_TPD);           /* Start the TX */
-      }
-
-      lp->tx_new = (++lp->tx_new) % lp->txRingSize; /* Ensure a wrap */
-       
-      dev->trans_start = jiffies;
-    }
+       lp->tx_new = (++lp->tx_new) % lp->txRingSize; /* Ensure a wrap */
+       dev->trans_start = jiffies;
 
-    if (TX_BUFFS_AVAIL) {
-      dev->tbusy = 0;                           /* Another pkt may be queued */
+       if (TX_BUFFS_AVAIL) {
+         dev->tbusy = 0;                      /* Another pkt may be queued */
+       }
+      } else {                                 /* Ring full - re-queue */
+       status = -1;
+      }
+      sti();
     }
   }
 
@@ -979,14 +1062,22 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
 
 /*
 ** The DE4X5 interrupt handler. 
+** 
+** I/O Read/Writes through intermediate PCI bridges are never 'posted',
+** so that the asserted interrupt always has some real data to work with -
+** if these I/O accesses are ever changed to memory accesses, ensure the
+** STS write is read immediately to complete the transaction if the adapter
+** is not on bus 0. Lost interrupts can still occur when the PCI bus load
+** is high and descriptor status bits cannot be set before the associated
+** interrupt is asserted and this routine entered.
 */
 static void
 de4x5_interrupt(int irq, struct pt_regs *regs)
 {
     struct device *dev = (struct device *)(irq2dev_map[irq]);
     struct de4x5_private *lp;
-    int iobase;
-    u_long imr, omr, sts;
+    s32 imr, omr, sts;
+    u_long iobase;
 
     if (dev == NULL) {
        printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
@@ -997,29 +1088,32 @@ de4x5_interrupt(int irq, struct pt_regs *regs)
       if (dev->interrupt)
        printk("%s: Re-entering the interrupt handler.\n", dev->name);
 
+      DISABLE_IRQs;                      /* Ensure non re-entrancy */
       dev->interrupt = MASK_INTERRUPTS;
 
-      /* 
-      ** Get the interrupt information and disable them. 
-      ** The device read will ensure pending buffers are flushed
-      ** in intermediate PCI bridges, so that the posted interrupt
-      ** has some real data to work with.
-      */
-      sts = inl(DE4X5_STS);
-      MASK_IRQs;
+      while ((sts = inl(DE4X5_STS)) & lp->irq_mask) { /* Read IRQ status */
+       outl(sts, DE4X5_STS);            /* Reset the board interrupts */
+
+       if (sts & (STS_RI | STS_RU))     /* Rx interrupt (packet[s] arrived) */
+         de4x5_rx(dev);
 
-      outl(sts, DE4X5_STS);              /* Reset the board interrupts */
+       if (sts & (STS_TI | STS_TU))     /* Tx interrupt (packet sent) */
+         de4x5_tx(dev); 
 
-      if (sts & (STS_RI | STS_RU))      /* Rx interrupt (packet[s] arrived) */
-       de4x5_rx(dev);
+       if (sts & STS_TM)                /* Autosense tick */
+         de4x5_ast(dev);
 
-      if (sts & (STS_TI | STS_TU))       /* Tx interrupt (packet sent) */
-       de4x5_tx(dev); 
+       if (sts & STS_LNF) {             /* TP Link has failed */
+         lp->lostMedia = LOST_MEDIA_THRESHOLD + 1;
+         lp->irq_mask &= ~IMR_LFM;
+         kick_tx(dev);
+       }
 
-      if (sts & STS_SE) {                /* Bus Error */
-       STOP_DE4X5;
-       printk("%s: Fatal bus error occurred, sts=0x%08lx, device stopped.\n", 
-                                                              dev->name, sts);
+       if (sts & STS_SE) {              /* Bus Error */
+         STOP_DE4X5;
+         printk("%s: Fatal bus error occured, sts=%#8x, device stopped.\n",
+                                                             dev->name, sts);
+       }
       }
 
       if (TX_BUFFS_AVAIL && dev->tbusy) {/* Any resources available? */
@@ -1028,8 +1122,7 @@ de4x5_interrupt(int irq, struct pt_regs *regs)
       }
 
       dev->interrupt = UNMASK_INTERRUPTS;
-
-      UNMASK_IRQs;
+      ENABLE_IRQs;
     }
 
     return;
@@ -1040,7 +1133,7 @@ de4x5_rx(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
   int i, entry;
-  volatile long status;
+  s32 status;
   char *buf;
 
   for (entry = lp->rx_new; lp->rx_ring[entry].status >= 0;entry = lp->rx_new) {
@@ -1066,22 +1159,17 @@ de4x5_rx(struct device *dev)
        
          if (entry < lp->rx_old) {         /* Wrapped buffer */
            short len = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
-           memcpy(skb->data, lp->rx_ring[lp->rx_old].buf, len);
-           memcpy(skb->data + len, lp->rx_ring[0].buf, pkt_len - len);
+           memcpy(skb->data, bus_to_virt(lp->rx_ring[lp->rx_old].buf), len);
+           memcpy(skb->data + len, bus_to_virt(lp->rx_ring[0].buf), pkt_len - len);
          } else {                          /* Linear buffer */
-           memcpy(skb->data, lp->rx_ring[lp->rx_old].buf, pkt_len);
+           memcpy(skb->data, bus_to_virt(lp->rx_ring[lp->rx_old].buf), pkt_len);
          }
 
-         /* 
-         ** Notify the upper protocol layers that there is another 
-         ** packet to handle
-         */
+         /* Push up the protocol stack */
          skb->protocol=eth_type_trans(skb,dev);
          netif_rx(skb);
 
-         /*
-         ** Update stats
-         */
+         /* Update stats */
          lp->stats.rx_packets++;
          for (i=1; i<DE4X5_PKT_STAT_SZ-1; i++) {
            if (pkt_len < (i*DE4X5_PKT_BIN_SZ)) {
@@ -1091,13 +1179,13 @@ de4x5_rx(struct device *dev)
          }
          buf = skb->data;                  /* Look at the dest addr */
          if (buf[0] & 0x01) {              /* Multicast/Broadcast */
-           if ((*(long *)&buf[0] == -1) && (*(short *)&buf[4] == -1)) {
+           if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) {
              lp->pktStats.broadcast++;
            } else {
              lp->pktStats.multicast++;
            }
-         } else if ((*(long *)&buf[0] == *(long *)&dev->dev_addr[0]) &&
-                    (*(short *)&buf[4] == *(short *)&dev->dev_addr[4])) {
+         } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) &&
+                    (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
            lp->pktStats.unicast++;
          }
          
@@ -1115,8 +1203,10 @@ de4x5_rx(struct device *dev)
       /* Change buffer ownership for this last frame, back to the adapter */
       for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
        lp->rx_ring[lp->rx_old].status = R_OWN;
+       barrier();
       }
       lp->rx_ring[entry].status = R_OWN;
+      barrier();
     }
 
     /*
@@ -1135,8 +1225,9 @@ static int
 de4x5_tx(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int entry, iobase = dev->base_addr;
-  long status;
+  u_long iobase = dev->base_addr;
+  int entry;
+  s32 status;
 
   for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
     status = lp->tx_ring[entry].status;
@@ -1151,8 +1242,12 @@ de4x5_tx(struct device *dev)
       if (status & TD_EC)  lp->pktStats.excessive_collisions++;
       if (status & TD_DE)  lp->stats.tx_aborted_errors++;
 
-      if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) {
+      if ((status != 0x7fffffff) &&              /* Not setup frame */
+         (status & (TD_LO | TD_NC | TD_EC | TD_LF))) {
        lp->lostMedia++;
+       if (lp->lostMedia > LOST_MEDIA_THRESHOLD) { /* Trip autosense */
+         kick_tx(dev);
+       }
       } else {
        outl(POLL_DEMAND, DE4X5_TPD);            /* Restart a stalled TX */
       }
@@ -1163,6 +1258,7 @@ de4x5_tx(struct device *dev)
     /* Free the buffer if it's not a setup frame. */
     if (lp->skb[entry] != NULL) {
       dev_kfree_skb(lp->skb[entry], FREE_WRITE);
+      lp->skb[entry] = NULL;
     }
 
     /* Update all the pointers */
@@ -1172,12 +1268,58 @@ de4x5_tx(struct device *dev)
   return 0;
 }
 
+static int
+de4x5_ast(struct device *dev)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+  s32 gep;
+
+  disable_ast(dev);
+
+  if (lp->chipset == DC21140) {
+    gep = inl(DE4X5_GEP);
+    if (((lp->media == _100Mb) &&  (gep & GEP_SLNK)) ||
+       ((lp->media == _10Mb)  &&  (gep & GEP_LNP))  ||
+       ((lp->media == _10Mb)  && !(gep & GEP_SLNK)) ||
+        (lp->media == NC)) {
+      if (lp->linkProb || ((lp->media == NC) && (!(gep & GEP_LNP)))) {
+       lp->lostMedia = LOST_MEDIA_THRESHOLD + 1;
+       lp->linkProb = 0;
+       kick_tx(dev);
+      } else {
+       switch(lp->media) {
+       case NC:
+         lp->linkProb = 0;
+         enable_ast(dev, DE4X5_AUTOSENSE_MS);
+         break;
+
+       case _10Mb:
+         lp->linkProb = 1;                    /* Flag a potential problem */
+         enable_ast(dev, 1500);
+         break;
+
+       case _100Mb:
+         lp->linkProb = 1;                    /* Flag a potential problem */
+         enable_ast(dev, 4000);
+         break;
+       }
+      }
+    } else {
+      lp->linkProb = 0;                        /* Link OK */
+      enable_ast(dev, DE4X5_AUTOSENSE_MS);
+    }
+  }
+
+  return 0;
+}
+
 static int
 de4x5_close(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  u_long imr, omr;
+  u_long iobase = dev->base_addr;
+  s32 imr, omr;
 
   dev->start = 0;
   dev->tbusy = 1;
@@ -1215,22 +1357,24 @@ static struct enet_statistics *
 de4x5_get_stats(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
 
   lp->stats.rx_missed_errors = (int) (inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
     
   return &lp->stats;
 }
 
-static void load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb)
+static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
 
-  lp->tx_ring[lp->tx_new].buf = buf;
+  lp->tx_ring[lp->tx_new].buf = virt_to_bus(buf);
   lp->tx_ring[lp->tx_new].des1 &= TD_TER;
   lp->tx_ring[lp->tx_new].des1 |= flags;
   lp->skb[lp->tx_new] = skb;
+  barrier();
   lp->tx_ring[lp->tx_new].status = T_OWN;
+  barrier();
 
   return;
 }
@@ -1248,7 +1392,7 @@ static void
 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
 
   /* First, double check that the adapter is open */
   if (irq2dev_map[dev->irq] != NULL) {
@@ -1279,9 +1423,10 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int i, j, bit, byte, iobase = dev->base_addr;
-  u_short hashcode;
-  u_long crc, omr, poly = CRC_POLYNOMIAL_LE;
+  u_long iobase = dev->base_addr;
+  int i, j, bit, byte;
+  u16 hashcode;
+  u32 omr, crc, poly = CRC_POLYNOMIAL_LE;
   char *pa;
 
   omr = inl(DE4X5_OMR);
@@ -1336,14 +1481,14 @@ static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs)
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-static void eisa_probe(struct device *dev, short ioaddr)
+static void eisa_probe(struct device *dev, u_long ioaddr)
 {
-  int i, maxSlots;
-  int status;
-  u_short vendor, device, iobase;
+  int i, maxSlots, status;
+  u_short vendor, device;
+  s32 cfid;
+  u_long iobase;
   struct bus_type *lp = &bus;
   char name[DE4X5_STRLEN];
-  long cfid;
 
   if (!ioaddr && autoprobed) return ;            /* Been here before ! */
   if ((ioaddr < 0x1000) && (ioaddr > 0)) return; /* PCI MODULE special */
@@ -1372,17 +1517,17 @@ static void eisa_probe(struct device *dev, short ioaddr)
        /* Write the PCI Configuration Registers */
        outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
        outl(0x00004000, PCI_CFLT);
-       outl((u_long)iobase, PCI_CBIO);
+       outl(iobase, PCI_CBIO);
 
        if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
          if ((dev = alloc_device(dev, iobase)) != NULL) {
            if ((status = de4x5_hw_init(dev, iobase)) == 0) {
              num_de4x5s++;
            }
-         num_eth++;
+           num_eth++;
          }
        } else if (autoprobed) {
-         printk("%s: region already allocated at 0x%04x.\n", dev->name, iobase);
+         printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
        }
       }
     }
@@ -1393,17 +1538,26 @@ static void eisa_probe(struct device *dev, short ioaddr)
 
 /*
 ** PCI bus I/O device probe
+** NB: PCI I/O accesses and Bus Mastering are enabled by the PCI BIOS, not
+** the driver. Some PCI BIOS's, pre V2.1, need the slot + features to be
+** enabled by the user first in the set up utility. Hence we just check for
+** enabled features and silently ignore the card if they're not.
+**
+** STOP PRESS: Some BIOS's __require__ the driver to enable the bus mastering
+** bit. Here, check for I/O accesses and then set BM. If you put the card in
+** a non BM slot, you're on your own (and complain to the PC vendor that your
+** PC doesn't conform to the PCI standard)!
 */
 #define PCI_DEVICE    (dev_num << 3)
 #define PCI_LAST_DEV  32
 
-static void pci_probe(struct device *dev, short ioaddr)
-
+static void pci_probe(struct device *dev, u_long ioaddr)
 {
   u_char irq;
-  u_short pb, dev_num, dev_last;
-  u_short vendor, device, status;
-  u_long class, iobase;
+  u_char pb, pbus, dev_num, dnum, dev_fn;
+  u_short vendor, device, index, status;
+  u_int class = DE4X5_CLASS_CODE;
+  u_int iobase;
   struct bus_type *lp = &bus;
 
   if (!ioaddr && autoprobed) return ;        /* Been here before ! */
@@ -1412,26 +1566,25 @@ static void pci_probe(struct device *dev, short ioaddr)
     lp->bus = PCI;
 
     if (ioaddr < 0x1000) {
-      pb = (u_short)(ioaddr >> 8);
-      dev_num = (u_short)(ioaddr & 0xff);
+      pbus = (u_short)(ioaddr >> 8);
+      dnum = (u_short)(ioaddr & 0xff);
     } else {
-      pb = 0;
-      dev_num = 0;
-    }
-    if (ioaddr > 0) {
-      dev_last = (dev_num < PCI_LAST_DEV) ? dev_num + 1 : PCI_LAST_DEV;
-    } else {
-      dev_last = PCI_LAST_DEV;
+      pbus = 0;
+      dnum = 0;
     }
+    
+    for (index=0; 
+        (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+        index++) {
+      dev_num = PCI_SLOT(dev_fn);
 
-    for (; (dev_num < dev_last) && (dev != NULL); dev_num++) {
-      pcibios_read_config_dword(pb, PCI_DEVICE, PCI_CLASS_REVISION, &class);
-      if (class != 0xffffffff) {
+      if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
        pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
        pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
        if (is_DC21040 || is_DC21041 || is_DC21140) {
          /* Set the device number information */
          lp->device = dev_num;
+         lp->bus_num = pb;
 
          /* Set the chipset information */
          lp->chipset = device;
@@ -1439,27 +1592,32 @@ static void pci_probe(struct device *dev, short ioaddr)
          /* Get the board I/O address */
          pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
          iobase &= CBIO_MASK;
-         
+
          /* Fetch the IRQ to be used */
          pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq);
 
-         /* Enable I/O Accesses and Bus Mastering */
+         /* Check if I/O accesses and Bus Mastering are enabled */
          pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
-         status |= PCI_COMMAND_IO | PCI_COMMAND_MASTER;
-         pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
-
-         /* If there is a device and I/O region is open, initialise dev. */
-         if ((DevicePresent(DE4X5_APROM) == 0) || is_not_dec) {
-           if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
-             if ((dev = alloc_device(dev, iobase)) != NULL) {
-               dev->irq = irq;
-               if ((status = de4x5_hw_init(dev, iobase)) == 0) {
-                 num_de4x5s++;
+         if (status & PCI_COMMAND_IO) {
+           if (!(status & PCI_COMMAND_MASTER)) {
+             status |= PCI_COMMAND_MASTER;
+             pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
+             pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+           }
+           if (status & PCI_COMMAND_MASTER) {
+             if ((DevicePresent(DE4X5_APROM) == 0) || is_not_dec) {
+               if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
+                 if ((dev = alloc_device(dev, iobase)) != NULL) {
+                   dev->irq = irq;
+                   if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+                     num_de4x5s++;
+                   }
+                   num_eth++;
+                 }
+               } else if (autoprobed) {
+                 printk("%s: region already allocated at 0x%04x.\n", dev->name, (u_short)iobase);
                }
-               num_eth++;
              }
-           } else if (autoprobed) {
-             printk("%s: region already allocated at 0x%04x.\n", dev->name, (u_short)iobase);
            }
          }
        }
@@ -1474,7 +1632,7 @@ static void pci_probe(struct device *dev, short ioaddr)
 ** Allocate the device by pointing to the next available space in the
 ** device structure. Should one not be available, it is created.
 */
-static struct device *alloc_device(struct device *dev, int iobase)
+static struct device *alloc_device(struct device *dev, u_long iobase)
 {
   int addAutoProbe = 0;
   struct device *tmp = NULL, *ret;
@@ -1485,7 +1643,7 @@ static struct device *alloc_device(struct device *dev, int iobase)
   */
   if (!loading_module) {
     while (dev->next != NULL) {
-      if ((dev->base_addr == 0xffe0) || (dev->base_addr == 0)) break;
+      if ((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0)) break;
       dev = dev->next;                     /* walk through eth device list */
       num_eth++;                           /* increment eth device number */
     }
@@ -1505,7 +1663,7 @@ static struct device *alloc_device(struct device *dev, int iobase)
     ** If memory could not be allocated, print an error message.
     */
     if ((dev->next == NULL) &&  
-       !((dev->base_addr == 0xffe0) || (dev->base_addr == 0))){
+       !((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0))){
       dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
                                           GFP_KERNEL);
 
@@ -1539,13 +1697,13 @@ static struct device *alloc_device(struct device *dev, int iobase)
     */
     if (ret != NULL) {
       if (addAutoProbe) {
-       for (; (tmp->next!=NULL) && (tmp->base_addr!=0xffe0); tmp=tmp->next);
+       for (; (tmp->next!=NULL) && (tmp->base_addr!=DE4X5_NDA); tmp=tmp->next);
 
        /*
        ** If no more device structures and can't use the current one, malloc
        ** one up. If memory could not be allocated, print an error message.
        */
-       if ((tmp->next == NULL) && !(tmp->base_addr == 0xffe0)) {
+       if ((tmp->next == NULL) && !(tmp->base_addr == DE4X5_NDA)) {
          tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8,
                                               GFP_KERNEL);
          tmp = tmp->next;                     /* point to the new device */
@@ -1589,7 +1747,16 @@ static struct device *alloc_device(struct device *dev, int iobase)
 static int autoconf_media(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
+
+  lp->tx_enable = YES;
+  if (de4x5_debug > 0 ) {
+    if (lp->chipset != DC21140) {
+      printk("%s: Searching for media... ",dev->name);
+    } else {
+      printk("%s: Searching for mode... ",dev->name);
+    }
+  }
 
   if (lp->chipset == DC21040) {
     lp->media = (lp->autosense == AUTO ? TP : lp->autosense);
@@ -1598,34 +1765,35 @@ static int autoconf_media(struct device *dev)
     lp->media = (lp->autosense == AUTO ? TP_NW : lp->autosense);
     dc21041_autoconf(dev);
   } else if (lp->chipset == DC21140) {
-    /* Force 10Mb/s (_100Mb for 100Mb/s) */
+    disable_ast(dev);
     lp->media = (lp->autosense == AUTO ? _10Mb : lp->autosense);
     dc21140_autoconf(dev);
   }
 
-  if (de4x5_debug >= 1 ) {
+  if (de4x5_debug > 0 ) {
     if (lp->chipset != DC21140) {
-      printk("%s: Media is %s\n",dev->name,
-                                       (lp->media == NC  ? "unconnected!" :
-                                       (lp->media == TP  ? "TP." :
-                                       (lp->media == ANS ? "TP/Nway." :
-                                       (lp->media == BNC ? "BNC." : 
-                                       (lp->media == AUI ? "AUI." : 
-                                                            "BNC/AUI."
-                                       ))))));
+      printk("media is %s\n", (lp->media == NC  ? "unconnected!" :
+                             (lp->media == TP  ? "TP." :
+                             (lp->media == ANS ? "TP/Nway." :
+                             (lp->media == BNC ? "BNC." : 
+                             (lp->media == AUI ? "AUI." : 
+                                                 "BNC/AUI."
+                             ))))));
     } else {
-      printk("%s: Mode is forced to %s\n",dev->name,
-                                       (lp->media == NC      ? "link down.":
-                                       (lp->media == _100Mb  ? "100Mb/s." :
-                                       (lp->media == _10Mb   ? "10Mb/s." :
-                                                               "\?\?\?"
-                                       ))));
+      printk("mode is %s\n",(lp->media == NC      ? "link down.":
+                           (lp->media == _100Mb  ? "100Mb/s." :
+                           (lp->media == _10Mb   ? "10Mb/s." :
+                                                   "\?\?\?"
+                           ))));
     }
   }
 
   if (lp->media) {
     lp->lostMedia = 0;
     inl(DE4X5_MFC);                         /* Zero the lost frames counter */
+    if ((lp->media == TP) || (lp->media == ANS)) {
+      lp->irq_mask |= IMR_LFM;
+    }
   }
   dce_ms_delay(10);
 
@@ -1635,9 +1803,9 @@ static int autoconf_media(struct device *dev)
 static void dc21040_autoconf(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  u_long i, sisr = 0, linkBad;
-  u_long t_3s    = 3000;
+  u_long iobase = dev->base_addr;
+  int i, linkBad;
+  s32 sisr = 0, t_3s    = 3000;
 
   switch (lp->media) {
   case TP:
@@ -1656,7 +1824,7 @@ static void dc21040_autoconf(struct device *dev)
   case AUI:
   case BNC_AUI:
     reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
-    dce_ms_delay(330);
+    dce_ms_delay(500);
     linkBad = ping_media(dev);
     if (linkBad && (lp->autosense == AUTO)) {
       lp->media = NC;
@@ -1665,8 +1833,13 @@ static void dc21040_autoconf(struct device *dev)
     break;
 
   case NC:
+#ifdef i386
     reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
     break;
+#else
+    /* JAE: for Alpha, default to BNC/AUI, *not* TP */
+    reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
+#endif  /* i386 */
   }
 
   return;
@@ -1681,8 +1854,8 @@ static void dc21040_autoconf(struct device *dev)
 static void dc21041_autoconf(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  u_long sts, irqs, irq_mask, omr;
+  u_long iobase = dev->base_addr;
+  s32 sts, irqs, irq_mask, omr;
 
   switch (lp->media) {
   case TP_NW:
@@ -1766,18 +1939,20 @@ static void dc21041_autoconf(struct device *dev)
 static void dc21140_autoconf(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  u_long omr;
+  u_long iobase = dev->base_addr;
+  s32 omr;
 
   switch(lp->media) {
   case _100Mb:      /* Set 100Mb/s, MII Port with PCS Function and Scrambler */
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
+    omr |= (de4x5_full_duplex ? OMR_FD : 0);   /* Set up Full Duplex */
     outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);
     outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);
     break;
 
   case _10Mb:       /* Set conventional 10Mb/s ENDEC interface */
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
+    omr |= (de4x5_full_duplex ? OMR_FD : 0);   /* Set up Full Duplex */
     outl(omr | OMR_TTM, DE4X5_OMR);
     outl(GEP_FDXD, DE4X5_GEP);
     break;
@@ -1786,11 +1961,12 @@ static void dc21140_autoconf(struct device *dev)
   return;
 }
 
-static long test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec)
+static int
+test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  long sts, time, csr12;
+  u_long iobase = dev->base_addr;
+  s32 sts, time, csr12;
 
   reset_init_sia(dev, csr13, csr14, csr15);
 
@@ -1815,18 +1991,36 @@ static long test_media(struct device *dev, long irqs, long irq_mask, long csr13,
 
   return sts;
 }
+/*
+static int test_sym_link(struct device *dev, u32 msec)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+  u32 gep, time;
+
+  / * Set link_fail_inhibit_timer * /
+  load_ms_timer(dev, msec);
 
+  / * Poll for timeout or SYM_LINK=0 * /
+  do {
+    time = inl(DE4X5_GPT) & GPT_VAL;
+    gep = inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP);
+  } while ((time > 0) && (gep & GEP_SLNK));
+
+  return gep;
+}
+*/
 /*
 ** Send a packet onto the media and watch for send errors that indicate the
 ** media is bad or unconnected.
 */
-static long ping_media(struct device *dev)
+static int ping_media(struct device *dev)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int entry, iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
+  int i, entry, linkBad;
+  s32 omr, t_3s = 4000;
   char frame[64];
-  long i, linkBad, omr;
-  u_long t_3s    = 3000;
 
   create_packet(dev, frame, sizeof(frame));
 
@@ -1854,11 +2048,11 @@ static long ping_media(struct device *dev)
 ** Check the Auto Negotiation State. Return OK when a link pass interrupt
 ** is received and the auto-negotiation status is NWAY OK.
 */
-static int test_ans(struct device *dev, long irqs, long irq_mask, long msec)
+static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
-  long sts, ans;
+  u_long iobase = dev->base_addr;
+  s32 sts, ans;
 
   outl(irq_mask, DE4X5_IMR);
 
@@ -1881,10 +2075,10 @@ static int test_ans(struct device *dev, long irqs, long irq_mask, long msec)
 /*
 **
 */
-static void reset_init_sia(struct device *dev, long sicr, long strr, long sigr)
+static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
 
   RESET_SIA;
   outl(sigr, DE4X5_SIGR);
@@ -1897,12 +2091,22 @@ static void reset_init_sia(struct device *dev, long sicr, long strr, long sigr)
 /*
 ** Load the timer on the DC21041 and 21140. Max time is 13.42 secs.
 */
-static void load_ms_timer(struct device *dev, u_long msec)
+static void load_ms_timer(struct device *dev, u32 msec)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-  int iobase = dev->base_addr;
+  u_long iobase = dev->base_addr;
+  s32 i = 2048, j;
 
-  outl((long)(msec * 10000)/2048, DE4X5_GPT);
+  if (lp->chipset == DC21140) {
+    j = inl(DE4X5_OMR);
+    if ((j & OMR_TTM) && (j & OMR_PS)) {          /* 10Mb/s MII */
+      i = 8192;
+    } else if ((~j & OMR_TTM) && (j & OMR_PS)) {  /* 100Mb/s MII */
+      i = 819;
+    }
+  }
+
+  outl((s32)(msec * 10000)/i, DE4X5_GPT);
 
   return;
 }
@@ -1931,7 +2135,7 @@ static void create_packet(struct device *dev, char *frame, int len)
 /*
 ** Known delay in microseconds
 */
-static void dce_us_delay(u_long usec)
+static void dce_us_delay(u32 usec)
 {
   udelay(usec);
 
@@ -1941,9 +2145,9 @@ static void dce_us_delay(u_long usec)
 /*
 ** Known delay in milliseconds, in millisecond steps.
 */
-static void dce_ms_delay(u_long msec)
+static void dce_ms_delay(u32 msec)
 {
-  u_long i;
+  u_int i;
   
   for (i=0; i<msec; i++) {
     dce_us_delay(1000);
@@ -1956,13 +2160,13 @@ static void dce_ms_delay(u_long msec)
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-int EISA_signature(char *name, long eisa_id)
+static int EISA_signature(char *name, s32 eisa_id)
 {
-  unsigned long i;
+  u_int i;
   char *signatures[] = DE4X5_SIGNATURE;
   char ManCode[DE4X5_STRLEN];
   union {
-    long ID;
+    s32 ID;
     char Id[4];
   } Eisa;
   int status = 0;
@@ -1999,24 +2203,23 @@ int EISA_signature(char *name, long eisa_id)
 ** ethernet address for later read out.
 */
 
-static int DevicePresent(short aprom_addr)
+static int DevicePresent(u_long aprom_addr)
 {
   union {
     struct {
-      u_long a;
-      u_long b;
+      u32 a;
+      u32 b;
     } llsig;
-    char Sig[sizeof(long) << 1];
+    char Sig[sizeof(u32) << 1];
   } dev;
   char data;
-  long i, j, tmp;
+  int i, j, tmp, status = 0;
   short sigLength;
-  int status = 0;
   struct bus_type *lp = &bus;
 
   dev.llsig.a = ETH_PROM_SIG;
   dev.llsig.b = ETH_PROM_SIG;
-  sigLength = sizeof(long) << 1;
+  sigLength = sizeof(u32) << 1;
 
   if (lp->chipset == DC21040) {
     for (i=0,j=0;(j<sigLength) && (i<PROBE_LENGTH+sigLength-1);i++) {
@@ -2051,12 +2254,11 @@ static int DevicePresent(short aprom_addr)
   return status;
 }
 
-static int aprom_crc(struct device *dev)
+static int get_hw_addr(struct device *dev)
 {
-  int iobase = dev->base_addr;
-  long i, k, tmp;
-  unsigned short j,chksum;
-  unsigned char status = 0;
+  u_long iobase = dev->base_addr;
+  int i, k, tmp, status = 0;
+  u_short j,chksum;
   struct bus_type *lp = &bus;
 
   for (i=0,k=0,j=0;j<3;j++) {
@@ -2107,7 +2309,7 @@ static int aprom_crc(struct device *dev)
 /*
 ** SROM Read
 */
-static short srom_rd(u_short addr, u_char offset)
+static short srom_rd(u_long addr, u_char offset)
 {
   sendto_srom(SROM_RD | SROM_SR, addr);
 
@@ -2118,7 +2320,7 @@ static short srom_rd(u_short addr, u_char offset)
   return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
 }
 
-static void srom_latch(u_long command, u_short addr)
+static void srom_latch(u_int command, u_long addr)
 {
   sendto_srom(command, addr);
   sendto_srom(command | DT_CLK, addr);
@@ -2127,7 +2329,7 @@ static void srom_latch(u_long command, u_short addr)
   return;
 }
 
-static void srom_command(u_long command, u_short addr)
+static void srom_command(u_int command, u_long addr)
 {
   srom_latch(command, addr);
   srom_latch(command, addr);
@@ -2136,9 +2338,9 @@ static void srom_command(u_long command, u_short addr)
   return;
 }
 
-static void srom_address(u_long command, u_short addr, u_char offset)
+static void srom_address(u_int command, u_long addr, u_char offset)
 {
-  long i;
+  int i;
   char a;
 
   a = (char)(offset << 2);
@@ -2150,16 +2352,17 @@ static void srom_address(u_long command, u_short addr, u_char offset)
   i = (getfrom_srom(addr) >> 3) & 0x01;
   if (i != 0) {
     printk("Bad SROM address phase.....\n");
+/*    printk(".");*/
   }
 
   return;
 }
 
-static short srom_data(u_long command, u_short addr)
+static short srom_data(u_int command, u_long addr)
 {
   int i;
   short word = 0;
-  long tmp;
+  s32 tmp;
 
   for (i=0; i<16; i++) {
     sendto_srom(command  | DT_CLK, addr);
@@ -2175,7 +2378,7 @@ static short srom_data(u_long command, u_short addr)
 }
 
 /*
-static void srom_busy(u_long command, u_short addr)
+static void srom_busy(u_int command, u_long addr)
 {
   sendto_srom((command & 0x0000ff00) | DT_CS, addr);
 
@@ -2189,7 +2392,7 @@ static void srom_busy(u_long command, u_short addr)
 }
 */
 
-static void sendto_srom(u_long command, u_short addr)
+static void sendto_srom(u_int command, u_long addr)
 {
   outl(command, addr);
   dce_us_delay(1);
@@ -2197,9 +2400,9 @@ static void sendto_srom(u_long command, u_short addr)
   return;
 }
 
-static long getfrom_srom(u_short addr)
+static int getfrom_srom(u_long addr)
 {
-  long tmp;
+  s32 tmp;
 
   tmp = inl(addr);
   dce_us_delay(1);
@@ -2238,6 +2441,44 @@ static char *build_setup_frame(struct device *dev, int mode)
   return pa;                     /* Points to the next entry */
 }
 
+static void enable_ast(struct device *dev, u32 time_out)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+
+  lp->irq_mask |= IMR_TMM;
+  outl(lp->irq_mask, DE4X5_IMR);
+  load_ms_timer(dev, time_out);
+
+  return;
+}
+
+static void disable_ast(struct device *dev)
+{
+  struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+  u_long iobase = dev->base_addr;
+
+  lp->irq_mask &= ~IMR_TMM;
+  outl(lp->irq_mask, DE4X5_IMR);
+  load_ms_timer(dev, 0);
+
+  return;
+}
+
+static void kick_tx(struct device *dev)
+{
+  struct sk_buff *skb;
+
+  if ((skb = alloc_skb(0, GFP_ATOMIC)) != NULL) {
+    skb->len= FAKE_FRAME_LEN;
+    skb->arp=1;
+    skb->dev=dev;
+    dev_queue_xmit(skb, dev, SOPRI_NORMAL);
+  }
+
+  return;
+}
+
 /*
 ** Perform IOCTL call functions here. Some are privileged operations and the
 ** effective uid is checked in those cases.
@@ -2246,12 +2487,13 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
   struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
   struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
-  int i, j, iobase = dev->base_addr, status = 0;
-  u_long omr;
+  u_long iobase = dev->base_addr;
+  int i, j, status = 0;
+  s32 omr;
   union {
-    unsigned char  addr[(HASH_TABLE_LEN * ETH_ALEN)];
-    unsigned short sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-    unsigned long  lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
+    u8  addr[(HASH_TABLE_LEN * ETH_ALEN)];
+    u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+    u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
   } tmp;
 
   switch(ioc->cmd) {
@@ -2260,29 +2502,32 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
       tmp.addr[i] = dev->dev_addr[i];
     }
     ioc->len = ETH_ALEN;
-    memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    }
 
     break;
   case DE4X5_SET_HWADDR:             /* Set the hardware address */
     if (suser()) {
-      memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
-      for (i=0; i<ETH_ALEN; i++) {
-       dev->dev_addr[i] = tmp.addr[i];
-      }
-      build_setup_frame(dev, PHYS_ADDR_ONLY);
-      /* Set up the descriptor and give ownership to the card */
-      while (set_bit(0, (void *)&dev->tbusy) != 0); /* Wait for lock to free */
-      if (lp->setup_f == HASH_PERF) {
-       load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
+      if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) {
+       memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN);
+       for (i=0; i<ETH_ALEN; i++) {
+         dev->dev_addr[i] = tmp.addr[i];
+       }
+       build_setup_frame(dev, PHYS_ADDR_ONLY);
+       /* Set up the descriptor and give ownership to the card */
+       while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
+       if (lp->setup_f == HASH_PERF) {
+         load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
                                                        SETUP_FRAME_LEN, NULL);
-      } else {
-       load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+       } else {
+         load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
                                                        SETUP_FRAME_LEN, NULL);
+       }
+       lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+       outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
+       dev->tbusy = 0;                              /* Unlock the TX ring */
       }
-      lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-      outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
-      dev->tbusy = 0;                              /* Unlock the TX ring */
-
     } else {
       status = -EPERM;
     }
@@ -2314,15 +2559,21 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
     break;
   case DE4X5_GET_MCA:                /* Get the multicast address table */
     ioc->len = (HASH_TABLE_LEN >> 3);
-    memcpy_tofs(ioc->data, lp->setup_frame, 192); 
+    if (!(status = verify_area(VERIFY_WRITE, ioc->data, 192))) {
+      memcpy_tofs(ioc->data, lp->setup_frame, 192); 
+    }
 
     break;
   case DE4X5_SET_MCA:                /* Set a multicast address */
     if (suser()) {
       if (ioc->len != HASH_TABLE_LEN) {         /* MCA changes */
-       memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+       if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len))) {
+         memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+         set_multicast_list(dev, ioc->len, tmp.addr);
+       }
+      } else {
+       set_multicast_list(dev, ioc->len, NULL);
       }
-      set_multicast_list(dev, ioc->len, tmp.addr);
     } else {
       status = -EPERM;
     }
@@ -2348,8 +2599,10 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
     break;
   case DE4X5_GET_STATS:              /* Get the driver statistics */
     cli();
-    memcpy_tofs(ioc->data, &lp->pktStats, sizeof(lp->pktStats)); 
-    ioc->len = DE4X5_PKT_STAT_SZ;
+    ioc->len = sizeof(lp->pktStats);
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, sizeof(lp->pktStats)))) {
+      memcpy_tofs(ioc->data, &lp->pktStats, ioc->len); 
+    }
     sti();
 
     break;
@@ -2365,29 +2618,36 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
     break;
   case DE4X5_GET_OMR:                /* Get the OMR Register contents */
     tmp.addr[0] = inl(DE4X5_OMR);
-    memcpy_tofs(ioc->data, tmp.addr, 1);
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
+      memcpy_tofs(ioc->data, tmp.addr, 1);
+    }
 
     break;
   case DE4X5_SET_OMR:                /* Set the OMR Register contents */
     if (suser()) {
-      memcpy_fromfs(tmp.addr, ioc->data, 1);
-      outl(tmp.addr[0], DE4X5_OMR);
+      if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) {
+       memcpy_fromfs(tmp.addr, ioc->data, 1);
+       outl(tmp.addr[0], DE4X5_OMR);
+      }
     } else {
       status = -EPERM;
     }
 
     break;
   case DE4X5_GET_REG:                /* Get the DE4X5 Registers */
-    tmp.lval[0] = inl(DE4X5_STS);
-    tmp.lval[1] = inl(DE4X5_BMR);
-    tmp.lval[2] = inl(DE4X5_IMR);
-    tmp.lval[3] = inl(DE4X5_OMR);
-    tmp.lval[4] = inl(DE4X5_SISR);
-    tmp.lval[5] = inl(DE4X5_SICR);
-    tmp.lval[6] = inl(DE4X5_STRR);
-    tmp.lval[7] = inl(DE4X5_SIGR);
-    memcpy_tofs(ioc->data, tmp.addr, 32);
-
+    j = 0;
+    tmp.lval[0] = inl(DE4X5_STS); j+=4;
+    tmp.lval[1] = inl(DE4X5_BMR); j+=4;
+    tmp.lval[2] = inl(DE4X5_IMR); j+=4;
+    tmp.lval[3] = inl(DE4X5_OMR); j+=4;
+    tmp.lval[4] = inl(DE4X5_SISR); j+=4;
+    tmp.lval[5] = inl(DE4X5_SICR); j+=4;
+    tmp.lval[6] = inl(DE4X5_STRR); j+=4;
+    tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
+    ioc->len = j;
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    }
     break;
 
 #define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
@@ -2399,35 +2659,35 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
       tmp.addr[j++] = dev->dev_addr[i];
     }
     tmp.addr[j++] = lp->rxRingSize;
-    tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
-    tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
+    tmp.lval[j>>2] = (s32)lp->rx_ring; j+=4;
+    tmp.lval[j>>2] = (s32)lp->tx_ring; j+=4;
 
     for (i=0;i<lp->rxRingSize-1;i++){
       if (i < 3) {
-       tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+       tmp.lval[j>>2] = (s32)&lp->rx_ring[i].status; j+=4;
       }
     }
-    tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+    tmp.lval[j>>2] = (s32)&lp->rx_ring[i].status; j+=4;
     for (i=0;i<lp->txRingSize-1;i++){
       if (i < 3) {
-       tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
+       tmp.lval[j>>2] = (s32)&lp->tx_ring[i].status; j+=4;
       }
     }
-    tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
-
+    tmp.lval[j>>2] = (s32)&lp->tx_ring[i].status; j+=4;
+      
     for (i=0;i<lp->rxRingSize-1;i++){
       if (i < 3) {
-       tmp.lval[j>>2] = (long)lp->rx_ring[i].buf; j+=4;
+       tmp.lval[j>>2] = (s32)lp->rx_ring[i].buf; j+=4;
       }
     }
-    tmp.lval[j>>2] = (long)lp->rx_ring[i].buf; j+=4;
+    tmp.lval[j>>2] = (s32)lp->rx_ring[i].buf; j+=4;
     for (i=0;i<lp->txRingSize-1;i++){
       if (i < 3) {
-       tmp.lval[j>>2] = (long)lp->tx_ring[i].buf; j+=4;
+       tmp.lval[j>>2] = (s32)lp->tx_ring[i].buf; j+=4;
       }
     }
-    tmp.lval[j>>2] = (long)lp->tx_ring[i].buf; j+=4;
-
+    tmp.lval[j>>2] = (s32)lp->tx_ring[i].buf; j+=4;
+      
     for (i=0;i<lp->rxRingSize;i++){
       tmp.lval[j>>2] = lp->rx_ring[i].status; j+=4;
     }
@@ -2443,12 +2703,14 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
     tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
     tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
     tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; 
-
+    
     tmp.addr[j++] = lp->txRingSize;
     tmp.addr[j++] = dev->tbusy;
-
+      
     ioc->len = j;
-    memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    }
 
     break;
   default:
@@ -2466,8 +2728,8 @@ static struct device thisDE4X5 = {
   0x2000, 10, /* I/O address, IRQ */
   0, 0, 0, NULL, de4x5_probe };
        
-int io=0x000b; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-int irq=10;    /* or use the insmod io= irq= options           */
+static int io=0x000b;  /* EDIT THESE LINES FOR YOUR CONFIGURATION */
+static int irq=10;     /* or use the insmod io= irq= options           */
 
 int
 init_module(void)
@@ -2487,15 +2749,15 @@ cleanup_module(void)
   if (MOD_IN_USE) {
     printk("%s: device busy, remove delayed\n",thisDE4X5.name);
   } else {
-    release_region(thisDE4X5.base_addr, (lp->bus == PCI ? 
-                                                    DE4X5_PCI_TOTAL_SIZE :
-                                                    DE4X5_EISA_TOTAL_SIZE));
     if (lp) {
-      kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
+      kfree_s(bus_to_virt(lp->rx_ring[0].buf), RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
     }
     kfree_s(thisDE4X5.priv, sizeof(struct de4x5_private) + ALIGN);
     thisDE4X5.priv = NULL;
 
+    release_region(thisDE4X5.base_addr, (lp->bus == PCI ? 
+                                                    DE4X5_PCI_TOTAL_SIZE :
+                                                    DE4X5_EISA_TOTAL_SIZE));
     unregister_netdev(&thisDE4X5);
   }
 }
index ee5c41b0a8ba33620b564f7c591e9805874937e6..dcf572113ccfda3a5300a9118322b1dcf562be1f 100644 (file)
 /*
 ** PCI Configuration Base I/O Address Register (PCI_CBIO)
 */
-#define CBIO_MASK   0x0000ff80       /* Base I/O Address Mask */
+#define CBIO_MASK   0xffffff80       /* Base I/O Address Mask */
 #define CBIO_IOSI   0x00000001       /* I/O Space Indicator (RO, value is 1) */
 
 /*
@@ -642,6 +642,3 @@ struct de4x5_ioctl {
 #define DE4X5_GET_OMR           0x0c /* Get the OMR Register contents */
 #define DE4X5_SET_OMR           0x0d /* Set the OMR Register contents */
 #define DE4X5_GET_REG           0x0e /* Get the DE4X5 Registers */
-
-
-
index 354eab0c398ebdc22d0c1281f0275ec592bcb357..07e9fab2d11364f182c3d3ca3211ca2b4efa8660 100644 (file)
@@ -1,6 +1,6 @@
 /*  depca.c: A DIGITAL DEPCA  & EtherWORKS ethernet driver for linux.
 
-    Written 1994 by David C. Davies.
+    Written 1994, 1995 by David C. Davies.
 
 
                       Copyright 1994 David C. Davies
@@ -8,6 +8,8 @@
                         United States Government
         (as represented by the Director, National Security Agency).  
 
+               Copyright 1995  Digital Equipment Corporation.
+
 
     This software may be used and distributed according to the terms of
     the GNU Public License, incorporated herein by reference.
 
     This  driver will NOT work   for the DE203,  DE204  and DE205 series  of
     cards,  since they have  a  new custom ASIC in   place of the AMD  LANCE
-    chip. 
+    chip.  See the 'ewrk3.c'   driver in the  Linux  source tree for running
+    those cards.
+
+    I have benchmarked the driver with a  DE100 at 595kB/s to (542kB/s from)
+    a DECstation 5000/200.
 
     The author may be reached as davies@wanton.lkg.dec.com or
     Digital Equipment Corporation, 550 King Street, Littleton MA 01460.
 
     =========================================================================
-    The driver was based on the 'lance.c' driver from Donald Becker which is
-    included with the standard driver distribution for linux. Modifications
-    were made to most routines and the hardware recognition routines were
-    written from scratch. Primary references used were:
+
+    The  driver was originally based  on   the 'lance.c' driver from  Donald
+    Becker   which  is included with  the  standard  driver distribution for
+    linux.  V0.4  is  a complete  re-write  with only  the kernel  interface
+    remaining from the original code.
 
     1) Lance.c code in /linux/drivers/net/
     2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
     8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
        Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
     
-    Peter Bauer's depca.c (V0.5) was referred to when debugging this driver.
-    The hash filter code was  derived from Reference  3 and has been  tested
-    only to the extent that the Table  A-1, page A-7,  was confirmed to fill
-    the   filter bit   positions  correctly.  Hash   filtering  is  not  yet
-    implemented in the current driver set.
+
+    Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
+    driver.
 
     The original DEPCA  card requires that the  ethernet ROM address counter
     be enabled to count and has an 8 bit NICSR.  The ROM counter enabling is
     The ability to load this driver as a loadable module has been added. To
     utilise this ability, you have to do <8 things:
 
+    0) have a copy of the loadable modules code installed on your system.
     1) copy depca.c from the  /linux/drivers/net directory to your favourite
     temporary directory.
-    2) edit the  source code near  line 1530 to reflect  the I/O address and
-    IRQ you're using.
+    2) if you wish, edit the  source code near  line 1530 to reflect the I/O
+    address and IRQ you're using (see also 5).
     3) compile  depca.c, but include -DMODULE in  the command line to ensure
     that the correct bits are compiled (see end of source code).
     4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
     kernel with the depca configuration turned off and reboot.
-    5) insmod depca.o
+    5) insmod depca.o [irq=7] [io=0x200]
+       [Alan Cox: Changed the code to allow command line irq/io assignments]
     6) run the net startup bits for your eth?? interface manually 
     (usually /etc/rc.inet[12] at boot time). 
     7) enjoy!
 
     Note that autoprobing is not allowed in loadable modules - the system is
-    already up and running and you're messing with interrupts. Also, there
-    is no way to check on the number of depcas installed at the moment.
+    already up and running and you're messing with interrupts.
 
     To unload a module, turn off the associated interface 
     'ifconfig eth?? down' then 'rmmod depca'.
 
-    [Alan Cox: Changed to split off the module values as ints for insmod
-     
-     you can now do insmod depca.c irq=7 io=0x200 ]
-     
 
     TO DO:
     ------
 
-    1. Implement the 2k buffer mode - does anyone need it??
 
     Revision History
     ----------------
       0.382    9-feb-95   Fix recognition bug reported by <bkm@star.rl.ac.uk>.
       0.383   22-feb-95   Fix for conflict with VESA SCSI reported by
                           <stromain@alf.dec.com>
+      0.384   17-mar-95   Fix a ring full bug reported by <bkm@star.rl.ac.uk>
+      0.385    3-apr-95   Fix a recognition bug reported by 
+                                                <ryan.niemi@lastfrontier.com>
+      0.386   21-apr-95   Fix the last fix...sorry, must be galloping senility
+      0.40    25-May-95   Rewrite for portability & updated.
+                          ALPHA support from <jestabro@amt.tay1.dec.com>
+      0.41    26-Jun-95   Added verify_area() calls in depca_ioctl() from
+                          suggestion by <heiko@colossus.escape.de>
 
     =========================================================================
 */
 
-static char *version = "depca.c:v0.383 2/22/94 davies@wanton.lkg.dec.com\n";
+static char *version = "depca.c:v0.41 5/26/95 davies@wanton.lkg.dec.com\n";
 
 #include <linux/config.h>
 #ifdef MODULE
@@ -188,6 +197,7 @@ static char *version = "depca.c:v0.383 2/22/94 davies@wanton.lkg.dec.com\n";
 #define MOD_DEC_USE_COUNT
 #endif /* MODULE */
 
+#include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -196,6 +206,7 @@ static char *version = "depca.c:v0.383 2/22/94 davies@wanton.lkg.dec.com\n";
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
+#include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -212,81 +223,84 @@ static int depca_debug = DEPCA_DEBUG;
 static int depca_debug = 1;
 #endif
 
-#ifndef PROBE_LENGTH
-#define PROBE_LENGTH    32
-#endif
+#define DEPCA_NDA 0xffe0            /* No Device Address */
 
+/*
+** Ethernet PROM defines
+*/
+#define PROBE_LENGTH    32
 #define ETH_PROM_SIG    0xAA5500FFUL
 
-#ifndef DEPCA_SIGNATURE
+/*
+** Set the number of Tx and Rx buffers. Ensure that the memory requested
+** here is <= to the amount of shared memory set up by the board switches.
+** The number of descriptors MUST BE A POWER OF 2.
+**
+** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
+*/
+#define NUM_RX_DESC     8               /* Number of RX descriptors */
+#define NUM_TX_DESC     8               /* Number of TX descriptors */
+#define RX_BUFF_SZ     1536            /* Buffer size for each Rx buffer */
+#define TX_BUFF_SZ     1536            /* Buffer size for each Tx buffer */
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+
+/*
+** EISA bus defines
+*/
+#define DEPCA_EISA_IO_PORTS 0x0c00       /* I/O port base address, slot 0 */
+#define MAX_EISA_SLOTS 16
+#define EISA_SLOT_INC 0x1000
+
+/*
+** ISA Bus defines
+*/
+#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
+#define DEPCA_IO_PORTS {0x300, 0x200, 0}
+#define DEPCA_TOTAL_SIZE 0x10
+static short mem_chkd = 0;
+
+/*
+** Name <-> Adapter mapping
+*/
 #define DEPCA_SIGNATURE {"DEPCA",\
                         "DE100","DE101",\
                          "DE200","DE201","DE202",\
                         "DE210",\
                          "DE422",\
                          ""}
-#define DEPCA_NAME_LENGTH 8
-#endif
-
-#ifndef DEPCA_RAM_BASE_ADDRESSES
-#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
-#endif
-static short mem_chkd = 0;               /* holds which base addrs have been */
-                                        /* checked, for multi-DEPCA case */
+static enum {DEPCA, de100, de101, de200, de201, de202, de210, de422, unknown} adapter;
 
-#ifndef DEPCA_IO_PORTS
-#define DEPCA_IO_PORTS {0x300, 0x200, 0}
-#endif
-
-#ifndef DEPCA_TOTAL_SIZE
-#define DEPCA_TOTAL_SIZE 0x10
-#endif
-
-#ifndef MAX_NUM_DEPCAS
+/*
+** Miscellaneous info...
+*/
+#define DEPCA_STRLEN 16
 #define MAX_NUM_DEPCAS 2
-#endif
-
-#ifndef DEPCA_EISA_IO_PORTS 
-#define DEPCA_EISA_IO_PORTS 0x0c00       /* I/O port base address, slot 0 */
-#endif
-
-#ifndef MAX_EISA_SLOTS
-#define MAX_EISA_SLOTS 8
-#endif
 
 /*
-** Set the number of Tx and Rx buffers. 
+** Memory Alignment. Each descriptor is 4 longwords long. To force a
+** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
+** DESC_ALIGN. ALIGN aligns the start address of the private memory area
+** and hence the RX descriptor ring's first entry. 
 */
-#ifndef DEPCA_BUFFER_LOG_SZ
-#define RING_SIZE      16              /* 16 buffers */
-#else
-#define RING_SIZE      (1 << (DEPCA_BUFFERS_LOG_SZ))
-#endif  /* DEPCA_BUFFER_LOG_SZ */
-
-#define PKT_BUF_SZ     1544            /* Buffer size for each Tx/Rx buffer */
-#define PKT_SZ         1514            /* Maximum ethernet packet length */
-#define DAT_SZ         1500            /* Maximum ethernet data length */
-#define PKT_HDR_LEN     14              /* Addresses and data length info */
-
-#ifdef HAVE_MULTICAST
-#ifndef CRC_POLYNOMIAL
-#define CRC_POLYNOMIAL 0x04c11db7       /* Ethernet CRC polynomial */
-#endif /* CRC_POLYNOMIAL */
-#endif /* HAVE_MULTICAST */
+#define ALIGN4      ((u_long)4 - 1)       /* 1 longword align */
+#define ALIGN8      ((u_long)8 - 1)       /* 2 longword (quadword) align */
+#define ALIGN         ALIGN8              /* Keep the LANCE happy... */
 
 /*
 ** The DEPCA Rx and Tx ring descriptors. 
 */
-struct depca_rx_head {
-    volatile long base;
-    short buf_length;          /* This length is negative 2's complement! */
-    short msg_length;          /* This length is "normal". */
+struct depca_rx_desc {
+    volatile s32 base;
+    s16 buf_length;            /* This length is negative 2's complement! */
+    s16 msg_length;            /* This length is "normal". */
 };
 
-struct depca_tx_head {
-    volatile long base;
-    short length;              /* This length is negative 2's complement! */
-    short misc;                 /* Errors and TDR info */
+struct depca_tx_desc {
+    volatile s32 base;
+    s16 length;                        /* This length is negative 2's complement! */
+    s16 misc;                   /* Errors and TDR info */
 };
 
 #define LA_MASK 0x0000ffff      /* LANCE address mask for mapping network RAM
@@ -296,72 +310,103 @@ struct depca_tx_head {
 ** The Lance initialization block, described in databook, in common memory.
 */
 struct depca_init {
-    unsigned short mode;       /* Mode register */
-    unsigned char phys_addr[ETH_ALEN]; /* Physical ethernet address */
-    unsigned short filter[4];  /* Multicast filter. */
-    unsigned long rx_ring;             /* Rx ring base pointer & ring length */
-    unsigned long tx_ring;     /* Tx ring base pointer & ring length */
+    u16 mode;                  /* Mode register */
+    u8  phys_addr[ETH_ALEN];   /* Physical ethernet address */
+    u8  mcast_table[8];                /* Multicast Hash Table. */
+    u32 rx_ring;               /* Rx ring base pointer & ring length */
+    u32 tx_ring;               /* Tx ring base pointer & ring length */
 };
 
+#define DEPCA_PKT_STAT_SZ 16
+#define DEPCA_PKT_BIN_SZ  128                /* Should be >=100 unless you
+                                                increase DEPCA_PKT_STAT_SZ */
 struct depca_private {
-    char devname[8];            /* Device Product String */
-    struct depca_rx_head *rx_ring; /* Pointer to start of RX descriptor ring */
-    struct depca_tx_head *tx_ring; /* Pointer to start of TX descriptor ring */
-    struct depca_init  init_block;/* Initialization block */
-    long bus_offset;            /* (E)ISA bus address offset vs LANCE */
-    long dma_buffs;            /* Start address of Rx and Tx buffers. */
-    int        cur_rx, cur_tx;         /* The next free ring entry */
-    int dirty_rx, dirty_tx;    /* The ring entries to be free()ed. */
-    int dma;
+    char devname[DEPCA_STRLEN];    /* Device Product String                  */
+    char adapter_name[DEPCA_STRLEN];/* /proc/ioports string                  */
+    char adapter;                  /* Adapter type                           */
+    struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
+    struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */
+    struct depca_init  init_block;/* Shadow Initialization block            */
+    char *rx_memcpy[NUM_RX_DESC];  /* CPU virt address of sh'd memory buffs  */
+    char *tx_memcpy[NUM_TX_DESC];  /* CPU virt address of sh'd memory buffs  */
+    u_long bus_offset;             /* (E)ISA bus address offset vs LANCE     */
+    u_long sh_mem;                /* Physical start addr of shared mem area */
+    u_long dma_buffs;             /* LANCE Rx and Tx buffers start address. */
+    int        rx_new, tx_new;            /* The next free ring entry               */
+    int rx_old, tx_old;                   /* The ring entries to be free()ed.       */
     struct enet_statistics stats;
-    char depca_na;              /* NICSR access width: 0=>byte, 1=>word */
-    short ringSize;             /* ring size based on available memory */
-    short rmask;                /* modulus mask based on ring size */
-    long rlen;                  /* log2(ringSize) for the descriptors */
+    struct {                       /* Private stats counters                 */
+       u32 bins[DEPCA_PKT_STAT_SZ];
+       u32 unicast;
+       u32 multicast;
+       u32 broadcast;
+       u32 excessive_collisions;
+       u32 tx_underruns;
+       u32 excessive_underruns;
+    } pktStats;
+    int txRingMask;                /* TX ring mask                           */
+    int rxRingMask;                /* RX ring mask                           */
+    s32 rx_rlen;                   /* log2(rxRingMask+1) for the descriptors */
+    s32 tx_rlen;                   /* log2(txRingMask+1) for the descriptors */
 };
 
+/*
+** The transmit ring full condition is described by the tx_old and tx_new
+** pointers by:
+**    tx_old            = tx_new    Empty ring
+**    tx_old            = tx_new+1  Full ring
+**    tx_old+txRingMask = tx_new    Full ring  (wrapped condition)
+*/
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+                        lp->tx_old+lp->txRingMask-lp->tx_new:\
+                         lp->tx_old               -lp->tx_new-1)
+
 /*
 ** Public Functions
 */
-static int depca_open(struct device *dev);
-static int depca_start_xmit(struct sk_buff *skb, struct device *dev);
-static void depca_interrupt(int irq, struct pt_regs * regs);
-static int depca_close(struct device *dev);
+static int    depca_open(struct device *dev);
+static int    depca_start_xmit(struct sk_buff *skb, struct device *dev);
+static void   depca_interrupt(int irq, struct pt_regs * regs);
+static int    depca_close(struct device *dev);
+static int    depca_ioctl(struct device *dev, struct ifreq *rq, int cmd);
 static struct enet_statistics *depca_get_stats(struct device *dev);
-#ifdef HAVE_MULTICAST
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
-#endif
+static void   set_multicast_list(struct device *dev,int num_addrs,void *addrs);
 
 /*
 ** Private functions
 */
-static int  depca_probe1(struct device *dev, short ioaddr);
-static void depca_init_ring(struct device *dev);
-static int  depca_rx(struct device *dev);
-static int  depca_tx(struct device *dev);
-
-static void LoadCSRs(struct device *dev);
-static int  InitRestartDepca(struct device *dev);
-static char *DepcaSignature(unsigned long mem_addr);
-static int  DevicePresent(short ioaddr);
-static int  EISA_signature(short iobase);
-#ifdef HAVE_MULTICAST
-static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table);
-#endif
-
-#ifndef MODULE
-static struct device *isa_probe(struct device *dev);
-static struct device *eisa_probe(struct device *dev);
-static struct device *alloc_device(struct device *dev, int ioaddr);
-
-static int num_depcas = 0, num_eth = 0, autoprobed = 0;
-
-#else
-int  init_module(void);
-void cleanup_module(void);
+static int    depca_hw_init(struct device *dev, u_long ioaddr);
+static void   depca_init_ring(struct device *dev);
+static int    depca_rx(struct device *dev);
+static int    depca_tx(struct device *dev);
+
+static void   LoadCSRs(struct device *dev);
+static int    InitRestartDepca(struct device *dev);
+static void   DepcaSignature(char *name, u_long paddr);
+static int    DevicePresent(u_long ioaddr);
+static int    get_hw_addr(struct device *dev);
+static int    EISA_signature(char *name, s32 eisa_id);
+static void   SetMulticastFilter(struct device *dev,int num_addrs,char *addrs);
+static void   isa_probe(struct device *dev, u_long iobase);
+static void   eisa_probe(struct device *dev, u_long iobase);
+static struct device *alloc_device(struct device *dev, u_long iobase);
+static int    load_packet(struct device *dev, struct sk_buff *skb);
 
+#ifdef MODULE
+int           init_module(void);
+void          cleanup_module(void);
+static int    autoprobed = 1, loading_module = 1;
+# else
+static u_char de1xx_irq[] = {2,3,4,5,7,0};
+static u_char de2xx_irq[] = {5,9,10,11,15,0};
+static u_char de422_irq[] = {5,9,10,11,0};
+static u_char *depca_irq;
+static int    autoprobed = 0, loading_module = 0;
 #endif /* MODULE */
 
+static char   name[DEPCA_STRLEN];
+static int    num_depcas = 0, num_eth = 0;
+
 /*
 ** Miscellaneous defines...
 */
@@ -369,309 +414,238 @@ void cleanup_module(void);
     outw(CSR0, DEPCA_ADDR);\
     outw(STOP, DEPCA_DATA)
 
-
 \f
 
 int depca_probe(struct device *dev)
 {
-    short base_addr = dev->base_addr;
-    int status = -ENODEV;
-#ifndef MODULE
-    struct device *eth0;
-#endif
+  int tmp = num_depcas, status = -ENODEV;
+  u_long iobase = dev->base_addr;
 
-    if (base_addr > 0x1ff) {         /* Check a single specified location. */
-      if (DevicePresent(base_addr) == 0) { /* Is DEPCA really here? */
-       status = depca_probe1(dev, base_addr);
-      }
-    } else if (base_addr > 0) {              /* Don't probe at all. */
-      status = -ENXIO;
-
-#ifdef MODULE
-    } else {
-      printk("Autoprobing is not supported when loading a module based driver.\n");
-      status = -EIO;
-#else
-    } else if (!autoprobed) {         /* First probe for the DEPCA test */
-                                      /* pattern in ROM */
-      eth0=isa_probe(dev);
-      eth0=eisa_probe(eth0);
-      if (dev->priv) status=0;
-      autoprobed = 1;
-    } else {
-      status = -ENXIO;
-#endif /* MODULE */
+  if ((iobase == 0) && loading_module){
+    printk("Autoprobing is not supported when loading a module based driver.\n");
+    status = -EIO;
+  } else {
+    isa_probe(dev, iobase);
+    eisa_probe(dev, iobase);
 
+    if ((tmp == num_depcas) && (iobase != 0) && loading_module) {
+      printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name, 
+                                                                      iobase);
     }
 
-    if (status) dev->base_addr = base_addr;
+    /*
+    ** Walk the device list to check that at least one device
+    ** initialised OK
+    */
+    for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
+
+    if (dev->priv) status = 0;
+    if (iobase == 0) autoprobed = 1;
+  }
 
-    return status;                     /* ENODEV would be more accurate. */
+  return status;
 }
 
 static int
-depca_probe1(struct device *dev, short ioaddr)
+depca_hw_init(struct device *dev, u_long ioaddr)
 {
-    struct depca_private *lp;
-    int i,j, status=0;
-    unsigned long mem_start, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
-    char *name = NULL;
-    unsigned int nicsr, offset, netRAM;
-
-
-    /*
-    ** Stop the DEPCA. Enable the DBR ROM. Disable interrupts and remote boot.
-    */
-    STOP_DEPCA;
-
-    nicsr = inb(DEPCA_NICSR);
-    nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
-    outb(nicsr, DEPCA_NICSR);
-
-    if (inw(DEPCA_DATA) == STOP) {
+  struct depca_private *lp;
+  int i, j, offset, netRAM, mem_len, status=0;
+  s16 nicsr;
+  u_long mem_start=0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
+
+  STOP_DEPCA;
+
+  nicsr = inb(DEPCA_NICSR);
+  nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
+  outb(nicsr, DEPCA_NICSR);
+
+  if (inw(DEPCA_DATA) == STOP) {
+    for (; mem_base[mem_chkd]; mem_chkd++) {
+      mem_start = mem_base[mem_chkd];
+      DepcaSignature(name, mem_start);
+      if (*name != '\0') break;
+    }
 
-    /* Now find out what kind of DEPCA we have. The DE100 uses a different
-    ** addressing scheme for some registers compared to the DE2xx series.
-    ** Note that a base address location is marked as checked if no DEPCA is
-    ** there or one is found (when the search is immediately terminated). This
-    ** shortens the search time a little for multiple DEPCAs.
-    */
+    if ((*name != '\0') && mem_start) {           /* found a DEPCA device */
+      dev->base_addr = ioaddr;
 
-      for (j = 0, i = 0; mem_base[i] && (j == 0);i++) {
-       if (((mem_chkd >> i) & 0x01) == 0) { /* has the memory been checked? */
-         name = DepcaSignature(mem_base[i]);/* check for a DEPCA here */
-         mem_chkd |= (0x01 << i);           /* mark location checked */
-         if (*name != '\0') {               /* one found? */
-           j = 1;                           /* set exit flag */
-           --i;
-         }
-       }
+      if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */
+       printk("%s: %s at 0x%04lx (EISA slot %d)", 
+                           dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f));
+      } else {                             /* ISA port address */
+       printk("%s: %s at 0x%04lx", dev->name, name, ioaddr);
       }
 
-      if (*name != '\0') {                   /* found a DEPCA device */
-       mem_start = mem_base[i];
-       dev->base_addr = ioaddr;
-
-       if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */
-         printk("%s: %s at %#3x (EISA slot %d)", 
-                                dev->name, name, ioaddr, ((ioaddr>>12)&0x0f));
-       } else {                             /* ISA port address */
-         printk("%s: %s at %#3x", dev->name, name, ioaddr);
-       }
-
-      /* There is a 32 byte station address PROM at DEPCA_PROM address.
-        The first six bytes are the station address. They can be read
-        directly since the signature search set up the ROM address 
-        counter correctly just before this function.
-
-        For the DE100 we have to be careful about which port is used to
-        read the ROM info.
-      */
-
-       if (strstr(name,"DE100")!= NULL) {
-         j = 1;
-       } else {
-         j = 0;
-       }
-
-       printk(", h/w address ");
-       for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */
-         printk("%2.2x:", dev->dev_addr[i] = inb(DEPCA_PROM + j));
-       }
-       printk("%2.2x", dev->dev_addr[i] = inb(DEPCA_PROM + j));
-
-       for (;i<32;i++) {                /* leave ROM counter in known state */
-         j=inb(DEPCA_PROM);
-       }
-
-       request_region(ioaddr, DEPCA_TOTAL_SIZE, dev->name);
-
-       /*
-       ** Set up the maximum amount of network RAM(kB)
-       */
-       if (strstr(name,"DEPCA")== NULL) {
-         netRAM=64;
-       } else {
-         netRAM=48;
-       }
+      printk(", h/w address ");
+      status = get_hw_addr(dev);
+      for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */
+       printk("%2.2x:", dev->dev_addr[i]);
+      }
+      printk("%2.2x", dev->dev_addr[i]);
 
-       /* 
-       ** Determine the base address for the DEPCA RAM from the NI-CSR
-       ** and make up a DEPCA-specific-data structure. 
-        */
+      if (status == 0) {
+       /* Set up the maximum amount of network RAM(kB) */
+       netRAM = ((adapter != DEPCA) ? 64 : 48);
+       if ((nicsr & _128KB) && (adapter == de422)) netRAM = 128;
+       offset = 0x0000;
 
+       /* Shared Memory Base Address */ 
        if (nicsr & BUF) {
          offset = 0x8000;              /* 32kbyte RAM offset*/
          nicsr &= ~BS;                 /* DEPCA RAM in top 32k */
-         printk(",\n      has %dkB RAM", netRAM - 32);
-       } else  if ((nicsr & _128KB) && (netRAM!=48)) {
-         offset = 0x0000;
-         printk(",\n      has 128kB RAM");
-       } else {
-         offset = 0x0000;              /* 64k/48k bytes RAM */
-         printk(",\n      has %dkB RAM", netRAM);
+         netRAM -= 32;
        }
-
        mem_start += offset;            /* (E)ISA start address */
-       printk(" at 0x%.5lx", mem_start);
-
-       /*
-       ** Enable the shadow RAM.
-       */
-       if (strstr(name,"DEPCA") == NULL) {
-         nicsr |= SHE;
-         outb(nicsr, DEPCA_NICSR);
-       }
+       if ((mem_len = (NUM_RX_DESC*(sizeof(struct depca_rx_desc)+RX_BUFF_SZ) +
+                       NUM_TX_DESC*(sizeof(struct depca_tx_desc)+TX_BUFF_SZ) +
+                       sizeof(struct depca_init))) <=
+           (netRAM<<10)) {
+         printk(",\n      has %dkB RAM at 0x%.5lx", netRAM, mem_start);
+
+         /* Enable the shadow RAM. */
+         if (adapter != DEPCA) {
+           nicsr |= SHE;
+           outb(nicsr, DEPCA_NICSR);
+         }
  
-       /*
-       ** Calculate the ring size based on the available RAM
-       ** found above. Allocate an equal number of buffers, each
-       ** of size PKT_BUF_SZ (1544 bytes) to the Tx and Rx, allowing one
-       ** descriptor entry (8 bytes) for each buffer. Make sure
-       ** that this ring size is <= RING_SIZE. The ring size must be
-       ** a power of 2.
-       */
-
-       j = (((netRAM << 10) - offset - sizeof(struct depca_private)) / 
-                                                      (PKT_BUF_SZ + 8)) >> 1;
-       for (i=0;j>1;i++) {
-         j >>= 1;
-       }
-
-       /* Hold the ring size information here before the depca
-       ** private structure is allocated. Need this for the memory
-       ** space calculations.
-       */
-       j = 1 << i;
-
-       /*
-       ** Set up memory information in the device structure.
-       ** Align the descriptor rings on an 8 byte (quadword) boundary.
-       **
-       **     depca_private area
-       **     rx ring descriptors
-       **     tx ring descriptors
-       **     rx buffers
-       **     tx buffers
-       **
-       */
-
-       /* private area & initialise */
-       dev->priv = (void *)((mem_start + 0x07) & ~0x07);      
-       lp = (struct depca_private *)dev->priv;
-       memset(dev->priv, 0, sizeof(struct depca_private));
-       strcpy(lp->devname,name);
-
-       /* Tx & Rx descriptors (aligned to a quadword boundary) */
-       mem_start = ((((unsigned long)dev->priv + 
-                       sizeof(struct depca_private)) +
-                       (unsigned long)0x07) & (unsigned long)~0x07);
-       lp->rx_ring = (struct depca_rx_head *)mem_start;
-
-       mem_start += (sizeof(struct depca_rx_head) * j);
-       lp->tx_ring = (struct depca_tx_head *)mem_start;
-
-       mem_start += (sizeof(struct depca_tx_head) * j);
-       lp->bus_offset = mem_start & 0x00ff0000;
-       mem_start &= LA_MASK;           /* LANCE re-mapped start address */
-
-       lp->dma_buffs = mem_start;
-
-       mem_start += (PKT_BUF_SZ * j);
-       /* (mem_start now points to the start of the Tx buffers) */
-
-       /* Initialise the data structures wrt CPU */
-       memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j);
-       memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j);
-
-       /* This should never happen. */
-       if ((long)(lp->rx_ring) & 0x07) {
-         printk("\n **ERROR** DEPCA Rx and Tx descriptor rings not on a quadword boundary.\n");
-         return -ENXIO;
-       }
-
-       /*
-       ** Finish initialising the ring information.
-       */
-       lp->ringSize = j;
-       if (lp->ringSize > RING_SIZE) lp->ringSize = RING_SIZE;
-       lp->rmask = lp->ringSize - 1;
-
-       /*
-       ** calculate the real RLEN size for the descriptors. It is
-       ** log2(ringSize).
-       */
-       for (i=0, j = lp->ringSize; j>1; i++) {
-         j >>= 1;
-       }
-       lp->rlen = (unsigned long)(i << 29);
-
-       /*
-       ** load the initialisation block
-       */
-       depca_init_ring(dev);
+         /* Define the device private memory */
+         dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL);
+         lp = (struct depca_private *)dev->priv;
+         memset((char *)dev->priv, 0, sizeof(struct depca_private));
+         lp->adapter = adapter;
+         sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+         request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name);
+
+         /* Initialisation Block */
+         lp->sh_mem = mem_start;
+         mem_start += sizeof(struct depca_init);
+
+         /* Tx & Rx descriptors (aligned to a quadword boundary) */
+         mem_start = (mem_start + ALIGN) & ~ALIGN;
+         lp->rx_ring = (struct depca_rx_desc *)mem_start;
+
+         mem_start += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
+         lp->tx_ring = (struct depca_tx_desc *)mem_start;
+
+         mem_start += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
+         lp->bus_offset = mem_start & 0x00ff0000;
+         mem_start &= LA_MASK;           /* LANCE re-mapped start address */
+
+         lp->dma_buffs = mem_start;
+
+         /* Finish initialising the ring information. */
+         lp->rxRingMask = NUM_RX_DESC - 1;
+         lp->txRingMask = NUM_TX_DESC - 1;
+
+         /* Calculate Tx/Rx RLEN size for the descriptors. */
+         for (i=0, j = lp->rxRingMask; j>0; i++) {
+           j >>= 1;
+         }
+         lp->rx_rlen = (s32)(i << 29);
+         for (i=0, j = lp->txRingMask; j>0; i++) {
+           j >>= 1;
+         }
+         lp->tx_rlen = (s32)(i << 29);
 
-       /*
-       ** Initialise the control and status registers
-       */
-       LoadCSRs(dev);
+         /* Load the initialisation block */
+         depca_init_ring(dev);
 
-       /*
-       ** Enable DEPCA board interrupts for autoprobing
-       */
-       nicsr = ((nicsr & ~IM)|IEN);
-       outb(nicsr, DEPCA_NICSR);
+         /* Initialise the control and status registers */
+         LoadCSRs(dev);
 
-       /* The DMA channel may be passed in on this parameter. */
-       dev->dma = 0;
+         /* Enable DEPCA board interrupts for autoprobing */
+         nicsr = ((nicsr & ~IM)|IEN);
+         outb(nicsr, DEPCA_NICSR);
 
-       /* To auto-IRQ we enable the initialization-done and DMA err,
-        interrupts. For now we will always get a DMA error. */
-       if (dev->irq < 2) {
+         /* To auto-IRQ we enable the initialization-done and DMA err,
+            interrupts. For now we will always get a DMA error. */
+         if (dev->irq < 2) {
 #ifndef MODULE
-         autoirq_setup(0);
+           unsigned char irqnum;
+           autoirq_setup(0);
+           
+           /* Assign the correct irq list */
+           switch (lp->adapter) {
+           case DEPCA:
+           case de100:
+           case de101:
+             depca_irq = de1xx_irq;
+             break;
+           case de200:
+           case de201:
+           case de202:
+           case de210:
+             depca_irq = de2xx_irq;
+             break;
+           case de422:
+             depca_irq = de422_irq;
+             break;
+           }
 
-         /* Trigger an initialization just for the interrupt. */
-         outw(INEA | INIT, DEPCA_DATA);
+           /* Trigger an initialization just for the interrupt. */
+           outw(INEA | INIT, DEPCA_DATA);
          
-         dev->irq = autoirq_report(1);
-         if (dev->irq) {
-           printk(" and uses IRQ%d.\n", dev->irq);
+           irqnum = autoirq_report(1);
+           if (!irqnum) {
+             printk("      and failed to detect IRQ line.\n");
+             status = -ENXIO;
+           } else {
+             for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) {
+               if (irqnum == depca_irq[i]) {
+                 dev->irq = irqnum;
+                 printk("      and uses IRQ%d.\n", dev->irq);
+               }
+             }
+             
+             if (!dev->irq) {
+               printk("      but incorrect IRQ line detected.\n");
+               status = -ENXIO;
+             }
+           }
+#endif /* MODULE */
          } else {
-           printk(" and failed to detect IRQ line.\n");
-           status = -EAGAIN;
+           printk(" and assigned IRQ%d.\n", dev->irq);
          }
-#endif /* MODULE */
+         if (status) release_region(ioaddr, DEPCA_TOTAL_SIZE);
        } else {
-         printk(" and assigned IRQ%d.\n", dev->irq);
+         printk(",\n      requests %dkB RAM: only %dkB is available!\n", 
+                                                       (mem_len>>10), netRAM);
+         status = -ENXIO;
        }
       } else {
+       printk("      which has an Ethernet PROM CRC error.\n");
        status = -ENXIO;
       }
-      if (!status) {
-       if (depca_debug > 0) {
-         printk(version);
-       }
+    }
+    if (!status) {
+      if (depca_debug > 0) {
+       printk(version);
+      }
 
-       /* The DEPCA-specific entries in the device structure. */
-       dev->open = &depca_open;
-       dev->hard_start_xmit = &depca_start_xmit;
-       dev->stop = &depca_close;
-       dev->get_stats = &depca_get_stats;
-#ifdef HAVE_MULTICAST
-       dev->set_multicast_list = &set_multicast_list;
-#endif
+      /* The DEPCA-specific entries in the device structure. */
+      dev->open = &depca_open;
+      dev->hard_start_xmit = &depca_start_xmit;
+      dev->stop = &depca_close;
+      dev->get_stats = &depca_get_stats;
+      dev->set_multicast_list = &set_multicast_list;
+      dev->do_ioctl = &depca_ioctl;
 
-       dev->mem_start = 0;
+      dev->mem_start = 0;
        
-       /* Fill in the generic field of the device structure. */
-       ether_setup(dev);
+      /* Fill in the generic field of the device structure. */
+      ether_setup(dev);
+    } else {                           /* Incorrectly initialised hardware */
+      if (dev->priv) {
+       kfree_s(dev->priv, sizeof(struct depca_private));
+       dev->priv = NULL;
       }
-    } else {
-      status = -ENXIO;
     }
+  } else {
+    status = -ENXIO;
+  }
 
-    return status;
+  return status;
 }
 
 \f
@@ -679,66 +653,87 @@ static int
 depca_open(struct device *dev)
 {
     struct depca_private *lp = (struct depca_private *)dev->priv;
-    int i,nicsr,ioaddr = dev->base_addr;
+    s16 nicsr;
+    u_long ioaddr = dev->base_addr;
+    int i, status = 0;
+    struct depca_init *p = (struct depca_init *)lp->sh_mem;
 
-    if (request_irq(dev->irq, &depca_interrupt, 0, "depca")) {
+    if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name)) {
         printk("depca_open(): Requested IRQ%d is busy\n",dev->irq);
-       return -EAGAIN;
+       status = -EAGAIN;
     }
 
     irq2dev_map[dev->irq] = dev;
-
-    /*
-    ** Stop the DEPCA & get the board status information.  
-    */
     STOP_DEPCA;
     nicsr = inb(DEPCA_NICSR);
 
-    /*
-    ** Make sure the shadow RAM is enabled
-    */
-    if (strstr(lp->devname,"DEPCA") == NULL) {
+    /* Make sure the shadow RAM is enabled */
+    if (adapter != DEPCA) {
       nicsr |= SHE;
       outb(nicsr, DEPCA_NICSR);
     }
 
-    /* 
-    ** Re-initialize the DEPCA... 
-    */
-    depca_init_ring(dev);                 /* initialize the descriptor rings */
+    /* Re-initialize the DEPCA... */
+    depca_init_ring(dev);
     LoadCSRs(dev);
 
     if (depca_debug > 1){
+      /* Copy the shadow init_block to shared memory */
+      memcpy_toio((char *)lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
+
       printk("%s: depca open with irq %d\n",dev->name,dev->irq);
       printk("Descriptor head addresses:\n");
-      printk("\t0x%8.8lx  0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
-      printk("Descriptor addresses:\n");
-      for (i=0;i<lp->ringSize;i++){
-       printk("\t0x%8.8lx  0x%8.8lx\n",(long)&lp->rx_ring[i].base,
-                                       (long)&lp->tx_ring[i].base);
+      printk("\t0x%lx  0x%lx\n",(u_long)lp->rx_ring, (u_long)lp->tx_ring);
+      printk("Descriptor addresses:\nRX: ");
+      for (i=0;i<lp->rxRingMask;i++){
+       if (i < 3) {
+         printk("0x%8.8lx ", (long) &lp->rx_ring[i].base);
+       }
+      }
+      printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base);
+      printk("TX: ");
+      for (i=0;i<lp->txRingMask;i++){
+       if (i < 3) {
+         printk("0x%8.8lx ", (long) &lp->tx_ring[i].base);
+       }
       }
-      printk("Buffer addresses:\n");
-      for (i=0;i<lp->ringSize;i++){
-       printk("\t0x%8.8lx  0x%8.8lx\n",(long)lp->rx_ring[i].base,
-                                        (long)lp->tx_ring[i].base);
+      printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base);
+      printk("\nDescriptor buffers:\nRX: ");
+      for (i=0;i<lp->rxRingMask;i++){
+       if (i < 3) {
+         printk("0x%8.8x  ", readl(&lp->rx_ring[i].base));
+       }
       }
-      printk("Initialisation block at 0x%8.8lx\n",(long)&lp->init_block);
-      printk("\tmode: 0x%4.4x\n",lp->init_block.mode);
+      printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
+      printk("TX: ");
+      for (i=0;i<lp->txRingMask;i++){
+       if (i < 3) {
+         printk("0x%8.8x  ", readl(&lp->tx_ring[i].base));
+       }
+      }
+      printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
+      printk("Status:  %d\n", status);
+      printk("Initialisation block at 0x%8.8lx\n",lp->sh_mem);
+      printk("\tmode: 0x%4.4x\n",readw(&p->mode));
       printk("\tphysical address: ");
-      for (i=0;i<6;i++){
-       printk("%2.2x:",(short)lp->init_block.phys_addr[i]);
+      for (i=0;i<ETH_ALEN-1;i++){
+       printk("%2.2x:",(u_char)readb(&p->phys_addr[i]));
       }
-      printk("\n\tlogical address filter: 0x");
-      for (i=0;i<4;i++){
-       printk("%2.2x",(short)lp->init_block.filter[i]);
+      printk("%2.2x\n",(u_char)readb(&p->phys_addr[i]));
+      printk("\tmulticast hash table: ");
+      for (i=0;i<(HASH_TABLE_LEN >> 3)-1;i++){
+       printk("%2.2x:",(u_char)readb(&p->mcast_table[i]));
       }
-      printk("\n\trx_ring at: 0x%8.8lx\n",(long)lp->init_block.rx_ring);
-      printk("\ttx_ring at: 0x%8.8lx\n",(long)lp->init_block.tx_ring);
-      printk("dma_buffs: 0x%8.8lx\n",(long)lp->dma_buffs);
-      printk("Ring size: %d\nMask: 0x%2.2x\nLog2(ringSize): 0x%8.8lx\n", 
-                                         (short)lp->ringSize, 
-                                          (char)lp->rmask,
-                                          (long)lp->rlen);
+      printk("%2.2x\n",(u_char)readb(&p->mcast_table[i]));
+      printk("\trx_ring at: 0x%8.8x\n",readl(&p->rx_ring));
+      printk("\ttx_ring at: 0x%8.8x\n",readl(&p->tx_ring));
+      printk("dma_buffs: 0x%8.8lx\n",lp->dma_buffs);
+      printk("Ring size:\nRX: %d  Log2(rxRingMask): 0x%8.8x\n", 
+                                          (int)lp->rxRingMask + 1, 
+                                          lp->rx_rlen);
+      printk("TX: %d  Log2(txRingMask): 0x%8.8x\n", 
+                                          (int)lp->txRingMask + 1, 
+                                          lp->tx_rlen);
       outw(CSR2,DEPCA_ADDR);
       printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA));
       outw(CSR1,DEPCA_ADDR);
@@ -747,9 +742,7 @@ depca_open(struct device *dev)
       printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA));
     }
 
-    /*
-    ** Enable DEPCA board interrupts and turn off LED
-    */
+    /* Enable DEPCA board interrupts and turn off LED */
     nicsr = ((nicsr & ~IM & ~LED)|IEN);
     outb(nicsr, DEPCA_NICSR);
     outw(CSR0,DEPCA_ADDR);
@@ -758,7 +751,7 @@ depca_open(struct device *dev)
     dev->interrupt = 0;
     dev->start = 1;
 
-    InitRestartDepca(dev);                /* ignore the return status */
+    status = InitRestartDepca(dev);
 
     if (depca_debug > 1){
       printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
@@ -767,39 +760,48 @@ depca_open(struct device *dev)
 
     MOD_INC_USE_COUNT;
 
-    return 0;                            /* Always succeed */
+    return status;
 }
 
 /* Initialize the lance Rx and Tx descriptor rings. */
 static void
 depca_init_ring(struct device *dev)
 {
-    struct depca_private *lp = (struct depca_private *)dev->priv;
-    unsigned long i;
-
-    lp->init_block.mode = DTX | DRX;        /* Disable Rx and Tx. */
-    lp->cur_rx = lp->cur_tx = 0;
-    lp->dirty_rx = lp->dirty_tx = 0;
-
-    /* Initialize the base addresses and length of each buffer in the ring */
-    for (i = 0; i < lp->ringSize; i++) {
-       lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | R_OWN;
-       lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
-       lp->tx_ring[i].base = (lp->dma_buffs + (i+lp->ringSize) * PKT_BUF_SZ) &
-                                                  (unsigned long)(0x00ffffff);
-    }
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  u_int i;
+  u_long p;
 
-    /* Set up the initialization block */
-    for (i = 0; i < ETH_ALEN; i++) {
-      lp->init_block.phys_addr[i] = dev->dev_addr[i];
-    }
-    for (i = 0; i < 4; i++) {
-      lp->init_block.filter[i] = 0x0000;
-    }
-    lp->init_block.rx_ring = ((unsigned long)lp->rx_ring & LA_MASK) | lp->rlen;
-    lp->init_block.tx_ring = ((unsigned long)lp->tx_ring & LA_MASK) | lp->rlen;
+  /* Lock out other processes whilst setting up the hardware */
+  set_bit(0, (void *)&dev->tbusy);
 
-    lp->init_block.mode = 0x0000;            /* Enable the Tx and Rx */ 
+  lp->rx_new = lp->tx_new = 0;
+  lp->rx_old = lp->tx_old = 0;
+
+  /* Initialize the base addresses and length of each buffer in the ring */
+  for (i = 0; i <= lp->rxRingMask; i++) {
+    writel((p=lp->dma_buffs+i*RX_BUFF_SZ) | R_OWN, &lp->rx_ring[i].base);
+    writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
+    lp->rx_memcpy[i]=(char *)(p+lp->bus_offset);
+  }
+  for (i = 0; i <= lp->txRingMask; i++) {
+    writel((p=lp->dma_buffs+(i+lp->txRingMask+1)*TX_BUFF_SZ) & 0x00ffffff,
+                                                        &lp->tx_ring[i].base);
+    lp->tx_memcpy[i]=(char *)(p+lp->bus_offset);
+  }
+
+  /* Set up the initialization block */
+  lp->init_block.rx_ring = ((u32)((u_long)lp->rx_ring)&LA_MASK) | lp->rx_rlen;
+  lp->init_block.tx_ring = ((u32)((u_long)lp->tx_ring)&LA_MASK) | lp->tx_rlen;
+
+  SetMulticastFilter(dev, 0, NULL);
+
+  for (i = 0; i < ETH_ALEN; i++) {
+    lp->init_block.phys_addr[i] = dev->dev_addr[i];
+  }
+
+  lp->init_block.mode = 0x0000;            /* Enable the Tx and Rx */
+
+  return;
 }
 
 /* 
@@ -808,148 +810,58 @@ depca_init_ring(struct device *dev)
 static int
 depca_start_xmit(struct sk_buff *skb, struct device *dev)
 {
-    struct depca_private *lp = (struct depca_private *)dev->priv;
-    int ioaddr = dev->base_addr;
-    int status = 0;
-
-    /* Transmitter timeout, serious problems. */
-    if (dev->tbusy) {
-      int tickssofar = jiffies - dev->trans_start;
-      if (tickssofar < 10) {
-       status = -1;
-      } else {
-       printk("%s: transmit timed out, status %04x, resetting.\n",
-              dev->name, inw(DEPCA_DATA));
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  u_long ioaddr = dev->base_addr;
+  int status = 0;
+
+  /* Transmitter timeout, serious problems. */
+  if (dev->tbusy) {
+    int tickssofar = jiffies - dev->trans_start;
+    if (tickssofar < 100) {
+      status = -1;
+    } else {
+      printk("%s: transmit timed out, status %04x, resetting.\n",
+            dev->name, inw(DEPCA_DATA));
        
-       STOP_DEPCA;
-       depca_init_ring(dev);
-       LoadCSRs(dev);
-       InitRestartDepca(dev);
-       dev->tbusy=0;
-       dev->trans_start = jiffies;
-      }
-      return status;
-    }
-
-    if (skb == NULL) {
-       dev_tint(dev);
-       return 0;
-    }
-
-    if (skb->len <= 0) {
-      return 0;
-    }
-
-    if (depca_debug > 3) {
-       outw(CSR0, DEPCA_ADDR);
-       printk("%s: depca_start_xmit() called, csr0 %4.4x.\n", dev->name,
-              inw(DEPCA_DATA));
-    }
-
-    /* Block a timer-based transmit from overlapping.  This could better be
-       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-    if (set_bit(0, (void*)&dev->tbusy) != 0)
-       printk("%s: Transmitter access conflict.\n", dev->name);
-
-    /*
-    ** The TX buffer, skb, has to be copied into the local network RAM
-    ** for the LANCE to access it. The skb may be at > 16MB for large 
-    ** (memory) systems.
-    */
-    {                          /* Fill in a Tx ring entry */
-      unsigned char *buf;
-      int entry = lp->cur_tx++;
-      int len;
-      long skbL = skb->len;
-      char *p = (char *) skb->data;
-
-      entry &= lp->rmask;                  /* Ring around buffer number. */
-      buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) & 
-                                                                  0x00ffffff);
-
-      /* Wait for a full ring to free up */
-      while (lp->tx_ring[entry].base < 0);
-
-      /* 
-      ** Caution: the write order is important here... don't set up the
-      ** ownership rights until all the other information is in place.
-      */
-      len = ((skbL > PKT_SZ) ? PKT_SZ : skbL); /* skb too long */
-      if (len < ETH_ZLEN) len = ETH_ZLEN;      /* len too short */
-      skbL -= len;
-      lp->tx_ring[entry].length = -len;
-
-      /* Clears various error flags */
-      lp->tx_ring[entry].misc = 0x0000;
-
-      /* copy the data from the socket buffer to the net memory */
-      memcpy((unsigned char *)(buf), skb->data, len);
-
-      /* Hand over buffer ownership to the LANCE */
-      if (skbL <= 0) lp->tx_ring[entry].base |= (T_ENP);
-      lp->tx_ring[entry].base |= (T_OWN|T_STP);
-
-      /* Trigger an immediate send demand. */
-      outw(CSR0, DEPCA_ADDR);
-      outw(INEA | TDMD, DEPCA_DATA);
-
+      STOP_DEPCA;
+      depca_init_ring(dev);
+      LoadCSRs(dev);
+      dev->interrupt = UNMASK_INTERRUPTS;
+      dev->start = 1;
+      dev->tbusy=0;
       dev->trans_start = jiffies;
+      InitRestartDepca(dev);
+    }
+    return status;
+  } else if (skb == NULL) {
+    dev_tint(dev);
+  } else if (skb->len > 0) {
+    /* Enforce 1 process per h/w access */
+    if (set_bit(0, (void*)&dev->tbusy) != 0) {
+      printk("%s: Transmitter access conflict.\n", dev->name);
+      status = -1;
+    } else {
+      if (TX_BUFFS_AVAIL) {                    /* Fill in a Tx ring entry */
+       status = load_packet(dev, skb);
 
-      for (p += len; skbL > 0; p += len) {
-
-       /* Get new buffer pointer */
-       entry = lp->cur_tx++;
-       entry &= lp->rmask;                 /* Ring around buffer number. */
-       buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
-                                                                  0x00ffffff);
-
-       /* Wait for a full ring to free up */
-       while (lp->tx_ring[entry].base < 0);
-       dev->tbusy=0;
-
-       /* Copy ethernet header to the new buffer */
-       memcpy((unsigned char *)buf, skb->data, PKT_HDR_LEN);
-
-       /* Determine length of data buffer */
-       len = ((skbL > DAT_SZ) ? DAT_SZ : skbL); /* skbL too long */
-       if (len < ETH_ZLEN) len = ETH_ZLEN;      /* len too short */
-       skbL -= len;
-       lp->tx_ring[entry].length = -len;
-
-       /* Clears various error flags */
-       lp->tx_ring[entry].misc = 0x0000;
-
-       /* copy the data from the socket buffer to the net memory */
-       memcpy((unsigned char *)(buf + PKT_HDR_LEN), (unsigned char *)p, len);
-
-       /* Hand over buffer ownership to the LANCE */
-       if (skbL <= 0) lp->tx_ring[entry].base |= T_ENP;
-       lp->tx_ring[entry].base |= T_OWN;
-      }
-
-      if (depca_debug > 4) {
-       unsigned char *pkt =
-         (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
-                                                                  0x00ffffff);
-
-       printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n",
-              dev->name, entry, (unsigned long) &lp->tx_ring[entry],
-              lp->tx_ring[entry].base, -lp->tx_ring[entry].length);
-       printk("%s:  Tx %2.2x %2.2x %2.2x ... %2.2x  %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x  %2.2x %2.2x.\n",
-              dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6],
-              pkt[7], pkt[8], pkt[11], pkt[12], pkt[13],
-              pkt[14], pkt[15]);
-      }
-      
-      /* Check if the TX ring is full or not - 'tbusy' cleared if not full. */
-      if (lp->tx_ring[(entry+1) & lp->rmask].base >= 0) {
-       dev->tbusy=0;
+       if (!status) {
+         /* Trigger an immediate send demand. */
+         outw(CSR0, DEPCA_ADDR);
+         outw(INEA | TDMD, DEPCA_DATA);
+         
+         dev->trans_start = jiffies;
+         dev_kfree_skb(skb, FREE_WRITE);
+       }
+       if (TX_BUFFS_AVAIL) {
+         dev->tbusy=0;
+       }  
+      } else {
+       status = -1;
       }
-
-      dev_kfree_skb (skb, FREE_WRITE);
     }
-
-    return 0;
+  }
+  
+  return status;
 }
 
 /*
@@ -958,137 +870,144 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev)
 static void
 depca_interrupt(int irq, struct pt_regs * regs)
 {
-    struct device *dev = (struct device *)(irq2dev_map[irq]);
-    struct depca_private *lp;
-    int csr0, ioaddr, nicsr;
-
-    if (dev == NULL) {
-       printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
-    } else {
-      lp = (struct depca_private *)dev->priv;
-      ioaddr = dev->base_addr;
-
-      if (dev->interrupt)
-       printk("%s: Re-entering the interrupt handler.\n", dev->name);
+  struct device *dev = (struct device *)(irq2dev_map[irq]);
+  struct depca_private *lp;
+  s16 csr0, nicsr;
+  u_long ioaddr;
 
-      dev->interrupt = MASK_INTERRUPTS;
+  if (dev == NULL) {
+    printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+  } else {
+    lp = (struct depca_private *)dev->priv;
+    ioaddr = dev->base_addr;
+    
+    if (dev->interrupt)
+      printk("%s: Re-entering the interrupt handler.\n", dev->name);
 
-      /* mask the DEPCA board interrupts and turn on the LED */
-      nicsr = inb(DEPCA_NICSR);
-      nicsr |= (IM|LED);
-      outb(nicsr, DEPCA_NICSR);
+    dev->interrupt = MASK_INTERRUPTS;
 
-      outw(CSR0, DEPCA_ADDR);
-      csr0 = inw(DEPCA_DATA);
+    /* mask the DEPCA board interrupts and turn on the LED */
+    nicsr = inb(DEPCA_NICSR);
+    nicsr |= (IM|LED);
+    outb(nicsr, DEPCA_NICSR);
 
-      /* Acknowledge all of the current interrupt sources ASAP. */
-      outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA);
+    outw(CSR0, DEPCA_ADDR);
+    csr0 = inw(DEPCA_DATA);
 
-      if (depca_debug > 5)
-       printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
-              dev->name, csr0, inw(DEPCA_DATA));
+    /* Acknowledge all of the current interrupt sources ASAP. */
+    outw(csr0 & INTE, DEPCA_DATA);
 
-      if (csr0 & RINT)         /* Rx interrupt (packet arrived) */
-       depca_rx(dev);
+    if (csr0 & RINT)                  /* Rx interrupt (packet arrived) */
+      depca_rx(dev);
 
-      if (csr0 & TINT)                 /* Tx interrupt (packet sent) */
-        depca_tx(dev);
+    if (csr0 & TINT)                  /* Tx interrupt (packet sent) */
+      depca_tx(dev);
 
-      /* Clear the interrupts we've handled. */
-      outw(CSR0, DEPCA_ADDR);
-      outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA);
+    if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { /* any resources available? */
+      dev->tbusy = 0;                  /* clear TX busy flag */
+      mark_bh(NET_BH);
+    }
 
-      if (depca_debug > 4) {
-       printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
-              dev->name, inw(DEPCA_ADDR),
-              inw(DEPCA_DATA));
-      }
+    /* Unmask the DEPCA board interrupts and turn off the LED */
+    nicsr = (nicsr & ~IM & ~LED);
+    outb(nicsr, DEPCA_NICSR);
 
-      /* Unmask the DEPCA board interrupts and turn off the LED */
-      nicsr = (nicsr & ~IM & ~LED);
-      outb(nicsr, DEPCA_NICSR);
-      dev->interrupt = UNMASK_INTERRUPTS;
-    }
+    dev->interrupt = UNMASK_INTERRUPTS;
+  }
 
-    return;
+  return;
 }
 
 static int
 depca_rx(struct device *dev)
 {
-    struct depca_private *lp = (struct depca_private *)dev->priv;
-    int entry = lp->cur_rx & lp->rmask;
-
-    /* If we own the next entry, it's a new packet. Send it up. */
-    for (; lp->rx_ring[entry].base >= 0; entry = (++lp->cur_rx) & lp->rmask) {
-       int status = lp->rx_ring[entry].base >> 16 ;
-       int chained;
-
-       /*
-       ** There is a tricky error noted by John Murphy, <murf@perftech.com>
-       ** to Russ Nelson: even with full-sized buffers, it's possible for a
-       ** jabber packet to use two buffers, with only the last one correctly
-       ** noting the error.
-       */
-
-       /* Check for a chaining buffer */
-       chained = 0;
-       if (status == R_STP) { 
-         chained = 1;
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  int i, entry;
+  s32 status;
+  char *buf;
+
+  for (entry=lp->rx_new; 
+       !(readl(&lp->rx_ring[entry].base) & R_OWN);
+       entry=lp->rx_new){
+    status = readl(&lp->rx_ring[entry].base) >> 16 ;
+    if (status & R_STP) {                      /* Remember start of frame */
+      lp->rx_old = entry;
+    }
+    if (status & R_ENP) {                      /* Valid frame status */
+      if (status & R_ERR) {                   /* There was an error. */
+       lp->stats.rx_errors++;                 /* Update the error stats. */
+       if (status & R_FRAM) lp->stats.rx_frame_errors++;
+       if (status & R_OFLO) lp->stats.rx_over_errors++;
+       if (status & R_CRC)  lp->stats.rx_crc_errors++;
+       if (status & R_BUFF) lp->stats.rx_fifo_errors++;
+      } else { 
+       short len, pkt_len = readw(&lp->rx_ring[entry].msg_length);
+       struct sk_buff *skb;
+
+       skb = alloc_skb(pkt_len, GFP_ATOMIC);
+       if (skb != NULL) {
+         skb->len = pkt_len;
+         skb->dev = dev;
+         if (entry < lp->rx_old) {         /* Wrapped buffer */
+           len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
+           memcpy_fromio(skb->data, lp->rx_memcpy[lp->rx_old], len);
+           memcpy_fromio(skb->data+len, lp->rx_memcpy[0], pkt_len-len);
+         } else {                          /* Linear buffer */
+           memcpy_fromio(skb->data, lp->rx_memcpy[lp->rx_old], pkt_len);
+         }
 
          /* 
-         ** Wait for next buffer to complete to check for errors. This
-         ** is slow but infrequent and allows for correct hardware buffer
-         ** chaining (whilst defeating the chaining's purpose).
+         ** Notify the upper protocol layers that there is another 
+         ** packet to handle
          */
-         while ((status=(lp->rx_ring[(entry+1)&lp->rmask].base >> 16)) < 0);
-
-         /* NB: 'status' now comes from the buffer following 'entry'. */
-       }
-         
-       if (status & R_ERR) {                  /* There was an error. */
-           lp->stats.rx_errors++;             /* Update the error stats. */
-           if (status & R_FRAM) lp->stats.rx_frame_errors++;
-           if (status & R_OFLO) lp->stats.rx_over_errors++;
-           if (status & R_CRC)  lp->stats.rx_crc_errors++;
-           if (status & R_BUFF) lp->stats.rx_fifo_errors++;
-       } else {          /* Malloc up new buffer, compatible  with net-2e. */
-           short pkt_len = lp->rx_ring[entry].msg_length;
-           struct sk_buff *skb;
-
-           skb = alloc_skb(pkt_len, GFP_ATOMIC);
-           if (skb == NULL) {
-               printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-               lp->stats.rx_dropped++; /* Really, deferred. */
-               break;
+         skb->protocol=eth_type_trans(skb,dev);
+         netif_rx(skb);
+         /*
+         ** Update stats
+         */
+         lp->stats.rx_packets++;
+         for (i=1; i<DEPCA_PKT_STAT_SZ-1; i++) {
+           if (pkt_len < (i*DEPCA_PKT_BIN_SZ)) {
+             lp->pktStats.bins[i]++;
+             i = DEPCA_PKT_STAT_SZ;
            }
-           skb->len = pkt_len;
-           skb->dev = dev;
-           memcpy(skb->data,
-                 (unsigned char *)((lp->rx_ring[entry].base+lp->bus_offset) &
-                                                                  0x00ffffff),
-                  pkt_len);
-           /* 
-           ** Notify the upper protocol layers that there is another 
-           ** packet to handle
-           */
-           skb->protocol=eth_type_trans(skb,dev);
-           netif_rx(skb);
-           lp->stats.rx_packets++;
-       }
-
-       /* turn over ownership of the current entry back to the LANCE */
-       lp->rx_ring[entry].base |= R_OWN;
-       if (chained && (status & R_ERR)) {          /* next entry also bad */
-         entry = (++lp->cur_rx) & lp->rmask;
-         lp->rx_ring[entry].base |= R_OWN;
+         }
+         buf = skb->data;                  /* Look at the dest addr */
+         if (buf[0] & 0x01) {              /* Multicast/Broadcast */
+           if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) {
+             lp->pktStats.broadcast++;
+           } else {
+             lp->pktStats.multicast++;
+           }
+         } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) &&
+                    (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
+           lp->pktStats.unicast++;
+         }
+         
+         lp->pktStats.bins[0]++;           /* Duplicates stats.rx_packets */
+         if (lp->pktStats.bins[0] == 0) {  /* Reset counters */
+           memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
+         }
+       } else {
+         printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+         lp->stats.rx_dropped++;       /* Really, deferred. */
+         break;
        }
+      }
+      /* Change buffer ownership for this last frame, back to the adapter */
+      for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)&lp->rxRingMask) {
+       writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, 
+                                               &lp->rx_ring[lp->rx_old].base);
+      }
+      writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
     }
 
-    /* 
-    ** We should check that at least two ring entries are free.  If not,
-    ** we should free one and mark stats->rx_dropped++. 
+    /*
+    ** Update entry information
     */
+    lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
+    }
 
     return 0;
 }
@@ -1100,46 +1019,37 @@ static int
 depca_tx(struct device *dev)
 {
   struct depca_private *lp = (struct depca_private *)dev->priv;
-  int dirty_tx = lp->dirty_tx & lp->rmask;
+  int entry;
+  s32 status;
+  u_long ioaddr = dev->base_addr;
 
-  if (depca_debug > 5)
-    printk("%s: Cleaning tx ring, dirty %d clean %d.\n",
-          dev->name, dirty_tx, (lp->cur_tx & lp->rmask));
-  
-  /* 
-  ** While the dirty entry is not the current one AND 
-  ** the LANCE doesn't own it... 
-  */
-  for (; dirty_tx!=(lp->cur_tx & lp->rmask) && lp->tx_ring[dirty_tx].base>0;
-                                       dirty_tx = ++lp->dirty_tx & lp->rmask) {
-    unsigned long *tmdp = (unsigned long *)(&lp->tx_ring[dirty_tx]);
-    int status = lp->tx_ring[dirty_tx].base >> 16;
+  for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
+    status = readl(&lp->tx_ring[entry].base) >> 16 ;
 
     if (status < 0) {                          /* Packet not yet sent! */
-      printk("interrupt for packet not yet sent!\n");
       break;
-    }
-    if (status & T_ERR) { /* There was an major error, log it. */
-      int err_status = lp->tx_ring[dirty_tx].misc;
-
+    } else if (status & T_ERR) {               /* An error occured. */
+      status = readl(&lp->tx_ring[entry].misc);
       lp->stats.tx_errors++;
-      if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
-      if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
-      if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
-      if (err_status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
-      /* We should re-init() after the FIFO error. */
+      if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+      if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+      if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
+      if (status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
+      if (status & (TMD3_BUFF | TMD3_UFLO)) {
+       /* Trigger an immediate send demand. */
+       outw(CSR0, DEPCA_ADDR);
+       outw(INEA | TDMD, DEPCA_DATA);
+      }
     } else if (status & (T_MORE | T_ONE)) {
       lp->stats.collisions++;
     } else {
       lp->stats.tx_packets++;
     }
 
-    if (depca_debug > 5)
-      printk("%s: Tx done entry %d, %4.4lx %4.4lx %4.4lx %4.4lx.\n",
-            dev->name, dirty_tx,
-            tmdp[0], tmdp[1], tmdp[2], tmdp[3]);
+    /* Update all the pointers */
+    lp->tx_old = (++lp->tx_old) & lp->txRingMask;
   }
-  /*mark_bh(INET_BH);*/
+
   return 0;
 }
 
@@ -1147,7 +1057,8 @@ static int
 depca_close(struct device *dev)
 {
   struct depca_private *lp = (struct depca_private *)dev->priv;
-  int nicsr, ioaddr = dev->base_addr;
+  s16 nicsr;
+  u_long ioaddr = dev->base_addr;
 
   dev->start = 0;
   dev->tbusy = 1;
@@ -1168,15 +1079,17 @@ depca_close(struct device *dev)
   /*
   ** Give back the ROM in case the user wants to go to DOS
   */
-  if (strstr(lp->devname,"DEPCA") == NULL) {
+  if (lp->adapter != DEPCA) {
     nicsr = inb(DEPCA_NICSR);
     nicsr &= ~SHE;
     outb(nicsr, DEPCA_NICSR);
   }
 
+  /*
+  ** Free the associated irq
+  */
   free_irq(dev->irq);
-
-  irq2dev_map[dev->irq] = 0;
+  irq2dev_map[dev->irq] = NULL;
 
   MOD_DEC_USE_COUNT;
 
@@ -1186,25 +1099,29 @@ depca_close(struct device *dev)
 static void LoadCSRs(struct device *dev)
 {
   struct depca_private *lp = (struct depca_private *)dev->priv;
-  int ioaddr = dev->base_addr;
+  u_long ioaddr = dev->base_addr;
 
   outw(CSR1, DEPCA_ADDR);                /* initialisation block address LSW */
-  outw((unsigned short)((unsigned long)(&lp->init_block) & LA_MASK), 
-                                                                   DEPCA_DATA);
+  outw((u16)(lp->sh_mem & LA_MASK), DEPCA_DATA);
   outw(CSR2, DEPCA_ADDR);                /* initialisation block address MSW */
-  outw((unsigned short)(((unsigned long)(&lp->init_block) & LA_MASK) >> 16), 
-                                                                   DEPCA_DATA);
+  outw((u16)((lp->sh_mem & LA_MASK) >> 16), DEPCA_DATA);
   outw(CSR3, DEPCA_ADDR);                /* ALE control */
   outw(ACON, DEPCA_DATA);
-  outw(CSR0, DEPCA_ADDR);                /* point back to CSR0 */
+
+  outw(CSR0, DEPCA_ADDR);                /* Point back to CSR0 */
+
+  return;
 }
 
 static int InitRestartDepca(struct device *dev)
 {
   struct depca_private *lp = (struct depca_private *)dev->priv;
-  int ioaddr = dev->base_addr;
+  u_long ioaddr = dev->base_addr;
   int i, status=0;
 
+  /* Copy the shadow init_block to shared memory */
+  memcpy_toio((char *)lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
+
   outw(CSR0, DEPCA_ADDR);                /* point back to CSR0 */
   outw(INIT, DEPCA_DATA);                /* initialize DEPCA */
 
@@ -1215,13 +1132,13 @@ static int InitRestartDepca(struct device *dev)
     /* clear IDON by writing a "1", enable interrupts and start lance */
     outw(IDON | INEA | STRT, DEPCA_DATA);
     if (depca_debug > 2) {
-      printk("%s: DEPCA open after %d ticks, init block %#lx csr0 %4.4x.\n",
-            dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
+      printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
+            dev->name, i, lp->sh_mem, inw(DEPCA_DATA));
     }
   } else {
+    printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
+            dev->name, i, lp->sh_mem, inw(DEPCA_DATA));
     status = -1;
-    printk("%s: DEPCA unopened after %d ticks, init block %#lx csr0 %4.4x.\n",
-          dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
   }
 
   return status;
@@ -1237,7 +1154,6 @@ depca_get_stats(struct device *dev)
     return &lp->stats;
 }
 
-#ifdef HAVE_MULTICAST
 /*
 ** Set or clear the multicast filter for this adaptor.
 ** num_addrs == -1     Promiscuous mode, receive all packets
@@ -1245,20 +1161,22 @@ depca_get_stats(struct device *dev)
 ** num_addrs > 0       Multicast mode, receive normal and MC packets, and do
 **                     best-effort filtering.
 */
-#define hash_filter lp->init_block.filter
-
 static void
 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
-  short ioaddr = dev->base_addr;
   struct depca_private *lp = (struct depca_private *)dev->priv;
+  u_long ioaddr = dev->base_addr;
   
   if (irq2dev_map[dev->irq] != NULL) {
+    while(dev->tbusy);                /* Stop ring access */
+    set_bit(0, (void*)&dev->tbusy);
+    while(lp->tx_old != lp->tx_new);  /* Wait for the ring to empty */
+
     STOP_DEPCA;                       /* Temporarily stop the depca.  */
     depca_init_ring(dev);             /* Initialize the descriptor rings */
 
     if (num_addrs >= 0) {
-      SetMulticastFilter(num_addrs, (char *)addrs, (char *)hash_filter);
+      SetMulticastFilter(dev, num_addrs, (char *)addrs);
       lp->init_block.mode &= ~PROM;   /* Unset promiscuous mode */
     } else {
       lp->init_block.mode |= PROM;    /* Set promiscuous mode */
@@ -1266,171 +1184,269 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 
     LoadCSRs(dev);                    /* Reload CSR3 */
     InitRestartDepca(dev);            /* Resume normal operation. */
+    dev->tbusy = 0;                   /* Unlock the TX ring */
   }
 }
 
 /*
 ** Calculate the hash code and update the logical address filter
 ** from a list of ethernet multicast addresses.
-** Derived from a 'C' program in the AMD data book:
-** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", 
-** Pub #17781, Rev. A, May 1993
+** Big endian crc one liner is mine, all mine, ha ha ha ha!
+** LANCE calculates its hash codes big endian.
 */
-static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table)
+static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs)
 {
-  char j, ctrl, bit, octet, hashcode;
-  short int i;
-  long int CRC, poly = (long int) CRC_POLYNOMIAL;
-
-  for (i=0;i<num_addrs;i++) {                /* for each address in the list */
-    if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* is multicast address? */ 
-      CRC = (long int) 0xffffffff;           /* init CRC for each address */
-      for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
-       for(j=0;j<8;j++) {                   /* process each address bit */
-         bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
-         ctrl = ((CRC < 0) ? 1 : 0);        /* shift the control bit */
-         CRC <<= 1;                         /* shift the CRC */
-         if (bit ^ ctrl) {                  /* (bit) XOR (control bit) */
-           CRC ^= poly;                     /* (CRC) XOR (polynomial) */
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  int i, j, bit, byte;
+  u16 hashcode;
+  s32 crc, poly = CRC_POLYNOMIAL_BE;
+
+  if (num_addrs == HASH_TABLE_LEN) {       /* Set all multicast bits */
+    for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
+      lp->init_block.mcast_table[i] = (char)0xff;
+    }
+  } else {
+    /* Clear the multicast table first */
+    for (i=0; i<(HASH_TABLE_LEN>>3); i++){
+      lp->init_block.mcast_table[i]=0;
+    }
+
+    /* Add multicast addresses */
+    for (i=0;i<num_addrs;i++) {            /* for each address in the list */
+      if ((*addrs & 0x01) == 1) {          /* multicast address? */ 
+       crc = 0xffffffff;                  /* init CRC for each address */
+       for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
+         /* process each address bit */ 
+         for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
+           crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0);
          }
        }
+       hashcode = (crc & 1);              /* hashcode is 6 LSb of CRC ... */
+       for (j=0;j<5;j++) {                /* ... in reverse order. */
+         hashcode = (hashcode << 1) | ((crc>>=1) & 1);
+       }                                      
+       
+       
+       byte = hashcode >> 3;              /* bit[3-5] -> byte in filter */
+       bit = 1 << (hashcode & 0x07);      /* bit[0-2] -> bit in byte */
+       lp->init_block.mcast_table[byte] |= bit;
+      } else {                             /* skip this address */
+       addrs += ETH_ALEN;
       }
-      hashcode = (CRC & 0x00000001);         /* hashcode is 6 LSb of CRC ... */
-      for (j=0;j<5;j++) {                    /* ... in reverse order. */
-       hashcode <<= 1;
-       CRC >>= 1;
-       hashcode |= (CRC & 0x00000001);
-      }                                      
-      octet = hashcode >> 3;                  /* bit[3-5] -> octet in filter */
-                                              /* bit[0-2] -> bit in octet */
-      multicast_table[octet] |= (1 << (hashcode & 0x07));
     }
   }
+
   return;
 }
 
-#endif  /* HAVE_MULTICAST */
-
-#ifndef MODULE
 /*
 ** ISA bus I/O device probe
 */
-static struct device *isa_probe(struct device *dev)
+static void isa_probe(struct device *dev, u_long ioaddr)
 {
-  int *port, ports[] = DEPCA_IO_PORTS;
-  int status;
-
-  for (status = -ENODEV, port = &ports[0]; 
-                             *port && (num_depcas < MAX_NUM_DEPCAS); port++) {
-    int ioaddr = *port;
+  int i = num_depcas, maxSlots;
+  s32 ports[] = DEPCA_IO_PORTS;
+
+  if (!ioaddr && autoprobed) return ;          /* Been here before ! */
+  if (ioaddr > 0x400) return;                  /* EISA Address */
+  if (i >= MAX_NUM_DEPCAS) return;             /* Too many ISA adapters */
+
+  if (ioaddr == 0) {                           /* Autoprobing */
+    maxSlots = MAX_NUM_DEPCAS;
+  } else {                                     /* Probe a specific location */
+    ports[i] = ioaddr;
+    maxSlots = i + 1;
+  }
 
-    if (DevicePresent(ioaddr) == 0) {
-      if (num_depcas > 0) {        /* only gets here in autoprobe */
-       dev = alloc_device(dev, ioaddr);
-      } else {
-       if ((status = depca_probe1(dev, ioaddr)) == 0) {
-         num_depcas++;
+  for (; (i<maxSlots) && (dev!=NULL) && ports[i]; i++) {
+    if (DevicePresent(ports[i]) == 0) { 
+      if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
+       if ((dev = alloc_device(dev, ports[i])) != NULL) {
+         if (depca_hw_init(dev, ports[i]) == 0) {
+           num_depcas++;
+         }
+         num_eth++;
        }
+      } else if (autoprobed) {
+       printk("%s: region already allocated at 0x%04x.\n", dev->name,ports[i]);
       }
-      num_eth++;
     }
   }
-  return dev;
+
+  return;
 }
 
 /*
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
-** the motherboard.
+** the motherboard. Upto 15 EISA devices are supported.
 */
-static struct device *eisa_probe(struct device *dev)
+static void eisa_probe(struct device *dev, u_long ioaddr)
 {
-  int i, ioaddr = DEPCA_EISA_IO_PORTS;
-  int status;
-
-  ioaddr+=0x1000;                         /* get the first slot address */
-  for (status = -ENODEV, i=1; i<MAX_EISA_SLOTS; i++, ioaddr+=0x1000) {
-
-    if (EISA_signature(DEPCA_EISA_ID) == 0) {
-      if (num_depcas > 0) {        /* only gets here in autoprobe */
-       dev = alloc_device(dev, ioaddr);
-      } else {
-       if ((status = depca_probe1(dev, ioaddr)) == 0) {
-         num_depcas++;
+  int i, maxSlots;
+  u_long iobase;
+  char name[DEPCA_STRLEN];
+
+  if (!ioaddr && autoprobed) return ;            /* Been here before ! */
+  if ((ioaddr < 0x400) && (ioaddr > 0)) return;  /* ISA Address */
+
+  if (ioaddr == 0) {                           /* Autoprobing */
+    iobase = EISA_SLOT_INC;                    /* Get the first slot address */
+    i = 1;
+    maxSlots = MAX_EISA_SLOTS;
+  } else {                                     /* Probe a specific location */
+    iobase = ioaddr;
+    i = (ioaddr >> 12);
+    maxSlots = i + 1;
+  }
+  if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS;
+
+  for (; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
+    if (EISA_signature(name, EISA_ID)) {
+      if (DevicePresent(iobase) == 0) { 
+       if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+         if ((dev = alloc_device(dev, iobase)) != NULL) {
+           if (depca_hw_init(dev, iobase) == 0) {
+             num_depcas++;
+           }
+           num_eth++;
+         }
+       } else if (autoprobed) {
+         printk("%s: region already allocated at 0x%04lx.\n",dev->name,iobase);
        }
       }
-      num_eth++;
     }
   }
-  return dev;
+
+  return;
 }
 
 /*
 ** Allocate the device by pointing to the next available space in the
 ** device structure. Should one not be available, it is created.
 */
-static struct device *alloc_device(struct device *dev, int ioaddr)
+static struct device *alloc_device(struct device *dev, u_long iobase)
 {
+  int addAutoProbe = 0;
+  struct device *tmp = NULL, *ret;
+  int (*init)(struct device *) = NULL;
+
   /*
   ** Check the device structures for an end of list or unused device
   */
-  while (dev->next != NULL) {
-    if (dev->next->base_addr == 0xffe0) break;
-    dev = dev->next;         /* walk through eth device list */
-    num_eth++;               /* increment eth device number */
-  }
+  if (!loading_module) {
+    while (dev->next != NULL) {
+      if ((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0)) break;
+      dev = dev->next;                     /* walk through eth device list */
+      num_eth++;                           /* increment eth device number */
+    }
 
-  /*
-  ** If no more device structures, malloc one up. If memory could
-  ** not be allocated, print an error message.
-  */
-  if (dev->next == NULL) {
-    dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
-                                        GFP_KERNEL);
-    if (dev->next == NULL) {
-      printk("eth%d: Device not initialised, insufficient memory\n",
-            num_eth);
+    /*
+    ** If an autoprobe is requested for another device, we must re-insert
+    ** the request later in the list. Remember the current information.
+    */
+    if ((dev->base_addr == 0) && (num_depcas > 0)) {
+      addAutoProbe++;
+      tmp = dev->next;                     /* point to the next device */
+      init = dev->init;                    /* remember the probe function */
     }
-  }
+
+    /*
+    ** If at end of list and can't use current entry, malloc one up. 
+    ** If memory could not be allocated, print an error message.
+    */
+    if ((dev->next == NULL) &&  
+       !((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0))){
+      dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+                                          GFP_KERNEL);
+
+      dev = dev->next;                     /* point to the new device */
+      if (dev == NULL) {
+       printk("eth%d: Device not initialised, insufficient memory\n",
+              num_eth);
+      } else {
+       /*
+       ** If the memory was allocated, point to the new memory area
+       ** and initialize it (name, I/O address, next device (NULL) and
+       ** initialisation probe routine).
+       */
+       dev->name = (char *)(dev + sizeof(struct device));
+       if (num_eth > 9999) {
+         sprintf(dev->name,"eth????");    /* New device name */
+       } else {
+         sprintf(dev->name,"eth%d", num_eth);/* New device name */
+       }
+       dev->base_addr = iobase;           /* assign the io address */
+       dev->next = NULL;                  /* mark the end of list */
+       dev->init = &depca_probe;          /* initialisation routine */
+       num_depcas++;
+      }
+    }
+    ret = dev;                             /* return current struct, or NULL */
   
-  /*
-  ** If the memory was allocated, point to the new memory area
-  ** and initialize it (name, I/O address, next device (NULL) and
-  ** initialisation probe routine).
-  */
-  if ((dev->next != NULL) &&
-      (num_eth > 0) && (num_eth < 9999)) {
-    dev = dev->next;                    /* point to the new device */
-    dev->name = (char *)(dev + 1);
-    sprintf(dev->name,"eth%d", num_eth);/* New device name */
-    dev->base_addr = ioaddr;            /* assign the io address */
-    dev->next = NULL;                   /* mark the end of list */
-    dev->init = &depca_probe;           /* initialisation routine */
-    num_depcas++;
+    /*
+    ** Now figure out what to do with the autoprobe that has to be inserted.
+    ** Firstly, search the (possibly altered) list for an empty space.
+    */
+    if (ret != NULL) {
+      if (addAutoProbe) {
+       for (;(tmp->next!=NULL) && (tmp->base_addr!=DEPCA_NDA); tmp=tmp->next);
+
+       /*
+       ** If no more device structures and can't use the current one, malloc
+       ** one up. If memory could not be allocated, print an error message.
+       */
+       if ((tmp->next == NULL) && !(tmp->base_addr == DEPCA_NDA)) {
+         tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+                                              GFP_KERNEL);
+         tmp = tmp->next;                     /* point to the new device */
+         if (tmp == NULL) {
+           printk("%s: Insufficient memory to extend the device list.\n", 
+                  dev->name);
+         } else {
+           /*
+           ** If the memory was allocated, point to the new memory area
+           ** and initialize it (name, I/O address, next device (NULL) and
+           ** initialisation probe routine).
+           */
+           tmp->name = (char *)(tmp + sizeof(struct device));
+           if (num_eth > 9999) {
+             sprintf(tmp->name,"eth????");       /* New device name */
+           } else {
+             sprintf(tmp->name,"eth%d", num_eth);/* New device name */
+           }
+           tmp->base_addr = 0;                /* re-insert the io address */
+           tmp->next = NULL;                  /* mark the end of list */
+           tmp->init = init;                  /* initialisation routine */
+         }
+       } else {                               /* structure already exists */
+         tmp->base_addr = 0;                  /* re-insert the io address */
+       }
+      }
+    }
+  } else {
+    ret = dev;
   }
 
-  return dev;
+  return ret;
 }
-#endif    /* MODULE */
 
 /*
 ** Look for a particular board name in the on-board Remote Diagnostics
-** and Boot (RDB) ROM. This will also give us a clue to the network RAM
+** and Boot (readb) ROM. This will also give us a clue to the network RAM
 ** base address.
 */
-static char *DepcaSignature(unsigned long mem_addr)
+static void DepcaSignature(char *name, u_long paddr)
 {
-  unsigned long i,j,k;
-  static char signatures[][DEPCA_NAME_LENGTH] = DEPCA_SIGNATURE;
-  static char thisName[DEPCA_NAME_LENGTH];
-  char tmpstr[17];
+  u_int i,j,k;
+  char *signatures[] = DEPCA_SIGNATURE;
+  char tmpstr[16];
 
   for (i=0;i<16;i++) {                  /* copy the first 16 bytes of ROM to */
-    tmpstr[i] = *(unsigned char *)(mem_addr+0xc000+i); /* a temporary string */
+    tmpstr[i] = readb(paddr+0xc000+i);  /* a temporary string */
   }
-  tmpstr[i]='\0';
 
-  strcpy(thisName,"");
-  for (i=0;*signatures[i]!='\0' && *thisName=='\0';i++) {
+  strcpy(name,"");
+  for (i=0;*signatures[i]!='\0' && *name=='\0';i++) {
     for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) {
       if (signatures[i][k] == tmpstr[j]) {              /* track signature */
        k++;
@@ -1439,11 +1455,13 @@ static char *DepcaSignature(unsigned long mem_addr)
       }
     }
     if (k == strlen(signatures[i])) {
-      strcpy(thisName,signatures[i]);
+      strcpy(name,signatures[i]);
     }
   }
 
-  return thisName;                    /* return the device name string */
+  adapter = i - 1;
+
+  return;
 }
 
 /*
@@ -1461,18 +1479,19 @@ static char *DepcaSignature(unsigned long mem_addr)
 ** PROM address counter is correctly positioned at the start of the
 ** ethernet address for later read out.
 */
-static int DevicePresent(short ioaddr)
+static int DevicePresent(u_long ioaddr)
 {
   union {
     struct {
-      u_long a;
-      u_long b;
+      u32 a;
+      u32 b;
     } llsig;
-    char Sig[sizeof(long) << 1];
+    char Sig[sizeof(u32) << 1];
   } dev;
   short sigLength=0;
-  char data;
-  int i, j, nicsr, status = 0;
+  s8 data;
+  s16 nicsr;
+  int i, j, status = 0;
 
   data = inb(DEPCA_PROM);                /* clear counter on DEPCA */
   data = inb(DEPCA_PROM);                /* read data */
@@ -1485,13 +1504,13 @@ static int DevicePresent(short ioaddr)
   
   dev.llsig.a = ETH_PROM_SIG;
   dev.llsig.b = ETH_PROM_SIG;
-  sigLength = sizeof(long) << 1;
+  sigLength = sizeof(u32) << 1;
 
   for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
     data = inb(DEPCA_PROM);
     if (dev.Sig[j] == data) {    /* track signature */
       j++;
-    } else {                    /* lost signature; begin search again */
+    } else {                     /* lost signature; begin search again */
       if (data == dev.Sig[0]) {  /* rare case.... */
        j=1;
       } else {
@@ -1507,23 +1526,112 @@ static int DevicePresent(short ioaddr)
   return status;
 }
 
+/*
+** The DE100 and DE101 PROM accesses were made non-standard for some bizarre
+** reason: access the upper half of the PROM with x=0; access the lower half
+** with x=1.
+*/
+static int get_hw_addr(struct device *dev)
+{
+  u_long ioaddr = dev->base_addr;
+  int i, k, tmp, status = 0;
+  u_short j, x, chksum;
+
+  x = (((adapter == de100) || (adapter == de101)) ? 1 : 0);
+
+  for (i=0,k=0,j=0;j<3;j++) {
+    k <<= 1 ;
+    if (k > 0xffff) k-=0xffff;
+
+    k += (u_char) (tmp = inb(DEPCA_PROM + x));
+    dev->dev_addr[i++] = (u_char) tmp;
+    k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
+    dev->dev_addr[i++] = (u_char) tmp;
+
+    if (k > 0xffff) k-=0xffff;
+  }
+  if (k == 0xffff) k=0;
+
+  chksum = (u_char) inb(DEPCA_PROM + x);
+  chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
+  if (k != chksum) status = -1;
+
+  return status;
+}
+
+/*
+** Load a packet into the shared memory
+*/
+static int load_packet(struct device *dev, struct sk_buff *skb)
+{
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  int i, entry, end, len, status = 0;
+
+  entry = lp->tx_new;                                 /* Ring around buffer number. */
+  end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
+  if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {/* Enough room? */
+    /* 
+    ** Caution: the write order is important here... don't set up the
+    ** ownership rights until all the other information is in place.
+    */
+    if (end < entry) {                         /* wrapped buffer */
+      len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
+      memcpy_toio(lp->tx_memcpy[entry], skb->data, len);
+      memcpy_toio(lp->tx_memcpy[0], skb->data + len, skb->len - len);
+    } else {                                   /* linear buffer */
+      memcpy_toio(lp->tx_memcpy[entry], skb->data, skb->len);
+    }
+
+    /* set up the buffer descriptors */
+    len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+    for (i = entry; i != end; i = (++i) & lp->txRingMask) {
+                                               /* clean out flags */
+      writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
+      writew(0x0000, &lp->tx_ring[i].misc);       /* clears other error flags */
+      writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);/* packet length in buffer */
+      len -= TX_BUFF_SZ;
+    }
+                                               /* clean out flags */
+    writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
+    writew(0x0000, &lp->tx_ring[end].misc);       /* clears other error flags */
+    writew(-len, &lp->tx_ring[end].length);       /* packet length in last buff */
+
+                                               /* start of packet */
+    writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
+                                               /* end of packet */
+    writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
+
+    for (i=end; i!=entry; --i) {
+                                               /* ownership of packet */
+      writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
+      if (i == 0) i=lp->txRingMask+1;
+    }   
+    writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
+    lp->tx_new = (++end) & lp->txRingMask;     /* update current pointers */
+  } else {
+    status = -1;
+  }
+
+  return status;
+}
+
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-static int EISA_signature(short iobase)
+static int EISA_signature(char *name, s32 eisa_id)
 {
-  unsigned long i;
-  int status;
+  u_int i;
   char *signatures[] = DEPCA_SIGNATURE;
-  char ManCode[8];
+  char ManCode[DEPCA_STRLEN];
   union {
-    u_long ID;
-    u_char Id[4];
+    s32 ID;
+    char Id[4];
   } Eisa;
+  int status = 0;
 
-  for (i=0; i<4; i++) {
-    Eisa.Id[i] = inb(iobase + i);
-  }
+  *name = '\0';
+  Eisa.ID = inl(eisa_id);
 
   ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
   ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
@@ -1532,13 +1640,179 @@ static int EISA_signature(short iobase)
   ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
   ManCode[5]='\0';
 
-  for (status = -ENXIO, i=0;*signatures[i] != '\0' && status;i++) {
+  for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
     if (strstr(ManCode, signatures[i]) != NULL) {
-      status = 0;
+      strcpy(name,ManCode);
+      status = 1;
     }
   }
-  
-  return status;                            /* return the device name string */
+
+  return status;
+}
+
+/*
+** Perform IOCTL call functions here. Some are privileged operations and the
+** effective uid is checked in those cases.
+*/
+static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data;
+  int i, status = 0;
+  u_long ioaddr = dev->base_addr;
+  union {
+    u8  addr[(HASH_TABLE_LEN * ETH_ALEN)];
+    u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+    u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
+  } tmp;
+
+  switch(ioc->cmd) {
+  case DEPCA_GET_HWADDR:             /* Get the hardware address */
+    for (i=0; i<ETH_ALEN; i++) {
+      tmp.addr[i] = dev->dev_addr[i];
+    }
+    ioc->len = ETH_ALEN;
+    if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    }
+
+    break;
+  case DEPCA_SET_HWADDR:             /* Set the hardware address */
+    if (suser()) {
+      if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) {
+       memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
+       for (i=0; i<ETH_ALEN; i++) {
+         dev->dev_addr[i] = tmp.addr[i];
+       }
+       while(dev->tbusy);              /* Stop ring access */
+       set_bit(0, (void*)&dev->tbusy);
+       while(lp->tx_old != lp->tx_new);/* Wait for the ring to empty */
+
+       STOP_DEPCA;                     /* Temporarily stop the depca.  */
+       depca_init_ring(dev);           /* Initialize the descriptor rings */
+       LoadCSRs(dev);                  /* Reload CSR3 */
+       InitRestartDepca(dev);          /* Resume normal operation. */
+       dev->tbusy = 0;                 /* Unlock the TX ring */
+      }
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case DEPCA_SET_PROM:               /* Set Promiscuous Mode */
+    if (suser()) {
+      while(dev->tbusy);                /* Stop ring access */
+      set_bit(0, (void*)&dev->tbusy);
+      while(lp->tx_old != lp->tx_new);  /* Wait for the ring to empty */
+
+      STOP_DEPCA;                       /* Temporarily stop the depca.  */
+      depca_init_ring(dev);             /* Initialize the descriptor rings */
+      lp->init_block.mode |= PROM;      /* Set promiscuous mode */
+
+      LoadCSRs(dev);                    /* Reload CSR3 */
+      InitRestartDepca(dev);            /* Resume normal operation. */
+      dev->tbusy = 0;                   /* Unlock the TX ring */
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case DEPCA_CLR_PROM:               /* Clear Promiscuous Mode */
+    if (suser()) {
+      while(dev->tbusy);                /* Stop ring access */
+      set_bit(0, (void*)&dev->tbusy);
+      while(lp->tx_old != lp->tx_new);  /* Wait for the ring to empty */
+
+      STOP_DEPCA;                       /* Temporarily stop the depca.  */
+      depca_init_ring(dev);             /* Initialize the descriptor rings */
+      lp->init_block.mode &= ~PROM;     /* Clear promiscuous mode */
+
+      LoadCSRs(dev);                    /* Reload CSR3 */
+      InitRestartDepca(dev);            /* Resume normal operation. */
+      dev->tbusy = 0;                   /* Unlock the TX ring */
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case DEPCA_SAY_BOO:                /* Say "Boo!" to the kernel log file */
+    printk("%s: Boo!\n", dev->name);
+
+    break;
+  case DEPCA_GET_MCA:                /* Get the multicast address table */
+    ioc->len = (HASH_TABLE_LEN >> 3);
+    if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, lp->init_block.mcast_table, ioc->len); 
+    }
+
+    break;
+  case DEPCA_SET_MCA:                /* Set a multicast address */
+    if (suser()) {
+      if (ioc->len != HASH_TABLE_LEN) {         /* MCA changes */
+       if (!(status=verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len))) {
+         memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+         set_multicast_list(dev, ioc->len, tmp.addr);
+       }
+      } else {
+       set_multicast_list(dev, ioc->len, NULL);
+      }
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case DEPCA_CLR_MCA:                /* Clear all multicast addresses */
+    if (suser()) {
+      set_multicast_list(dev, 0, NULL);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case DEPCA_MCA_EN:                 /* Enable pass all multicast addressing */
+    if (suser()) {
+      set_multicast_list(dev, HASH_TABLE_LEN, NULL);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case DEPCA_GET_STATS:              /* Get the driver statistics */
+    cli();
+    ioc->len = sizeof(lp->pktStats);
+    if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, &lp->pktStats, ioc->len); 
+    }
+    sti();
+
+    break;
+  case DEPCA_CLR_STATS:              /* Zero out the driver statistics */
+    if (suser()) {
+      cli();
+      memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+      sti();
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case DEPCA_GET_REG:                /* Get the DEPCA Registers */
+    i=0;
+    tmp.sval[i++] = inw(DEPCA_NICSR);
+    outw(CSR0, DEPCA_ADDR);              /* status register */
+    tmp.sval[i++] = inw(DEPCA_DATA);
+    memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
+    ioc->len = i+sizeof(struct depca_init);
+    if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    }
+
+    break;
+  default:
+    status = -EOPNOTSUPP;
+  }
+
+  return status;
 }
 
 #ifdef MODULE
@@ -1549,13 +1823,8 @@ static struct device thisDepca = {
   0x200, 7,   /* I/O address, IRQ */
   0, 0, 0, NULL, depca_probe };
 
-/*
- *     This is a tweak to keep the insmod program happy. It can only
- *     set int values with var=value so we split these out.
- */
-int irq=7;     /* EDIT THESE LINE FOR YOUR CONFIGURATION */
-int io=0x200;   /* Or use the irq= io= options to insmod */
+static int irq=7;      /* EDIT THESE LINE FOR YOUR CONFIGURATION */
+static int io=0x200;    /* Or use the irq= io= options to insmod */
        
 int
 init_module(void)
@@ -1564,6 +1833,7 @@ init_module(void)
   thisDepca.base_addr=io;
   if (register_netdev(&thisDepca) != 0)
     return -EIO;
+
   return 0;
 }
 
@@ -1574,6 +1844,11 @@ cleanup_module(void)
     printk("%s: device busy, remove delayed\n",thisDepca.name);
   } else {
     release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE);
+    if (thisDepca.priv) {
+      kfree_s(thisDepca.priv, sizeof(struct depca_private));
+      thisDepca.priv = NULL;
+    }
+
     unregister_netdev(&thisDepca);
   }
 }
index a3a30a8aa9cf72385c20448208e94cd20df6f54d..012f7399527aba274e17d4b0730fc020ecab817c 100644 (file)
@@ -62,6 +62,8 @@
 #define STOP           0x0004  /* Stop */
 #define STRT           0x0002  /* Start */
 #define INIT           0x0001  /* Initialize */
+#define INTM            0xff00  /* Interrupt Mask */
+#define INTE            0xfff0  /* Interrupt Enable */
 
 /*
 ** CONTROL AND STATUS REGISTER 3 (CSR3)
 #define T_DEF          0x0400  /* Deferred */
 #define T_STP       0x02000000         /* Start of Packet */
 #define T_ENP       0x01000000 /* End of Packet */
+#define T_FLAGS     0xff000000  /* TX Flags Field */
 
 /*
 ** Transmit Message Descriptor 3 (TMD3) bit definitions.
 /*
 ** Miscellaneous
 */
+#define HASH_TABLE_LEN   64           /* Bits */
+#define HASH_BITS        0x003f       /* 6 LS bits */
 
 #define MASK_INTERRUPTS   1
 #define UNMASK_INTERRUPTS 0
 
-#define EISA_EN         0x0001   /* Enable EISA bus buffers */
-#define DEPCA_EISA_ID   ioaddr+0x80   /* ID long word for EISA card */
-#define DEPCA_EISA_CTRL ioaddr+0x84   /* Control word for EISA card */
+#define EISA_EN         0x0001        /* Enable EISA bus buffers */
+#define EISA_ID         iobase+0x0080 /* ID long word for EISA card */
+#define EISA_CTRL       iobase+0x0084 /* Control word for EISA card */
+
+/*
+** Include the IOCTL stuff
+*/
+#include <linux/sockios.h>
+
+#define        DEPCAIOCTL      SIOCDEVPRIVATE
+
+struct depca_ioctl {
+       unsigned short cmd;                /* Command to run */
+       unsigned short len;                /* Length of the data buffer */
+       unsigned char  *data;              /* Pointer to the data buffer */
+};
+
+/* 
+** Recognised commands for the driver 
+*/
+#define DEPCA_GET_HWADDR       0x01 /* Get the hardware address */
+#define DEPCA_SET_HWADDR       0x02 /* Get the hardware address */
+#define DEPCA_SET_PROM         0x03 /* Set Promiscuous Mode */
+#define DEPCA_CLR_PROM         0x04 /* Clear Promiscuous Mode */
+#define DEPCA_SAY_BOO          0x05 /* Say "Boo!" to the kernel log file */
+#define DEPCA_GET_MCA          0x06 /* Get a multicast address */
+#define DEPCA_SET_MCA          0x07 /* Set a multicast address */
+#define DEPCA_CLR_MCA          0x08 /* Clear a multicast address */
+#define DEPCA_MCA_EN           0x09 /* Enable a multicast address group */
+#define DEPCA_GET_STATS        0x0a /* Get the driver statistics */
+#define DEPCA_CLR_STATS        0x0b /* Zero out the driver statistics */
+#define DEPCA_GET_REG          0x0c /* Get the Register contents */
+#define DEPCA_SET_REG          0x0d /* Set the Register contents */
+#define DEPCA_DUMP              0x0f /* Dump the DEPCA Status */
+
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
new file mode 100644 (file)
index 0000000..487cecb
--- /dev/null
@@ -0,0 +1,949 @@
+/*
+ * hp100.c: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
+ *
+ * Author:  Jaroslav Kysela, <perex@pf.jcu.cz>
+ *
+ * Supports only the following Hewlett Packard cards:
+ *
+ *     HP J2577        10/100 EISA card with REVA Cascade chip
+ *     HP J2573        10/100 ISA card with REVA Cascade chip
+ *     HP 27248B       10 only EISA card with Cascade chip
+ *     HP J2577        10/100 EISA card with Cascade chip
+ *     HP J2573        10/100 ISA card with Cascade chip
+ *
+ * Other ATT2MD01 Chip based boards might be supported in the future
+ * (there are some minor changes needed).
+ *
+ * This driver is based on the 'hpfepkt' crynwr packet driver.
+ *
+ * This source/code is public free; you can distribute it and/or modify 
+ * it under terms of the GNU General Public License (published by the
+ * Free Software Foundation) either version two of this License, or any 
+ * later version.
+ * ----------------------------------------------------------------------------
+ *
+ * Note: Some routines (interrupt handling, transmit) assumes that  
+ *       there is the PERFORMANCE page selected...
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * If you are going to use the module version of this driver, you may
+ * change this values at the "insert time" :
+ *
+ *   Variable                   Description
+ *
+ *   hp100_default_rx_ratio    Range 1-99 - onboard memory used for RX 
+ *                              packets in %.
+ *   hp100_port                        Adapter port (for example 0x380).
+ *
+ * ----------------------------------------------------------------------------
+ * MY BEST REGARDS GOING TO:
+ *
+ * IPEX s.r.o which lend me two HP J2573 cards and
+ * the HP AdvanceStack 100VG Hub-15 for debugging.
+ *
+ * Russel Nellson <nelson@crynwr.com> for help with obtaining sources
+ * of the 'hpfepkt' packet driver.
+ *
+ * Also thanks to Abacus Electric s.r.o which let me to use their 
+ * motherboard for my second computer.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * TO DO:
+ * ======
+ *       - ioctl handling - some runtime setup things
+ *       - PCI card support
+ *
+ * Revision history:
+ * =================
+ * 
+ *    Version   Date       Description
+ *
+ *     0.1     14-May-95   Initial writing. ALPHA code was released.
+ *                          Only HP J2573 on 10Mb/s (two machines) tested.
+ *      0.11    14-Jun-95   Reset interface bug fixed?
+ *                         Little bug in hp100_close function fixed.
+ *                          100Mb/s connection debugged.
+ *
+ */
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif /* MODULE */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/types.h>
+
+#include "hp100.h"
+
+/*
+ *  defines
+ */
+
+#define HP100_MAX_PACKET_SIZE  (1536+4)
+#define HP100_MIN_PACKET_SIZE  60
+
+#ifndef HP100_RX_RATIO
+/* default - 65% onboard memory on the card are used for RX packets */
+#define HP100_RX_RATIO         65
+#endif
+
+/*
+ *  structures
+ */
+
+struct hp100_eisa_id {
+  u_int id;
+  char *name;
+};
+
+struct hp100_private {
+  struct hp100_eisa_id *id;
+  u_short soft_model;
+  u_int memory_size;
+  u_short rx_ratio;
+  short lan_type;                  /* 10Mb/s, 100Mb/s or -1 (error) */
+  int hub_status;                  /* login to hub successfull? */
+  u_char mac1_mode;
+  u_char mac2_mode;
+  struct enet_statistics stats;
+};
+
+struct hp100_rx_look {
+  struct hp100_rx_header header;
+  char something[ 24 ];                    /* 2 * MAC @6 + protocol @2+8 + pad to 4 byte */
+};
+
+/*
+ *  variables
+ */
+static struct hp100_eisa_id hp100_eisa_ids[] = {
+  { 0x080F1F022, "HP J2577 rev A" }, /* 10/100 EISA card with REVA Cascade chip */
+  { 0x050F1F022, "HP J2573 rev A" }, /* 10/100 ISA card with REVA Cascade chip */
+  { 0x02019F022, "HP 27248B" },             /* 10 only EISA card with Cascade chip */
+  { 0x04019F022, "HP J2577" },      /* 10/100 EISA card with Cascade chip */
+  { 0x05019F022, "HP J2573" }       /* 10/100 ISA card with Cascade chip */
+};
+
+#ifdef MODULE
+int hp100_default_rx_ratio = HP100_RX_RATIO;
+#endif
+
+/*
+ *  prototypes
+ */
+
+static int hp100_probe1( struct device *dev, int ioaddr );
+static int hp100_open( struct device *dev );
+static int hp100_close( struct device *dev );
+static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
+static void hp100_rx( struct device *dev );
+static struct enet_statistics *hp100_get_stats( struct device *dev );
+static void hp100_update_stats( struct device *dev );
+#ifdef HAVE_MULTICAST
+static void hp100_set_multicast_list( struct device *dev, int num_addrs, void *addrs );
+#endif
+#ifndef LINUX_1_1_52
+static void hp100_interrupt( int irq, struct pt_regs *regs );
+#else
+static void hp100_interrupt( int irq );
+#endif
+
+static void hp100_start_interface( struct device *dev );
+static void hp100_stop_interface( struct device *dev );
+static void hp100_load_eeprom( struct device *dev );
+static int hp100_sense_lan( struct device *dev );
+static int hp100_login_to_vg_hub( struct device *dev );
+static int hp100_down_vg_link( struct device *dev );
+
+/*
+ *  probe functions
+ */
+int hp100_probe( struct device *dev )
+{
+  int base_addr = dev ? dev -> base_addr : 0;
+  int ioaddr;
+        
+  if ( base_addr > 0xff )      /* Check a single specified location. */
+    return hp100_probe1(dev, base_addr);
+   else 
+    if ( base_addr != 0 ) return -ENXIO;
+         
+  /* at first - probe all EISA possible port regions (if EISA bus present) */
+  
+  for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 )
+    {
+      if ( check_region( ioaddr, 0x20 ) ) continue;
+      if ( hp100_probe1( dev, ioaddr ) == 0 ) return 0;
+    }
+         
+  /* at second - probe all ISA possible port regions */
+         
+  for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 )
+    {
+      if ( check_region( ioaddr, 0x20 ) ) continue;
+      if ( hp100_probe1( dev, ioaddr ) == 0 ) return 0;
+    }
+                                                                            
+  return -ENODEV;
+}
+
+static int hp100_probe1( struct device *dev, int ioaddr )
+{
+  int i;
+  u_char uc;
+  u_int eisa_id;
+  struct hp100_private *lp;
+  struct hp100_eisa_id *eid;
+
+  if ( dev == NULL )
+    {
+#ifdef HP100_DEBUG
+      printk( "hp100_probe1: dev == NULL ?\n" );
+#endif
+      return EIO;
+    }
+
+  if ( inb( ioaddr + 0 ) != HP100_HW_ID_0 ||
+       inb( ioaddr + 1 ) != HP100_HW_ID_1 ||
+       ( inb( ioaddr + 2 ) & 0xf0 ) != HP100_HW_ID_2_REVA ||
+       inb( ioaddr + 3 ) != HP100_HW_ID_3 ) 
+     return -ENODEV;
+
+  dev -> base_addr = ioaddr;
+
+#ifdef HP100_DEBUG_PROBE1
+  printk( "hp100_probe1: card found at port 0x%x\n", ioaddr );
+#endif
+
+  hp100_page( ID_MAC_ADDR );
+  for ( i = uc = eisa_id = 0; i < 4; i++ )
+    {
+      eisa_id >>= 8;
+      eisa_id |= ( hp100_inb( BOARD_ID + i ) ) << 24;
+      uc += eisa_id >> 24;
+    }
+  uc += hp100_inb( BOARD_ID + 4 );
+
+#ifdef HP100_DEBUG_PROBE1
+  printk( "hp100_probe1: EISA ID = 0x%08x  checksum = 0x%02x\n", eisa_id, uc );
+#endif
+
+  if ( uc != 0xff )            /* bad checksum? */
+    {
+      printk( "hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr );
+      return -ENODEV;
+    }  
+
+  for ( i = 0; i < sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ); i++ )
+    if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) )
+      break;
+  if ( i >= sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ) )
+    {
+      printk( "hp100_probe1: card at port 0x%x isn't known\n", ioaddr );
+      return -ENODEV;
+    }
+  eid = &hp100_eisa_ids[ i ];
+  if ( ( eid -> id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
+    {
+      printk( "hp100_probe1: newer version of card %s at port 0x%x - unsupported\n", 
+       eid -> name, ioaddr );
+      return -ENODEV;
+    }
+
+  for ( i = uc = 0; i < 7; i++ )
+    uc += hp100_inb( LAN_ADDR + i );
+  if ( uc != 0xff )
+    {
+      printk( "hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n", 
+       eid -> name, ioaddr );
+      return -EIO;
+    }
+
+  hp100_page( HW_MAP );
+  if ( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN | HP100_BM_WRITE | HP100_BM_READ ) )
+    {
+      printk( "hp100_probe1: memory mapped io isn't supported (card %s at port 0x%x)\n",
+       eid -> name, ioaddr );
+      return -EIO;
+    }
+
+  if ( ( dev -> priv = kmalloc( sizeof( struct hp100_private ), GFP_KERNEL ) ) == NULL )
+    return -ENOMEM;
+  memset( dev -> priv, 0, sizeof( struct hp100_private ) );
+
+  lp = (struct hp100_private *)dev -> priv;
+  lp -> id = eid;
+  hp100_page( ID_MAC_ADDR );
+  lp -> soft_model = hp100_inb( SOFT_MODEL );
+  lp -> mac1_mode = HP100_MAC1MODE3;
+  lp -> mac2_mode = HP100_MAC2MODE3;
+  
+  dev -> base_addr = ioaddr;
+  hp100_page( HW_MAP );
+  dev -> irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQ_MASK;
+  if ( dev -> irq == 2 ) dev -> irq = 9;
+  lp -> memory_size = 0x200 << ( ( hp100_inb( SRAM ) & 0xe0 ) >> 5 );
+#ifndef MODULE
+  lp -> rx_ratio = HP100_RX_RATIO;
+#else
+  lp -> rx_ratio = hp100_default_rx_ratio;
+#endif
+
+  dev -> open = hp100_open;
+  dev -> stop = hp100_close;
+  dev -> hard_start_xmit = hp100_start_xmit;
+  dev -> get_stats = hp100_get_stats;
+#ifdef HAVE_MULTICAST
+  dev -> set_multicast_list = &hp100_set_multicast_list;
+#endif
+
+#ifndef LINUX_1_1_52
+  request_region( dev -> base_addr, 0x20, eid -> name );
+#endif
+
+  hp100_page( ID_MAC_ADDR );
+  for ( i = uc = 0; i < 6; i++ )
+    dev -> dev_addr[ i ] = hp100_inb( LAN_ADDR + i );
+
+  ether_setup( dev );
+
+  lp -> lan_type = hp100_sense_lan( dev );
+     
+  printk( "%s: %s at 0x%x, IRQ %d, %dkB SRAM (rx/tx %d%%), ",
+    dev -> name, lp -> id -> name, ioaddr, dev -> irq, 
+    lp -> memory_size >> ( 10 - 4 ), lp -> rx_ratio );
+  switch ( lp -> lan_type ) {
+    case HP100_LAN_100: printk( "100Mb/s VG TP" ); break;
+    case HP100_LAN_10:  printk( "10Mb/s TP" );     break;
+    default:           printk( "link down" );     break;
+  }
+  printk( ".\n" );
+
+  return 0;
+}
+
+/*
+ *  open/close functions
+ */
+
+static int hp100_open( struct device *dev )
+{
+  int i;
+  int ioaddr = dev -> base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+  if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) < 0 )
+    {
+      printk( "%s: no connection found - check wire\n", dev -> name );
+      return -EIO;
+    }
+
+  if ( request_irq( dev -> irq, hp100_interrupt, SA_INTERRUPT, lp -> id -> name ) )
+    {
+      printk( "%s: unable to get IRQ %d\n", dev -> name, dev -> irq );
+      return -EAGAIN;
+    }
+  irq2dev_map[ dev -> irq ] = dev;
+
+#ifdef MODULE
+  MOD_INC_USE_COUNT;
+#endif
+  
+  dev -> tbusy = 0;
+  dev -> trans_start = jiffies;
+  dev -> interrupt = 0;
+  dev -> start = 1;
+
+  lp -> mac1_mode = HP100_MAC1MODE3;
+  lp -> mac2_mode = HP100_MAC2MODE3;
+  
+  hp100_page( MAC_CTRL );
+  hp100_orw( HP100_LINK_BEAT_DIS, LAN_CFG_10 );
+
+  hp100_stop_interface( dev );
+  hp100_reset_card();
+  hp100_load_eeprom( dev );
+
+  hp100_outw( HP100_MMAP_DIS | HP100_SET_HB | 
+              HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
+  hp100_outw( HP100_DEBUG_EN | HP100_RX_HDR | HP100_EE_EN | HP100_RESET_HB |
+              HP100_FAKE_INT | HP100_RESET_LB, OPTION_LSW );
+#if 0
+  hp100_outw( HP100_PRIORITY_TX | HP100_ADV_NXT_PKT | 
+              HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+#else
+  hp100_outw( HP100_ADV_NXT_PKT | HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+#endif
+
+  hp100_page( MAC_ADDRESS );
+  for ( i = 0; i < 6; i++ )
+    hp100_outb( dev -> dev_addr[ i ], MAC_ADDR + i );
+  for ( i = 0; i < 8; i++ )            /* setup multicast filter to receive all */
+    hp100_outb( 0xff, HASH_BYTE0 + i );
+  hp100_page( PERFORMANCE );
+  hp100_outw( 0xfefe, IRQ_MASK );      /* mask off all ints */
+  hp100_outw( 0xffff, IRQ_STATUS );    /* ack */
+  hp100_outw( (HP100_RX_PACKET | HP100_RX_ERROR | HP100_SET_HB) |
+              (HP100_TX_ERROR | HP100_SET_LB ), IRQ_MASK );
+                                       /* and enable few */
+  hp100_reset_card();
+  hp100_page( MMU_CFG );
+  hp100_outw( ( lp -> memory_size * lp -> rx_ratio ) / 100, RX_MEM_STOP );
+  hp100_outw( lp -> memory_size - 1, TX_MEM_STOP );
+  hp100_unreset_card();
+
+  if ( lp -> lan_type == HP100_LAN_100 )
+    lp -> hub_status = hp100_login_to_vg_hub( dev );
+
+  hp100_start_interface( dev );
+
+  return 0;
+}
+
+static int hp100_close( struct device *dev )
+{
+  int ioaddr = dev -> base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+  hp100_page( PERFORMANCE );
+  hp100_outw( 0xfefe, IRQ_MASK );              /* mask off all ints */
+
+  hp100_stop_interface( dev );                 /* relogin */
+
+  if ( lp -> lan_type == HP100_LAN_100 )
+    hp100_login_to_vg_hub( dev );
+
+  dev -> tbusy = 1;
+  dev -> start = 0;
+
+  free_irq( dev -> irq );
+  irq2dev_map[ dev -> irq ] = NULL;
+#ifdef MODULE
+  MOD_DEC_USE_COUNT;
+#endif
+  return 0;
+}
+
+/* 
+ *  transmit
+ */
+
+static int hp100_start_xmit( struct sk_buff *skb, struct device *dev )
+{
+  int i;
+  int ioaddr = dev -> base_addr;
+  u_short val;
+  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+  
+  if ( ( i = ( hp100_inl( TX_MEM_FREE ) & ~0x7fffffff ) ) < skb -> len + 16 )
+    {
+#ifdef HP100_DEBUG
+      printk( "hp100_start_xmit: rx free mem = 0x%x\n", i );
+#endif
+      if ( jiffies - dev -> trans_start < 2 * HZ ) return -EAGAIN;
+      if ( lp -> lan_type == HP100_LAN_100 && lp -> hub_status < 0 )
+                               /* 100Mb/s adapter isn't connected to hub */
+        {
+          printk( "%s: login to 100Mb/s hub retry\n", dev -> name );
+          hp100_ints_off();
+          hp100_stop_interface( dev );
+          lp -> hub_status = hp100_login_to_vg_hub( dev );
+          hp100_start_interface( dev );
+          hp100_ints_on();
+        }
+       else
+        {
+          hp100_ints_off();
+          i = hp100_sense_lan( dev );
+          hp100_page( PERFORMANCE );
+          hp100_ints_on();
+          if ( i == HP100_LAN_ERR )
+            printk( "%s: link down detected\n", dev -> name );
+           else
+          if ( lp -> lan_type != i )
+            {
+              /* it's very heavy - all network setting must be changed!!! */
+              printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev -> name );
+              lp -> lan_type = i;
+              hp100_ints_off();
+              hp100_stop_interface( dev );
+              if ( lp -> lan_type == HP100_LAN_100 )
+                lp -> hub_status = hp100_login_to_vg_hub( dev );
+              hp100_start_interface( dev );
+              hp100_ints_on();
+            }
+           else
+            {
+              printk( "%s: interface reset\n", dev -> name );
+              hp100_ints_off();
+              hp100_stop_interface( dev );
+              hp100_start_interface( dev );
+              hp100_ints_on();
+            }
+        }
+      dev -> trans_start = jiffies;
+      return -EAGAIN;
+    }
+    
+  if ( skb == NULL )
+    {
+      dev_tint( dev );
+      return 0;
+    }
+    
+  if ( skb -> len <= 0 ) return 0;
+
+  for ( i = 0; i < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_TX_CMD ); i++ )
+    {
+#ifdef HP100_DEBUG_TX
+      printk( "hp100_start_xmit: busy\n" );
+#endif    
+    }
+    
+  hp100_ints_off();
+  val = hp100_inw( IRQ_STATUS );
+  hp100_outw( val & HP100_TX_COMPLETE, IRQ_STATUS );
+#ifdef HP100_DEBUG_TX
+  printk( "hp100_start_xmit: irq_status = 0x%x, len = %d\n", val, (int)skb -> len );
+#endif
+  if ( skb -> len >= HP100_MIN_PACKET_SIZE )
+    {
+      hp100_outw( skb -> len, DATA32 );                /* length to memory manager */
+      hp100_outw( skb -> len, FRAGMENT_LEN );
+      outsl( ioaddr + HP100_REG_DATA32, skb -> data, ( skb -> len + 3 ) >> 2 );
+      hp100_outw( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
+    }
+   else
+    {
+      hp100_outw( HP100_MIN_PACKET_SIZE, DATA32 ); /* length to memory manager */
+      hp100_outw( HP100_MIN_PACKET_SIZE, FRAGMENT_LEN );
+      i = skb -> len + 3;
+      outsl( ioaddr + HP100_REG_DATA32, skb -> data, i >> 2 );
+      for ( i &= ~3; i < HP100_MIN_PACKET_SIZE; i += 4 ) 
+        hp100_outl( 0, DATA32 );
+      hp100_outw( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
+    }
+  lp -> stats.tx_packets++;
+  dev -> trans_start = jiffies;
+  hp100_ints_on();
+
+  dev_kfree_skb( skb, FREE_WRITE );
+
+#ifdef HP100_DEBUG_TX
+  printk( "hp100_start_xmit: end\n" );
+#endif
+
+  return 0;
+}
+
+/*
+ *  receive - called from interrupt handler
+ */
+
+static void hp100_rx( struct device *dev )
+{
+  int packets, pkt_len;
+  int ioaddr = dev -> base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+  u_int header;
+  struct sk_buff *skb;
+
+  packets = hp100_inb( RX_PKT_CNT );
+#ifdef HP100_DEBUG
+  if ( packets > 1 )
+    printk( "hp100_rx: waiting packets = %d\n", packets );
+#endif
+  while ( packets-- > 0 )
+    {
+      for ( pkt_len = 0; pkt_len < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_ADV_NXT_PKT ); pkt_len++ )
+        {
+#ifdef HP100_DEBUG_TX
+          printk( "hp100_rx: busy, remaining packets = %d\n", packets );
+#endif    
+        }
+      header = hp100_inl( DATA32 );
+      pkt_len = header & HP100_PKT_LEN_MASK;
+#ifdef HP100_DEBUG_RX
+      printk( "hp100_rx: new packet - length = %d, errors = 0x%x, dest = 0x%x\n",
+       header & HP100_PKT_LEN_MASK, ( header >> 16 ) & 0xfff8, ( header >> 16 ) & 7 );
+#endif
+      skb = alloc_skb( ( pkt_len + 3 ) & ~3, GFP_ATOMIC );
+      if ( skb == NULL )
+        {
+#ifdef HP100_DEBUG
+          printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len );
+#endif
+          lp -> stats.rx_dropped++;
+        }
+       else
+        {
+          skb -> len = pkt_len;
+          skb -> dev = dev;
+          insl( ioaddr + HP100_REG_DATA32, skb -> data, ( pkt_len + 3 ) >> 2 );
+          skb->protocol=eth_type_trans(skb,dev);
+          netif_rx( skb );
+          lp -> stats.rx_packets++;
+        }
+      hp100_outw( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW );
+      switch ( header & 0x00070000 ) {
+        case (HP100_MULTI_ADDR_HASH<<16):
+        case (HP100_MULTI_ADDR_NO_HASH<<16):
+          lp -> stats.multicast++; break;
+      }
+    }
+#ifdef HP100_DEBUG_RX
+   printk( "hp100_rx: end\n" );
+#endif
+}
+
+/*
+ *  statistics
+ */
+static struct enet_statistics *hp100_get_stats( struct device *dev )
+{
+  int ioaddr = dev -> base_addr;
+
+  hp100_ints_off();
+  hp100_update_stats( dev );
+  hp100_ints_on();
+  return &((struct hp100_private *)dev -> priv) -> stats;
+}
+
+static void hp100_update_stats( struct device *dev )
+{
+  int ioaddr = dev -> base_addr;
+  u_short val;
+  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+         
+  hp100_page( MAC_CTRL );              /* get all statistics bytes */
+  val = hp100_inw( DROPPED ) & 0x0fff;
+  lp -> stats.rx_errors += val;
+  lp -> stats.rx_over_errors += val;
+  val = hp100_inb( CRC );
+  lp -> stats.rx_errors += val;
+  lp -> stats.rx_crc_errors += val;
+  val = hp100_inb( ABORT );
+  lp -> stats.tx_errors += val;
+  lp -> stats.tx_aborted_errors += val;
+  hp100_page( PERFORMANCE );
+}
+
+/*
+ *  multicast setup
+ */
+
+#ifdef HAVE_MULTICAST
+
+/*
+ *  Set or clear the multicast filter for this adapter.
+ *
+ *  num_addrs == -1             Promiscuous mode, receive all packets
+ *  num_addrs == 0              Normal mode, clear multicast list
+ *  num_addrs > 0               Multicast mode, receive normal and MC packets,
+ *                              best-effort filtering.
+ */
+                                                          
+static void hp100_set_multicast_list( struct device *dev, int num_addrs, void *addrs )
+{
+  int ioaddr = dev -> base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+#ifdef HP100_DEBUG_MULTI
+  printk( "hp100_set_multicast_list: num_addrs = %d\n", num_addrs );
+#endif
+  hp100_ints_off();
+  cli();
+  hp100_page( MAC_CTRL );
+  hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );       /* stop rx/tx */
+
+  if ( num_addrs < 0 )
+    {
+      lp -> mac2_mode = HP100_MAC2MODE6;  /* promiscuous mode, all good */
+      lp -> mac1_mode = HP100_MAC1MODE6;  /* packets on the net */
+    }
+   else
+  if ( num_addrs > 0 )
+    {
+      lp -> mac2_mode = HP100_MAC2MODE5;  /* multicast mode, packets for me */
+      lp -> mac1_mode = HP100_MAC1MODE5;  /* broadcasts and all multicasts */
+    }
+   else
+     {
+      lp -> mac2_mode = HP100_MAC2MODE3;  /* normal mode, packets for me */
+      lp -> mac1_mode = HP100_MAC1MODE3;  /* and broadcasts */
+    }
+
+  hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
+  hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
+  hp100_orb( lp -> mac1_mode, MAC_CFG_1 );
+
+  hp100_orb( HP100_RX_EN | HP100_RX_IDLE, MAC_CFG_1 );         /* enable rx */
+  hp100_orb( HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 );         /* enable tx */
+  hp100_page( PERFORMANCE );
+  sti();
+  hp100_ints_on();
+}
+
+#endif /* HAVE_MULTICAST */
+
+/*
+ *  hardware interrupt handling
+ */
+
+#ifndef LINUX_1_1_52
+static void hp100_interrupt( int irq, struct pt_regs *regs )
+#else
+static void hp100_interrupt( int irq )
+#endif
+{
+  struct device *dev = (struct device *)irq2dev_map[ irq ];
+  struct hp100_private *lp;
+  int ioaddr;
+  u_short val;
+
+  if ( dev == NULL ) return;
+  ioaddr = dev -> base_addr;
+  if ( dev -> interrupt )
+    printk( "%s: re-entering the interrupt handler\n", dev -> name );
+  hp100_ints_off();
+  dev -> interrupt = 1;
+  val = hp100_inw( IRQ_STATUS );
+#ifdef HP100_DEBUG_IRQ
+  printk( "hp100_interrupt: irq_status = 0x%x\n", val );
+#endif
+  if ( val & HP100_RX_PACKET )
+    {
+      hp100_rx( dev );
+      hp100_outw( HP100_RX_PACKET, IRQ_STATUS );
+    }
+  if ( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE) )
+    {
+      hp100_outw( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE), IRQ_STATUS );
+    }
+  if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) )
+    {
+      lp = (struct hp100_private *)dev -> priv;
+      hp100_update_stats( dev );
+      hp100_outw( val & (HP100_TX_ERROR | HP100_RX_ERROR), IRQ_STATUS );
+    }
+#ifdef HP100_DEBUG_IRQ
+  printk( "hp100_interrupt: end\n" );
+#endif
+  dev -> interrupt = 0;
+  hp100_ints_on();
+}
+
+/*
+ *  some misc functions
+ */
+
+static void hp100_start_interface( struct device *dev )
+{
+  int ioaddr = dev -> base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+  hp100_unreset_card();
+  cli();
+  hp100_page( MAC_CTRL );
+  hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
+  hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
+  hp100_orb( lp -> mac1_mode, MAC_CFG_1 );
+  hp100_orb( HP100_RX_EN | HP100_RX_IDLE, MAC_CFG_1 );
+  hp100_orb( HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 );
+  hp100_page( PERFORMANCE );
+  hp100_outw( HP100_INT_EN | HP100_SET_LB, OPTION_LSW );
+  hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW );
+  sti();
+} 
+
+static void hp100_stop_interface( struct device *dev )
+{
+  int ioaddr = dev -> base_addr;
+  u_short val;
+
+  hp100_outw( HP100_INT_EN | HP100_RESET_LB | 
+              HP100_TRI_INT | HP100_SET_HB, OPTION_LSW );
+  val = hp100_inw( OPTION_LSW );
+  hp100_page( HW_MAP );
+  hp100_andb( HP100_BM_SLAVE, BM );
+  hp100_page( MAC_CTRL );
+  hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );
+  if ( !(val & HP100_HW_RST) ) return;
+  for ( val = 0; val < 6000; val++ )
+    if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) ==
+                                    (HP100_TX_IDLE | HP100_RX_IDLE) )
+      return;
+  printk( "%s: hp100_stop_interface - timeout\n", dev -> name );
+}
+
+static void hp100_load_eeprom( struct device *dev )
+{
+  int i;
+  int ioaddr = dev -> base_addr;
+
+  hp100_page( EEPROM_CTRL );
+  hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL );
+  hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL );
+  for ( i = 0; i < 6000; i++ )
+    if ( !( hp100_inw( OPTION_MSW ) & HP100_EE_LOAD ) ) return;
+  printk( "%s: hp100_load_eeprom - timeout\n", dev -> name );
+}
+
+/* return values: LAN_10, LAN_100 or LAN_ERR (not connected or hub is down)... */
+
+static int hp100_sense_lan( struct device *dev )
+{
+  int i;
+  int ioaddr = dev -> base_addr;
+  u_short val_VG, val_10;
+  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+  hp100_page( MAC_CTRL );
+  hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
+  val_10 = hp100_inw( LAN_CFG_10 );
+  val_VG = hp100_inw( LAN_CFG_VG );
+#ifdef HP100_DEBUG_SENSE
+  printk( "hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10 );
+#endif
+  if ( val_10 & HP100_LINK_BEAT_ST ) return HP100_LAN_10;
+  if ( lp -> id -> id == 0x02019F022 ) /* HP J27248B doesn't have 100Mb/s interface */
+    return HP100_LAN_ERR;
+  for ( i = 0; i < 2500; i++ )
+    {
+      val_VG = hp100_inw( LAN_CFG_VG );
+      if ( val_VG & HP100_LINK_CABLE_ST ) return HP100_LAN_100;
+    }
+  return HP100_LAN_ERR;
+}
+
+static int hp100_down_vg_link( struct device *dev )
+{
+  int ioaddr = dev -> base_addr;
+  unsigned long time;
+  int i;
+
+  hp100_page( MAC_CTRL );
+  for ( i = 2500; i > 0; i-- )
+    if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
+  if ( i <= 0 )                                /* not signal - not logout */
+    return 0;
+  hp100_andw( ~HP100_LINK_CMD, LAN_CFG_VG );
+  time = jiffies + 10; 
+  while ( time > jiffies )
+    if ( !( hp100_inw( LAN_CFG_VG ) & ( HP100_LINK_UP_ST | 
+                                        HP100_LINK_CABLE_ST | 
+                                        HP100_LINK_GOOD_ST ) ) )
+      return 0;
+#ifdef HP100_DEBUG
+  printk( "hp100_down_vg_link: timeout\n" );
+#endif
+  return -EIO;
+}
+
+static int hp100_login_to_vg_hub( struct device *dev )
+{
+  int i;
+  int ioaddr = dev -> base_addr;
+  u_short val;
+  unsigned long time;  
+
+  hp100_page( MAC_CTRL );
+  hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
+  time = jiffies + ( HZ / 2 );
+  do {
+    if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
+  } while ( time > jiffies );
+  if ( time <= jiffies )
+    {
+#ifdef HP100_DEBUG
+      printk( "hp100_login_to_vg_hub: timeout for link\n" );
+#endif
+      return -EIO;
+    }
+    
+  if ( hp100_down_vg_link( dev ) < 0 ) /* if fail, try reset VG link */
+    {
+      hp100_andw( ~HP100_VG_RESET, LAN_CFG_VG );
+      hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
+    }
+  /* bring up link */
+  hp100_orw( HP100_LOAD_ADDR | HP100_LINK_CMD, LAN_CFG_VG );
+  for ( i = 2500; i > 0; i-- )
+    if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
+  if ( i <= 0 )
+    {
+#ifdef HP100_DEBUG
+      printk( "hp100_login_to_vg_hub: timeout for link (bring up)\n" );
+#endif
+      goto down_link;
+    }
+
+  time = jiffies + ( HZ / 2 );
+  do {   
+    val = hp100_inw( LAN_CFG_VG );
+    if ( ( val & ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) ) == 
+                 ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) )
+      return 0;        /* success */
+  } while ( time > jiffies );
+  if ( val & HP100_LINK_GOOD_ST )
+    printk( "%s: 100Mb cable training failed, check cable.\n", dev -> name );
+   else
+    printk( "%s: 100Mb node not accepted by hub, check frame type or security.\n", dev -> name );
+
+down_link:
+  hp100_down_vg_link( dev );
+  hp100_page( MAC_CTRL );
+  hp100_andw( ~( HP100_LOAD_ADDR | HP100_PROM_MODE ), LAN_CFG_VG );
+  hp100_orw( HP100_LINK_CMD, LAN_CFG_VG );
+  return -EIO;
+}
+
+/*
+ *  module section
+ */
+#ifdef MODULE
+
+char kernel_version[] = UTS_RELEASE;
+
+static int hp100_port = -1;
+
+static struct device dev_hp100 = {
+  "        ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, hp100_probe
+};
+
+int init_module( void )
+{
+  if ( hp100_port > 0 ) dev_hp100.base_addr = hp100_port;
+  if ( register_netdev( &dev_hp100 ) != 0 ) return -EIO;
+  return 0;
+}         
+
+void cleanup_module( void )
+{
+  unregister_netdev( &dev_hp100 );
+  release_region( dev_hp100.base_addr, 0x20 );
+  kfree_s( dev_hp100.priv, sizeof( struct hp100_private ) );
+  dev_hp100.priv = NULL;
+}
+
+#endif
diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h
new file mode 100644 (file)
index 0000000..9f14f95
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
+ *
+ * Author:  Jaroslav Kysela, <perex@pf.jcu.cz>
+ *
+ * Header file...
+ *
+ * This driver is based on the 'hpfepkt' crynwr packet driver.
+ *
+ * This source/code is public free; you can distribute it and/or modify 
+ * it under terms of the GNU General Public License (published by the
+ * Free Software Foundation) either version two of this License, or any 
+ * later version.
+ */
+
+/****************************************************************************
+ *  Hardware Constants
+ ****************************************************************************/
+/*
+ *  ATT2MD01 Register Page Constants
+ */
+
+#define HP100_PAGE_PERFORMANCE 0x0     /* Page 0 */
+#define HP100_PAGE_MAC_ADDRESS 0x1     /* Page 1 */
+#define HP100_PAGE_HW_MAP      0x2     /* Page 2 */
+#define HP100_PAGE_EEPROM_CTRL 0x3     /* Page 3 */
+#define HP100_PAGE_MAC_CTRL    0x4     /* Page 4 */
+#define HP100_PAGE_MMU_CFG     0x5     /* Page 5 */
+#define HP100_PAGE_ID_MAC_ADDR 0x6     /* Page 6 */
+#define HP100_PAGE_MMU_POINTER 0x7     /* Page 7 */
+
+/*
+ *  ATT2MD01 Register Addresses
+ */
+
+/*  Present on all pages  */
+
+#define HP100_REG_HW_ID                0x00    /* R:  (16) Unique card ID           */
+#define HP100_REG_TRACE                0x00    /* W:  (16) Used for debug output    */
+#define HP100_REG_PAGING       0x02    /* R:  (16),15:4 Card ID             */
+                                        /* W:  (16),3:0 Switch pages         */
+#define HP100_REG_OPTION_LSW   0x04    /* RW: (16) Select card functions    */
+#define HP100_REG_OPTION_MSW   0x06    /* RW: (16) Select card functions    */
+                                        
+/*  Page 0 - Performance  */
+
+#define HP100_REG_IRQ_STATUS   0x08    /* RW: (16) Which ints are pending   */
+#define HP100_REG_IRQ_MASK     0x0a    /* RW: (16) Select ints to allow     */
+#define HP100_REG_FRAGMENT_LEN 0x0c    /* RW: (16)12:0 Current fragment len */
+#define HP100_REG_OFFSET       0x0e    /* RW: (16)12:0 Offset to start read */
+#define HP100_REG_DATA32       0x10    /* RW: (32) I/O mode data port       */
+#define HP100_REG_DATA16       0x12    /* RW: WORDs must be read from here  */
+#define HP100_REG_TX_MEM_FREE  0x14    /* RD: (32) Amount of free Tx mem    */
+#define HP100_REG_RX_PKT_CNT   0x18    /* RD: (8) Rx count of pkts on card  */
+#define HP100_REG_TX_PKT_CNT   0x19    /* RD: (8) Tx count of pkts on card  */
+                                        
+/*  Page 1 - MAC Address/Hash Table  */
+
+#define HP100_REG_MAC_ADDR     0x08    /* RW: (8) Cards MAC address         */
+#define HP100_REG_HASH_BYTE0   0x10    /* RW: (8) Cards multicast filter    */
+                                        
+/*  Page 2 - Hardware Mapping  */
+
+#define HP100_REG_MEM_MAP_LSW  0x08    /* RW: (16) LSW of cards mem addr    */
+#define HP100_REG_MEM_MAP_MSW  0x0a    /* RW: (16) MSW of cards mem addr    */
+#define HP100_REG_IO_MAP       0x0c    /* RW: (8) Cards I/O address         */
+#define HP100_REG_IRQ_CHANNEL  0x0d    /* RW: (8) IRQ and edge/level int    */
+#define HP100_REG_SRAM         0x0e    /* RW: (8) How much RAM on card      */
+#define HP100_REG_BM           0x0f    /* RW: (8) Controls BM functions     */
+                                        
+/*  Page 3 - EEPROM/Boot ROM  */
+
+#define HP100_REG_EEPROM_CTRL  0x08    /* RW: (16) Used to load EEPROM      */
+                                        
+/*  Page 4 - LAN Configuration  */
+
+#define HP100_REG_LAN_CFG_10   0x08    /* RW: (16) Set 10M XCVR functions   */
+#define HP100_REG_LAN_CFG_VG   0x0a    /* RW: (16) Set 100M XCVR functions  */
+#define HP100_REG_MAC_CFG_1    0x0c    /* RW: (8) Types of pkts to accept   */
+#define HP100_REG_MAC_CFG_2    0x0d    /* RW: (8) Misc MAC functions        */
+/* The follow clear when read: */
+#define HP100_REG_DROPPED      0x10    /* R:  (16),11:0 Pkts cant fit in mem*/
+#define HP100_REG_CRC          0x12    /* R:  (8) Pkts with CRC             */
+#define HP100_REG_ABORT                0x13    /* R:  (8) Aborted Tx pkts           */
+                                        
+/*  Page 5 - MMU  */
+
+#define HP100_REG_RX_MEM_STOP  0x0c    /* RW: (16) End of Rx ring addr      */
+#define HP100_REG_TX_MEM_STOP  0x0e    /* RW: (16) End of Tx ring addr      */
+                                        
+/*  Page 6 - Card ID/Physical LAN Address  */
+
+#define HP100_REG_BOARD_ID     0x08    /* R:  (8) EISA/ISA card ID          */
+#define HP100_REG_BOARD_IO_CHCK 0x0c   /* R:  (8) Added to ID to get FFh    */
+#define HP100_REG_SOFT_MODEL   0x0d    /* R:  (8) Config program defined    */
+#define HP100_REG_LAN_ADDR     0x10    /* R:  (8) MAC addr of card          */
+#define HP100_REG_LAN_ADDR_CHCK 0x16   /* R:  (8) Added to addr to get FFh  */
+                                        
+/*  Page 7 - MMU Current Pointers  */
+
+#define HP100_REG_RX_MEM_BR    0x08    /* R:  (16) Current begin of Rx ring */
+#define HP100_REG_RX_MEM_ER    0x0a    /* R:  (16) Current end of Rx ring   */
+#define HP100_REG_TX_MEM_BR    0x0c    /* R:  (16) Current begin of Tx ring */
+#define HP100_REG_TX_MEM_ER    0x0e    /* R:  (16) Current end of Rx ring   */
+#define HP100_REG_MEM_DEBUG    0x1a    /* RW: (16) Used for memory tests    */
+                                                
+/*
+ *  HardwareIDReg bits/masks
+ */
+
+#define HP100_HW_ID_0          0x50    /* Hardware ID bytes.                */
+#define HP100_HW_ID_1          0x48
+#define HP100_HW_ID_2_REVA     0x50    /* Rev. A ID. NOTE: lower nibble not used */
+#define HP100_HW_ID_3          0x53
+
+/*
+ *  OptionLSWReg bits/masks
+ */
+
+#define HP100_DEBUG_EN         0x8000  /* 0:Disable, 1:Enable Debug Dump Pointer */
+#define HP100_RX_HDR           0x4000  /* 0:Disable, 1:Enable putting pkt into */
+                                        /*   system memory before Rx interrupt */
+#define HP100_MMAP_DIS         0x2000  /* 0:Enable, 1:Disable memory mapping. */
+                                        /*   MMAP_DIS must be 0 and MEM_EN must */
+                                        /*   be 1 for memory-mapped mode to be */
+                                        /*   enabled */
+#define HP100_EE_EN            0x1000  /* 0:Disable,1:Enable EEPROM writing */
+#define HP100_BM_WRITE         0x0800  /* 0:Slave, 1:Bus Master for Tx data */
+#define HP100_BM_READ          0x0400  /* 0:Slave, 1:Bus Master for Rx data */
+#define HP100_TRI_INT          0x0200  /* 0:Dont, 1:Do tri-state the int */
+#define HP100_MEM_EN           0x0040  /* Config program set this to */
+                                        /*   0:Disable, 1:Enable mem map. */
+                                        /*   See MMAP_DIS. */
+#define HP100_IO_EN            0x0020  /* 0:Disable, 1:Enable I/O transfers */
+#define HP100_BOOT_EN          0x0010  /* 0:Disable, 1:Enable boot ROM access */
+#define HP100_FAKE_INT         0x0008  /* 0:No int, 1:int */
+#define HP100_INT_EN           0x0004  /* 0:Disable, 1:Enable ints from card */
+#define HP100_HW_RST           0x0002  /* 0:Reset, 1:Out of reset */
+
+/*
+ *  OptionMSWReg bits/masks
+ */
+#define HP100_PRIORITY_TX      0x0080  /* 0:Don't, 1:Do all Tx pkts as priority */
+#define HP100_EE_LOAD          0x0040  /* 1:EEPROM loading, 0 when done */
+#define HP100_ADV_NXT_PKT      0x0004  /* 1:Advance to next pkt in Rx queue, */
+                                        /*   h/w will set to 0 when done */
+#define HP100_TX_CMD           0x0002  /* 1:Tell h/w download done, h/w will set */
+                                        /*   to 0 when done */
+
+/*
+ *  InterruptStatusReg/InterruptMaskReg bits/masks.  These bits will 0 when a 1 
+ *  is written to them.
+ */
+#define HP100_RX_PACKET                0x0400  /* 0:No, 1:Yes pkt has been Rx */
+#define HP100_RX_ERROR         0x0200  /* 0:No, 1:Yes Rx pkt had error */
+#define HP100_TX_SPACE_AVAIL   0x0010  /* 0:<8192, 1:>=8192 Tx free bytes */
+#define HP100_TX_COMPLETE      0x0008  /* 0:No, 1:Yes a Tx has completed */
+#define HP100_TX_ERROR         0x0002  /* 0:No, 1:Yes Tx pkt had error */
+                                        
+/*
+ *  TxMemoryFreeCountReg bits/masks.
+ */
+#define HP100_AUTO_COMPARE     0x8000  /* Says at least 8k is available for Tx. */
+                                        /*   NOTE: This mask is for the upper */
+                                        /*   word of the register. */
+
+/*
+ *  IRQChannelReg bits/masks.
+ */
+#define HP100_ZERO_WAIT_EN     0x80    /* 0:No, 1:Yes assers NOWS signal */
+#define HP100_LEVEL_IRQ                0x10    /* 0:Edge, 1:Level type interrupts. */
+                                        /*   Only valid on EISA cards. */
+#define HP100_IRQ_MASK         0x0F    /* Isolate the IRQ bits */
+
+/*
+ *  SRAMReg bits/masks.
+ */
+#define HP100_RAM_SIZE_MASK    0xe0    /* AND to get SRAM size index */
+#define HP100_RAM_SIZE_SHIFT   0x05    /* Shift count to put index in lower bits */
+
+/*
+ *  BMReg bits/masks.
+ */
+#define HP100_BM_SLAVE         0x04    /* 0:Slave, 1:BM mode */
+
+/*
+ *  EEPROMControlReg bits/masks.
+ */
+#define HP100_EEPROM_LOAD      0x0001  /* 0->1 loads the EEPROM into registers. */
+                                        /*   When it goes back to 0, load is  */
+                                        /*   complete.  This should take ~600us. */
+
+/*
+ *  LANCntrCfg10Reg bits/masks.
+ */
+#define HP100_SQU_ST           0x0100  /* 0:No, 1:Yes collision signal sent */
+                                        /*   after Tx.  Only used for AUI. */
+#define HP100_MAC10_SEL                0x00c0  /* Get bits to indicate MAC */
+#define HP100_AUI_SEL          0x0020  /* Status of AUI selection */
+#define HP100_LOW_TH           0x0010  /* 0:No, 1:Yes allow better cabling */
+#define HP100_LINK_BEAT_DIS    0x0008  /* 0:Enable, 1:Disable link beat */
+#define HP100_LINK_BEAT_ST     0x0004  /* 0:No, 1:Yes link beat being Rx */
+#define HP100_R_ROL_ST         0x0002  /* 0:No, 1:Yes Rx twisted pair has been */
+                                        /*   reversed */
+#define HP100_AUI_ST           0x0001  /* 0:No, 1:Yes use AUI on TP card */
+
+/* MAC Selection, use with MAC10_SEL bits */
+#define HP100_AUTO_SEL_10      0x0     /* Auto select */
+#define HP100_XCVR_LXT901_10   0x1     /* LXT901 10BaseT transceiver */
+#define HP100_XCVR_7213                0x2     /* 7213 transceiver */
+#define HP100_XCVR_82503       0x3     /* 82503 transceiver */
+
+
+/*
+ *  LANCntrCfgVGReg bits/masks.
+ */
+#define HP100_FRAME_FORMAT     0x0800  /* 0:802.3, 1:802.5 frames */
+#define HP100_BRIDGE           0x0400  /* 0:No, 1:Yes tell hub it's a bridge */
+#define HP100_PROM_MODE                0x0200  /* 0:No, 1:Yes tell hub card is */
+                                        /*   promiscuous */
+#define HP100_REPEATER         0x0100  /* 0:No, 1:Yes tell hub MAC wants to be */
+                                        /*   a cascaded repeater */
+#define HP100_MAC100_SEL       0x0080  /* 0:No, 1:Yes use 100 Mbit MAC */
+#define HP100_LINK_UP_ST       0x0040  /* 0:No, 1:Yes endnode logged in */
+#define HP100_LINK_CABLE_ST    0x0020  /* 0:No, 1:Yes cable can hear tones from */
+                                        /*   hub */
+#define HP100_LOAD_ADDR                0x0010  /* 0->1 card addr will be sent to hub. */
+                                        /*   100ms later the link status bits are */
+                                        /*   valid */
+#define HP100_LINK_CMD         0x0008  /* 0->1 link will attempt to log in. */
+                                        /*   100ms later the link status bits are */
+                                        /*   valid */
+#define HP100_LINK_GOOD_ST     0x0002  /* 0:No, 1:Yes cable passed training */
+#define HP100_VG_RESET         0x0001  /* 0:Yes, 1:No reset the 100VG MAC */
+
+
+/*
+ *  MACConfiguration1Reg bits/masks.
+ */
+#define HP100_RX_IDLE          0x80    /* 0:Yes, 1:No currently receiving pkts */
+#define HP100_TX_IDLE          0x40    /* 0:Yes, 1:No currently Txing pkts */
+#define HP100_RX_EN            0x20    /* 0:No, 1:Yes allow receiving of pkts */
+#define HP100_TX_EN            0x10    /* 0:No, 1:Yes allow transmiting of pkts */
+#define HP100_ACC_ERRORED      0x08    /* 0:No, 1:Yes allow Rx of errored pkts */
+#define HP100_ACC_MC           0x04    /* 0:No, 1:Yes allow Rx of multicast pkts */
+#define HP100_ACC_BC           0x02    /* 0:No, 1:Yes allow Rx of broadcast pkts */
+#define HP100_ACC_PHY          0x01    /* 0:No, 1:Yes allow Rx of ALL physical pkts */
+
+#define HP100_MAC1MODEMASK     0xf0    /* Hide ACC bits */
+#define HP100_MAC1MODE1                0x00    /* Receive nothing, must also disable RX */
+#define HP100_MAC1MODE2                0x00
+#define HP100_MAC1MODE3                HP100_MAC1MODE2 | HP100_ACC_BC
+#define HP100_MAC1MODE4                HP100_MAC1MODE3 | HP100_ACC_MC
+#define HP100_MAC1MODE5                HP100_MAC1MODE4 /* set mc hash to all ones also */
+#define HP100_MAC1MODE6                HP100_MAC1MODE5 | HP100_ACC_PHY /* Promiscuous */
+
+/* Note MODE6 will receive all GOOD packets on the LAN. This really needs
+   a mode 7 defined to be LAN Analyzer mode, which will receive errored and
+   runt packets, and keep the CRC bytes. */
+
+#define HP100_MAC1MODE7                MAC1MODE6 OR ACC_ERRORED
+
+/*
+ *  MACConfiguration2Reg bits/masks.
+ */
+#define HP100_TR_MODE          0x80    /* 0:No, 1:Yes support Token Ring formats */
+#define HP100_TX_SAME          0x40    /* 0:No, 1:Yes Tx same packet continuous */
+#define HP100_LBK_XCVR         0x20    /* 0:No, 1:Yes loopback through MAC & */
+                                        /*   transceiver */
+#define HP100_LBK_MAC          0x10    /* 0:No, 1:Yes loopback through MAC */
+#define HP100_CRC_I            0x08    /* 0:No, 1:Yes inhibit CRC on Tx packets */
+#define HP100_KEEP_CRC         0x02    /* 0:No, 1:Yes keep CRC on Rx packets. */
+                                        /*   The length will reflect this. */
+
+#define HP100_MAC2MODEMASK     0x02
+#define HP100_MAC2MODE1                0x00
+#define HP100_MAC2MODE2                0x00
+#define HP100_MAC2MODE3                0x00
+#define HP100_MAC2MODE4                0x00
+#define HP100_MAC2MODE5                0x00
+#define HP100_MAC2MODE6                0x00
+#define HP100_MAC2MODE7                KEEP_CRC
+
+/*
+ *  Set/Reset bits
+ */
+#define HP100_SET_HB           0x0100  /* 0:Set fields to 0 whose mask is 1 */
+#define HP100_SET_LB           0x0001  /* HB sets upper byte, LB sets lower byte */
+#define HP100_RESET_HB         0x0000  /* For readability when resetting bits */
+#define HP100_RESET_LB         0x0000  /* For readability when resetting bits */
+
+/*
+ *  Misc. Constants
+ */
+#define HP100_LAN_100          100     /* lan_type value for VG */
+#define HP100_LAN_10           10      /* lan_type value for 10BaseT */
+#define HP100_LAN_ERR          (-1)    /* lan_type value for link down */
+
+/*
+ *  Receive Header Definition.
+ */
+
+struct hp100_rx_header {
+  u_short rx_length;                   /* Pkt length is bits 12:0 */
+  u_short rx_status;                   /* status of the packet */
+};
+
+#define HP100_PKT_LEN_MASK     0x1FFF  /* AND with RxLength to get length bits */
+
+/* Receive Packet Status.  Note, the error bits are only valid if ACC_ERRORED 
+   bit in the MAC Configuration Register 1 is set. */
+   
+#define HP100_RX_PRI           0x8000  /* 0:No, 1:Yes packet is priority */
+#define HP100_SDF_ERR          0x4000  /* 0:No, 1:Yes start of frame error */
+#define HP100_SKEW_ERR         0x2000  /* 0:No, 1:Yes skew out of range */
+#define HP100_BAD_SYMBOL_ERR   0x1000  /* 0:No, 1:Yes invalid symbol received */
+#define HP100_RCV_IPM_ERR      0x0800  /* 0:No, 1:Yes pkt had an invalid packet */
+                                        /*   marker */
+#define HP100_SYMBOL_BAL_ERR   0x0400  /* 0:No, 1:Yes symbol balance error */
+#define HP100_VG_ALN_ERR       0x0200  /* 0:No, 1:Yes non-octet received */
+#define HP100_TRUNC_ERR                0x0100  /* 0:No, 1:Yes the packet was truncated */
+#define HP100_RUNT_ERR         0x0040  /* 0:No, 1:Yes pkt length < Min Pkt */
+                                        /*   Length Reg. */
+#define HP100_ALN_ERR          0x0010  /* 0:No, 1:Yes align error. */
+#define HP100_CRC_ERR          0x0008  /* 0:No, 1:Yes CRC occurred. */
+
+/* The last three bits indicate the type of destination address */
+
+#define HP100_MULTI_ADDR_HASH  0x0006  /* 110: Addr multicast, matched hash */
+#define HP100_BROADCAST_ADDR   0x0003  /* x11: Addr broadcast */
+#define HP100_MULTI_ADDR_NO_HASH 0x0002        /* 010: Addr multicast, didn't match hash */
+#define HP100_PHYS_ADDR_MATCH  0x0001  /* x01: Addr was physical and mine */
+#define HP100_PHYS_ADDR_NO_MATCH 0x0000        /* x00: Addr was physical but not mine */
+
+/*
+ *  macros
+ */
+
+#define hp100_inb( reg ) \
+        inb( ioaddr + HP100_REG_##reg )
+#define hp100_inw( reg ) \
+       inw( ioaddr + HP100_REG_##reg )
+#define hp100_inl( reg ) \
+       inl( ioaddr + HP100_REG_##reg )
+#define hp100_outb( data, reg ) \
+       outb( data, ioaddr + HP100_REG_##reg )
+#define hp100_outw( data, reg ) \
+       outw( data, ioaddr + HP100_REG_##reg )
+#define hp100_outl( data, reg ) \
+       outl( data, ioaddr + HP100_REG_##reg )
+#define hp100_orb( data, reg ) \
+       outb( inb( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg )
+#define hp100_orw( data, reg ) \
+       outw( inw( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg )
+#define hp100_andb( data, reg ) \
+       outb( inb( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg )
+#define hp100_andw( data, reg ) \
+       outw( inw( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg )
+
+#define hp100_page( page ) \
+       outw( HP100_PAGE_##page, ioaddr + HP100_REG_PAGING )
+#define hp100_ints_off() \
+       outw( HP100_INT_EN | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_ints_on() \
+       outw( HP100_INT_EN | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_mem_map_enable() \
+       outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_mem_map_disable() \
+       outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_reset_card() \
+       outw( HP100_HW_RST | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_unreset_card() \
+       outw( HP100_HW_RST | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW )
index 9f0b41feb7aee9d0f05f3eb92898605877e656b9..f9b96b3b0acccc569332ee81daf057f53c518542 100644 (file)
@@ -1517,7 +1517,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
   case PPPIOCSDEBUG:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      ppp_debug = get_int ((int *) l);
+      ppp_debug = get_user ((int *) l);
       ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
       ppp_debug &= 0xff;
       PRINTKN (1, (KERN_INFO "ppp_ioctl: set debug level %d, netpacket %d\n", 
index a93c5beb19662a397e0e3364e470691942d7ca4e..cac39d5b71b6b7c20c474bba502bc5950a3cad8d 100644 (file)
@@ -41,6 +41,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( NCR,            NCR_53C825,     "53c825"),
        DEVICE( ADAPTEC,        ADAPTEC_2940,   "2940"),
        DEVICE( ADAPTEC,        ADAPTEC_294x,   "294x"),
+       DEVICE( ADAPTEC,        ADAPTEC_7850,   "AIC-7850"),
        DEVICE( DPT,            DPT,            "SmartCache/Raid"),
        DEVICE( S3,             S3_864_1,       "Vision 864-P"),
        DEVICE( S3,             S3_864_2,       "Vision 864-P"),
@@ -57,9 +58,11 @@ struct pci_dev_info dev_info[] = {
        BRIDGE( UMC,            UMC_UM8881F,    "UM8881F",              0x02),
        BRIDGE( UMC,            UMC_UM8891A,    "UM8891A",              0x01),
        DEVICE( UMC,            UMC_UM8886F,    "UM8886F"),
+       DEVICE( UMC,            UMC_UM8886A,    "UM8886A"),
        DEVICE( UMC,            UMC_UM8673F,    "UM8673F"),
        DEVICE( DEC,            DEC_TULIP,      "DC21040"),
-       DEVICE( DEC,            DEC_TULIP_FAST, "DC21040"),
+       DEVICE( DEC,            DEC_TULIP_FAST, "DC21140"),
+       DEVICE( DEC,            DEC_TULIP_PLUS, "DC21041"),
        DEVICE( DEC,            DEC_FDDI,       "DEFPA"),
        DEVICE( DEC,            DEC_BRD,        "DC21050"),
        DEVICE( MATROX,         MATROX_MGA_2,   "Atlas PX2085"),
@@ -80,6 +83,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( CIRRUS,         CIRRUS_5434_4,  "GD 5434"),
        DEVICE( CIRRUS,         CIRRUS_5434_8,  "GD 5434"),
        DEVICE( CIRRUS,         CIRRUS_6729,    "CL 6729"),
+       DEVICE( CIRRUS,         CIRRUS_7542,    "CL 7542"),
        DEVICE( BUSLOGIC,       BUSLOGIC_946C,  "946C"),
        DEVICE( BUSLOGIC,       BUSLOGIC_946C_2,"946C"),
        DEVICE( N9,             N9_I128,        "Imagine 128"),
@@ -128,7 +132,8 @@ struct pci_dev_info dev_info[] = {
        DEVICE( PROMISE,        PROMISE_5300,   "DC5030"),
        DEVICE( QLOGIC,         QLOGIC_ISP1020, "ISP1020"),
        DEVICE( QLOGIC,         QLOGIC_ISP1022, "ISP1022"),
-       DEVICE( X,              X_AGX016,       "ITT AGX016")
+       DEVICE( X,              X_AGX016,       "ITT AGX016"),
+       DEVICE( VORTEX,         VORTEX_GDT,     "GDT 6000b")
 };
 
 
@@ -327,6 +332,9 @@ const char *pci_strvendor(unsigned int vendor)
              case PCI_VENDOR_ID_3COM:          return "3Com";
              case PCI_VENDOR_ID_PROMISE:       return "Promise Technology";
              case PCI_VENDOR_ID_QLOGIC:        return "Q Logic";
+             case PCI_VENDOR_ID_X:             return "X TECHNOLOGY";
+             case PCI_VENDOR_ID_ACC:           return "ACC MICROELECTRONICS";
+             case PCI_VENDOR_ID_VORTEX:        return "VORTEX";
              default:                          return "Unknown vendor";
        }
 }
index 5d7e4ce15a1a0cf190765b9779bae1fee68f2d40..c948d3254c69f8b855e2b0aad9abae1203d79cf2 100644 (file)
 #include <linux/errno.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
+#include <linux/proc_fs.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include "../block/blk.h"
@@ -218,7 +219,7 @@ static Scsi_Host_Template *the_template = NULL;
  *
  *     NCR53c720/710 - need to add fatal interrupt or GEN code for 
  *             command completion signaling.   Need to take care of 
- *             ADD WITH CARRY instructions since carry is unimplemented.
+ *             ADD WITH CARRY instructions since carry is unimplemented.
  *             Also need to modify all SDID, SCID, etc. registers,
  *             and table indirect select code since these use bit
  *             fielded (ie 1<<target) instead of binary encoded
@@ -642,7 +643,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
     hostdata->expecting_sto = 0;
 
     if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
-        (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
+       (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
        /* XXX Should disable interrupts, etc. here */
        scsi_unregister (host);
        return -1;
@@ -720,8 +721,8 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
        /* Size of dynamic part of command structure : */
        2 * /* Worst case : we don't know if we need DATA IN or DATA out */
                ( 2 * /* Current instructions per scatter/gather segment */ 
-                 tpnt->sg_tablesize + 
-                  3 /* Current startup / termination required per phase */
+                 tpnt->sg_tablesize + 
+                 3 /* Current startup / termination required per phase */
                ) *
        8 /* Each instruction is eight bytes */;
     /* Note that alignment will be guaranteed, since we put the command
@@ -742,7 +743,7 @@ static int normal_init (Scsi_Host_Template *tpnt, int board, int chip,
 
        ASSUMPTION : 
                 Regardless of how many simultaneous SCSI commands we allow,
-         the probe code only executes a _single_ instruction at a time,
+        the probe code only executes a _single_ instruction at a time,
         so we only need one here, and don't need to allocate NCR53c7x0_cmd
         structures for each target until we are no longer in scan_scsis
         and kmalloc() has become functional (memory_init() happens 
@@ -879,9 +880,9 @@ static int ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
        (error = pcibios_read_config_word (bus, device_fn, PCI_COMMAND, 
            &command)) ||
        (error = pcibios_read_config_dword (bus, device_fn, 
-           PCI_BASE_ADDRESS_0, &io_port)) || 
+           PCI_BASE_ADDRESS_0, (int *) &io_port)) || 
        (error = pcibios_read_config_dword (bus, device_fn, 
-           PCI_BASE_ADDRESS_1, &base)) ||
+           PCI_BASE_ADDRESS_1, (int *) &base)) ||
        (error = pcibios_read_config_byte (bus, device_fn, PCI_CLASS_REVISION,
            &revision)) ||
        (error = pcibios_read_config_byte (bus, device_fn, PCI_INTERRUPT_LINE,
@@ -951,7 +952,7 @@ static int ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
 
     if (chip && device_id != expected_id) 
        printk ("scsi-ncr53c7,8xx : warning : device id of 0x%04x doesn't\n"
-                "                   match expected 0x%04x\n",
+               "                   match expected 0x%04x\n",
            (unsigned int) device_id, (unsigned int) expected_id );
     
     if (max_revision != -1 && revision > max_revision) 
@@ -1015,7 +1016,7 @@ int NCR53c7xx_detect(Scsi_Host_Template *tpnt) {
                !pcibios_find_device (PCI_VENDOR_ID_NCR, 
                    pci_chip_ids[i].pci_device_id, pci_index, &pci_bus, 
                    &pci_device_fn) && 
-               !ncr_pci_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip, 
+               !ncr_pci_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip, 
                    pci_bus, pci_device_fn, /* no options */ 0); 
                ++count, ++pci_index);
     }
@@ -1275,7 +1276,7 @@ static int NCR53c8xx_run_tests (struct Scsi_Host *host) {
 
        if (hostdata->test_dest != 0xdeadbeef) {
            printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n"
-                    "        probable cache invalidation problem.  Please configure caching\n"
+                   "        probable cache invalidation problem.  Please configure caching\n"
                    "        as write-through or disabled\n",
                host->host_no, hostdata->test_dest);
        }
@@ -1872,7 +1873,7 @@ static int NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
         * status, etc are used.
         */
 
-        cmd->cmd->result = 0xffff;             
+       cmd->cmd->result = 0xffff;              
 
        /* 
         * Restart command as a REQUEST SENSE.
@@ -2285,13 +2286,19 @@ NCR53c8x0_soft_reset (struct Scsi_Host *host) {
      * and SCSI recommended .5s selection timeout.
      */
 
+    /*
+     * The new gcc won't recognize preprocessing directives
+     * within macro args.
+     */
+#if 0
     NCR53c7x0_write8(STIME0_REG_800, 
        ((14 << STIME0_800_SEL_SHIFT) & STIME0_800_SEL_MASK) 
 /* Disable HTH interrupt */
-#if 0
-       | ((15 << STIME0_800_HTH_SHIFT) & STIME0_800_HTH_MASK)
+       | ((15 << STIME0_800_HTH_SHIFT) & STIME0_800_HTH_MASK));
+#else
+    NCR53c7x0_write8(STIME0_REG_800, 
+       ((14 << STIME0_800_SEL_SHIFT) & STIME0_800_SEL_MASK));
 #endif
-    );
 
 
 
@@ -2344,7 +2351,7 @@ create_cmd (Scsi_Cmnd *cmd) {
     NCR53c7x0_local_declare();
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-        host->hostdata;        
+       host->hostdata; 
     struct NCR53c7x0_cmd *tmp = NULL;  /* NCR53c7x0_cmd structure for this command */
     int datain,                /* Number of instructions per phase */
        dataout;
@@ -2601,7 +2608,7 @@ create_cmd (Scsi_Cmnd *cmd) {
                DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) | 
                DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
            cmd_datain[3] = virt_to_bus(hostdata->script) +
-               hostdata->E_msg_in;
+               hostdata->E_msg_in;
 #if 0
            print_insn (host, cmd_datain, "dynamic ", 1);
            print_insn (host, cmd_datain + 2, "dynamic ", 1);
@@ -2615,7 +2622,7 @@ create_cmd (Scsi_Cmnd *cmd) {
                DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) | 
                DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
            cmd_dataout[3] = virt_to_bus(hostdata->script) +
-               hostdata->E_msg_in;
+               hostdata->E_msg_in;
 #if 0
            print_insn (host, cmd_dataout, "dynamic ", 1);
            print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -2900,7 +2907,7 @@ static void intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
 
     /* selection timeout */
     if ((is_8xx_chip && (sist1 & SIST1_800_STO)) ||
-        (!is_8xx_chip && (sstat0_sist0 & SSTAT0_700_STO))) {
+       (!is_8xx_chip && (sstat0_sist0 & SSTAT0_700_STO))) {
        fatal = 1;
        if (hostdata->options & OPTION_DEBUG_INTR) {
            printk ("scsi%d : Selection Timeout\n", host->host_no);
@@ -3112,8 +3119,8 @@ static void NCR53c7x0_intr (int irq, struct pt_regs * regs) {
 restart:
                    for (cmd_prev_ptr = (struct NCR53c7x0_cmd **) 
                         &(hostdata->running_list), cmd = 
-                         (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
-                         cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next), 
+                        (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
+                        cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next), 
                         cmd = (struct NCR53c7x0_cmd *) cmd->next) {
                        Scsi_Cmnd *tmp;
 
@@ -3766,9 +3773,9 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
  */
 
     for (curr = (volatile struct NCR53c7x0_cmd *) hostdata->issue_queue, 
-         prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->issue_queue);
+        prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->issue_queue);
         curr && curr->cmd != cmd; prev = (volatile struct NCR53c7x0_cmd **)
-         &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
+        &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
        *prev = (struct NCR53c7x0_cmd *) curr->next;
@@ -3793,7 +3800,7 @@ int NCR53c7xx_abort (Scsi_Cmnd *cmd) {
     for (curr = (volatile struct NCR53c7x0_cmd *) hostdata->running_list, 
         prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->running_list);
         curr && curr->cmd != cmd; prev = (volatile struct NCR53c7x0_cmd **) 
-         &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
+        &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
        restore_flags(flags);
@@ -3973,7 +3980,7 @@ ncr_halt (struct Scsi_Host *host) {
                tmp = NCR53c7x0_read8(SSTAT0_REG);
            }
        } else if (istat & ISTAT_DIP) {
-            NCR53c7x0_write8(hostdata->istat, 0);
+           NCR53c7x0_write8(hostdata->istat, 0);
            tmp = NCR53c7x0_read8(DSTAT_REG);
            if (tmp & DSTAT_ABRT)
                break;
index d3c4339fb11ee78e07994c0f1532674d42488891..d561fd6e340c761ebda0c0cb35b74db9d028fde4 100644 (file)
@@ -78,12 +78,15 @@ extern int NCR53c7xx_release(struct Scsi_Host *);
 #define NCR53c7xx_release NULL
 #endif
 
-#define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 4)", NCR53c7xx_detect,      \
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
+#define NCR53c7xx {NULL, NULL, generic_proc_info, "NCR53c7xx",          \
+       PROC_SCSI_NCR53C7xx, "NCR53c{7,8}xx (rel 4)", NCR53c7xx_detect, \
        NULL, /* info */ NULL, /* command, deprecated */ NULL,          \
        NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset,      \
-        NULL /* slave attach */, scsicam_bios_param, /* can queue */ 1, \
+       NULL /* slave attach */, scsicam_bios_param, /* can queue */ 1, \
        /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 1 ,         \
-        /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
+       /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
 #endif /* defined(HOSTS_C) || defined(MODULE) */ 
 
 #ifndef HOSTS_C
@@ -385,9 +388,9 @@ extern int NCR53c7xx_release(struct Scsi_Host *);
 /* 0x80 - 0x04 are reserved */
 #define CTEST0_700_RTRG                0x02    /* Real target mode */
 #define CTEST0_700_DDIR                0x01    /* Data direction, 1 = 
-                                        * SCSI bus to host, 0  =
-                                        * host to SCSI.
-                                        */
+                                        * SCSI bus to host, 0  =
+                                        * host to SCSI.
+                                        */
 
 #define CTEST1_REG_700         0x15    /* Chip test 1 ro */
 #define CTEST1_REG_800         0x19    /* Chip test 1 ro */
@@ -544,7 +547,7 @@ extern int NCR53c7xx_release(struct Scsi_Host *);
 #define CTEST7_EVP             0x04    /* 1 = host bus even parity, 0 = odd */
 #define CTEST7_10_TT1          0x02    /* Transfer type */
 #define CTEST7_00_DC           0x02    /* Set to drive DC low during instruction 
-                                           fetch */
+                                          fetch */
 #define CTEST7_DIFF            0x01    /* Differential mode */
 
 #define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
@@ -620,8 +623,8 @@ extern int NCR53c7xx_release(struct Scsi_Host *);
                                         * speeds.
                                         */
 #define CTEST8_0066_DAS                0x02    /* Disable automatic target/initiator
-                                        * switching.
-                                        */
+                                        * switching.
+                                        */
 #define CTEST8_0066_LDE                0x01    /* Last disconnect enable.
                                         * The status of pending 
                                         * disconnect is maintained by
@@ -980,11 +983,12 @@ struct NCR53c7x0_cmd {
 
 
     volatile struct NCR53c7x0_cmd *next, *prev;        
-                                        /* Linux maintained lists.  Note that
+                                       /* Linux maintained lists.  Note that
                                           hostdata->free is a singly linked
                                           list; the rest are doubly linked */
                                         
 
+    long dsa_size; /* Size of DSA structure */
 
     u32 *data_transfer_start;          /* Start of data transfer routines */
     u32 *data_transfer_end;            /* Address after end of data transfer o
@@ -1058,7 +1062,7 @@ struct NCR53c7x0_hostdata {
         * NCR53c700-66 = 70066
         * NCR53c710 = 710
         * NCR53c720 = 720 
-         * NCR53c810 = 810
+        * NCR53c810 = 810
         */
 
     /*
@@ -1216,7 +1220,7 @@ struct NCR53c7x0_hostdata {
                                           to other target/lun combinations */
 
     int debug_count_limit;             /* Number of commands to execute
-                                          before puking to limit debugging 
+                                          before puking to limit debugging 
                                           output */
                                    
 
@@ -1364,7 +1368,7 @@ struct NCR53c7x0_hostdata {
                (offset)]);                                             \
        }
 
-#define patch_abs_rwri_data(script, offset, symbol, value)             \
+#define patch_abs_rwri_data(script, offset, symbol, value)             \
        for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof            \
            (u32)); ++i)                                                \
            (script)[A_##symbol##_used[i] - (offset)] =                 \
index c3bf5af6dab132f5d46815d9c1a3e8ac41fea7fe..240540ed48ffdcb35bd3f996efa62191d4815c12 100644 (file)
@@ -1,3 +1,19 @@
+Mon May 15 19:33:14 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
+       * scsi.c: Added native multichannel and wide scsi support. 
+
+       * proc.c (dispatch_scsi_info) (build_proc_dir_hba_entries): 
+       Updated /proc/scsi interface.  
+
+Thu May  4 17:58:48 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
+
+       * sd.c (requeue_sd_request): zero out the scatterlist only if
+       scsi_malloc returned memory for it.     
+
+       * eata_dma.c (register_HBA) (eata_queue): add support for
+       large scatter/gatter tables and set use_clustering accordingly
+
+       * hosts.c: make use_clustering changable in the Scsi_Host structure.
+
 Wed Apr 12 15:25:52 1995  Eric Youngdale  (eric@andante)
 
        * Linux 1.2.5 released.
@@ -7,7 +23,12 @@ Wed Apr 12 15:25:52 1995  Eric Youngdale  (eric@andante)
        complete commands per interrupt.  Seems to come up with faster
        cards.
 
-       * eata_dma.c: Modularize.  Update to 2.3.5r.
+       * eata_dma.c: Update to 2.3.5r. Modularize. Improved error handling
+        thruout and fixed bug interrupt routine which resulted in shifted 
+        status bytes. Added blink LED state checks for ISA and EISA HBAs.
+        Memory mamagement bug seems to have disapeared ==> increasing 
+        C_P_L_CURRENT_MAX to 16 for now. Decreasing C_P_L_DIV to 3 for 
+        performance reasons.  
 
        * scsi.c: If we get a FMK, EOM, or ILI when attempting to scan
        the bus, assume that it was just noise on the bus, and ignore
@@ -86,11 +107,11 @@ Mon Feb 20 08:57:17 1995  Eric Youngdale  (eric@andante)
 
        * hosts.h: Change io_port to long int from short.
 
-       * 53c7,8xx.c: crash on AEN fixed, SCSI reset is no longer a NOP,
-         NULL pointer panic on odd UDCs fixed, two bugs in diagnostic output 
-         fixed, should initialize correctly if left running, now loadable, 
-         new memory allocation, extraneous diagnostic output suppressed,
-         splx() replaced with save/restore flags. [ Drew ]
+       * 53c7,8xx.c: crash on AEN fixed, SCSI reset is no longer a NOP,
+         NULL pointer panic on odd UDCs fixed, two bugs in diagnostic output 
+         fixed, should initialize correctly if left running, now loadable, 
+         new memory allocation, extraneous diagnostic output suppressed,
+         splx() replaced with save/restore flags. [ Drew ]
 
        * hosts.c, hosts.h, scsi_ioctl.c, sd.c, sd_ioctl.c, sg.c, sr.c,
        sr_ioctl.c: Add special junk at end that Emacs will use for
@@ -119,7 +140,10 @@ Wed Feb 15 10:52:56 1995  Eric Youngdale  (eric@andante)
 
        * eata.c: Update to 1.17.
 
-       * eata_dma.c: Add more support for /proc/scsi, add HBA_interpret flag.
+       * eata_dma.c: Update to 2.31a. Add more support for /proc/scsi. 
+        Continuing modularization. Less crashes because of the bug in the
+        memory management ==> increase C_P_L_CURRENT_MAX to 10
+        and decrease C_P_L_DIV to 4.
 
        * hosts.c: If we remove last host registered, reuse host number.
        When freeing memory from host being deregistered, free extra_bytes
@@ -188,8 +212,12 @@ Wed Feb  1 09:20:45 1995  Eric Youngdale  (eric@andante)
        * NCR5380.c: Update interrupt handler with new arglist.  Minor
        cleanups.
 
-       * eata_dma.c: Modularize.  Add hooks for /proc/scsi.  
-       New version 2.3.0a.
+       * eata_dma.c: Begin to modularize.  Add hooks for /proc/scsi.  
+       New version 2.3.0a. Add code in interrupt handler to allow
+        certain CDROM drivers to be detected which return a 
+        CHECK_CONDITION during SCSI bus scan. Add opcode check to get
+        all DATA IN and DATA OUT phases right. Utilize HBA_interpret flag.
+       Improvements in HBA identification. Various other minor stuff.
        
        * hosts.c: Initialize ->dma_channel and ->io_port when registering
        a new host.
@@ -238,7 +266,9 @@ Mon Jan 23 23:53:10 1995  Eric Youngdale  (eric@andante)
 
        * 53c7,8xx.h: Change SG size to 127.
 
-       * eata_dma: Update to version 0i.
+       * eata_dma: Update to version 2.10i. Remove bug in the registration
+        of multiple HBAs and channels. Minor other improvements and stylistic 
+        changes.
 
        * scsi.c: Test for Toshiba XM-3401TA and exclude from detection
        as toshiba drive - photo cd does not work with this drive.
@@ -262,7 +292,9 @@ Sun Jan 22 22:08:46 1995  Eric Youngdale  (eric@andante)
 
        * aha152x.c: Update to version 1.8 from Juergen.
 
-       * eata_dma.c: Update from Michael Neuffer
+       * eata_dma.c: Update from Michael Neuffer.
+        Remove hard limit of 2 commands per lun and make it better 
+        configurable. Improvements in HBA identification.
 
        * in2000.c: Fix biosparam to support large disks.
 
@@ -278,7 +310,7 @@ Wed Jan 18 23:33:09 1995  Eric Youngdale  (eric@andante)
        * buslogic.c: Likewise.
 
        * eata_dma.c: Use min of 2 cmd_per_lun for OCS_enabled boards.
-
+          
        * scsi.c: Make RECOVERED_ERROR a SUGGEST_IS_OK.
 
        * sd.c: Fail if we are opening a non-existent partition.
@@ -290,7 +322,7 @@ Wed Jan 18 23:33:09 1995  Eric Youngdale  (eric@andante)
        * sr_ioctl.c: Remove CDROMMULTISESSION_SYS ioctl.
 
        * ultrastor.c: Fix bug in call to ultrastor_interrupt (wrong #args).
-
 Mon Jan 16 07:18:23 1995  Eric Youngdale  (eric@andante)
 
        * Linux 1.1.82 released.
index c843fb721562f46ea437ffba49ff759980baa65e..a23a8dbc89551c92f4f54d0edb01ed3d22094e43 100644 (file)
@@ -1,5 +1,5 @@
 
-# Makefile for kernel/blk_drv/scsi
+# Makefile for linux/drivers/scsi
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
 .c.o:
        $(CC) $(CFLAGS) -c $<
 
+# This is used for ELF - it needs to migrate or be moved.
+LD_RFLAG = -m elf_i386
+
 AHA152X        = -DDEBUG_AHA152X -DAUTOCONF -DSKIP_BIOSTEST -DIRQ=11
 
 ifeq (${CFLAGS},)
 CFLAGS = -D__KERNEL__=1 \
-       -Wall -Wstrict-prototypes -I. -I../../include \
+       -DMODULE -Wall -Wstrict-prototypes -I. -I../../include \
        -O2 -fomit-frame-pointer -m486
 
 include ../../.config
@@ -25,31 +28,43 @@ endif
 
 SCSI_OBJS =
 SCSI_SRCS =
+SCSI_DEP =
 SCSI_MODULE_OBJS =
 
-ifdef CONFIG_SCSI
+SCSI_SRCS := hosts.c scsi.c scsi_ioctl.c constants.c scsicam.c scsi_proc.c
 
-SCSI_OBJS := hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o
-SCSI_SRCS := hosts.c scsi.c scsi_ioctl.c constants.c scsicam.c
+ifdef CONFIG_SCSI
+SCSI_OBJS := hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_mod.o
+endif
 
+SCSI_SRCS := $(SCSI_SRCS) st.c
 ifdef CONFIG_CHR_DEV_ST
 SCSI_OBJS := $(SCSI_OBJS) st.o
-SCSI_SRCS := $(SCSI_SRCS) st.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) st.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) sd.c sd_ioctl.c
 ifdef CONFIG_BLK_DEV_SD
 SCSI_OBJS := $(SCSI_OBJS) sd.o sd_ioctl.o
-SCSI_SRCS := $(SCSI_SRCS) sd.c sd_ioctl.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) sd_mod.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) sr.c sr_ioctl.c
 ifdef CONFIG_BLK_DEV_SR
 SCSI_OBJS := $(SCSI_OBJS) sr.o sr_ioctl.o
-SCSI_SRCS := $(SCSI_SRCS) sr.c sr_ioctl.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) sr_mod.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) sg.c
 ifdef CONFIG_CHR_DEV_SG
 SCSI_OBJS := $(SCSI_OBJS) sg.o
-SCSI_SRCS := $(SCSI_SRCS) sg.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) sg.o
 endif
 
 SCSI_SRCS := $(SCSI_SRCS) qlogic.c
@@ -59,31 +74,40 @@ else
 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) qlogic.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) aha152x.c
 ifdef CONFIG_SCSI_AHA152X
 SCSI_OBJS := $(SCSI_OBJS) aha152x.o
-SCSI_SRCS := $(SCSI_SRCS) aha152x.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha152x.o
 endif
 
-ifdef CONFIG_SCSI_AHA1542
 SCSI_SRCS := $(SCSI_SRCS) aha1542.c
+ifdef CONFIG_SCSI_AHA1542
 SCSI_OBJS := $(SCSI_OBJS) aha1542.o
 else
 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha1542.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) aha1740.c
 ifdef CONFIG_SCSI_AHA1740
 SCSI_OBJS := $(SCSI_OBJS) aha1740.o
-SCSI_SRCS := $(SCSI_SRCS) aha1740.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha1740.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) aic7xxx.c
+SCSI_DEP := $(SCSI_DEP) aic7xxx_seq.h
 ifdef CONFIG_SCSI_AIC7XXX
 SCSI_OBJS := $(SCSI_OBJS) aic7xxx.o
-SCSI_SRCS := $(SCSI_SRCS) aic7xxx.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aic7xxx.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) buslogic.c
 ifdef CONFIG_SCSI_BUSLOGIC
 SCSI_OBJS := $(SCSI_OBJS) buslogic.o
-SCSI_SRCS := $(SCSI_SRCS) buslogic.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) buslogic.o
 endif
 
 SCSI_SRCS := $(SCSI_SRCS) eata_dma.c
@@ -93,77 +117,91 @@ else
 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata_dma.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) eata_pio.c
+ifdef CONFIG_SCSI_EATA_PIO
+SCSI_OBJS := $(SCSI_OBJS) eata_pio.o
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata_pio.o
+endif
+
+SCSI_SRCS := $(SCSI_SRCS) u14-34f.c
 ifdef CONFIG_SCSI_U14_34F
 SCSI_OBJS := $(SCSI_OBJS) u14-34f.o
-SCSI_SRCS := $(SCSI_SRCS) u14-34f.c
 else
 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) u14-34f.o
 endif
 
-ifdef CONFIG_SCSI_DEBUG
 SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
+ifdef CONFIG_SCSI_DEBUG
 SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o
 else
 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_debug.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) fdomain.c
 ifdef CONFIG_SCSI_FUTURE_DOMAIN
 SCSI_OBJS := $(SCSI_OBJS) fdomain.o
-SCSI_SRCS := $(SCSI_SRCS) fdomain.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) fdomain.o
 endif
 
-ifdef CONFIG_SCSI_IN2000
 SCSI_SRCS := $(SCSI_SRCS) in2000.c
+ifdef CONFIG_SCSI_IN2000
 SCSI_OBJS := $(SCSI_OBJS) in2000.o
 else
 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) in2000.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c
 ifdef CONFIG_SCSI_GENERIC_NCR5380
 SCSI_OBJS := $(SCSI_OBJS) g_NCR5380.o
-SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) 53c7,8xx.c
 ifdef CONFIG_SCSI_NCR53C7xx
 SCSI_OBJS := $(SCSI_OBJS) 53c7,8xx.o 
-SCSI_SRCS := $(SCSI_SRCS) 53c7,8xx.c
 else
 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) 53c7,8xx.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) pas16.c
 ifdef CONFIG_SCSI_PAS16
 SCSI_OBJS := $(SCSI_OBJS) pas16.o
-SCSI_SRCS := $(SCSI_SRCS) pas16.c
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) seagate.c
 ifdef CONFIG_SCSI_SEAGATE
 SCSI_OBJS := $(SCSI_OBJS) seagate.o
-SCSI_SRCS := $(SCSI_SRCS) seagate.c
 else
 ifdef CONFIG_SCSI_FD_8xx
 SCSI_OBJS := $(SCSI_OBJS) seagate.o
-SCSI_SRCS := $(SCSI_SRCS) seagate.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) seagate.o
 endif
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) wd7000.c
 ifdef CONFIG_SCSI_7000FASST
 SCSI_OBJS := $(SCSI_OBJS) wd7000.o
-SCSI_SRCS := $(SCSI_SRCS) wd7000.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) wd7000.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) t128.c
 ifdef CONFIG_SCSI_T128
 SCSI_OBJS := $(SCSI_OBJS) t128.o
-SCSI_SRCS := $(SCSI_SRCS) t128.c
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) ultrastor.c
 ifdef CONFIG_SCSI_ULTRASTOR
 SCSI_OBJS := $(SCSI_OBJS) ultrastor.o
-SCSI_SRCS := $(SCSI_SRCS) ultrastor.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) ultrastor.o
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) eata.c
 ifdef CONFIG_SCSI_EATA
 SCSI_OBJS := $(SCSI_OBJS) eata.o
-SCSI_SRCS := $(SCSI_SRCS) eata.c
 else
 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata.o
 endif
@@ -177,11 +215,11 @@ scsi.a: $(SCSI_OBJS)
 aha152x.o: aha152x.c
        $(CC) $(CFLAGS) $(AHA152X) -c aha152x.c 
 
-aic7770:       aic7770.c
-               $(CC) $(CFLAGS) -o $@ aic7770.c
+aic7xxx_asm:   aic7xxx_asm.c
+       $(CC) $(CFLAGS) -o $@ aic7xxx_asm.c
 
-aic7xxx_seq.h: aic7770 aic7xxx.seq
-               ./aic7770 -o $@ aic7xxx.seq
+aic7xxx_seq.h: aic7xxx_asm aic7xxx.seq
+       ./aic7xxx_asm -o $@ aic7xxx.seq
 
 seagate.o: seagate.c
        $(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -c seagate.c 
@@ -197,24 +235,24 @@ seagate.o: seagate.c
        mv scriptu.h 53c8xx_u.h
        rm fake.c
 
-modules: $(SCSI_MODULE_OBJS)
-       echo $(SCSI_MODULE_OBJS) > ../../modules/SCSI_MODULES
-       (cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done)
+scsi_mod.o: hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
+       $(LD) $(LD_RFLAG) -r -o $@ hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
 
-dep:
-       $(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend
-       $(CPP) -M -DMODULE $(SCSI_MODULE_OBJS:.o=.c) >> .depend
+sr_mod.o: sr.o sr_ioctl.o
+       $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o
 
-else
+sd_mod.o: sd.o sd_ioctl.o
+       $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o
 
-scsi.a:
-       rm -f scsi.a
-       @echo No SCSI drivers configured
-       $(AR) rcs scsi.a
 
-dep:
+modules: $(SCSI_MODULE_OBJS)
+       echo $(SCSI_MODULE_OBJS) > ../../modules/SCSI_MODULES
+       (cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done)
 
-endif
+dep:   $(SCSI_DEP)
+       $(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend
+       $(CPP) -M -DMODULE $(patsubst sd_mod.c,sd.c sd_ioctl.c, \
+                          $(patsubst sr_mod.c,sr.c sr_ioctl.c, $(SCSI_MODULE_OBJS:.o=.c))) >> .depend
 
 #
 # include a dependency file if one exists
index c2881457bf81c299e514cfc90cd8c7f8f0f89a57..3b78233e68f3ad73a2146e8a65153c546db7b1cb 100644 (file)
@@ -438,9 +438,9 @@ static __inline__ void run_main(void) {
     cli();
     if (!main_running) {
        main_running = 1;
-        NCR5380_main();
+       NCR5380_main();
        /* 
-         * main_running is cleared in NCR5380_main once it can't do 
+        * main_running is cleared in NCR5380_main once it can't do 
         * more work, and NCR5380_main exits with interrupts disabled.
         */
        sti();
@@ -808,8 +808,8 @@ static void NCR5380_init (struct Scsi_Host *instance, int flags) {
 #ifndef AUTOSENSE
     if ((instance->cmd_per_lun > 1) || instance->can_queue > 1)) 
         printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n"
-               "         without AUTOSENSE option, contingent allegiance conditions may\n"
-               "         be incorrectly cleared.\n", instance->host_no);
+               "         without AUTOSENSE option, contingent allegiance conditions may\n"
+               "         be incorrectly cleared.\n", instance->host_no);
 #endif /* def AUTOSENSE */
 
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -1108,7 +1108,7 @@ static void NCR5380_intr (int irq, struct pt_regs * regs) {
                                     && jiffies < timeout)
                                ;
                              if (jiffies >= timeout)
-                               printk("scsi: timeout at %d\n", __LINE__);
+                               printk("scsi: timeout at %d\n", __LINE__);
                            }
 #else /* NCR_TIMEOUT */
                            while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
@@ -1621,8 +1621,8 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
     NCR5380_setup(instance);
 
     if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
-        *phase = tmp;
-        return -1;
+       *phase = tmp;
+       return -1;
     }
 #if defined(REAL_DMA) || defined(REAL_DMA_POLL) 
 #ifdef READ_OVERRUNS
@@ -1737,17 +1737,17 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
 #ifdef READ_OVERRUNS
       udelay(10);
       if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH|BASR_ACK)) ==
-           (BASR_PHASE_MATCH | BASR_ACK))) {
-        saved_data = NCR5380_read(INPUT_DATA_REGISTER);
-        overrun = 1;
+          (BASR_PHASE_MATCH | BASR_ACK))) {
+       saved_data = NCR5380_read(INPUT_DATA_REGISTER);
+       overrun = 1;
       }
 #endif
     } else {
       int limit = 100;
       while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) ||
-            (NCR5380_read(STATUS_REG) & SR_REQ)) {
-        if (!(tmp & BASR_PHASE_MATCH)) break;
-        if (--limit < 0) break;
+           (NCR5380_read(STATUS_REG) & SR_REQ)) {
+       if (!(tmp & BASR_PHASE_MATCH)) break;
+       if (--limit < 0) break;
       }
     }
 
@@ -1770,15 +1770,15 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
     if (*phase == p && (p & SR_IO) && residue == 0) {
       if (overrun) {
 #if (NDEBUG & NDEBUG_DMA)
-        printk("Got an input overrun, using saved byte\n");
+       printk("Got an input overrun, using saved byte\n");
 #endif
-        **data = saved_data;
-        *data += 1;
-        *count -= 1;
-        cnt = toPIO = 1;
+       **data = saved_data;
+       *data += 1;
+       *count -= 1;
+       cnt = toPIO = 1;
       } else {
-        printk("No overrun??\n");
-        cnt = toPIO = 2;
+       printk("No overrun??\n");
+       cnt = toPIO = 2;
       }
 #if (NDEBUG & NDEBUG_DMA)
       printk("Doing %d-byte PIO to 0x%X\n", cnt, *data);
@@ -1839,7 +1839,7 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
 #if 1
                while (!(NCR5380_read(BUS_AND_STATUS_REG) & 
                        BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) &
-                       BASR_PHASE_MATCH));
+                       BASR_PHASE_MATCH));
 #else
                if (NCR5380_read(STATUS_REG) & SR_REQ) {
                    for (; timeout && 
@@ -1989,16 +1989,16 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) {
                if (!cmd->device->borken &&
                    (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
 #else
-                transfersize = cmd->transfersize;
+               transfersize = cmd->transfersize;
 
 #ifdef LIMIT_TRANSFERSIZE  /* If we have problems with interrupt service */
-                if( transfersize > 512 )
-                    transfersize = 512;
+               if( transfersize > 512 )
+                   transfersize = 512;
 #endif  /* LIMIT_TRANSFERSIZE */
 
-                if (!cmd->device->borken && transfersize && 
-                    cmd->SCp.this_residual && !(cmd->SCp.this_residual % 
-                    transfersize)) {
+               if (!cmd->device->borken && transfersize && 
+                   cmd->SCp.this_residual && !(cmd->SCp.this_residual % 
+                   transfersize)) {
 #endif
                    len = transfersize;
                    if (NCR5380_transfer_dma(instance, &phase,
@@ -2132,8 +2132,8 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) {
                        cli();
                        cmd->host_scribble = (unsigned char *) 
                            hostdata->issue_queue;
-                       hostdata->issue_queue = (Scsi_Cmnd *) cmd;
-                       sti();
+                       hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+                       sti();
 #if (NDEBUG & NDEBUG_QUEUES)
                        printk("scsi%d : REQUEST SENSE added to head of issue queue\n");
 #endif
@@ -2176,7 +2176,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) {
                    sti();
 #if (NDEBUG & NDEBUG_QUEUES)
                    printk("scsi%d : command for target %d lun %d was moved from connected to"
-                          "  the disconnected_queue\n", instance->host_no, 
+                          "  the disconnected_queue\n", instance->host_no, 
                            cmd->target, cmd->lun);
 #endif
                    /* 
@@ -2663,7 +2663,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) {
 #if (NDEBUG & NDEBUG_ABORT)
     printk("scsi%d : abort failed, command connected.\n", instance->host_no);
 #endif
-        return SCSI_ABORT_NOT_RUNNING;
+       return SCSI_ABORT_NOT_RUNNING;
     }
 
 /*
@@ -2693,13 +2693,13 @@ int NCR5380_abort (Scsi_Cmnd *cmd) {
 
     for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; 
        tmp = (Scsi_Cmnd *) tmp->host_scribble) 
-        if (cmd == tmp) {
-            sti(); 
+       if (cmd == tmp) {
+           sti(); 
 #if (NDEBUG & NDEBUG_ABORT)
     printk("scsi%d : aborting disconnected command.\n", instance->host_no);
 #endif
   
-            if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
+           if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
                return SCSI_ABORT_BUSY;
 
 #if (NDEBUG & NDEBUG_ABORT)
@@ -2740,7 +2740,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) {
 
     sti();
     printk("scsi%d : warning : SCSI command probably completed successfully\n"
-           "         before abortion\n", instance->host_no); 
+          "         before abortion\n", instance->host_no); 
     return SCSI_ABORT_NOT_RUNNING;
 }
 
index 7d80697fe5358ef7d4d637bbb197f8d7568ef0f6..bd0fcaa85788861fc9efac2b02fef8b2cc98f381 100644 (file)
@@ -293,10 +293,10 @@ static void NCR5380_reselect (struct Scsi_Host *instance);
 static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag);
 #if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
 static int NCR5380_transfer_dma (struct Scsi_Host *instance,
-        unsigned char *phase, int *count, unsigned char **data);
+       unsigned char *phase, int *count, unsigned char **data);
 #endif
 static int NCR5380_transfer_pio (struct Scsi_Host *instance,
-        unsigned char *phase, int *count, unsigned char **data);
+       unsigned char *phase, int *count, unsigned char **data);
 
 #if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386)
 static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
diff --git a/drivers/scsi/README-FIRST.aic7xxx b/drivers/scsi/README-FIRST.aic7xxx
deleted file mode 100644 (file)
index efd0bbd..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-The 274x/284x support is basically the same as in the kernel, with
-some minor structural changes.  The 294x support is preliminary, with
-a few things still hardwired (like the SCSI ID and FIFO threshold).
-You have been warned.
-
-To function properly, you must use this with a kernel version 1.1.68
-or above - these have the SCSI changes in the kernel which support
-varying numbers of outstanding SCSI commands per driver instance (they
-also contain the Adaptec PCI definitions).
-
-You can find instructions in the SCSI-HOWTO on how to install SCSI
-drivers into the kernel.  In a nutshell, find all the aha274x stuff
-and change it to aic7xxx.
-
-Please direct all problems to the AIC7770 mailing list - see the README
-for details.
-:ja
index 21b33fe2fc427d5f667857fd7def364a570b3b0b..b488f7021eb46d6b4a02b04ebf579ac4b474de39 100644 (file)
 #include <linux/string.h>
 #include <linux/wait.h>
 #include <linux/ioport.h>
+#include <linux/proc_fs.h>
 
 #include "aha152x.h"
 
@@ -422,9 +423,9 @@ static inline void append_SC( Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
   else
     {
       for( end=*SC;
-           end->host_scribble;
-           end = (Scsi_Cmnd *) end->host_scribble )
-        ;
+          end->host_scribble;
+          end = (Scsi_Cmnd *) end->host_scribble )
+       ;
       end->host_scribble = (unsigned char *) new_SC;
     }
 }
@@ -486,18 +487,18 @@ static int getphase(void)
   while( 1 )
     {
       do
-        {
-          while( !( ( sstat1 = GETPORT( SSTAT1 ) ) & (BUSFREE|SCSIRSTI|REQINIT ) ) )
-            ;
-          if( sstat1 & BUSFREE )
-            return P_BUSFREE;
-          if( sstat1 & SCSIRSTI )
-            {
-              /* IBM drive responds with RSTI to RSTO */
-              printk("aha152x: RESET IN\n");
-              SETPORT( SSTAT1, SCSIRSTI );
-            }
-        }
+       {
+         while( !( ( sstat1 = GETPORT( SSTAT1 ) ) & (BUSFREE|SCSIRSTI|REQINIT ) ) )
+           ;
+         if( sstat1 & BUSFREE )
+           return P_BUSFREE;
+         if( sstat1 & SCSIRSTI )
+           {
+             /* IBM drive responds with RSTI to RSTO */
+             printk("aha152x: RESET IN\n");
+             SETPORT( SSTAT1, SCSIRSTI );
+           }
+       }
       while( TESTHI( SCSISIG, ACKI ) || TESTLO( SSTAT1, REQINIT ) );
 
       SETPORT( SSTAT1, CLRSCSIPERR );
@@ -505,14 +506,14 @@ static int getphase(void)
       phase = GETPORT( SCSISIG ) & P_MASK ;
 
       if( TESTHI( SSTAT1, SCSIPERR ) )
-        {
-          if( (phase & (CDO|MSGO))==0 )                         /* DATA phase */
-            return P_PARITY;
+       {
+         if( (phase & (CDO|MSGO))==0 )                         /* DATA phase */
+           return P_PARITY;
 
-          make_acklow();
-        }
+         make_acklow();
+       }
       else
-        return phase;
+       return phase;
     }
 }
 
@@ -574,15 +575,15 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
 #else
       if(setup_called>5)
 #endif
-        {
-          printk("\naha152x: %s\n", setup_str );
+       {
+         printk("\naha152x: %s\n", setup_str );
 #ifdef DEBUG_AHA152X
-          printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>[,<DEBUG>]]]]]\n");
+         printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>[,<DEBUG>]]]]]\n");
 #else
-          printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>]]]]\n");
+         printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>]]]]\n");
 #endif
-          panic("aha152x panics in line %d", __LINE__);
-        }
+         panic("aha152x panics in line %d", __LINE__);
+       }
 
       port_base       = setup_portbase;
       interrupt_level = setup_irq;
@@ -595,53 +596,53 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
 
 #ifndef PCMCIA
       for( i=0; i<PORT_COUNT && (port_base != ports[i]); i++)
-        ;
+       ;
 
       if(i==PORT_COUNT)
-        {
-          printk("unknown portbase 0x%03x\n", port_base);
-          panic("aha152x panics in line %d", __LINE__);
-        }
+       {
+         printk("unknown portbase 0x%03x\n", port_base);
+         panic("aha152x panics in line %d", __LINE__);
+       }
 #endif
 
       if(!aha152x_porttest(port_base))
-        {
-          printk("portbase 0x%03x fails probe\n", port_base);
+       {
+         printk("portbase 0x%03x fails probe\n", port_base);
 #ifdef PCMCIA
-          return 0;
+         return 0;
 #else
-          panic("aha152x panics in line %d", __LINE__);
+         panic("aha152x panics in line %d", __LINE__);
 #endif
-        }
+       }
 
 #ifndef PCMCIA
       i=0;
       while(irqs[i] && (interrupt_level!=irqs[i]))
-        i++;
+       i++;
       if(!irqs[i])
-        {
-          printk("illegal IRQ %d\n", interrupt_level);
-          panic("aha152x panics in line %d", __LINE__);
-        }
+       {
+         printk("illegal IRQ %d\n", interrupt_level);
+         panic("aha152x panics in line %d", __LINE__);
+       }
 #endif
       
       if( (this_host < 0) || (this_host > 7) )
-        {
-          printk("illegal SCSI ID %d\n", this_host);
-          panic("aha152x panics in line %d", __LINE__);
-        }
+       {
+         printk("illegal SCSI ID %d\n", this_host);
+         panic("aha152x panics in line %d", __LINE__);
+       }
 
       if( (can_disconnect < 0) || (can_disconnect > 1) )
-        {
-          printk("reconnect %d should be 0 or 1\n", can_disconnect);
-          panic("aha152x panics in line %d", __LINE__);
-        }
+       {
+         printk("reconnect %d should be 0 or 1\n", can_disconnect);
+         panic("aha152x panics in line %d", __LINE__);
+       }
 
       if( (can_doparity < 0) || (can_doparity > 1) )
-        {
-          printk("parity %d should be 0 or 1\n", can_doparity);
-          panic("aha152x panics in line %d", __LINE__);
-        }
+       {
+         printk("parity %d should be 0 or 1\n", can_doparity);
+         panic("aha152x panics in line %d", __LINE__);
+       }
       printk("ok\n");
     }
   else
@@ -651,13 +652,13 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
 
       ok=0;
       for( i=0; i < ADDRESS_COUNT && !ok; i++)
-        for( j=0; (j < SIGNATURE_COUNT) && !ok; j++)
-          ok=!memcmp((void *) addresses[i]+signatures[j].sig_offset,
-                     (void *) signatures[j].signature,
-                     (int) signatures[j].sig_length);
+       for( j=0; (j < SIGNATURE_COUNT) && !ok; j++)
+         ok=!memcmp((void *) addresses[i]+signatures[j].sig_offset,
+                    (void *) signatures[j].signature,
+                    (int) signatures[j].sig_length);
 
       if(!ok)
-        return 0;
+       return 0;
 
       printk("aha152x: BIOS test: passed, ");
 #else
@@ -667,15 +668,15 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
 #if !defined(PORTBASE)
       printk("porttest: ");
       for( i=0; i<PORT_COUNT && !aha152x_porttest(ports[i]); i++)
-        ;
+       ;
 
       if(i==PORT_COUNT)
-        {
-          printk("failed\n");
-          return 0;
-        }
+       {
+         printk("failed\n");
+         return 0;
+       }
       else
-        port_base=ports[i];
+       port_base=ports[i];
       printk("ok, ");
 #else
       port_base=PORTBASE;
@@ -718,20 +719,20 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
   if(ok<0)
     {
       if(ok == -EINVAL)
-        {
-           printk("aha152x: bad IRQ %d.\n", interrupt_level);
-           printk("         Contact author.\n");
-        }
+       {
+          printk("aha152x: bad IRQ %d.\n", interrupt_level);
+          printk("         Contact author.\n");
+       }
       else
-        if( ok == -EBUSY)
-          printk( "aha152x: IRQ %d already in use. Configure another.\n",
-                  interrupt_level);
-        else
-          {
-            printk( "\naha152x: Unexpected error code on requesting IRQ %d.\n",
-                    interrupt_level);
-            printk("         Contact author.\n");
-          }
+       if( ok == -EBUSY)
+         printk( "aha152x: IRQ %d already in use. Configure another.\n",
+                 interrupt_level);
+       else
+         {
+           printk( "\naha152x: Unexpected error code on requesting IRQ %d.\n",
+                   interrupt_level);
+           printk("         Contact author.\n");
+         }
       panic("aha152x: driver needs an IRQ.\n");
     }
 
@@ -750,11 +751,11 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
   aha152x_reset(NULL);
 
   printk("aha152x: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d, reconnect=%s, parity=%s\n",
-         port_base,
-         interrupt_level,
-         this_host,
-         can_disconnect ? "enabled" : "disabled",
-         can_doparity ? "enabled" : "disabled");
+        port_base,
+        interrupt_level,
+        this_host,
+        can_disconnect ? "enabled" : "disabled",
+        can_doparity ? "enabled" : "disabled");
 
   request_region(port_base, 0x20, "aha152x");        /* Register */
 
@@ -793,7 +794,7 @@ int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     printk( "SCpnt (target = %d lun = %d cmnd = ", SCpnt->target, SCpnt->lun);
     print_command(SCpnt->cmnd);
     printk( ", cmd_len=%d, pieces = %d size = %u), ",
-            SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen );
+           SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen );
     disp_ports();
   }
 #endif
@@ -821,7 +822,7 @@ int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
       SCpnt->SCp.buffer           = NULL;
       SCpnt->SCp.buffers_residual = 0;
     }
-          
+         
   SCpnt->SCp.Status              = CHECK_CONDITION;
   SCpnt->SCp.Message             = 0;
   SCpnt->SCp.have_data_in        = 0;
@@ -895,9 +896,9 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
     {
       /* dequeue */
       if(prev)
-        prev->host_scribble = ptr->host_scribble;
+       prev->host_scribble = ptr->host_scribble;
       else
-        issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
+       issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
       restore_flags(flags);
 
       ptr->host_scribble = NULL;
@@ -913,7 +914,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
       /* fail abortion, if bus is busy */
 
       if(!current_SC)
-        printk("bus busy w/o current command, ");
+       printk("bus busy w/o current command, ");
  
       restore_flags(flags);
       return SCSI_ABORT_BUSY;
@@ -940,43 +941,43 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
   if(ptr)
     if(!aborting)
       {
-        /* dequeue */
-        if(prev)
-          prev->host_scribble = ptr->host_scribble;
-        else
-          disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
+       /* dequeue */
+       if(prev)
+         prev->host_scribble = ptr->host_scribble;
+       else
+         disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
   
-        /* set command current and initiate selection,
-           let the interrupt routine take care of the abortion */
-        current_SC     = ptr;
-        ptr->SCp.phase = in_selection|aborted;
-        SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
+       /* set command current and initiate selection,
+          let the interrupt routine take care of the abortion */
+       current_SC     = ptr;
+       ptr->SCp.phase = in_selection|aborted;
+       SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
   
-        /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
-        SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
-        SETPORT( SIMODE1, ENSELTIMO );
+       /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
+       SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
+       SETPORT( SIMODE1, ENSELTIMO );
   
-        /* Enable SELECTION OUT sequence */
-        SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
+       /* Enable SELECTION OUT sequence */
+       SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
   
-        SETBITS( DMACNTRL0, INTEN );
-        abort_result=SCSI_ABORT_SUCCESS;
-        aborting++;
-        abortion_complete=0;
+       SETBITS( DMACNTRL0, INTEN );
+       abort_result=SCSI_ABORT_SUCCESS;
+       aborting++;
+       abortion_complete=0;
 
-        sti();  /* Hi Eric, guess what ;-) */
+       sti();  /* Hi Eric, guess what ;-) */
   
-        /* sleep until the abortion is complete */
-        while(!abortion_complete)
+       /* sleep until the abortion is complete */
+       while(!abortion_complete)
          barrier();
-        aborting=0;
-        return abort_result;
+       aborting=0;
+       return abort_result;
       }
     else
       {
-        /* we're already aborting a command */
-        restore_flags(flags);
-        return SCSI_ABORT_BUSY;
+       /* we're already aborting a command */
+       restore_flags(flags);
+       return SCSI_ABORT_BUSY;
       }
 
   /* command wasn't found */
@@ -1044,12 +1045,12 @@ int aha152x_reset(Scsi_Cmnd * __unused)
 #endif
 
        if(current_SC && !current_SC->device->soft_reset)
-         {
-           current_SC->host_scribble = NULL;
-           current_SC->result = DID_RESET << 16;
-           current_SC->done(current_SC);
-           current_SC=NULL;
-         }
+        {
+          current_SC->host_scribble = NULL;
+          current_SC->result = DID_RESET << 16;
+          current_SC->done(current_SC);
+          current_SC=NULL;
+        }
 
        save_flags(flags);
        cli();
@@ -1082,8 +1083,8 @@ int aha152x_reset(Scsi_Cmnd * __unused)
 #if defined( DEBUG_RESET )
        if(aha152x_debug & debug_reset)
        {
-         printk("commands on targets w/ soft-resets:\n");
-         show_queues();
+        printk("commands on targets w/ soft-resets:\n");
+        show_queues();
        }
 #endif
 
@@ -1124,7 +1125,7 @@ int aha152x_biosparam(Scsi_Disk * disk, int dev, int *info_array )
   if(aha152x_debug & debug_biosparam)
   {
     printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
-           info_array[0], info_array[1], info_array[2]);
+          info_array[0], info_array[1], info_array[2]);
     printk("WARNING: check, if the bios geometry is correct.\n");
   }
 #endif
@@ -1152,7 +1153,7 @@ void aha152x_done( int error )
     {
 #if defined(DEBUG_DONE)
       if(aha152x_debug & debug_done)
-        printk("done(%x), ", error);
+       printk("done(%x), ", error);
 #endif
 
       save_flags(flags);
@@ -1164,11 +1165,11 @@ void aha152x_done( int error )
       /* turn led off, when no commands are in the driver */
       commands--;
       if(!commands)
-        SETPORT( PORTA, 0 );                                  /* turn led off */
+       SETPORT( PORTA, 0 );                                  /* turn led off */
 
 #if defined(DEBUG_QUEUES)
       if(aha152x_debug & debug_queues) 
-        printk("ok (%d), ", commands);
+       printk("ok (%d), ", commands);
 #endif
       restore_flags(flags);
 
@@ -1177,30 +1178,30 @@ void aha152x_done( int error )
 
 #if defined(DEBUG_PHASES)
       if(aha152x_debug & debug_phases)
-        printk("BUS FREE loop, ");
+       printk("BUS FREE loop, ");
 #endif
       while( TESTLO( SSTAT1, BUSFREE ) )
-        ;
+       ;
 #if defined(DEBUG_PHASES)
       if(aha152x_debug & debug_phases)
-        printk("BUS FREE\n");
+       printk("BUS FREE\n");
 #endif
 
       done_SC->result = error;
       if(done_SC->scsi_done)
-        {
+       {
 #if defined(DEBUG_DONE)
-          if(aha152x_debug & debug_done)
-            printk("calling scsi_done, ");
+         if(aha152x_debug & debug_done)
+           printk("calling scsi_done, ");
 #endif
-          done_SC->scsi_done( done_SC );
+         done_SC->scsi_done( done_SC );
 #if defined(DEBUG_DONE)
-          if(aha152x_debug & debug_done)
-            printk("done returned, ");
+         if(aha152x_debug & debug_done)
+           printk("done returned, ");
 #endif
-        }
+       }
       else
-        panic( "aha152x: current_SC->scsi_done() == NULL" );
+       panic( "aha152x: current_SC->scsi_done() == NULL" );
     }
   else
     aha152x_panic( "done() called outside of command" );
@@ -1242,19 +1243,19 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
       int identify_msg, target, i;
 
       /* Avoid conflicts when a target reconnects
-         while we are trying to connect to another. */
+        while we are trying to connect to another. */
       if(current_SC)
-        {
+       {
 #if defined(DEBUG_QUEUES)
          if(aha152x_debug & debug_queues)
-          printk("i+, ");
+         printk("i+, ");
 #endif
          save_flags(flags);
-          cli();
-          append_SC( &issue_SC, current_SC);
-          current_SC=NULL;
-          restore_flags(flags);
-        }
+         cli();
+         append_SC( &issue_SC, current_SC);
+         current_SC=NULL;
+         restore_flags(flags);
+       }
 
       /* disable sequences */
       SETPORT( SCSISEQ, 0 );
@@ -1263,35 +1264,35 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
 
 #if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
       if(aha152x_debug & (debug_queues|debug_phases))
-        printk("reselected, ");
+       printk("reselected, ");
 #endif
 
       i = GETPORT(SELID) & ~(1 << this_host);
       target=0;
       if(i)
-        for( ; (i & 1)==0; target++, i>>=1)
-          ;
+       for( ; (i & 1)==0; target++, i>>=1)
+         ;
       else
-        aha152x_panic("reconnecting target unknown");
+       aha152x_panic("reconnecting target unknown");
 
 #if defined(DEBUG_QUEUES)
       if(aha152x_debug & debug_queues)
-        printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
+       printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
 #endif
       SETPORT( SCSIID, (this_host << OID_) | target );
       SETPORT( SCSISEQ, ENRESELI );
 
       if(TESTLO( SSTAT0, SELDI ))
-        aha152x_panic("RESELI failed");
+       aha152x_panic("RESELI failed");
 
       SETPORT( SCSISIG, P_MSGI );
 
       /* Get identify message */
       if((i=getphase())!=P_MSGI)
-        {
-          printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
-          aha152x_panic("unknown lun");
-        }
+       {
+         printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
+         aha152x_panic("unknown lun");
+       }
       SETPORT( SCSISEQ, 0 );
 
       SETPORT( SXFRCTL0, CH1);
@@ -1299,18 +1300,18 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
       identify_msg = GETPORT(SCSIBUS);
 
       if(!(identify_msg & IDENTIFY_BASE))
-        {
-          printk("target=%d, inbound message (%02x) != IDENTIFY\n",
-                 target, identify_msg);
-          aha152x_panic("unknown lun");
-        }
+       {
+         printk("target=%d, inbound message (%02x) != IDENTIFY\n",
+                target, identify_msg);
+         aha152x_panic("unknown lun");
+       }
 
       make_acklow();
       getphase();
 
 #if defined(DEBUG_QUEUES)
       if(aha152x_debug & debug_queues)
-        printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
+       printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
 #endif
 
       save_flags(flags);
@@ -1318,17 +1319,17 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
 
 #if defined(DEBUG_QUEUES)
       if(aha152x_debug & debug_queues)
-        printk("d-, ");
+       printk("d-, ");
 #endif
       current_SC = remove_SC( &disconnected_SC,
-                              target,
-                              identify_msg & 0x3f );
+                             target,
+                             identify_msg & 0x3f );
 
       if(!current_SC)
-        {
-          printk("lun=%d, ", identify_msg & 0x3f );
-          aha152x_panic("no disconnected command for that lun");
-        }
+       {
+         printk("lun=%d, ", identify_msg & 0x3f );
+         aha152x_panic("no disconnected command for that lun");
+       }
 
       current_SC->SCp.phase &= ~disconnected;
       restore_flags(flags);
@@ -1347,44 +1348,44 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
     {
       /* bus is free to issue a queued command */
       if(TESTHI( SSTAT1, BUSFREE) && issue_SC)
-        {
-          save_flags(flags);
-          cli();
+       {
+         save_flags(flags);
+         cli();
 #if defined(DEBUG_QUEUES)
-          if(aha152x_debug & debug_queues)
-            printk("i-, ");
+         if(aha152x_debug & debug_queues)
+           printk("i-, ");
 #endif
-          current_SC = remove_first_SC( &issue_SC );
-          restore_flags(flags);
+         current_SC = remove_first_SC( &issue_SC );
+         restore_flags(flags);
 
 #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
          if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
-            printk("issuing command, ");
+           printk("issuing command, ");
 #endif
-          current_SC->SCp.phase = in_selection;
+         current_SC->SCp.phase = in_selection;
 
   #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
          if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
-            printk("selecting %d, ", current_SC->target); 
+           printk("selecting %d, ", current_SC->target); 
   #endif
-          SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
+         SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
 
-          /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
-          SETPORT( SXFRCTL1, can_doparity ? (ENSPCHK|ENSTIMER) : ENSTIMER);
+         /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
+         SETPORT( SXFRCTL1, can_doparity ? (ENSPCHK|ENSTIMER) : ENSTIMER);
 
-          /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
-          SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
-          SETPORT( SIMODE1, ENSELTIMO );
+         /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
+         SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
+         SETPORT( SIMODE1, ENSELTIMO );
 
-          /* Enable SELECTION OUT sequence */
-          SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
-        
+         /* Enable SELECTION OUT sequence */
+         SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
+       
   #if defined(DEBUG_RACE)
-          leave_driver("(selecting) intr");
+         leave_driver("(selecting) intr");
   #endif
-          SETBITS( DMACNTRL0, INTEN );
-          return;
-        }
+         SETBITS( DMACNTRL0, INTEN );
+         return;
+       }
 
       /* No command we are busy with and no new to issue */
       printk("aha152x: ignoring spurious interrupt, nothing to do\n");
@@ -1402,103 +1403,103 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
   if(current_SC->SCp.phase & in_selection)
     {
       if( TESTLO( SSTAT1, SELTO ) )
-        /* no timeout */
-        if( TESTHI( SSTAT0, SELDO ) )
-          {
-            /* clear BUS FREE interrupt */
-            SETPORT( SSTAT1, CLRBUSFREE);
+       /* no timeout */
+       if( TESTHI( SSTAT0, SELDO ) )
+         {
+           /* clear BUS FREE interrupt */
+           SETPORT( SSTAT1, CLRBUSFREE);
 
-            /* Disable SELECTION OUT sequence */
-            CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
+           /* Disable SELECTION OUT sequence */
+           CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
 
-            /* Disable SELECTION OUT DONE interrupt */
-            CLRBITS(SIMODE0, ENSELDO);
-            CLRBITS(SIMODE1, ENSELTIMO);
+           /* Disable SELECTION OUT DONE interrupt */
+           CLRBITS(SIMODE0, ENSELDO);
+           CLRBITS(SIMODE1, ENSELTIMO);
 
-            if( TESTLO(SSTAT0, SELDO) )
-              {
-                printk("aha152x: passing bus free condition\n");
+           if( TESTLO(SSTAT0, SELDO) )
+             {
+               printk("aha152x: passing bus free condition\n");
 
 #if defined(DEBUG_RACE)
-                leave_driver("(passing bus free) intr");
+               leave_driver("(passing bus free) intr");
 #endif
-                SETBITS( DMACNTRL0, INTEN);
+               SETBITS( DMACNTRL0, INTEN);
 
-                if(current_SC->SCp.phase & aborted)
-                  {
-                    abort_result=SCSI_ABORT_ERROR;
+               if(current_SC->SCp.phase & aborted)
+                 {
+                   abort_result=SCSI_ABORT_ERROR;
                    abortion_complete++;
-                  }
+                 }
 
-                aha152x_done( DID_NO_CONNECT << 16 );
-                return;
-              }
+               aha152x_done( DID_NO_CONNECT << 16 );
+               return;
+             }
 #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
            if(aha152x_debug & (debug_selection|debug_phases))
-              printk("SELDO (SELID=%x), ", GETPORT(SELID));
+             printk("SELDO (SELID=%x), ", GETPORT(SELID));
 #endif
 
-            /* selection was done */
-            SETPORT( SSTAT0, CLRSELDO );
+           /* selection was done */
+           SETPORT( SSTAT0, CLRSELDO );
 
 #if defined(DEBUG_ABORT)
-            if((aha152x_debug & debug_abort) && (current_SC->SCp.phase & aborted))
-              printk("(ABORT) target selected, ");
+           if((aha152x_debug & debug_abort) && (current_SC->SCp.phase & aborted))
+             printk("(ABORT) target selected, ");
 #endif
 
-            current_SC->SCp.phase &= ~in_selection;
-            current_SC->SCp.phase |= in_other;
+           current_SC->SCp.phase &= ~in_selection;
+           current_SC->SCp.phase |= in_other;
 
 #if defined(DEBUG_RACE)
-            leave_driver("(SELDO) intr");
+           leave_driver("(SELDO) intr");
 #endif
 
-            SETPORT( SCSISIG, P_MSGO );
+           SETPORT( SCSISIG, P_MSGO );
 
-            SETPORT( SIMODE0, 0 );
-            SETPORT( SIMODE1, ENREQINIT|ENBUSFREE );
-            SETBITS( DMACNTRL0, INTEN);
-            return;
-          }
-        else
-          aha152x_panic("neither timeout nor selection\007");
+           SETPORT( SIMODE0, 0 );
+           SETPORT( SIMODE1, ENREQINIT|ENBUSFREE );
+           SETBITS( DMACNTRL0, INTEN);
+           return;
+         }
+       else
+         aha152x_panic("neither timeout nor selection\007");
       else
-        {
+       {
 #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
          if(aha152x_debug & (debug_selection|debug_phases))
-          printk("SELTO, ");
+         printk("SELTO, ");
 #endif
          /* end selection attempt */
-          CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
+         CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
 
-          /* timeout */
-          SETPORT( SSTAT1, CLRSELTIMO );
+         /* timeout */
+         SETPORT( SSTAT1, CLRSELTIMO );
 
-          SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
-          SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
-          SETBITS( DMACNTRL0, INTEN );
+         SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+         SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+         SETBITS( DMACNTRL0, INTEN );
 #if defined(DEBUG_RACE)
-          leave_driver("(SELTO) intr");
+         leave_driver("(SELTO) intr");
 #endif
 
-          if(current_SC->SCp.phase & aborted)
-            {
+         if(current_SC->SCp.phase & aborted)
+           {
 #if defined(DEBUG_ABORT)
              if(aha152x_debug & debug_abort)
-                printk("(ABORT) selection timeout, ");
-#endif
-              abort_result=SCSI_ABORT_ERROR;
-              abortion_complete++;
-            }
-
-          if( TESTLO( SSTAT0, SELINGO ) )
-            /* ARBITRATION not won */
-            aha152x_done( DID_BUS_BUSY << 16 );
-          else
-            /* ARBITRATION won, but SELECTION failed */
-            aha152x_done( DID_NO_CONNECT << 16 );
-          return;
-        }
+               printk("(ABORT) selection timeout, ");
+#endif
+             abort_result=SCSI_ABORT_ERROR;
+             abortion_complete++;
+           }
+
+         if( TESTLO( SSTAT0, SELINGO ) )
+           /* ARBITRATION not won */
+           aha152x_done( DID_BUS_BUSY << 16 );
+         else
+           /* ARBITRATION won, but SELECTION failed */
+           aha152x_done( DID_NO_CONNECT << 16 );
+         return;
+       }
     }
 
   /* enable interrupt, when target leaves current phase */
@@ -1514,180 +1515,180 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
     {
     case P_MSGO:                                               /* MESSAGE OUT */
       {
-        unsigned char message;
+       unsigned char message;
 
 #if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
-        if(aha152x_debug & (debug_intr|debug_msgo|debug_phases))
-          printk("MESSAGE OUT, ");
+       if(aha152x_debug & (debug_intr|debug_msgo|debug_phases))
+         printk("MESSAGE OUT, ");
 #endif
 
-        if( current_SC->SCp.phase & aborted )
-          {
+       if( current_SC->SCp.phase & aborted )
+         {
 #if defined(DEBUG_MSGO) || defined(DEBUG_ABORT)
-            if(aha152x_debug & (debug_msgo|debug_abort))
-              printk("ABORT, ");
-#endif
-            message=ABORT;
-          }
-        else
-          /* If we didn't identify yet, do it. Otherwise there's nothing to do,
-             but reject (probably we got an message before, that we have to
-             reject (SDTR, WDTR, etc.) */
-          if( !(current_SC->SCp.phase & sent_ident))
-            {
-              message=IDENTIFY(can_disconnect,current_SC->lun);
+           if(aha152x_debug & (debug_msgo|debug_abort))
+             printk("ABORT, ");
+#endif
+           message=ABORT;
+         }
+       else
+         /* If we didn't identify yet, do it. Otherwise there's nothing to do,
+            but reject (probably we got an message before, that we have to
+            reject (SDTR, WDTR, etc.) */
+         if( !(current_SC->SCp.phase & sent_ident))
+           {
+             message=IDENTIFY(can_disconnect,current_SC->lun);
 #if defined(DEBUG_MSGO)
-              if(aha152x_debug & debug_msgo)
-                printk("IDENTIFY (reconnect=%s;lun=%d), ", 
-                        can_disconnect ? "enabled" : "disabled", current_SC->lun);
-#endif
-            }
-          else
-            {
-              message=MESSAGE_REJECT;
+             if(aha152x_debug & debug_msgo)
+               printk("IDENTIFY (reconnect=%s;lun=%d), ", 
+                       can_disconnect ? "enabled" : "disabled", current_SC->lun);
+#endif
+           }
+         else
+           {
+             message=MESSAGE_REJECT;
 #if defined(DEBUG_MSGO)
-              if(aha152x_debug & debug_msgo)
-                printk("REJECT, ");
+             if(aha152x_debug & debug_msgo)
+               printk("REJECT, ");
 #endif
-            }
-          
-        CLRBITS( SXFRCTL0, ENDMA);
+           }
+         
+       CLRBITS( SXFRCTL0, ENDMA);
 
-        SETPORT( SIMODE0, 0 );
-        SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE );
+       SETPORT( SIMODE0, 0 );
+       SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE );
 
-        /* wait for data latch to become ready or a phase change */
-        while( TESTLO( DMASTAT, INTSTAT ) )
-          ;
+       /* wait for data latch to become ready or a phase change */
+       while( TESTLO( DMASTAT, INTSTAT ) )
+         ;
 
-        if( TESTHI( SSTAT1, PHASEMIS ) )
-          aha152x_panic("unable to send message");
+       if( TESTHI( SSTAT1, PHASEMIS ) )
+         aha152x_panic("unable to send message");
 
-        /* Leave MESSAGE OUT after transfer */
-        SETPORT( SSTAT1, CLRATNO);
+       /* Leave MESSAGE OUT after transfer */
+       SETPORT( SSTAT1, CLRATNO);
 
-        SETPORT( SCSIDAT, message );
+       SETPORT( SCSIDAT, message );
 
-        make_acklow();
-        getphase();
+       make_acklow();
+       getphase();
 
-        if(message==IDENTIFY(can_disconnect,current_SC->lun))
-          current_SC->SCp.phase |= sent_ident;
+       if(message==IDENTIFY(can_disconnect,current_SC->lun))
+         current_SC->SCp.phase |= sent_ident;
 
-        if(message==ABORT)
-          {
-            /* revive abort(); abort() enables interrupts */
-            abort_result=SCSI_ABORT_SUCCESS;
-            abortion_complete++;
+       if(message==ABORT)
+         {
+           /* revive abort(); abort() enables interrupts */
+           abort_result=SCSI_ABORT_SUCCESS;
+           abortion_complete++;
 
-            current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
+           current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
 
-            /* exit */
-            SETBITS( DMACNTRL0, INTEN );
+           /* exit */
+           SETBITS( DMACNTRL0, INTEN );
 #if defined(DEBUG_RACE)
-            leave_driver("(ABORT) intr");
+           leave_driver("(ABORT) intr");
 #endif
-            aha152x_done(DID_ABORT<<16);
-            return;
-          }
+           aha152x_done(DID_ABORT<<16);
+           return;
+         }
       }
       break;
 
     case P_CMD:                                          /* COMMAND phase */
 #if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
       if(aha152x_debug & (debug_intr|debug_cmd|debug_phases))
-        printk("COMMAND, ");
+       printk("COMMAND, ");
 #endif
       if( !(current_SC->SCp.sent_command) )
-        {
-          if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
-            printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n",
-                   GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
-
-          /* reset fifo and enable writes */
-          SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
-          SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
-
-          /* clear transfer count and scsi fifo */
-          SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
-          SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
+       {
+         if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
+           printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n",
+                  GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
+
+         /* reset fifo and enable writes */
+         SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
+         SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
+
+         /* clear transfer count and scsi fifo */
+         SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
+         SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
   
-          /* missing phase raises INTSTAT */
-          SETPORT( SIMODE0, 0 );
-          SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+         /* missing phase raises INTSTAT */
+         SETPORT( SIMODE0, 0 );
+         SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
   
 #if defined(DEBUG_CMD)
-          if(aha152x_debug & debug_cmd)
-            printk("waiting, ");
+         if(aha152x_debug & debug_cmd)
+           printk("waiting, ");
 #endif
-          /* wait for FIFO to get empty */
-          while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
-            ;
+         /* wait for FIFO to get empty */
+         while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
+           ;
   
-          if( TESTHI( SSTAT1, PHASEMIS ) )
-            aha152x_panic("target left COMMAND phase");
+         if( TESTHI( SSTAT1, PHASEMIS ) )
+           aha152x_panic("target left COMMAND phase");
 
 #if defined(DEBUG_CMD)
-          if(aha152x_debug & debug_cmd)
-          {
-            printk("DFIFOEMP, outsw (%d bytes, %d words), ",
+         if(aha152x_debug & debug_cmd)
+         {
+           printk("DFIFOEMP, outsw (%d bytes, %d words), ",
                   current_SC->cmd_len, current_SC->cmd_len >> 1 );
-            disp_ports();
-          }
+           disp_ports();
+         }
 #endif
   
-          outsw( DATAPORT, &current_SC->cmnd, current_SC->cmd_len >> 1 );
+         outsw( DATAPORT, &current_SC->cmnd, current_SC->cmd_len >> 1 );
 
 #if defined(DEBUG_CMD)
          if(aha152x_debug & debug_cmd)
-          {
-            printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
-            disp_ports();
-          }
+         {
+           printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
+           disp_ports();
+         }
 #endif
 
 #if defined(DEBUG_CMD)
          if(aha152x_debug & debug_cmd)
-            printk("waiting for SEMPTY, ");
+           printk("waiting for SEMPTY, ");
 #endif
 
-          /* wait for SCSI FIFO to get empty.
-             very important to send complete commands. */
-          while( TESTLO ( SSTAT2, SEMPTY ) )
-            ;
+         /* wait for SCSI FIFO to get empty.
+            very important to send complete commands. */
+         while( TESTLO ( SSTAT2, SEMPTY ) )
+           ;
 
 #if defined(DEBUG_CMD)
          if(aha152x_debug & debug_cmd)
-            printk("SEMPTY, ");
+           printk("SEMPTY, ");
 #endif
 
-          CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
-          /* transfer can be considered ended, when SCSIEN reads back zero */
-          while( TESTHI( SXFRCTL0, SCSIEN ) )
-            ;
+         CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+         /* transfer can be considered ended, when SCSIEN reads back zero */
+         while( TESTHI( SXFRCTL0, SCSIEN ) )
+           ;
 
 #if defined(DEBUG_CMD)
          if(aha152x_debug & debug_cmd)
-            printk("!SEMPTY, ");
+           printk("!SEMPTY, ");
 #endif
 
-          CLRBITS(DMACNTRL0, ENDMA);
+         CLRBITS(DMACNTRL0, ENDMA);
 
 #if defined(DEBUG_CMD) || defined(DEBUG_INTR)
-          if(debug_cmd & debug_intr)
-            printk("sent %d/%d command bytes, ", GETSTCNT(),
-                   current_SC->cmd_len);
+         if(debug_cmd & debug_intr)
+           printk("sent %d/%d command bytes, ", GETSTCNT(),
+                  current_SC->cmd_len);
 #endif
 
-        }
+       }
       else
-        aha152x_panic("Nothing to sent while in COMMAND OUT");
+       aha152x_panic("Nothing to sent while in COMMAND OUT");
       break;
 
     case P_MSGI:                                          /* MESSAGE IN phase */
 #if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
       if(aha152x_debug & (debug_intr|debug_msgi|debug_phases))
-        printk("MESSAGE IN, ");
+       printk("MESSAGE IN, ");
 #endif
       SETPORT( SXFRCTL0, CH1);
 
@@ -1695,173 +1696,173 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
       SETPORT( SIMODE1, ENBUSFREE);
   
       while( phase == P_MSGI ) 
-        {
-          current_SC->SCp.Message = GETPORT( SCSIBUS );
-          switch(current_SC->SCp.Message)
-            {
-            case DISCONNECT:
+       {
+         current_SC->SCp.Message = GETPORT( SCSIBUS );
+         switch(current_SC->SCp.Message)
+           {
+           case DISCONNECT:
 #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
              if(aha152x_debug & (debug_msgi|debug_phases))
-                printk("target disconnected, ");
-#endif
-              current_SC->SCp.Message = 0;
-              current_SC->SCp.phase   |= disconnected;
-              if(!can_disconnect)
-                aha152x_panic("target was not allowed to disconnect");
-              break;
-        
-            case COMMAND_COMPLETE:
+               printk("target disconnected, ");
+#endif
+             current_SC->SCp.Message = 0;
+             current_SC->SCp.phase   |= disconnected;
+             if(!can_disconnect)
+               aha152x_panic("target was not allowed to disconnect");
+             break;
+       
+           case COMMAND_COMPLETE:
 #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
              if(aha152x_debug & (debug_msgi|debug_phases))
-                printk("inbound message ( COMMAND COMPLETE ), ");
+               printk("inbound message ( COMMAND COMPLETE ), ");
 #endif
-              done++;
-              break;
+             done++;
+             break;
 
-            case MESSAGE_REJECT:
+           case MESSAGE_REJECT:
 #if defined(DEBUG_MSGI)
              if(aha152x_debug & debug_msgi)
-                printk("inbound message ( MESSAGE REJECT ), ");
+               printk("inbound message ( MESSAGE REJECT ), ");
 #endif
-              break;
+             break;
 
-            case SAVE_POINTERS:
+           case SAVE_POINTERS:
 #if defined(DEBUG_MSGI)
              if(aha152x_debug & debug_msgi)
-                printk("inbound message ( SAVE DATA POINTERS ), ");
+               printk("inbound message ( SAVE DATA POINTERS ), ");
 #endif
-              break;
+             break;
 
-            case EXTENDED_MESSAGE:
-              
-                int           i, code;
+           case EXTENDED_MESSAGE:
+             { 
+               int           i, code;
 
 #if defined(DEBUG_MSGI)
-               if(aha152x_debug & debug_msgi)
-                  printk("inbound message ( EXTENDED MESSAGE ), ");
+               if(aha152x_debug & debug_msgi)
+                 printk("inbound message ( EXTENDED MESSAGE ), ");
 #endif
-                make_acklow();
-                if(getphase()!=P_MSGI)
-                  break;
+               make_acklow();
+               if(getphase()!=P_MSGI)
+                 break;
   
-                i=GETPORT(SCSIBUS);
+               i=GETPORT(SCSIBUS);
 
 #if defined(DEBUG_MSGI)
-               if(aha152x_debug & debug_msgi)
-                  printk("length (%d), code ( ", i);
+               if(aha152x_debug & debug_msgi)
+                 printk("length (%d), code ( ", i);
 #endif
 
-                make_acklow();
-                if(getphase()!=P_MSGI)
-                  break;
+               make_acklow();
+               if(getphase()!=P_MSGI)
+                 break;
 
-                code = GETPORT(SCSIBUS);
+               code = GETPORT(SCSIBUS);
 
-                switch( code )
-                  {
-                  case 0x00:
+               switch( code )
+                 {
+                 case 0x00:
 #if defined(DEBUG_MSGI)
-                   if(aha152x_debug & debug_msgi)
-                      printk("MODIFY DATA POINTER ");
+                   if(aha152x_debug & debug_msgi)
+                     printk("MODIFY DATA POINTER ");
 #endif
-                    SETPORT(SCSISIG, P_MSGI|ATNO);
-                    break;
-                  case 0x01:
+                   SETPORT(SCSISIG, P_MSGI|ATNO);
+                   break;
+                 case 0x01:
 #if defined(DEBUG_MSGI)
-                   if(aha152x_debug & debug_msgi)
-                      printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
+                   if(aha152x_debug & debug_msgi)
+                     printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
 #endif
-                    SETPORT(SCSISIG, P_MSGI|ATNO);
-                    break;
-                  case 0x02:
+                   SETPORT(SCSISIG, P_MSGI|ATNO);
+                   break;
+                 case 0x02:
 #if defined(DEBUG_MSGI)
-                   if(aha152x_debug & debug_msgi)
-                      printk("EXTENDED IDENTIFY ");
+                   if(aha152x_debug & debug_msgi)
+                     printk("EXTENDED IDENTIFY ");
 #endif
-                    break;
-                  case 0x03:
+                   break;
+                 case 0x03:
 #if defined(DEBUG_MSGI)
-                   if(aha152x_debug & debug_msgi)
-                      printk("WIDE DATA TRANSFER REQUEST ");
+                   if(aha152x_debug & debug_msgi)
+                     printk("WIDE DATA TRANSFER REQUEST ");
 #endif
-                    SETPORT(SCSISIG, P_MSGI|ATNO);
-                    break;
-                  default:
+                   SETPORT(SCSISIG, P_MSGI|ATNO);
+                   break;
+                 default:
 #if defined(DEBUG_MSGI)
-                   if(aha152x_debug & debug_msgi)
-                      if( code & 0x80 )
-                        printk("reserved (%d) ", code );
-                      else
-                        printk("vendor specific (%d) ", code);
-#endif
-                    SETPORT(SCSISIG, P_MSGI|ATNO);
-                    break;
-                  }
+                   if(aha152x_debug & debug_msgi)
+                     if( code & 0x80 )
+                       printk("reserved (%d) ", code );
+                     else
+                       printk("vendor specific (%d) ", code);
+#endif
+                   SETPORT(SCSISIG, P_MSGI|ATNO);
+                   break;
+                 }
 #if defined(DEBUG_MSGI)
-               if(aha152x_debug & debug_msgi)
-                  printk(" ), data ( ");
+               if(aha152x_debug & debug_msgi)
+                 printk(" ), data ( ");
 #endif
-                while( --i && (make_acklow(), getphase()==P_MSGI))
-                  {
+               while( --i && (make_acklow(), getphase()==P_MSGI))
+                 {
 #if defined(DEBUG_MSGI)
-                   if(aha152x_debug & debug_msgi)
-                      printk("%x ", GETPORT(SCSIBUS) );
+                   if(aha152x_debug & debug_msgi)
+                     printk("%x ", GETPORT(SCSIBUS) );
 #else
-                    GETPORT(SCSIBUS);
+                   GETPORT(SCSIBUS);
 #endif
-                  }
+                 }
 #if defined(DEBUG_MSGI)
-               if(aha152x_debug & debug_msgi)
-                  printk(" ), ");
-#endif
-                /* We reject all extended messages. To do this
-                   we just enter MSGO by asserting ATN. Since
-                   we have already identified a REJECT message
-                   will be sent. */
-                SETPORT(SCSISIG, P_MSGI|ATNO);
-              }
-              break;
+               if(aha152x_debug & debug_msgi)
+                 printk(" ), ");
+#endif
+               /* We reject all extended messages. To do this
+                  we just enter MSGO by asserting ATN. Since
+                  we have already identified a REJECT message
+                  will be sent. */
+               SETPORT(SCSISIG, P_MSGI|ATNO);
+             }
+             break;
        
-            default:
-              printk("unsupported inbound message %x, ", current_SC->SCp.Message);
-              break;
+           default:
+             printk("unsupported inbound message %x, ", current_SC->SCp.Message);
+             break;
 
-            }
+           }
 
-          make_acklow();
-          phase=getphase();
-        
+         make_acklow();
+         phase=getphase();
+       } 
 
       /* clear SCSI fifo on BUSFREE */
       if(phase==P_BUSFREE)
-        SETPORT(SXFRCTL0, CH1|CLRCH1);
+       SETPORT(SXFRCTL0, CH1|CLRCH1);
 
       if(current_SC->SCp.phase & disconnected)
-        {
-          save_flags(flags);
-          cli();
+       {
+         save_flags(flags);
+         cli();
 #if defined(DEBUG_QUEUES)
          if(aha152x_debug & debug_queues)
-            printk("d+, ");
+           printk("d+, ");
 #endif
-          append_SC( &disconnected_SC, current_SC);
-          current_SC = NULL;
-          restore_flags(flags);
+         append_SC( &disconnected_SC, current_SC);
+         current_SC = NULL;
+         restore_flags(flags);
 
-          SETBITS( SCSISEQ, ENRESELI );
+         SETBITS( SCSISEQ, ENRESELI );
 
-          SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
-          SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+         SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+         SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
 
-          SETBITS( DMACNTRL0, INTEN );
-          return;
-        }
+         SETBITS( DMACNTRL0, INTEN );
+         return;
+       }
       break;
 
     case P_STATUS:                                         /* STATUS IN phase */
 #if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
       if(aha152x_debug & (debug_status|debug_intr|debug_phases))
-        printk("STATUS, ");
+       printk("STATUS, ");
 #endif
       SETPORT( SXFRCTL0, CH1);
 
@@ -1878,318 +1879,318 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
 #if defined(DEBUG_STATUS)
       if(aha152x_debug & debug_status)
       {
-        printk("inbound status ");
-        print_status( current_SC->SCp.Status );
-        printk(", ");
+       printk("inbound status ");
+       print_status( current_SC->SCp.Status );
+       printk(", ");
       }
 #endif
       break;
 
     case P_DATAI:                                            /* DATA IN phase */
       {
-        int fifodata, data_count, done;
+       int fifodata, data_count, done;
 
 #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-        if(aha152x_debug & (debug_datai|debug_intr|debug_phases))
-          printk("DATA IN, ");
+       if(aha152x_debug & (debug_datai|debug_intr|debug_phases))
+         printk("DATA IN, ");
 #endif
 
-        if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
-          printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
-                 GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
+       if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
+         printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
+                GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
 
-        /* reset host fifo */
-        SETPORT(DMACNTRL0, RSTFIFO);
-        SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
+       /* reset host fifo */
+       SETPORT(DMACNTRL0, RSTFIFO);
+       SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
 
-        SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN );
+       SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN );
 
-        SETPORT( SIMODE0, 0 );
-        SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+       SETPORT( SIMODE0, 0 );
+       SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
 
-        /* done is set when the FIFO is empty after the target left DATA IN */
-        done=0;
+       /* done is set when the FIFO is empty after the target left DATA IN */
+       done=0;
       
-        /* while the target stays in DATA to transfer data */
-        while ( !done ) 
-          {
+       /* while the target stays in DATA to transfer data */
+       while ( !done ) 
+         {
 #if defined(DEBUG_DATAI)
-            if(aha152x_debug & debug_datai)
-              printk("expecting data, ");
-#endif
-            /* wait for PHASEMIS or full FIFO */
-            while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) )
-              ;
-
-            if( TESTHI( DMASTAT, DFIFOFULL ) )
-              fifodata=GETPORT(FIFOSTAT);
-            else
-              {
-                /* wait for SCSI fifo to get empty */
-                while( TESTLO( SSTAT2, SEMPTY ) )
-                  ;
-
-                /* rest of data in FIFO */
-                fifodata=GETPORT(FIFOSTAT);
+           if(aha152x_debug & debug_datai)
+             printk("expecting data, ");
+#endif
+           /* wait for PHASEMIS or full FIFO */
+           while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) )
+             ;
+
+           if( TESTHI( DMASTAT, DFIFOFULL ) )
+             fifodata=GETPORT(FIFOSTAT);
+           else
+             {
+               /* wait for SCSI fifo to get empty */
+               while( TESTLO( SSTAT2, SEMPTY ) )
+                 ;
+
+               /* rest of data in FIFO */
+               fifodata=GETPORT(FIFOSTAT);
 #if defined(DEBUG_DATAI)
-                if(aha152x_debug & debug_datai)
-                  printk("last transfer, ");
+               if(aha152x_debug & debug_datai)
+                 printk("last transfer, ");
 #endif
-                done=1;
-              }
+               done=1;
+             }
   
 #if defined(DEBUG_DATAI)
-            if(aha152x_debug & debug_datai)
-              printk("fifodata=%d, ", fifodata);
+           if(aha152x_debug & debug_datai)
+             printk("fifodata=%d, ", fifodata);
 #endif
 
-            while( fifodata && current_SC->SCp.this_residual )
-              {
-                data_count=fifodata;
+           while( fifodata && current_SC->SCp.this_residual )
+             {
+               data_count=fifodata;
   
-                /* limit data transfer to size of first sg buffer */
-                if (data_count > current_SC->SCp.this_residual)
-                  data_count = current_SC->SCp.this_residual;
+               /* limit data transfer to size of first sg buffer */
+               if (data_count > current_SC->SCp.this_residual)
+                 data_count = current_SC->SCp.this_residual;
   
-                fifodata -= data_count;
+               fifodata -= data_count;
 
 #if defined(DEBUG_DATAI)
-                if(aha152x_debug & debug_datai)
-                  printk("data_count=%d, ", data_count);
+               if(aha152x_debug & debug_datai)
+                 printk("data_count=%d, ", data_count);
 #endif
   
-                if(data_count&1)
-                  {
-                    /* get a single byte in byte mode */
-                    SETBITS(DMACNTRL0, _8BIT );
-                    *current_SC->SCp.ptr++ = GETPORT( DATAPORT );
-                    current_SC->SCp.this_residual--;
-                  }
-                if(data_count>1)
-                  {
-                    CLRBITS(DMACNTRL0, _8BIT );
-                    data_count >>= 1; /* Number of words */
-                    insw( DATAPORT, current_SC->SCp.ptr, data_count );
+               if(data_count&1)
+                 {
+                   /* get a single byte in byte mode */
+                   SETBITS(DMACNTRL0, _8BIT );
+                   *current_SC->SCp.ptr++ = GETPORT( DATAPORT );
+                   current_SC->SCp.this_residual--;
+                 }
+               if(data_count>1)
+                 {
+                   CLRBITS(DMACNTRL0, _8BIT );
+                   data_count >>= 1; /* Number of words */
+                   insw( DATAPORT, current_SC->SCp.ptr, data_count );
 #if defined(DEBUG_DATAI)
-                    if(aha152x_debug & debug_datai)
+                   if(aha152x_debug & debug_datai)
 /* show what comes with the last transfer */
-                      if(done)
-                        {
-                          int           i;
-                          unsigned char *data;
+                     if(done)
+                       {
+                         int           i;
+                         unsigned char *data;
   
-                          printk("data on last transfer (%d bytes: ",
-                                 2*data_count);
-                          data = (unsigned char *) current_SC->SCp.ptr;
-                          for( i=0; i<2*data_count; i++)
-                            printk("%2x ", *data++);
-                          printk("), ");
-                        }
-#endif
-                    current_SC->SCp.ptr           += 2 * data_count;
-                    current_SC->SCp.this_residual -= 2 * data_count;
-                  }
-              
-                /* if this buffer is full and there are more buffers left */
-                if (!current_SC->SCp.this_residual &&
-                     current_SC->SCp.buffers_residual)
-                  {
-                    /* advance to next buffer */
-                    current_SC->SCp.buffers_residual--;
-                    current_SC->SCp.buffer++;
-                    current_SC->SCp.ptr =
-                      current_SC->SCp.buffer->address;
-                    current_SC->SCp.this_residual =
-                      current_SC->SCp.buffer->length;
-                  
-              }
+                         printk("data on last transfer (%d bytes: ",
+                                2*data_count);
+                         data = (unsigned char *) current_SC->SCp.ptr;
+                         for( i=0; i<2*data_count; i++)
+                           printk("%2x ", *data++);
+                         printk("), ");
+                       }
+#endif
+                   current_SC->SCp.ptr           += 2 * data_count;
+                   current_SC->SCp.this_residual -= 2 * data_count;
+                 }
+             
+               /* if this buffer is full and there are more buffers left */
+               if (!current_SC->SCp.this_residual &&
+                    current_SC->SCp.buffers_residual)
+                 {
+                   /* advance to next buffer */
+                   current_SC->SCp.buffers_residual--;
+                   current_SC->SCp.buffer++;
+                   current_SC->SCp.ptr =
+                     current_SC->SCp.buffer->address;
+                   current_SC->SCp.this_residual =
+                     current_SC->SCp.buffer->length;
+                 } 
+             }
  
-            /*
-             * Fifo should be empty
-             */
-            if(fifodata>0)
-              {
-                printk("aha152x: more data than expected (%d bytes)\n",
-                       GETPORT(FIFOSTAT));
-                SETBITS(DMACNTRL0, _8BIT );
-                printk("aha152x: data ( ");
-                while(fifodata--)
-                  printk("%2x ", GETPORT( DATAPORT ));
-                printk(")\n");
-              }
+           /*
+            * Fifo should be empty
+            */
+           if(fifodata>0)
+             {
+               printk("aha152x: more data than expected (%d bytes)\n",
+                      GETPORT(FIFOSTAT));
+               SETBITS(DMACNTRL0, _8BIT );
+               printk("aha152x: data ( ");
+               while(fifodata--)
+                 printk("%2x ", GETPORT( DATAPORT ));
+               printk(")\n");
+             }
 
 #if defined(DEBUG_DATAI)
-            if(aha152x_debug & debug_datai)
-              if(!fifodata)
-                printk("fifo empty, ");
-              else
-                printk("something left in fifo, ");
+           if(aha152x_debug & debug_datai)
+             if(!fifodata)
+               printk("fifo empty, ");
+             else
+               printk("something left in fifo, ");
 #endif
-          }
+         }
 
 #if defined(DEBUG_DATAI)
-        if((aha152x_debug & debug_datai) && (current_SC->SCp.buffers_residual || current_SC->SCp.this_residual))
-          printk("left buffers (buffers=%d, bytes=%d), ",
-                 current_SC->SCp.buffers_residual, 
-                 current_SC->SCp.this_residual);
+       if((aha152x_debug & debug_datai) && (current_SC->SCp.buffers_residual || current_SC->SCp.this_residual))
+         printk("left buffers (buffers=%d, bytes=%d), ",
+                current_SC->SCp.buffers_residual, 
+                current_SC->SCp.this_residual);
 #endif
-        /* transfer can be considered ended, when SCSIEN reads back zero */
-        CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
-        while( TESTHI( SXFRCTL0, SCSIEN ) )
-          ;
-        CLRBITS(DMACNTRL0, ENDMA );
+       /* transfer can be considered ended, when SCSIEN reads back zero */
+       CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+       while( TESTHI( SXFRCTL0, SCSIEN ) )
+         ;
+       CLRBITS(DMACNTRL0, ENDMA );
 
 #if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
-        if(aha152x_debug & (debug_datai|debug_intr))
-          printk("got %d bytes, ", GETSTCNT());
+       if(aha152x_debug & (debug_datai|debug_intr))
+         printk("got %d bytes, ", GETSTCNT());
 #endif
 
-        current_SC->SCp.have_data_in++;
+       current_SC->SCp.have_data_in++;
       }
       break;
 
     case P_DATAO:                                           /* DATA OUT phase */
       {
-        int data_count;
+       int data_count;
 
 #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-        if(aha152x_debug & (debug_datao|debug_intr|debug_phases))
-          printk("DATA OUT, ");
+       if(aha152x_debug & (debug_datao|debug_intr|debug_phases))
+         printk("DATA OUT, ");
 #endif
 #if defined(DEBUG_DATAO)
-        if(aha152x_debug & debug_datao)
-          printk("got data to send (bytes=%d, buffers=%d), ",
-                 current_SC->SCp.this_residual,
-                 current_SC->SCp.buffers_residual );
+       if(aha152x_debug & debug_datao)
+         printk("got data to send (bytes=%d, buffers=%d), ",
+                current_SC->SCp.this_residual,
+                current_SC->SCp.buffers_residual );
 #endif
 
-        if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) )
-          {
-            printk("%d(%d) left in FIFO, ", GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT) );
-            aha152x_panic("FIFO should be empty");
-          }
+       if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) )
+         {
+           printk("%d(%d) left in FIFO, ", GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT) );
+           aha152x_panic("FIFO should be empty");
+         }
 
-        SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
-        SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
+       SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
+       SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
 
-        SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
-        SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
+       SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
+       SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
  
-        SETPORT( SIMODE0, 0 );
-        SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
-
-        /* while current buffer is not empty or
-           there are more buffers to transfer */
-        while( TESTLO( SSTAT1, PHASEMIS ) &&
-                 (current_SC->SCp.this_residual ||
-                  current_SC->SCp.buffers_residual) )
-          {
+       SETPORT( SIMODE0, 0 );
+       SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+
+       /* while current buffer is not empty or
+          there are more buffers to transfer */
+       while( TESTLO( SSTAT1, PHASEMIS ) &&
+                (current_SC->SCp.this_residual ||
+                 current_SC->SCp.buffers_residual) )
+         {
 #if defined(DEBUG_DATAO)
-            if(aha152x_debug & debug_datao)
-              printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
-                     current_SC->SCp.this_residual,
-                     current_SC->SCp.buffers_residual);
+           if(aha152x_debug & debug_datao)
+             printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
+                    current_SC->SCp.this_residual,
+                    current_SC->SCp.buffers_residual);
 #endif
-            /* transfer rest of buffer, but max. 128 byte */
-            data_count = current_SC->SCp.this_residual > 128 ?
-                         128 : current_SC->SCp.this_residual ;
+           /* transfer rest of buffer, but max. 128 byte */
+           data_count = current_SC->SCp.this_residual > 128 ?
+                        128 : current_SC->SCp.this_residual ;
 
 #if defined(DEBUG_DATAO)
-            if(aha152x_debug & debug_datao)
-              printk("data_count=%d, ", data_count);
+           if(aha152x_debug & debug_datao)
+             printk("data_count=%d, ", data_count);
 #endif
   
-            if(data_count&1)
-              {
-                /* put a single byte in byte mode */
-                SETBITS(DMACNTRL0, _8BIT );
-                SETPORT(DATAPORT, *current_SC->SCp.ptr++);
-                current_SC->SCp.this_residual--;
-              }
-            if(data_count>1)
-              {
-                CLRBITS(DMACNTRL0, _8BIT );
-                data_count >>= 1; /* Number of words */
-                outsw( DATAPORT, current_SC->SCp.ptr, data_count );
-                current_SC->SCp.ptr           += 2 * data_count;
-                current_SC->SCp.this_residual -= 2 * data_count;
-              }
-
-            /* wait for FIFO to get empty */
-            while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
-              ;
+           if(data_count&1)
+             {
+               /* put a single byte in byte mode */
+               SETBITS(DMACNTRL0, _8BIT );
+               SETPORT(DATAPORT, *current_SC->SCp.ptr++);
+               current_SC->SCp.this_residual--;
+             }
+           if(data_count>1)
+             {
+               CLRBITS(DMACNTRL0, _8BIT );
+               data_count >>= 1; /* Number of words */
+               outsw( DATAPORT, current_SC->SCp.ptr, data_count );
+               current_SC->SCp.ptr           += 2 * data_count;
+               current_SC->SCp.this_residual -= 2 * data_count;
+             }
+
+           /* wait for FIFO to get empty */
+           while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
+             ;
 
 #if defined(DEBUG_DATAO)
-            if(aha152x_debug & debug_datao)
-              printk("fifo (%d bytes), transfered (%d bytes), ",
-                     GETPORT(FIFOSTAT), GETSTCNT() );
-#endif
-
-            /* if this buffer is empty and there are more buffers left */
-            if ( TESTLO( SSTAT1, PHASEMIS ) &&
-                 !current_SC->SCp.this_residual &&
-                  current_SC->SCp.buffers_residual)
-              {
-                 /* advance to next buffer */
-                 current_SC->SCp.buffers_residual--;
-                 current_SC->SCp.buffer++;
-                 current_SC->SCp.ptr =
-                   current_SC->SCp.buffer->address;
-                 current_SC->SCp.this_residual =
-                 current_SC->SCp.buffer->length;
-              }
-          }
-
-        if ( current_SC->SCp.this_residual ||
-             current_SC->SCp.buffers_residual )
-          {
-            /* target leaves DATA OUT for an other phase
-               (perhaps disconnect) */
-
-            /* data in fifos has to be resend */
-            data_count = GETPORT(SSTAT2) & (SFULL|SFCNT);
-
-            data_count += GETPORT(FIFOSTAT) ;
-            current_SC->SCp.ptr           -= data_count;
-            current_SC->SCp.this_residual += data_count;
+           if(aha152x_debug & debug_datao)
+             printk("fifo (%d bytes), transfered (%d bytes), ",
+                    GETPORT(FIFOSTAT), GETSTCNT() );
+#endif
+
+           /* if this buffer is empty and there are more buffers left */
+           if ( TESTLO( SSTAT1, PHASEMIS ) &&
+                !current_SC->SCp.this_residual &&
+                 current_SC->SCp.buffers_residual)
+             {
+                /* advance to next buffer */
+                current_SC->SCp.buffers_residual--;
+                current_SC->SCp.buffer++;
+                current_SC->SCp.ptr =
+                  current_SC->SCp.buffer->address;
+                current_SC->SCp.this_residual =
+                current_SC->SCp.buffer->length;
+             }
+         }
+
+       if ( current_SC->SCp.this_residual ||
+            current_SC->SCp.buffers_residual )
+         {
+           /* target leaves DATA OUT for an other phase
+              (perhaps disconnect) */
+
+           /* data in fifos has to be resend */
+           data_count = GETPORT(SSTAT2) & (SFULL|SFCNT);
+
+           data_count += GETPORT(FIFOSTAT) ;
+           current_SC->SCp.ptr           -= data_count;
+           current_SC->SCp.this_residual += data_count;
 #if defined(DEBUG_DATAO)
-            if(aha152x_debug & debug_datao)
-              printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
-                     current_SC->SCp.this_residual,
-                     current_SC->SCp.buffers_residual,
-                     data_count );
-#endif
-            SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
-            CLRBITS(SXFRCTL0, SCSIEN|DMAEN );
-            CLRBITS(DMACNTRL0, ENDMA);
-          }
-        else
-          {
+           if(aha152x_debug & debug_datao)
+             printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
+                    current_SC->SCp.this_residual,
+                    current_SC->SCp.buffers_residual,
+                    data_count );
+#endif
+           SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
+           CLRBITS(SXFRCTL0, SCSIEN|DMAEN );
+           CLRBITS(DMACNTRL0, ENDMA);
+         }
+       else
+         {
 #if defined(DEBUG_DATAO)
-            if(aha152x_debug & debug_datao)
-              printk("waiting for SCSI fifo to get empty, ");
+           if(aha152x_debug & debug_datao)
+             printk("waiting for SCSI fifo to get empty, ");
 #endif
-            /* wait for SCSI fifo to get empty */
-            while( TESTLO( SSTAT2, SEMPTY ) )
-              ;
+           /* wait for SCSI fifo to get empty */
+           while( TESTLO( SSTAT2, SEMPTY ) )
+             ;
 #if defined(DEBUG_DATAO)
-            if(aha152x_debug & debug_datao)
-              printk("ok, left data (bytes=%d, buffers=%d) ",
-                     current_SC->SCp.this_residual,
-                     current_SC->SCp.buffers_residual);
+           if(aha152x_debug & debug_datao)
+             printk("ok, left data (bytes=%d, buffers=%d) ",
+                    current_SC->SCp.this_residual,
+                    current_SC->SCp.buffers_residual);
 #endif
-            CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+           CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
 
-            /* transfer can be considered ended, when SCSIEN reads back zero */
-            while( TESTHI( SXFRCTL0, SCSIEN ) )
-              ;
+           /* transfer can be considered ended, when SCSIEN reads back zero */
+           while( TESTHI( SXFRCTL0, SCSIEN ) )
+             ;
 
-            CLRBITS(DMACNTRL0, ENDMA);
-          }
+           CLRBITS(DMACNTRL0, ENDMA);
+         }
 
 #if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
-        if(aha152x_debug & (debug_datao|debug_intr))
-          printk("sent %d data bytes, ", GETSTCNT() );
+       if(aha152x_debug & (debug_datao|debug_intr))
+         printk("sent %d data bytes, ", GETSTCNT() );
 #endif
       }
       break;
@@ -2200,7 +2201,7 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
 #endif
 #if defined(DEBUG_PHASES)
       if(aha152x_debug & debug_phases)
-        printk("unexpected BUS FREE, ");
+       printk("unexpected BUS FREE, ");
 #endif
       current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
 
@@ -2230,7 +2231,7 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
     {
 #if defined(DEBUG_INTR)
       if(aha152x_debug & debug_intr)
-        printk("command done.\n");
+       printk("command done.\n");
 #endif
 #if defined(DEBUG_RACE)
       leave_driver("(done) intr");
@@ -2243,12 +2244,12 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
       SETBITS( DMACNTRL0, INTEN );
 
       aha152x_done(   (current_SC->SCp.Status  & 0xff)
-                    | ( (current_SC->SCp.Message & 0xff) << 8)
-                    | ( DID_OK << 16) );
+                   | ( (current_SC->SCp.Message & 0xff) << 8)
+                   | ( DID_OK << 16) );
 
 #if defined(DEBUG_RACE)
       printk("done returned (DID_OK: Status=%x; Message=%x).\n",
-             current_SC->SCp.Status, current_SC->SCp.Message);
+            current_SC->SCp.Status, current_SC->SCp.Message);
 #endif
       return;
     }
@@ -2544,12 +2545,12 @@ static void leave_driver(const char *func)
 static void show_command(Scsi_Cmnd *ptr)
 {
   printk("0x%08x: target=%d; lun=%d; cmnd=( ",
-         (unsigned int) ptr, ptr->target, ptr->lun);
+        (unsigned int) ptr, ptr->target, ptr->lun);
   
   print_command(ptr->cmnd);
 
   printk("); residual=%d; buffers=%d; phase |",
-         ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+        ptr->SCp.this_residual, ptr->SCp.buffers_residual);
 
   if( ptr->SCp.phase & not_issued   )  printk("not issued|");
   if( ptr->SCp.phase & in_selection )  printk("in selection|");
@@ -2560,32 +2561,32 @@ static void show_command(Scsi_Cmnd *ptr)
     { 
       printk("; in other(");
       switch( (ptr->SCp.phase >> 16) & P_MASK )
-        {
-        case P_DATAO:
-          printk("DATA OUT");
-          break;
-        case P_DATAI:
-          printk("DATA IN");
-          break;
-        case P_CMD:
-          printk("COMMAND");
-          break;
-        case P_STATUS:
-          printk("STATUS");
-          break;
-        case P_MSGO:
-          printk("MESSAGE OUT");
-          break;
-        case P_MSGI:
-          printk("MESSAGE IN");
-          break;
-        default: 
-          printk("*illegal*");
-          break;
-        }
+       {
+       case P_DATAO:
+         printk("DATA OUT");
+         break;
+       case P_DATAI:
+         printk("DATA IN");
+         break;
+       case P_CMD:
+         printk("COMMAND");
+         break;
+       case P_STATUS:
+         printk("STATUS");
+         break;
+       case P_MSGO:
+         printk("MESSAGE OUT");
+         break;
+       case P_MSGI:
+         printk("MESSAGE IN");
+         break;
+       default: 
+         printk("*illegal*");
+         break;
+       }
       printk(")");
       if(ptr->SCp.phase & (1<<16))
-        printk("; phaseend");
+       printk("; phaseend");
     }
   printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
 }
@@ -2618,3 +2619,10 @@ static void show_queues(void)
   disp_enintr();
   restore_flags(flags);
 }
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = AHA152X;
+
+#include "scsi_module.c"
+#endif
index 7b7a81b729c29dcfa77e28d246ba41c7929425f9..e876f3e1e9f3217fc470e6f22f83e413cd8a2349 100644 (file)
@@ -18,6 +18,8 @@ int        aha152x_abort(Scsi_Cmnd *);
 int        aha152x_reset(Scsi_Cmnd *);
 int        aha152x_biosparam(Disk *, int, int*);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 /* number of queueable commands
    (unless we support more than 1 cmd_per_lun this should do) */
 #define AHA152X_MAXQUEUE       7               
@@ -27,22 +29,25 @@ int        aha152x_biosparam(Disk *, int, int*);
 /* Initial value of Scsi_Host entry */
 #define AHA152X       { /* next */             NULL,                       \
                        /* usage_count */       NULL,                       \
+                                               generic_proc_info,          \
+                                               "aha152x",                  \
+                                               PROC_SCSI_AHA152X,          \
                        /* name */              AHA152X_REVID,              \
                        /* detect */            aha152x_detect,             \
                        /* release */           NULL,                       \
-                       /* info */              NULL,                       \
+                       /* info */              NULL,                       \
                        /* command */           aha152x_command,            \
                        /* queuecommand */      aha152x_queue,              \
-                        /* abort */            aha152x_abort,              \
-                        /* reset */            aha152x_reset,              \
-                        /* slave_attach */     /* NULL */  0,              \
-                        /* bios_param */       aha152x_biosparam,          \
+                       /* abort */             aha152x_abort,              \
+                       /* reset */             aha152x_reset,              \
+                       /* slave_attach */      /* NULL */  0,              \
+                       /* bios_param */        aha152x_biosparam,          \
                        /* can_queue */         1,                          \
-                        /* this_id */          7,                          \
-                        /* sg_tablesize */     SG_ALL,                     \
-                        /* cmd_per_lun */      1,                          \
-                        /* present */          0,                          \
-                        /* unchecked_isa_dma */        0,                          \
+                       /* this_id */           7,                          \
+                       /* sg_tablesize */      SG_ALL,                     \
+                       /* cmd_per_lun */       1,                          \
+                       /* present */           0,                          \
+                       /* unchecked_isa_dma */ 0,                          \
                        /* use_clustering */    DISABLE_CLUSTERING }
 #endif
 
@@ -150,12 +155,12 @@ int        aha152x_biosparam(Disk *, int, int*);
 
 /* SCSI transfer count */
 #define GETSTCNT()   ( (GETPORT(STCNT2)<<16) \
-                     + (GETPORT(STCNT1)<< 8) \
-                     + GETPORT(STCNT0) )
+                    + (GETPORT(STCNT1)<< 8) \
+                    + GETPORT(STCNT0) )
 
 #define SETSTCNT(X)  { SETPORT(STCNT2, ((X) & 0xFF0000) >> 16); \
-                       SETPORT(STCNT1, ((X) & 0x00FF00) >>  8); \
-                       SETPORT(STCNT0, ((X) & 0x0000FF) ); }
+                      SETPORT(STCNT1, ((X) & 0x00FF00) >>  8); \
+                      SETPORT(STCNT0, ((X) & 0x0000FF) ); }
 
 /* SCSI interrupt status */
 #define        TARGET          0x80
@@ -339,22 +344,22 @@ typedef union {
 
 #ifdef DEBUG_AHA152X
 enum {
-        debug_skipports =0x0001,
-        debug_queue     =0x0002,
-        debug_intr      =0x0004,
-        debug_selection =0x0008,
-        debug_msgo      =0x0010,
-        debug_msgi      =0x0020,
-        debug_status    =0x0040,
-        debug_cmd       =0x0080,
-        debug_datai     =0x0100,
-        debug_datao     =0x0200,
-        debug_abort     =0x0400,
-        debug_done      =0x0800,
-        debug_biosparam =0x1000,
-        debug_phases    =0x2000,
-        debug_queues    =0x4000,
-        debug_reset     =0x8000,
+       debug_skipports =0x0001,
+       debug_queue     =0x0002,
+       debug_intr      =0x0004,
+       debug_selection =0x0008,
+       debug_msgo      =0x0010,
+       debug_msgi      =0x0020,
+       debug_status    =0x0040,
+       debug_cmd       =0x0080,
+       debug_datai     =0x0100,
+       debug_datao     =0x0200,
+       debug_abort     =0x0400,
+       debug_done      =0x0800,
+       debug_biosparam =0x1000,
+       debug_phases    =0x2000,
+       debug_queues    =0x4000,
+       debug_reset     =0x8000,
 };
 #endif
 
index 0d8c73c406b03311e9ea70f61fdc34480aab0c27..2dae34a7e9eeff58a7528b8d6e3cfbd8a0ef00ba 100644 (file)
 #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/dma.h>
-
 #include <asm/system.h>
 #include <asm/io.h>
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
 
+
 #include "aha1542.h"
 
 #ifdef DEBUG
@@ -94,7 +93,7 @@ static char *setup_str[MAXBOARDS] = {(char *)NULL,(char *)NULL};
 
 struct aha1542_hostdata{
        /* This will effectively start both of them at the first mailbox */
-        int bios_translation;   /* Mapping bios uses - for compatibility */
+       int bios_translation;   /* Mapping bios uses - for compatibility */
        int aha1542_last_mbi_used;
        int aha1542_last_mbo_used;
        Scsi_Cmnd * SCint[AHA1542_MAILBOXES];
@@ -889,7 +888,7 @@ void aha1542_setup( char *str, int *ints)
        case 6:
            atbt = 0x04;
            break;
-        case 7:
+       case 7:
            atbt = 0x01;
            break;
        case 8:
index 005a1f1e8814e4cfe35a502079955cd3b623374f..f03cbbfa71261126bf56e1e0fb39c711dd29e93a 100644 (file)
@@ -136,6 +136,8 @@ int aha1542_abort(Scsi_Cmnd *);
 int aha1542_reset(Scsi_Cmnd *);
 int aha1542_biosparam(Disk *, int, int*);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 #define AHA1542_MAILBOXES 8
 #define AHA1542_SCATTER 16
 #define AHA1542_CMDLUN 1
@@ -145,6 +147,9 @@ int aha1542_biosparam(Disk *, int, int*);
 #endif
 
 #define AHA1542 {  NULL, NULL,                         \
+                    generic_proc_info,                 \
+                    "aha1542",                         \
+                    PROC_SCSI_AHA1542,                 \
                     "Adaptec 1542",                    \
                     aha1542_detect,                    \
                     NULL,                              \
@@ -153,7 +158,7 @@ int aha1542_biosparam(Disk *, int, int*);
                     aha1542_queuecommand,              \
                     aha1542_abort,                     \
                     aha1542_reset,                     \
-                    NULL,                              \
+                    NULL,                              \
                     aha1542_biosparam,                 \
                     AHA1542_MAILBOXES,                 \
                     7,                                 \
index 557cb22920b7cda3ea26f692b6748835707d2e80..462635e868897e320cd44e55d2e626624389cab3 100644 (file)
  * if it doesn't work for your devices, take a look.
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 #include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
-
+#include <linux/proc_fs.h>
 #include <linux/sched.h>
 #include <asm/dma.h>
 
@@ -123,7 +127,7 @@ sense[0],sense[1],sense[2],sense[3]);
                retval = DID_ERROR; /* Didn't find a better error */
            }
            /* In any other case return DID_OK so for example
-               CONDITION_CHECKS make it through to the appropriate
+              CONDITION_CHECKS make it through to the appropriate
               device driver */
        }
     }
@@ -181,7 +185,7 @@ void aha1740_intr_handle(int irq, struct pt_regs * regs)
        ecbptr = (struct ecb *) bus_to_virt(inl(MBOXIN0));
        outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */
       
-        switch ( adapstat & G2INTST_MASK )
+       switch ( adapstat & G2INTST_MASK )
        {
        case    G2INTST_CCBRETRY:
        case    G2INTST_CCBERROR:
@@ -253,22 +257,22 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     
     if(*cmd == REQUEST_SENSE)
     {
-        if (bufflen != sizeof(SCpnt->sense_buffer))
+       if (bufflen != sizeof(SCpnt->sense_buffer))
        {
            printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
-        }
-        SCpnt->result = 0;
-        done(SCpnt); 
-        return 0;
+       }
+       SCpnt->result = 0;
+       done(SCpnt); 
+       return 0;
     }
 
 #ifdef DEBUG
     if (*cmd == READ_10 || *cmd == WRITE_10)
-        i = xscsi2int(cmd+2);
+       i = xscsi2int(cmd+2);
     else if (*cmd == READ_6 || *cmd == WRITE_6)
-        i = scsi2int(cmd+2);
+       i = scsi2int(cmd+2);
     else
-        i = -1;
+       i = -1;
     printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
     printk("scsi cmd:");
     for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
@@ -313,35 +317,35 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 
     if (SCpnt->use_sg)
     {
-        struct scatterlist * sgpnt;
-        struct aha1740_chain * cptr;
-        int i;
+       struct scatterlist * sgpnt;
+       struct aha1740_chain * cptr;
+       int i;
 #ifdef DEBUG
-        unsigned char * ptr;
+       unsigned char * ptr;
 #endif
-        ecb[ecbno].sg = 1;       /* SCSI Initiator Command  w/scatter-gather*/
-        SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
-        sgpnt = (struct scatterlist *) SCpnt->request_buffer;
-        cptr = (struct aha1740_chain *) SCpnt->host_scribble; 
-        if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
-        for(i=0; i<SCpnt->use_sg; i++)
+       ecb[ecbno].sg = 1;        /* SCSI Initiator Command  w/scatter-gather*/
+       SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
+       sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+       cptr = (struct aha1740_chain *) SCpnt->host_scribble; 
+       if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
+       for(i=0; i<SCpnt->use_sg; i++)
        {
            cptr[i].dataptr = (long) sgpnt[i].address;
            cptr[i].datalen = sgpnt[i].length;
-        }
-        ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
-        ecb[ecbno].dataptr = (long) cptr;
+       }
+       ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
+       ecb[ecbno].dataptr = (long) cptr;
 #ifdef DEBUG
-        printk("cptr %x: ",cptr);
-        ptr = (unsigned char *) cptr;
-        for(i=0;i<24;i++) printk("%02x ", ptr[i]);
+       printk("cptr %x: ",cptr);
+       ptr = (unsigned char *) cptr;
+       for(i=0;i<24;i++) printk("%02x ", ptr[i]);
 #endif
     }
     else
     {
-        SCpnt->host_scribble = NULL;
-        ecb[ecbno].datalen = bufflen;
-        ecb[ecbno].dataptr = (long) buff;
+       SCpnt->host_scribble = NULL;
+       ecb[ecbno].datalen = bufflen;
+       ecb[ecbno].dataptr = (long) buff;
     }
     ecb[ecbno].lun = SCpnt->lun;
     ecb[ecbno].ses = 1;        /* Suppress underrun errors */
@@ -355,9 +359,9 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 #ifdef DEBUG
     {
        int i;
-        printk("aha1740_command: sending.. ");
-        for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
-            printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
+       printk("aha1740_command: sending.. ");
+       for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
+           printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
     }
     printk("\n");
 #endif
@@ -366,7 +370,7 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
          non-terminating while loops with interrupts disabled.  So did
          I when I wrote it, but the Adaptec Spec says the card is so fast,
          that this problem virtually never occurs so I've kept it.  We
-          do printk a warning first, so that you'll know if it happens.
+         do printk a warning first, so that you'll know if it happens.
          In practice the only time we've seen this message is when some-
          thing else is in the driver was broken, like _makecode(), or
          when a scsi device hung the scsi bus.  Even under these conditions,
@@ -451,8 +455,8 @@ int aha1740_detect(Scsi_Host_Template * tpnt)
 
     if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT )
     {  /* If the card isn't ready, hard reset it */
-        outb(G2CNTRL_HRST,G2CNTRL);
-        outb(0,G2CNTRL);    
+       outb(G2CNTRL_HRST,G2CNTRL);
+       outb(0,G2CNTRL);    
     }
 
     printk("Configuring Adaptec at IO:%x, IRQ %d\n",base,
@@ -462,8 +466,8 @@ int aha1740_detect(Scsi_Host_Template * tpnt)
 
     if (request_irq(irq_level,aha1740_intr_handle, 0, "aha1740"))
     {
-        printk("Unable to allocate IRQ for adaptec controller.\n");
-        return 0;
+       printk("Unable to allocate IRQ for adaptec controller.\n");
+       return 0;
     }
     request_region(base, 0x5c,"aha1740");  /* Reserve the space that we need to use */
     return 1;
@@ -504,6 +508,13 @@ DEB(printk("aha1740_biosparam\n"));
   return 0;
 }
 
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = AHA1740;
+
+#include "scsi_module.c"
+#endif
+
 /* Okay, you made it all the way through.  As of this writing, 3/31/93, I'm
 brad@saturn.gaylord.com or brad@bradpc.gaylord.com.  I'll try to help as time
 permits if you have any trouble with this driver.  Happy Linuxing! */
index d216979f86dd2510c34f6509c8d913365db8b594..16be2eb1973efa00c582a4dc6e0f88441358f2e4 100644 (file)
@@ -159,6 +159,8 @@ int aha1740_abort(Scsi_Cmnd *);
 int aha1740_reset(Scsi_Cmnd *);
 int aha1740_biosparam(Disk *, int, int*);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 #define AHA1740_ECBS 32
 #define AHA1740_SCATTER 16
 
@@ -167,6 +169,9 @@ int aha1740_biosparam(Disk *, int, int*);
 #endif
 
 #define AHA1740 {NULL, NULL,                           \
+                  generic_proc_info,                   \
+                  "aha1740",                           \
+                  PROC_SCSI_AHA1740,                   \
                   "Adaptec 174x (EISA)",               \
                   aha1740_detect,                      \
                   NULL,                                \
@@ -175,7 +180,7 @@ int aha1740_biosparam(Disk *, int, int*);
                   aha1740_queuecommand,                \
                   aha1740_abort,                       \
                   aha1740_reset,                       \
-                  NULL,                                \
+                  NULL,                                \
                   aha1740_biosparam,                   \
                   AHA1740_ECBS,                        \
                   7,                                   \
diff --git a/drivers/scsi/aic7770.c b/drivers/scsi/aic7770.c
deleted file mode 100644 (file)
index 42b14a9..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * Adaptec 274x/284x/294x device driver for Linux.
- * Copyright (c) 1994 The University of Calgary Department of Computer Science.
- * 
- * 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.
- *
- *  Comments are started by `#' and continue to the end of the line; lines
- *  may be of the form:
- *
- *     <label>*
- *     <label>*  <undef-sym> = <value>
- *     <label>*  <opcode> <operand>*
- *
- *  A <label> is an <undef-sym> ending in a colon.  Spaces, tabs, and commas
- *  are token separators.
- */
-
-#define _POSIX_SOURCE  1
-#define _POSIX_C_SOURCE        2
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#define MEMORY         512             /* 2^9 29-bit words */
-#define MAXLINE                1024
-#define MAXTOKEN       32
-#define ADOTOUT                "a.out"
-#define NOVALUE                -1
-
-/*
- *  AIC-7770 register definitions
- */
-#define R_SINDEX       0x65
-#define R_ALLONES      0x69
-#define R_ALLZEROS     0x6a
-#define R_NONE         0x6a
-
-static
-char sccsid[] =
-    "@(#)aic7770.c 1.10 94/07/22 jda";
-
-int debug;
-int lineno, LC;
-char *filename;
-FILE *ifp, *ofp;
-unsigned char M[MEMORY][4];
-
-void error(char *s)
-{
-       fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
-       exit(EXIT_FAILURE);
-}
-
-void *Malloc(size_t size)
-{
-       void *p = malloc(size);
-       if (!p)
-               error("out of memory");
-       return(p);
-}
-
-void *Realloc(void *ptr, size_t size)
-{
-       void *p = realloc(ptr, size);
-       if (!p)
-               error("out of memory");
-       return(p);
-}
-
-char *Strdup(char *s)
-{
-       char *p = (char *)Malloc(strlen(s) + 1);
-       strcpy(p, s);
-       return(p);
-}
-
-typedef struct sym_t {
-       struct sym_t *next;             /* MUST BE FIRST */
-       char *name;
-       int value;
-       int npatch, *patch;
-} sym_t;
-
-sym_t *head;
-
-void define(char *name, int value)
-{
-       sym_t *p, *q;
-
-       for (p = head, q = (sym_t *)&head; p; p = p->next) {
-               if (!strcmp(p->name, name))
-                       error("redefined symbol");
-               q = p;
-       }
-
-       p = q->next = (sym_t *)Malloc(sizeof(sym_t));
-       p->next = NULL;
-       p->name = Strdup(name);
-       p->value = value;
-       p->npatch = 0;
-       p->patch = NULL;
-
-       if (debug) {
-               fprintf(stderr, "\"%s\" ", p->name);
-               if (p->value != NOVALUE)
-                       fprintf(stderr, "defined as 0x%x\n", p->value);
-               else
-                       fprintf(stderr, "undefined\n");
-       }
-}
-
-sym_t *lookup(char *name)
-{
-       sym_t *p;
-
-       for (p = head; p; p = p->next)
-               if (!strcmp(p->name, name))
-                       return(p);
-       return(NULL);
-}
-
-void patch(sym_t *p, int location)
-{
-       p->npatch += 1;
-       p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
-
-       p->patch[p->npatch - 1] = location;
-}
-
-void backpatch(void)
-{
-       int i;
-       sym_t *p;
-
-       for (p = head; p; p = p->next) {
-
-               if (p->value == NOVALUE) {
-                       fprintf(stderr,
-                               "%s: undefined symbol \"%s\"\n",
-                               filename, p->name);
-                       exit(EXIT_FAILURE);
-               }
-
-               if (p->npatch) {
-                       if (debug)
-                               fprintf(stderr,
-                                       "\"%s\" (0x%x) patched at",
-                                       p->name, p->value);
-
-                       for (i = 0; i < p->npatch; i++) {
-                               M[p->patch[i]][0] &= ~1;
-                               M[p->patch[i]][0] |= ((p->value >> 8) & 1);
-                               M[p->patch[i]][1] = p->value & 0xff;
-
-                               if (debug)
-                                       fprintf(stderr, " 0x%x", p->patch[i]);
-                       }
-
-                       if (debug)
-                               fputc('\n', stderr);
-               }
-       }
-}
-
-/*
- *  Output words in byte-reversed order (least significant first)
- *  since the sequencer RAM is loaded that way.
- */
-void output(FILE *fp)
-{
-       int i;
-
-       for (i = 0; i < LC; i++)
-               fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
-                       M[i][3],
-                       M[i][2],
-                       M[i][1],
-                       M[i][0]);
-}
-
-char **getl(int *n)
-{
-       int i;
-       char *p;
-       static char buf[MAXLINE];
-       static char *a[MAXTOKEN];
-
-       i = 0;
-
-       while (fgets(buf, sizeof(buf), ifp)) {
-
-               lineno += 1;
-
-               if (buf[strlen(buf)-1] != '\n')
-                       error("line too long");
-
-               p = strchr(buf, '#');
-               if (p)
-                       *p = '\0';
-
-               for (p = strtok(buf, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
-                       if (i < MAXTOKEN-1)
-                               a[i++] = p;
-                       else
-                               error("too many tokens");
-               if (i) {
-                       *n = i;
-                       return(a);
-               }
-       }
-       return(NULL);
-}
-
-#define A      0x8000          /* `A'ccumulator ok */
-#define I      0x4000          /* use as immediate value */
-#define SL     0x2000          /* shift left */
-#define SR     0x1000          /* shift right */
-#define RL     0x0800          /* rotate left */
-#define RR     0x0400          /* rotate right */
-#define LO     0x8000          /* lookup: ori-{jmp,jc,jnc,call} */
-#define LA     0x4000          /* lookup: and-{jz,jnz} */
-#define LX     0x2000          /* lookup: xor-{je,jne} */
-#define NA     -1              /* not applicable */
-
-struct {
-       char *name;
-       int n;                  /* number of operands, including opcode */
-       unsigned int op;        /* immediate or L?|pos_from_0 */
-       unsigned int dest;      /* NA, pos_from_0, or I|immediate */
-       unsigned int src;       /* NA, pos_from_0, or I|immediate */
-       unsigned int imm;       /* pos_from_0, A|pos_from_0, or I|immediate */
-       unsigned int addr;      /* NA or pos_from_0 */
-       int fmt;                /* instruction format - 1, 2, or 3 */
-} instr[] = {
-/*
- *             N  OP    DEST           SRC             IMM     ADDR FMT
- */
-       "mov",  3, 1,    1,             2,              I|0xff, NA,  1,
-       "mov",  4, LO|2, NA,            1,              I|0,    3,   3,
-       "mvi",  3, 0,    1,             I|R_ALLZEROS,   A|2,    NA,  1,
-       "mvi",  4, LO|2, NA,            I|R_ALLZEROS,   1,      3,   3,
-       "not",  2, 2,    1,             1,              I|0xff, NA,  1,
-       "not",  3, 2,    1,             2,              I|0xff, NA,  1,
-       "and",  3, 1,    1,             1,              A|2,    NA,  1,
-       "and",  4, 1,    1,             3,              A|2,    NA,  1,
-       "or",   3, 0,    1,             1,              A|2,    NA,  1,
-       "or",   4, 0,    1,             3,              A|2,    NA,  1,
-       "or",   5, LO|3, NA,            1,              2,      4,   3,
-       "xor",  3, 2,    1,             1,              A|2,    NA,  1,
-       "xor",  4, 2,    1,             3,              A|2,    NA,  1,
-       "nop",  1, 1,    I|R_NONE,      I|R_ALLZEROS,   I|0xff, NA,  1,
-       "inc",  2, 3,    1,             1,              I|1,    NA,  1,
-       "inc",  3, 3,    1,             2,              I|1,    NA,  1,
-       "dec",  2, 3,    1,             1,              I|0xff, NA,  1,
-       "dec",  3, 3,    1,             2,              I|0xff, NA,  1,
-       "jmp",  2, LO|0, NA,            I|R_SINDEX,     I|0,    1,   3,
-       "jc",   2, LO|0, NA,            I|R_SINDEX,     I|0,    1,   3,
-       "jnc",  2, LO|0, NA,            I|R_SINDEX,     I|0,    1,   3,
-       "call", 2, LO|0, NA,            I|R_SINDEX,     I|0,    1,   3,
-       "test", 5, LA|3, NA,            1,              A|2,    4,   3,
-       "cmp",  5, LX|3, NA,            1,              A|2,    4,   3,
-       "ret",  1, 1,    I|R_NONE,      I|R_ALLZEROS,   I|0xff, NA,  1,
-       "clc",  1, 3,    I|R_NONE,      I|R_ALLZEROS,   I|1,    NA,  1,
-       "clc",  4, 3,    2,             I|R_ALLZEROS,   A|3,    NA,  1,
-       "stc",  1, 3,    I|R_NONE,      I|R_ALLONES,    I|1,    NA,  1,
-       "stc",  2, 3,    1,             I|R_ALLONES,    I|1,    NA,  1,
-       "add",  3, 3,    1,             1,              A|2,    NA,  1,
-       "add",  4, 3,    1,             3,              A|2,    NA,  1,
-       "adc",  3, 4,    1,             1,              A|2,    NA,  1,
-       "adc",  4, 4,    1,             3,              A|2,    NA,  1,
-       "shl",  3, 5,    1,             1,              SL|2,   NA,  2,
-       "shl",  4, 5,    1,             2,              SL|3,   NA,  2,
-       "shr",  3, 5,    1,             1,              SR|2,   NA,  2,
-       "shr",  4, 5,    1,             2,              SR|3,   NA,  2,
-       "rol",  3, 5,    1,             1,              RL|2,   NA,  2,
-       "rol",  4, 5,    1,             2,              RL|3,   NA,  2,
-       "ror",  3, 5,    1,             1,              RR|2,   NA,  2,
-       "ror",  4, 5,    1,             2,              RR|3,   NA,  2,
-       /*
-        *  Extensions (note also that mvi allows A)
-        */
-       "clr",  2, 1,    1,             I|R_ALLZEROS,   I|0xff, NA,  1,
-       0
-};
-
-int eval_operand(char **a, int spec)
-{
-       int i;
-       unsigned int want = spec & (LO|LA|LX);
-
-       static struct {
-               unsigned int what;
-               char *name;
-               int value;
-       } jmptab[] = {
-               LO,     "jmp",          8,
-               LO,     "jc",           9,
-               LO,     "jnc",          10,
-               LO,     "call",         11,
-               LA,     "jz",           15,
-               LA,     "jnz",          13,
-               LX,     "je",           14,
-               LX,     "jne",          12,
-       };
-
-       spec &= ~(LO|LA|LX);
-
-       for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
-               if (jmptab[i].what == want &&
-                   !strcmp(jmptab[i].name, a[spec]))
-               {
-                       return(jmptab[i].value);
-               }
-
-       if (want)
-               error("invalid jump");
-
-       return(spec);           /* "case 0" - no flags set */
-}
-
-int eval_sdi(char **a, int spec)
-{
-       sym_t *p;
-       unsigned val;
-
-       if (spec == NA)
-               return(NA);
-
-       switch (spec & (A|I|SL|SR|RL|RR)) {
-           case SL:
-           case SR:
-           case RL:
-           case RR:
-               if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
-                       val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
-               else {
-                       p = lookup(a[spec &~ (SL|SR|RL|RR)]);
-                       if (!p)
-                               error("undefined symbol used");
-                       val = p->value;
-               }
-
-               switch (spec & (SL|SR|RL|RR)) {         /* blech */
-                   case SL:
-                       if (val > 7)
-                               return(0xf0);
-                       return(((val % 8) << 4) |
-                              (val % 8));
-                   case SR:
-                       if (val > 7)
-                               return(0xf0);
-                       return(((val % 8) << 4) |
-                              (1 << 3) |
-                              ((8 - (val % 8)) % 8));
-                   case RL:
-                       return(val % 8);
-                   case RR:
-                       return((8 - (val % 8)) % 8);
-               }
-           case I:
-               return(spec &~ I);
-           case A:
-               /*
-                *  An immediate field of zero selects
-                *  the accumulator.  Vigorously object
-                *  if zero is given otherwise - it's
-                *  most likely an error.
-                */
-               spec &= ~A;
-               if (!strcmp("A", a[spec]))
-                       return(0);
-               if (isdigit(*a[spec]) &&
-                   strtol(a[spec], NULL, 0) == 0)
-               {
-                       error("immediate value of zero selects accumulator");
-               }
-               /* falls through */
-           case 0:
-               if (isdigit(*a[spec]))
-                       return(strtol(a[spec], NULL, 0));
-               p = lookup(a[spec]);
-               if (p)
-                       return(p->value);
-               error("undefined symbol used");
-       }
-
-       return(NA);             /* shut the compiler up */
-}
-
-int eval_addr(char **a, int spec)
-{
-       sym_t *p;
-
-       if (spec == NA)
-               return(NA);
-       if (isdigit(*a[spec]))
-               return(strtol(a[spec], NULL, 0));
-
-       p = lookup(a[spec]);
-
-       if (p) {
-               if (p->value != NOVALUE)
-                       return(p->value);
-               patch(p, LC);
-       } else {
-               define(a[spec], NOVALUE);
-               p = lookup(a[spec]);
-               patch(p, LC);
-       }
-
-       return(NA);             /* will be patched in later */
-}
-
-int crack(char **a, int n)
-{
-       int i;
-       int I_imm, I_addr;
-       int I_op, I_dest, I_src, I_ret;
-
-       /*
-        *  Check for "ret" at the end of the line; remove
-        *  it unless it's "ret" alone - we still want to
-        *  look it up in the table.
-        */
-       I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
-       if (I_ret && n > 1)
-               n -= 1;
-
-       for (i = 0; instr[i].name; i++) {
-               /*
-                *  Look for match in table given constraints,
-                *  currently just the name and the number of
-                *  operands.
-                */
-               if (!strcmp(instr[i].name, *a) && instr[i].n == n)
-                       break;
-       }
-       if (!instr[i].name)
-               error("unknown opcode or wrong number of operands");
-
-       I_op    = eval_operand(a, instr[i].op);
-       I_src   = eval_sdi(a, instr[i].src);
-       I_imm   = eval_sdi(a, instr[i].imm);
-       I_dest  = eval_sdi(a, instr[i].dest);
-       I_addr  = eval_addr(a, instr[i].addr);
-
-       switch (instr[i].fmt) {
-           case 1:
-           case 2:
-               M[LC][0] = (I_op << 1) | I_ret;
-               M[LC][1] = I_dest;
-               M[LC][2] = I_src;
-               M[LC][3] = I_imm;
-               break;
-           case 3:
-               if (I_ret)
-                       error("illegal use of \"ret\"");
-               M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
-               M[LC][1] = I_addr & 0xff;
-               M[LC][2] = I_src;
-               M[LC][3] = I_imm;
-               break;
-       }
-
-       return(1);              /* no two-byte instructions yet */
-}
-
-#undef SL
-#undef SR
-#undef RL
-#undef RR
-#undef LX
-#undef LA
-#undef LO
-#undef I
-#undef A
-
-void assemble(void)
-{
-       int n;
-       char **a;
-       sym_t *p;
-
-       while ((a = getl(&n))) {
-
-               while (a[0][strlen(*a)-1] == ':') {
-                       a[0][strlen(*a)-1] = '\0';
-                       p = lookup(*a);
-                       if (p)
-                               p->value = LC;
-                       else
-                               define(*a, LC);
-                       a += 1;
-                       n -= 1;
-               }
-
-               if (!n)                 /* line was all labels */
-                       continue;
-
-               if (n == 3 && !strcmp("VERSION", *a))
-                       fprintf(ofp, "#define %s \"%s\"\n", a[1], a[2]);
-               else {
-                       if (n == 3 && !strcmp("=", a[1]))
-                               define(*a, strtol(a[2], NULL, 0));
-                       else
-                               LC += crack(a, n);
-               }
-       }
-
-       backpatch();
-       output(ofp);
-
-       if (debug)
-               output(stderr);
-}
-
-int main(int argc, char **argv)
-{
-       int c;
-
-       while ((c = getopt(argc, argv, "dho:")) != EOF) {
-               switch (c) {
-                   case 'd':
-                       debug = !0;
-                       break;
-                   case 'o':
-                       ofp = fopen(optarg, "w");
-                       if (!ofp) {
-                               perror(optarg);
-                               exit(EXIT_FAILURE);
-                       }
-                       break;
-                   case 'h':
-                       printf("usage: %s [-d] [-ooutput] input\n", *argv);
-                       exit(EXIT_SUCCESS);
-                   case NULL:
-                       /*
-                        *  An impossible option to shut the compiler
-                        *  up about sccsid[].
-                        */
-                       exit((int)sccsid);
-                   default:
-                       exit(EXIT_FAILURE);
-               }
-       }
-
-       if (argc - optind != 1) {
-               fprintf(stderr, "%s: must have one input file\n", *argv);
-               exit(EXIT_FAILURE);
-       }
-       filename = argv[optind];
-
-       ifp = fopen(filename, "r");
-       if (!ifp) {
-               perror(filename);
-               exit(EXIT_FAILURE);
-       }
-
-       if (!ofp) {
-               ofp = fopen(ADOTOUT, "w");
-               if (!ofp) {
-                       perror(ADOTOUT);
-                       exit(EXIT_FAILURE);
-               }
-       }
-
-       assemble();
-       exit(EXIT_SUCCESS);
-}
index e06212766bfe9e78550b5f70f1fdba1a51fa74ef..cc54d2fd3dcf22f17e181cc737daad91f948baf1 100644 (file)
@@ -1,44 +1,67 @@
-/*
- *  @(#)aic7xxx.c 1.34 94/11/30 jda
+/*+M*************************************************************************
+ * Adaptec 274x/284x/294x device driver for Linux.
  *
- *  Adaptec 274x/284x/294x device driver for Linux.
- *  Copyright (c) 1994 The University of Calgary Department of Computer Science.
- *  
- *  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.
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *   All rights reserved.
  *
- *  Sources include the Adaptec 1740 driver (aha1740.c), the
- *  Ultrastor 24F driver (ultrastor.c), various Linux kernel
- *  source, the Adaptec EISA config file (!adp7771.cfg), the
- *  Adaptec AHA-2740A Series User's Guide, the Linux Kernel
- *  Hacker's Guide, Writing a SCSI Device Driver for Linux,
- *  the Adaptec 1542 driver (aha1542.c), the Adaptec EISA
- *  overlay file (adp7770.ovl), the Adaptec AHA-2740 Series
- *  Technical Reference Manual, the Adaptec AIC-7770 Data
- *  Book, the ANSI SCSI specification, the ANSI SCSI-2
- *  specification (draft 10c), ...
+ * 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.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of Calgary
+ *      Department of Computer Science and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
- *  On a twin-bus adapter card, channel B is ignored.  Rationale:
- *  it would greatly complicate the sequencer and host driver code,
- *  and both busses are multiplexed on to the EISA bus anyway.  So
- *  I don't really see any technical advantage to supporting both.
+ * 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.
+ * 
+ * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F
+ * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA
+ * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide,
+ * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux,
+ * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file
+ * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual,
+ * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
+ * ANSI SCSI-2 specification (draft 10c), ...
  *
- *  As well, multiple adapter card using the same IRQ level are
- *  not supported.  It doesn't make sense to configure the cards
- *  this way from a performance standpoint.  Not to mention that
- *  the kernel would have to support two devices per registered IRQ.
- */
+ * ----------------------------------------------------------------
+ *  Modified to include support for wide and twin bus adapters,
+ *  DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ *  and other rework of the code.
+ *
+ *  Parts of this driver are based on the FreeBSD driver by Justin
+ *  T. Gibbs.
+ *
+ *  A Boot time option was also added for not resetting the scsi bus.
+ *
+ *    Form:  aic7xxx=extended,no_reset
+ *
+ *    -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 04/03/95
+ *
+ *  $Id: aic7xxx.c,v 1.49 1995/06/28 05:41:09 deang Exp $
+ *-M*************************************************************************/
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
 
 #include <stdarg.h>
 #include <asm/io.h>
 #include <linux/ioport.h>
 #include <linux/bios32.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #include <linux/pci.h>
-
+#include <linux/proc_fs.h>
 #include "../block/blk.h"
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
 #include "aic7xxx.h"
 
+#define AIC7XXX_C_VERSION  "$Revision: 1.49 $"
+
+#define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
+#define MIN(a,b) ((a < b) ? a : b)
+
+/*
+ * Defines for PCI bus support, testing twin bus support, DMAing of
+ * SCBs, and tagged queueing.
+ *
+ *   o PCI bus support - this has been implemented and working since
+ *     the December 1, 1994 release of this driver. If you don't have
+ *     a PCI bus and do not wish to configure your kernel with PCI
+ *     support, then make sure this define is set to the cprrect
+ *     define for PCI support (CONFIG_PCI) and configure your kernel
+ *     without PCI support (make config).
+ *
+ *   o Twin bus support - this has been tested and does work.
+ *
+ *   o DMAing of SCBs - thanks to Kai Makisara, this now works
+ *
+ *   o Tagged queueing - this driver is capable of tagged queueing
+ *     but I am unsure as to how well the higher level driver implements
+ *     tagged queueing. Therefore, the maximum commands per lun is
+ *     set to 2. If you want to implement tagged queueing, ensure
+ *     this define is not commented out.
+ *
+ *   o Sharing IRQs - allowed for sharing of IRQs. This will allow
+ *     for multiple aic7xxx host adapters sharing the same IRQ, but
+ *     not for sharing IRQs with other devices. The higher level
+ *     PCI code and interrupt handling needs to be modified to
+ *     support this.
+ *
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 03/11/95
+ */
+
+/* Uncomment this for testing twin bus support. */
+#define AIC7XXX_TWIN_SUPPORT
+
+/* Uncomment this for DMAing of SCBs. */
+#define AIC7XXX_USE_DMA
+
+/* Uncomment this for tagged queueing. */
+/* #define AIC7XXX_TAGGED_QUEUEING */
+
+/* Uncomment this for allowing sharing of IRQs. */
+#define AIC7XXX_SHARE_IRQS
+
+/* Set this to the delay in seconds after SCSI bus reset. */
+#define AIC7XXX_RESET_DELAY 15
+
+/*
+ * Uncomment this to always use scatter/gather lists.
+ * *NOTE: The sequencer must be changed also!
+ */
+#define AIC7XXX_USE_SG
+
+/*
+ * Controller type and options
+ */
+typedef enum {
+  AIC_NONE,
+  AIC_274x,    /* EISA aic7770 */
+  AIC_284x,    /* VLB  aic7770 */
+  AIC_7870,    /* PCI  aic7870 */
+  AIC_7850,    /* PCI  aic7850 */
+  AIC_7872     /* PCI  aic7870 on 394x */
+} aha_type;
+
+typedef enum {
+  AIC_SINGLE,  /* Single Channel */
+  AIC_TWIN,    /* Twin Channel */
+  AIC_WIDE     /* Wide Channel */
+} aha_bus_type;
+
+typedef enum {
+  AIC_UNKNOWN,
+  AIC_ENABLED,
+  AIC_DISABLED
+} aha_status_type;
+
 /*
- *  There should be a specific return value for this in scsi.h, but
- *  it seems that most drivers ignore it.
+ * There should be a specific return value for this in scsi.h, but
+ * it seems that most drivers ignore it.
  */
-#define DID_UNDERFLOW  DID_ERROR
+#define DID_UNDERFLOW   DID_ERROR
 
-/* EISA/VL-bus stuff */
+/*
+ *  What we want to do is have the higher level scsi driver requeue
+ *  the command to us. There is no specific driver status for this
+ *  condition, but the higher level scsi driver will requeue the
+ *  command on a DID_BUS_BUSY error.
+ */
+#define DID_RETRY_COMMAND DID_BUS_BUSY
 
+/*
+ * EISA/VL-bus stuff
+ */
 #define MINSLOT                1
 #define MAXSLOT                15
 #define SLOTBASE(x)    ((x) << 12)
-
 #define MAXIRQ         15
 
-/* AIC-7770 offset definitions */
-
-#define O_MINREG(x)    ((x) + 0xc00)           /* i/o range to reserve */
-#define O_MAXREG(x)    ((x) + 0xcbf)
-
-#define O_SCSISEQ(x)   ((x) + 0xc00)           /* scsi sequence control */
-#define O_SCSISIGI(x)  ((x) + 0xc03)           /* scsi control signal read */
-#define O_SCSISIGO(x)  ((x) + 0xc03)           /* scsi control signal write */
-#define O_SCSIID(x)    ((x) + 0xc05)           /* scsi id */
-#define O_SSTAT0(x)    ((x) + 0xc0b)           /* scsi status register 0 */
-#define O_CLRSINT1(x)  ((x) + 0xc0c)           /* clear scsi interrupt 1 */
-#define O_SSTAT1(x)    ((x) + 0xc0c)           /* scsi status register 1 */
-#define O_SELID(x)     ((x) + 0xc19)           /* [re]selection id */
-#define O_SBLKCTL(x)   ((x) + 0xc1f)           /* scsi block control */
-#define O_SEQCTL(x)    ((x) + 0xc60)           /* sequencer control */
-#define O_SEQRAM(x)    ((x) + 0xc61)           /* sequencer ram data */
-#define O_SEQADDR(x)   ((x) + 0xc62)           /* sequencer address (W) */
-#define O_BIDx(x)      ((x) + 0xc80)           /* board id */
-#define O_BCTL(x)      ((x) + 0xc84)           /* board control */
-#define O_HCNTRL(x)    ((x) + 0xc87)           /* host control */
-#define O_SCBPTR(x)    ((x) + 0xc90)           /* scb pointer */
-#define O_INTSTAT(x)   ((x) + 0xc91)           /* interrupt status */
-#define O_ERROR(x)     ((x) + 0xc92)           /* hard error */
-#define O_CLRINT(x)    ((x) + 0xc92)           /* clear interrupt status */
-#define O_SCBCNT(x)    ((x) + 0xc9a)           /* scb auto increment */
-#define O_QINFIFO(x)   ((x) + 0xc9b)           /* queue in fifo */
-#define O_QINCNT(x)    ((x) + 0xc9c)           /* queue in count */
-#define O_QOUTFIFO(x)  ((x) + 0xc9d)           /* queue out fifo */
-#define O_QOUTCNT(x)   ((x) + 0xc9e)           /* queue out count */
-#define O_SCBARRAY(x)  ((x) + 0xca0)           /* scb array start */
-
-/* AIC-7870-only definitions */
-
-#define O_DSPCISTATUS(x) ((x) + 0xc86)         /* ??? */
-
-/* host adapter offset definitions */
-
-#define HA_REJBYTE(x)  ((x) + 0xc31)           /* 1st message in byte */
-#define HA_MSG_FLAGS(x)        ((x) + 0xc35)           /* outgoing message flag */
-#define HA_MSG_LEN(x)  ((x) + 0xc36)           /* outgoing message length */
-#define HA_MSG_START(x)        ((x) + 0xc37)           /* outgoing message body */
-#define HA_ARG_1(x)    ((x) + 0xc4c)           /* sdtr <-> rate parameters */
-#define HA_ARG_2(x)    ((x) + 0xc4d)
-#define HA_RETURN_1(x) ((x) + 0xc4c)
-#define HA_RETURN_2(x) ((x) + 0xc4d)
-#define HA_SIGSTATE(x) ((x) + 0xc4e)           /* value in SCSISIGO */
-#define HA_NEEDSDTR(x) ((x) + 0xc4f)           /* synchronous negotiation? */
-#define HA_SCBCOUNT(x) ((x) + 0xc56)           /* number of hardware SCBs */
-
-#define HA_SCSICONF(x) ((x) + 0xc5a)           /* SCSI config register */
-#define HA_INTDEF(x)   ((x) + 0xc5c)           /* interrupt def'n register */
-#define HA_HOSTCONF(x) ((x) + 0xc5d)           /* host config def'n register */
-
-/* debugging code */
+/*
+ * Standard EISA Host ID regs  (Offset from slot base)
+ */
+#define HID0(x)         ((x) + 0xC80)   /* 0,1: msb of ID2, 2-7: ID1      */
+#define HID1(x)         ((x) + 0xC81)   /* 0-4: ID3, 5-7: LSB ID2         */
+#define HID2(x)         ((x) + 0xC82)   /* product                        */
+#define HID3(x)         ((x) + 0xC83)   /* firmware revision              */
 
 /*
-#define AIC7XXX_DEBUG
-*/
+ * AIC-7770 I/O range to reserve for a card
+ */
+#define MINREG(x)      ((x) + 0xC00ul)
+#define MAXREG(x)      ((x) + 0xCBFul)
+
+/* -------------------- AIC-7770 offset definitions ----------------------- */
 
 /*
- *  If a parity error occurs during a data transfer phase, run the
- *  command to completion - it's easier that way - making a note
- *  of the error condition in this location.  This then will modify
- *  a DID_OK status into a DID_PARITY one for the higher-level SCSI
- *  code.
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
  */
-#define aic7xxx_parity(cmd)    ((cmd)->SCp.Status)
+#define SCSISEQ(x)             ((x) + 0xC00ul)
+#define                TEMODEO         0x80
+#define                ENSELO          0x40
+#define                ENSELI          0x20
+#define                ENRSELI         0x10
+#define                ENAUTOATNO      0x08
+#define                ENAUTOATNI      0x04
+#define                ENAUTOATNP      0x02
+#define                SCSIRSTO        0x01
 
 /*
- *  Since the sequencer code DMAs the scatter-gather structures
- *  directly from memory, we use this macro to assert that the
- *  kernel structure hasn't changed.
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
  */
-#define SG_STRUCT_CHECK(sg) \
-       ((char *)&(sg).address - (char *)&(sg) != 0 ||  \
-        (char *)&(sg).length  - (char *)&(sg) != 8 ||  \
-        sizeof((sg).address) != 4 ||                   \
-        sizeof((sg).length)  != 4 ||                   \
-        sizeof(sg)           != 12)
+#define SXFRCTL1(x)            ((x) + 0xC02ul)
+#define                BITBUCKET       0x80
+#define                SWRAPEN         0x40
+#define                ENSPCHK         0x20
+#define                STIMESEL        0x18
+#define                ENSTIMER        0x04
+#define                ACTNEGEN        0x02
+#define                STPWEN          0x01            /* Powered Termination */
 
 /*
- *  "Static" structures.  Note that these are NOT initialized
- *  to zero inside the kernel - we have to initialize them all
- *  explicitly.
- *
- *  We support a maximum of one adapter card per IRQ level (see the
- *  rationale for this above).  On an interrupt, use the IRQ as an
- *  index into aic7xxx_boards[] to locate the card information.
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
  */
-static struct Scsi_Host *aic7xxx_boards[MAXIRQ + 1];
+#define SCSISIGI(x)            ((x) + 0xC03ul)
+#define                CDI             0x80
+#define                IOI             0x40
+#define                MSGI            0x20
+#define                ATNI            0x10
+#define                SELI            0x08
+#define                BSYI            0x04
+#define                REQI            0x02
+#define                ACKI            0x01
 
 /*
- *  The maximum number of SCBs we could have for ANY type
- *  of card.  DON'T FORGET TO CHANGE THE SCB MASK IN THE
- *  SEQUENCER CODE IF THIS IS MODIFIED!
+ * SCSI Contol Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus. Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
  */
-#define AIC7XXX_MAXSCB 16
+#define SCSISIGO(x)            ((x) + 0xC03ul)
+#define                CDO             0x80
+#define                IOO             0x40
+#define                MSGO            0x20
+#define                ATNO            0x10
+#define                SELO            0x08
+#define                BSYO            0x04
+#define                REQO            0x02
+#define                ACKO            0x01
 
-struct aic7xxx_host {
-       int base;                                       /* card base address */
-       int maxscb;                                     /* hardware SCBs */
-       int startup;                                    /* intr type check */
-       int extended;                                   /* extended xlate? */
-       volatile int unpause;                           /* value for HCNTRL */
-       volatile Scsi_Cmnd *SCB_array[AIC7XXX_MAXSCB];  /* active commands */
-};
+/*
+ * SCSI Rate
+ */
+#define SCSIRATE(x)            ((x) + 0xC04ul)
 
-struct aic7xxx_host_config {
-       int irq;                                        /* IRQ number */
-       int base;                                       /* I/O base */
-       int maxscb;                                     /* hardware SCBs */
      int unpause;                                    /* value for HCNTRL */
-       int scsi_id;                                    /* host SCSI id */
-       int extended;                                   /* extended xlate? */
-};
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel
+ */
+#define SCSIID(x)              ((x) + 0xC05ul)
+#define                TID             0xF0            /* Target ID mask */
+#define                OID             0x0F            /* Our ID mask */
 
-struct aic7xxx_scb {
-       unsigned char control;
-       unsigned char target_channel_lun;               /* 4/1/3 bits */
-       unsigned char SG_segment_count;
-       unsigned char SG_list_pointer[4];
-       unsigned char SCSI_cmd_pointer[4];
-       unsigned char SCSI_cmd_length;
-       unsigned char RESERVED[2];                      /* must be zero */
-       unsigned char target_status;
-       unsigned char residual_data_count[3];
-       unsigned char residual_SG_segment_count;
-       unsigned char data_pointer[4];
-       unsigned char data_count[3];
-#if 0
-       /*
-        *  No real point in transferring this to the
-        *  SCB registers.
-        */
-       unsigned char RESERVED[6];
-#endif
-};
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+#define SSTAT0(x)              ((x) + 0xC0Bul)
+#define                TARGET          0x80            /* Board is a target */
+#define                SELDO           0x40            /* Selection Done */
+#define                SELDI           0x20            /* Board has been selected */
+#define                SELINGO         0x10            /* Selection In Progress */
+#define                SWRAP           0x08            /* 24bit counter wrap */
+#define                SDONE           0x04            /* STCNT = 0x000000 */
+#define                SPIORDY         0x02            /* SCSI PIO Ready */
+#define                DMADONE         0x01            /* DMA transfer completed */
 
 /*
- *  NB.  This table MUST be ordered shortest period first.
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
  */
-static struct {
-       short period;
-       short rate;
-       char *english;
-} aic7xxx_synctab[] = {
-       100,    0,      "10.0",
-       125,    1,      "8.0",
-       150,    2,      "6.67",
-       175,    3,      "5.7",
-       200,    4,      "5.0",
-       225,    5,      "4.4",
-       250,    6,      "4.0",
-       275,    7,      "3.6"
-};
+#define CLRSINT1(x)            ((x) + 0xC0Cul)
+#define                CLRSELTIMEO     0x80
+#define                CLRATNO         0x40
+#define                CLRSCSIRSTI     0x20
+/*  UNUSED                     0x10 */
+#define                CLRBUSFREE      0x08
+#define                CLRSCSIPERR     0x04
+#define                CLRPHASECHG     0x02
+#define                CLRREQINIT      0x01
 
-static int aic7xxx_synctab_max =
-       sizeof(aic7xxx_synctab) / sizeof(aic7xxx_synctab[0]);
+/*
+ * SCSI Status 1 (p. 3-24)
+ * These interrupt bits are of interest to the kernel driver
+ */
+#define SSTAT1(x)              ((x) + 0xC0Cul)
+#define                SELTO           0x80
+#define                ATNTARG         0x40
+#define                SCSIRSTI        0x20
+#define                PHASEMIS        0x10
+#define                BUSFREE         0x08
+#define                SCSIPERR        0x04
+#define                PHASECHG        0x02
+#define                REQINIT         0x01
 
-enum aha_type {
-       T_NONE,
-       T_274X,
-       T_284X,
-       T_294X,
-       T_MAX
-};
+/*
+ * SCSI Interrrupt Mode 1 (pp. 3-28,29).
+ * Set bits in this register enable the corresponding
+ * interrupt source.
+ */
+#define        SIMODE1(x)              ((x) + 0xC11ul)
+#define                ENSELTIMO       0x80
+#define                ENATNTARG       0x40
+#define                ENSCSIRST       0x20
+#define                ENPHASEMIS      0x10
+#define                ENBUSFREE       0x08
+#define                ENSCSIPERR      0x04
+#define                ENPHASECHG      0x02
+#define                ENREQINIT       0x01
 
-#ifdef AIC7XXX_DEBUG
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id. The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+#define SELID(x)               ((x) + 0xC19ul)
+#define                SELID_MASK      0xF0
+#define                ONEBIT          0x08
+/*  UNUSED                     0x07 */
 
-       extern int vsprintf(char *, const char *, va_list);
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  See aic7xxx_read_eprom for detailed information on
+ * the protocol necessary to read the serial EEPROM.
+ */
+#define SEECTL(x)              ((x) + 0xC1Eul)
+#define                EXTARBACK       0x80
+#define                EXTARBREQ       0x40
+#define                SEEMS           0x20
+#define                SEERDY          0x10
+#define                SEECS           0x08
+#define                SEECK           0x04
+#define                SEEDO           0x02
+#define                SEEDI           0x01
 
-       static
-       void debug(const char *fmt, ...)
-       {
-               va_list ap;
-               char buf[256];
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection. In a twin channel configuration
+ * addresses 0x00-0x1E are gated to the appropriate channel based on this
+ * register. SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+#define SBLKCTL(x)             ((x) + 0xC1Ful)
+/*  UNUSED                     0xC0 */
+#define                AUTOFLUSHDIS    0x20            /* used for Rev C check */
+/*  UNUSED                     0x10 */
+#define                SELBUSB         0x08
+/*  UNUSED                     0x04 */
+#define                SELWIDE         0x02
+/*  UNUSED                     0x01 */
+#define                SELSINGLE       0x00
 
-               va_start(ap, fmt);
-                 vsprintf(buf, fmt, ap);
-                 printk(buf);
-               va_end(ap);
-       }
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+#define SEQCTL(x)              ((x) + 0xC60ul)
+#define                PERRORDIS       0x80
+#define                PAUSEDIS        0x40
+#define                FAILDIS         0x20
+#define        FASTMODE        0x10
+#define                BRKADRINTEN     0x08
+#define                STEP            0x04
+#define                SEQRESET        0x02
+#define                LOADRAM         0x01
 
-       static
-       void debug_config(enum aha_type type, struct aic7xxx_host_config *p)
-       {
-               int ioport2, ioport3;
-
-               static char *BRT[T_MAX][16] = {
-                       { },                                    /* T_NONE */
-                       {
-                               "2",   "???", "???", "12",      /* T_274X */
-                               "???", "???", "???", "28",
-                               "???", "???", "???", "44",
-                               "???", "???", "???", "60"
-                       },
-                       {
-                               "2",  "4",  "8",  "12",         /* T_284X */
-                               "16", "20", "24", "28",
-                               "32", "36", "40", "44",
-                               "48", "52", "56", "60"
-                       },
-                       {
-                               "???", "???", "???", "???",     /* T_294X */
-                               "???", "???", "???", "???",
-                               "???", "???", "???", "???",
-                               "???", "???", "???", "???"
-                       }
-               };
-               static int DFT[4] = {
-                       0, 50, 75, 100
-               };
-               static int SST[4] = {
-                       256, 128, 64, 32
-               };
-
-               ioport2 = inb(HA_HOSTCONF(p->base));
-               ioport3 = inb(HA_SCSICONF(p->base));
-
-               switch (type) {
-                   case T_274X:
-                       printk("AHA274X AT EISA SLOT %d:\n", p->base >> 12);
-                       break;
-                   case T_284X:
-                       printk("AHA284X AT SLOT %d:\n", p->base >> 12);
-                       break;
-                   case T_294X:
-                       printk("AHA294X (PCI-bus):\n");
-                       break;
-                   default:
-                       panic("aic7xxx debug_config: internal error\n");
-               }
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write
+ * four bytes in sucessesion. The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+#define SEQRAM(x)              ((x) + 0xC61ul)
 
-               printk("    irq %d\n"
-                      "    bus release time %s bclks\n"
-                      "    data fifo threshold %d%%\n",
-                      p->irq,
-                      BRT[type][(ioport2 >> 2) & 0xf],
-                      DFT[(ioport2 >> 6) & 0x3]);
-
-               printk("    SCSI CHANNEL A:\n"
-                      "        scsi id %d\n"
-                      "        scsi bus parity check %sabled\n"
-                      "        scsi selection timeout %d ms\n"
-                      "        scsi bus reset at power-on %sabled\n",
-                      ioport3 & 0x7,
-                      (ioport3 & 0x20) ? "en" : "dis",
-                      SST[(ioport3 >> 3) & 0x3],
-                      (ioport3 & 0x40) ? "en" : "dis");
-
-               if (type == T_274X) {
-                       printk("        scsi bus termination %sabled\n",
-                              (ioport3 & 0x80) ? "en" : "dis");
-               }
-       }
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+#define SEQADDR0(x)            ((x) + 0xC62ul)
+#define SEQADDR1(x)            ((x) + 0xC63ul)
 
-       static
-       void debug_rate(int base, int rate)
-       {
-               int target = inb(O_SCSIID(base)) >> 4;
-
-               if (rate) {
-                       printk("aic7xxx: target %d now synchronous at %sMb/s\n",
-                              target,
-                              aic7xxx_synctab[(rate >> 4) & 0x7].english);
-               } else {
-                       printk("aic7xxx: target %d using asynchronous mode\n",
-                              target);
-               }
-       }
+#define ACCUM(x)               ((x) + 0xC64ul)         /* accumulator */
 
-#else
+/*
+ * Board Control (p. 3-43)
+ */
+#define BCTL(x)                ((x) + 0xC84ul)
+/*   RSVD                      0xF0 */
+#define                ACE             0x08    /* Support for external processors */
+/*   RSVD                      0x06 */
+#define                ENABLE          0x01
 
-#      define debug(fmt, args...)
-#      define debug_config(x)
-#      define debug_rate(x,y)
+#define BUSSPD(x)              ((x) + 0xC86ul) /* FIFO threshold bits ? */
 
-#endif AIC7XXX_DEBUG
+/*
+ * Host Control (p. 3-47) R/W
+ * Overal host control of the device.
+ */
+#define HCNTRL(x)              ((x) + 0xC87ul)
+/*    UNUSED                   0x80 */
+#define                POWRDN          0x40
+/*    UNUSED                   0x20 */
+#define                SWINT           0x10
+#define                IRQMS           0x08
+#define                PAUSE           0x04
+#define                INTEN           0x02
+#define                CHIPRST         0x01
+#define                REQ_PAUSE       IRQMS | PAUSE | INTEN
+#define                UNPAUSE_274X    IRQMS | INTEN
+#define                UNPAUSE_284X    INTEN
+#define                UNPAUSE_294X    IRQMS | INTEN
 
 /*
- *  XXX - these options apply unilaterally to _all_ 274x/284x/294x
- *       cards in the system.  This should be fixed, but then,
- *       does anyone really have more than one in a machine?
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
  */
-static int aic7xxx_extended = 0;               /* extended translation on? */
+#define SCBPTR(x)              ((x) + 0xC90ul)
 
-void aic7xxx_setup(char *s, int *dummy)
-{
-       int i;
-       char *p;
-
-       static struct {
-               char *name;
-               int *flag;
-       } options[] = {
-               "extended",     &aic7xxx_extended,
-               NULL
-       };
-
-       for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
-               for (i = 0; options[i].name; i++)
-                       if (!strcmp(options[i].name, p))
-                               *(options[i].flag) = !0;
-       }
-}
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+#define INTSTAT(x)             ((x) + 0xC91ul)
+#define                SEQINT_MASK     0xF0            /* SEQINT Status Codes */
+#define                        BAD_PHASE       0x00
+#define                        SEND_REJECT     0x10
+#define                        NO_IDENT        0x20
+#define                        NO_MATCH        0x30
+#define                        MSG_SDTR        0x40
+#define                        MSG_WDTR        0x50
+#define                        MSG_REJECT      0x60
+#define                        BAD_STATUS      0x70
+#define                        RESIDUAL        0x80
+#define                        ABORT_TAG       0x90
+#define                        AWAITING_MSG    0xa0
+#define        BRKADRINT 0x08
+#define                SCSIINT   0x04
+#define                CMDCMPLT  0x02
+#define                SEQINT    0x01
+#define                INT_PEND  (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
 
-static
-void aic7xxx_getscb(int base, struct aic7xxx_scb *scb)
-{
-       /*
-        *  This is almost identical to aic7xxx_putscb().
-        */
-       outb(0x80, O_SCBCNT(base));     /* SCBAUTO */
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors. You usually cannot recover from
+ * these without a full board reset.
+ */
+#define ERROR(x)               ((x) + 0xC92ul)
+/*    UNUSED                   0xF0 */
+#define                PARERR          0x08
+#define                ILLOPCODE       0x04
+#define                ILLSADDR        0x02
+#define                ILLHADDR        0x01
 
-       asm volatile("cld\n\t"
-                    "rep\n\t"
-                    "insb"
-                    : /* no output */
-                    :"D" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
-                    :"di", "cx", "dx");
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+#define CLRINT(x)              ((x) + 0xC92ul)
+#define                CLRBRKADRINT    0x08
+#define                CLRSCSIINT      0x04
+#define                CLRCMDINT       0x02
+#define                CLRSEQINT       0x01
 
-       outb(0, O_SCBCNT(base));
-}
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+#define SCBCNT(x)              ((x) + 0xC9Aul)
+#define                SCBAUTO         0x80
+#define                SCBCNT_MASK     0x1F
 
 /*
- *  How much data should be transferred for this SCSI command?  Stop
- *  at segment sg_last if it's a scatter-gather command so we can
- *  compute underflow easily.
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
  */
-static
-unsigned aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
-{
-       int i, segments;
-       unsigned length;
-       struct scatterlist *sg;
+#define QINFIFO(x)             ((x) + 0xC9Bul)
 
-       segments = cmd->use_sg - sg_last;
-       sg = (struct scatterlist *)cmd->buffer;
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+#define QINCNT(x)              ((x) + 0xC9Cul)
 
-       if (cmd->use_sg) {
-               for (i = length = 0;
-                    i < cmd->use_sg && i < segments;
-                    i++)
-               {
-                       length += sg[i].length;
-               }
-       } else
-               length = cmd->request_bufflen;
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+#define QOUTFIFO(x)            ((x) + 0xC9Dul)
 
-       return(length);
-}
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+#define QOUTCNT(x)             ((x) + 0xC9Eul)
 
-static
-void aic7xxx_sg_check(Scsi_Cmnd *cmd)
-{
-       int i;
-       struct scatterlist *sg = (struct scatterlist *)cmd->buffer;
+#define SCBARRAY(x)            ((x) + 0xCA0ul)
 
-       if (cmd->use_sg) {
-               for (i = 0; i < cmd->use_sg; i++)
-                       if ((unsigned)sg[i].length > 0xffff)
-                               panic("aic7xxx_sg_check: s/g segment > 64k\n");
-       }
-}
+/* ---------------- END AIC-7770 Register Definitions ----------------- */
 
-static
-void aic7xxx_to_scsirate(unsigned char *rate,
-                        unsigned char transfer,
-                        unsigned char offset)
-{
-       int i;
+/* --------------------- AIC-7870-only definitions -------------------- */
 
-       transfer *= 4;
+#define DSPCISTATUS(x)         ((x) + 0xC86ul)
+#define        DFTHRESH        0xC0
 
-       for (i = 0; i < aic7xxx_synctab_max-1; i++) {
+/* Scratch RAM offset definitions */
 
-               if (transfer == aic7xxx_synctab[i].period) {
-                       *rate = (aic7xxx_synctab[i].rate << 4) | (offset & 0xf);
-                       return;
-               }
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the Linux sequencer code. If I can figure out
+ * how to read the EISA configuration info at probe time, the cards could
+ * be run without BIOS support installed
+ */
 
-               if (transfer > aic7xxx_synctab[i].period &&
-                   transfer < aic7xxx_synctab[i+1].period)
-               {
-                       *rate = (aic7xxx_synctab[i+1].rate << 4) |
-                               (offset & 0xf);
-                       return;
-               }
-       }
-       *rate = 0;
-}
+/*
+ * 1 byte per target starting at this address for configuration values
+ */
+#define HA_TARG_SCRATCH(x)     ((x) + 0xC20ul)
 
 /*
- *  Pause the sequencer and wait for it to actually stop - this
- *  is important since the sequencer can disable pausing for critical
- *  sections.
+ * The sequencer will stick the first byte of any rejected message here so
+ * we can see what is getting thrown away.
  */
-#define PAUSE_SEQUENCER(p)     \
-       do {                                                            \
-               outb(0xe, O_HCNTRL(p->base));   /* IRQMS|PAUSE|INTEN */ \
-                                                                       \
-               while ((inb(O_HCNTRL(p->base)) & 0x4) == 0)             \
-                       ;                                               \
-       } while (0)
+#define HA_REJBYTE(x)          ((x) + 0xC31ul)
 
 /*
- *  Unpause the sequencer.  Unremarkable, yet done often enough to
- *  warrant an easy way to do it.
+ * Bit vector of targets that have disconnection disabled.
  */
-#define UNPAUSE_SEQUENCER(p)   \
-       outb(p->unpause, O_HCNTRL(p->base))     /* IRQMS|INTEN */
+#define        HA_DISC_DSB             ((x) + 0xc32ul)
 
 /*
- *  See comments in aic7xxx_loadram() wrt this.
+ * Length of pending message
  */
-#define RESTART_SEQUENCER(p)   \
-       do {                                                    \
-               do {                                            \
-                       outb(0x2, O_SEQCTL(p->base));           \
-                                                               \
-               } while (inb(O_SEQADDR(p->base)) != 0 &&        \
-                        inb(O_SEQADDR(p->base) + 1) != 0);     \
-                                                               \
-               UNPAUSE_SEQUENCER(p);                           \
-       } while (0)
+#define HA_MSG_LEN(x)          ((x) + 0xC34ul)
 
 /*
- *  Since we declared this using SA_INTERRUPT, interrupts should
- *  be disabled all through this function unless we say otherwise.
+ * Outgoing Message Body
  */
-static
-void aic7xxx_isr(int irq)
-{
-       int base, intstat;
-       struct aic7xxx_host *p;
-       
-       p = (struct aic7xxx_host *)aic7xxx_boards[irq]->hostdata;
-       base = p->base;
+#define HA_MSG_START(x)                ((x) + 0xC35ul)
 
-       /*
-        *  Check the startup flag - if no commands have been queued,
-        *  we probably have the interrupt type set wrong.  Reverse
-        *  the stored value and the active one in the host control
-        *  register.
-        */
-       if (p->startup) {
-               p->unpause ^= 0x8;
-               outb(inb(O_HCNTRL(p->base)) ^ 0x8, O_HCNTRL(p->base));
-               return;
-       }
+/*
+ * These are offsets into the card's scratch ram. Some of the values are
+ * specified in the AHA2742 technical reference manual and are initialized
+ * by the BIOS at boot time.
+ */
+#define HA_ARG_1(x)            ((x) + 0xC4Aul) /* sdtr <-> rate parameters */
+#define HA_RETURN_1(x)         ((x) + 0xC4Aul)
+#define                SEND_SENSE      0x80
+#define                SEND_SDTR       0x80
+#define                SEND_WDTR       0x80
+#define                SEND_REJ        0x40
+
+#define HA_SIGSTATE(x)         ((x) + 0xC4Bul) /* value in SCSISIGO */
+#define HA_SCBCOUNT(x)         ((x) + 0xC52ul) /* number of hardware SCBs */
+
+#define HA_FLAGS(x)            ((x) + 0xC53ul) /* TWIN and WIDE bus flags */
+#define                SINGLE_BUS      0x00
+#define                TWIN_BUS        0x01
+#define                WIDE_BUS        0x02
+#define                ACTIVE_MSG      0x20
+#define                IDENTIFY_SEEN   0x40
+#define                RESELECTING     0x80
+
+#define HA_ACTIVE0(x)          ((x) + 0xC54ul) /* Active bits; targets 0-7 */
+#define HA_ACTIVE1(x)          ((x) + 0xC55ul) /* Active bits; targets 8-15 */
+#define        SAVED_TCL(x)            ((x) + 0xC56ul) /* Saved target, channel, LUN */
+#define WAITING_SCBH(x)                ((x) + 0xC57ul) /* Head of disconnected targets list. */
+#define WAITING_SCBT(x)                ((x) + 0xC58ul) /* Tail of disconnected targets list. */
+
+#define HA_SCSICONF(x)         ((x) + 0xC5Aul) /* SCSI config register */
+#define HA_INTDEF(x)           ((x) + 0xC5Cul) /* interrupt def'n register */
+#define HA_HOSTCONF(x)         ((x) + 0xC5Dul) /* host config def'n register */
+
+#define MSG_ABORT              0x06
+#define        MSG_BUS_DEVICE_RESET    0x0c
+#define BUS_8_BIT              0x00
+#define BUS_16_BIT             0x01
+#define BUS_32_BIT             0x02
 
-       /*
-        *  Handle all the interrupt sources - especially for SCSI
-        *  interrupts, we won't get a second chance at them.
-        */
-       intstat = inb(O_INTSTAT(base));
 
-       if (intstat & 0x8) {                            /* BRKADRINT */
+/*
+ *
+ * Define the format of the SEEPROM registers (16 bits).
+ *
+ */
+struct seeprom_config {
 
-               panic("aic7xxx_isr: brkadrint, error = 0x%x, seqaddr = 0x%x\n",
-                     inb(O_ERROR(base)), inw(O_SEQADDR(base)));
-       }
+/*
+ * SCSI ID Configuration Flags
+ */
+#define CFXFER         0x0007          /* synchronous transfer rate */
+#define CFSYNCH                0x0008          /* enable synchronous transfer */
+#define CFDISC         0x0010          /* enable disconnection */
+#define CFWIDEB                0x0020          /* wide bus device */
+/* UNUSED              0x00C0 */
+#define CFSTART                0x0100          /* send start unit SCSI command */
+#define CFINCBIOS      0x0200          /* include in BIOS scan */
+#define CFRNFOUND      0x0400          /* report even if not found */
+/* UNUSED              0xF800 */
+  unsigned short device_flags[16];     /* words 0-15 */
 
-       if (intstat & 0x4) {                            /* SCSIINT */
-
-               int scbptr = inb(O_SCBPTR(base));
-               int status = inb(O_SSTAT1(base));
-               Scsi_Cmnd *cmd;
-
-               cmd = (Scsi_Cmnd *)p->SCB_array[scbptr];
-               if (!cmd) {
-                       printk("aic7xxx_isr: no command for scb (scsiint)\n");
-                       /*
-                        *  Turn off the interrupt and set status
-                        *  to zero, so that it falls through the
-                        *  reset of the SCSIINT code.
-                        */
-                       outb(status, O_CLRSINT1(base));
-                       UNPAUSE_SEQUENCER(p);
-                       outb(0x4, O_CLRINT(base));      /* undocumented */
-                       status = 0;
-               }
-               p->SCB_array[scbptr] = NULL;
+/*
+ * BIOS Control Bits
+ */
+#define CFSUPREM       0x0001          /* support all removeable drives */
+#define CFSUPREMB      0x0002          /* support removeable drives for boot only */
+#define CFBIOSEN       0x0004          /* BIOS enabled */
+/* UNUSED              0x0008 */
+#define CFSM2DRV       0x0010          /* support more than two drives */
+/* UNUSED              0x0060 */
+#define CFEXTEND       0x0080          /* extended translation enabled */
+/* UNUSED              0xFF00 */
+  unsigned short bios_control;         /* word 16 */
 
-               /*
-                *  Only the SCSI Status 1 register has information
-                *  about exceptional conditions that we'd have a
-                *  SCSIINT about; anything in SSTAT0 will be handled
-                *  by the sequencer.  Note that there can be multiple
-                *  bits set.
-                */
-               if (status & 0x80) {                    /* SELTO */
-                       /*
-                        *  Hardware selection timer has expired.  Turn
-                        *  off SCSI selection sequence.
-                        */
-                       outb(0, O_SCSISEQ(base));
-                       cmd->result = DID_TIME_OUT << 16;
-
-                       /*
-                        *  If there's an active message, it belongs to the
-                        *  command that is getting punted - remove it.
-                        */
-                       outb(0, HA_MSG_FLAGS(base));
-
-                       /*
-                        *  Shut off the offending interrupt sources, reset
-                        *  the sequencer address to zero and unpause it,
-                        *  then call the high-level SCSI completion routine.
-                        *
-                        *  WARNING!  This is a magic sequence!  After many
-                        *  hours of guesswork, turning off the SCSI interrupts
-                        *  in CLRSINT? does NOT clear the SCSIINT bit in
-                        *  INTSTAT.  By writing to the (undocumented, unused
-                        *  according to the AIC-7770 manual) third bit of
-                        *  CLRINT, you can clear INTSTAT.  But, if you do it
-                        *  while the sequencer is paused, you get a BRKADRINT
-                        *  with an Illegal Host Address status, so the
-                        *  sequencer has to be restarted first.
-                        */
-                       outb(0x80, O_CLRSINT1(base));   /* CLRSELTIMO */
-                       RESTART_SEQUENCER(p);
-
-                       outb(0x4, O_CLRINT(base));      /* undocumented */
-                       cmd->scsi_done(cmd);
-               }
+/*
+ * Host Adapter Control Bits
+ */
+/* UNUSED              0x0003 */
+#define CFWSTERM       0x0008          /* SCSI high byte termination (wide card) */
+#define CFSTERM                0x0004          /* SCSI low byte termination (non-wide cards) */
+#define CFSPARITY      0x0010          /* SCSI parity */
+/* UNUSED              0x0020 */
+#define CFRESETB       0x0040          /* reset SCSI bus at IC initialization */
+/* UNUSED              0xFF80 */
+  unsigned short adapter_control;      /* word 17 */
 
-               if (status & 0x4) {                     /* SCSIPERR */
-                       /*
-                        *  A parity error has occurred during a data
-                        *  transfer phase.  Flag it and continue.
-                        */
-                       printk("aic7xxx: parity error on target %d, lun %d\n",
-                              cmd->target,
-                              cmd->lun);
-                       aic7xxx_parity(cmd) = DID_PARITY;
-
-                       /*
-                        *  Clear interrupt and resume as above.
-                        */
-                       outb(0x4, O_CLRSINT1(base));    /* CLRSCSIPERR */
-                       UNPAUSE_SEQUENCER(p);
-
-                       outb(0x4, O_CLRINT(base));      /* undocumented */
-               }
+/*
+ * Bus Release, Host Adapter ID
+ */
+#define CFSCSIID       0x000F          /* host adapter SCSI ID */
+/* UNUSED              0x00F0 */
+#define CFBRTIME       0xFF00          /* bus release time */
+  unsigned short brtime_id;            /* word 18 */
 
-               if ((status & (0x8|0x4)) == 0 && status) {
-                       /*
-                        *  We don't know what's going on.  Turn off the
-                        *  interrupt source and try to continue.
-                        */
-                       printk("aic7xxx_isr: sstat1 = 0x%x\n", status);
-                       outb(status, O_CLRSINT1(base));
-                       UNPAUSE_SEQUENCER(p);
-                       outb(0x4, O_CLRINT(base));      /* undocumented */
-               }
-       }
+/*
+ * Maximum targets
+ */
+#define CFMAXTARG      0x00FF  /* maximum targets */
+/* UNUSED              0xFF00 */
+  unsigned short max_targets;          /* word 19 */
 
-       if (intstat & 0x2) {                            /* CMDCMPLT */
+  unsigned short res_1[11];            /* words 20-30 */
+  unsigned short checksum;             /* word 31 */
 
-               int complete, old_scbptr;
-               struct aic7xxx_scb scb;
-               unsigned actual;
-               Scsi_Cmnd *cmd;
+};
 
-               /*
-                *  The sequencer will continue running when it
-                *  issues this interrupt.  There may be >1 commands
-                *  finished, so loop until we've processed them all.
-                */
-               do {
-                       complete = inb(O_QOUTFIFO(base));
-
-                       cmd = (Scsi_Cmnd *)p->SCB_array[complete];
-                       if (!cmd) {
-                               printk("aic7xxx warning: "
-                                      "no command for scb (cmdcmplt)\n");
-                               continue;
-                       }
-                       p->SCB_array[complete] = NULL;
-                       
-                       PAUSE_SEQUENCER(p);
-
-                       /*
-                        *  After pausing the sequencer (and waiting
-                        *  for it to stop), save its SCB pointer, then
-                        *  write in our completed one and read the SCB
-                        *  registers.  Afterwards, restore the saved
-                        *  pointer, unpause the sequencer and call the
-                        *  higher-level completion function - unpause
-                        *  first since we have no idea how long done()
-                        *  will take.
-                        */
-                       old_scbptr = inb(O_SCBPTR(base));
-                       outb(complete, O_SCBPTR(base));
-
-                       aic7xxx_getscb(base, &scb);
-                       outb(old_scbptr, O_SCBPTR(base));
-
-                       UNPAUSE_SEQUENCER(p);
-
-                       cmd->result = scb.target_status |
-                                    (aic7xxx_parity(cmd) << 16);
-
-                       /*
-                        *  Did we underflow?  At this time, there's only
-                        *  one other driver that bothers to check for this,
-                        *  and cmd->underflow seems to be set rather half-
-                        *  heartedly in the higher-level SCSI code.
-                        */
-                       actual = aic7xxx_length(cmd,
-                                               scb.residual_SG_segment_count);
-
-                       actual -= ((scb.residual_data_count[2] << 16) |
-                                  (scb.residual_data_count[1] <<  8) |
-                                  (scb.residual_data_count[0]));
-
-                       if (actual < cmd->underflow) {
-                               printk("aic7xxx: target %d underflow - "
-                                      "wanted (at least) %u, got %u\n",
-                                      cmd->target, cmd->underflow, actual);
-
-                               cmd->result = scb.target_status |
-                                            (DID_UNDERFLOW << 16);
-                       }
-
-                       cmd->scsi_done(cmd);
-
-                       /*
-                        *  Clear interrupt status before checking
-                        *  the output queue again.  This eliminates
-                        *  a race condition whereby a command could
-                        *  complete between the queue poll and the
-                        *  interrupt clearing, so notification of the
-                        *  command being complete never made it back
-                        *  up to the kernel.
-                        */
-                       outb(0x2, O_CLRINT(base));      /* CLRCMDINT */
-
-               } while (inb(O_QOUTCNT(base)));
-       }
 
-       if (intstat & 0x1) {                            /* SEQINT */
+#define AIC7XXX_DEBUG
 
-               unsigned char transfer, offset, rate;
+/*
+ * Pause the sequencer and wait for it to actually stop - this
+ * is important since the sequencer can disable pausing for critical
+ * sections.
+ */
+#define PAUSE_SEQUENCER(p) \
+  outb(p->pause, HCNTRL(p->base));                     \
+  while ((inb(HCNTRL(p->base)) & PAUSE) == 0)          \
+    ;                                                  \
 
-               /*
-                *  Although the sequencer is paused immediately on
-                *  a SEQINT, an interrupt for a SCSIINT or a CMDCMPLT
-                *  condition will have unpaused the sequencer before
-                *  this point.
-                */
-               PAUSE_SEQUENCER(p);
-
-               switch (intstat & 0xf0) {
-                   case 0x00:
-                       panic("aic7xxx_isr: unknown scsi bus phase\n");
-                   case 0x10:
-                       debug("aic7xxx_isr warning: "
-                             "issuing message reject, 1st byte 0x%x\n",
-                             inb(HA_REJBYTE(base)));
-                       break;
-                   case 0x20:
-                       panic("aic7xxx_isr: reconnecting target %d "
-                             "didn't issue IDENTIFY message\n",
-                             (inb(O_SELID(base)) >> 4) & 0xf);
-                   case 0x30:
-                       debug("aic7xxx_isr: sequencer couldn't find match "
-                             "for reconnecting target %d - issuing ABORT\n",
-                             (inb(O_SELID(base)) >> 4) & 0xf);
-                       break;
-                   case 0x40:
-                       transfer = inb(HA_ARG_1(base));
-                       offset = inb(HA_ARG_2(base));
-                       aic7xxx_to_scsirate(&rate, transfer, offset);
-                       outb(rate, HA_RETURN_1(base));
-                       debug_rate(base, rate);
-                       break;
-                   default:
-                       debug("aic7xxx_isr: seqint, "
-                             "intstat = 0x%x, scsisigi = 0x%x\n",
-                             intstat, inb(O_SCSISIGI(base)));
-                       break;
-               }
+/*
+ * Unpause the sequencer. Unremarkable, yet done often enough to
+ * warrant an easy way to do it.
+ */
+#define UNPAUSE_SEQUENCER(p) \
+  outb(p->unpause, HCNTRL(p->base))
 
-               outb(0x1, O_CLRINT(base));              /* CLRSEQINT */
-               UNPAUSE_SEQUENCER(p);
-       }
-}
+/*
+ * Restart the sequencer program from address zero
+ */
+#define RESTART_SEQUENCER(p) \
+  do {                                                 \
+    outb(SEQRESET | FASTMODE, SEQCTL(p->base));        \
+  } while (inb(SEQADDR0(p->base)) != 0 &&              \
+          inb(SEQADDR1(p->base)) != 0);                \
+  UNPAUSE_SEQUENCER(p);
 
 /*
- *  Probing for EISA boards: it looks like the first two bytes
- *  are a manufacturer code - three characters, five bits each:
- *
- *              BYTE 0   BYTE 1   BYTE 2   BYTE 3
- *             ?1111122 22233333 PPPPPPPP RRRRRRRR
- *
- *  The characters are baselined off ASCII '@', so add that value
- *  to each to get the real ASCII code for it.  The next two bytes
- *  appear to be a product and revision number, probably vendor-
- *  specific.  This is what is being searched for at each port,
- *  and what should probably correspond to the ID= field in the
- *  ECU's .cfg file for the card - if your card is not detected,
- *  make sure your signature is listed in the array.
- *
- *  The fourth byte's lowest bit seems to be an enabled/disabled
- *  flag (rest of the bits are reserved?).
+ * If an error occurs during a data transfer phase, run the comand
+ * to completion - it's easier that way - making a note of the error
+ * condition in this location. This then will modify a DID_OK status
+ * into an appropriate error for the higher-level SCSI code.
  */
+#define aic7xxx_error(cmd)     ((cmd)->SCp.Status)
 
-static
-enum aha_type aic7xxx_probe(int slot, int s_base)
-{
-       int i;
-       unsigned char buf[4];
-
-       static struct {
-               int n;
-               unsigned char signature[sizeof(buf)];
-               enum aha_type type;
-       } S[] = {
-               4, { 0x04, 0x90, 0x77, 0x71 }, T_274X,  /* host adapter 274x */
-               4, { 0x04, 0x90, 0x77, 0x70 }, T_274X,  /* motherboard 274x  */
-               4, { 0x04, 0x90, 0x77, 0x56 }, T_284X,  /* 284x, BIOS enabled */
-       };
-
-       for (i = 0; i < sizeof(buf); i++) {
-               /*
-                *  The VL-bus cards need to be primed by
-                *  writing before a signature check.
-                */
-               outb(0x80 + i, s_base);
-               buf[i] = inb(s_base + i);
-       }
+/*
+ * Keep track of the targets returned status.
+ */
+#define aic7xxx_status(cmd)    ((cmd)->SCp.sent_command)
 
-       for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) {
-               if (!memcmp(buf, S[i].signature, S[i].n)) {
-                       /*
-                        *  Signature match on enabled card?
-                        */
-                       if (inb(s_base + 4) & 1)
-                               return(S[i].type);
-                       printk("aic7xxx disabled at slot %d, ignored\n", slot);
-               }
-       }
-       return(T_NONE);
-}
+/*
+ * The position of the SCSI commands scb within the scb array.
+ */
+#define aic7xxx_position(cmd)  ((cmd)->SCp.have_data_in)
 
 /*
- *  Return ' ' for plain 274x, 'T' for twin-channel, 'W' for
- *  wide channel, '?' for anything else.
+ * Since the sequencer code DMAs the scatter-gather structures
+ * directly from memory, we use this macro to assert that the
+ * kernel structure hasn't changed.
  */
+#define SG_STRUCT_CHECK(sg) \
+  ((char *)&(sg).address - (char *)&(sg) != 0 ||  \
+   (char *)&(sg).length  - (char *)&(sg) != 8 ||  \
+   sizeof((sg).address) != 4 ||                   \
+   sizeof((sg).length)  != 4 ||                   \
+   sizeof(sg)           != 12)
 
-static
-char aic7xxx_type(int base)
-{
-       /*
-        *  AIC-7770/7870s can be wired so that, on chip reset,
-        *  the SCSI Block Control register indicates how many
-        *  busses the chip is configured for.  The two high bits
-        *  set indicate a 294x.
-        */
-       switch (inb(O_SBLKCTL(base))) {
-           case 0:
-           case 0xc0:
-               return(' ');
-           case 2:
-           case 0xc2:
-               return('W');
-           case 8:
-               return('T');
-           default:
-               printk("aic7xxx has unknown bus configuration\n");
-               return('?');
-       }
-}
+/*
+ * "Static" structures. Note that these are NOT initialized
+ * to zero inside the kernel - we have to initialize them all
+ * explicitly.
+ *
+ * We support a maximum of one adapter card per IRQ level (see the
+ * rationale for this above). On an interrupt, use the IRQ as an
+ * index into aic7xxx_boards[] to locate the card information.
+ */
+static struct Scsi_Host *aic7xxx_boards[MAXIRQ + 1];
 
-static
-void aic7xxx_loadram(int base)
-{
-       static unsigned char seqprog[] = {
-               /*
-                *  Each sequencer instruction is 29 bits
-                *  long (fill in the excess with zeroes)
-                *  and has to be loaded from least -> most
-                *  significant byte, so this table has the
-                *  byte ordering reversed.
-                */
-#              include "aic7xxx_seq.h"
-       };
+/*
+ * The driver keeps up to four scb structures per card in memory. Only the
+ * first 26 bytes of the structure are valid for the hardware, the rest used
+ * for driver level bookeeping. The driver is further optimized
+ * so that we only have to download the first 19 bytes since as long
+ * as we always use S/G, the last fields should be zero anyway.
+ */
+#ifdef AIC7XXX_USE_SG
+#define SCB_DOWNLOAD_SIZE      19      /* amount to actually download */
+#else
+#define SCB_DOWNLOAD_SIZE      26
+#endif
 
+#define SCB_UPLOAD_SIZE                19      /* amount to actually upload */
+
+struct aic7xxx_scb {
+/* ------------    Begin hardware supported fields    ---------------- */
+/*1 */  unsigned char control;
+#define SCB_NEEDWDTR 0x80                       /* Initiate Wide Negotiation */
+#define SCB_NEEDSDTR 0x40                       /* Initiate Sync Negotiation */
+#define SCB_NEEDDMA  0x08                       /* SCB needs to be DMA'd from
+                                                * from host memory
+                                                */
+#define SCB_REJ_MDP      0x80                   /* Reject MDP message */
+#define SCB_DISEN        0x40                   /* SCB Disconnect enable */
+#define SCB_TE           0x20                   /* Tag enable */
+/*      RESERVED         0x10 */
+#define SCB_WAITING      0x08                   /* Waiting */
+#define SCB_DIS          0x04                   /* Disconnected */
+#define SCB_TAG_TYPE     0x03
+#define         SIMPLE_QUEUE 0x00               /* Simple Queue */
+#define         HEAD_QUEUE   0x01               /* Head of Queue */
+#define         ORD_QUEUE    0x02               /* Ordered Queue */
+/*              ILLEGAL      0x03 */
+/*2 */  unsigned char target_channel_lun;       /* 4/1/3 bits */
+/*3 */  unsigned char SG_segment_count;
+/*7 */  unsigned char SG_list_pointer[4] __attribute__ ((packed));
+/*11*/  unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
+/*12*/  unsigned char SCSI_cmd_length;
+/*14*/  unsigned char RESERVED[2];              /* must be zero */
+/*15*/  unsigned char target_status;
+/*18*/  unsigned char residual_data_count[3];
+/*19*/  unsigned char residual_SG_segment_count;
+/*23*/  unsigned char data_pointer[4] __attribute__ ((packed));
+/*26*/  unsigned char data_count[3];
+/*30*/  unsigned char host_scb[4] __attribute__ ((packed));
+/*31*/  u_char next_waiting;            /* Used to thread SCBs awaiting selection. */
+#define SCB_LIST_NULL 0x10              /* SCB list equivelent to NULL */
+#if 0
        /*
-        *  When the AIC-7770 is paused (as on chip reset), the
-        *  sequencer address can be altered and a sequencer
-        *  program can be loaded by writing it, byte by byte, to
-        *  the sequencer RAM port - the Adaptec documentation
-        *  recommends using REP OUTSB to do this, hence the inline
-        *  assembly.  Since the address autoincrements as we load
-        *  the program, reset it back to zero afterward.  Disable
-        *  sequencer RAM parity error detection while loading, and
-        *  make sure the LOADRAM bit is enabled for loading.
+        *  No real point in transferring this to the
+        *  SCB registers.
         */
-       outb(0x83, O_SEQCTL(base));     /* PERRORDIS|SEQRESET|LOADRAM */
+       unsigned char RESERVED[1];
+#endif
 
-       asm volatile("cld\n\t"
-                    "rep\n\t"
-                    "outsb"
-                    : /* no output */
-                    :"S" (seqprog), "c" (sizeof(seqprog)), "d" (O_SEQRAM(base))
-                    :"si", "cx", "dx");
+       /*-----------------end of hardware supported fields----------------*/
+       struct aic7xxx_scb *next;       /* next ptr when in free list */
+       Scsi_Cmnd          *cmd;        /* Scsi_Cmnd for this scb */
+       int                 state;      /* current state of scb */
+#define SCB_FREE               0x00
+#define SCB_ACTIVE             0x01
+#define SCB_ABORTED            0x02
+#define SCB_DEVICE_RESET       0x04
+#define SCB_IMMED              0x08
+#define SCB_SENSE              0x10
+       unsigned int        position;       /* Position in scb array */
+#ifdef AIC7XXX_USE_SG
+       struct scatterlist  sg;
+       struct scatterlist  sense_sg;
+#endif
+       unsigned char       sense_cmd[6];   /* Allocate 6 characters for sense command */
+};
 
-       /*
-        *  WARNING!  This is a magic sequence!  After extensive
-        *  experimentation, it seems that you MUST turn off the
-        *  LOADRAM bit before you play with SEQADDR again, else
-        *  you will end up with parity errors being flagged on
-        *  your sequencer program.  (You would also think that
-        *  turning off LOADRAM and setting SEQRESET to reset the
-        *  address to zero would work, but you need to do it twice
-        *  for it to take effect on the address.  Timing problem?)
-        */
-       outb(0, O_SEQCTL(base));
-       do {
-               /*
-                *  Actually, reset it until
-                *  the address shows up as
-                *  zero just to be safe..
-                */
-               outb(0x2, O_SEQCTL(base));      /* SEQRESET */
+static struct {
+  unsigned char errno;
+  char *errmesg;
+} hard_error[] = {
+  { ILLHADDR,  "Illegal Host Access" },
+  { ILLSADDR,  "Illegal Sequencer Address referrenced" },
+  { ILLOPCODE, "Illegal Opcode in sequencer program" },
+  { PARERR,    "Sequencer Ram Parity Error" }
+};
 
-       } while (inb(O_SEQADDR(base)) != 0 && inb(O_SEQADDR(base) + 1) != 0);
-}
+static unsigned char
+generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
 
-static
-void aha274x_config(struct aic7xxx_host_config *p, va_list ap)
-{
-       int base = va_arg(ap, int);
+/*
+ * The maximum number of SCBs we could have for ANY type
+ * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
+ * SEQUENCER CODE IF THIS IS MODIFIED!
+ */
+#define AIC7XXX_MAXSCB 16
 
-       /*
-        *  Give the AIC-7770 a reset - reading the 274x's registers
-        *  returns zeroes unless you do.  This forces a pause of the
-        *  Sequencer.
-        */
-       outb(1, O_HCNTRL(base));        /* CHIPRST */
+/*
+ * Define a structure used for each host adapter, only one per IRQ.
+ */
+struct aic7xxx_host {
+  int                      base;             /* card base address */
+  int                      maxscb;           /* hardware SCBs */
+  int                      numscb;           /* current number of scbs */
+  int                      extended;         /* extended xlate? */
+  aha_type                 type;             /* card type */
+  aha_bus_type             bus_type;         /* normal/twin/wide bus */
+  unsigned char            a_scanned;        /* 0 not scanned, 1 scanned */
+  unsigned char            b_scanned;        /* 0 not scanned, 1 scanned */
+  unsigned int             isr_count;        /* Interrupt count */
+  volatile unsigned char   unpause;          /* unpause value for HCNTRL */
+  volatile unsigned char   pause;            /* pause value for HCNTRL */
+  volatile unsigned short  needsdtr_copy;    /* default config */
+  volatile unsigned short  needsdtr;
+  volatile unsigned short  sdtr_pending;
+  volatile unsigned short  needwdtr_copy;    /* default config */
+  volatile unsigned short  needwdtr;
+  volatile unsigned short  wdtr_pending;
+  struct seeprom_config    seeprom;
+  int                      have_seeprom;
+  struct Scsi_Host        *next;             /* allow for multiple IRQs */
+  struct aic7xxx_scb       scb_array[AIC7XXX_MAXSCB];  /* active commands */
+  struct aic7xxx_scb      *free_scb;         /* list of free SCBs */
+};
 
-       p->base = base;
-       p->irq = inb(HA_INTDEF(base)) & 0xf;
-       p->scsi_id = inb(HA_SCSICONF(base)) & 0x7;
+struct aic7xxx_host_config {
+  int              irq;        /* IRQ number */
+  int              base;       /* I/O base */
+  int              maxscb;     /* hardware SCBs */
+  int              unpause;    /* unpause value for HCNTRL */
+  int              pause;      /* pause value for HCNTRL */
+  int              scsi_id;    /* host SCSI ID */
+  int              scsi_id_b;  /* host SCSI ID B channel for twin cards */
+  int              extended;   /* extended xlate? */
+  int              busrtime;   /* bus release time */
+  aha_type         type;       /* card type */
+  aha_bus_type     bus_type;   /* normal/twin/wide bus */
+  aha_status_type  parity;     /* bus parity enabled/disabled */
+  aha_status_type  low_term;   /* bus termination low byte */
+  aha_status_type  high_term;  /* bus termination high byte (wide cards only) */
+};
 
-       /*
-        *  This value for HCNTRL may be changed in the ISR if we
-        *  catch a spurious interrupt right away.
-        */
-       p->unpause = 0xa;
+/*
+ * Valid SCSIRATE values. (p. 3-17)
+ * Provides a mapping of tranfer periods in ns to the proper value to
+ * stick in the scsiscfr reg to use that transfer rate.
+ */
+static struct {
+  short period;
+  short rate;
+  char *english;
+} aic7xxx_syncrates[] = {
+  { 100,   0,  "10.0" },
+  { 125,   1,  "8.0"  },
+  { 150,   2,  "6.67" },
+  { 175,   3,  "5.7"  },
+  { 200,   4,  "5.0"  },
+  { 225,   5,  "4.4"  },
+  { 250,   6,  "4.0"  },
+  { 275,   7,  "3.6"  }
+};
 
-       /*
-        *  XXX - these are values that I don't know how to query
-        *        the hardware for.  Apparently some revision E
-        *        '7770s can have more SCBs, and I don't know how
-        *        to get the "extended translation" flag from the
-        *        EISA data area.
-        */
-       p->maxscb = 4;
-       p->extended = aic7xxx_extended;
+static int num_aic7xxx_syncrates =
+    sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
 
-       /*
-        *  A reminder until this can be detected automatically.
-        */
-       printk("aha274x: extended translation %sabled\n",
-               p->extended ? "en" : "dis");
-}
+#ifdef AIC7XXX_DEBUG
+extern int vsprintf(char *, const char *, va_list);
 
-static
-void aha284x_config(struct aic7xxx_host_config *p, va_list ap)
+static void
+debug(const char *fmt, ...)
 {
-       int base = va_arg(ap, int);
+  va_list ap;
+  char buf[256];
 
-       /*
-        *  Give the AIC-7770 a reset - this forces a pause of the
-        *  Sequencer and returns everything to default values.
-        */
-       outb(1, O_HCNTRL(base));        /* CHIPRST */
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  printk(buf);
+  va_end(ap);
+}
 
-       p->base = base;
-       p->unpause = 0x2;
-       p->irq = inb(HA_INTDEF(base)) & 0xf;
-       p->scsi_id = inb(HA_SCSICONF(base)) & 0x7;
+static void
+debug_config(struct aic7xxx_host_config *p)
+{
+  int host_conf, scsi_conf;
+  unsigned char brelease;
+  unsigned char dfthresh;
+
+  static int DFT[] = { 0, 50, 75, 100 };
+  static int SST[] = { 256, 128, 64, 32 };
+  static char *BUSW[] = { "", "-TWIN", "-WIDE" };
+
+  host_conf = inb(HA_HOSTCONF(p->base));
+  scsi_conf = inb(HA_SCSICONF(p->base));
+
+  /*
+   * The 7870 gets the bus release time and data FIFO threshold
+   * from the serial EEPROM (stored in the config structure) and
+   * scsi_conf register respectively.  The 7770 gets the bus
+   * release time and data FIFO threshold from the scsi_conf and
+   * host_conf registers respectively.
+   */
+  if ((p->type == AIC_274x) || (p->type == AIC_284x))
+  {
+    brelease = scsi_conf & 0x3F;
+    dfthresh = host_conf >> 6;
+  }
+  else
+  {
+    brelease = p->busrtime;
+    dfthresh = scsi_conf >> 6;
+  }
+  if (brelease == 0)
+  {
+    brelease = 2;
+  }
+
+  switch (p->type)
+  {
+    case AIC_274x:
+      printk("AIC7770%s AT EISA SLOT %d:\n", BUSW[p->bus_type], p->base >> 12);
+      break;
+
+    case AIC_284x:
+      printk("AIC7770%s AT VLB SLOT %d:\n", BUSW[p->bus_type], p->base >> 12);
+      break;
+
+    case AIC_7870:
+      printk("AIC7870%s (PCI-bus):\n", BUSW[p->bus_type]);
+      break;
+
+    case AIC_7850:
+      printk("AIC7850%s (PCI-bus):\n", BUSW[p->bus_type]);
+      break;
+
+    case AIC_7872:
+      printk("AIC7872%s (PCI-bus):\n", BUSW[p->bus_type]);
+      break;
+
+    default:
+      panic("aic7xxx debug_config: internal error\n");
+  }
+
+  printk("    irq %d\n"
+        "    bus release time %d bclks\n"
+        "    data fifo threshold %d%%\n",
+        p->irq,
+        brelease,
+        DFT[dfthresh]);
+
+  printk("    SCSI CHANNEL A:\n"
+        "        scsi id %d\n"
+        "        scsi selection timeout %d ms\n"
+        "        scsi bus reset at power-on %sabled\n",
+        scsi_conf & 0x07,
+        SST[(scsi_conf >> 3) & 0x03],
+        (scsi_conf & 0x40) ? "en" : "dis");
+
+  if (((p->type == AIC_274x) || (p->type == AIC_284x)) && p->parity == AIC_UNKNOWN)
+  { /* Set the parity for 7770 based cards. */
+    p->parity = (scsi_conf & 0x20) ? AIC_ENABLED : AIC_DISABLED;
+  }
+  if (p->parity != AIC_UNKNOWN)
+  {
+    printk("        scsi bus parity %sabled\n",
+          (p->parity == AIC_ENABLED) ? "en" : "dis");
+  }
+
+  if (p->type == AIC_274x)
+  {
+    p->low_term = (scsi_conf & 0x80) ? AIC_ENABLED : AIC_DISABLED;
+  }
+  if (p->low_term != AIC_UNKNOWN)
+  {
+    printk("        scsi bus termination (low byte) %sabled\n",
+         (p->low_term == AIC_ENABLED) ? "en" : "dis");
+  }
+  if ((p->bus_type == AIC_WIDE) && (p->high_term != AIC_UNKNOWN))
+  {
+    printk("        scsi bus termination (high byte) %sabled\n",
+         (p->high_term == AIC_ENABLED) ? "en" : "dis");
+  }
+}
+#else
+#  define debug(fmt, args...)
+#  define debug_config(x)
+#endif AIC7XXX_DEBUG
 
-       /*
-        *  XXX - these are values that I don't know how to query
-        *        the hardware for.  Apparently some revision E
-        *        '7770s can have more SCBs, and I don't know how
-        *        to get the "extended translation" flag from the
-        *        onboard memory.
-        */
-       p->maxscb = 4;
-       p->extended = aic7xxx_extended;
+/*
+ * XXX - these options apply unilaterally to _all_ 274x/284x/294x
+ *       cards in the system. This should be fixed, but then,
+ *       does anyone really have more than one in a machine?
+ */
+static int aic7xxx_extended = 0;       /* extended translation on? */
+static int aic7xxx_no_reset = 0;       /* no resetting of SCSI bus */
 
-       /*
-        *  A reminder until this can be detected automatically.
-        */
-       printk("aha284x: extended translation %sabled\n",
-               p->extended ? "en" : "dis");
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_setup
+ *
+ * Description:
+ *   Handle Linux boot parameters.
+ *-F*************************************************************************/
+void
+aic7xxx_setup(char *s, int *dummy)
+{
+  int   i;
+  char *p;
+
+  static struct {
+    char *name;
+    int *flag;
+  } options[] = {
+    { "extended",    &aic7xxx_extended },
+    { "no_reset",    &aic7xxx_no_reset },
+    { NULL,          NULL}
+  };
+
+  for (p = strtok(s, ","); p; p = strtok(NULL, ","))
+  {
+    for (i = 0; options[i].name; i++)
+    {
+      if (!strcmp(options[i].name, p))
+      {
+       *(options[i].flag) = !0;
+      }
+    }
+  }
 }
 
-static
-void aha294x_config(struct aic7xxx_host_config *p, va_list ap)
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_loadseq
+ *
+ * Description:
+ *   Load the sequencer code into the controller memory.
+ *-F*************************************************************************/
+static void
+aic7xxx_loadseq(int base)
 {
-       int error;
-       unsigned long io_port;
-       unsigned char bus, device_fn, irq;
+  static unsigned char seqprog[] = {
+    /*
+     * Each sequencer instruction is 29 bits
+     * long (fill in the excess with zeroes)
+     * and has to be loaded from least -> most
+     * significant byte, so this table has the
+     * byte ordering reversed.
+     */
+#   include "aic7xxx_seq.h"
+  };
+
+  /*
+   * When the AIC-7770 is paused (as on chip reset), the
+   * sequencer address can be altered and a sequencer
+   * program can be loaded by writing it, byte by byte, to
+   * the sequencer RAM port - the Adaptec documentation
+   * recommends using REP OUTSB to do this, hence the inline
+   * assembly. Since the address autoincrements as we load
+   * the program, reset it back to zero afterward. Disable
+   * sequencer RAM parity error detection while loading, and
+   * make sure the LOADRAM bit is enabled for loading.
+   */
+  outb(PERRORDIS | SEQRESET | LOADRAM, SEQCTL(base));
+
+  asm volatile("cld\n\t"
+              "rep\n\t"
+              "outsb"
+              : /* no output */
+              :"S" (seqprog), "c" (sizeof(seqprog)), "d" (SEQRAM(base))
+              :"si", "cx", "dx");
+
+  /*
+   * WARNING!  This is a magic sequence!  After extensive
+   * experimentation, it seems that you MUST turn off the
+   * LOADRAM bit before you play with SEQADDR again, else
+   * you will end up with parity errors being flagged on
+   * your sequencer program. (You would also think that
+   * turning off LOADRAM and setting SEQRESET to reset the
+   * address to zero would work, but you need to do it twice
+   * for it to take effect on the address. Timing problem?)
+   */
+  do {
+    /*
+     * Actually, reset it until
+     * the address shows up as
+     * zero just to be safe..
+     */
+    outb(SEQRESET | FASTMODE, SEQCTL(base));
+  } while ((inb(SEQADDR0(base)) != 0) && (inb(SEQADDR1(base)) != 0));
+}
 
-       bus = va_arg(ap, unsigned char);
-       device_fn = va_arg(ap, unsigned char);
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_delay
+ *
+ * Description:
+ *   Delay for specified amount of time.
+ *-F*************************************************************************/
+static void
+aic7xxx_delay(int seconds)
+{
+  unsigned long i;
 
-       /*
-        *  Read esundry information from PCI BIOS.
-        */
-       error = pcibios_read_config_dword(bus,
-                                         device_fn,
-                                         PCI_BASE_ADDRESS_0,
-                                         &io_port);
-       if (error) {
-               panic("aha294x_config: error %s reading i/o port\n",
-                     pcibios_strerror(error));
-       }
+  i = jiffies + (seconds * 100);  /* compute time to stop */
 
-       error = pcibios_read_config_byte(bus,
-                                        device_fn,
-                                        PCI_INTERRUPT_LINE,
-                                        &irq);
-       if (error) {
-               panic("aha294x_config: error %s reading irq\n",
-                     pcibios_strerror(error));
-       }
+  while (jiffies < i)
+  {
+    ;  /* Do nothing! */
+  }
+}
 
-       /*
-        *  Make the base I/O register look like EISA and VL-bus.
-        */
-       p->base = io_port - 0xc01;
+/*+F*************************************************************************
+ * Function:
+ *   rcs_version
+ *
+ * Description:
+ *   Return a string containing just the RCS version number from either
+ *   an Id or Revison RCS clause.
+ *-F*************************************************************************/
+const char *
+rcs_version(const char *version_info)
+{
+  static char buf[10];
+  char *bp, *ep;
+
+  bp = NULL;
+  strcpy(buf, "????");
+  if (!strncmp(version_info, "$Id: ", 5))
+  {
+    if ((bp = strchr(version_info, ' ')) != NULL)
+    {
+      bp++;
+      if ((bp = strchr(bp, ' ')) != NULL)
+      {
+       bp++;
+      }
+    }
+  }
+  else
+  {
+    if (!strncmp(version_info, "$Revision: ", 11))
+    {
+      if ((bp = strchr(version_info, ' ')) != NULL)
+      {
+       bp++;
+      }
+    }
+  }
+
+  if (bp != NULL)
+  {
+    if ((ep = strchr(bp, ' ')) != NULL)
+    {
+      register int len = ep - bp;
+
+      strncpy(buf, bp, len);
+      buf[len] = '\0';
+    }
+  }
+
+  return buf;
+}
 
-       /*
-        *  Give the AIC-7870 a reset - this forces a pause of the
-        *  Sequencer and returns everything to default values.
-        */
-       outb(1, O_HCNTRL(p->base));     /* CHIPRST */
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_info
+ *
+ * Description:
+ *   Return a string describing the driver.
+ *-F*************************************************************************/
+const char *
+aic7xxx_info(struct Scsi_Host *notused)
+{
+  static char buffer[128];
 
-       p->irq = irq;
-       p->maxscb = 16;
-       p->unpause = 0xa;
+  strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+  strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
+  strcat(buffer, "/");
+  strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
+  strcat(buffer, "/");
+  strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
 
-       /*
-        *  XXX - these are values that I don't know how to query
-        *        the hardware for, so for now the SCSI host ID is
-        *        hardwired to 7, and the "extended translation"
-        *        flag is taken from boot-time flags.
-        */
-       p->scsi_id = 7;
-       p->extended = aic7xxx_extended;
+  return buffer;
+}
 
-       /*
-        *  XXX - force data fifo threshold to 100%.  Why does this
-        *        need to be done?
-        */
-#      define  DFTHRESH        3
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_putscb
+ *
+ * Description:
+ *   Transfer a SCB to the controller.
+ *-F*************************************************************************/
+static void
+aic7xxx_putscb(int base, struct aic7xxx_scb *scb)
+{
+#ifdef AIC7XXX_USE_DMA
+  /*
+   * All we need to do, is to output the position
+   * of the SCB in the SCBARRAY to the QINFIFO
+   * of the host adapter.
+   */
+  outb(scb->position, QINFIFO(base));
+#else
+  /*
+   * By turning on the SCB auto increment, any reference
+   * to the SCB I/O space postincrements the SCB address
+   * we're looking at. So turn this on and dump the relevant
+   * portion of the SCB to the card.
+   */
+  outb(SCBAUTO, SCBCNT(base));
+
+  asm volatile("cld\n\t"
+              "rep\n\t"
+              "outsb"
+              : /* no output */
+              :"S" (scb), "c" (SCB_DOWNLOAD_SIZE), "d" (SCBARRAY(base))
+              :"si", "cx", "dx");
+
+  outb(0, SCBCNT(base));
+#endif
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_putdmascb
+ *
+ * Description:
+ *   DMA a SCB to the controller.
+ *-F*************************************************************************/
+static void
+aic7xxx_putdmascb(int base, struct aic7xxx_scb *scb)
+{
+  /*
+   * By turning on the SCB auto increment, any reference
+   * to the SCB I/O space postincrements the SCB address
+   * we're looking at. So turn this on and dump the relevant
+   * portion of the SCB to the card.
+   */
+  outb(SCBAUTO, SCBCNT(base));
+
+  asm volatile("cld\n\t"
+              "rep\n\t"
+              "outsb"
+              : /* no output */
+              :"S" (scb), "c" (31), "d" (SCBARRAY(base))
+              :"si", "cx", "dx");
+
+  outb(0, SCBCNT(base));
+}
 
-       outb(DFTHRESH << 6, O_DSPCISTATUS(p->base));
-       outb(p->scsi_id | (DFTHRESH << 6), HA_SCSICONF(p->base));
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_getscb
+ *
+ * Description:
+ *   Get a SCB from the controller.
+ *-F*************************************************************************/
+static void
+aic7xxx_getscb(int base, struct aic7xxx_scb *scb)
+{
+  /*
+   * This is almost identical to aic7xxx_putscb().
+   */
+  outb(SCBAUTO, SCBCNT(base));
+
+  asm volatile("cld\n\t"
+              "rep\n\t"
+              "insb"
+              : /* no output */
+              :"D" (scb), "c" (SCB_UPLOAD_SIZE), "d" (SCBARRAY(base))
+              :"di", "cx", "dx");
+
+  outb(0, SCBCNT(base));
+}
 
-       /*
-        *  A reminder until this can be detected automatically.
-        */
-       printk("aha294x: extended translation %sabled\n",
-               p->extended ? "en" : "dis");
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_length
+ *
+ * Description:
+ *   How much data should be transferred for this SCSI command? Stop
+ *   at segment sg_last if it's a scatter-gather command so we can
+ *   compute underflow easily.
+ *-F*************************************************************************/
+static unsigned
+aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
+{
+  int i, segments;
+  unsigned length;
+  struct scatterlist *sg;
+
+  segments = cmd->use_sg - sg_last;
+  sg = (struct scatterlist *) cmd->buffer;
+
+  if (cmd->use_sg)
+  {
+    for (i = length = 0; i < cmd->use_sg && i < segments; i++)
+    {
+      length += sg[i].length;
+    }
+  }
+  else
+  {
+    length = cmd->request_bufflen;
+  }
+
+  return(length);
 }
 
-static
-int aic7xxx_register(Scsi_Host_Template *template, enum aha_type type, ...)
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_scsirate
+ *
+ * Description:
+ *   Look up the valid period to SCSIRATE conversion in our table
+ *-F*************************************************************************/
+static void
+aic7xxx_scsirate(unsigned char *scsirate, unsigned char period,
+                unsigned char offset, int target)
 {
-       va_list ap;
-       int i, base;
-       struct Scsi_Host *host;
-       struct aic7xxx_host *p;
-       struct aic7xxx_host_config config;
-
-       va_start(ap, type);
-       
-       switch (type) {
-           case T_274X:
-               aha274x_config(&config, ap);
-               break;
-           case T_284X:
-               aha284x_config(&config, ap);
-               break;
-           case T_294X:
-               aha294x_config(&config, ap);
-               break;
-           default:
-               panic("aic7xxx_register: internal error\n");
+  int i;
+
+  for (i = 0; i < num_aic7xxx_syncrates; i++)
+  {
+    if ((aic7xxx_syncrates[i].period - period) >= 0)
+    {
+      *scsirate = (aic7xxx_syncrates[i].rate << 4) | (offset & 0x0F);
+      printk("aic7xxx: target %d now synchronous at %sMb/s, offset = 0x%x\n",
+            target, aic7xxx_syncrates[i].english, offset);
+      return;
+    }
+  }
+
+  /*
+   * Default to asyncronous transfer
+   */
+  *scsirate = 0;
+  printk("aic7xxx: target %d using asynchronous transfers\n", target);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_isr
+ *
+ * Description:
+ *   SCSI controller interrupt handler.
+ *
+ *   NOTE: Since we declared this using SA_INTERRUPT, interrupts should
+ *         be disabled all through this function unless we say otherwise.
+ *-F*************************************************************************/
+static void
+aic7xxx_isr(int irq, struct pt_regs * regs)
+{
+  int base, intstat;
+  struct aic7xxx_host *p;
+  struct aic7xxx_scb *scb;
+  unsigned char active, ha_flags, transfer;
+  unsigned char scsi_id, bus_width;
+  unsigned char offset, rate, scratch;
+  unsigned char max_offset;
+  unsigned char head, tail;
+  unsigned short target_mask;
+  long flags;
+  void *addr;
+  int actual;
+  int target, tcl;
+  int scbptr;
+  Scsi_Cmnd *cmd;
+#if 0
+static int_count = 0;
+#endif
+
+  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+#ifdef AIC7XXX_SHARE_IRQS
+  /*
+   * Search for the host with a pending interrupt.
+   */
+  while ((p != NULL) && !(inb(INTSTAT(p->base)) & INT_PEND))
+  {
+    p = (struct aic7xxx_host *) p->next->hostdata;
+  }
+  if (p == NULL)
+  {
+    printk("aic7xxx_isr: Encountered spurious interrupt.\n");
+    return;
+  }
+#endif
+  base = p->base;
+  if (p->isr_count == 0xffffffff)
+  {
+    p->isr_count = 0;
+  }
+  else
+  {
+    p->isr_count = p->isr_count + 1;
+  }
+  if ((p->a_scanned == 0) && (p->isr_count == 1))
+  {
+    /* Allow for one interrupt when the card is enabled. */
+    return;
+  }
+
+  /*
+   * Handle all the interrupt sources - especially for SCSI
+   * interrupts, we won't get a second chance at them.
+   */
+  intstat = inb(INTSTAT(base));
+
+  if (intstat & BRKADRINT)
+  {
+    int i;
+    unsigned char errno = inb(ERROR(base));
+
+    printk("aic7xxx_isr: brkadrint (0x%x):\n", errno);
+    for (i = 0; i < NUMBER(hard_error); i++)
+    {
+      if (errno & hard_error[i].errno)
+      {
+       printk("  %s\n", hard_error[i].errmesg);
+      }
+    }
+
+    panic("aic7xxx_isr: brkadrint, error = 0x%x, seqaddr = 0x%x\n",
+         inb(ERROR(base)),
+         inb(SEQADDR1(base)) << 8 | inb(SEQADDR0(base)));
+  }
+
+  if (intstat & SEQINT)
+  {
+    /*
+     * Although the sequencer is paused immediately on
+     * a SEQINT, an interrupt for a SCSIINT or a CMDCMPLT
+     * condition will have unpaused the sequencer before
+     * this point.
+     */
+    PAUSE_SEQUENCER(p);
+
+    switch (intstat & SEQINT_MASK)
+    {
+      case BAD_PHASE:
+       panic("aic7xxx_isr: unknown scsi bus phase\n");
+
+      case SEND_REJECT:
+       debug("aic7xxx_isr warning: issuing message reject, 1st byte 0x%x\n",
+             inb(HA_REJBYTE(base)));
+       break;
+
+      case NO_IDENT:
+       panic("aic7xxx_isr: reconnecting target %d at seqaddr 0x%x "
+             "didn't issue IDENTIFY message\n",
+             (inb(SELID(base)) >> 4) & 0x0F,
+             (inb(SEQADDR1(base)) << 8) | inb(SEQADDR0(base)));
+       break;
+
+      case NO_MATCH:
+       tcl = inb(SCBARRAY(base) + 1);
+       target = (tcl >> 4) & 0x0F;
+       /* Purposefully mask off the top bit of targets 8-15. */
+       target_mask = 0x01 << (target & 0x07);
+
+       debug("aic7xxx_isr: sequencer couldn't find match "
+             "for reconnecting target %d, channel %d, lun %d - "
+             "issuing ABORT\n", target, (tcl & 0x08) >> 3, tcl & 0x07);
+       if (tcl & 0x88)
+       {
+         /* Second channel stores its info in byte
+          * two of HA_ACTIVE
+          */
+         active = inb(HA_ACTIVE1(base));
+         active = active & ~(target_mask);
+         outb(active, HA_ACTIVE1(base));
        }
-       va_end(ap);
+       else
+       {
+         active = inb(HA_ACTIVE0(base));
+         active = active & ~(target_mask);
+         outb(active, HA_ACTIVE0(base));
+       }
+#ifdef AIC7XXX_USE_DMA
+       outb(SCB_NEEDDMA, SCBARRAY(base));
+#endif
 
-       base = config.base;
+       /*
+        * Check out why this use to be outb(0x80, CLRINT(base))
+        * clear the timeout
+        */
+       outb(CLRSELTIMEO, CLRSINT1(base));
+       RESTART_SEQUENCER(p);
+       break;
 
+      case MSG_SDTR:
        /*
-        *  The IRQ level in i/o port 4 maps directly onto the real
-        *  IRQ number.  If it's ok, register it with the kernel.
-        *
-        *  NB. the Adaptec documentation says the IRQ number is only
-        *      in the lower four bits; the ECU information shows the
-        *      high bit being used as well.  Which is correct?
+        * Help the sequencer to translate the negotiated
+        * transfer rate. Transfer is 1/4 the period
+        * in ns as is returned by the sync negotiation
+        * message. So, we must multiply by four.
         */
-       if (config.irq < 9 || config.irq > 15) {
-               printk("aic7xxx uses unsupported IRQ level, ignoring\n");
-               return(0);
+       transfer = (inb(HA_ARG_1(base)) << 2);
+       offset = inb(ACCUM(base));
+       scsi_id = inb(SCSIID(base)) >> 0x04;
+       if (inb(SBLKCTL(base)) & 0x08)
+       {
+         scsi_id = scsi_id + 8;  /* B channel */
        }
-       
+       target_mask = (0x01 << scsi_id);
+       scratch = inb(HA_TARG_SCRATCH(base) + scsi_id);
        /*
-        *  Lock out other contenders for our i/o space.
+        * The maximum offset for a wide device is 0x08; for a
+        * 8-bit bus device the maximum offset is 0x0f.
         */
-       snarf_region(O_MINREG(base), O_MAXREG(base)-O_MINREG(base));
-
+       if (scratch & 0x80)
+       {
+         max_offset = 0x08;
+       }
+       else
+       {
+         max_offset = 0x0f;
+       }
+       aic7xxx_scsirate(&rate, transfer, MIN(offset, max_offset), scsi_id);
        /*
-        *  Any card-type-specific adjustments before we register
-        *  the scsi host(s).
+        * Preserve the wide transfer flag.
         */
-       switch (aic7xxx_type(base)) {
-           case 'T':
-               printk("aic7xxx warning: ignoring channel B of 274x-twin\n");
-               break;
-           case ' ':
-               break;
-           default:
-               printk("aic7xxx is an unsupported type, ignoring\n");
-               return(0);
+       rate = rate | (scratch & 0x80);
+       outb(rate, HA_TARG_SCRATCH(base) + scsi_id);
+       outb(rate, SCSIRATE(base));
+       if ((rate & 0xf) == 0)
+       { /*
+          * The requested rate was so low that asynchronous transfers
+          * are faster (not to mention the controller won't support
+          * them), so we issue a reject to ensure we go to asynchronous
+          * transfers.
+          */
+          outb(SEND_REJ, HA_RETURN_1(base));
+       }
+       else
+       {
+         /*
+          * See if we initiated Sync Negotiation
+          */
+         if (p->sdtr_pending & target_mask)
+         {
+           /*
+            * Don't send an SDTR back to the target.
+            */
+           outb(0, HA_RETURN_1(base));
+         }
+         else
+         {
+           /*
+            * Send our own SDTR in reply.
+            */
+           printk("Sending SDTR!!\n");
+           outb(SEND_SDTR, HA_RETURN_1(base));
+         }
        }
-
        /*
-        *  Before registry, make sure that the offsets of the
-        *  struct scatterlist are what the sequencer will expect,
-        *  otherwise disable scatter-gather altogether until someone
-        *  can fix it.  This is important since the sequencer will
-        *  DMA elements of the SG array in while executing commands.
+        * Clear the flags.
         */
-       if (template->sg_tablesize != SG_NONE) {
-               struct scatterlist sg;
+       p->needsdtr = p->needsdtr & ~target_mask;
+       p->sdtr_pending = p->sdtr_pending & ~target_mask;
+       break;
+
+      case MSG_WDTR:
+      {
+       bus_width = inb(ACCUM(base));
+       scsi_id = inb(SCSIID(base)) >> 0x04;
+       if (inb(SBLKCTL(base)) & 0x08)
+       {
+         scsi_id = scsi_id + 8;  /* B channel */
+       }
+       printk("Received MSG_WDTR, scsi_id = %d, "
+              "needwdtr = 0x%x\n", scsi_id, p->needwdtr);
+       scratch = inb(HA_TARG_SCRATCH(base) + scsi_id);
 
-               if (SG_STRUCT_CHECK(sg)) {
-                       printk("aic7xxx warning: kernel scatter-gather "
-                              "structures changed, disabling it\n");
-                       template->sg_tablesize = SG_NONE;
-               }
+       target_mask = (0x01 << scsi_id);
+       if (p->wdtr_pending & target_mask)
+       {
+         /*
+          * Don't send an WDTR back to the target, since we asked first.
+          */
+         outb(0, HA_RETURN_1(base));
+         switch (bus_width)
+         {
+           case BUS_8_BIT:
+             scratch = scratch & 0x7F;
+             break;
+
+           case BUS_16_BIT:
+             printk("aic7xxx_isr: target %d using 16 bit transfers\n",
+                    scsi_id);
+             scratch = scratch | 0x80;
+             break;
+         }
        }
-       
+       else
+       {
+         /*
+          * Send our own WDTR in reply.
+          */
+         printk("Will send WDTR!!\n");
+         switch (bus_width)
+         {
+           case BUS_8_BIT:
+             scratch = scratch & 0x7F;
+             break;
+
+           case BUS_32_BIT:
+             /* Negotiate 16 bits. */
+             bus_width = BUS_16_BIT;
+             /* Yes, we mean to fall thru here */
+
+           case BUS_16_BIT:
+             printk("aic7xxx_isr: target %d using 16 bit transfers\n",
+                    scsi_id);
+             scratch = scratch | 0x80;
+             break;
+         }
+         outb(bus_width | SEND_WDTR, HA_RETURN_1(base));
+       }
+       p->needwdtr = p->needwdtr & ~target_mask;
+       p->wdtr_pending = p->wdtr_pending & ~target_mask;
+       outb(scratch, HA_TARG_SCRATCH(base) + scsi_id);
+       outb(scratch, SCSIRATE(base));
+       break;
+      }
+
+      case MSG_REJECT:
+      {
        /*
-        *  Register each "host" and fill in the returned Scsi_Host
-        *  structure as best we can.  Some of the parameters aren't
-        *  really relevant for bus types beyond ISA, and none of the
-        *  high-level SCSI code looks at it anyway.. why are the fields
-        *  there?  Also save the pointer so that we can find the
-        *  information when an IRQ is triggered.
+        * What we care about here is if we had an
+        * outstanding SDTR or WDTR message for this
+        * target. If we did, this is a signal that
+        * the target is refusing negotiation.
         */
-       host = scsi_register(template, sizeof(struct aic7xxx_host));
-       host->can_queue = config.maxscb;
-       host->this_id = config.scsi_id;
-       host->irq = config.irq;
 
-       aic7xxx_boards[config.irq] = host;
-       
-       p = (struct aic7xxx_host *)host->hostdata;
-       for (i = 0; i < AIC7XXX_MAXSCB; i++)
-               p->SCB_array[i] = NULL;
+       unsigned char targ_scratch, scsi_id;
+       unsigned short mask;
 
-       p->base = config.base;
-       p->maxscb = config.maxscb;
-       p->extended = config.extended;
+       scsi_id = inb(SCSIID(base)) >> 0x04;
+       if (inb(SBLKCTL(base)) & 0x08)
+       {
+         scsi_id = scsi_id + 8;
+       }
 
-       /*
-        *  The interrupt trigger is different depending
-        *  on whether the card is EISA or VL-bus - sometimes.
-        *  The startup variable will be cleared once the first
-        *  command is queued, and is checked in the isr to
-        *  try and detect when the interrupt type is set
-        *  incorrectly, triggering an interrupt immediately.
-        *  This is now just set on a per-card-type basis.
-        */
-       p->unpause = config.unpause;
-       p->startup = !0;
+       mask = (0x01 << scsi_id);
 
-       /*
-        *  Register IRQ with the kernel _after_ the host information
-        *  is set up, in case we take an interrupt right away, due to
-        *  the interrupt type being set wrong.
-        */
-       if (request_irq(config.irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx")) {
-               printk("aic7xxx couldn't register irq %d, ignoring\n",
-                      config.irq);
-               return(0);
-       }
+       targ_scratch = inb(HA_TARG_SCRATCH(base) + scsi_id);
 
-       /*
-        *  Print out debugging information before re-enabling
-        *  the card - a lot of registers on it can't be read
-        *  when the sequencer is active.
-        */
-#ifdef AIC7XXX_DEBUG
-       debug_config(type, &config);
+       if (p->wdtr_pending & mask)
+       {
+         /*
+          * note 8bit xfers and clear flag
+          */
+         targ_scratch = targ_scratch & 0x7F;
+         p->needwdtr = p->needwdtr & ~mask;
+         p->wdtr_pending = p->wdtr_pending & ~mask;
+         outb(targ_scratch, HA_TARG_SCRATCH(base) + scsi_id);
+         printk("aic7xxx: target %d refusing WIDE negotiation. Using "
+                "8 bit transfers\n", scsi_id);
+       }
+       else
+       {
+         if (p->sdtr_pending & mask)
+         {
+           /*
+            * note asynch xfers and clear flag
+            */
+           targ_scratch = targ_scratch & 0xF0;
+           p->needsdtr = p->needsdtr & ~mask;
+           p->sdtr_pending = p->sdtr_pending & ~mask;
+           outb(targ_scratch, HA_TARG_SCRATCH(base) + scsi_id);
+           printk("aic7xxx: target %d refusing syncronous negotiation. Using "
+                  "asyncronous transfers\n", scsi_id);
+         }
+         /*
+          * Otherwise, we ignore it.
+          */
+       }
+       outb(targ_scratch, HA_TARG_SCRATCH(base) + scsi_id);
+       outb(targ_scratch, SCSIRATE(base));
+       break;
+      }
+
+      case BAD_STATUS:
+       scsi_id = inb(SCSIID(base)) >> 0x04;
+       scbptr = inb(SCBPTR(base));
+       scb = &(p->scb_array[scbptr]);
+       outb(0, HA_RETURN_1(base));   /* CHECK_CONDITION may change this */
+       if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+       {
+         printk("aic7xxx_isr: referenced scb not valid "
+                "during seqint 0x%x scb(%d) state(%x), cmd(%x)\n",
+                intstat, scbptr, scb->state, (unsigned int) scb->cmd);
+       }
+       else
+       {
+         cmd = scb->cmd;
+         aic7xxx_getscb(base, scb);
+         aic7xxx_status(cmd) = scb->target_status;
+
+         cmd->result = cmd->result | scb->target_status;
+
+         /*
+          * This test is just here for debugging purposes.
+          * It will go away when the timeout problem is resolved.
+          */
+         switch (status_byte(scb->target_status))
+         {
+           case GOOD:
+             break;
+
+           case CHECK_CONDITION:
+             if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
+             {
+               void         *req_buf;
+#ifndef AIC7XXX_USE_SG
+               unsigned int  req_buflen;
 #endif
 
-       /*
-        *  Load the sequencer program, then re-enable the board -
-        *  resetting the AIC-7770 disables it, leaving the lights
-        *  on with nobody home.  On the PCI bus you *may* be home,
-        *  but then your mailing address is dynamically assigned
-        *  so no one can find you anyway :-)
-        */
-       aic7xxx_loadram(base);
-       if (type != T_294X)
-               outb(1, O_BCTL(base));  /* ENABLE */
-
-       /*
-        *  Set the host adapter registers to indicate that synchronous
-        *  negotiation should be attempted the first time the targets
-        *  are communicated with.  Also initialize the active message
-        *  flag to indicate that there is no message.
-        */
-       outb(0xff, HA_NEEDSDTR(base));
-       outb(0, HA_MSG_FLAGS(base));
+               /* Update the timeout for the SCSI command. */
+/*                update_timeout(cmd, SENSE_TIMEOUT); */
 
-       /*
-        *  For reconnecting targets, the sequencer code needs to
-        *  know how many SCBs it has to search through.
-        */
-       outb(config.maxscb, HA_SCBCOUNT(base));
+               /* Send a sense command to the requesting target. */
+               cmd->flags = cmd->flags | WAS_SENSE;
+               memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+                      sizeof(generic_sense));
 
-       /*
-        *  Unpause the sequencer before returning and enable
-        *  interrupts - we shouldn't get any until the first
-        *  command is sent to us by the high-level SCSI code.
-        */
-       UNPAUSE_SEQUENCER(p);
-       return(1);
-}
+               scb->sense_cmd[1] = cmd->lun << 5;
+               scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
 
-int aic7xxx_detect(Scsi_Host_Template *template)
-{
-       enum aha_type type;
-       int found = 0, slot, base;
+#ifdef AIC7XXX_USE_SG
+               scb->sense_sg.address = (char *) &cmd->sense_buffer;
+               scb->sense_sg.length = sizeof(cmd->sense_buffer);
+               req_buf = &scb->sense_sg;
+#else
+               req_buf = &cmd->sense_buffer;
+               req_buflen = sizeof(cmd->sense_buffer);
+#endif
+               cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+               memset(scb, 0, SCB_DOWNLOAD_SIZE);
+               scb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+                   ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+               addr = scb->sense_cmd;
+               scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+               memcpy(scb->SCSI_cmd_pointer, &addr,
+                      sizeof(scb->SCSI_cmd_pointer));
+#ifdef AIC7XXX_USE_SG
+               scb->SG_segment_count = 1;
+               memcpy (scb->SG_list_pointer, &req_buf,
+                       sizeof(scb->SG_list_pointer));
+#else
+               scb->SG_segment_count = 0;
+               memcpy (scb->data_pointer, &req_buf,
+                       sizeof(scb->data_pointer));
+               memcpy (scb->data_count, &req_buflen, 3);
+#endif
 
-       /*
-        *  EISA/VL-bus card signature probe.
-        */
-       for (slot = MINSLOT; slot <= MAXSLOT; slot++) {
+               outb(SCBAUTO, SCBCNT(base));
+               asm volatile("cld\n\t"
+                            "rep\n\t"
+                            "outsb"
+                            : /* no output */
+                            :"S" (scb), "c" (SCB_DOWNLOAD_SIZE), "d" (SCBARRAY(base))
+                            :"si", "cx", "dx");
+               outb(0, SCBCNT(base));
+               outb(SCB_LIST_NULL, (SCBARRAY(base) + 30));
 
-               base = SLOTBASE(slot);
-               
-               if (check_region(O_MINREG(base),
-                                O_MAXREG(base)-O_MINREG(base)))
+               /*
+                * Add this SCB to the "waiting for selection" list.
+                */
+               head = inb(WAITING_SCBH(base));
+               tail = inb(WAITING_SCBT(base));
+               if (head & SCB_LIST_NULL)
+               { /* list is empty */
+                 head = scb->position;
+                 tail = SCB_LIST_NULL;
+               }
+               else
                {
-                       /*
-                        *  Some other driver has staked a
-                        *  claim to this i/o region already.
-                        */
-                       continue;
+                 if (tail & SCB_LIST_NULL)
+                 { /* list has one element */
+                   tail = scb->position;
+                   outb(head, SCBPTR(base));
+                   outb(tail, (SCBARRAY(base) + 30));
+                 }
+                 else
+                 { /* list has more than one element */
+                   outb(tail, SCBPTR(base));
+                   tail = scb->position;
+                   outb(tail, (SCBARRAY(base) + 30));
+                 }
                }
+               outb(head, WAITING_SCBH(base));
+               outb(tail, WAITING_SCBT(base));
+               outb(SEND_SENSE, HA_RETURN_1(base));
+             }  /* first time sense, no errors */
+             else
+             {
+               /*
+                * Indicate that we asked for sense, have the sequencer do
+                * a normal command complete, and have the scsi driver handle
+                * this condition.
+                */
+               cmd->flags = cmd->flags | ASKED_FOR_SENSE;
+             }
+             break;
+
+           case BUSY:
+             printk("aic7xxx_isr: Target busy\n");
+             if (!aic7xxx_error(cmd))
+             {
+               aic7xxx_error(cmd) = DID_BUS_BUSY;
+             }
+             break;
+
+           case QUEUE_FULL:
+             printk("aic7xxx_isr: Queue full\n");
+             if (!aic7xxx_error(cmd))
+             {
+               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+             }
+             break;
 
-               type = aic7xxx_probe(slot, O_BIDx(base));
-
-               if (type != T_NONE) {
-                       /*
-                        *  We "find" a 274x if we locate the card
-                        *  signature and we can set it up and register
-                        *  it with the kernel without incident.
-                        */
-                       found += aic7xxx_register(template, type, base);
-               }
+           default:
+             printk("aic7xxx_isr: Unexpected target status 0x%x\n",
+                    scb->target_status);
+             if (!aic7xxx_error(cmd))
+             {
+               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+             }
+             break;
+         }  /* end switch */
+       }  /* end else of */
+       break;
+
+      case RESIDUAL:
+       scbptr = inb(SCBPTR(base));
+       scb = &(p->scb_array[scbptr]);
+       if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+       {
+         printk("aic7xxx_isr: referenced scb not valid "
+                "during seqint 0x%x scb(%d) state(%x), cmd(%x)\n",
+                intstat, scbptr, scb->state, (unsigned int) scb->cmd);
        }
-
-       /*
-        *  PCI-bus probe.
-        */
-       if (pcibios_present()) {
-               int index = 0;
-               unsigned char bus, device_fn;
-
-               while (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
-                                           PCI_DEVICE_ID_ADAPTEC_2940,
-                                           index,
-                                           &bus,
-                                           &device_fn))
-               {
-                       found += aic7xxx_register(template, T_294X,
-                                                 bus, device_fn);
-                       index += 1;
-               }
+       else
+       {
+         cmd = scb->cmd;
+         /*
+          *  Don't destroy valid residual information with
+          *  residual coming from a check sense operation.
+          */
+         if (!(cmd->flags & WAS_SENSE))
+         {
+           /*
+            *  We had an underflow. At this time, there's only
+            *  one other driver that bothers to check for this,
+            *  and cmd->underflow seems to be set rather half-
+            *  heartedly in the higher-level SCSI code.
+            */
+           actual = aic7xxx_length(cmd, scb->residual_SG_segment_count);
+
+           actual -= ((inb(SCBARRAY(base + 17)) << 16) |
+                      (inb(SCBARRAY(base + 16)) <<  8) |
+                      inb(SCBARRAY(base + 15)));
+
+           if (actual < cmd->underflow)
+           {
+             printk("aic7xxx: target %d underflow - "
+                    "wanted (at least) %u, got %u\n",
+                    cmd->target, cmd->underflow, actual);
+
+             aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+             aic7xxx_status(cmd) = scb->target_status;
+           }
+         }
        }
+       break;
 
-       template->name = (char *)aic7xxx_info(NULL);
-       return(found);
-}
-
-const char *aic7xxx_info(struct Scsi_Host *notused)
-{
-       return("Adaptec AHA274x/284x/294x (EISA/VL-bus/PCI -> Fast SCSI) "
-              AIC7XXX_SEQ_VERSION "/"
-              AIC7XXX_H_VERSION "/"
-              "1.34");
-}
-
-static
-void aic7xxx_buildscb(struct aic7xxx_host *p,
-                     Scsi_Cmnd *cmd,
-                     struct aic7xxx_scb *scb)
-{
-       void *addr;
-       unsigned length;
-
-       memset(scb, 0, sizeof(*scb));
+      case ABORT_TAG:
+       scbptr = inb(SCBPTR(base));
+       scb = &(p->scb_array[scbptr]);
+       if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+       {
+         printk("aic7xxx_isr: referenced scb not valid "
+                "during seqint 0x%x scb(%d) state(%x), cmd(%x)\n",
+                intstat, scbptr, scb->state, (unsigned int) scb->cmd);
+       }
+       else
+       {
+         cmd = scb->cmd;
+         /*
+          * We didn't recieve a valid tag back from the target
+          * on a reconnect.
+          */
+         printk("aic7xxx_isr: invalid tag recieved on channel %c "
+                "target %d, lun %d -- sending ABORT_TAG\n",
+                 (cmd->channel & 0x01) ? 'B':'A',
+                 cmd->target, cmd->lun & 0x07);
+         /*
+          *  This is a critical section, since we don't want the
+          *  queue routine mucking with the host data.
+          */
+         save_flags(flags);
+         cli();
+
+         /*
+          *  Process the command after marking the scb as free
+          *  and adding it to the free list.
+          */
+         scb->state = SCB_FREE;
+         scb->cmd = NULL;
+         scb->next = p->free_scb;      /* preserve next pointer */
+         p->free_scb = scb;            /* add at head of list */
+
+         restore_flags (flags);
+         cmd->result = (DID_RETRY_COMMAND << 16);
+         cmd->scsi_done(cmd);
+       }
+       break;
 
-       /*
-        *  NB. channel selection (bit 3) is always zero.
-        */
-       scb->target_channel_lun = ((cmd->target << 4) & 0xf0) |
-                                  (cmd->lun & 0x7);
+      case AWAITING_MSG:
+       scbptr = inb(SCBPTR(base));
+       scb = &(p->scb_array[scbptr]);
+       if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+       {
+         printk("aic7xxx_isr: referenced scb not valid "
+                "during seqint 0x%x scb(%d) state(%x), cmd(%x)\n",
+                intstat, scbptr, scb->state, (unsigned int) scb->cmd);
+       }
+       else
+       {
+         /*
+          * This SCB had a zero length command, informing the sequencer
+          * that we wanted to send a special message to this target.
+          * We only do this for BUS_DEVICE_RESET messages currently.
+          */
+          if (scb->state & SCB_DEVICE_RESET)
+          {
+            outb(MSG_BUS_DEVICE_RESET, HA_MSG_START(base));
+            outb(1, HA_MSG_LEN(base));
+          }
+          else
+          {
+            panic ("aic7xxx_isr: AWAITING_SCB for an SCB that does "
+                   "not have a waiting message");
+          }
+       }
+       break;
+
+      default:               /* unknown */
+       debug("aic7xxx_isr: seqint, intstat = 0x%x, scsisigi = 0x%x\n",
+             intstat, inb(SCSISIGI(base)));
+       break;
+    }
+    outb(CLRSEQINT, CLRINT(base));
+    UNPAUSE_SEQUENCER(p);
+  }
+
+  if (intstat & SCSIINT)
+  {
+    int status = inb(SSTAT1(base));
+
+    scbptr = inb(SCBPTR(base));
+    scb = &p->scb_array[scbptr];
+    if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+    {
+      printk("aic7xxx_isr: no command for scb (scsiint)\n");
+      /*
+       * Turn off the interrupt and set status
+       * to zero, so that it falls through the
+       * reset of the SCSIINT code.
+       */
+      outb(status, CLRSINT1(base));
+      UNPAUSE_SEQUENCER(p);
+      outb(CLRSCSIINT, CLRINT(base));
+      status = 0;
+      scb = NULL;
+    }
+    else
+    {
+      cmd = scb->cmd;
+
+      /*
+       * Only the SCSI Status 1 register has information
+       * about exceptional conditions that we'd have a
+       * SCSIINT about; anything in SSTAT0 will be handled
+       * by the sequencer. Note that there can be multiple
+       * bits set.
+       */
+      if (status & SELTO)
+      {
+       unsigned char target_mask = (1 << (cmd->target & 0x07));
+       unsigned char waiting;
 
        /*
-        *  The interpretation of request_buffer and request_bufflen
-        *  changes depending on whether or not use_sg is zero; a
-        *  non-zero use_sg indicates the number of elements in the
-        *  scatter-gather array.
-        *
-        *  The AIC-7770 can't support transfers of any sort larger
-        *  than 2^24 (three-byte count) without backflips.  For what
-        *  the kernel is doing, this shouldn't occur.  I hope.
+        * Hardware selection timer has expired. Turn
+        * off SCSI selection sequence.
         */
-       length = aic7xxx_length(cmd, 0);
-
+       outb(ENRSELI, SCSISEQ(base));
+       cmd->result = (DID_TIME_OUT << 16);
        /*
-        *  The sequencer code cannot yet handle scatter-gather segments
-        *  larger than 64k (two-byte length).  The 1.1.x kernels, however,
-        *  have a four-byte length field in the struct scatterlist, so
-        *  make sure we don't exceed 64k on these kernels for now.
+        * Clear an pending messages for the timed out
+        * target and mark the target as free.
         */
-       aic7xxx_sg_check(cmd);
+       ha_flags = inb(HA_FLAGS(base));
+       outb(ha_flags & ~ACTIVE_MSG, HA_FLAGS(base));
 
-       if (length > 0xffffff) {
-               panic("aic7xxx_buildscb: can't transfer > 2^24 - 1 bytes\n");
+       if (scb->target_channel_lun & 0x88)
+       {
+         active = inb(HA_ACTIVE1(base));
+         active = active & ~(target_mask);
+         outb(active, HA_ACTIVE1(base));
        }
-
-       /*
-        *  XXX - this relies on the host data being stored in a
-        *        little-endian format.
-        */
-       addr = cmd->cmnd;
-       scb->SCSI_cmd_length = cmd->cmd_len;
-       memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
-
-       if (cmd->use_sg) {
-#if 0
-               debug("aic7xxx_buildscb: SG used, %d segments, length %u\n",
-                     cmd->use_sg,
-                     length);
-#endif
-               scb->SG_segment_count = cmd->use_sg;
-               memcpy(scb->SG_list_pointer,
-                      &cmd->request_buffer,
-                      sizeof(scb->SG_list_pointer));
-       } else {
-               scb->SG_segment_count = 0;
-               memcpy(scb->data_pointer,
-                      &cmd->request_buffer,
-                      sizeof(scb->data_pointer));
-               memcpy(scb->data_count,
-                      &cmd->request_bufflen,
-                      sizeof(scb->data_count));
+       else
+       {
+         active = inb(HA_ACTIVE0(base));
+         active = active & ~(target_mask);
+         outb(active, HA_ACTIVE0(base));
        }
-}
 
-static
-void aic7xxx_putscb(int base, struct aic7xxx_scb *scb)
-{
-       /*
-        *  By turning on the SCB auto increment, any reference
-        *  to the SCB I/O space postincrements the SCB address
-        *  we're looking at.  So turn this on and dump the relevant
-        *  portion of the SCB to the card.
-        */
-       outb(0x80, O_SCBCNT(base));     /* SCBAUTO */
-
-       asm volatile("cld\n\t"
-                    "rep\n\t"
-                    "outsb"
-                    : /* no output */
-                    :"S" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
-                    :"si", "cx", "dx");
-
-       outb(0, O_SCBCNT(base));
-}
-
-int aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
-{
-       long flags;
-       int empty, old_scbptr;
-       struct aic7xxx_host *p;
-       struct aic7xxx_scb scb;
-
-#if 0
-       debug("aic7xxx_queue: cmd 0x%x (size %u), target %d, lun %d\n",
-             cmd->cmnd[0],
-             cmd->cmd_len,
-             cmd->target,
-             cmd->lun);
+#ifdef AIC7XXX_USE_DMA
+       outb(SCB_NEEDDMA, SCBARRAY(base));
 #endif
 
-       p = (struct aic7xxx_host *)cmd->host->hostdata;
-
        /*
-        *  Construct the SCB beforehand, so the sequencer is
-        *  paused a minimal amount of time.
+        * Shut off the offending interrupt sources, reset
+        * the sequencer address to zero and unpause it,
+        * then call the high-level SCSI completion routine.
+        *
+        * WARNING!  This is a magic sequence!  After many
+        * hours of guesswork, turning off the SCSI interrupts
+        * in CLRSINT? does NOT clear the SCSIINT bit in
+        * INTSTAT. By writing to the (undocumented, unused
+        * according to the AIC-7770 manual) third bit of
+        * CLRINT, you can clear INTSTAT. But, if you do it
+        * while the sequencer is paused, you get a BRKADRINT
+        * with an Illegal Host Address status, so the
+        * sequencer has to be restarted first.
         */
-       aic7xxx_buildscb(p, cmd, &scb);
+       outb(CLRSELTIMEO, CLRSINT1(base));
 
-       /*
-        *  Clear the startup flag - we can now legitimately
-        *  expect interrupts.
-        */
-       p->startup = 0;
+       outb(CLRSCSIINT, CLRINT(base));
 
+       /* Shift the waiting for selection queue forward */
+       waiting = inb(WAITING_SCBH(base));
+       outb(waiting, SCBPTR(base));
+       waiting = inb(SCBARRAY(base) + 30);
+       outb(waiting, WAITING_SCBH(base));
+
+       RESTART_SEQUENCER(p);
        /*
-        *  This is a critical section, since we don't want the
-        *  interrupt routine mucking with the host data or the
-        *  card.  Since the kernel documentation is vague on
-        *  whether or not we are in a cli/sti pair already, save
-        *  the flags to be on the safe side.
+        * This is a critical section, since we don't want the
+        * queue routine mucking with the host data.
         */
        save_flags(flags);
        cli();
 
        /*
-        *  Find a free slot in the SCB array to load this command
-        *  into.  Since can_queue is set to the maximum number of
-        *  SCBs for the card, we should always find one.
-        */
-       for (empty = 0; empty < p->maxscb; empty++)
-               if (!p->SCB_array[empty])
-                       break;
-       if (empty == p->maxscb)
-               panic("aic7xxx_queue: couldn't find a free scb\n");
-
-       /*
-        *  Pause the sequencer so we can play with its registers -
-        *  wait for it to acknowledge the pause.
-        *
-        *  XXX - should the interrupts be left on while doing this?
-        */
-       PAUSE_SEQUENCER(p);
-
-       /*
-        *  Save the SCB pointer and put our own pointer in - this
-        *  selects one of the four banks of SCB registers.  Load
-        *  the SCB, then write its pointer into the queue in FIFO
-        *  and restore the saved SCB pointer.
+        * Process the command after marking the scb as free
+        * and adding it to the free list.
         */
-       old_scbptr = inb(O_SCBPTR(p->base));
-       outb(empty, O_SCBPTR(p->base));
-       
-       aic7xxx_putscb(p->base, &scb);
+       scb->state = SCB_FREE;
+       scb->cmd = NULL;
+       scb->next = p->free_scb;        /* preserve next pointer */
+       p->free_scb = scb;              /* add at head of list */
 
-       outb(empty, O_QINFIFO(p->base));
-       outb(old_scbptr, O_SCBPTR(p->base));
+       restore_flags(flags);
 
-       /*
-        *  Make sure the Scsi_Cmnd pointer is saved, the struct it
-        *  points to is set up properly, and the parity error flag
-        *  is reset, then unpause the sequencer and watch the fun
-        *  begin.
-        */
-       cmd->scsi_done = fn;
-       p->SCB_array[empty] = cmd;
-       aic7xxx_parity(cmd) = DID_OK;
+       cmd->scsi_done(cmd);
+#if 0
+  printk("aic7xxx_isr: SELTO scb(%d) state(%x), cmd(%x)\n",
+        scb->position, scb->state, (unsigned int) scb->cmd);
+#endif
+      }
+      else
+      {
+       if (status & SCSIPERR)
+       {
+         /*
+          * A parity error has occurred during a data
+          * transfer phase. Flag it and continue.
+          */
+         printk("aic7xxx: parity error on target %d, "
+                "channel %d, lun %d\n",
+                cmd->target,
+                cmd->channel & 0x01,
+                cmd->lun & 0x07);
+         aic7xxx_error(cmd) = DID_PARITY;
+
+         /*
+          * Clear interrupt and resume as above.
+          */
+         outb(CLRSCSIPERR, CLRSINT1(base));
+         UNPAUSE_SEQUENCER(p);
+
+         outb(CLRSCSIINT, CLRINT(base));
+         scb = NULL;
+       }
+       else
+       {
+         if (! (status & BUSFREE))
+         {
+            /*
+             * We don't know what's going on. Turn off the
+             * interrupt source and try to continue.
+             */
+            printk("aic7xxx_isr: sstat1 = 0x%x\n", status);
+            outb(status, CLRSINT1(base));
+            UNPAUSE_SEQUENCER(p);
+            outb(CLRSCSIINT, CLRINT(base));
+            scb = NULL;
+         }
+       }
+      }
+    }  /* else */
+  }
+
+  if (intstat & CMDCMPLT)
+  {
+    int complete;
+
+    /*
+     * The sequencer will continue running when it
+     * issues this interrupt. There may be >1 commands
+     * finished, so loop until we've processed them all.
+     */
+    do {
+      complete = inb(QOUTFIFO(base));
+
+      scb = &(p->scb_array[complete]);
+      if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+      {
+       printk("aic7xxx warning: "
+              "no command for scb %d (cmdcmplt)\n"
+              "QOUTCNT = %d, SCB state = 0x%x, CMD = 0x%x\n",
+              complete, inb(QOUTFIFO(base)),
+              scb->state, (unsigned int) scb->cmd);
+       outb(CLRCMDINT, CLRINT(base));
+       continue;
+      }
+      cmd = scb->cmd;
+
+      cmd->result = (aic7xxx_error(cmd) << 16) | aic7xxx_status(cmd);
+      if ((cmd->flags & WAS_SENSE) && !(cmd->flags & ASKED_FOR_SENSE))
+      { /* Got sense information. */
+       cmd->flags = cmd->flags & ASKED_FOR_SENSE;
+      }
+#if 0
+      printk("aic7xxx_intr: (complete) state = %d, cmd = 0x%x, free = 0x%x\n",
+            scb->state, (unsigned int) scb->cmd, (unsigned int) p->free_scb);
+#endif
+      /*
+       * This is a critical section, since we don't want the
+       * queue routine mucking with the host data.
+       */
+      save_flags(flags);
+      cli();
+
+      scb->state = SCB_FREE;
+      scb->next = p->free_scb;
+      scb->cmd = NULL;
+      p->free_scb = &(p->scb_array[scb->position]);
+
+      restore_flags(flags);
+#if 0
+  if (scb != &p->scb_array[scb->position])
+  {
+    printk("aic7xxx_isr: (complete) address mismatch, pos %d\n", scb->position);
+  }
+  printk("aic7xxx_isr: (complete) state = %d, cmd = 0x%x, free = 0x%x\n",
+        scb->state, (unsigned int) scb->cmd, (unsigned int) p->free_scb);
+#endif
 
-       UNPAUSE_SEQUENCER(p);
+      cmd->scsi_done(cmd);
+
+      /*
+       * Clear interrupt status before checking
+       * the output queue again. This eliminates
+       * a race condition whereby a command could
+       * complete between the queue poll and the
+       * interrupt clearing, so notification of the
+       * command being complete never made it back
+       * up to the kernel.
+       */
+      outb(CLRCMDINT, CLRINT(base));
+    } while (inb(QOUTCNT(base)));
+  }
+}
 
-       restore_flags(flags);
-       return(0);
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_probe
+ *
+ * Description:
+ *   Probing for EISA boards: it looks like the first two bytes
+ *   are a manufacturer code - three characters, five bits each:
+ *
+ *               BYTE 0   BYTE 1   BYTE 2   BYTE 3
+ *              ?1111122 22233333 PPPPPPPP RRRRRRRR
+ *
+ *   The characters are baselined off ASCII '@', so add that value
+ *   to each to get the real ASCII code for it. The next two bytes
+ *   appear to be a product and revision number, probably vendor-
+ *   specific. This is what is being searched for at each port,
+ *   and what should probably correspond to the ID= field in the
+ *   ECU's .cfg file for the card - if your card is not detected,
+ *   make sure your signature is listed in the array.
+ *
+ *   The fourth byte's lowest bit seems to be an enabled/disabled
+ *   flag (rest of the bits are reserved?).
+ *-F*************************************************************************/
+static aha_type
+aic7xxx_probe(int slot, int base)
+{
+  int i;
+  unsigned char buf[4];
+
+  static struct {
+    int n;
+    unsigned char signature[sizeof(buf)];
+    aha_type type;
+  } AIC7xxx[] = {
+    { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_274x },  /* host adapter 274x */
+    { 4, { 0x04, 0x90, 0x77, 0x70 }, AIC_274x },  /* motherboard 274x  */
+    { 4, { 0x04, 0x90, 0x77, 0x56 }, AIC_284x },  /* 284x, BIOS enabled */
+    { 4, { 0x04, 0x90, 0x77, 0x57 }, AIC_284x }   /* 284x, BIOS disabled */
+  };
+
+  /*
+   * The VL-bus cards need to be primed by
+   * writing before a signature check.
+   */
+  for (i = 0; i < sizeof(buf); i++)
+  {
+    outb(0x80 + i, base);
+    buf[i] = inb(base + i);
+  }
+
+  for (i = 0; i < NUMBER(AIC7xxx); i++)
+  {
+    /*
+     * Signature match on enabled card?
+     */
+    if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n))
+    {
+      if (inb(base + 4) & 1)
+      {
+       return(AIC7xxx[i].type);
+      }
+
+      printk("aic7xxx disabled at slot %d, ignored\n", slot);
+    }
+  }
+
+  return(AIC_NONE);
 }
 
-/* return values from aic7xxx_kill */
+/*+F*************************************************************************
+ * Function:
+ *   read_seeprom
+ *
+ * Description:
+ *   Reads the serial EEPROM and returns 1 if successful and 0 if
+ *   not successful.
+ *
+ *   The instruction set of the 93C46 chip is as follows:
+ *
+ *               Start  OP
+ *     Function   Bit  Code  Address    Data     Description
+ *     -------------------------------------------------------------------
+ *     READ        1    10   A5 - A0             Reads data stored in memory,
+ *                                               starting at specified address
+ *     EWEN        1    00   11XXXX              Write enable must preceed
+ *                                               all programming modes
+ *     ERASE       1    11   A5 - A0             Erase register A5A4A3A2A1A0
+ *     WRITE       1    01   A5 - A0   D15 - D0  Writes register
+ *     ERAL        1    00   10XXXX              Erase all registers
+ *     WRAL        1    00   01XXXX    D15 - D0  Writes to all registers
+ *     EWDS        1    00   00XXXX              Disables all programming
+ *                                               instructions
+ *     *Note: A value of X for address is a don't care condition.
+ *
+ *   The 93C46 has a four wire interface: clock, chip select, data in, and
+ *   data out.  In order to perform one of the above functions, you need
+ *   to enable the chip select for a clock period (typically a minimum of
+ *   1 usec, with the clock high and low a minimum of 750 and 250 nsec
+ *   respectively.  While the chip select remains high, you can clock in
+ *   the instructions (above) starting with the start bit, followed by the
+ *   OP code, Address, and Data (if needed).  For the READ instruction, the
+ *   requested 16-bit register contents is read from the data out line but
+ *   is preceded by an initial zero (leading 0, followed by 16-bits, MSB
+ *   first).  The clock cycling from low to high initiates the next data
+ *   bit to be sent from the chip.
+ *
+ *   The 7870 interface to the 93C46 serial EEPROM is through the SEECTL
+ *   register.  After successful arbitration for the memory port, the
+ *   SEECS bit of the SEECTL register is connected to the chip select.
+ *   The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
+ *   and data in lines respectively.  The SEERDY bit of SEECTL is useful
+ *   in that it gives us an 800 nsec timer.  After a write to the SEECTL
+ *   register, the SEERDY goes high 800 nsec later.  The one exception
+ *   to this is when we first request access to the memory port.  The
+ *   SEERDY goes high to signify that access has been granted and, for
+ *   this case, has no implied timing.
+ *
+ *-F*************************************************************************/
+static int
+read_seeprom(int base, struct seeprom_config *sc)
+{
+  int i = 0, k = 0;
+  unsigned long timeout;
+  unsigned char temp;
+  unsigned short checksum = 0;
+  unsigned short *seeprom = (unsigned short *) sc;
+  struct seeprom_cmd {
+    unsigned char len;
+    unsigned char bits[3];
+  };
+  struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
+
+#define CLOCK_PULSE(p) \
+  while ((inb(SEECTL(base)) & SEERDY) == 0)    \
+  {                                            \
+    ;  /* Do nothing */                                \
+  }
+
+  /*
+   * Request access of the memory port.  When access is
+   * granted, SEERDY will go high.  We use a 1 second
+   * timeout which should be near 1 second more than
+   * is needed.  Reason: after the 7870 chip reset, there
+   * should be no contention.
+   */
+  outb(SEEMS, SEECTL(base));
+  timeout = jiffies + 100;  /* 1 second timeout */
+  while ((jiffies < timeout) && ((inb(SEECTL(base)) & SEERDY) == 0))
+  {
+    ;  /* Do nothing!  Wait for access to be granted. */
+  }
+  if ((inb(SEECTL(base)) & SEERDY) == 0)
+  {
+    outb (0, SEECTL(base));
+    return (0);
+  }
+
+  /*
+   * Read the first 32 registers of the seeprom.  For the 7870,
+   * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
+   * but only the first 32 are used by Adaptec BIOS.  The loop
+   * will range from 0 to 31.
+   */
+  for (k = 0; k < (sizeof(*sc) / 2); k = k + 1)
+  {
+    /* Send chip select for one clock cycle. */
+    outb(SEEMS | SEECK | SEECS, SEECTL(base));
+    CLOCK_PULSE(base);
+
+    /*
+     * Now we're ready to send the read command followed by the
+     * address of the 16-bit register we want to read.
+     */
+    for (i = 0; i < seeprom_read.len; i = i + 1)
+    {
+      temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
+      outb(temp, SEECTL(base));
+      CLOCK_PULSE(base);
+      temp = temp ^ SEECK;
+      outb(temp, SEECTL(base));
+      CLOCK_PULSE(base);
+    }
+    /* Send the 6 bit address (MSB first, LSB last). */
+    for (i = 5; i >= 0; i = i - 1)
+    {
+      temp = k;
+      temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
+      temp = SEEMS | SEECS | (temp << 1);
+      outb(temp, SEECTL(base));
+      CLOCK_PULSE(base);
+      temp = temp ^ SEECK;
+      outb(temp, SEECTL(base));
+      CLOCK_PULSE(base);
+    }
+
+    /*
+     * Now read the 16 bit register.  An initial 0 precedes the
+     * register contents which begins with bit 15 (MSB) and ends
+     * with bit 0 (LSB).  The initial 0 will be shifted off the
+     * top of our word as we let the loop run from 0 to 16.
+     */
+    for (i = 0; i <= 16; i = i + 1)
+    {
+      temp = SEEMS | SEECS;
+      outb(temp, SEECTL(base));
+      CLOCK_PULSE(base);
+      temp = temp ^ SEECK;
+      seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL(base)) & SEEDI);
+      outb(temp, SEECTL(base));
+      CLOCK_PULSE(base);
+    }
+
+    /*
+     * The serial EEPROM has a checksum in the last word.  Keep a
+     * running checksum for all words read except for the last
+     * word.  We'll verify the checksum after all words have been
+     * read.
+     */
+    if (k < (sizeof(*sc) / 2) - 1)
+    {
+      checksum = checksum + seeprom[k];
+    }
+
+    /* Reset the chip select for the next command cycle. */
+    outb(SEEMS, SEECTL(base));
+    CLOCK_PULSE(base);
+    outb(SEEMS | SEECK, SEECTL(base));
+    CLOCK_PULSE(base);
+    outb(SEEMS, SEECTL(base));
+    CLOCK_PULSE(base);
+  }
+
+  if (checksum != sc->checksum)
+  {
+    printk ("aic7xxx : SEEPROM checksum error, ignoring SEEPROM settings.\n");
+    return (0);
+  }
 
-enum k_state {
-       k_ok,                           /* scb found and message sent */
-       k_busy,                         /* message already present */
-       k_absent,                       /* couldn't locate scb */
-       k_disconnect,                   /* scb found, but disconnected */
-};
+#if 0
+  printk ("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+  printk ("Serial EEPROM:");
+  for (k = 0; k < (sizeof(*sc) / 2); k = k + 1)
+  {
+    if (((k % 8) == 0) && (k != 0))
+    {
+      printk ("\n              ");
+    }
+    printk (" 0x%x", seeprom[k]);
+  }
+  printk ("\n");
+#endif
 
-/*
- *  This must be called with interrupts disabled - it's going to
- *  be messing around with the host data, and an interrupt being
- *  fielded in the middle could get ugly.
- *
- *  Since so much of the abort and reset code is shared, this
- *  function performs more magic than it really should.  If the
- *  command completes ok, then it will call scsi_done with the
- *  result code passed in.  The unpause parameter controls whether
- *  or not the sequencer gets unpaused - the reset function, for
- *  instance, may want to do something more aggressive.
+  /* Release access to the memory port and the serial EEPROM. */
+  outb(0, SEECTL(base));
+  return (1);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   detect_maxscb
  *
- *  Note that the command is checked for in our SCB_array first
- *  before the sequencer is paused, so if k_absent is returned,
- *  then the sequencer is NOT paused.
- */
+ * Description:
+ *   Return the maximum number of SCB's allowed for a given controller.
+ *-F*************************************************************************/
+static int
+detect_maxscb(aha_type type, int base)
+{
+  unsigned char sblkctl_reg;
+  int maxscb = 0;
+
+  switch (type)
+  {
+    case AIC_274x:
+    case AIC_284x:
+      /*
+       * Check for Rev C or E boards. Rev E boards can supposedly have
+       * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
+       * Until we know how to access more than 4 SCBs for the Rev E chips,
+       * we limit them, along with the Rev C chips, to 4 SCBs.
+       *
+       * The Rev E boards have a read/write autoflush bit in the
+       * SBLKCTL registor, while in the Rev C boards it is read only.
+       */
+      sblkctl_reg = inb(SBLKCTL(base)) ^ AUTOFLUSHDIS;
+      outb(sblkctl_reg, SBLKCTL(base));
+      if (inb(SBLKCTL(base)) == sblkctl_reg)
+      {  /* We detected a Rev E board. */
+       printk("aic7770: Rev E and subsequent; using 4 SCB's\n");
+       outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL(base));
+       maxscb = 4;
+      }
+      else
+      {
+       printk("aic7770: Rev C and previous; using 4 SCB's\n");
+       maxscb = 4;
+      }
+      break;
+
+    case AIC_7850:
+      maxscb = 3;
+      break;
+
+    case AIC_7870:
+      maxscb = 16;
+      break;
+
+    case AIC_7872:
+      /*
+       * Really has 255, but we'll wait to verify that we access
+       * them the same way and do not have to set the card to
+       * use the memory port to access external SCB RAM.
+       */
+      maxscb = 16;
+      break;
+
+    case AIC_NONE:
+      /*
+       * This should never happen... But just in case.
+       */
+      break;
+  }
+
+  return(maxscb);
+}
 
-static
-enum k_state aic7xxx_kill(Scsi_Cmnd *cmd, unsigned char message,
-                         unsigned int result, int unpause)
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_register
+ *
+ * Description:
+ *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *-F*************************************************************************/
+static int
+aic7xxx_register(Scsi_Host_Template *template, aha_type type,
+                int base, unsigned char irq)
 {
-       struct aic7xxx_host *p;
-       int i, scb, found, queued;
-       unsigned char scbsave[AIC7XXX_MAXSCB];
+  static char * board_name[] = {"", "274x", "284x", "7870", "7850", "7872"};
+  int i;
+  unsigned char sblkctl;
+  int max_targets;
+  int found = 1;
+  unsigned char target_settings;
+  unsigned char scsi_conf;
+  int have_seeprom = 0;
+  struct Scsi_Host *host;
+  struct aic7xxx_host *p;
+  struct aic7xxx_host_config config;
+  struct seeprom_config sc;
+
+  config.type = type;
+  config.base = base;
+  config.irq = irq;
+  config.parity = AIC_UNKNOWN;
+  config.low_term = AIC_UNKNOWN;
+  config.high_term = AIC_UNKNOWN;
+  config.busrtime = 0;
+
+  /*
+   * Lock out other contenders for our i/o space.
+   */
+  request_region(MINREG(base), MAXREG(base) - MINREG(base), "aic7xxx");
+
+  switch (type)
+  {
+    case AIC_274x:
+#if 1
+      printk("aha274x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
+#endif
+      /*
+       * For some 274x boards, we must clear the CHIPRST bit
+       * and pause the sequencer. For some reason, this makes
+       * the driver work. For 284x boards, we give it a
+       * CHIPRST just like the 294x boards.
+       *
+       * Use the BIOS settings to determine the interrupt
+       * trigger type (level or edge) and use this value
+       * for pausing and unpausing the sequencer.
+       */
+      config.unpause = (inb(HCNTRL(config.base)) & IRQMS) | INTEN;
+      config.pause = config.unpause | PAUSE;
+      config.extended = aic7xxx_extended;
+
+      /*
+       * I don't think we need to kick the reset again, the initial probe
+       * does a reset, it seems that this is kicking a dead horse here.
+       * So... I will try to just verify that the chip has come out of the
+       * reset state and continue the same as the 284x.
+       * In the Calgary version of the driver:
+       *   1) Chip Reset
+       *   2) Set unpause to IRQMS | INTEN
+       *   3) If an interrupt occured without any commands queued, the
+       *      unpause was set to just INTEN
+       * I changed the initial reset code to just mask in the CHIPRST bit
+       * and try to leave the other settings alone.
+       *
+       * I don't think we need the warning about chip reset not being clear.
+       * On both my test machines (2842 & 2940), they work just fine with a
+       * HCNTRL() of 0x5 (PAUSE | CHIPRST). Notice though, the 274x also
+       * adds the INTEN flag, where neither the 284x or 294x do.
+       */
+      outb(config.pause | CHIPRST, HCNTRL(config.base));
+      aic7xxx_delay(1);
+      if (inb(HCNTRL(config.base)) & CHIPRST)
+      {
+       printk("aic7xxx_register: Chip reset not cleared; clearing manually.\n");
+      }
+      outb(config.pause, HCNTRL(config.base));
+
+      /*
+       * Just to be on the safe side with the 274x, we will re-read the irq
+       * since there was some issue about reseting the board.
+       */
+      config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
+      config.busrtime = inb(HA_SCSICONF(config.base)) & 0x3C;
+
+      /*
+       * A reminder until this can be detected automatically.
+       */
+      printk("aha274x: extended translation %sabled\n",
+            config.extended ? "en" : "dis");
+      break;
+
+    case AIC_284x:
+#if 1
+      printk("aha284x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
+#endif
+      outb(CHIPRST, HCNTRL(config.base));
+      config.unpause = UNPAUSE_284X;
+      config.pause = REQ_PAUSE; /* DWG would like to be like the rest */
+      config.extended = aic7xxx_extended;
+      config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
+
+      /*
+       * A reminder until this can be detected automatically.
+       */
+      printk("aha284x: extended translation %sabled\n",
+            config.extended ? "en" : "dis");
+      break;
+
+    case AIC_7850:
+    case AIC_7870:
+    case AIC_7872:
+#if 1
+      printk("aic%s hcntrl=0x%x\n", board_name[type], inb(HCNTRL(config.base)));
+#endif
 
-       p = (struct aic7xxx_host *)cmd->host->hostdata;
+      outb(CHIPRST, HCNTRL(config.base));
+      config.unpause = UNPAUSE_294X;
+      config.pause = config.unpause | PAUSE;
+      config.extended = aic7xxx_extended;
+      config.scsi_id = 7;
+
+      printk ("aic78xx: Reading SEEPROM... ");
+      have_seeprom = read_seeprom(base, &sc);
+      if (! have_seeprom)
+      {
+       printk ("Unable to read SEEPROM\n");
+      }
+      else
+      {
+       printk ("done\n");
+       config.extended = (sc.bios_control & CFEXTEND) >> 7;
+       config.scsi_id = (sc.brtime_id & CFSCSIID);
+       config.parity = (sc.adapter_control & CFSPARITY) ?
+                        AIC_ENABLED : AIC_DISABLED;
+       config.low_term = (sc.adapter_control & CFSTERM) ?
+                             AIC_ENABLED : AIC_DISABLED;
+       config.high_term = (sc.adapter_control & CFWSTERM) ?
+                             AIC_ENABLED : AIC_DISABLED;
+       config.busrtime = (sc.brtime_id & CFBRTIME) >> 8;
+      }
+
+      /*
+       * XXX - force data fifo threshold to 100%. Why does this
+       *       need to be done?
+       */
+      outb(inb(DSPCISTATUS(config.base)) | DFTHRESH, DSPCISTATUS(config.base));
+      outb(config.scsi_id | DFTHRESH, HA_SCSICONF(config.base));
+
+      /*
+       * In case we are a wide card, place scsi ID in second conf byte.
+       */
+      outb(config.scsi_id, (HA_SCSICONF(config.base) + 1));
+
+      /*
+       * A reminder until this can be detected automatically.
+       */
+      printk("aic%s: extended translation %sabled\n", board_name[type],
+            config.extended ? "en" : "dis");
+      break;
+
+    default:
+      panic("aic7xxx_register: internal error\n");
+  }
+
+  config.maxscb = detect_maxscb(type, base);
+
+  if ((config.type == AIC_274x) || (config.type == AIC_284x))
+  {
+    if (config.pause & IRQMS)
+    {
+      printk("aic7xxx: Using Level Sensitive Interrupts\n");
+    }
+    else
+    {
+      printk("aic7xxx: Using Edge Triggered Interrupts\n");
+    }
+  }
+
+  /*
+   * Read the bus type from the SBLKCTL register. Set the FLAGS
+   * register in the sequencer for twin and wide bus cards.
+   */
+  sblkctl = inb(SBLKCTL(base)) & 0x0F;  /* mask out upper two bits */
+  switch (sblkctl)
+  {
+    case 0:     /* narrow/normal bus */
+      config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+      config.bus_type = AIC_SINGLE;
+      outb(0, HA_FLAGS(base));
+      break;
+
+    case 2:     /* Wide bus */
+      config.scsi_id = inb(HA_SCSICONF(base) + 1) & 0x0F;
+      config.bus_type = AIC_WIDE;
+      printk("aic7xxx : Enabling wide channel of %s-Wide\n",
+            board_name[config.type]);
+      outb(WIDE_BUS, HA_FLAGS(base));
+      break;
+
+    case 8:     /* Twin bus */
+      config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+#ifdef AIC7XXX_TWIN_SUPPORT
+      config.scsi_id_b = inb(HA_SCSICONF(base) + 1) & 0x07;
+      config.bus_type = AIC_TWIN;
+      printk("aic7xxx : Enabled channel B of %s-Twin\n",
+            board_name[config.type]);
+      outb(TWIN_BUS, HA_FLAGS(base));
+#else
+      config.bus_type = AIC_SINGLE;
+      printk("aic7xxx : Channel B of %s-Twin will be ignored\n",
+            board_name[config.type]);
+      outb(0, HA_FLAGS(base));
+#endif
+      break;
+
+    default:
+      printk("aic7xxx is an unsupported type 0x%x, please "
+            "mail deang@ims.com\n", inb(SBLKCTL(base)));
+      outb(0, HA_FLAGS(base));
+      return(0);
+  }
+
+  /*
+   * Clear the upper two bits. For the 294x cards, clearing the
+   * upper two bits, will take the card out of diagnostic mode
+   * and make the host adatper LED follow bus activity (will not
+   * always be on).
+   */
+  outb(sblkctl, SBLKCTL(base));
+
+  /*
+   * The IRQ level in i/o port 4 maps directly onto the real
+   * IRQ number. If it's ok, register it with the kernel.
+   *
+   * NB. the Adaptec documentation says the IRQ number is only
+   *     in the lower four bits; the ECU information shows the
+   *     high bit being used as well. Which is correct?
+   *
+   * The 294x cards (PCI) get their interrupt from PCI BIOS.
+   */
+  if (((config.type == AIC_274x) || (config.type == AIC_284x))
+      && (config.irq < 9 || config.irq > 15))
+  {
+    printk("aic7xxx uses unsupported IRQ level, ignoring\n");
+    return(0);
+  }
+
+  /*
+   * Check the IRQ to see if it is shared by another aic7xxx
+   * controller. If it is and sharing of IRQs is not defined,
+   * then return 0 hosts found. If sharing of IRQs is allowed
+   * or the IRQ is not shared by another host adapter, then
+   * proceed.
+   */
+#ifndef AIC7XXX_SHARE_IRQS
+   if (aic7xxx_boards[config.irq] != NULL)
+   {
+     printk("aic7xxx_register: Sharing of IRQs is not configured.\n");
+     return(0);
+   }
+#endif
 
+  /*
+   * Print out debugging information before re-enabling
+   * the card - a lot of registers on it can't be read
+   * when the sequencer is active.
+   */
+  debug_config(&config);
+
+  /*
+   * Before registry, make sure that the offsets of the
+   * struct scatterlist are what the sequencer will expect,
+   * otherwise disable scatter-gather altogether until someone
+   * can fix it. This is important since the sequencer will
+   * DMA elements of the SG array in while executing commands.
+   */
+  if (template->sg_tablesize != SG_NONE)
+  {
+    struct scatterlist sg;
+
+    if (SG_STRUCT_CHECK(sg))
+    {
+      printk("aic7xxx warning: kernel scatter-gather "
+            "structures changed, disabling it\n");
+      template->sg_tablesize = SG_NONE;
+    }
+  }
+
+  /*
+   * Register each "host" and fill in the returned Scsi_Host
+   * structure as best we can. Some of the parameters aren't
+   * really relevant for bus types beyond ISA, and none of the
+   * high-level SCSI code looks at it anyway. Why are the fields
+   * there? Also save the pointer so that we can find the
+   * information when an IRQ is triggered.
+   */
+  host = scsi_register(template, sizeof(struct aic7xxx_host));
+  host->can_queue = config.maxscb;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+  host->cmd_per_lun = 2;
+#else
+  host->cmd_per_lun = 1;
+#endif
+  host->this_id = config.scsi_id;
+  host->irq = config.irq;
+  if (config.bus_type == AIC_WIDE)
+  {
+    host->max_id = 16;
+  }
+  if (config.bus_type == AIC_TWIN)
+  {
+    host->max_channel = 1;
+  }
+
+  p = (struct aic7xxx_host *) host->hostdata;
+
+  /* Initialize the scb array by setting the state to free. */
+  for (i = 0; i < AIC7XXX_MAXSCB; i = i + 1)
+  {
+    p->scb_array[i].state = SCB_FREE;
+    p->scb_array[i].next = NULL;
+    p->scb_array[i].cmd = NULL;
+  }
+
+  p->isr_count = 0;
+  p->a_scanned = 0;
+  p->b_scanned = 0;
+  p->base = config.base;
+  p->maxscb = config.maxscb;
+  p->numscb = 0;
+  p->extended = config.extended;
+  p->type = config.type;
+  p->bus_type = config.bus_type;
+  p->have_seeprom = have_seeprom;
+  p->seeprom = sc;
+  p->free_scb = NULL;
+  p->next = NULL;
+
+  p->unpause = config.unpause;
+  p->pause = config.pause;
+
+  if (aic7xxx_boards[config.irq] == NULL)
+  {
+    /*
+     * Register IRQ with the kernel.
+     */
+    if (request_irq(config.irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx"))
+    {
+      printk("aic7xxx couldn't register irq %d, ignoring\n", config.irq);
+      return(0);
+    }
+    aic7xxx_boards[config.irq] = host;
+  }
+  else
+  {
+    /*
+     * We have found a host adapter sharing an IRQ of a previously
+     * registered host adapter. Add this host adapter's Scsi_Host
+     * to the beginning of the linked list of hosts at the same IRQ.
+     */
+    p->next = aic7xxx_boards[config.irq];
+    aic7xxx_boards[config.irq] = host;
+  }
+
+  /*
+   * Load the sequencer program, then re-enable the board -
+   * resetting the AIC-7770 disables it, leaving the lights
+   * on with nobody home. On the PCI bus you *may* be home,
+   * but then your mailing address is dynamically assigned
+   * so no one can find you anyway :-)
+   */
+  printk("aic7xxx: Downloading sequencer code..");
+  aic7xxx_loadseq(base);
+
+  /* Set Fast Mode and Enable the board */
+  outb(FASTMODE, SEQCTL(base));
+
+  if ((p->type == AIC_274x || p->type == AIC_284x))
+  {
+    outb(ENABLE, BCTL(base));
+  }
+
+  printk("done.\n");
+
+  /*
+   * Set the SCSI Id, SXFRCTL1, and SIMODE1, for both channels
+   */
+  if (p->bus_type == AIC_TWIN)
+  {
+    /*
+     * The device is gated to channel B after a chip reset,
+     * so set those values first.
+     */
+    outb(config.scsi_id_b, SCSIID(base));
+    scsi_conf = inb(HA_SCSICONF(base) + 1) & (ENSPCHK | STIMESEL);
+    scsi_conf = scsi_conf | ENSTIMER | ACTNEGEN | STPWEN;
+    outb(scsi_conf, SXFRCTL1(base));
+    outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+    /* Select Channel A */
+    outb(0, SBLKCTL(base));
+  }
+  outb(config.scsi_id, SCSIID(base));
+  scsi_conf = inb(HA_SCSICONF(base)) & (ENSPCHK | STIMESEL);
+  outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
+  outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+
+  /* Look at the information that board initialization or the board
+   * BIOS has left us. In the lower four bits of each target's
+   * scratch space any value other than 0 indicates that we should
+   * initiate synchronous transfers. If it's zero, the user or the
+   * BIOS has decided to disable synchronous negotiation to that
+   * target so we don't activate the needsdtr flag.
+   */
+  p->needsdtr_copy = 0;
+  p->sdtr_pending = 0;
+  p->needwdtr_copy = 0;
+  p->wdtr_pending = 0;
+  if (p->bus_type == AIC_SINGLE)
+  {
+    max_targets = 8;
+  }
+  else
+  {
+    max_targets = 16;
+  }
+
+  for (i = 0; i < max_targets; i = i + 1)
+  {
+    if (have_seeprom)
+    {
+      target_settings = (sc.device_flags[i] & CFXFER) << 4;
+      if (sc.device_flags[i] & CFSYNCH)
+      {
+       p->needsdtr_copy = p->needsdtr_copy | (0x01 << i);
+      }
+      if ((sc.device_flags[i] & CFWIDEB) && (p->bus_type == AIC_WIDE))
+      {
+       p->needwdtr_copy = p->needwdtr_copy | (0x01 << i);
+      }
+    }
+    else
+    {
+      target_settings = inb(HA_TARG_SCRATCH(base) + i);
+      if (target_settings & 0x0F)
+      {
+       p->needsdtr_copy = p->needsdtr_copy | (0x01 << i);
        /*
-        *  If we can't find the command, assume it just completed
-        *  and shrug it away.
+        * Default to asynchronous transfers (0 offset)
         */
-       for (scb = 0; scb < p->maxscb; scb++)
-               if (p->SCB_array[scb] == cmd)
-                       break;
+       target_settings = target_settings & 0xF0;
+      }
+      /*
+       * If we are not wide, forget WDTR. This makes the driver
+       * work on some cards that don't leave these fields cleared
+       * when BIOS is not installed.
+       */
+      if ((target_settings & 0x80) && (p->bus_type == AIC_WIDE))
+      {
+       p->needwdtr_copy = p->needwdtr_copy | (0x01 << i);
+       target_settings = target_settings & 0x7F;
+      }
+    }
+    outb(target_settings, (HA_TARG_SCRATCH(base) + i));
+  }
+
+  p->needsdtr = p->needsdtr_copy;
+  p->needwdtr = p->needwdtr_copy;
+  printk("NeedSdtr = 0x%x, 0x%x\n", p->needsdtr_copy, p->needsdtr);
+  printk("NeedWdtr = 0x%x, 0x%x\n", p->needwdtr_copy, p->needwdtr);
+
+  /* 
+   * Clear the control byte for every SCB so that the sequencer
+   * doesn't get confused and think that one of them is valid
+   */
+  for (i = 0; i < config.maxscb; i = i + 1)
+  {
+    outb(i, SCBPTR(base));
+    outb(0, SCBARRAY(base));
+  }
+
+  /*
+   * For reconnecting targets, the sequencer code needs to
+   * know how many SCBs it has to search through.
+   */
+  outb(config.maxscb, HA_SCBCOUNT(base));
+
+  /*
+   * Clear the active flags - no targets are busy.
+   */
+  outb(0, HA_ACTIVE0(base));
+  outb(0, HA_ACTIVE1(base));
+
+  /* We don't have any waiting selections */
+  outb (SCB_LIST_NULL, WAITING_SCBH(base));
+  outb (SCB_LIST_NULL, WAITING_SCBT(base));
+
+  /*
+   * Reset the SCSI bus. Is this necessary?
+   *   There may be problems for a warm boot without resetting
+   *   the SCSI bus. Either BIOS settings in scratch RAM
+   *   will not get reinitialized, or devices may stay at
+   *   previous negotiated settings (SDTR and WDTR) while
+   *   the driver will think that no negotiations have been
+   *   performed.
+   *
+   * Some devices need a long time to "settle" after a SCSI
+   * bus reset.
+   */
+
+  if (!aic7xxx_no_reset)
+  {
+    printk("Resetting the SCSI bus...\n");
+    outb(SCSIRSTO, SCSISEQ(base));
+    udelay(1000);
+    outb(0, SCSISEQ(base));
+    aic7xxx_delay(AIC7XXX_RESET_DELAY);
+  }
+
+  /*
+   * Unpause the sequencer before returning and enable
+   * interrupts - we shouldn't get any until the first
+   * command is sent to us by the high-level SCSI code.
+   */
+  UNPAUSE_SEQUENCER(p);
+  return(found);
+}
 
-       if (scb == p->maxscb)
-               return(k_absent);
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_detect
+ *
+ * Description:
+ *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *-F*************************************************************************/
+int
+aic7xxx_detect(Scsi_Host_Template *template)
+{
+  aha_type type = AIC_NONE;
+  int found = 0, slot, base;
+  unsigned char irq = 0;
+  int i;
+
+  /*
+   * Since we may allow sharing of IRQs, it is imperative
+   * that we "null-out" the aic7xxx_boards array. It is
+   * not guaranteed to be initialized to 0 (NULL). We use
+   * a NULL entry to indicate that no prior hosts have
+   * been found/registered for that IRQ.
+   */
+  for (i = 0; i <= MAXIRQ; i++)
+  {
+    aic7xxx_boards[i] = NULL;
+  }
+
+  /*
+   * EISA/VL-bus card signature probe.
+   */
+  for (slot = MINSLOT; slot <= MAXSLOT; slot++)
+  {
+    base = SLOTBASE(slot);
+
+    if (check_region(MINREG(base), MAXREG(base) - MINREG(base)))
+    {
+      /*
+       * Some other driver has staked a
+       * claim to this i/o region already.
+       */
+      continue;
+    }
+
+    type = aic7xxx_probe(slot, HID0(base));
+    if (type != AIC_NONE)
+    {
+      printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
+#if 0
+      outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
+      irq = inb(HA_INTDEF(base)) & 0x0F;
+#endif
 
-       PAUSE_SEQUENCER(p);
+      /*
+       * We "find" a AIC-7770 if we locate the card
+       * signature and we can set it up and register
+       * it with the kernel without incident.
+       */
+      found += aic7xxx_register(template, type, base, irq);
+    }
+  }
+
+#ifdef CONFIG_PCI
+
+#define DEVREVID  0x08
+#define DEVCONFIG 0x40
+#define DEVSTATUS 0x41
+#define RAMPSM    0x02
+
+/* This should be defined in pci.h */
+#define PCI_DEVICE_ID_ADAPTEC_7850     0x5078
+#define PCI_DEVICE_ID_ADAPTEC_7872     0x7278
+
+  /*
+   * PCI-bus probe.
+   */
+  if (pcibios_present())
+  {
+    int error;
+    int done = 0;
+    unsigned int io_port;
+    unsigned short index = 0;
+    unsigned char pci_bus, pci_device_fn;
+    unsigned char devrevid, devconfig, devstatus;
+    char rev_id[] = {'B', 'C', 'D'};
+
+    while (!done)
+    {
+      if ((!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+                               PCI_DEVICE_ID_ADAPTEC_294x,
+                               index, &pci_bus, &pci_device_fn)) ||
+          (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+                               PCI_DEVICE_ID_ADAPTEC_2940,
+                               index, &pci_bus, &pci_device_fn)))
+      {
+       type = AIC_7870;
+      }
+      else
+      {
+       if (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+                               PCI_DEVICE_ID_ADAPTEC_7850,
+                               index, &pci_bus, &pci_device_fn))
+       {
+         type = AIC_7850;
+       }
+       else
+       {
+         if (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+                                 PCI_DEVICE_ID_ADAPTEC_7872,
+                                 index, &pci_bus, &pci_device_fn))
+         {
+           type = AIC_7872;
+         }
+         else
+         {
+           type = AIC_NONE;
+           done = 1;
+         }
+       }
+      }
 
+      if (!done)
+      {
        /*
-        *  This is the best case, really.  Check to see if the
-        *  command is still in the sequencer's input queue.  If
-        *  so, simply remove it.  Reload the queue afterward.
+        * Read esundry information from PCI BIOS.
         */
-       queued = inb(O_QINCNT(p->base));
-       
-       for (i = found = 0; i < queued; i++) {
-               scbsave[i] = inb(O_QINFIFO(p->base));
-
-               if (scbsave[i] == scb) {
-                       found = 1;
-                       i -= 1;
-               }
-       }
+       error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                         PCI_BASE_ADDRESS_0, &io_port);
 
-       queued -= found;
-       for (i = 0; i < queued; i++)
-               outb(scbsave[i], O_QINFIFO(p->base));
-
-       if (found)
-               goto complete;
+       if (error)
+       {
+         panic("aic7xxx_detect: error 0x%x reading i/o port.\n", error);
+       }
 
-       /*
-        *  Check the current SCB bank.  If it's not the one belonging
-        *  to the command we want to kill, assume that the command
-        *  is disconnected.  It's rather a pain to force a reconnect
-        *  and send a message to the target, so we abdicate responsibility
-        *  in this case.
-        */
-       if (inb(O_SCBPTR(p->base)) != scb) {
-               if (unpause)
-                       UNPAUSE_SEQUENCER(p);
-               return(k_disconnect);
+       error = pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                        PCI_INTERRUPT_LINE, &irq);
+       if (error)
+       {
+         panic("aic7xxx_detect: error %d reading irq.\n", error);
        }
 
        /*
-        *  Presumably at this point our target command is active.  Check
-        *  to see if there's a message already in effect.  If not, place
-        *  our message in and assert ATN so the target goes into MESSAGE
-        *  OUT phase.
+        * Make the base I/O register look like EISA and VL-bus.
         */
-       if (inb(HA_MSG_FLAGS(p->base)) & 0x80) {
-               if (unpause)
-                       UNPAUSE_SEQUENCER(p);
-               return(k_busy);
-       }
+       base = io_port - 0xC01;
 
-       outb(0x80, HA_MSG_FLAGS(p->base));              /* active message */
-       outb(1, HA_MSG_LEN(p->base));                   /* length = 1 */
-       outb(message, HA_MSG_START(p->base));           /* message body */
+       printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
+       outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
 
-       /*
-        *  Assert ATN.  Use the value of SCSISIGO saved by the
-        *  sequencer code so we don't alter its contents radically
-        *  in the middle of something critical.
-        */
-       outb(inb(HA_SIGSTATE(p->base)) | 0x10, O_SCSISIGO(p->base));
+       error = pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                        DEVREVID, &devrevid);
+       if (devrevid < 3)
+       {
+         printk ("aic7xxx_detect: AIC-7870 Rev %c\n", rev_id[devrevid]);
+       }
+       error = pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                        DEVCONFIG, &devconfig);
+       error = pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                        DEVSTATUS, &devstatus);
+       printk ("aic7xxx_detect: devconfig 0x%x, devstatus 0x%x\n",
+               devconfig, devstatus);
+       if (devstatus & RAMPSM)
+       {
+         printk ("aic7xxx_detect: detected external SCB RAM, "
+                 "mail deang@ims.com for test patch");
+       }
 
-       /*
-        *  The command has been killed.  Do the bookkeeping, unpause
-        *  the sequencer, and notify the higher-level SCSI code.
-        */
-complete:
-       p->SCB_array[scb] = NULL;
-       if (unpause)
-               UNPAUSE_SEQUENCER(p);
+       found += aic7xxx_register(template, type, base, irq);
+       index += 1;
+      }
+    }
+  }
+#endif CONFIG_PCI
 
-       cmd->result = result << 16;
-       cmd->scsi_done(cmd);
-       return(k_ok);
+  template->name = (char *) aic7xxx_info(NULL);
+  return(found);
 }
 
-int aic7xxx_abort(Scsi_Cmnd *cmd)
-{
-       int rv;
-       long flags;
-
-       save_flags(flags);
-       cli();
 
-       switch (aic7xxx_kill(cmd, ABORT, DID_ABORT, !0)) {
-           case k_ok:          rv = SCSI_ABORT_SUCCESS;        break;
-           case k_busy:        rv = SCSI_ABORT_BUSY;           break;
-           case k_absent:      rv = SCSI_ABORT_NOT_RUNNING;    break;
-           case k_disconnect:  rv = SCSI_ABORT_SNOOZE;         break;
-           default:
-               panic("aic7xxx_do_abort: internal error\n");
-       }
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_buildscb
+ *
+ * Description:
+ *   Build a SCB.
+ *-F*************************************************************************/
+static void
+aic7xxx_buildscb(struct aic7xxx_host *p,
+                Scsi_Cmnd *cmd,
+                struct aic7xxx_scb *scb)
+{
+  void *addr;
+  unsigned length;
+  unsigned short mask;
+
+  /*
+   * Setup the control byte if we need negotiation and have not
+   * already requested it.
+   */
+#ifdef AIC7XXX_TAGGED_QUEUEING
+  if (cmd->device->tagged_supported)
+  {
+    if (cmd->device->tagged_queue == 0)
+    {
+      printk ("aic7xxx_buildscb: Enabling tagged queuing for target %d, "
+             "channel %d\n", cmd->target, cmd->channel);
+      cmd->device->tagged_queue = 1;
+      cmd->device->current_tag = 1;  /* enable tagging */
+    }
+    cmd->tag = cmd->device->current_tag;
+    cmd->device->current_tag = cmd->device->current_tag + 1;
+    scb->control = scb->control | SCB_TE;
+  }
+#endif
+  mask = (0x01 << cmd->target);
+  if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
+  {
+    p->wdtr_pending = p->wdtr_pending | mask;
+    scb->control = scb->control | SCB_NEEDWDTR;
+#if 0
+    printk("Sending WDTR request to target %d.\n", cmd->target);
+#endif
+  }
+  else
+  {
+    if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
+    {
+      p->sdtr_pending = p->sdtr_pending | mask;
+      scb->control = scb->control | SCB_NEEDSDTR;
+#if 0
+      printk("Sending SDTR request to target %d.\n", cmd->target);
+#endif
+    }
+  }
 
-       restore_flags(flags);
-       return(rv);
+#if 0
+  printk("aic7xxx_queue: target %d, cmd 0x%x (size %u), wdtr 0x%x, mask 0x%x\n",
+        cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
+#endif
+  scb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+       ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+
+  /*
+   * The interpretation of request_buffer and request_bufflen
+   * changes depending on whether or not use_sg is zero; a
+   * non-zero use_sg indicates the number of elements in the
+   * scatter-gather array.
+   *
+   * The AIC-7770 can't support transfers of any sort larger
+   * than 2^24 (three-byte count) without backflips. For what
+   * the kernel is doing, this shouldn't occur. I hope.
+   */
+  length = aic7xxx_length(cmd, 0);
+
+  if (length > 0xFFFFFF)
+  {
+    panic("aic7xxx_buildscb: can't transfer > 2^24 - 1 bytes\n");
+  }
+
+  /*
+   * XXX - this relies on the host data being stored in a
+   *       little-endian format.
+   */
+  addr = cmd->cmnd;
+  scb->SCSI_cmd_length = cmd->cmd_len;
+  memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
+
+  if (cmd->use_sg)
+  {
+#if 0
+    debug("aic7xxx_buildscb: SG used, %d segments, length %u\n",
+         cmd->use_sg, length);
+#endif
+    scb->SG_segment_count = cmd->use_sg;
+    memcpy(scb->SG_list_pointer, &cmd->request_buffer,
+          sizeof(scb->SG_list_pointer));
+  }
+  else
+  {
+#if 0
+    debug ("aic7xxx_buildscb: Creating scatterlist, addr=0x%lx, length=%d.\n",
+          (unsigned long) cmd->request_buffer, cmd->request_bufflen);
+#endif
+#ifdef AIC7XXX_USE_SG
+    scb->SG_segment_count = 1;
+    scb->sg.address = (char *) cmd->request_buffer;
+    scb->sg.length = cmd->request_bufflen;
+    addr = &scb->sg;
+    memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
+#else
+    scb->SG_segment_count = 0;
+    memcpy(scb->data_pointer, &cmd->request_buffer, sizeof(scb->data_pointer));
+    memcpy(scb->data_count, &cmd->request_bufflen, 3);
+#endif
+  }
 }
 
-/*
- *  Resetting the bus always succeeds - is has to, otherwise the
- *  kernel will panic!  Try a surgical technique - sending a BUS
- *  DEVICE RESET message - on the offending target before pulling
- *  the SCSI bus reset line.
- */
-
-int aic7xxx_reset(Scsi_Cmnd *cmd)
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_queue
+ *
+ * Description:
+ *   Queue a SCB to the controller.
+ *-F*************************************************************************/
+int
+aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 {
-       int i;
-       long flags;
-       Scsi_Cmnd *reset;
-       struct aic7xxx_host *p;
-
-       p = (struct aic7xxx_host *)cmd->host->hostdata;
-       save_flags(flags);
-       cli();
+  long flags;
+#ifndef AIC7XXX_USE_DMA
+  int old_scbptr;
+#endif
+  struct aic7xxx_host *p;
+  struct aic7xxx_scb *scb;
+  unsigned char curscb;
+
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+
+  /* Check to see if channel was scanned. */
+ if (!p->a_scanned && (cmd->channel == 0))
+  {
+    printk("aic7xxx: Scanning channel A for devices.\n");
+    p->a_scanned = 1;
+  }
+  else
+  {
+    if (!p->b_scanned && (cmd->channel == 1))
+    {
+      printk("aic7xxx: Scanning channel B for devices.\n");
+      p->b_scanned = 1;
+    }
+  }
 
-       switch (aic7xxx_kill(cmd, BUS_DEVICE_RESET, DID_RESET, 0)) {
+#if 0
+  debug("aic7xxx_queue: cmd 0x%x (size %u), target %d, channel %d, lun %d\n",
+       cmd->cmnd[0], cmd->cmd_len, cmd->target, cmd->channel,
+       cmd->lun & 0x07);
+#endif
 
-           case k_ok:
-               /*
-                *  The RESET message was sent to the target
-                *  with no problems.  Flag that target as
-                *  needing a SDTR negotiation on the next
-                *  connection and restart the sequencer.
-                */
-               outb((1 << cmd->target), HA_NEEDSDTR(p->base));
-               UNPAUSE_SEQUENCER(p);
-               break;
+  /*
+   * This is a critical section, since we don't want the
+   * interrupt routine mucking with the host data or the
+   * card. Since the kernel documentation is vague on
+   * whether or not we are in a cli/sti pair already, save
+   * the flags to be on the safe side.
+   */
+  save_flags(flags);
+  cli();
+
+  /*
+   * Find a free slot in the SCB array to load this command
+   * into. Since can_queue is set to the maximum number of
+   * SCBs for the card, we should always find one.
+   *
+   * First try to find an scb in the free list. If there are
+   * none in the free list, then check the current number of
+   * of scbs and take an unused one from the scb array.
+   */
+  scb = p->free_scb;
+  if (scb != NULL)
+  { /* found one in the free list */
+    p->free_scb = scb->next;   /* remove and update head of list */
+    /*
+     * Warning! For some unknown reason, the scb at the head
+     * of the free list is not the same address that it should
+     * be. That's why we set the scb pointer taken by the
+     * position in the array. The scb at the head of the list
+     * should match this address, but it doesn't.
+     */
+    scb = &(p->scb_array[scb->position]);
+    scb->control = 0;
+    scb->state = SCB_ACTIVE;
+  }
+  else
+  {
+    if (p->numscb >= p->maxscb)
+    {
+      panic("aic7xxx_queue: couldn't find a free scb\n");
+    }
+    else
+    {
+      /*
+       * Initialize the scb within the scb array. The
+       * position within the array is the position on
+       * the board that it will be loaded.
+       */
+      scb = &(p->scb_array[p->numscb]);
+      memset(scb, 0, sizeof(*scb));
+
+      scb->position = p->numscb;
+      p->numscb = p->numscb + 1;
+      scb->state = SCB_ACTIVE;
+      scb->next_waiting = SCB_LIST_NULL;
+      memcpy(scb->host_scb, &scb, sizeof(scb));
+#ifdef AIC7XXX_USE_DMA
+      scb->control = SCB_NEEDDMA;
+#endif
+      PAUSE_SEQUENCER(p);
+      curscb = inb(SCBPTR(p->base));
+      outb(scb->position, SCBPTR(p->base));
+      aic7xxx_putdmascb(p->base, scb);
+      outb(curscb, SCBPTR(p->base));
+      UNPAUSE_SEQUENCER(p);
+      scb->control = 0;
+    }
+  }
+
+  scb->cmd = cmd;
+  aic7xxx_position(cmd) = scb->position;
+
+  /*
+   * Construct the SCB beforehand, so the sequencer is
+   * paused a minimal amount of time.
+   */
+  aic7xxx_buildscb(p, cmd, scb);
 
-           case k_absent:
-               /*
-                *  The sequencer will not be paused if aic7xxx_kill()
-                *  couldn't find the command.
-                */
-               PAUSE_SEQUENCER(p);
-               /* falls through */
+#if 0
+  if (scb != &p->scb_array[scb->position])
+  {
+    printk("aic7xxx_queue: address of scb by position does not match scb address\n");
+  }
+  printk("aic7xxx_queue: SCB pos=%d, cmdptr=0x%x, state=%d, freescb=0x%x\n",
+        scb->position, (unsigned int) scb->cmd,
+        scb->state, (unsigned int) p->free_scb);
+#endif
+  /*
+   * Pause the sequencer so we can play with its registers -
+   * wait for it to acknowledge the pause.
+   *
+   * XXX - should the interrupts be left on while doing this?
+   */
+  PAUSE_SEQUENCER(p);
+
+  /*
+   * Save the SCB pointer and put our own pointer in - this
+   * selects one of the four banks of SCB registers. Load
+   * the SCB, then write its pointer into the queue in FIFO
+   * and restore the saved SCB pointer.
+   */
+#ifdef AIC7XXX_USE_DMA
+  aic7xxx_putscb(p->base, scb);
+#else
+  old_scbptr = inb(SCBPTR(p->base));
+  outb(scb->position, SCBPTR(p->base));
 
-           case k_busy:
-           case k_disconnect:
-               /*
-                *  Do a hard reset of the SCSI bus.  According to the
-                *  SCSI-2 draft specification, reset has to be asserted
-                *  for at least 25us.  I'm invoking the kernel delay
-                *  function for 30us since I'm not totally trusting of
-                *  the busy loop timing.
-                *
-                *  XXX - I'm not convinced this works.  I tried resetting
-                *        the bus before, trying to get the devices on the
-                *        bus to revert to asynchronous transfer, and it
-                *        never seemed to work.
-                */
-               debug("aic7xxx: attempting to reset scsi bus and card\n");
+  aic7xxx_putscb(p->base, scb);
 
-               outb(1, O_SCSISEQ(p->base));            /* SCSIRSTO */
-               udelay(30);
-               outb(0, O_SCSISEQ(p->base));            /* !SCSIRSTO */
+  outb(scb->position, QINFIFO(p->base));
+  outb(old_scbptr, SCBPTR(p->base));
+#endif
+  /*
+   * Make sure the Scsi_Cmnd pointer is saved, the struct it
+   * points to is set up properly, and the parity error flag
+   * is reset, then unpause the sequencer and watch the fun
+   * begin.
+   */
+  cmd->scsi_done = fn;
+  aic7xxx_error(cmd) = DID_OK;
+  aic7xxx_status(cmd) = 0;
+
+  cmd->result = 0;
+  memset (&cmd->sense_buffer, 0, sizeof (cmd->sense_buffer));
+
+  UNPAUSE_SEQUENCER(p);
+  restore_flags(flags);
+  return(0);
+}
 
-               outb(0xff, HA_NEEDSDTR(p->base));
-               UNPAUSE_SEQUENCER(p);
+/* return values from aic7xxx_kill */
+typedef enum {
+  k_ok,             /* scb found and message sent */
+  k_busy,           /* message already present */
+  k_absent,         /* couldn't locate scb */
+  k_disconnect,     /* scb found, but disconnected */
+} k_state;
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_kill
+ *
+ * Description:
+ *   This must be called with interrupts disabled - it's going to
+ *   be messing around with the host data, and an interrupt being
+ *   fielded in the middle could get ugly.
+ *
+ *   Since so much of the abort and reset code is shared, this
+ *   function performs more magic than it really should. If the
+ *   command completes ok, then it will call scsi_done with the
+ *   result code passed in. The unpause parameter controls whether
+ *   or not the sequencer gets unpaused - the reset function, for
+ *   instance, may want to do something more aggressive.
+ *
+ *   Note that the command is checked for in our SCB_array first
+ *   before the sequencer is paused, so if k_absent is returned,
+ *   then the sequencer is NOT paused.
+ *-F*************************************************************************/
+static k_state
+aic7xxx_kill(Scsi_Cmnd *cmd, unsigned char message,
+            unsigned int result, int unpause)
+{
+  struct aic7xxx_host *p;
+  struct aic7xxx_scb *scb;
+  int i, active_scb, found, queued;
+  unsigned char scbsave[AIC7XXX_MAXSCB];
+  unsigned char flags;
+  int scb_control;
+  k_state status;
 
-               /*
-                *  Locate the command and return a "reset" status
-                *  for it.  This is not completely correct and will
-                *  probably return to haunt me later.
-                */
-               for (i = 0; i < p->maxscb; i++) {
-                       if (cmd == p->SCB_array[i]) {
-                               reset = (Scsi_Cmnd *)p->SCB_array[i];
-                               p->SCB_array[i] = NULL;
-                               reset->result = DID_RESET << 16;
-                               reset->scsi_done(reset);
-                               break;
-                       }
-               }
-               break;
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+  scb = &p->scb_array[aic7xxx_position(cmd)];
 
-           default:
-               panic("aic7xxx_reset: internal error\n");
-       }
+#if 0
+  printk("aic7xxx_kill: In the kill function...\n");
+#endif
+  PAUSE_SEQUENCER(p);
+
+  /*
+   * Case 1: In the QINFIFO
+   *
+   * This is the best case, really. Check to see if the
+   * command is still in the sequencer's input queue. If
+   * so, simply remove it. Reload the queue afterward.
+   */
+  queued = inb(QINCNT(p->base));
+
+  for (i = found = 0; i < (queued - found); i++)
+  {
+    scbsave[i] = inb(QINFIFO(p->base));
+
+    if (scbsave[i] == scb->position)
+    {
+      found = 1;
+      i = i - 1;
+    }
+  }
+
+  for (queued = 0; queued < i; queued++)
+  {
+    outb(scbsave[queued], QINFIFO(p->base));
+  }
+
+  if (found)
+  {
+    status = k_ok;
+    goto complete;
+  }
+
+  active_scb = inb(SCBPTR(p->base));
+  /*
+   * Case 2: Not the active command
+   *
+   * Check the current SCB bank. If it's not the one belonging
+   * to the command we want to kill, select the scb we want to
+   * abort and turn off the disconnected bit. The driver will
+   * then abort the command and notify us of the abort.
+   */
+  if (active_scb != scb->position)
+  {
+    outb(scb->position, SCBPTR(p->base));
+    scb_control = inb(SCBARRAY(p->base));
+    scb_control = scb_control & ~SCB_DIS;
+    outb(scb_control, SCBARRAY(p->base));
+    outb(active_scb, SCBPTR(p->base));
+    status = k_disconnect;
+    goto complete;
+  }
+
+  scb_control = inb(SCBARRAY(p->base));
+  if (scb_control & SCB_DIS)
+  {
+    scb_control = scb_control & ~SCB_DIS;
+    outb(scb_control, SCBARRAY(p->base));
+    status = k_disconnect;
+    goto complete;
+  }
+
+  /*
+   * Presumably at this point our target command is active. Check
+   * to see if there's a message already in effect. If not, place
+   * our message in and assert ATN so the target goes into MESSAGE
+   * OUT phase.
+   */
+  flags = inb(HA_FLAGS(p->base));
+  if (flags & ACTIVE_MSG)
+  {
+    /*
+     * If there is a message in progress, reset the bus
+     * and have all devices renegotiate.
+     */
+    if (cmd->channel & 0x01)
+    {
+      p->needsdtr = p->needsdtr_copy & 0xFF00;
+      p->sdtr_pending = p->sdtr_pending & 0x00FF;
+      outb(0, HA_ACTIVE1(p->base));
+    }
+    else
+    {
+      if (p->bus_type == AIC_WIDE)
+      {
+       p->needsdtr = p->needsdtr_copy;
+       p->needwdtr = p->needwdtr_copy;
+       p->sdtr_pending = 0;
+       p->wdtr_pending = 0;
+       outb(0, HA_ACTIVE0(p->base));
+       outb(0, HA_ACTIVE1(p->base));
+      }
+      else
+      {
+       p->needsdtr = p->needsdtr_copy & 0x00FF;
+       p->sdtr_pending = p->sdtr_pending & 0xFF00;
+       outb(0, HA_ACTIVE0(p->base));
+      }
+    }
+    /* Reset the bus. */
+    outb(SCSIRSTO, SCSISEQ(p->base));
+    udelay(1000);
+    outb(0, SCSISEQ(p->base));
+    aic7xxx_delay(AIC7XXX_RESET_DELAY);
+
+    status = k_busy;
+    goto complete;
+  }
+
+  outb(flags | ACTIVE_MSG, HA_FLAGS(p->base));    /* active message */
+  outb(1, HA_MSG_LEN(p->base));                   /* length = 1 */
+  outb(message, HA_MSG_START(p->base));           /* message body */
+
+  /*
+   * Assert ATN. Use the value of SCSISIGO saved by the
+   * sequencer code so we don't alter its contents radically
+   * in the middle of something critical.
+   */
+  outb(inb(HA_SIGSTATE(p->base)) | 0x10, SCSISIGO(p->base));
+
+  status = k_ok;
+
+  /*
+   * The command has been killed. Do the bookkeeping, unpause
+   * the sequencer, and notify the higher-level SCSI code.
+   */
+complete:
+  if (unpause)
+  {
+    UNPAUSE_SEQUENCER(p);
+  }
+
+  /*
+   * Mark the scb as free and clear the scbs command pointer.
+   * Add the scb to the head of the free list being careful
+   * to preserve the next pointers.
+   */
+  scb->state = SCB_FREE;          /* mark the scb as free */
+  scb->cmd = NULL;                /* clear the command pointer */
+  scb->next = p->free_scb;        /* preserve next pointer */
+  p->free_scb = scb;              /* add at head of free list */
+  cmd->result = cmd->result << 16;
+  cmd->scsi_done(cmd);
+  return(status);
+}
 
-       restore_flags(flags);
-       return(SCSI_RESET_SUCCESS);
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+int
+aic7xxx_abort(Scsi_Cmnd *cmd)
+{
+  int rv;
+  long flags;
+
+  save_flags(flags);
+  cli();
+
+  switch (aic7xxx_kill(cmd, ABORT, DID_ABORT, !0))
+  {
+    case k_ok:          rv = SCSI_ABORT_SUCCESS;        break;
+    case k_busy:        rv = SCSI_ABORT_BUSY;           break;
+    case k_absent:      rv = SCSI_ABORT_NOT_RUNNING;    break;
+    case k_disconnect:  rv = SCSI_ABORT_SNOOZE;         break;
+    default:            panic("aic7xxx_abort: internal error\n");
+  }
+
+  restore_flags(flags);
+  return(rv);
 }
 
-int aic7xxx_biosparam(Disk *disk, int devno, int geom[])
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_reset
+ *
+ * Description:
+ *   Resetting the bus always succeeds - is has to, otherwise the
+ *   kernel will panic! Try a surgical technique - sending a BUS
+ *   DEVICE RESET message - on the offending target before pulling
+ *   the SCSI bus reset line.
+ *-F*************************************************************************/
+int
+aic7xxx_reset(Scsi_Cmnd *cmd)
 {
-       int heads, sectors, cylinders;
-       struct aic7xxx_host *p;
-       
-       p = (struct aic7xxx_host *)disk->device->host->hostdata;
+  long flags;
+  struct aic7xxx_host *p;
+
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+  save_flags(flags);
+  cli();
+
+  switch (aic7xxx_kill(cmd, BUS_DEVICE_RESET, DID_RESET, 0))
+  {
+    case k_ok:
+      /*
+       * The RESET message was sent to the target
+       * with no problems. Flag that target as
+       * needing a SDTR negotiation on the next
+       * connection and restart the sequencer.
+       */
+      p->needsdtr = p->needsdtr & (1 << cmd->target);
+      UNPAUSE_SEQUENCER(p);
+      break;
+
+    case k_absent:
+      /*
+       * The sequencer will not be paused if aic7xxx_kill()
+       * couldn't find the command.
+       */
+      PAUSE_SEQUENCER(p);
+      /* falls through */
+
+    case k_busy:
+      cmd->result = DID_RESET << 16;  /* return reset code */
+      cmd->scsi_done(cmd);
+      break;
+
+    case k_disconnect:
+      /*
+       * Do a hard reset of the SCSI bus. According to the
+       * SCSI-2 draft specification, reset has to be asserted
+       * for at least 25us. I'm invoking the kernel delay
+       * function for 30us since I'm not totally trusting of
+       * the busy loop timing.
+       *
+       * XXX - I'm not convinced this works. I tried resetting
+       *       the bus before, trying to get the devices on the
+       *       bus to revert to asynchronous transfer, and it
+       *       never seemed to work.
+       */
+      debug("aic7xxx: attempting to reset scsi bus and card\n");
+
+      outb(SCSIRSTO, SCSISEQ(p->base));
+      udelay(1000);
+      outb(0, SCSISEQ(p->base));
+      aic7xxx_delay(AIC7XXX_RESET_DELAY);
+
+      UNPAUSE_SEQUENCER(p);
+
+      /*
+       * Locate the command and return a "reset" status
+       * for it. This is not completely correct and will
+       * probably return to haunt me later.
+       */
+      cmd->result = DID_RESET << 16;  /* return reset code */
+      cmd->scsi_done(cmd);
+      break;
+
+    default:
+      panic("aic7xxx_reset: internal error\n");
+  }
+
+  restore_flags(flags);
+  return(SCSI_RESET_SUCCESS);
+}
 
-       /*
-        *  XXX - if I could portably find the card's configuration
-        *        information, then this could be autodetected instead
-        *        of left to a boot-time switch.
-        */
-       heads = 64;
-       sectors = 32;
-       cylinders = disk->capacity / (heads * sectors);
-
-       if (p->extended && cylinders > 1024) {
-               heads = 255;
-               sectors = 63;
-               cylinders = disk->capacity / (255 * 63);
-       }
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_biosparam
+ *
+ * Description:
+ *   Return the disk geometry for the given SCSI device.
+ *-F*************************************************************************/
+int
+aic7xxx_biosparam(Disk *disk, int devno, int geom[])
+{
+  int heads, sectors, cylinders;
+  struct aic7xxx_host *p;
+
+  p = (struct aic7xxx_host *) disk->device->host->hostdata;
+
+  /*
+   * XXX - if I could portably find the card's configuration
+   *       information, then this could be autodetected instead
+   *       of left to a boot-time switch.
+   */
+  heads = 64;
+  sectors = 32;
+  cylinders = disk->capacity / (heads * sectors);
+
+  if (p->extended && cylinders > 1024)
+  {
+    heads = 255;
+    sectors = 63;
+    cylinders = disk->capacity / (255 * 63);
+  }
+
+  geom[0] = heads;
+  geom[1] = sectors;
+  geom[2] = cylinders;
+
+  return(0);
+}
 
-       geom[0] = heads;
-       geom[1] = sectors;
-       geom[2] = cylinders;
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = AIC7XXX;
 
-       return(0);
-}
+#include "scsi_module.c"
+#endif
 
index 027772a8b795831823fb64e54bfd7fb1d56a62ad..b2bd81edaa2f46ff5a792c43f1b7a4013d578ccc 100644 (file)
@@ -1,37 +1,55 @@
-/* @(#)aic7xxx.h 1.14 94/11/30 jda */
-
-/*
+/*+M*************************************************************************
  * Adaptec 274x/284x/294x device driver for Linux.
- * Copyright (c) 1994 The University of Calgary Department of Computer Science.
- * 
- * 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.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *   All rights reserved.
+ *
+ * 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.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of Calgary
+ *      Department of Computer Science and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
  * 
- * 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 aic7xxx_h
-#define aic7xxx_h
+ * $Id: aic7xxx.h,v 1.18 1995/06/22 04:17:56 deang Exp $
+ *-M*************************************************************************/
+#ifndef _aic7xxx_h
+#define _aic7xxx_h
 
-#define AIC7XXX_H_VERSION      "1.14"
+#define AIC7XXX_H_VERSION  "$Revision: 1.18 $"
 
 /*
- *  Scsi_Host_Template (see hosts.h) for 274x - some fields
- *  to do with card config are filled in after the card is
- *  detected.
+ * Scsi_Host_Template (see hosts.h) for AIC-7770/AIC-7870 - some fields
+ * to do with card config are filled in after the card is detected.
  */
 #define AIC7XXX        {                                               \
        NULL,                                                   \
        NULL,                                                   \
+       generic_proc_info,                                      \
+       "aic7xxx",                                              \
+       PROC_SCSI_AIC7XXX,                                      \
        NULL,                                                   \
        aic7xxx_detect,                                         \
        NULL,                                                   \
        -1,                     /* max simultaneous cmds      */\
        -1,                     /* scsi id of host adapter    */\
        SG_ALL,                 /* max scatter-gather cmds    */\
-       1,                      /* cmds per lun (linked cmds) */\
-       0,                      /* number of 274x's present   */\
+       2,                      /* cmds per lun (linked cmds) */\
+       0,                      /* number of 7xxx's present   */\
        0,                      /* no memory DMA restrictions */\
-       DISABLE_CLUSTERING                                      \
+       ENABLE_CLUSTERING                                       \
 }
 
 extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
@@ -60,4 +78,6 @@ extern int aic7xxx_reset(Scsi_Cmnd *);
 
 extern const char *aic7xxx_info(struct Scsi_Host *);
 
-#endif
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
+#endif /* _aic7xxx_h */
index 8538e8fd104779f962b81413bd03d47d4e4c3e49..a9bd7b8292650cb84c6b04614aa943ee1101c311 100644 (file)
@@ -1,27 +1,52 @@
-# @(#)aic7xxx.seq 1.32 94/11/29 jda
-#
-# Adaptec 274x/284x/294x device driver for Linux.
-# Copyright (c) 1994 The University of Calgary Department of Computer Science.
-# 
-# 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.
+##+M#########################################################################
+# Adaptec 274x/284x/294x device driver for Linux and FreeBSD.
+#
+# Copyright (c) 1994 John Aycock
+#   The University of Calgary Department of Computer Science.
+#   All rights reserved.
+#
+# Modifications/enhancements:
+#   Copyright (c) 1994, 1995 Justin Gibbs. All rights reserved.
+#
+# 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.
+# 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. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by the University of Calgary
+#      Department of Computer Science and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# 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.
 # 
-# 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.
+# FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 
+# optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
+#
+##-M#########################################################################
 
-VERSION AIC7XXX_SEQ_VERSION 1.32
+VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.19 1995/06/05 06:11:41 deang Exp $"
 
 SCBMASK                = 0x1f
 
 SCSISEQ                = 0x00
+ENRSELI                = 0x10
 SXFRCTL0       = 0x01
 SXFRCTL1       = 0x02
 SCSISIGI       = 0x03
@@ -33,7 +58,10 @@ STCNT                = 0x08
 STCNT+0                = 0x08
 STCNT+1                = 0x09
 STCNT+2                = 0x0a
+CLRSINT0       = 0x0b
 SSTAT0         = 0x0b
+SELDO          = 0x40
+SELDI          = 0x20
 CLRSINT1       = 0x0c
 SSTAT1         = 0x0c
 SIMODE1                = 0x11
@@ -51,6 +79,9 @@ SINDIR                = 0x6c
 DINDIR         = 0x6d
 FUNCTION1      = 0x6e
 HADDR          = 0x88
+HADDR+1                = 0x89
+HADDR+2                = 0x8a
+HADDR+3                = 0x8b
 HCNT           = 0x8c
 HCNT+0         = 0x8c
 HCNT+1         = 0x8d
@@ -64,19 +95,37 @@ QINFIFO             = 0x9b
 QINCNT         = 0x9c
 QOUTFIFO       = 0x9d
 
-SCSICONF       = 0x5a
+SCSICONF_A     = 0x5a
+SCSICONF_B     = 0x5b
 
 #  The two reserved bytes at SCBARRAY+1[23] are expected to be set to
 #  zero, and the reserved bit in SCBARRAY+0 is used as an internal flag
 #  to indicate whether or not to reload scatter-gather parameters after
-#  a disconnect.
+#  a disconnect.  We also use bits 6 & 7 to indicate whether or not to
+#  initiate SDTR or WDTR repectively when starting this command.
 #
 SCBARRAY+0     = 0xa0
+
+DISCONNECTED   = 0x04
+NEEDDMA                = 0x08
+SG_LOAD                = 0x10
+TAG_ENB                = 0x20
+NEEDSDTR       = 0x40
+NEEDWDTR       = 0x80
+
 SCBARRAY+1     = 0xa1
 SCBARRAY+2     = 0xa2
 SCBARRAY+3     = 0xa3
+SCBARRAY+4     = 0xa4
+SCBARRAY+5     = 0xa5
+SCBARRAY+6     = 0xa6
 SCBARRAY+7     = 0xa7
+SCBARRAY+8     = 0xa8
+SCBARRAY+9     = 0xa9
+SCBARRAY+10    = 0xaa
 SCBARRAY+11    = 0xab
+SCBARRAY+12    = 0xac
+SCBARRAY+13    = 0xad
 SCBARRAY+14    = 0xae
 SCBARRAY+15    = 0xaf
 SCBARRAY+16    = 0xb0
@@ -89,100 +138,265 @@ SCBARRAY+22      = 0xb6
 SCBARRAY+23    = 0xb7
 SCBARRAY+24    = 0xb8
 SCBARRAY+25    = 0xb9
+SCBARRAY+26    = 0xba
+SCBARRAY+27    = 0xbb
+SCBARRAY+28    = 0xbc
+SCBARRAY+29    = 0xbd
+SCBARRAY+30    = 0xbe
+
+BAD_PHASE      = 0x01                          # unknown scsi bus phase
+CMDCMPLT       = 0x02                          # Command Complete
+SEND_REJECT    = 0x11                          # sending a message reject
+NO_IDENT       = 0x21                          # no IDENTIFY after reconnect
+NO_MATCH       = 0x31                          # no cmd match for reconnect
+MSG_SDTR       = 0x41                          # SDTR message recieved
+MSG_WDTR       = 0x51                          # WDTR message recieved
+MSG_REJECT     = 0x61                          # Reject message recieved
+BAD_STATUS     = 0x71                          # Bad status from target
+RESIDUAL       = 0x81                          # Residual byte count != 0
+ABORT_TAG      = 0x91                          # Sent an ABORT_TAG message
+AWAITING_MSG   = 0xa1                          # Kernel requested to specify
+                                               # a message to this target
+                                               # (command was null), so tell
+                                               # it that it can fill the
+                                               # message buffer.
 
-SIGNAL_0       = 0x01                          # unknown scsi bus phase
-SIGNAL_1       = 0x11                          # message reject
-SIGNAL_2       = 0x21                          # no IDENTIFY after reconnect
-SIGNAL_3       = 0x31                          # no cmd match for reconnect
-SIGNAL_4       = 0x41                          # SDTR -> SCSIRATE conversion
 
 #  The host adapter card (at least the BIOS) uses 20-2f for SCSI
-#  device information, 32-33 and 5a-5f as well.  Since we don't support
-#  wide or twin-bus SCSI, 28-2f can be reclaimed.  As it turns out, the
-#  BIOS trashes 20-27 anyway, writing the synchronous negotiation results
+#  device information, 32-33 and 5a-5f as well. As it turns out, the
+#  BIOS trashes 20-2f, writing the synchronous negotiation results
 #  on top of the BIOS values, so we re-use those for our per-target
 #  scratchspace (actually a value that can be copied directly into
-#  SCSIRATE).  This implies, since we can't get the BIOS config values,
-#  that all targets will be negotiated with for synchronous transfer.
-#  NEEDSDTR has one bit per target indicating if an SDTR message is
-#  needed for that device - this will be set initially, as well as
-#  after a bus reset condition.
-#
-#  The high bit of DROPATN is set if ATN should be dropped before the ACK
-#  when outb is called.  REJBYTE contains the first byte of a MESSAGE IN
-#  message, so the driver can report an intelligible error if a message is
-#  rejected.
-#
-#  RESELECT's high bit is true if we are currently handling a reselect;
+#  SCSIRATE).  The kernel driver will enable synchronous negotiation
+#  for all targets that have a value other than 0 in the lower four
+#  bits of the target scratch space.  This should work irregardless of
+#  whether the bios has been installed. NEEDWDTR and NEEDSDTR are the top
+#  two bits of the SCB control byte.  The kernel driver will set these
+#  when a WDTR or SDTR message should be sent to the target the SCB's 
+#  command references.
+#
+#  REJBYTE contains the first byte of a MESSAGE IN message, so the driver 
+#  can report an intelligible error if a message is rejected.
+#
+#  FLAGS's high bit is true if we are currently handling a reselect;
 #  its next-highest bit is true ONLY IF we've seen an IDENTIFY message
 #  from the reselecting target.  If we haven't had IDENTIFY, then we have
 #  no idea what the lun is, and we can't select the right SCB register
 #  bank, so force a kernel panic if the target attempts a data in/out or
-#  command phase instead of corrupting something.
+#  command phase instead of corrupting something.  FLAGS also contains
+#  configuration bits so that we can optimize for TWIN and WIDE controllers
+#  as well as the MAX_OFFSET bit which we set when we want to negotiate for
+#  maximum sync offset irregardless of what the per target scratch space says.
 #
 #  Note that SG_NEXT occupies four bytes.
 #
 SYNCNEG                = 0x20
-DISC_DSB_A     = 0x32
 
-DROPATN                = 0x30
 REJBYTE                = 0x31
-RESELECT       = 0x34
-
-MSG_FLAGS      = 0x35
-MSG_LEN                = 0x36
-MSG_START+0    = 0x37
-MSG_START+1    = 0x38
-MSG_START+2    = 0x39
-MSG_START+3    = 0x3a
-MSG_START+4    = 0x3b
-MSG_START+5    = 0x3c
--MSG_START+0   = 0xc9                          # 2's complement of MSG_START+0
-
-ARG_1          = 0x4c                          # sdtr conversion args & return
-ARG_2          = 0x4d
-RETURN_1       = 0x4c
-
-SIGSTATE       = 0x4e                          # value written to SCSISIGO
-NEEDSDTR       = 0x4f                          # send SDTR message, 1 bit/trgt
-
-SG_SIZEOF      = 12                            # sizeof(struct scatterlist)
-SG_NOLOAD      = 0x50                          # load SG pointer/length?
-SG_COUNT       = 0x51                          # working value of SG count
-SG_NEXT                = 0x52                          # working value of SG pointer
-SG_NEXT+0      = 0x52
-SG_NEXT+1      = 0x53
-SG_NEXT+2      = 0x54
-SG_NEXT+3      = 0x55
-
-SCBCOUNT       = 0x56                          # the actual number of SCBs
+DISC_DSB_A     = 0x32
+DISC_DSB_B     = 0x33
+
+MSG_LEN                = 0x34
+MSG_START+0    = 0x35
+MSG_START+1    = 0x36
+MSG_START+2    = 0x37
+MSG_START+3    = 0x38
+MSG_START+4    = 0x39
+MSG_START+5    = 0x3a
+-MSG_START+0   = 0xcb                          # 2's complement of MSG_START+0
+
+ARG_1          = 0x4a                          # sdtr conversion args & return
+BUS_16_BIT     = 0x01
+RETURN_1       = 0x4a
+
+SIGSTATE       = 0x4b                          # value written to SCSISIGO
+
+# Linux users should use 0xc (12) for SG_SIZEOF
+#SG_SIZEOF     = 0x8                           # sizeof(struct ahc_dma)
+SG_SIZEOF      = 0xc                           # sizeof(struct scatterlist)
+# if AIC7XXX_USE_SG
+SCB_SIZEOF     = 0x13                          # sizeof SCB to DMA (19 bytes)
+# else
+#SCB_SIZEOF    = 0x1a                          # sizeof SCB without SG
+# endif
+
+SG_NOLOAD      = 0x4c                          # load SG pointer/length?
+SG_COUNT       = 0x4d                          # working value of SG count
+SG_NEXT                = 0x4e                          # working value of SG pointer
+SG_NEXT+0      = 0x4e
+SG_NEXT+1      = 0x4f
+SG_NEXT+2      = 0x50
+SG_NEXT+3      = 0x51
+
+SCBCOUNT       = 0x52                          # the actual number of SCBs
+FLAGS          = 0x53                          # Device configuration flags
+TWIN_BUS       = 0x01
+WIDE_BUS       = 0x02
+MAX_OFFSET     = 0x08
+ACTIVE_MSG     = 0x20
+IDENTIFY_SEEN  = 0x40
+RESELECTED     = 0x80
+
+MAX_OFFSET_8BIT        = 0x0f
+MAX_OFFSET_WIDE        = 0x08
+
+ACTIVE_A       = 0x54
+ACTIVE_B       = 0x55
+SAVED_TCL      = 0x56                          # Temporary storage for the 
+                                               # target/channel/lun of a
+                                               # reconnecting target
+
+# After starting the selection hardware, we return to the "poll_for_work"
+# loop so that we can check for reconnecting targets as well as for our
+# selection to complete just in case the reselection wins bus arbitration.
+# The problem with this is that we must keep track of the SCB that we've
+# already pulled from the QINFIFO and started the selection on just in case
+# the reselection wins so that we can retry the selection at a later time.
+# This problem cannot be resolved by holding a single entry in scratch
+# ram since a reconnecting target can request sense and this will create
+# yet another SCB waiting for selection.  The solution used here is to 
+# use byte 31 of the SCB as a psuedo-next pointer and to thread a list
+# of SCBs that are awaiting selection.  Since 0 is a valid SCB offset, 
+# SCB_LIST_NULL is 0x10 which is out of range.  The kernel driver must
+# add an entry to this list everytime a request sense occurs.  The sequencer
+# will automatically consume the entries.
+
+WAITING_SCBH   = 0x57                          # head of list of SCBs awaiting
+                                               # selection
+WAITING_SCBT   = 0x58                          # tail of list of SCBs awaiting
+                                               # selection
+SCB_LIST_NULL  = 0x10
+
 
 #  Poll QINCNT for work - the lower bits contain
 #  the number of entries in the Queue In FIFO.
 #
 start:
-       test    SCSISIGI,0x4    jnz reselect    # BSYI
-       test    QINCNT,SCBMASK  jz start
-
-#  We have at least one queued SCB now.  Set the SCB pointer
-#  from the FIFO so we see the right bank of SCB registers,
-#  then set SCSI options and set the initiator and target
-#  SCSI IDs.
+       test    WAITING_SCBH,SCB_LIST_NULL jz start_waiting
+poll_for_work:
+       test    FLAGS,TWIN_BUS  jz start2       # Are we a twin channel device?
+# For fairness, we check the other bus first, since we just finished a 
+# transaction on the current channel.
+       xor     SBLKCTL,0x08                    # Toggle to the other bus
+       test    SSTAT0,SELDI    jnz reselect
+       test    SSTAT0,SELDO    jnz select
+       xor     SBLKCTL,0x08                    # Toggle to the original bus
+start2:
+       test    SSTAT0,SELDI    jnz reselect
+       test    SSTAT0,SELDO    jnz select
+       test    WAITING_SCBH,SCB_LIST_NULL jz start_waiting
+       test    QINCNT,SCBMASK  jz poll_for_work
+
+# We have at least one queued SCB now and we don't have any 
+# SCBs in the list of SCBs awaiting selection.  Set the SCB
+# pointer from the FIFO so we see the right bank of SCB 
+# registers, then set SCSI options and set the initiator and
+# target SCSI IDs.
 #
        mov     SCBPTR,QINFIFO
-       mov     SCBARRAY+1      call initialize
+
+# If the control byte of this SCB has the NEEDDMA flag set, we have
+# yet to DMA it from host memory
+
+test    SCBARRAY+0,NEEDDMA      jz test_busy    
+       clr     HCNT+2
+       clr     HCNT+1
+       mvi     HCNT+0,SCB_SIZEOF
+
+       mvi     DINDEX,HADDR      
+       mvi     SCBARRAY+26     call bcopy_4
+        
+       mvi     DFCNTRL,0xd                     # HDMAEN|DIRECTION|FIFORESET
+
+#  Wait for DMA from host memory to data FIFO to complete, then disable
+#  DMA and wait for it to acknowledge that it's off.
+#
+       call    dma_finish
+
+# Copy the SCB from the FIFO to  the SCBARRAY
+
+       mvi     DINDEX, SCBARRAY+0
+       call    bcopy_3_dfdat 
+       call    bcopy_4_dfdat
+       call    bcopy_4_dfdat
+       call    bcopy_4_dfdat   
+       call    bcopy_4_dfdat
+# ifndef AIC7XXX_USE_SG
+#      call    bcopy_3_dfdat
+#      call    bcopy_4_dfdat
+# endif
+
+# See if there is not already an active SCB for this target.  This code
+# locks out on a per target basis instead of target/lun.  Although this
+# is not ideal for devices that have multiple luns active at the same
+# time, it is faster than looping through all SCB's looking for active
+# commands.  It may be benificial to make findscb a more general procedure
+# to see if the added cost of the search is negligible.  This code also 
+# assumes that the kernel driver will clear the active flags on board 
+# initialization, board reset, and a target's SELTO.
+
+test_busy:
+       test    SCBARRAY+0,0x20 jnz start_scb
+       and     FUNCTION1,0x70,SCBARRAY+1
+       mov     A,FUNCTION1
+       test    SCBARRAY+1,0x88 jz test_a       # Id < 8 && A channel
+
+       test    ACTIVE_B,A      jnz requeue
+       or      ACTIVE_B,A      # Mark the current target as busy
+       jmp     start_scb
+
+# Place the currently active back on the queue for later processing
+requeue:
+       mov     QINFIFO, SCBPTR
+       jmp     poll_for_work
+
+# Pull the first entry off of the waiting for selection list
+start_waiting:
+       mov     SCBPTR,WAITING_SCBH
+       jmp     start_scb
+
+test_a:
+       test    ACTIVE_A,A      jnz requeue
+       or      ACTIVE_A,A      # Mark the current target as busy
+
+start_scb:
+       and     SINDEX,0xf7,SBLKCTL  #Clear the channel select bit
+       and     A,0x08,SCBARRAY+1    #Get new channel bit
+       or      SINDEX,A             
+       mov     SBLKCTL,SINDEX  # select channel
+       mov     SCBARRAY+1      call initialize_scsiid
+
+# Enable selection phase as an initiator, and do automatic ATN
+# after the selection.  We do this now so that we can overlap the
+# rest of our work to set up this target with the arbitration and
+# selection bus phases.
+#
+start_selection:
+       or      SCSISEQ,0x48                    # ENSELO|ENAUTOATNO
+       mov     WAITING_SCBH, SCBPTR
        clr     SG_NOLOAD
-       clr     RESELECT
+       and     FLAGS,0x3f      # !RESELECTING
 
 #  As soon as we get a successful selection, the target should go
 #  into the message out phase since we have ATN asserted.  Prepare
 #  the message to send, locking out the device driver.  If the device
 #  driver hasn't beaten us with an ABORT or RESET message, then tack
-#  on a SDTR negotiation if required.
+#  on an SDTR negotiation if required.
 #
 #  Messages are stored in scratch RAM starting with a flag byte (high bit
 #  set means active message), one length byte, and then the message itself.
 #
+
+       test    SCBARRAY+11,0xff jnz identify   # 0 Length Command?
+
+#  The kernel has sent us an SCB with no command attached.  This implies
+#  that the kernel wants to send a message of some sort to this target,
+#  so we interrupt the driver, allow it to fill the message buffer, and
+#  then go back into the arbitration loop
+       mvi     INTSTAT,AWAITING_MSG
+       jmp     poll_for_work
+
+identify:
        mov     SCBARRAY+1      call disconnect # disconnect ok?
 
        and     SINDEX,0x7,SCBARRAY+1           # lun
@@ -190,64 +404,50 @@ start:
        or      SINDEX,0x80     call mk_mesg    # IDENTIFY message
 
        mov     A,SINDEX
+       test    SCBARRAY+0,0xe0 jz  !message    # WDTR, SDTR or TAG??
        cmp     MSG_START+0,A   jne !message    # did driver beat us?
-       mvi     MSG_START+1     call mk_sdtr    # build SDTR message if needed
 
-!message:
+# Tag Message if Tag enabled in SCB control block.  Use SCBPTR as the tag
+# value
 
-#  Enable selection phase as an initiator, and do automatic ATN
-#  after the selection.
-#
-       mvi     SCSISEQ,0x48                    # ENSELO|ENAUTOATNO
+mk_tag:
+       mvi     DINDEX, MSG_START+1
+       test    SCBARRAY+0,TAG_ENB jz mk_tag_done
+       and     A,0x23,SCBARRAY+0
+       mov     DINDIR,A
+       mov     DINDIR,SCBPTR
 
-#  Wait for successful arbitration.  The AIC-7770 documentation says
-#  that SELINGO indicates successful arbitration, and that it should
-#  be used to look for SELDO.  However, if the sequencer is paused at
-#  just the right time - a parallel fsck(8) on two drives did it for
-#  me - then SELINGO can flip back to false before we've seen it.  This
-#  makes the sequencer sit in the arbitration loop forever.  This is
-#  Not Good.
-#
-#  Therefore, I've added a check in the arbitration loop for SELDO
-#  too.  This could arguably be made a critical section by disabling
-#  pauses, but I don't want to make a potentially infinite loop a CS.
-#  I suppose you could fold it into the select loop, too, but since
-#  I've been hunting this bug for four days it's kinda like a trophy.
-#
-arbitrate:
-       test    SSTAT0,0x40     jnz *select     # SELDO
-       test    SSTAT0,0x10     jz arbitrate    # SELINGO
+       add     MSG_LEN,-MSG_START+0,DINDEX     # update message length
 
-#  Wait for a successful selection.  If the hardware selection
-#  timer goes off, then the driver gets the interrupt, so we don't
-#  need to worry about it.
-#
-select:
-       test    SSTAT0,0x40     jz select       # SELDO
-       jmp     *select
+mk_tag_done:
+
+       mov     DINDEX  call mk_dtr     # build DTR message if needed
+
+!message:
+       jmp     poll_for_work
 
-#  Reselection is being initiated by a target - we've seen the BSY
-#  line driven active, and we didn't do it!  Enable the reselection
-#  hardware, and wait for it to finish.  Make a note that we've been
+#  Reselection has been initiated by a target. Make a note that we've been
 #  reselected, but haven't seen an IDENTIFY message from the target
 #  yet.
 #
 reselect:
-       mvi     SCSISEQ,0x10                    # ENRSELI
+       mov     SELID           call initialize_scsiid
+       and     FLAGS,0x3f                      # reselected, no IDENTIFY       
+       or      FLAGS,RESELECTED jmp select2
 
-reselect1:
-       test    SSTAT0,0x20     jz reselect1    # SELDI
-       mov     SELID           call initialize
-
-       mvi     RESELECT,0x80                   # reselected, no IDENTIFY
-
-#  After the [re]selection, make sure that the [re]selection enable
-#  bit is off.  This chip is flaky enough without extra things
-#  turned on.  Also clear the BUSFREE bit in SSTAT1 since we'll be
-#  using it shortly.
+# After the selection, remove this SCB from the "waiting for selection"
+# list.  This is achieved by simply moving our "next" pointer into
+# WAITING_SCBH and setting our next pointer to null so that the next
+# time this SCB is used, we don't get confused.
 #
-*select:
-       clr     SCSISEQ
+select:
+       or      SCBARRAY+0,NEEDDMA
+       mov     WAITING_SCBH,SCBARRAY+30
+       mvi     SCBARRAY+30,SCB_LIST_NULL
+select2:
+       call    initialize_for_target
+       mvi     SCSISEQ,ENRSELI
+       mvi     CLRSINT0,0x60                   # CLRSELDI|CLRSELDO
        mvi     CLRSINT1,0x8                    # CLRBUSFREE
 
 #  Main loop for information transfer phases.  If BSY is false, then
@@ -273,41 +473,44 @@ ITloop:
        cmp     A,0xa0          je p_mesgout
        cmp     A,0xe0          je p_mesgin
 
-       mvi     INTSTAT,SIGNAL_0                # unknown - signal driver
+       mvi     INTSTAT,BAD_PHASE               # unknown - signal driver
 
 p_dataout:
        mvi     0               call scsisig    # !CDO|!IOO|!MSGO
        call    assert
        call    sg_load
 
-       mvi     A,3
-       mvi     DINDEX,HCNT
-       mvi     SCBARRAY+23     call bcopy
+       mvi     DINDEX,HADDR
+       mvi     SCBARRAY+19     call bcopy_4
 
-       mvi     A,3
-       mvi     DINDEX,STCNT
-       mvi     SCBARRAY+23     call bcopy
+#      mvi     DINDEX,HCNT     # implicit since HCNT is next to HADDR
+       mvi     SCBARRAY+23     call bcopy_3
 
-       mvi     A,4
-       mvi     DINDEX,HADDR
-       mvi     SCBARRAY+19     call bcopy
+       mvi     DINDEX,STCNT
+       mvi     SCBARRAY+23     call bcopy_3
 
+# If we are the last SG block, don't set wideodd.
+       test    SCBARRAY+18,0xff jnz p_dataout_wideodd
        mvi     0x3d            call dma        # SCSIEN|SDMAEN|HDMAEN|
                                                #   DIRECTION|FIFORESET
+       jmp     p_dataout_rest
 
+p_dataout_wideodd:
+       mvi     0xbd            call dma        # WIDEODD|SCSIEN|SDMAEN|HDMAEN|
+                                               #   DIRECTION|FIFORESET
+
+p_dataout_rest:
 #  After a DMA finishes, save the final transfer pointer and count
 #  back into the SCB, in case a device disconnects in the middle of
 #  a transfer.  Use SHADDR and STCNT instead of HADDR and HCNT, since
 #  it's a reflection of how many bytes were transferred on the SCSI
 #  (as opposed to the host) bus.
 #
-       mvi     A,3
        mvi     DINDEX,SCBARRAY+23
-       mvi     STCNT           call bcopy
+       mvi     STCNT           call bcopy_3
 
-       mvi     A,4
        mvi     DINDEX,SCBARRAY+19
-       mvi     SHADDR          call bcopy
+       mvi     SHADDR          call bcopy_4
 
        call    sg_advance
        mov     SCBARRAY+18,SG_COUNT            # residual S/G count
@@ -319,27 +522,29 @@ p_datain:
        call    assert
        call    sg_load
 
-       mvi     A,3
-       mvi     DINDEX,HCNT
-       mvi     SCBARRAY+23     call bcopy
+       mvi     DINDEX,HADDR
+       mvi     SCBARRAY+19     call bcopy_4
+
+#      mvi     DINDEX,HCNT     # implicit since HCNT is next to HADDR
+       mvi     SCBARRAY+23     call bcopy_3
 
-       mvi     A,3
        mvi     DINDEX,STCNT
-       mvi     SCBARRAY+23     call bcopy
-
-       mvi     A,4
-       mvi     DINDEX,HADDR
-       mvi     SCBARRAY+19     call bcopy
+       mvi     SCBARRAY+23     call bcopy_3
 
+# If we are the last SG block, don't set wideodd.
+       test    SCBARRAY+18,0xff jnz p_datain_wideodd
        mvi     0x39            call dma        # SCSIEN|SDMAEN|HDMAEN|
                                                #   !DIRECTION|FIFORESET
-       mvi     A,3
+       jmp     p_datain_rest
+p_datain_wideodd:
+       mvi     0xb9            call dma        # WIDEODD|SCSIEN|SDMAEN|HDMAEN|
+                                               #   !DIRECTION|FIFORESET
+p_datain_rest:
        mvi     DINDEX,SCBARRAY+23
-       mvi     STCNT           call bcopy
+       mvi     STCNT           call bcopy_3
 
-       mvi     A,4
        mvi     DINDEX,SCBARRAY+19
-       mvi     SHADDR          call bcopy
+       mvi     SHADDR          call bcopy_4
 
        call    sg_advance
        mov     SCBARRAY+18,SG_COUNT            # residual S/G count
@@ -354,17 +559,14 @@ p_command:
        mvi     0x80            call scsisig    # CDO|!IOO|!MSGO
        call    assert
 
-       mvi     A,3
-       mvi     DINDEX,HCNT
-       mvi     SCBARRAY+11     call bcopy
+       mvi     DINDEX,HADDR
+       mvi     SCBARRAY+7      call bcopy_4
 
-       mvi     A,3
-       mvi     DINDEX,STCNT
-       mvi     SCBARRAY+11     call bcopy
+#      mvi     DINDEX,HCNT     # implicit since HCNT is next to HADDR
+       mvi     SCBARRAY+11     call bcopy_3
 
-       mvi     A,4
-       mvi     DINDEX,HADDR
-       mvi     SCBARRAY+7      call bcopy
+       mvi     DINDEX,STCNT
+       mvi     SCBARRAY+11     call bcopy_3
 
        mvi     0x3d            call dma        # SCSIEN|SDMAEN|HDMAEN|
                                                #   DIRECTION|FIFORESET
@@ -376,8 +578,8 @@ p_command:
 p_status:
        mvi     0xc0            call scsisig    # CDO|IOO|!MSGO
 
-       mvi     SCBARRAY+14     call inb
-       jmp     ITloop
+       mvi     SCBARRAY+14     call inb_first
+       jmp     p_mesgin_done
 
 #  Message out phase.  If there is no active message, but the target
 #  took us into this phase anyway, build a no-op message and send it.
@@ -386,12 +588,14 @@ p_mesgout:
        mvi     0xa0            call scsisig    # CDO|!IOO|MSGO
        mvi     0x8             call mk_mesg    # build NOP message
 
+       clr     STCNT+2
+       clr     STCNT+1
+
 #  Set up automatic PIO transfer from MSG_START.  Bit 3 in
 #  SXFRCTL0 (SPIOEN) is already on.
 #
        mvi     SINDEX,MSG_START+0
        mov     DINDEX,MSG_LEN
-       clr     A
 
 #  When target asks for a byte, drop ATN if it's the last one in
 #  the message.  Otherwise, keep going until the message is exhausted.
@@ -424,14 +628,13 @@ p_mesgout2:
 #  an SPIORDY that hadn't dropped yet.
 #
 p_mesgout3:
-       call    one_stcnt
+       mvi     STCNT+0, 0x01   
        mov     SCSIDATL,SINDIR
 
 p_mesgout4:
        test    SSTAT0,0x4      jz p_mesgout4   # SDONE
        dec     DINDEX
-       inc     A
-       cmp     MSG_LEN,A       jne p_mesgout2
+       test    DINDEX,0xff     jnz p_mesgout2
 
 #  If the next bus phase after ATN drops is a message out, it means
 #  that the target is requesting that the last message(s) be resent.
@@ -448,7 +651,7 @@ p_mesgout5:
 
 p_mesgout6:
        mvi     CLRSINT1,0x40                   # CLRATNO - in case of PHASEMIS
-       clr     MSG_FLAGS                       # no active msg
+       and     FLAGS,0xdf                      # no active msg
        jmp     ITloop
 
 #  Message in phase.  Bytes are read using Automatic PIO mode, but not
@@ -468,46 +671,103 @@ p_mesgin:
 
 #  We got a "command complete" message, so put the SCB pointer
 #  into the Queue Out, and trigger a completion interrupt.
-#
+#  Check status for non zero return and interrupt driver if needed
+#  This allows the driver to interpret errors only when they occur
+#  instead of always uploading the scb.  If the status is SCSI_CHECK,
+#  the driver will download a new scb requesting sense to replace
+#  the old one, modify the "waiting for selection" SCB list and set 
+#  RETURN_1 to 0x80.  If RETURN_1 is set to 0x80 the sequencer imediately
+#  jumps to main loop where it will run down the waiting SCB list.
+#  If the kernel driver does not wish to request sense, it need
+#  only clear RETURN_1, and the command is allowed to complete.  We don't 
+#  bother to post to the QOUTFIFO in the error case since it would require 
+#  extra work in the kernel driver to ensure that the entry was removed 
+#  before the command complete code tried processing it.
+
+# First check for residuals
+       test    SCBARRAY+15,0xff        jnz resid
+       test    SCBARRAY+16,0xff        jnz resid
+       test    SCBARRAY+17,0xff        jnz resid
+
+check_status:
+       test    SCBARRAY+14,0xff        jz status_ok    # 0 Status?
+       mvi     INTSTAT,BAD_STATUS                      # let driver know
+       test    RETURN_1, 0x80  jz status_ok
+       jmp     p_mesgin_done
+
+status_ok:
+#  First, mark this target as free.
+       test    SCBARRAY+0,0x20 jnz complete            # Tagged command
+       and     FUNCTION1,0x70,SCBARRAY+1
+       mov     A,FUNCTION1
+       test    SCBARRAY+1,0x88 jz clear_a
+       xor     ACTIVE_B,A
+       jmp     complete
+
+clear_a:
+       xor     ACTIVE_A,A
+
+complete:
        mov     QOUTFIFO,SCBPTR
-       mvi     INTSTAT,0x2                     # CMDCMPLT
+       mvi     INTSTAT,CMDCMPLT
+       test    SCBARRAY+11,0xff jz start       # Immediate message complete
        jmp     p_mesgin_done
 
-#  Is it an extended message?  We only support the synchronous data
-#  transfer request message, which will probably be in response to
-#  an SDTR message out from us.  If it's not an SDTR, reject it -
+# If we have a residual count, interrupt and tell the host.  Other
+# alternatives are to pause the sequencer on all command completes (yuck),
+# dma the resid directly to the host (slick, but a ton of instructions), or
+# have the sequencer pause itself when it encounters a non-zero resid 
+# (unecessary pause just to flag the command -- yuck, but takes few instructions
+# and since it shouldn't happen that often is good enough for our purposes).  
+
+resid:
+       mvi     INTSTAT,RESIDUAL
+       jmp     check_status
+
+#  Is it an extended message?  We only support the synchronous and wide data
+#  transfer request messages, which will probably be in response to
+#  WDTR or SDTR message outs from us.  If it's not SDTR or WDTR, reject it -
 #  apparently this can be done after any message in byte, according
 #  to the SCSI-2 spec.
 #
-#  XXX - we should really reject this if we didn't initiate the SDTR
-#       negotiation; this may cause problems with unusual devices.
-#
 p_mesgin1:
        cmp     A,1             jne p_mesgin2   # extended message code?
        
-       mvi     A               call inb_next
-       cmp     A,3             jne p_mesginN   # extended mesg length = 3
-       mvi     A               call inb_next
-       cmp     A,1             jne p_mesginN   # SDTR code
+       mvi     ARG_1           call inb_next   # extended message length
+       mvi     A               call inb_next   # extended message code
+
+       cmp     A,1             je p_mesginSDTR # Syncronous negotiation message
+       cmp     A,3             je p_mesginWDTR # Wide negotiation message
+       jmp     p_mesginN
+
+p_mesginWDTR:
+       cmp     ARG_1,2         jne p_mesginN   # extended mesg length = 2
+       mvi     A               call inb_next   # Width of bus
+       mvi     INTSTAT,MSG_WDTR                # let driver know
+       test    RETURN_1,0x80   jz p_mesgin_done# Do we need to send WDTR?
+
+# We didn't initiate the wide negotiation, so we must respond to the request
+       and     RETURN_1,0x7f                   # Clear the SEND_WDTR Flag
+       or      FLAGS,ACTIVE_MSG
+       mvi     DINDEX,MSG_START+0
+       mvi     MSG_START+0     call mk_wdtr    # build WDTR message    
+       or      SINDEX,0x10,SIGSTATE            # turn on ATNO
+       call    scsisig
+       jmp     p_mesgin_done
 
+p_mesginSDTR:
+       cmp     ARG_1,3         jne p_mesginN   # extended mesg length = 3
        mvi     ARG_1           call inb_next   # xfer period
-       mvi     ARG_2           call inb_next   # REQ/ACK offset
-       mvi     INTSTAT,SIGNAL_4                # call driver to convert
-
-       call    ndx_sdtr                        # index sync config for target
-       mov     DINDEX,SINDEX
-       mov     DINDIR,RETURN_1                 # save returned value
-
-       not     A                               # turn off "need sdtr" flag
-       and     NEEDSDTR,A
-
-#  Even though the SCSI-2 specification says that a device responding
-#  to our SDTR message should honor our parameters for transmitting
-#  to us, it doesn't seem to work too well in real life.  In particular,
-#  a lot of CD-ROM and tape units don't function: try using the SDTR
-#  parameters the device sent us for both transmitting and receiving.
-#
-       mov     SCSIRATE,RETURN_1
+       mvi     A               call inb_next   # REQ/ACK offset
+       mvi     INTSTAT,MSG_SDTR                # call driver to convert
+
+       test    RETURN_1,0xc0   jz p_mesgin_done# Do we need to mk_sdtr or rej?
+       test    RETURN_1,0x40   jnz p_mesginN   # Requested SDTR too small - rej
+       or      FLAGS,ACTIVE_MSG
+       mvi     DINDEX, MSG_START+0
+       mvi     MSG_START+0     call mk_sdtr
+       or      SINDEX,0x10,SIGSTATE            # turn on ATNO
+       call    scsisig
        jmp     p_mesgin_done
 
 #  Is it a disconnect message?  Set a flag in the SCB to remind us
@@ -547,43 +807,47 @@ p_mesgin5:
 
        test    A,0x78          jnz p_mesginN   # !DiscPriv|!LUNTAR|!Reserved
 
-       mov     A               call findSCB    # switch to correct SCB
-
-#  If a active message is present after calling findSCB, then either it
-#  or the driver is trying to abort the command.  Either way, something
-#  untoward has happened and we should just leave it alone.
-#
-       test    MSG_FLAGS,0x80  jnz p_mesgin_done
-
-       xor     SCBARRAY+0,0x4                  # clear disconnect bit in SCB
-       mvi     RESELECT,0xc0                   # make note of IDENTIFY
+       and     A,0x07                          # lun in lower three bits
+       or      SAVED_TCL,A,SELID          
+       and     SAVED_TCL,0xf7
+       and     A,0x08,SBLKCTL                  # B Channel??
+       or      SAVED_TCL,A
+       call    inb_last                        # ACK
+       mov     ALLZEROS        call findSCB    
+setup_SCB:
+       and     SCBARRAY+0,0xfb                 # clear disconnect bit in SCB
+       or      FLAGS,IDENTIFY_SEEN             # make note of IDENTIFY
 
        call    sg_scb2ram                      # implied restore pointers
                                                #   required on reselect
-       jmp     p_mesgin_done
+       jmp     ITloop
+get_tag:
+       mvi     A               call inb_first
+       cmp     A,0x20          jne return      # Simple Tag message?
+       mvi     A               call inb_next
+       call                    inb_last
+       test    A,0xf0          jnz abort_tag   # Tag in range?
+       mov     SCBPTR,A
+       mov     A,SAVED_TCL
+       cmp     SCBARRAY+1,A            jne abort_tag
+       test    SCBARRAY+0,TAG_ENB      jz  abort_tag
+       ret
+abort_tag:
+       or      SINDEX,0x10,SIGSTATE            # turn on ATNO
+       call    scsisig
+       mvi     INTSTAT,ABORT_TAG               # let driver know
+       mvi     0xd             call mk_mesg    # ABORT TAG message
+       ret
 
-#  Message reject?  If we have an outstanding SDTR negotiation, assume
-#  that it's a response from the target selecting asynchronous transfer,
-#  otherwise just ignore it since we have no clue what it pertains to.
-#
-#  XXX - I don't have a device that responds this way.  Does this code
-#       actually work?
+#  Message reject?  Let the kernel driver handle this.  If we have an 
+#  outstanding WDTR or SDTR negotiation, assume that it's a response from 
+#  the target selecting 8bit or asynchronous transfer, otherwise just ignore 
+#  it since we have no clue what it pertains to.
 #
 p_mesgin6:
        cmp     A,7             jne p_mesgin7   # message reject code?
 
-       and     FUNCTION1,0x70,SCSIID           # outstanding SDTR message?
-       mov     A,FUNCTION1
-       test    NEEDSDTR,A      jz p_mesgin_done  # no - ignore rejection
-
-       call    ndx_sdtr                        # note use of asynch xfer
-       mov     DINDEX,SINDEX
-       clr     DINDIR
-
-       not     A                               # turn off "active sdtr" flag
-       and     NEEDSDTR,A
-
-       clr     SCSIRATE                        # select asynch xfer
+       mvi     INTSTAT, MSG_REJECT
        jmp     p_mesgin_done
 
 #  [ ADD MORE MESSAGE HANDLING HERE ]
@@ -600,7 +864,7 @@ p_mesgin7:
 p_mesginN:
        or      SINDEX,0x10,SIGSTATE            # turn on ATNO
        call    scsisig
-       mvi     INTSTAT,SIGNAL_1                # let driver know
+       mvi     INTSTAT,SEND_REJECT             # let driver know
 
        mvi     0x7             call mk_mesg    # MESSAGE REJECT message
 
@@ -608,6 +872,7 @@ p_mesgin_done:
        call    inb_last                        # ack & turn auto PIO back on
        jmp     ITloop
 
+
 #  Bus free phase.  It might be useful to interrupt the device
 #  driver if we aren't expecting this.  For now, make sure that
 #  ATN isn't being asserted and look for a new command.
@@ -615,44 +880,54 @@ p_mesgin_done:
 p_busfree:
        mvi     CLRSINT1,0x40                   # CLRATNO
        clr     SIGSTATE
+
+#  if this is an immediate command, perform a psuedo command complete to
+#  notify the driver.
+       test    SCBARRAY+11,0xff        jz status_ok
        jmp     start
 
-#  Bcopy: number of bytes to transfer should be in A, DINDEX should
-#  contain the destination address, and SINDEX should contain the
-#  source address.  All input parameters are trashed on return.
-#
-bcopy:
+#  Instead of a generic bcopy routine that requires an argument, we unroll
+#  the two cases that are actually used, and call them explicitly.  This
+#  not only reduces the overhead of doing a bcopy by 2/3rds, but ends up
+#  saving space in the program since you don't have to put the argument 
+#  into the accumulator before the call.  Both functions expect DINDEX to
+#  contain the destination address and SINDEX to contain the source 
+#  address.
+bcopy_3:
        mov     DINDIR,SINDIR
-       dec     A
-       cmp     ALLZEROS,A      jne bcopy
-       ret
+       mov     DINDIR,SINDIR
+       mov     DINDIR,SINDIR   ret
+
+bcopy_4:
+       mov     DINDIR,SINDIR
+       mov     DINDIR,SINDIR
+       mov     DINDIR,SINDIR
+       mov     DINDIR,SINDIR   ret
+       
+bcopy_3_dfdat:
+       mov     DINDIR,DFDAT
+       mov     DINDIR,DFDAT
+       mov     DINDIR,DFDAT    ret
+
+bcopy_4_dfdat:
+       mov     DINDIR,DFDAT
+       mov     DINDIR,DFDAT
+       mov     DINDIR,DFDAT
+       mov     DINDIR,DFDAT    ret
 
 #  Locking the driver out, build a one-byte message passed in SINDEX
 #  if there is no active message already.  SINDEX is returned intact.
 #
 mk_mesg:
-       mvi     SEQCTL,0x40                     # PAUSEDIS
-       test    MSG_FLAGS,0x80  jnz mk_mesg1    # active message?
+       mvi     SEQCTL,0x50                     # PAUSEDIS|FASTMODE
+       test    FLAGS,ACTIVE_MSG jnz mk_mesg1   # active message?
 
-       mvi     MSG_FLAGS,0x80                  # if not, there is now
+       or      FLAGS,ACTIVE_MSG                # if not, there is now
        mvi     MSG_LEN,1                       # length = 1
        mov     MSG_START+0,SINDEX              # 1-byte message
 
 mk_mesg1:
-       clr     SEQCTL                          # !PAUSEDIS
-       ret
-
-#  Input byte in Automatic PIO mode.  The address to store the byte
-#  in should be in SINDEX.  DINDEX will be used by this routine.
-#
-inb:
-       test    SSTAT0,0x2      jz inb          # SPIORDY
-       mov     DINDEX,SINDEX
-       call    one_stcnt                       # xfer one byte
-       mov     DINDIR,SCSIDATL
-inb1:
-       test    SSTAT0,0x4      jz inb1         # SDONE - wait to "finish"
-       ret
+       mvi     SEQCTL,0x10     ret             # !PAUSEDIS|FASTMODE
 
 #  Carefully read data in Automatic PIO mode.  I first tried this using
 #  Manual PIO mode, but it gave me continual underrun errors, probably
@@ -672,13 +947,15 @@ inb1:
 #  use the same calling convention as inb.
 #
 inb_first:
+       clr     STCNT+2
+       clr     STCNT+1
        mov     DINDEX,SINDEX
        mov     DINDIR,SCSIBUSL ret             # read byte directly from bus
 
 inb_next:
        mov     DINDEX,SINDEX                   # save SINDEX
 
-       call    one_stcnt                       # xfer one byte
+        mvi     STCNT+0,1                      # xfer one byte
        mov     NONE,SCSIDATL                   # dummy read from latch to ACK
 inb_next1:
        test    SSTAT0,0x4      jz inb_next1    # SDONE
@@ -687,37 +964,12 @@ inb_next2:
        mov     DINDIR,SCSIBUSL ret             # read byte directly from bus
 
 inb_last:
-       call    one_stcnt                       # ACK with dummy read
+       mvi     STCNT+0,1                       # ACK with dummy read
        mov     NONE,SCSIDATL
 inb_last1:
        test    SSTAT0,0x4      jz inb_last1    # wait for completion
        ret
 
-#  Output byte in Automatic PIO mode.  The byte to output should be
-#  in SINDEX.  If DROPATN's high bit is set, then ATN will be dropped
-#  before the byte is output.
-#
-outb:
-       test    SSTAT0,0x2      jz outb         # SPIORDY
-       call    one_stcnt                       # xfer one byte
-
-       test    DROPATN,0x80    jz outb1
-       mvi     CLRSINT1,0x40                   # CLRATNO
-       clr     DROPATN
-outb1:
-       mov     SCSIDATL,SINDEX
-outb2:
-       test    SSTAT0,0x4      jz outb2        # SDONE
-       ret
-
-#  Write the value "1" into the STCNT registers, for Automatic PIO
-#  transfers.
-#
-one_stcnt:
-       clr     STCNT+2
-       clr     STCNT+1
-       mvi     STCNT+0,1       ret
-
 #  DMA data transfer.  HADDR and HCNT must be loaded first, and
 #  SINDEX should contain the value to load DFCNTRL with - 0x3d for
 #  host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
@@ -752,47 +1004,40 @@ dma5:
 dma6:
        test    DFCNTRL,0x38    jnz dma6        # SCSIENACK|SDMAENACK|HDMAENACK
 
-       mvi     A,3
        mvi     DINDEX,SCBARRAY+15
-       mvi     STCNT           call bcopy
+       mvi     STCNT           call bcopy_3
 
        ret
 
+dma_finish:
+       test    DFSTATUS,0x8    jz dma_finish   # HDONE
+
+       clr     DFCNTRL                         # disable DMA
+dma_finish2:
+       test    DFCNTRL,0x8     jnz dma_finish2 # HDMAENACK
+       ret
+
 #  Common SCSI initialization for selection and reselection.  Expects
 #  the target SCSI ID to be in the upper four bits of SINDEX, and A's
 #  contents are stomped on return.
 #
-initialize:
-       clr     SBLKCTL                         # channel A, !wide
-       and     SCSIID,0xf0,SINDEX              # target ID
-       and     A,0x7,SCSICONF                  # SCSI_ID_A[210]
-       or      SCSIID,A
-
-#  Esundry initialization.
-#
-       clr     DROPATN
-       clr     SIGSTATE
+initialize_scsiid:
+       and     SINDEX,0xf0             # Get target ID
+       and     A,0x0f,SCSIID
+       or      SINDEX,A
+       mov     SCSIID,SINDEX ret
 
-#  Turn on Automatic PIO mode now, before we expect to see an REQ
+initialize_for_target:
+#  Turn on Automatic PIO mode now, before we expect to see a REQ
 #  from the target.  It shouldn't hurt anything to leave it on.  Set
 #  CLRCHN here before the target has entered a data transfer mode -
 #  with synchronous SCSI, if you do it later, you blow away some
 #  data in the SCSI FIFO that the target has already sent to you.
 #
-#  DFON is a 7870 bit enabling digital filtering of REQ and ACK signals.
-#
+       clr     SIGSTATE 
+
        mvi     SXFRCTL0,0x8a                   # DFON|SPIOEN|CLRCHN
 
-#  Set SCSI bus parity checking and the selection timeout value,
-#  and enable the hardware selection timer.  Set the SELTO interrupt
-#  to signal the driver.
-#
-#  STPWEN is 7870-specific, enabling an external termination power source.
-#
-       and     A,0x38,SCSICONF                 # PARITY_ENB_A|SEL_TIM_A[10]
-       or      SXFRCTL1,0x5,A                  # ENSTIMER|STPWEN
-       mvi     SIMODE1,0x84                    # ENSELTIMO|ENSCSIPERR
-       
 #  Initialize scatter-gather pointers by setting up the working copy
 #  in scratch RAM.
 #
@@ -800,66 +1045,60 @@ initialize:
 
 #  Initialize SCSIRATE with the appropriate value for this target.
 #
-       call    ndx_sdtr
-       mov     SCSIRATE,SINDIR
-       ret
+       call    ndx_dtr
+       mov     SCSIRATE,SINDIR ret
 
 #  Assert that if we've been reselected, then we've seen an IDENTIFY
 #  message.
 #
 assert:
-       test    RESELECT,0x80   jz assert1      # reselected?
-       test    RESELECT,0x40   jnz assert1     # seen IDENTIFY?
-
-       mvi     INTSTAT,SIGNAL_2                # no - cause a kernel panic
+       test    FLAGS,RESELECTED        jz return       # reselected?
+       test    FLAGS,IDENTIFY_SEEN     jnz return      # seen IDENTIFY?
 
-assert1:
-       ret
+       mvi     INTSTAT,NO_IDENT        ret     # no - cause a kernel panic
 
 #  Find out if disconnection is ok from the information the BIOS has left
-#  us.  The target ID should be in the upper four bits of SINDEX; A will
+#  us.  The tcl from SCBARRAY+1 should be in SINDEX; A will
 #  contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok)
 #  on exit.
 #
-#  This is the only place the target ID is limited to three bits, so we
-#  can use the FUNCTION1 register.
+#  To allow for wide or twin busses, we check the upper bit of the target ID
+#  and the channel ID and look at the appropriate disconnect register. 
 #
 disconnect:
        and     FUNCTION1,0x70,SINDEX           # strip off extra just in case
        mov     A,FUNCTION1
-       test    DISC_DSB_A,A    jz disconnect1  # bit nonzero if DISabled
+       test    SINDEX, 0x88    jz disconnect_a
 
+       test    DISC_DSB_B,A    jz disconnect1  # bit nonzero if DISabled
        clr     A               ret
+
+disconnect_a:
+       test    DISC_DSB_A,A    jz disconnect1  # bit nonzero if DISabled
+       clr     A               ret
+
 disconnect1:
        mvi     A,0x40          ret
 
-#  Locate the SCB matching the target ID in SELID and the lun in the lower
-#  three bits of SINDEX, and switch the SCB to it.  Have the kernel print
-#  a warning message if it can't be found, and generate an ABORT message
-#  to the target.
+#  Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch 
+#  the SCB to it.  Have the kernel print a warning message if it can't be 
+#  found, and generate an ABORT message to the target.  SINDEX should be
+#  cleared on call.
 #
 findSCB:
-       and     A,0x7,SINDEX                    # lun in lower three bits
-       or      A,A,SELID                       # can I do this?
-       and     A,0xf7                          # only channel A implemented
-       mov     DINDEX,A                        # save in DINDEX for later
-
-       clr     SINDEX
-
-findSCB1:
-       mov     A,DINDEX                        # reload A after 1st iteration
+       mov     A,SAVED_TCL
        mov     SCBPTR,SINDEX                   # switch to new SCB
-       cmp     SCBARRAY+1,A    jne findSCB2    # target ID/channel/lun match?
-       test    SCBARRAY+0,0x4  jz findSCB2     # should be disconnected
-
+       cmp     SCBARRAY+1,A    jne findSCB1    # target ID/channel/lun match?
+       test    SCBARRAY+0,0x4  jz findSCB1     # should be disconnected
+       test    SCBARRAY+0,TAG_ENB jnz get_tag
        ret
 
-findSCB2:
+findSCB1:
        inc     SINDEX
        mov     A,SCBCOUNT
-       cmp     SINDEX,A        jne findSCB1
+       cmp     SINDEX,A        jne findSCB
 
-       mvi     INTSTAT,SIGNAL_3                # not found - signal kernel
+       mvi     INTSTAT,NO_MATCH                # not found - signal kernel
        mvi     0x6             call mk_mesg    # ABORT message
 
        or      SINDEX,0x10,SIGSTATE            # assert ATNO
@@ -871,32 +1110,24 @@ findSCB2:
 sg_scb2ram:
        mov     SG_COUNT,SCBARRAY+2
 
-       mvi     A,4
        mvi     DINDEX,SG_NEXT
-       mvi     SCBARRAY+3      call bcopy
+       mvi     SCBARRAY+3      call bcopy_4
 
        mvi     SG_NOLOAD,0x80
-       test    SCBARRAY+0,0x10 jnz sg_scb2ram1 # don't reload s/g?
-       clr     SG_NOLOAD
-
-sg_scb2ram1:
-       ret
+       test    SCBARRAY+0,0x10 jnz return      # don't reload s/g?
+       clr     SG_NOLOAD        ret
 
 #  Copying RAM values back to SCB, for Save Data Pointers message.
 #
 sg_ram2scb:
        mov     SCBARRAY+2,SG_COUNT
 
-       mvi     A,4
        mvi     DINDEX,SCBARRAY+3
-       mvi     SG_NEXT         call bcopy
+       mvi     SG_NEXT         call bcopy_4
 
        and     SCBARRAY+0,0xef,SCBARRAY+0
-       test    SG_NOLOAD,0x80  jz sg_ram2scb1  # reload s/g?
-       or      SCBARRAY+0,0x10
-
-sg_ram2scb1:
-       ret
+       test    SG_NOLOAD,0x80  jz return       # reload s/g?
+       or      SCBARRAY+0,SG_LOAD       ret
 
 #  Load a struct scatter if needed and set up the data address and
 #  length.  If the working value of the SG count is nonzero, then
@@ -905,28 +1136,23 @@ sg_ram2scb1:
 #  This, like the above DMA, assumes a little-endian host data storage.
 #
 sg_load:
-       test    SG_COUNT,0xff   jz sg_load3     # SG being used?
-       test    SG_NOLOAD,0x80  jnz sg_load3    # don't reload s/g?
+       test    SG_COUNT,0xff   jz return       # SG being used?
+       test    SG_NOLOAD,0x80  jnz return      # don't reload s/g?
 
        clr     HCNT+2
        clr     HCNT+1
        mvi     HCNT+0,SG_SIZEOF
 
-       mvi     A,4
        mvi     DINDEX,HADDR
-       mvi     SG_NEXT         call bcopy
+       mvi     SG_NEXT         call bcopy_4
 
        mvi     DFCNTRL,0xd                     # HDMAEN|DIRECTION|FIFORESET
 
 #  Wait for DMA from host memory to data FIFO to complete, then disable
 #  DMA and wait for it to acknowledge that it's off.
 #
-sg_load1:
-       test    DFSTATUS,0x8    jz sg_load1     # HDONE
 
-       clr     DFCNTRL                         # disable DMA
-sg_load2:
-       test    DFCNTRL,0x8     jnz sg_load2    # HDMAENACK
+       call    dma_finish
 
 #  Copy data from FIFO into SCB data pointer and data count.  This assumes
 #  that the struct scatterlist has this structure (this and sizeof(struct
@@ -938,21 +1164,26 @@ sg_load2:
 #              unsigned short length;  /* two bytes, little-endian order */
 #      }
 #
-       mov     SCBARRAY+19,DFDAT               # new data address
-       mov     SCBARRAY+20,DFDAT
-       mov     SCBARRAY+21,DFDAT
-       mov     SCBARRAY+22,DFDAT
 
-       mov     NONE,DFDAT                      # throw away four bytes
+# Not in FreeBSD.  the scatter list entry is only 8 bytes.
+# 
+# struct ahc_dma_seg {
+#       physaddr addr;                  /* four bytes, little-endian order */
+#       long    len;                    /* four bytes, little endian order */   
+# };
+#
+
+       mvi     DINDEX, SCBARRAY+19
+       call    bcopy_4_dfdat
+
+# For Linux, we must throw away four bytes since there is a 32bit gap
+# in the middle of a struct scatterlist
+       mov     NONE,DFDAT
        mov     NONE,DFDAT
        mov     NONE,DFDAT
        mov     NONE,DFDAT
 
-       mov     SCBARRAY+23,DFDAT
-       mov     SCBARRAY+24,DFDAT
-       clr     SCBARRAY+25
-
-sg_load3:
+       call    bcopy_3_dfdat           #Only support 24 bit length.
        ret
 
 #  Advance the scatter-gather pointers only IF NEEDED.  If SG is enabled,
@@ -963,7 +1194,7 @@ sg_load3:
 #  next time.
 #
 sg_advance:
-       test    SG_COUNT,0xff   jz sg_advance2  # s/g enabled?
+       test    SG_COUNT,0xff   jz return       # s/g enabled?
 
        test    STCNT+0,0xff    jnz sg_advance1 # SCSI transfer count nonzero?
        test    STCNT+1,0xff    jnz sg_advance1
@@ -976,47 +1207,69 @@ sg_advance:
        add     SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
        adc     SG_NEXT+1,A,SG_NEXT+1
        adc     SG_NEXT+2,A,SG_NEXT+2
-       adc     SG_NEXT+3,A,SG_NEXT+3
-
-       ret
+       adc     SG_NEXT+3,A,SG_NEXT+3   ret
 
 sg_advance1:
-       mvi     SG_NOLOAD,0x80                  # don't reload s/g next time
-sg_advance2:
-       ret
+       mvi     SG_NOLOAD,0x80  ret             # don't reload s/g next time
 
 #  Add the array base SYNCNEG to the target offset (the target address
 #  is in SCSIID), and return the result in SINDEX.  The accumulator
 #  contains the 3->8 decoding of the target ID on return.
 #
-ndx_sdtr:
+ndx_dtr:
        shr     A,SCSIID,4
-       and     A,0x7
+       test    SBLKCTL,0x08    jz ndx_dtr_2
+       or      A,0x08          # Channel B entries add 8
+ndx_dtr_2:
        add     SINDEX,SYNCNEG,A
 
        and     FUNCTION1,0x70,SCSIID           # 3-bit target address decode
        mov     A,FUNCTION1     ret
 
-#  If we need to negotiate transfer parameters, build the SDTR message
+#  If we need to negotiate transfer parameters, build the WDTR or SDTR message
 #  starting at the address passed in SINDEX.  DINDEX is modified on return.
+#  The SCSI-II spec requires that Wide negotiation occur first and you can
+#  only negotiat one or the other at a time otherwise in the event of a message
+#  reject, you wouldn't be able to tell which message was the culpret.
 #
-mk_sdtr:
-       mov     DINDEX,SINDEX                   # save SINDEX
+mk_dtr:
+       test    SCBARRAY+0,0xc0 jz return       # NEEDWDTR|NEEDSDTR
+       test    SCBARRAY+0,NEEDWDTR jnz  mk_wdtr_16bit
+       or      FLAGS, MAX_OFFSET       # Force an offset of 15 or 8 if WIDE
 
-       call    ndx_sdtr
-       test    NEEDSDTR,A      jnz mk_sdtr1    # do we need negotiation?
-       ret
-
-mk_sdtr1:
+mk_sdtr:
        mvi     DINDIR,1                        # extended message
        mvi     DINDIR,3                        # extended message length = 3
        mvi     DINDIR,1                        # SDTR code
-       mvi     DINDIR,25                       # REQ/ACK transfer period
-       mvi     DINDIR,15                       # REQ/ACK offset
-
-       add     MSG_LEN,-MSG_START+0,DINDEX     # update message length
-       ret
+       call    sdtr_to_rate
+       mov     DINDIR,RETURN_1                 # REQ/ACK transfer period
+       test    FLAGS, MAX_OFFSET jnz mk_sdtr_max_offset
+       and     DINDIR,0x0f,SINDIR              # Sync Offset
+
+mk_sdtr_done:
+       add     MSG_LEN,-MSG_START+0,DINDEX ret # update message length
+
+mk_sdtr_max_offset:
+# We're initiating sync negotiation, so request the max offset we can (15 or 8)
+       xor     FLAGS, MAX_OFFSET
+       test    SCSIRATE, 0x80  jnz wmax_offset # Talking to a WIDE device?
+       mvi     DINDIR, MAX_OFFSET_8BIT
+       jmp     mk_sdtr_done
+
+wmax_offset:
+       mvi     DINDIR, MAX_OFFSET_WIDE
+       jmp     mk_sdtr_done
+
+mk_wdtr_16bit:
+       mvi     ARG_1,BUS_16_BIT
+mk_wdtr:
+       mvi     DINDIR,1                        # extended message
+       mvi     DINDIR,2                        # extended message length = 2
+       mvi     DINDIR,3                        # WDTR code
+       mov     DINDIR,ARG_1                    # bus width
 
+       add     MSG_LEN,-MSG_START+0,DINDEX ret # update message length
+       
 #  Set SCSI bus control signal state.  This also saves the last-written
 #  value into a location where the higher-level driver can read it - if
 #  it has to send an ABORT or RESET message, then it needs to know this
@@ -1027,3 +1280,21 @@ mk_sdtr1:
 scsisig:
        mov     SIGSTATE,SINDEX
        mov     SCSISIGO,SINDEX ret
+
+sdtr_to_rate:
+       call    ndx_dtr                         # index scratch space for target
+       shr     A,SINDIR,0x4
+       dec     SINDEX                          #Preserve SINDEX
+       and     A,0x7
+       clr     RETURN_1
+sdtr_to_rate_loop:
+       test    A,0x0f  jz sdtr_to_rate_done
+       add     RETURN_1,0x18
+       dec     A       
+       jmp     sdtr_to_rate_loop
+sdtr_to_rate_done:
+       shr     RETURN_1,0x2
+       add     RETURN_1,0x18   ret
+
+return:
+       ret
diff --git a/drivers/scsi/aic7xxx_asm.c b/drivers/scsi/aic7xxx_asm.c
new file mode 100644 (file)
index 0000000..665e6b5
--- /dev/null
@@ -0,0 +1,643 @@
+/*+M*************************************************************************
+ * Adaptec AIC7770/AIC7870 sequencer code assembler.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *   All rights reserved.
+ *
+ * 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.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of Calgary
+ *      Department of Computer Science and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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.
+ *
+ * Comments are started by `#' and continue to the end of the line; lines
+ * may be of the form:
+ *      <label>*
+ *      <label>*  <undef-sym> = <value>
+ *      <label>*  <opcode> <operand>*
+ *
+ * A <label> is an <undef-sym> ending in a colon.  Spaces, tabs, and commas
+ * are token separators.
+ *
+ *-M*************************************************************************/
+static char id[] = "$Id: aic7xxx_asm.c,v 1.8 1995/05/25 06:25:36 root Exp $";
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define MEMORY         448
+#define MAXLINE                1024
+#define MAXTOKEN       32
+#define ADOTOUT                "a.out"
+#define NOVALUE                -1
+
+/*
+ * AIC-7770/AIC-7870 register definitions
+ */
+#define R_SINDEX       0x65
+#define R_ALLONES      0x69
+#define R_ALLZEROS     0x6a
+#define R_NONE         0x6a
+
+int debug;
+int lineno, LC;
+char *filename;
+FILE *ifp, *ofp;
+unsigned char M[MEMORY][4];
+
+void 
+error(char *s)
+{
+       fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
+       exit(EXIT_FAILURE);
+}
+
+void *
+Malloc(size_t size)
+{
+       void *p = malloc(size);
+       if (!p)
+               error("out of memory");
+       return(p);
+}
+
+void *
+Realloc(void *ptr, size_t size)
+{
+       void *p = realloc(ptr, size);
+       if (!p)
+               error("out of memory");
+       return(p);
+}
+
+char *
+Strdup(char *s)
+{
+       char *p = (char *)Malloc(strlen(s) + 1);
+       strcpy(p, s);
+       return(p);
+}
+
+typedef struct sym_t {
+       struct sym_t    *next;          /* MUST BE FIRST */
+       char            *name;
+       int             value;
+       int             npatch; 
+       int             *patch;
+} sym_t;
+
+sym_t *head;
+
+void
+define(char *name, int value)
+{
+       sym_t *p, *q;
+
+       for (p = head, q = (sym_t *)&head; p; p = p->next) {
+               if (!strcmp(p->name, name))
+                       error("redefined symbol");
+               q = p;
+       }
+
+       p = q->next = (sym_t *)Malloc(sizeof(sym_t));
+       p->next = NULL;
+       p->name = Strdup(name);
+       p->value = value;
+       p->npatch = 0;
+       p->patch = NULL;
+
+       if (debug) {
+               fprintf(stderr, "\"%s\" ", p->name);
+               if (p->value != NOVALUE)
+                       fprintf(stderr, "defined as 0x%x\n", p->value);
+               else
+                       fprintf(stderr, "undefined\n");
+       }
+}
+
+sym_t *
+lookup(char *name)
+{
+       sym_t *p;
+
+       for (p = head; p; p = p->next)
+               if (!strcmp(p->name, name))
+                       return(p);
+       return(NULL);
+}
+
+void 
+patch(sym_t *p, int location)
+{
+       p->npatch += 1;
+       p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
+
+       p->patch[p->npatch - 1] = location;
+}
+
+void backpatch(void)
+{
+       int i;
+       sym_t *p;
+
+       for (p = head; p; p = p->next) {
+
+               if (p->value == NOVALUE) {
+                       fprintf(stderr,
+                               "%s: undefined symbol \"%s\"\n",
+                               filename, p->name);
+                       exit(EXIT_FAILURE);
+               }
+
+               if (p->npatch) {
+                       if (debug)
+                               fprintf(stderr,
+                                       "\"%s\" (0x%x) patched at",
+                                       p->name, p->value);
+
+                       for (i = 0; i < p->npatch; i++) {
+                               M[p->patch[i]][0] &= ~1;
+                               M[p->patch[i]][0] |= ((p->value >> 8) & 1);
+                               M[p->patch[i]][1] = p->value & 0xff;
+
+                               if (debug)
+                                       fprintf(stderr, " 0x%x", p->patch[i]);
+                       }
+
+                       if (debug)
+                               fputc('\n', stderr);
+               }
+       }
+}
+
+/*
+ *  Output words in byte-reversed order (least significant first)
+ *  since the sequencer RAM is loaded that way.
+ */
+void
+output(FILE *fp)
+{
+       int i;
+
+       for (i = 0; i < LC; i++)
+               fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+                       M[i][3],
+                       M[i][2],
+                       M[i][1],
+                       M[i][0]);
+       printf("%d out of %d instructions used.\n", LC, MEMORY);
+}
+
+char **
+getl(int *n)
+{
+       int i;
+       char *p, *quote;
+       static char buf[MAXLINE];
+       static char *a[MAXTOKEN];
+
+       i = 0;
+
+       while (fgets(buf, sizeof(buf), ifp)) {
+
+               lineno += 1;
+
+               if (buf[strlen(buf)-1] != '\n')
+                       error("line too long");
+
+               p = strchr(buf, '#');
+               if (p)
+                       *p = '\0';
+               p = buf;
+rescan:
+               quote = strchr(p, '\"');
+               if (quote)
+                       *quote = '\0';
+               for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
+                       if (i < MAXTOKEN-1)
+                               a[i++] = p;
+                       else
+                               error("too many tokens");
+               if (quote) {
+                       quote++; 
+                       p = strchr(quote, '\"');
+                       if (!p)
+                               error("unterminated string constant");
+                       else if (i < MAXTOKEN-1) {
+                               a[i++] = quote;
+                               *p = '\0';
+                               p++;
+                       }
+                       else
+                               error("too many tokens");
+                       goto rescan;
+               }               
+               if (i) {
+                       *n = i;
+                       return(a);
+               }
+       }
+       return(NULL);
+}
+
+#define A      0x8000          /* `A'ccumulator ok */
+#define I      0x4000          /* use as immediate value */
+#define SL     0x2000          /* shift left */
+#define SR     0x1000          /* shift right */
+#define RL     0x0800          /* rotate left */
+#define RR     0x0400          /* rotate right */
+#define LO     0x8000          /* lookup: ori-{jmp,jc,jnc,call} */
+#define LA     0x4000          /* lookup: and-{jz,jnz} */
+#define LX     0x2000          /* lookup: xor-{je,jne} */
+#define NA     -1              /* not applicable */
+
+struct {
+       char *name;
+       int n;                  /* number of operands, including opcode */
+       unsigned int op;        /* immediate or L?|pos_from_0 */
+       unsigned int dest;      /* NA, pos_from_0, or I|immediate */
+       unsigned int src;       /* NA, pos_from_0, or I|immediate */
+       unsigned int imm;       /* pos_from_0, A|pos_from_0, or I|immediate */
+       unsigned int addr;      /* NA or pos_from_0 */
+       int fmt;                /* instruction format - 1, 2, or 3 */
+} instr[] = {
+/*
+ *               N  OP    DEST         SRC             IMM     ADDR    FMT
+ */
+       { "mov",  3, 1,    1,           2,              I|0xff, NA,     1 },
+       { "mov",  4, LO|2, NA,          1,              I|0,    3,      3 },
+       { "mvi",  3, 0,    1,           I|R_ALLZEROS,   A|2,    NA,     1 },
+       { "mvi",  4, LO|2, NA,          I|R_ALLZEROS,   1,      3,      3 },
+       { "not",  2, 2,    1,           1,              I|0xff, NA,     1 },
+       { "and",  3, 1,    1,           1,              A|2,    NA,     1 },
+       { "and",  4, 1,    1,           3,              A|2,    NA,     1 },
+       { "or",   3, 0,    1,           1,              A|2,    NA,     1 },
+       { "or",   4, 0,    1,           3,              A|2,    NA,     1 },
+       { "or",   5, LO|3, NA,          1,              2,      4,      3 },
+       { "xor",  3, 2,    1,           1,              A|2,    NA,     1 },
+       { "xor",  4, 2,    1,           3,              A|2,    NA,     1 },
+       { "nop",  1, 1,    I|R_NONE,    I|R_ALLZEROS,   I|0xff, NA,     1 },
+       { "inc",  2, 3,    1,           1,              I|1,    NA,     1 },
+       { "inc",  3, 3,    1,           2,              I|1,    NA,     1 },
+       { "dec",  2, 3,    1,           1,              I|0xff, NA,     1 },
+       { "dec",  3, 3,    1,           2,              I|0xff, NA,     1 },
+       { "jmp",  2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
+       { "jc",   2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
+       { "jnc",  2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
+       { "call", 2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
+       { "test", 5, LA|3,   NA,        1,              A|2,    4,      3 },
+       { "cmp",  5, LX|3,   NA,        1,              A|2,    4,      3 },
+       { "ret",  1, 1,  I|R_NONE,      I|R_ALLZEROS,   I|0xff, NA,     1 },
+       { "ret",  1, 1,  I|R_NONE,      I|R_ALLZEROS,   I|0xff, NA,     1 },
+       { "clc",  1, 3,  I|R_NONE,      I|R_ALLZEROS,   I|1,    NA,     1 },
+       { "clc",  4, 3,  2,             I|R_ALLZEROS,   A|3,    NA,     1 },
+       { "stc",  2, 3,  1,             I|R_ALLONES,    I|1,    NA,     1 },
+       { "add",  3, 3,  1,             1,              A|2,    NA,     1 },
+       { "add",  4, 3,  1,             3,              A|2,    NA,     1 },
+       { "adc",  3, 4,  1,             1,              A|2,    NA,     1 },
+       { "adc",  4, 4,  1,             3,              A|2,    NA,     1 },
+       { "shl",  3, 5,  1,             1,              SL|2,   NA,     2 },
+       { "shl",  4, 5,  1,             2,              SL|3,   NA,     2 },
+       { "shr",  3, 5,  1,             1,              SR|2,   NA,     2 },
+       { "shr",  4, 5,  1,             2,              SR|3,   NA,     2 },
+       { "rol",  3, 5,  1,             1,              RL|2,   NA,     2 },
+       { "rol",  4, 5,  1,             2,              RL|3,   NA,     2 },
+       { "ror",  3, 5,  1,             1,              RR|2,   NA,     2 },
+       { "ror",  4, 5,  1,             2,              RR|3,   NA,     2 },
+       /*
+        *  Extensions (note also that mvi allows A)
+        */
+       { "clr",  2, 1,  1,     I|R_ALLZEROS,           I|0xff, NA,     1 },
+       { 0,      0, 0,  0,     0,                      0,      0,      0 }
+};
+
+int 
+eval_operand(char **a, int spec)
+{
+       int i;
+       unsigned int want = spec & (LO|LA|LX);
+
+       static struct {
+               unsigned int what;
+               char *name;
+               int value;
+       } jmptab[] = {
+               { LO,   "jmp",          8  },
+               { LO,   "jc",           9  },
+               { LO,   "jnc",          10 },
+               { LO,   "call",         11 },
+               { LA,   "jz",           15 },
+               { LA,   "jnz",          13 },
+               { LX,   "je",           14 },
+               { LX,   "jne",          12 },
+       };
+
+       spec &= ~(LO|LA|LX);
+
+       for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
+               if (jmptab[i].what == want &&
+                   !strcmp(jmptab[i].name, a[spec]))
+               {
+                       return(jmptab[i].value);
+               }
+
+       if (want)
+               error("invalid jump");
+
+       return(spec);           /* "case 0" - no flags set */
+}
+
+int
+eval_sdi(char **a, int spec)
+{
+       sym_t *p;
+       unsigned val;
+
+       if (spec == NA)
+               return(NA);
+
+       switch (spec & (A|I|SL|SR|RL|RR)) {
+           case SL:
+           case SR:
+           case RL:
+           case RR:
+               if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
+                       val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
+               else {
+                       p = lookup(a[spec &~ (SL|SR|RL|RR)]);
+                       if (!p)
+                               error("undefined symbol used");
+                       val = p->value;
+               }
+
+               switch (spec & (SL|SR|RL|RR)) {         /* blech */
+                   case SL:
+                       if (val > 7)
+                               return(0xf0);
+                       return(((val % 8) << 4) |
+                              (val % 8));
+                   case SR:
+                       if (val > 7)
+                               return(0xf0);
+                       return(((val % 8) << 4) |
+                              (1 << 3) |
+                              ((8 - (val % 8)) % 8));
+                   case RL:
+                       return(val % 8);
+                   case RR:
+                       return((8 - (val % 8)) % 8);
+               }
+           case I:
+               return(spec &~ I);
+           case A:
+               /*
+                *  An immediate field of zero selects
+                *  the accumulator.  Vigorously object
+                *  if zero is given otherwise - it's
+                *  most likely an error.
+                */
+               spec &= ~A;
+               if (!strcmp("A", a[spec]))
+                       return(0);
+               if (isdigit(*a[spec]) &&
+                   strtol(a[spec], NULL, 0) == 0)
+               {
+                       error("immediate value of zero selects accumulator");
+               }
+               /* falls through */
+           case 0:
+               if (isdigit(*a[spec]))
+                       return(strtol(a[spec], NULL, 0));
+               p = lookup(a[spec]);
+               if (p)
+                       return(p->value);
+               error("undefined symbol used");
+       }
+
+       return(NA);             /* shut the compiler up */
+}
+
+int
+eval_addr(char **a, int spec)
+{
+       sym_t *p;
+
+       if (spec == NA)
+               return(NA);
+       if (isdigit(*a[spec]))
+               return(strtol(a[spec], NULL, 0));
+
+       p = lookup(a[spec]);
+
+       if (p) {
+               if (p->value != NOVALUE)
+                       return(p->value);
+               patch(p, LC);
+       } else {
+               define(a[spec], NOVALUE);
+               p = lookup(a[spec]);
+               patch(p, LC);
+       }
+
+       return(NA);             /* will be patched in later */
+}
+
+int
+crack(char **a, int n)
+{
+       int i;
+       int I_imm, I_addr;
+       int I_op, I_dest, I_src, I_ret;
+
+       /*
+        *  Check for "ret" at the end of the line; remove
+        *  it unless it's "ret" alone - we still want to
+        *  look it up in the table.
+        */
+       I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
+       if (I_ret && n > 1)
+               n -= 1;
+
+       for (i = 0; instr[i].name; i++) {
+               /*
+                *  Look for match in table given constraints,
+                *  currently just the name and the number of
+                *  operands.
+                */
+               if (!strcmp(instr[i].name, *a) && instr[i].n == n)
+                       break;
+       }
+       if (!instr[i].name)
+               error("unknown opcode or wrong number of operands");
+
+       I_op    = eval_operand(a, instr[i].op);
+       I_src   = eval_sdi(a, instr[i].src);
+       I_imm   = eval_sdi(a, instr[i].imm);
+       I_dest  = eval_sdi(a, instr[i].dest);
+       I_addr  = eval_addr(a, instr[i].addr);
+
+       if( LC >= MEMORY )
+               error("Memory exhausted!\n");
+
+       switch (instr[i].fmt) {
+           case 1:
+           case 2:
+               M[LC][0] = (I_op << 1) | I_ret;
+               M[LC][1] = I_dest;
+               M[LC][2] = I_src;
+               M[LC][3] = I_imm;
+               break;
+           case 3:
+               if (I_ret)
+                       error("illegal use of \"ret\"");
+               M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
+               M[LC][1] = I_addr & 0xff;
+               M[LC][2] = I_src;
+               M[LC][3] = I_imm;
+               break;
+       }
+
+       return (1);             /* no two-byte instructions yet */
+}
+
+#undef SL
+#undef SR
+#undef RL
+#undef RR
+#undef LX
+#undef LA
+#undef LO
+#undef I
+#undef A
+
+void
+assemble(void)
+{
+       int n;
+       char **a;
+       sym_t *p;
+
+       while ((a = getl(&n))) {
+
+               while (a[0][strlen(*a)-1] == ':') {
+                       a[0][strlen(*a)-1] = '\0';
+                       p = lookup(*a);
+                       if (p)
+                               p->value = LC;
+                       else
+                               define(*a, LC);
+                       a += 1;
+                       n -= 1;
+               }
+
+               if (!n)                 /* line was all labels */
+                       continue;
+
+               if (n == 3 && !strcmp("VERSION", *a))
+                       fprintf(ofp, "#define %s \"%s\"\n", a[1], a[2]);
+               else {
+                       if (n == 3 && !strcmp("=", a[1]))
+                               define(*a, strtol(a[2], NULL, 0));
+                       else
+                               LC += crack(a, n);
+               }
+       }
+
+       backpatch();
+       output(ofp);
+
+       if (debug)
+               output(stderr);
+}
+
+int
+main(int argc, char **argv)
+{
+       int c;
+
+       while ((c = getopt(argc, argv, "dho:vD")) != EOF) {
+               switch (c) {
+                   case 'd':
+                       debug = !0;
+                       break;
+                   case 'D':
+                   {
+                       char *p;
+                       if ((p = strchr(optarg, '=')) != NULL) {
+                               *p = '\0';
+                               define(optarg, strtol(p + 1, NULL, 0));
+                       }
+                       else
+                               define(optarg, 1);
+                       break;
+                   }
+                   case 'o':
+                       ofp = fopen(optarg, "w");
+                       if (!ofp) {
+                               perror(optarg);
+                               exit(EXIT_FAILURE);
+                       }
+                       break;
+                   case 'h':
+                       printf("usage: %s [-d] [-Dname] [-ooutput] input\n", 
+                               *argv);
+                       exit(EXIT_SUCCESS);
+                       break;
+                   case 'v':
+                       printf("%s\n", id);
+                       exit(EXIT_SUCCESS);
+                       break;
+                   default:
+                       exit(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       if (argc - optind != 1) {
+               fprintf(stderr, "%s: must have one input file\n", *argv);
+               exit(EXIT_FAILURE);
+       }
+       filename = argv[optind];
+
+       ifp = fopen(filename, "r");
+       if (!ifp) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+
+       if (!ofp) {
+               ofp = fopen(ADOTOUT, "w");
+               if (!ofp) {
+                       perror(ADOTOUT);
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       assemble();
+       exit(EXIT_SUCCESS);
+}
index a5824b04be091350032207da10c72973a0d9766b..bdb1c380dff1408b27ffaf2063c566523e1e606a 100644 (file)
@@ -89,7 +89,7 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/config.h>
-
+#include <linux/proc_fs.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/dma.h>
index 4a1e4059c3498943c09745dfd45547a2e0055111..98671741fd21441e425070ae67627195c9ed0e7a 100644 (file)
@@ -12,7 +12,12 @@ const char *buslogic_info(struct Scsi_Host *);
 int buslogic_reset(Scsi_Cmnd *);
 int buslogic_biosparam(Disk *, int, int *);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 #define BUSLOGIC { NULL, NULL,                 \
+                  generic_proc_info,           \
+                  "buslogic",                  \
+                  PROC_SCSI_BUSLOGIC,          \
                   "BusLogic",                  \
                   buslogic_detect,             \
                   0,   /* no release func */   \
index 793cfc80523a4e429612f6ef264f1ea9b51348db..9edcd4423850ccb474707cd798d85b9a0052dd7a 100644 (file)
@@ -9,12 +9,12 @@
 #include "scsi.h"
 #include "hosts.h"
 
-#define CONST_COMMAND  0x01
-#define CONST_STATUS   0x02
-#define CONST_SENSE    0x04
-#define CONST_XSENSE   0x08
-#define CONST_CMND     0x10
-#define CONST_MSG      0x20
+#define CONST_COMMAND   0x01
+#define CONST_STATUS    0x02
+#define CONST_SENSE     0x04
+#define CONST_XSENSE    0x08
+#define CONST_CMND      0x10
+#define CONST_MSG       0x20
 
 static const char unknown[] = "UNKNOWN";
 
@@ -45,15 +45,15 @@ static const char *group_1_commands[] = {
 /* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", 
 /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", 
 /* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", 
-/* 38-3c */ unknown, "Compare","Copy Verify", "Write Buffer", "Read Buffer", 
-/* 3d-39 */ unknown, "Read Long",  unknown,
+/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", 
+/* 3d-3f */ "Update Block", "Read Long",  "Write Long",
 };
 
 
 static const char *group_2_commands[] = {
-/* 40-41 */ "Change Definition", unknown
-/* 42-48 */ unknown, unknown, unknown, unknown, unknown, unknown, unknown,
-/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown,
+/* 40-41 */ "Change Definition", "Write Same"
+/* 42-48 */ unknown, unknown, unknown, unknown, unknown, unknown, unknown, 
+/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, unknown,
 /* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
 /* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
 /* 5c-5f */ unknown, unknown, unknown,
@@ -64,46 +64,47 @@ static const char *group_2_commands[] = {
 #define group(opcode) (((opcode) >> 5) & 7)
 
 #define RESERVED_GROUP  0
-#define VENDOR_GROUP   1
-#define NOTEXT_GROUP   2
+#define VENDOR_GROUP    1
+#define NOTEXT_GROUP    2
 
 static const char **commands[] = {
-group_0_commands, group_1_commands, group_2_commands, 
-(const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, 
-(const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, 
-(const char **) VENDOR_GROUP};
+    group_0_commands, group_1_commands, group_2_commands, 
+    (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, 
+    (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, 
+    (const char **) VENDOR_GROUP
+};
 
 static const char reserved[] = "RESERVED";
 static const char vendor[] = "VENDOR SPECIFIC";
 
 static void print_opcode(int opcode) {
-  const char **table = commands[ group(opcode) ];
-  switch ((unsigned long) table) {
-  case RESERVED_GROUP:
-       printk("%s(0x%02x) ", reserved, opcode); 
-       break;
-  case NOTEXT_GROUP:
-       printk("%s(0x%02x) ", unknown, opcode); 
-       break;
-  case VENDOR_GROUP:
-       printk("%s(0x%02x) ", vendor, opcode); 
-       break;
-  default:
-       printk("%s ",table[opcode & 0x1f]);
-  }
+    const char **table = commands[ group(opcode) ];
+    switch ((unsigned long) table) {
+    case RESERVED_GROUP:
+       printk("%s(0x%02x) ", reserved, opcode); 
+       break;
+    case NOTEXT_GROUP:
+       printk("%s(0x%02x) ", unknown, opcode); 
+       break;
+    case VENDOR_GROUP:
+       printk("%s(0x%02x) ", vendor, opcode); 
+       break;
+    default:
+       printk("%s ",table[opcode & 0x1f]);
+    }
 }
 #else /* CONST & CONST_COMMAND */
 static void print_opcode(int opcode) {
-  printk("0x%02x ", opcode);
+    printk("0x%02x ", opcode);
 }
 #endif  
 
 void print_command (unsigned char *command) {
-  int i,s;
-  print_opcode(command[0]);
-  for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) 
-       printk("%02x ", command[i]);
-  printk("\n");
+    int i,s;
+    print_opcode(command[0]);
+    for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) 
+       printk("%02x ", command[i]);
+    printk("\n");
 }
 
 #if (CONSTANTS & CONST_STATUS)
@@ -116,11 +117,11 @@ static const char * statuses[] = {
 #endif
 
 void print_status (int status) {
-  status = (status >> 1) & 0xf;
+    status = (status >> 1) & 0xf;
 #if (CONSTANTS & CONST_STATUS)
-  printk("%s ",statuses[status]);
+    printk("%s ",statuses[status]);
 #else
-  printk("0x%0x ", status); 
+    printk("0x%0x ", status); 
 #endif 
 }
 
@@ -137,15 +138,15 @@ void print_status (int status) {
 #define C 0x200  /* COMMUNICATION DEVICE */
 
 struct error_info{
-  unsigned char code1, code2;
-  unsigned short int devices;
-  char * text;
+    unsigned char code1, code2;
+    unsigned short int devices;
+    char * text;
 };
 
 struct error_info2{
-  unsigned char code1, code2_min, code2_max;
-  unsigned short int devices;
-  char * text;
+    unsigned char code1, code2_min, code2_max;
+    unsigned short int devices;
+    char * text;
 };
 
 static struct error_info2 additional2[] =
@@ -353,54 +354,54 @@ static struct error_info additional[] =
 
 #if (CONSTANTS & CONST_SENSE)
 static char *snstext[] = {
-       "None","Recovered Error","Not Ready","Medium Error","Hardware Error",
-       "Illegal Request","Unit Attention","Data Protect","Blank Check",
-       "Key=9","Copy Aborted","Aborted Command","End-Of-Medium",
-       "Volume Overflow", "Miscompare", "Key=15"};
+    "None","Recovered Error","Not Ready","Medium Error","Hardware Error",
+    "Illegal Request","Unit Attention","Data Protect","Blank Check",
+    "Key=9","Copy Aborted","Aborted Command","End-Of-Medium",
+    "Volume Overflow", "Miscompare", "Key=15"};
 #endif
 
 
 /* Print sense information */
 void print_sense(char * devclass, Scsi_Cmnd * SCpnt)
 {
-       int i, s;
-       int sense_class, valid, code;
-       unsigned char * sense_buffer = SCpnt->sense_buffer;
-       char * error = NULL;
-       int dev = SCpnt->request.dev;
-
-       sense_class = (sense_buffer[0] >> 4) & 0x07;
-       code = sense_buffer[0] & 0xf;
-       valid = sense_buffer[0] & 0x80;
-
-       if (sense_class == 7) { 
-         s = sense_buffer[7] + 8;
-         if(s > sizeof(SCpnt->sense_buffer)) s = sizeof(SCpnt->sense_buffer);
-
-         if (!valid)
+    int i, s;
+    int sense_class, valid, code;
+    unsigned char * sense_buffer = SCpnt->sense_buffer;
+    char * error = NULL;
+    int dev = SCpnt->request.dev;
+    
+    sense_class = (sense_buffer[0] >> 4) & 0x07;
+    code = sense_buffer[0] & 0xf;
+    valid = sense_buffer[0] & 0x80;
+    
+    if (sense_class == 7) { 
+       s = sense_buffer[7] + 8;
+       if(s > sizeof(SCpnt->sense_buffer)) s = sizeof(SCpnt->sense_buffer);
+       
+       if (!valid)
            printk("extra data not valid ");
-         
-         if (sense_buffer[2] & 0x80) printk( "FMK ");
-         if (sense_buffer[2] & 0x40) printk( "EOM ");
-         if (sense_buffer[2] & 0x20) printk( "ILI ");
-
-         switch (code) {
-         case 0x0:
+       
+       if (sense_buffer[2] & 0x80) printk( "FMK ");
+       if (sense_buffer[2] & 0x40) printk( "EOM ");
+       if (sense_buffer[2] & 0x20) printk( "ILI ");
+       
+       switch (code) {
+       case 0x0:
            error = "Current";
            break;
-         case 0x1:
+       case 0x1:
            error = "Deferred";
            break;
-         default:
+       default:
            error = "Invalid";
-         }
-         
-         printk("%s error ", error);
-         
+       }
+       
+       printk("%s error ", error);
+       
 #if (CONSTANTS & CONST_SENSE)
-         printk( "%s%x: sense key %s\n", devclass, dev, snstext[sense_buffer[2] & 0x0f]);
+       printk( "%s%x: sense key %s\n", devclass, dev, snstext[sense_buffer[2] & 0x0f]);
 #else
-         printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]);
+       printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]);
 #endif
        
        /* Check to see if additional sense information is available */
@@ -409,42 +410,42 @@ void print_sense(char * devclass, Scsi_Cmnd * SCpnt)
        
 #if (CONSTANTS & CONST_XSENSE)
        for(i=0; additional[i].text; i++)
-               if(additional[i].code1 == sense_buffer[12] &&
-                  additional[i].code2 == sense_buffer[13])
-                       printk("Additional sense indicates %s\n", additional[i].text);
+           if(additional[i].code1 == sense_buffer[12] &&
+              additional[i].code2 == sense_buffer[13])
+               printk("Additional sense indicates %s\n", additional[i].text);
        
        for(i=0; additional2[i].text; i++)
-               if(additional2[i].code1 == sense_buffer[12] &&
-                  additional2[i].code2_min >= sense_buffer[13]  &&
-                  additional2[i].code2_max <= sense_buffer[13]) {
-                       printk("Additional sense indicates ");
-                       printk(additional2[i].text, sense_buffer[13]);
-                       printk("\n");
-               };
+           if(additional2[i].code1 == sense_buffer[12] &&
+              additional2[i].code2_min >= sense_buffer[13]  &&
+              additional2[i].code2_max <= sense_buffer[13]) {
+               printk("Additional sense indicates ");
+               printk(additional2[i].text, sense_buffer[13]);
+               printk("\n");
+           };
 #else
        printk("ASC=%2x ASCQ=%2x\n", sense_buffer[12], sense_buffer[13]);
 #endif
-       } else { 
-
+    } else { 
+       
 #if (CONSTANTS & CONST_SENSE)
-         if (sense_buffer[0] < 15)
+       if (sense_buffer[0] < 15)
            printk("%s%x: old sense key %s\n", devclass, dev, snstext[sense_buffer[0] & 0x0f]);
-         else
+       else
 #endif
            printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]);
-
-         printk("Non-extended sense class %d code 0x%0x ", sense_class, code);
-         s = 4;
-       }
        
-      done:
+       printk("Non-extended sense class %d code 0x%0x ", sense_class, code);
+       s = 4;
+    }
+    
+ done:
 #if !(CONSTANTS & CONST_SENSE)
-       printk("Raw sense data:");
-       for (i = 0; i < s; ++i) 
-         printk("0x%02x ", sense_buffer[i]);
-       printk("\n");
+    printk("Raw sense data:");
+    for (i = 0; i < s; ++i) 
+       printk("0x%02x ", sense_buffer[i]);
+    printk("\n");
 #endif
-       return;
+    return;
 }
 
 #if (CONSTANTS & CONST_MSG) 
@@ -486,11 +487,11 @@ int print_msg (const unsigned char *msg) {
        switch (msg[2]) {
        case EXTENDED_MODIFY_DATA_POINTER:
            printk("pointer = %d", (int) (msg[3] << 24) | (msg[4] << 16) | 
-               (msg[5] << 8) | msg[6]);
+                  (msg[5] << 8) | msg[6]);
            break;
        case EXTENDED_SDTR:
            printk("period = %d ns, offset = %d", (int) msg[3] * 4, (int) 
-               msg[4]);
+                  msg[4]);
            break;
        case EXTENDED_WDTR:
            printk("width = 2^%d bytes", msg[3]);
@@ -503,18 +504,18 @@ int print_msg (const unsigned char *msg) {
        for (i = 0; i < len; ++i)
            printk("%02x ", msg[i]);
 #endif
-    /* Identify */
+       /* Identify */
     } else if (msg[0] & 0x80) {
 #if (CONSTANTS & CONST_MSG)
        printk("Identify disconnect %sallowed %s %d ",
-           (msg[0] & 0x40) ? "" : "not ",
-           (msg[0] & 0x20) ? "target routine" : "lun",
-           msg[0] & 0x7);
+              (msg[0] & 0x40) ? "" : "not ",
+              (msg[0] & 0x20) ? "target routine" : "lun",
+              msg[0] & 0x7);
 #else
-    printk("%02x ", msg[0]);
+       printk("%02x ", msg[0]);
 #endif
-    len = 1;
-    /* Normal One byte */
+       len = 1;
+       /* Normal One byte */
     } else if (msg[0] < 0x1f) {
 #if (CONSTANTS & CONST_MSG)
        if (msg[0] < NO_ONE_BYTE_MSGS)
@@ -525,15 +526,15 @@ int print_msg (const unsigned char *msg) {
        printk("%02x ", msg[0]);
 #endif
        len = 1;
-    /* Two byte */
+       /* Two byte */
     } else if (msg[0] <= 0x2f) {
 #if (CONSTANTS & CONST_MSG)
        if ((msg[0] - 0x20) < NO_TWO_BYTE_MSGS)
            printk("%s %02x ", two_byte_msgs[msg[0] - 0x20], 
-               msg[1]);
+                  msg[1]);
        else 
            printk("reserved two byte (%02x %02x) ", 
-               msg[0], msg[1]);
+                  msg[0], msg[1]);
 #else
        printk("%02x %02x", msg[0], msg[1]);
 #endif
@@ -542,16 +543,35 @@ int print_msg (const unsigned char *msg) {
 #if (CONSTANTS & CONST_MSG)
        printk(reserved);
 #else
-       printk("%02x ", msg[0]);
+    printk("%02x ", msg[0]);
 #endif
     return len;
 }
 
 void print_Scsi_Cmnd (Scsi_Cmnd *cmd) {
     printk("scsi%d : destination target %d, lun %d\n", 
-    cmd->host->host_no, 
-    cmd->target, 
-    cmd->lun);
+          cmd->host->host_no, 
+          cmd->target, 
+          cmd->lun);
     printk("        command = ");
     print_command (cmd->cmnd);
 }
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
index 8f95f2c59793297ca98fd7fc5fe4e71cd03492aa..99a5924d38ee42721e76143fcf41faa1708db5dd 100644 (file)
@@ -198,14 +198,14 @@ struct eata_info {
    ulong  data_len;     /* Number of valid bytes after this field */
    ulong  sign;         /* ASCII "EATA" signature */
    unchar        :4,    /* unused low nibble */
-          version:4;    /* EATA version, should be 0x1 */
+         version:4;    /* EATA version, should be 0x1 */
    unchar  ocsena:1,    /* Overlap Command Support Enabled */
-           tarsup:1,    /* Target Mode Supported */
-                 :2,
-           dmasup:1,    /* DMA Supported */
-           drqvld:1,    /* DRQ Index (DRQX) is valid */
-              ata:1,    /* This is an ATA device */
-           haaval:1;    /* Host Adapter Address Valid */
+          tarsup:1,    /* Target Mode Supported */
+                :2,
+          dmasup:1,    /* DMA Supported */
+          drqvld:1,    /* DRQ Index (DRQX) is valid */
+             ata:1,    /* This is an ATA device */
+          haaval:1;    /* Host Adapter Address Valid */
    ushort cp_pad_len;   /* Number of pad bytes after cp_len */
    unchar host_addr[3]; /* Host Adapter SCSI ID for channels 2, 1, 0 */
    unchar reserved;
@@ -215,17 +215,17 @@ struct eata_info {
    ushort unused;
    ushort scatt_size;   /* Max number of entries in scatter/gather table */
    unchar     irq:4,    /* Interrupt Request assigned to this controller */
-           irq_tr:1,    /* 0 for edge triggered, 1 for level triggered */
-           second:1,    /* 1 if this is a secondary (not primary) controller */
-             drqx:2;    /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
+          irq_tr:1,    /* 0 for edge triggered, 1 for level triggered */
+          second:1,    /* 1 if this is a secondary (not primary) controller */
+            drqx:2;    /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
    unchar  sync;        /* 1 if scsi target id 7...0 is running sync scsi */
 
    /* Structure extension defined in EATA 2.0B */
    unchar  isaena:1,    /* ISA i/o addressing is disabled/enabled */
-         forcaddr:1,    /* Port address has been forced */
-                 :6;
+        forcaddr:1,    /* Port address has been forced */
+                :6;
    unchar  max_id:5,    /* Max number of SCSI target IDs */
-         max_chan:3;    /* Max SCSI channel number on this board */
+        max_chan:3;    /* Max SCSI channel number on this board */
 
    ushort ipad[249];
    };
@@ -234,17 +234,17 @@ struct eata_info {
 struct eata_config {
    ushort len;          /* Number of bytes following this field */
    unchar edis:1,       /* Disable EATA interface after config command */
-         ocena:1,       /* Overlapped Commands Enabled */
-        mdpena:1,       /* Transfer all Modified Data Pointer Messages */
-        tarena:1,       /* Target Mode Enabled for this controller */
-              :4;
+        ocena:1,       /* Overlapped Commands Enabled */
+       mdpena:1,       /* Transfer all Modified Data Pointer Messages */
+       tarena:1,       /* Target Mode Enabled for this controller */
+             :4;
    unchar cpad[511];
    };
 
 /* Returned status packet structure */
 struct mssp {
    unchar adapter_status:7,    /* State related to current command */
-                     eoc:1;    /* End Of Command (1 = command completed) */
+                    eoc:1;    /* End Of Command (1 = command completed) */
    unchar target_status;       /* SCSI status received after data transfer */
    unchar unused[2];
    ulong inv_res_len;          /* Number of bytes not transferred */
@@ -255,23 +255,23 @@ struct mssp {
 /* MailBox SCSI Command Packet */
 struct mscp {
    unchar  sreset:1,     /* SCSI Bus Reset Signal should be asserted */
-             init:1,     /* Re-initialize controller and self test */
-           reqsen:1,     /* Transfer Request Sense Data to addr using DMA */
-               sg:1,     /* Use Scatter/Gather */
-                 :1,
-           interp:1,     /* The controller interprets cp, not the target */ 
-             dout:1,     /* Direction of Transfer is Out (Host to Target) */
-              din:1;     /* Direction of Transfer is In (Target to Host) */
+            init:1,     /* Re-initialize controller and self test */
+          reqsen:1,     /* Transfer Request Sense Data to addr using DMA */
+              sg:1,     /* Use Scatter/Gather */
+                :1,
+          interp:1,     /* The controller interprets cp, not the target */ 
+            dout:1,     /* Direction of Transfer is Out (Host to Target) */
+             din:1;     /* Direction of Transfer is In (Target to Host) */
    unchar sense_len;     /* Request Sense Length */
    unchar unused[4];
    unchar phsunit:1,     /* Send to Target Physical Unit (bypass RAID) */
-          notused:7;
+         notused:7;
    unchar target;        /* SCSI Target ID */
    unchar     lun:3,     /* LUN */
-                 :2,
-           luntar:1,     /* This cp is for Target (not LUN) */
-           dispri:1,     /* Disconnect Privilege granted */
-              one:1;     /* 1 */
+                :2,
+          luntar:1,     /* This cp is for Target (not LUN) */
+          dispri:1,     /* Disconnect Privilege granted */
+             one:1;     /* 1 */
    unchar mess[3];       /* Massage to/from Target */
    unchar cdb[12];       /* Command Descriptor Block */
    ulong  data_len;      /* If sg=0 Data Length, if sg=1 sglist length */
@@ -346,7 +346,7 @@ static inline unchar read_pio (ushort iobase, ushort *start, ushort *end) {
    for (p = start; p <= end; p++) {
 
       while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) 
-         if (--loop == 0) return TRUE;
+        if (--loop == 0) return TRUE;
 
       loop = MAXLOOP;
       *p = inw(iobase);
@@ -356,7 +356,7 @@ static inline unchar read_pio (ushort iobase, ushort *start, ushort *end) {
 }
 
 static inline int port_detect(ushort *port_base, unsigned int j, 
-                              Scsi_Host_Template * tpnt) {
+                             Scsi_Host_Template * tpnt) {
    unsigned char irq, dma_channel, subversion;
    unsigned char protocol_rev;
    struct eata_info info;
@@ -371,7 +371,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
 
    if(check_region(*port_base, REGION_SIZE)) {
       printk("%s: address 0x%03x in use, skipping probe.\n", 
-             name, *port_base);
+            name, *port_base);
       return FALSE;
       }
 
@@ -386,7 +386,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
 
    if (ntohl(info.data_len) < EATA_2_0A_SIZE) {
       printk("%s: config structure size (%ld bytes) too short, detaching.\n", 
-             name, ntohl(info.data_len));
+            name, ntohl(info.data_len));
       return FALSE;
       }
    else if (ntohl(info.data_len) == EATA_2_0A_SIZE)
@@ -404,10 +404,10 @@ static inline int port_detect(ushort *port_base, unsigned int j,
    if (*port_base & EISA_RANGE) {
 
       if (!info.haaval || info.ata || info.drqvld) {
-         printk("%s: unusable EISA board found (%d%d%d), detaching.\n", 
-                name, info.haaval, info.ata, info.drqvld);
-         return FALSE;
-         }
+        printk("%s: unusable EISA board found (%d%d%d), detaching.\n", 
+               name, info.haaval, info.ata, info.drqvld);
+        return FALSE;
+        }
 
       subversion = ESA;
       dma_channel = NO_DMA;
@@ -415,10 +415,10 @@ static inline int port_detect(ushort *port_base, unsigned int j,
    else {
 
       if (!info.haaval || info.ata || !info.drqvld) {
-         printk("%s: unusable ISA board found (%d%d%d), detaching.\n",
-                name, info.haaval, info.ata, info.drqvld);
-         return FALSE;
-         }
+        printk("%s: unusable ISA board found (%d%d%d), detaching.\n",
+               name, info.haaval, info.ata, info.drqvld);
+        return FALSE;
+        }
 
       subversion = ISA;
       dma_channel = dma_channel_table[3 - info.drqx];
@@ -429,7 +429,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
 
    if (subversion == ESA && !info.irq_tr)
       printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
-             name, irq);
+            name, irq);
 
    if (info.second)
       board_status = "Sec.";
@@ -445,7 +445,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
 
    if (subversion == ISA && request_dma(dma_channel, driver_name)) {
       printk("%s: unable to allocate DMA channel %u, detaching.\n",
-             name, dma_channel);
+            name, dma_channel);
       free_irq(irq);
       return FALSE;
       }
@@ -510,9 +510,9 @@ static inline int port_detect(ushort *port_base, unsigned int j,
    strcpy(BN(j), name);
 
    printk("%s: 2.0%c, %s, ID %d, PORT 0x%03x, IRQ %u, DMA %u, SG %d, "\
-          "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev, board_status, 
-           sh[j]->this_id, sh[j]->io_port, sh[j]->irq, sh[j]->dma_channel,
-           sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun);
+         "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev, board_status, 
+          sh[j]->this_id, sh[j]->io_port, sh[j]->irq, sh[j]->dma_channel,
+          sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun);
 
    /* DPT PM2012 does not allow to detect sg_tablesize correctly */
    if (sh[j]->sg_tablesize > MAX_SGLIST || sh[j]->sg_tablesize < 2) {
@@ -529,12 +529,12 @@ static inline int port_detect(ushort *port_base, unsigned int j,
 #if defined (DEBUG_DETECT)
    if (protocol_rev != 'A')
       printk("%s: EATA 2.0%c, isaena %u, forcaddr %u, max_id %u,"\
-             " max_chan %u.\n", name, protocol_rev, info.isaena, 
-             info.forcaddr, info.max_id, info.max_chan);
+            " max_chan %u.\n", name, protocol_rev, info.isaena, 
+            info.forcaddr, info.max_id, info.max_chan);
 
    printk("%s: Version 0x%x, SYNC 0x%x, infol %ld, cpl %ld spl %ld.\n", 
-          name, info.version, info.sync, ntohl(info.data_len), 
-          ntohl(info.cp_len), ntohl(info.sp_len));
+         name, info.version, info.sync, ntohl(info.data_len), 
+         ntohl(info.cp_len), ntohl(info.sp_len));
 #endif
 
    return TRUE;
@@ -617,18 +617,18 @@ int eata2x_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
       if (i >= sh[j]->can_queue) i = 0;
 
       if (HD(j)->cp_stat[i] == FREE) {
-         HD(j)->last_cp_used = i;
-         break;
-         }
+        HD(j)->last_cp_used = i;
+        break;
+        }
       }
 
    if (k == sh[j]->can_queue) {
       printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
 
       if (HD(j)->in_reset) 
-         printk("%s: qcomm, already in reset.\n", BN(j));
+        printk("%s: qcomm, already in reset.\n", BN(j));
       else if (eata2x_reset(SCpnt) == SCSI_RESET_SUCCESS) 
-         panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
+        panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
 
       SCpnt->result = DID_BUS_BUSY << 16; 
       SCpnt->host_scribble = NULL;
@@ -656,13 +656,13 @@ int eata2x_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    SCpnt->host_scribble = (unsigned char *) &cpp->index;
 
    if (do_trace) printk("%s: qcomm, mbox %d, target %d, pid %ld.\n",
-                        BN(j), i, SCpnt->target, SCpnt->pid);
+                       BN(j), i, SCpnt->target, SCpnt->pid);
 
    for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
      if (SCpnt->cmnd[0] == data_out_cmds[k]) {
-        cpp->dout = TRUE;
-        break;
-        }
+       cpp->dout = TRUE;
+       break;
+       }
 
    cpp->din = !cpp->dout;
    cpp->reqsen = TRUE;
@@ -690,7 +690,7 @@ int eata2x_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
       SCpnt->result = DID_ERROR << 16; 
       SCpnt->host_scribble = NULL;
       printk("%s: qcomm, target %d, pid %ld, adapter busy, DID_ERROR, done.\n", 
-             BN(j), SCpnt->target, SCpnt->pid);
+            BN(j), SCpnt->target, SCpnt->pid);
       restore_flags(flags);
       done(SCpnt);    
       return 0;
@@ -710,13 +710,13 @@ int eata2x_abort (Scsi_Cmnd *SCarg) {
 
    if (SCarg->host_scribble == NULL) {
       printk("%s: abort, target %d, pid %ld inactive.\n",
-             BN(j), SCarg->target, SCarg->pid);
+            BN(j), SCarg->target, SCarg->pid);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
    i = *(unsigned int *)SCarg->host_scribble;
    printk("%s: abort, mbox %d, target %d, pid %ld.\n", 
-          BN(j), i, SCarg->target, SCarg->pid);
+         BN(j), i, SCarg->target, SCarg->pid);
 
    if (i >= sh[j]->can_queue)
       panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -737,8 +737,8 @@ int eata2x_abort (Scsi_Cmnd *SCarg) {
       printk("%s: abort, mbox %d is in use.\n", BN(j), i);
 
       if (SCarg != HD(j)->cp[i].SCpnt)
-         panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
-               BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+        panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+              BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
 
       restore_flags(flags);
       return SCSI_ABORT_SNOOZE;
@@ -768,7 +768,7 @@ int eata2x_reset (Scsi_Cmnd *SCarg) {
    cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
    printk("%s: reset, enter, target %d, pid %ld.\n", 
-          BN(j), SCarg->target, SCarg->pid);
+         BN(j), SCarg->target, SCarg->pid);
 
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
@@ -794,27 +794,27 @@ int eata2x_reset (Scsi_Cmnd *SCarg) {
       if (HD(j)->cp_stat[i] == FREE) continue;
 
       if (HD(j)->cp_stat[i] == LOCKED) {
-         HD(j)->cp_stat[i] = FREE;
-         printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
-         continue;
-         }
+        HD(j)->cp_stat[i] = FREE;
+        printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+        continue;
+        }
 
       SCpnt = HD(j)->cp[i].SCpnt;
       HD(j)->cp_stat[i] = IN_RESET;
       printk("%s: reset, mbox %d in reset, pid %ld.\n",
-             BN(j), i, SCpnt->pid);
+            BN(j), i, SCpnt->pid);
 
       if (SCpnt == NULL)
-         panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+        panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
 
       if (SCpnt->host_scribble == NULL)
-         panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+        panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
 
       if (*(unsigned int *)SCpnt->host_scribble != i) 
-         panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+        panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
 
       if (SCpnt->scsi_done == NULL) 
-         panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+        panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
 
       if (SCpnt == SCarg) arg_done = TRUE;
       }
@@ -851,7 +851,7 @@ int eata2x_reset (Scsi_Cmnd *SCarg) {
       HD(j)->cp_stat[i] = LOCKED;
 
       printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
-             BN(j), i, SCpnt->pid);
+            BN(j), i, SCpnt->pid);
       restore_flags(flags);
       SCpnt->scsi_done(SCpnt);
       cli();
@@ -887,7 +887,7 @@ static void eata2x_interrupt_handler(int irq, struct pt_regs * regs) {
       }
 
    if (do_trace) printk("%s: ihdlr, enter, irq %d, calls %d.\n", 
-                        driver_name, irq, calls[irq]);
+                       driver_name, irq, calls[irq]);
 
    /* Service all the boards configured on this irq */
    for (j = 0; sh[j] != NULL; j++) {
@@ -898,164 +898,164 @@ static void eata2x_interrupt_handler(int irq, struct pt_regs * regs) {
 
       /* Loop until all interrupts for a board are serviced */
       while (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED) {
-         total_loops++;
-         loops++;
+        total_loops++;
+        loops++;
 
-         if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
-                              BN(j), HD(j)->iocount);
+        if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
+                             BN(j), HD(j)->iocount);
    
-         /* Read the status register to clear the interrupt indication */
-         inb(sh[j]->io_port + REG_STATUS);
+        /* Read the status register to clear the interrupt indication */
+        inb(sh[j]->io_port + REG_STATUS);
    
-         /* Service all mailboxes of this board */
-         for (i = 0; i < sh[j]->can_queue; i++) {
-            spp = &HD(j)->sp[i];
+        /* Service all mailboxes of this board */
+        for (i = 0; i < sh[j]->can_queue; i++) {
+           spp = &HD(j)->sp[i];
    
-            /* Check if this mailbox has completed the operation */
-            if (spp->eoc == FALSE) continue;
+           /* Check if this mailbox has completed the operation */
+           if (spp->eoc == FALSE) continue;
    
-            spp->eoc = FALSE;
+           spp->eoc = FALSE;
    
-            if (HD(j)->cp_stat[i] == IGNORE) {
-               HD(j)->cp_stat[i] = FREE;
-               continue;
-               }
-            else if (HD(j)->cp_stat[i] == LOCKED) {
-               HD(j)->cp_stat[i] = FREE;
-               printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
-                      BN(j), i, HD(j)->iocount);
-               continue;
-               }
-            else if (HD(j)->cp_stat[i] == FREE) {
-               printk("%s: ihdlr, mbox %d is free, count %d.\n", 
-                      BN(j), i, HD(j)->iocount);
-               continue;
-               }
-            else if (HD(j)->cp_stat[i] == IN_RESET)
-               printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
-            else if (HD(j)->cp_stat[i] != IN_USE) 
-               panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
+           if (HD(j)->cp_stat[i] == IGNORE) {
+              HD(j)->cp_stat[i] = FREE;
+              continue;
+              }
+           else if (HD(j)->cp_stat[i] == LOCKED) {
+              HD(j)->cp_stat[i] = FREE;
+              printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
+                     BN(j), i, HD(j)->iocount);
+              continue;
+              }
+           else if (HD(j)->cp_stat[i] == FREE) {
+              printk("%s: ihdlr, mbox %d is free, count %d.\n", 
+                     BN(j), i, HD(j)->iocount);
+              continue;
+              }
+           else if (HD(j)->cp_stat[i] == IN_RESET)
+              printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
+           else if (HD(j)->cp_stat[i] != IN_USE) 
+              panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
    
-            HD(j)->cp_stat[i] = FREE;
-            cpp = &HD(j)->cp[i];
-            SCpnt = spp->SCpnt;
+           HD(j)->cp_stat[i] = FREE;
+           cpp = &HD(j)->cp[i];
+           SCpnt = spp->SCpnt;
    
-            if (SCpnt == NULL)
-               panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
+           if (SCpnt == NULL)
+              panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
    
-            if (SCpnt != cpp->SCpnt)
-               panic("%s: ihdlr, mbox %d, sp SCpnt %p, cp SCpnt %p.\n",
-                     BN(j), i, SCpnt, cpp->SCpnt);
+           if (SCpnt != cpp->SCpnt)
+              panic("%s: ihdlr, mbox %d, sp SCpnt %p, cp SCpnt %p.\n",
+                    BN(j), i, SCpnt, cpp->SCpnt);
    
-            if (SCpnt->host_scribble == NULL)
-               panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
-                     BN(j), i, SCpnt->pid, SCpnt);
+           if (SCpnt->host_scribble == NULL)
+              panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
+                    BN(j), i, SCpnt->pid, SCpnt);
    
-            if (*(unsigned int *)SCpnt->host_scribble != i) 
-               panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
-                     " irq %d.\n", BN(j), i, SCpnt->pid, 
-                     *(unsigned int *)SCpnt->host_scribble, irq);
+           if (*(unsigned int *)SCpnt->host_scribble != i) 
+              panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
+                    " irq %d.\n", BN(j), i, SCpnt->pid, 
+                    *(unsigned int *)SCpnt->host_scribble, irq);
    
-            tstatus = status_byte(spp->target_status);
+           tstatus = status_byte(spp->target_status);
    
-            switch (spp->adapter_status) {
-               case ASOK:     /* status OK */
+           switch (spp->adapter_status) {
+              case ASOK:     /* status OK */
    
-                  /* Forces a reset if a disk drive keeps returning BUSY */
-                  if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) 
-                     status = DID_ERROR << 16;
+                 /* Forces a reset if a disk drive keeps returning BUSY */
+                 if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) 
+                    status = DID_ERROR << 16;
    
-                  /* If there was a bus reset, redo operation on each target */
-                  else if (tstatus != GOOD
-                           && SCpnt->device->type == TYPE_DISK
-                           && HD(j)->target_reset[SCpnt->target])
-                     status = DID_BUS_BUSY << 16;
+                 /* If there was a bus reset, redo operation on each target */
+                 else if (tstatus != GOOD
+                          && SCpnt->device->type == TYPE_DISK
+                          && HD(j)->target_reset[SCpnt->target])
+                    status = DID_BUS_BUSY << 16;
    
-                  /* Works around a flaw in scsi.c */
-                  else if (tstatus == CHECK_CONDITION
-                           && SCpnt->device->type == TYPE_DISK
-                           && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
-                     status = DID_BUS_BUSY << 16;
-
-                  else
-                     status = DID_OK << 16;
+                 /* Works around a flaw in scsi.c */
+                 else if (tstatus == CHECK_CONDITION
+                          && SCpnt->device->type == TYPE_DISK
+                          && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+                    status = DID_BUS_BUSY << 16;
+
+                 else
+                    status = DID_OK << 16;
    
-                  if (tstatus == GOOD)
-                     HD(j)->target_reset[SCpnt->target] = FALSE;
+                 if (tstatus == GOOD)
+                    HD(j)->target_reset[SCpnt->target] = FALSE;
    
-                  if (spp->target_status && SCpnt->device->type == TYPE_DISK)
-                     printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
-                            "0x%x, sense key 0x%x.\n", BN(j), 
-                            SCpnt->target, SCpnt->lun, SCpnt->pid,
-                            spp->target_status, SCpnt->sense_buffer[2]);
+                 if (spp->target_status && SCpnt->device->type == TYPE_DISK)
+                    printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
+                           "0x%x, sense key 0x%x.\n", BN(j), 
+                           SCpnt->target, SCpnt->lun, SCpnt->pid,
+                           spp->target_status, SCpnt->sense_buffer[2]);
    
-                  HD(j)->target_time_out[SCpnt->target] = 0;
+                 HD(j)->target_time_out[SCpnt->target] = 0;
    
-                  break;
-               case ASST:     /* Selection Time Out */
-               case 0x02:     /* Command Time Out   */
+                 break;
+              case ASST:     /* Selection Time Out */
+              case 0x02:     /* Command Time Out   */
    
-                  if (HD(j)->target_time_out[SCpnt->target] > 1)
-                     status = DID_ERROR << 16;
-                  else {
-                     status = DID_TIME_OUT << 16;
-                     HD(j)->target_time_out[SCpnt->target]++;
-                     }
+                 if (HD(j)->target_time_out[SCpnt->target] > 1)
+                    status = DID_ERROR << 16;
+                 else {
+                    status = DID_TIME_OUT << 16;
+                    HD(j)->target_time_out[SCpnt->target]++;
+                    }
    
-                  break;
-               case 0x03:     /* SCSI Bus Reset Received */
-               case 0x04:     /* Initial Controller Power-up */
+                 break;
+              case 0x03:     /* SCSI Bus Reset Received */
+              case 0x04:     /* Initial Controller Power-up */
    
-                  if (SCpnt->device->type != TYPE_TAPE)
-                     status = DID_BUS_BUSY << 16;
-                  else
-                     status = DID_ERROR << 16;
+                 if (SCpnt->device->type != TYPE_TAPE)
+                    status = DID_BUS_BUSY << 16;
+                 else
+                    status = DID_ERROR << 16;
    
-                  for (k = 0; k < MAX_TARGET; k++) 
-                     HD(j)->target_reset[k] = TRUE;
+                 for (k = 0; k < MAX_TARGET; k++) 
+                    HD(j)->target_reset[k] = TRUE;
    
-                  break;
-               case 0x07:     /* Bus Parity Error */
-               case 0x0c:     /* Controller Ram Parity */
-               case 0x05:     /* Unexpected Bus Phase */
-               case 0x06:     /* Unexpected Bus Free */
-               case 0x08:     /* SCSI Hung */
-               case 0x09:     /* Unexpected Message Reject */
-               case 0x0a:     /* SCSI Bus Reset Stuck */
-               case 0x0b:     /* Auto Request-Sense Failed */
-               default:
-                  status = DID_ERROR << 16;
-                  break;
-               }
+                 break;
+              case 0x07:     /* Bus Parity Error */
+              case 0x0c:     /* Controller Ram Parity */
+              case 0x05:     /* Unexpected Bus Phase */
+              case 0x06:     /* Unexpected Bus Free */
+              case 0x08:     /* SCSI Hung */
+              case 0x09:     /* Unexpected Message Reject */
+              case 0x0a:     /* SCSI Bus Reset Stuck */
+              case 0x0b:     /* Auto Request-Sense Failed */
+              default:
+                 status = DID_ERROR << 16;
+                 break;
+              }
    
-            SCpnt->result = status | spp->target_status;
-            HD(j)->iocount++;
+           SCpnt->result = status | spp->target_status;
+           HD(j)->iocount++;
 
-            if (loops > 1) HD(j)->multicount++;
+           if (loops > 1) HD(j)->multicount++;
 
 #if defined (DEBUG_INTERRUPT)
-            if (SCpnt->result || do_trace)
+           if (SCpnt->result || do_trace)
 #else
-            if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
-                (spp->adapter_status != ASOK && 
-                 spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
-                do_trace)
+           if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
+               (spp->adapter_status != ASOK && 
+                spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
+               do_trace)
 #endif
-               printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\
-                      " target %d:%d, pid %ld, count %d.\n",
-                      BN(j), i, spp->adapter_status, spp->target_status,
-                      SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount);
+              printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\
+                     " target %d:%d, pid %ld, count %d.\n",
+                     BN(j), i, spp->adapter_status, spp->target_status,
+                     SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount);
    
-            /* Set the command state to inactive */
-            SCpnt->host_scribble = NULL;
+           /* Set the command state to inactive */
+           SCpnt->host_scribble = NULL;
    
-            restore_flags(flags);
-            SCpnt->scsi_done(SCpnt);
-            cli();
+           restore_flags(flags);
+           SCpnt->scsi_done(SCpnt);
+           cli();
 
-            }   /* Mailbox loop */
+           }   /* Mailbox loop */
 
-         }   /* Multiple command loop */
+        }   /* Multiple command loop */
 
       }   /* Boards loop */
 
@@ -1063,16 +1063,16 @@ static void eata2x_interrupt_handler(int irq, struct pt_regs * regs) {
 
    if (total_loops == 0) 
      printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
-            driver_name, irq, calls[irq]);
+           driver_name, irq, calls[irq]);
 
    if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n", 
-                        driver_name, irq, calls[irq]);
+                       driver_name, irq, calls[irq]);
 
 #if defined (DEBUG_STATISTICS)
    if ((calls[irq] % 100000) == 10000)
       for (j = 0; sh[j] != NULL; j++)
-         printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
-                calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
+        printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
+               calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
 #endif
 
    restore_flags(flags);
index 7c61df22c9156b1dbaecd891c3dcdfa66aa4943c..8b9916c9c27bb68ef950e78160854189308ef590 100644 (file)
@@ -15,24 +15,24 @@ int eata2x_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *);
 
 #define EATA {                                                 \
-                NULL, /* Ptr for modules */                    \
-                NULL, /* usage count for modules */           \
-                "EATA/DMA 2.0x rev. " EATA_VERSION " ",        \
-                eata2x_detect,                                \
-                NULL, /* Release */                           \
-               NULL,                                          \
+               NULL, /* Ptr for modules */                    \
+               NULL, /* usage count for modules */            \
+               "EATA/DMA 2.0x rev. " EATA_VERSION " ",        \
+               eata2x_detect,                                 \
+               NULL, /* Release */                            \
+               NULL,                                          \
                NULL,                                          \
                eata2x_queuecommand,                           \
                eata2x_abort,                                  \
                eata2x_reset,                                  \
-               NULL,                                          \
+               NULL,                                          \
                scsicam_bios_param,                            \
                0,   /* can_queue, reset by detect */          \
-                7,   /* this_id, reset by detect */            \
-                0,   /* sg_tablesize, reset by detect */       \
-                0,   /* cmd_per_lun, reset by detect */        \
+               7,   /* this_id, reset by detect */            \
+               0,   /* sg_tablesize, reset by detect */       \
+               0,   /* cmd_per_lun, reset by detect */        \
                0,   /* number of boards present */            \
-                1,   /* unchecked isa dma, reset by detect */  \
-                ENABLE_CLUSTERING                              \
-                }
+               1,   /* unchecked isa dma, reset by detect */  \
+               ENABLE_CLUSTERING                              \
+               }
 #endif
index e103bc9f44195b89e2b603cc24f72cea648f2bf8..4d715d4e65719ec7ef714e640857969e492e71a7 100644 (file)
  *      -supports all PCI based EATA-DMA boards             *
  *      -supports multiple HBAs with & without IRQ sharing  *
  *      -supports all SCSI channels on multi channel boards *
- *      -displays (more or less useful) infos in /proc/scsi *
  *      -can be loaded as module                            *
+ *      -displays statistical and hardware information      *
+ *       in /proc/scsi/eata_dma                             *
+ *      -needs identical HBA ids on all channels            * 
  *                                                          *
  *  (c)1993,94,95 Michael Neuffer                           *
  *                neuffer@goofy.zdv.uni-mainz.de            *
@@ -44,7 +46,7 @@
  * Thanks also to Greg Hosler who did a lot of testing and  *
  * found quite a number of bugs during the development.     *
  ************************************************************
- *  last change: 95/04/10       OS: Linux 1.2.00 or higher  *
+ *  last change: 95/06/28 OS: Linux 1.3.4 + pre1.3 SCSI pat.*
  ************************************************************/
 
 /* Look in eata_dma.h for configuration and revision information */
@@ -62,6 +64,8 @@
 #include <linux/in.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <asm/byteorder.h>
 #include <asm/types.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include "hosts.h"
 #include <linux/scsicam.h>
 #include "eata_dma.h"
+#include "eata_dma_proc.h" 
 
-#if EATA_DMA_PROC  
-#include "eata_dma_proc.h"  /* If you're interested send me a mail */ 
-ulong  reads[13];           /* /proc/scsi probably won't get       */ 
-ulong  writes[13];          /* into the kernel before pl. 1.3      */
-#endif
 
-static uint ISAbases[] =
+static u32 ISAbases[] =
 {0x1F0, 0x170, 0x330, 0x230};
 static unchar EISAbases[] =
 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
@@ -96,7 +96,6 @@ static uint internal_command_finished = TRUE;
 static unchar HBA_interpret = FALSE;
 static u32 fake_int_base;
 static u32 fake_int_result;
-static struct geom_emul geometry;      /* Drive 1 & 2 geometry */
 
 static ulong int_counter = 0;
 static ulong queue_counter = 0;
@@ -104,34 +103,41 @@ static ulong queue_counter = 0;
 void eata_scsi_done (Scsi_Cmnd * SCpnt)
 {
     return;
-}      
+}   
 
 void eata_fake_int_handler(s32 irq, struct pt_regs * regs)
 {
     fake_int_result = inb(fake_int_base + HA_RSTATUS);
-    DBG(DBG_INTR3, printk("eata_fake_int_handler called irq%ld base %#lx res %#lx\n", 
-                         irq, fake_int_base, fake_int_result));
+    DBG(DBG_INTR3, printk("eata_fake_int_handler called irq%d base %#x"
+                         " res %#x\n", irq, fake_int_base, fake_int_result));
     return;
 }
 
-#if EATA_DMA_PROC 
 #include "eata_dma_proc.c"
-#endif
 
+#ifdef MODULE
 int eata_release(struct Scsi_Host *sh)
 {
-  if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq);
-  else reg_IRQ[sh->irq]--;
+    uint i;
+    if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq);
+    else reg_IRQ[sh->irq]--;
     
     scsi_init_free((void *)status, 512);
+    scsi_init_free((void *)dma_scratch, 512);
+    for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */
+       if(SD(sh)->ccb[i].sg_list != NULL)
+           scsi_init_free((void *) SD(sh)->ccb[i].sg_list, 
+                          sh->sg_tablesize * sizeof(struct eata_sg_list));
+    }
     
-  if (SD(sh)->channel == 0) {
-      if (sh->dma_channel != 0xff) free_dma(sh->dma_channel);
-      if (sh->io_port && sh->n_io_port)
-         release_region(sh->io_port, sh->n_io_port);
-  }
-  return(TRUE);
+    if (SD(sh)->channel == 0) {
+       if (sh->dma_channel != 0xff) free_dma(sh->dma_channel);
+       if (sh->io_port && sh->n_io_port)
+           release_region(sh->io_port, sh->n_io_port);
+    }
+    return(TRUE);
 }
+#endif
 
 const char *eata_info(struct Scsi_Host *host)
 {
@@ -155,44 +161,44 @@ void eata_int_handler(int irq, struct pt_regs * regs)
     cli();
 
     for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) {
-        if (sh->irq != irq)
+       if (sh->irq != irq)
            continue;
-        if (!(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ))
+       if (!(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ))
            continue;
-
+       
        int_counter++;
-
+       
        sp=&SD(sh)->sp;
-
+       
        cp = sp->ccb;
        cmd = cp->cmd;
        base = (uint) cmd->host->base;
-
+       
        hba_stat = sp->hba_stat;
-
-       scsi_stat = (sp->scsi_stat >> 1) && 0x1f; 
-
+       
+       scsi_stat = (sp->scsi_stat >> 1) & 0x1f; 
+       
        if (sp->EOC == FALSE) {
            eata_stat = inb(base + HA_RSTATUS);
            printk("eata_dma: int_handler, board: %x cmd %lx returned "
                   "unfinished.\nEATA: %x HBA: %x SCSI: %x spadr %lx spadrirq "
                   "%lx, irq%d\n", base, (long)cp, eata_stat, hba_stat, 
                   scsi_stat,(long)&status, (long)&status[irq], irq);
-           DBG(DBG_DELAY,DEL2(800));
+           DBG(DBG_DELAY, DEL2(800));
            restore_flags(flags);
            return;
        } 
-
+       
        if (cp->status == LOCKED) {
            cp->status = FREE;
            eata_stat = inb(base + HA_RSTATUS);
            printk("eata_dma: int_handler, freeing locked queueslot\n");
-           DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+           DBG(DBG_INTR && DBG_DELAY, DEL2(800));
            restore_flags(flags);
            return;
        }
-
-       eata_stat = inb(base + HA_RSTATUS);     
+       
+       eata_stat = inb(base + HA_RSTATUS); 
        DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, target: "
                             "%x, lun: %x, ea_s: %#.2x, hba_s: %#.2x \n", 
                             irq, base, cmd->pid, cmd->target, cmd->lun, 
@@ -202,63 +208,67 @@ void eata_int_handler(int irq, struct pt_regs * regs)
        case HA_NO_ERROR:       /* NO Error */
            if (scsi_stat == CONDITION_GOOD
                && cmd->device->type == TYPE_DISK
-               && (HD(cmd)->t_state[cmd->target] == RESET))
-               result = DID_BUS_BUSY << 16;        
-            else if (scsi_stat == GOOD)
-             HD(cmd)->t_state[cmd->target] = FALSE;
+               && (HD(cmd)->t_state[cp->cp_channel][cp->cp_id] == RESET))
+               result = DID_BUS_BUSY << 16;        
+           else if (scsi_stat == GOOD)
+               HD(cmd)->t_state[cp->cp_channel][cp->cp_id] = OK;
            else if (scsi_stat == CHECK_CONDITION
-                     && cmd->device->type == TYPE_DISK
-                     && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
-             result = DID_BUS_BUSY << 16;
+                    && cmd->device->type == TYPE_DISK
+                    && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+               result = DID_BUS_BUSY << 16;
            else
-               result = DID_OK << 16;
-           HD(cmd)->t_timeout[cmd->target] = FALSE;
+               result = DID_OK << 16;
+           HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] = OK;
            break;
-       case HA_ERR_SEL_TO:             /* Selection Timeout */
+       case HA_ERR_SEL_TO:     /* Selection Timeout */
            result = DID_BAD_TARGET << 16;  
            break;
-       case HA_ERR_CMD_TO:             /* Command Timeout   */
-           if (HD(cmd)->t_timeout[cmd->target] > 1)
+       case HA_ERR_CMD_TO:     /* Command Timeout   */
+           if (HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] > 1)
                result = DID_ERROR << 16;
            else {
                result = DID_TIME_OUT << 16;
-               HD(cmd)->t_timeout[cmd->target]++;
+               HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id]++;
            }
            break;
-        case HA_ERR_RESET:              /* SCSI Bus Reset Received */
-        case HA_INIT_POWERUP:           /* Initial Controller Power-up */
+       case HA_ERR_RESET:              /* SCSI Bus Reset Received */
+       case HA_INIT_POWERUP:           /* Initial Controller Power-up */
            if (cmd->device->type != TYPE_TAPE)
                result = DID_BUS_BUSY << 16;
            else
                result = DID_ERROR << 16;
-
+           
            for (i = 0; i < MAXTARGET; i++)
-               HD(cmd)->t_state[i] = RESET;
+               HD(cmd)->t_state[cp->cp_channel][i] = RESET;
            break;
-        case HA_UNX_BUSPHASE:       /* Unexpected Bus Phase */
-        case HA_UNX_BUS_FREE:       /* Unexpected Bus Free */
-        case HA_BUS_PARITY:         /* Bus Parity Error */
-        case HA_SCSI_HUNG:          /* SCSI Hung */
-        case HA_UNX_MSGRJCT:        /* Unexpected Message Reject */
-        case HA_RESET_STUCK:        /* SCSI Bus Reset Stuck */
-        case HA_RSENSE_FAIL:        /* Auto Request-Sense Failed */
-        case HA_PARITY_ERR:         /* Controller Ram Parity */
+       case HA_UNX_BUSPHASE:       /* Unexpected Bus Phase */
+       case HA_UNX_BUS_FREE:       /* Unexpected Bus Free */
+       case HA_BUS_PARITY:         /* Bus Parity Error */
+       case HA_SCSI_HUNG:          /* SCSI Hung */
+       case HA_UNX_MSGRJCT:        /* Unexpected Message Reject */
+       case HA_RESET_STUCK:        /* SCSI Bus Reset Stuck */
+       case HA_RSENSE_FAIL:        /* Auto Request-Sense Failed */
+       case HA_PARITY_ERR:         /* Controller Ram Parity */
        default:
            result = DID_ERROR << 16;
            break;
        }
        cmd->result = result | (scsi_stat << 1); 
-
+       
 #if DBG_INTR2
-       if (scsi_stat || result || hba_stat || eata_stat != 0x50) 
-           printk("eata_stat: %#x hba_stat: %#.2x,scsi_stat: %#.2x, "
-                  "sense_key: %#x, result: %#.8x\n", eata_stat, hba_stat, 
-                scsi_stat,cmd->sense_buffer[2] & 0xf, cmd->result); 
+       if (scsi_stat || result || hba_stat || eata_stat != 0x50 
+           || cmd->scsi_done == NULL || cmd->device->id == 7) 
+           printk("HBA: %d, channel %d, id: %d, lun %d, pid %ld:\n" 
+                  "eata_stat %#x, hba_stat %#.2x, scsi_stat %#.2x, "
+                  "sense_key: %#x, result: %#.8x\n", 
+                  x, cmd->device->channel, cmd->device->id, cmd->device->lun,
+                  cmd->pid, eata_stat, hba_stat, scsi_stat, 
+                  cmd->sense_buffer[2] & 0xf, cmd->result); 
        DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
 #endif
-
-       cp->status = FREE;   /* now we can release the slot  */
+       
+       cp->status = FREE;          /* now we can release the slot  */
+       
        restore_flags(flags);
        if(cmd->scsi_done != eata_scsi_done) cmd->scsi_done(cmd);
        else {
@@ -269,31 +279,50 @@ void eata_int_handler(int irq, struct pt_regs * regs)
        cli();
     }
     restore_flags(flags);
-
+    
     return;
 }
 
-inline uint eata_send_command(ulong addr, uint base, unchar command)
+inline int eata_send_command(u32 addr, u32 base, u8 command)
 {
-    uint loop = R_LIMIT;
-
+    long loop = R_LIMIT;
+    
     while (inb(base + HA_RAUXSTAT) & HA_ABUSY)
-        if (--loop == 0)
-            return(FALSE);
-
-    outb(addr & 0x000000ff, base + HA_WDMAADDR);
-    outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
+       if (--loop == 0)
+           return(FALSE);
+    
+    outb( addr & 0x000000ff,        base + HA_WDMAADDR);
+    outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 1);
     outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
     outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
     outb(command, base + HA_WCOMMAND);
     return(TRUE);
 }
 
-int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
+#if 0
+inline int eata_send_immediate(u32 addr, u32 base, u8 cmnd, u8 cmnd2, u8 id, 
+                              u8 lun)
 {
-    uint i, x, y;
-    long flags;
+    if(addr){
+       outb( addr & 0x000000ff,        base + HA_WDMAADDR);
+       outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 1);
+       outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
+       outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+    } else {
+       outb(id,  base + HA_WSUBCODE);
+       outb(lun, base + HA_WSUBLUN);
+    }
+    
+    outb(cmnd2, base + HA_WCOMMAND2);
+    outb(cmnd,  base + HA_WCOMMAND);
+    return(TRUE);
+}
+#endif
 
+int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
+{
+    unsigned int i, x, y;
+    u32 flags;
     hostdata *hd;
     struct Scsi_Host *sh;
     struct eata_ccb *cp;
@@ -303,50 +332,50 @@ int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
     cli();
 
     queue_counter++;
-
+    
     if (done == (void *)eata_scsi_done) { 
-        if (internal_command_finished == TRUE)
+       if (internal_command_finished == TRUE)
            internal_command_finished = FALSE;
-        else 
+       else 
            cmd->result = (DID_ERROR << 16) + QUEUE_FULL;
     }
     
     hd = HD(cmd);
     sh = cmd->host;
+    
     /* check for free slot */
-     for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) { 
+    for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) { 
        if (y >= sh->can_queue)
            y = 0;
        if (hd->ccb[y].status == FREE)
            break;
     }
-
+    
     hd->last_ccb = y;
-
+    
     if (x == sh->can_queue) { 
-
-        DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n",sh->can_queue,x,y));
+       
+       DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n", 
+                             sh->can_queue, x, y));
 #if DEBUG_EATA
-        panic("eata_dma: run out of queue slots cmdno:%ld intrno: %ld\n", 
+       panic("eata_dma: run out of queue slots cmdno:%ld intrno: %ld\n", 
              queue_counter, int_counter);
 #else
-        panic("eata_dma: run out of queue slots....\n");
+       panic("eata_dma: run out of queue slots....\n");
 #endif
     }
-
+    
     cp = &hd->ccb[y];
-
-    memset(cp, 0, sizeof(struct eata_ccb));
-
-    cp->status = USED;         /* claim free slot */
+    
+    memset(cp, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
+    
+    cp->status = USED;      /* claim free slot */
     
     DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n",
                          cmd->pid, cmd->target, cmd->lun, y));
     DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
     cmd->scsi_done = (void *)done;
-
+    
     switch (cmd->cmnd[0]) {
     case CHANGE_DEFINITION: case COMPARE:         case COPY:
     case COPY_VERIFY:       case LOG_SELECT:      case MODE_SELECT:
@@ -358,366 +387,366 @@ int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
     case SEARCH_HIGH_12:    case SEARCH_EQUAL_12: case SEARCH_LOW_12:
     case WRITE_12:          case WRITE_VERIFY_12: case SET_WINDOW: 
     case MEDIUM_SCAN:       case SEND_VOLUME_TAG:            
-    case 0xea:         /* alternate number for WRITE LONG */
-       cp->DataOut = TRUE;     /* Output mode */
-        break;
-    case 0x00:
+    case 0xea:      /* alternate number for WRITE LONG */
+       cp->DataOut = TRUE;     /* Output mode */
+       break;
+    case TEST_UNIT_READY:
     default:
-       cp->DataIn = TRUE;      /* Input mode  */
+       cp->DataIn = TRUE;      /* Input mode  */
     }
-
-    if (done == (void *) eata_scsi_done && HBA_interpret == TRUE) 
-        cp->Interpret = TRUE;   /* Interpret command */
-   
+    
+    if ((done == (void *) eata_scsi_done && HBA_interpret == TRUE) 
+       || cmd->target == sh->this_id) 
+       cp->Interpret = TRUE;   /* Interpret command */
+    
     if (cmd->use_sg) {
-       cp->scatter = TRUE;     /* SG mode     */
-       cp->cp_dataDMA = htonl((long)&cp->sg_list);
-        cp->cp_datalen = htonl(cmd->use_sg*8);
+       cp->scatter = TRUE;     /* SG mode     */
+       if (cp->sg_list == NULL) {
+           cp->sg_list = kmalloc(SG_SIZE_BIG*sizeof(struct eata_sg_list),
+                                    GFP_ATOMIC | GFP_DMA);
+       }
+       cp->cp_dataDMA = htonl((ulong)cp->sg_list); 
+       if (cp->cp_dataDMA == 0)
+           panic("eata_dma: Run out of DMA memory for SG lists !\n");
+
+       cp->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));
        sl=(struct scatterlist *)cmd->request_buffer;
        for(i = 0; i < cmd->use_sg; i++, sl++){
-           cp->sg_list[i].data = htonl((ulong) sl->address);
-           cp->sg_list[i].len = htonl((ulong) sl->length);
-       }
+           cp->sg_list[i].data = htonl((u32) sl->address);
+           cp->sg_list[i].len = htonl((u32) sl->length);
+       }
     } else {
-        cp->scatter = FALSE;
+       cp->scatter = FALSE;
        cp->cp_datalen = htonl(cmd->request_bufflen);
-       cp->cp_dataDMA = htonl((ulong)cmd->request_buffer);
+       cp->cp_dataDMA = htonl((u32)cmd->request_buffer);
     }
-
+    
     cp->Auto_Req_Sen = TRUE;
-    cp->cp_reqDMA = htonl((ulong) cmd->sense_buffer);
+    cp->cp_reqDMA = htonl((u32) cmd->sense_buffer);
     cp->reqlen = sizeof(cmd->sense_buffer);
-
+    
     cp->cp_id = cmd->target;
+    cp->cp_channel = cmd->channel;
     cp->cp_lun = cmd->lun;
     cp->cp_dispri = TRUE;
     cp->cp_identify = TRUE;
     memcpy(cp->cp_cdb, cmd->cmnd, cmd->cmd_len);
-
-    cp->cp_statDMA = htonl((ulong) &(hd->sp));
-
+    
+    cp->cp_statDMA = htonl((u32) &(hd->sp));
+    
     cp->cp_viraddr = cp;
     cp->cmd = cmd;
-    cmd->host_scribble = (char *)&hd->ccb[y];  
-
-    if(eata_send_command((ulong) cp, (uint) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
-      cmd->result = DID_ERROR << 16;
-      printk("eata_queue target %d, pid %ld, HBA busy, returning DID_ERROR, done.\n",
-              cmd->target, cmd->pid);
-      restore_flags(flags);
-      if(done != (void *)eata_scsi_done) done(cmd);
-      return (0);
+    cmd->host_scribble = (char *)&hd->ccb[y];   
+    
+    if(eata_send_command((u32) cp, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
+       cmd->result = DID_ERROR << 16;
+       printk("eata_queue target %d, pid %ld, HBA busy, returning DID_ERROR,"
+              " done.\n", cmd->target, cmd->pid);
+       restore_flags(flags);
+       if(done != (void *)eata_scsi_done) done(cmd);
+       return (0);
     }
-    DBG(DBG_QUEUE,printk("Queued base %#.4lx pid: %ld target: %x lun: %x slot %d irq %d\n",
-          (long)sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq));
+    DBG(DBG_QUEUE,printk("Queued base %#.4x pid: %ld target: %x lun: %x "
+                        "slot %d irq %d\n", (s32)sh->base, cmd->pid, 
+                        cmd->target, cmd->lun, y, sh->irq));
     DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
     restore_flags(flags);
     return (0);
 }
 
-static volatile int internal_done_flag = 0;
-static volatile int internal_done_errcode = 0;
-
-static void internal_done(Scsi_Cmnd * cmd)
-{
-    internal_done_errcode = cmd->result;
-    ++internal_done_flag;
-}
-
-int eata_command(Scsi_Cmnd * cmd)
-{
-
-    DBG(DBG_COM, printk("eata_command: calling eata_queue\n"));
-
-    eata_queue(cmd, (void *)internal_done);
-
-    while (!internal_done_flag);
-    internal_done_flag = 0;
-    return (internal_done_errcode);
-}
 
 int eata_abort(Scsi_Cmnd * cmd)
 {
     ulong flags;
-    uint loop = R_LIMIT;
+    ulong loop = R_LIMIT;
 
     save_flags(flags);
     cli();
 
-    DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x reason %x\n",
-                          cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
+    DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x"
+                          " reason %x\n", cmd->pid, cmd->target, cmd->lun, 
+                          cmd->abort_reason));
     DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-
-    while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
-        if (--loop == 0) {
+    
+    
+    while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
+       if (--loop == 0) {
            printk("eata_dma: abort, timeout error.\n");
            restore_flags(flags);
            DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
            return (SCSI_ABORT_ERROR);
        }
+    if (CD(cmd)->status == USED) {
+       DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
+       restore_flags(flags);
+       return (SCSI_ABORT_BUSY);  /* SNOOZE */ 
+    }
     if (CD(cmd)->status == FREE) {
-        DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n")); 
+       DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n")); 
        restore_flags(flags);
        return (SCSI_ABORT_NOT_RUNNING);
     }
-    if (CD(cmd)->status == USED) {
-        DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
-       restore_flags(flags);
-       return (SCSI_ABORT_BUSY);  /* SNOOZE */ 
-    }
     if (CD(cmd)->status == RESET) {
        restore_flags(flags);
-        printk("eata_dma: abort, command reset error.\n");
+       printk("eata_dma: abort, command reset error.\n");
        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-       return (SCSI_ABORT_ERROR);
+       return (SCSI_ABORT_ERROR);
     }
     if (CD(cmd)->status == LOCKED) {
        restore_flags(flags);
-        DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
-        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-       return (SCSI_ABORT_NOT_RUNNING);
+       DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_ABORT_NOT_RUNNING);
     } else
        panic("eata_dma: abort: invalid slot status\n");
 }
 
 int eata_reset(Scsi_Cmnd * cmd)
 {
-    uint x, z, time, limit = 0;
-    uint loop = R_LIMIT;
+    ushort x, z; 
+    ulong time, limit = 0;
+    ulong loop = R_LIMIT;
     ulong flags;
     unchar success = FALSE;
     Scsi_Cmnd *sp; 
-
+    
     save_flags(flags);
     cli();
-
-    DBG(DBG_ABNORM, printk("eata_reset called pid:%ld target: %x lun: %x reason %x\n",
-                          cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
-
-
+    
+    DBG(DBG_ABNORM, printk("eata_reset called pid:%ld target: %x lun: %x"
+                          " reason %x\n", cmd->pid, cmd->target, cmd->lun, 
+                          cmd->abort_reason));
+       
     if (HD(cmd)->state == RESET) {
        printk("eata_reset: exit, already in reset.\n");
        restore_flags(flags);
-        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-       return (SCSI_RESET_ERROR);
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_RESET_ERROR);
     }
-
-    while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
-        if (--loop == 0) {
-           printk("eata_reset: exit, timeout error.\n");
+    
+    while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
+       if (--loop == 0) {
+           printk("eata_reset: exit, timeout error.\n");
            restore_flags(flags);
            DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
            return (SCSI_RESET_ERROR);
        }
-    for (z = 0; z < MAXTARGET; z++) {
-       HD(cmd)->t_state[z] = RESET;
-       HD(cmd)->t_timeout[z] = FALSE;
+    for (x = 0; x < MAXCHANNEL; x++) {
+       for (z = 0; z < MAXTARGET; z++) {
+           HD(cmd)->t_state[x][z] = RESET;
+           HD(cmd)->t_timeout[x][z] = NO_TIMEOUT;
+       }
     }
 
     for (x = 0; x < cmd->host->can_queue; x++) {
-
        if (HD(cmd)->ccb[x].status == FREE)
            continue;
-
+       
        if (HD(cmd)->ccb[x].status == LOCKED) {
            HD(cmd)->ccb[x].status = FREE;
            printk("eata_reset: locked slot %d forced free.\n", x);
            DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-           continue;
+           continue;
        }
        sp = HD(cmd)->ccb[x].cmd;
        HD(cmd)->ccb[x].status = RESET;
        printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
-        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       
        if (sp == NULL)
            panic("eata_reset: slot %d, sp==NULL.\n", x);
-            DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       
        if (sp == cmd)
            success = TRUE;
     }
-
+    
     /* hard reset the HBA  */
-    inb((uint) (cmd->host->base) + HA_RSTATUS);  /* This might cause trouble */
-    eata_send_command(0, (uint) cmd->host->base, EATA_CMD_RESET);
-
+    inb((u32) (cmd->host->base) + HA_RSTATUS);  /* This might cause trouble */
+    eata_send_command(0, (u32) cmd->host->base, EATA_CMD_RESET);
+    
     DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n"));
     HD(cmd)->state = RESET;
-
+    
     restore_flags(flags);
-
+    
     time = jiffies;
-    while (jiffies < (time + 300) && limit++ < 10000000);
-
+    while (jiffies < (time + 300) && limit++ < 10000000)
+       /* nothing */;
+    
     save_flags(flags);
     cli();
-
-    DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %d.\n", limit));
+    
+    DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %ld.\n", 
+                          limit));
     DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+    
     for (x = 0; x < cmd->host->can_queue; x++) {
-
+       
        /* Skip slots already set free by interrupt */
        if (HD(cmd)->ccb[x].status != RESET)
            continue;
-
+       
        sp = HD(cmd)->ccb[x].cmd;
        sp->result = DID_RESET << 16;
-
+       
        /* This mailbox is still waiting for its interrupt */
        HD(cmd)->ccb[x].status = LOCKED;
-
+       
        printk("eata_reset: slot %d locked, DID_RESET, pid %ld done.\n",
-           x, sp->pid);
-        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+              x, sp->pid);
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
        restore_flags(flags);
        sp->scsi_done(sp);
        cli();
     }
-
+    
     HD(cmd)->state = FALSE;
     restore_flags(flags);
-
+    
     if (success) {
        DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n"));
-        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-       return (SCSI_RESET_SUCCESS);
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_RESET_SUCCESS);
     } else {
        DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));
-        DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-       return (SCSI_RESET_PUNT);
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_RESET_PUNT);
     }
 }
 
-char * get_board_data(ulong base, uint irq, uint id)
+char * get_board_data(u32 base, u32 irq, u32 id)
 {
-    struct eata_ccb cp;
-    struct eata_sp  sp;
+    struct eata_ccb *cp;
+    struct eata_sp  *sp;
     static char *buff;
-    u32 i;
+    ulong i;
+    ulong limit = 0;
 
-    buff = dma_scratch;
+    cp = (struct eata_ccb *) scsi_init_malloc(sizeof(struct eata_ccb),
+                                             GFP_ATOMIC | GFP_DMA);
+    sp = (struct eata_sp *) scsi_init_malloc(sizeof(struct eata_sp), 
+                                            GFP_ATOMIC | GFP_DMA);
 
-    memset(&cp, 0, sizeof(struct eata_ccb));
-    memset(&sp, 0, sizeof(struct eata_sp));
+    buff = dma_scratch;
+    memset(cp, 0, sizeof(struct eata_ccb));
+    memset(sp, 0, sizeof(struct eata_sp));
     memset(buff, 0, 256);
 
-    cp.DataIn = TRUE;     
-    cp.Interpret = TRUE;   /* Interpret command */
+    cp->DataIn = TRUE;     
+    cp->Interpret = TRUE;   /* Interpret command */
  
-    cp.cp_datalen = htonl(255);  
-    cp.cp_dataDMA = htonl((s32)buff);
-    cp.cp_viraddr = &cp;
-
-    cp.cp_id = id;
-    cp.cp_lun = 0;
+    cp->cp_datalen = htonl(255);  
+    cp->cp_dataDMA = htonl((s32)buff);
+    cp->cp_viraddr = cp;
+    
+    cp->cp_id = id;
+    cp->cp_lun = 0;
 
-    cp.cp_cdb[0] = INQUIRY;
-    cp.cp_cdb[1] = 0;
-    cp.cp_cdb[2] = 0;
-    cp.cp_cdb[3] = 0;
-    cp.cp_cdb[4] = 255;
-    cp.cp_cdb[5] = 0;
+    cp->cp_cdb[0] = INQUIRY;
+    cp->cp_cdb[1] = 0;
+    cp->cp_cdb[2] = 0;
+    cp->cp_cdb[3] = 0;
+    cp->cp_cdb[4] = 255;
+    cp->cp_cdb[5] = 0;
 
-    cp.cp_statDMA = htonl((ulong) &sp);
+    cp->cp_statDMA = htonl((ulong) sp);
 
     fake_int_base = base;
     fake_int_result = 0;
 
-    eata_send_command((u32) &cp, (u32) base, EATA_CMD_DMA_SEND_CP);
+    eata_send_command((u32) cp, (u32) base, EATA_CMD_DMA_SEND_CP);
     
     i = jiffies + 300;
-    while (!fake_int_result && jiffies <= i) 
-        /* nothing */;
+    while (fake_int_result == FALSE && jiffies <= i) 
+       barrier();
     
-    DBG(DBG_INTR3, printk("fake_int_result: %#lx hbastat %#lx scsistat %#lx,"
+    DBG(DBG_INTR3, printk("fake_int_result: %#x hbastat %#x scsistat %#x,"
                          " buff %p sp %p\n",
-                          fake_int_result, (u32) (sp.hba_stat & 0x7f), 
-                         (u32) sp.scsi_stat, buff, &sp));
+                         fake_int_result, (u32) (sp->hba_stat & 0x7f), 
+                         (u32) sp->scsi_stat, buff, sp));
+
+    scsi_init_free((void *)cp, sizeof(struct eata_ccb));
+    scsi_init_free((void *)sp, sizeof(struct eata_sp));
     
-    if (jiffies > i || (fake_int_result & 1))
-        return (NULL);
-    else
-        return (buff);
+    if ((fake_int_result & HA_SERROR) || jiffies > i){
+       /* hard reset the HBA  */
+       inb((u32) (base) + HA_RSTATUS);
+       eata_send_command(0, base, EATA_CMD_RESET);
+       i = jiffies;
+       while (jiffies < (i + 300) && limit++ < 10000000)
+           barrier();
+       return (NULL);
+    } else
+       return (buff);
 }
     
 int check_blink_state(long base)
 {
-    uint loops = 10;
-    ulong blinkindicator = 0x42445054;
-    ulong state = 0x12345678;
-    ulong oldstate = 0;
+    ushort loops = 10;
+    u32 blinkindicator;
+    u32 state = 0x12345678;
+    u32 oldstate = 0;
 
+    blinkindicator = htonl(0x54504442);
     while ((loops--) && (state != oldstate)) {
        oldstate = state;
        state = inl((uint) base + 1);
     }
 
     DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n",
-                         (state == oldstate) && (state == blinkindicator)));
+             (state == oldstate) && (state == blinkindicator)));
 
     if ((state == oldstate) && (state == blinkindicator))
-        return(TRUE);
+       return(TRUE);
     else
-        return (FALSE);
+       return (FALSE);
 }
 
-int get_conf_PIO(struct eata_register *base, struct get_conf *buf)
+int get_conf_PIO(u32 base, struct get_conf *buf)
 {
     ulong loop = R_LIMIT;
-    ushort *p;
+    u16 *p;
 
-    u8  warning = FALSE;
-    
-    if(check_region((int) base, 9)) {
-        if ((int)base == 0x1f0 || (int)base == 0x170) {
-            warning = 1;
-        } else
-        return (FALSE);
-    }
+    if(check_region(base, 9)) 
+       return (FALSE);
+     
     memset(buf, 0, sizeof(struct get_conf));
 
-    while (inb((uint) base + HA_RSTATUS) & HA_SBUSY)
+    while (inb(base + HA_RSTATUS) & HA_SBUSY)
        if (--loop == 0) 
            return (FALSE);
        
-    DBG(DBG_PIO && DBG_PROBE,printk("Issuing PIO READ CONFIG to HBA at %lx\n", 
-                                  (long)base));
-    eata_send_command(0, (uint) base, EATA_CMD_PIO_READ_CONFIG);
+    DBG(DBG_PIO && DBG_PROBE,
+       printk("Issuing PIO READ CONFIG to HBA at %#x\n", base));
+    eata_send_command(0, base, EATA_CMD_PIO_READ_CONFIG);
+
     loop = R_LIMIT;
-    for (p = (ushort *) buf; 
-         (long)p <= ((long)buf + (sizeof(struct get_conf)/ 2)); p++) {
-        while (!(inb((uint) base + HA_RSTATUS) & HA_SDRQ))
+    for (p = (u16 *) buf; 
+        (long)p <= ((long)buf + (sizeof(struct get_conf) / 2)); p++) {
+       while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
            if (--loop == 0)
-               return (FALSE);
+               return (FALSE);
+
        loop = R_LIMIT;
-       *p = inw((uint) base + HA_RDATA);
+       *p = inw(base + HA_RDATA);
     }
-    if (!(inb((uint) base + HA_RSTATUS) & HA_SERROR)) {                /* Error ? */
-        DBG(DBG_PIO&&DBG_PROBE, printk("\nSignature: %c%c%c%c\n", 
-                             (char)buf->sig[0], (char)buf->sig[1], 
-                             (char)buf->sig[2], (char)buf->sig[3]));
 
-       if ((buf->sig[0] == 'E') && (buf->sig[1] == 'A')
-           && (buf->sig[2] == 'T') && (buf->sig[3] == 'A')) {
+    if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {            /* Error ? */
+       if (htonl(EATA_SIGNATURE) == buf->signature) {
            DBG(DBG_PIO&&DBG_PROBE, printk("EATA Controller found at %x "
-                     "EATA Level: %x\n", (uint) base, (uint) (buf->version)));
-       
-           while (inb((uint) base + HA_RSTATUS) & HA_SDRQ) 
-               inw((uint) base + HA_RDATA);
-            if (warning == TRUE)
-                printk("Warning: HBA with IO on 0x%p detected,\n"
-                       "         this IO space is already allocated, probably by the IDE driver.\n"
-                       "         This might lead to problems.", base);
-           return (TRUE);
+                                          "EATA Level: %x\n", (uint) base, 
+                                          (uint) (buf->version)));
+           
+           while (inb(base + HA_RSTATUS) & HA_SDRQ) 
+               inw(base + HA_RDATA);
+           return (TRUE);
        } 
     } else {
-        DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer "
-                             "for HBA at %lx\n", (long)base));
+       DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer "
+                 "for HBA at %lx\n", (long)base));
     }
     return (FALSE);
 }
@@ -726,127 +755,146 @@ void print_config(struct get_conf *gc)
 {
     printk("Please check values: (read config data)\n");
     printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d DMAS:%d\n",
-       (uint) ntohl(gc->len), gc->version,
-       gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support,
-       gc->DMA_support);
+          (u32) ntohl(gc->len), gc->version,
+          gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support,
+          gc->DMA_support);
     printk("DMAV:%d HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n",
-       gc->DMA_valid, gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
-       gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
-    printk("IRQ:%d IRQT:%d DMAC:%d FORCADR:%d MCH:%d RIDQ:%d PCI:%d EISA:%d\n",
-       gc->IRQ, gc->IRQ_TR, (8 - gc->DMA_channel) & 7, gc->FORCADR, 
-       gc->MAX_CHAN, gc->ID_qest, gc->is_PCI, gc->is_EISA);
+          gc->DMA_valid, gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
+          gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
+    printk("IRQ:%d IRQT:%d DMAC:%d FORCADR:%d SG_64K:%d SG_UAE:%d MID:%d "
+          "MCH:%d MLUN:%d\n",
+          gc->IRQ, gc->IRQ_TR, (8 - gc->DMA_channel) & 7, gc->FORCADR, 
+          gc->SG_64K, gc->SG_UAE, gc->MAX_ID, gc->MAX_CHAN, gc->MAX_LUN); 
+    printk("RIDQ:%d PCI:%d EISA:%d\n",
+          gc->ID_qest, gc->is_PCI, gc->is_EISA);
     DBG(DPT_DEBUG, DELAY(1400));
 }
 
-int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
+short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, 
+                  u8 bustype)
 {
     ulong size = 0;
     unchar dma_channel = 0;
-    char *buff;
-    uint i;
+    char *buff = 0;
+    unchar bugs = 0;
     struct Scsi_Host *sh;
     hostdata *hd;
     
+    
     DBG(DBG_REGISTER, print_config(gc));
 
-    if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22) 
-        gc->MAX_CHAN = 0;
+    if (gc->DMA_support == FALSE) {
+       printk("The EATA HBA at %#.4x does not support DMA.\n" 
+              "Please use the EATA-PIO driver.\n", base);
+       return (FALSE);
+    }
 
-    if (!reg_IRQ[gc->IRQ]) {   /* Interrupt already registered ? */
-        if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT, "eata_dma")){
-           reg_IRQ[gc->IRQ] += (gc->MAX_CHAN+1);
+    if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22) 
+       gc->MAX_CHAN = 0;
+    
+    if (reg_IRQ[gc->IRQ] == FALSE) {    /* Interrupt already registered ? */
+       if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT,
+                        "eata_dma")){
+           reg_IRQ[gc->IRQ]++;
            if (!gc->IRQ_TR)
-               reg_IRQL[gc->IRQ] = TRUE;       /* IRQ is edge triggered */
+               reg_IRQL[gc->IRQ] = TRUE;   /* IRQ is edge triggered */
        } else {
            printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
            return (FALSE);
        }
-    } else {                   /* More than one HBA on this IRQ */
+    } else {            /* More than one HBA on this IRQ */
        if (reg_IRQL[gc->IRQ] == TRUE) {
            printk("Can't support more than one HBA on this IRQ,\n"
                   "  if the IRQ is edge triggered. Sorry.\n");
            return (FALSE);
        } else
-           reg_IRQ[gc->IRQ] += (gc->MAX_CHAN+1);
+           reg_IRQ[gc->IRQ]++;
     }
-
+    
     /* if gc->DMA_valid it must be an ISA HBA and we have to register it */
     dma_channel = 0xff;
     if (gc->DMA_valid) {
-        if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) {
-            printk("Unable to allocate DMA channel %d for ISA HBA at %#.4lx.\n",
-                   dma_channel, base);
-            reg_IRQ[gc->IRQ] -= (gc->MAX_CHAN+1);
-            if (reg_IRQ[gc->IRQ] == 0)
-                free_irq(gc->IRQ);
-            if (!gc->IRQ_TR)
-                reg_IRQL[gc->IRQ] = FALSE; 
-            return (FALSE);
-        }
-    } 
-    
-    buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]);
+       if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) {
+           printk("Unable to allocate DMA channel %d for ISA HBA at %#.4x.\n",
+                  dma_channel, base);
+           reg_IRQ[gc->IRQ]--;
+           if (reg_IRQ[gc->IRQ] == 0)
+               free_irq(gc->IRQ);
+           if (gc->IRQ_TR == FALSE)
+               reg_IRQL[gc->IRQ] = FALSE; 
+           return (FALSE);
+       }
+    }
+    if (bustype != IS_EISA)
+       buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]);
 
     if (buff == NULL) {
-        if (gc->DMA_support == FALSE)
-            printk("HBA at %#.4lx doesn't support DMA. Sorry\n", base);
-        else
-            printk("HBA at %#.4lx didn't react on INQUIRY. Sorry.\n", base);
-        if (gc->DMA_valid) 
-            free_dma(dma_channel);
-        reg_IRQ[gc->IRQ] -= (gc->MAX_CHAN+1);
-        if (reg_IRQ[gc->IRQ] == 0)
-            free_irq(gc->IRQ);
-        if (!gc->IRQ_TR)
-            reg_IRQL[gc->IRQ] = FALSE; 
-        return (FALSE);
+       if (bustype == IS_EISA) {
+           bugs = bugs || BROKEN_INQUIRY;
+       } else {
+           if (gc->DMA_support == FALSE)
+               printk("HBA at %#.4x doesn't support DMA. Sorry\n", base);
+           else
+               printk("HBA at %#.4x does not react on INQUIRY. Sorry.\n", 
+                      base);
+           if (gc->DMA_valid) 
+               free_dma(dma_channel);
+           reg_IRQ[gc->IRQ]--;
+           if (reg_IRQ[gc->IRQ] == 0)
+               free_irq(gc->IRQ);
+           if (gc->IRQ_TR == FALSE)
+               reg_IRQL[gc->IRQ] = FALSE; 
+           return (FALSE);
+       }
     }
     
     if (gc->DMA_support == FALSE && buff != NULL)  
-        printk("HBA %.12sat %#.4lx doesn't set the DMA_support flag correctly.\n",
-               &buff[16], base);
+       printk("HBA %.12sat %#.4x doesn't set the DMA_support flag correctly.\n",
+              &buff[16], base);
     
     request_region(base, 9, "eata_dma"); /* We already checked the 
-                                          * availability, so this could 
-                                          * only fail if we're on 
-                                         * 0x1f0 or 0x170.
-                                          */
-
+                                         * availability, so this
+                                         * should not fail.
+                                         */
+    
     if(ntohs(gc->queuesiz) == 0) {
-        gc->queuesiz = ntohs(64);
-           printk("Warning: Queue size had to be corrected.\n"
-                  "This might be a PM2012 with a defective Firmware\n");
+       gc->queuesiz = ntohs(64);
+       printk("Warning: Queue size has to be corrected. Assuming 64 queueslots\n"
+              "         This might be a PM2012B with a defective Firmware\n");
     }
 
-    size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/
-                              (gc->MAX_CHAN + 1));
+    size = sizeof(hostdata) + ((sizeof(struct eata_ccb) + sizeof(long)) 
+                              * ntohs(gc->queuesiz));
 
-    if (gc->MAX_CHAN) {
-       printk("This is a multichannel HBA. Linux doesn't support them,\n");
-       printk("so we'll try to register every channel as a virtual HBA.\n");
+    DBG(DBG_REGISTER, printk("scsi_register size: %ld\n", size));
+    
+    sh = scsi_register(tpnt, size);
+    
+    if(sh == NULL) {
+       if (gc->DMA_valid) 
+           free_dma(dma_channel);
+       
+       reg_IRQ[gc->IRQ]--;
+       if (reg_IRQ[gc->IRQ] == 0)
+           free_irq(gc->IRQ);
+       if (gc->IRQ_TR == FALSE)
+           reg_IRQL[gc->IRQ] = FALSE; 
+       return (FALSE);
     }
     
-    for (i = 0; i <= gc->MAX_CHAN; i++) {
-
-       sh = scsi_register(tpnt, size);
-
-       if(sh == NULL) {
-           if (gc->DMA_valid) 
-               free_dma(dma_channel);
-           reg_IRQ[gc->IRQ] -= 1;
-           if (reg_IRQ[gc->IRQ] == 0)
-               free_irq(gc->IRQ);
-           if (!gc->IRQ_TR)
-               reg_IRQL[gc->IRQ] = FALSE; 
-           return (FALSE);
-       }
+    hd = SD(sh);                   
+    
+    memset(hd->ccb, 0, sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
+    memset(hd->reads, 0, sizeof(u32) * 26); 
 
-       hd = SD(sh);                   
+    hd->broken_INQUIRY = (bugs & BROKEN_INQUIRY);
 
-       memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)) / 
-              (gc->MAX_CHAN + 1));
-        memset(hd->reads, 0, sizeof(ulong) * 26); 
+    if(hd->broken_INQUIRY == TRUE) {
+       strcpy(SD(sh)->vendor, "DPT");
+       strcpy(SD(sh)->name, "??????????");
+       strcpy(SD(sh)->revision, "???.?");
+    } else {    
        strncpy(SD(sh)->vendor, &buff[8], 8);
        SD(sh)->vendor[8] = 0;
        strncpy(SD(sh)->name, &buff[16], 17);
@@ -857,130 +905,153 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
        SD(sh)->revision[3] = '.';
        SD(sh)->revision[4] = buff[35];
        SD(sh)->revision[5] = 0;
-       switch (ntohl(gc->len)) {
-       case 0x1c:
-           SD(sh)->EATA_revision = 'a';
-           break;
-       case 0x1e:
-           SD(sh)->EATA_revision = 'b';
-           break;
-       case 0x22:
-           SD(sh)->EATA_revision = 'c';
-           break;
-       default:
-           SD(sh)->EATA_revision = '?';
-       }
-       sh->base = (char *) base;
-       sh->io_port = (ushort) base;
-       sh->n_io_port = 9;
-       sh->irq = gc->IRQ;
-       sh->dma_channel = dma_channel;
-       sh->this_id = gc->scsi_id[3 - i];
-       sh->can_queue = ntohs(gc->queuesiz) / (gc->MAX_CHAN + 1);
-
-       if (gc->OCS_enabled == TRUE) {
-           sh->cmd_per_lun = sh->can_queue/C_P_L_DIV; 
-#if 0   /* The memory management seems to be more stable now */
-           if (sh->cmd_per_lun > C_P_L_CURRENT_MAX)
-               sh->cmd_per_lun = C_P_L_CURRENT_MAX;
-#endif
-       } else {
-           sh->cmd_per_lun = 1;
-       }
-       sh->sg_tablesize = ntohs(gc->SGsiz);
-       if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
-           sh->sg_tablesize = SG_SIZE;
-           if (ntohs(gc->SGsiz) == 0)
-               printk("Warning: SG size had to be corrected.\n"
-                      "This might be a PM2012 with a defective Firmware\n");
-       }
+    }
 
-       hd->channel = i;
+    switch (ntohl(gc->len)) {
+    case 0x1c:
+       SD(sh)->EATA_revision = 'a';
+       break;
+    case 0x1e:
+       SD(sh)->EATA_revision = 'b';
+       break;
+    case 0x22:
+       SD(sh)->EATA_revision = 'c';
+       break;
+    case 0x24:
+       SD(sh)->EATA_revision = 'z';            
+    default:
+       SD(sh)->EATA_revision = '?';
+    }
 
+    if(ntohl(gc->len) >= 0x22) {
+       if (gc->is_PCI == TRUE)
+           hd->bustype = IS_PCI;
+       else if (gc->is_EISA == TRUE)
+           hd->bustype = IS_EISA;
+       else
+           hd->bustype = IS_ISA;
+    } else if(hd->broken_INQUIRY == FALSE) {
        if (buff[21] == '4')
-           hd->bustype = 'P';
+           hd->bustype = IS_PCI;
        else if (buff[21] == '2')
-           hd->bustype = 'E';
+           hd->bustype = IS_EISA;
        else
-           hd->bustype = 'I';
+           hd->bustype = IS_ISA;
+    } else 
+       hd->bustype = bustype;
+    
+    if(ntohl(gc->len) >= 0x22) {
+       sh->max_id = gc->MAX_ID;
+       sh->max_lun = gc->MAX_LUN;
+    } else {
+       sh->max_id = 8;
+       sh->max_lun = 8;
+    }
 
-       if (gc->SECOND)
-           hd->primary = FALSE;
+    hd->channel = gc->MAX_CHAN;     
+    sh->max_channel = gc->MAX_CHAN; 
+    sh->base = (char *) base;
+    sh->io_port = (u16) base;
+    sh->n_io_port = 9;
+    sh->irq = gc->IRQ;
+    sh->dma_channel = dma_channel;
+    
+    /* FIXME:
+     * SCSI midlevel code should support different HBA ids on every channel
+     */
+    sh->this_id = gc->scsi_id[3];
+    sh->can_queue = ntohs(gc->queuesiz);
+    
+    if (gc->OCS_enabled == TRUE) 
+       if(hd->bustype != IS_ISA)
+           sh->cmd_per_lun = sh->can_queue/C_P_L_DIV; 
        else
-           hd->primary = TRUE;
-
-       if (hd->bustype != 'I') {
-           sh->unchecked_isa_dma = FALSE;
-           sh->wish_block = FALSE;        
-       }
-       else {
-           sh->unchecked_isa_dma = TRUE;   /* We're doing ISA DMA */
-           sh->wish_block = TRUE;          /* This will reduce performance */
-       }
-       if((hd->primary == TRUE) && (i == 0) && HARDCODED){                  
-         geometry.drv[0].heads = HEADS0;          
-         geometry.drv[0].sectors = SECTORS0;      
-         geometry.drv[0].cylinder = CYLINDER0;
-         geometry.drv[0].id = ID0;
-         geometry.drv[0].trans = TRUE;
-         geometry.drv[1].heads = HEADS1;
-         geometry.drv[1].sectors = SECTORS1;
-         geometry.drv[1].cylinder = CYLINDER1;
-         geometry.drv[1].id = ID1;
-         geometry.drv[1].trans = TRUE;
-       } else {
-         geometry.drv[0].id=-1;
-         geometry.drv[1].id=-1;
+           sh->cmd_per_lun = 8;
+    else 
+       sh->cmd_per_lun = 1;
+    
+    /* FIXME:
+     * SG should be allocated more dynamically 
+     */
+    /*
+     * If we are using a ISA board, we can't use extended SG,
+     * because we would need exessive amounts of memory for
+     * bounce buffers.
+     */
+    if (gc->SG_64K == TRUE && ntohs(gc->SGsiz) == 64 && hd->bustype != IS_ISA){
+       sh->sg_tablesize = SG_SIZE_BIG;
+       sh->use_clustering = FALSE;
+    } else {
+       sh->sg_tablesize = ntohs(gc->SGsiz);
+       sh->use_clustering = TRUE;
+       if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
+           sh->sg_tablesize = SG_SIZE;
+           if (ntohs(gc->SGsiz) == 0)
+               printk("Warning: SG size had to be corrected.\n"
+                      "This might be a PM2012 with a defective Firmware\n");
        }
-
-       hd->next = NULL;        /* build a linked list of all HBAs */
-       hd->prev = last_HBA;
-       if(hd->prev != NULL)
-           SD(hd->prev)->next = sh;
-       last_HBA = sh;
-       if (first_HBA == NULL)
-           first_HBA = sh;
-       registered_HBAs++;
     }
-    return (1);
+    
+    if (gc->SECOND)
+       hd->primary = FALSE;
+    else
+       hd->primary = TRUE;
+    
+    sh->wish_block = FALSE;        
+    
+    if (hd->bustype != IS_ISA) {
+       sh->unchecked_isa_dma = FALSE;
+    } else {
+       sh->unchecked_isa_dma = TRUE;   /* We're doing ISA DMA */
+    }
+    
+    hd->next = NULL;    /* build a linked list of all HBAs */
+    hd->prev = last_HBA;
+    if(hd->prev != NULL)
+       SD(hd->prev)->next = sh;
+    last_HBA = sh;
+    if (first_HBA == NULL)
+       first_HBA = sh;
+    registered_HBAs++;
+    
+    return (TRUE);
 }
 
 
-long find_EISA(struct get_conf *buf)
+void find_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
 {
-    struct eata_register *base;
+    u32 base;
     int i;
-
+    
 #if CHECKPAL
-    unsigned char pal1, pal2, pal3, *p;
+    u8 pal1, pal2, pal3;
 #endif
-
+    
     for (i = 0; i < MAXEISA; i++) {
-       if (EISAbases[i] == TRUE) {     /* Still a possibility ?          */
-
-           base = (void *)0x1c88 + (i * 0x1000);
+       if (EISAbases[i] == TRUE) { /* Still a possibility ?          */
+           
+           base = 0x1c88 + (i * 0x1000);
 #if CHECKPAL
-           p = (char *)base;
-           pal1 = *(p - 8);
-           pal2 = *(p - 7);
-           pal3 = *(p - 6);
-
+           pal1 = inb((u16)base - 8);
+           pal2 = inb((u16)base - 7);
+           pal3 = inb((u16)base - 6);
+           
            if (((pal1 == 0x12) && (pal2 == 0x14)) ||
                ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) ||
                ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
                DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
-                       (int)pal1, (int)pal2, (int)pal3));
+                                     (int)pal1, (int)pal2, (int)pal3));
 #endif
                if (get_conf_PIO(base, buf) == TRUE) {
-                   DBG(DBG_PROBE&&DBG_EISA,print_config(buf));
-                   if (buf->IRQ) {          /* We'll check the 
-                                             * primary/secondary stuff
-                                             * later
-                                             */
-                       EISAbases[i] = 0;
-                       return ((ulong)base);
-                   } 
-                   printk("No valid IRQ. HBA removed from list\n");
+                   DBG(DBG_PROBE && DBG_EISA, print_config(buf));
+                   if (buf->IRQ) {  
+                       register_HBA(base, buf, tpnt, IS_EISA);
+                   } else
+                       printk("eata_dma: No valid IRQ. HBA removed from list\n");
+               } else {
+                   if (check_blink_state(base)) 
+                       printk("HBA is in BLINK state. Consult your HBAs "
+                              " Manual to correct this.\n");
                } 
                /* Nothing found here so we take it from the list */
                EISAbases[i] = 0;  
@@ -989,25 +1060,26 @@ long find_EISA(struct get_conf *buf)
 #endif
        }
     }
-    return (0l);               /* Nothing found  :-(             */
+    return
 }
 
-long find_ISA(struct get_conf *buf)
+void find_ISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
 {
-    int l;
-    long ret;
-
-    for (l = 0; l < MAXISA; l++) {     
-        if (ISAbases[l]) {     
-           if (get_conf_PIO((struct eata_register *)ISAbases[l],buf) == TRUE){
-               ret = ISAbases[l];
-               ISAbases[l] = 0;
-               return (ret);
-           } else
-               ISAbases[l] = 0;
-        }
+    int i;
+    
+    for (i = 0; i < MAXISA; i++) {  
+       if (ISAbases[i]) {  
+           if (get_conf_PIO(ISAbases[i],buf) == TRUE){
+               register_HBA(ISAbases[i], buf, tpnt, IS_ISA);
+           } else {
+               if (check_blink_state(ISAbases[i])) 
+                   printk("HBA is in BLINK state. Consult your HBAs "
+                          "Manual to correct this.\n");
+           }
+           ISAbases[i] = 0;
+       }
     }
-    return ((long)NULL);
+    return;
 }
 
 void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
@@ -1016,92 +1088,95 @@ void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
 #ifndef CONFIG_PCI
     printk("Kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
 #else
-
-    unchar pci_bus, pci_device_fn;
-    static short pci_index = 0;        /* Device index to PCI BIOS calls */
-    ulong base = 0;
-    ushort com_adr;
-    ushort rev_device;
-    uint error, i, x;
+    
+    u8 pci_bus, pci_device_fn;
+    static s16 pci_index = 0;   /* Device index to PCI BIOS calls */
+    u32 base = 0;
+    u16 com_adr;
+    u16 rev_device;
+    u32 error, i, x;
 
     if (pcibios_present()) {
        for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
-
            if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, 
                                    pci_index, &pci_bus, &pci_device_fn))
                break;
-           DBG(DBG_PROBE && DBG_PCI, printk("eata_dma: HBA at bus %d, device %d,"
-                               " function %d, index %d\n", (int)pci_bus, 
-                               (int)((pci_device_fn & 0xf8) >> 3),
-                               (int)(pci_device_fn & 7), pci_index));
-
+           DBG(DBG_PROBE && DBG_PCI, 
+               printk("eata_dma: HBA at bus %d, device %d,"
+                      " function %d, index %d\n", (s32)pci_bus, 
+                      (s32)((pci_device_fn & 0xf8) >> 3),
+                      (s32)(pci_device_fn & 7), pci_index));
+           
            if (!(error = pcibios_read_config_word(pci_bus, pci_device_fn, 
-                                                PCI_CLASS_DEVICE, &rev_device))) {
-               if (rev_device == PCI_CLASS_STORAGE_SCSI) {
+                                      PCI_CLASS_DEVICE, &rev_device))) {
+               if (rev_device == PCI_CLASS_STORAGE_SCSI) {
                    if (!(error = pcibios_read_config_word(pci_bus, 
-                                                          pci_device_fn, PCI_COMMAND, 
-                                                          (ushort *) & com_adr))) {
-                       if (!((com_adr & PCI_COMMAND_IO) && 
+                                              pci_device_fn, PCI_COMMAND, 
+                                              (u16 *) & com_adr))) {
+                       if (!((com_adr & PCI_COMMAND_IO) && 
                              (com_adr & PCI_COMMAND_MASTER))) {
                            printk("HBA has IO or BUSMASTER mode disabled\n");
                            continue;
                        }
                    } else
-                       printk("error %x while reading PCI_COMMAND\n", error);
-               } else
-                 printk("DEVICECLASSID %x didn't match\n", rev_device);
+                       printk("eata_dma: error %x while reading "
+                              "PCI_COMMAND\n", error);
+               } else
+                   printk("DEVICECLASSID %x didn't match\n", rev_device);
            } else {
-             printk("error %x while reading PCI_CLASS_BASE\n", error);
-             continue;
+               printk("eata_dma: error %x while reading PCI_CLASS_BASE\n", 
+                      error);
+               continue;
            }
-
+           
            if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                                 PCI_BASE_ADDRESS_0, &base))){
-
-               /* Check if the address is valid */
-               if (base & 0x01) {
+                                      PCI_BASE_ADDRESS_0, (int *) &base))){
+               
+               /* Check if the address is valid */
+               if (base & 0x01) {
                    base &= 0xfffffffe;
-                                       /* EISA tag there ? */
+                   /* EISA tag there ? */
                    if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
-                       continue;       /* Jep, it's forced, so move on  */
-                   base += 0x10;       /* Now, THIS is the real address */
+                       continue;   /* Jep, it's forced, so move on  */
+                   base += 0x10;   /* Now, THIS is the real address */
                    if (base != 0x1f8) {
-                       /* We didn't find it in the primary search */
-                       if (get_conf_PIO((struct eata_register *)base, buf)) {
-                           if (buf->FORCADR)   /* If the address is forced */
-                               continue;       /* we'll find it later      */
-
+                       /* We didn't find it in the primary search */
+                       if (get_conf_PIO(base, buf) == TRUE) {
+                           if (buf->FORCADR)   /* If the address is forced */
+                               continue;       /* we'll find it later      */
+                           
                            /* OK. We made it till here, so we can go now  
                             * and register it. We  only have to check and 
                             * eventually remove it from the EISA and ISA list 
                             */
-
-                           register_HBA(base, buf, tpnt);
-
+                           
+                           register_HBA(base, buf, tpnt, IS_PCI);
+                           
                            if (base < 0x1000) {
-                               for (x = 0; x < MAXISA; ++x) {
+                               for (x = 0; x < MAXISA; ++x) {
                                    if (ISAbases[x] == base) {
-                                       ISAbases[x] = 0;
+                                       ISAbases[x] = 0;
                                        break;
                                    }
-                               }
+                               }
                            } else if ((base & 0x0fff) == 0x0c88) {
-                               x = (base >> 12) & 0x0f;
+                               x = (base >> 12) & 0x0f;
                                EISAbases[x] = 0;
                            }
-                           continue;  /*break;*/
-                       } else if (check_blink_state(base)) {
-                           printk("HBA is in BLINK state. Consult your HBAs "
-                                  " Manual to correct this.\n");
+                           continue;  /* break; */
+                       } else if (check_blink_state(base) == TRUE) {
+                           printk("eata_dma: HBA is in BLINK state.\n"
+                                  "Consult your HBAs Manual to correct this.\n");
                        }
                    }
                }
            } else
-             printk("error %x while reading PCI_BASE_ADDRESS_0\n", error);
+               printk("eata_dma: error %x while reading "
+                      "PCI_BASE_ADDRESS_0\n", error);
        }
     } else
-    printk("No BIOS32 extensions present. This release still depends on it."
-            " Sorry.\n");
+       printk("No BIOS32 extensions present. This eata_dma release "
+              "still depends on it.\nSkipping scan for PCI HBAs. Sorry.\n");
 #endif /* #ifndef CONFIG_PCI */
     return;
 }
@@ -1110,76 +1185,83 @@ int eata_detect(Scsi_Host_Template * tpnt)
 {
     struct Scsi_Host *HBA_ptr;
     struct get_conf gc;
-    ulong base = 0;
     int i;
-    geometry.drv[0].trans = geometry.drv[1].trans = 0;
-
-    DBG((DBG_PROBE && DBG_DELAY)|| DPT_DEBUG,
+    
+    DBG((DBG_PROBE && DBG_DELAY) || DPT_DEBUG,
        printk("Using lots of delays to let you read the debugging output\n"));
 
     status = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
     dma_scratch = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
 
     find_PCI(&gc, tpnt);
-
-    for (i = 0; i < MAXEISA; i++) {
-       base = find_EISA(&gc);
-       if (base)
-           register_HBA(base, &gc, tpnt);
-    }
-
-    for (i = 0; i <= MAXISA; i++) {
-       base = find_ISA(&gc);
-       if (base)
-           register_HBA(base, &gc, tpnt);
-    }
-
+    
+    find_EISA(&gc, tpnt);
+    
+    find_ISA(&gc, tpnt);
+    
     for (i = 0; i <= MAXIRQ; i++)
        if (reg_IRQ[i]){
            free_irq(i);
-           request_irq(i, eata_int_handler, SA_INTERRUPT, "EATA-DMA");
+           request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, "eata_dma");
        }
-
+    
     HBA_ptr = first_HBA;
-
+    
     if (registered_HBAs != 0) {
-        printk("EATA (Extended Attachment) driver version: %d.%d%s\n"
+       printk("EATA (Extended Attachment) driver version: %d.%d%s\n"
               "developed in co-operation with DPT\n"             
-              "(c) 1993-95 Michael Neuffer  neuffer@goofy.zdv.uni-mainz.de\n",
+              "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n",
               VER_MAJOR, VER_MINOR, VER_SUB);
-    printk("Registered HBAs:\n");
-    printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: ID: Pr: QS: SG: CPL:\n");
-    for (i = 1; i <= registered_HBAs; i++) {
-           printk("scsi%-2d: %.10s v%s 2.0%c  %s %#.4lx   %2d",
-              HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
-              SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')? 
-              "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
-                   (u32) HBA_ptr->base, HBA_ptr->irq);
-            if(HBA_ptr->dma_channel != 0xff)
-               printk("   %2x ", HBA_ptr->dma_channel);
-            else
-                printk("  %s", "BMST");
-            printk("  %d   %d   %c  %2d  %2d   %2d\n", SD(HBA_ptr)->channel, 
-                   HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N', 
-              HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
-        HBA_ptr = SD(HBA_ptr)->next;
+       printk("Registered HBAs:");
+       printk("\nHBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: "
+              "ID: Pr: QS: SG: CPL:\n");
+       for (i = 1; i <= registered_HBAs; i++) {
+           printk("scsi%-2d: %.10s v%s 2.0%c  %s %#.4x   %2d",
+                  HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
+                  SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')? 
+                  "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
+                  (u32) HBA_ptr->base, HBA_ptr->irq);
+           if(HBA_ptr->dma_channel != 0xff)
+               printk("   %2x ", HBA_ptr->dma_channel);
+           else
+               printk("  %s", "BMST");
+           printk("  %d   %d   %c  %2d  %2d   %2d\n", SD(HBA_ptr)->channel, 
+                  HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N', 
+                  HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+           HBA_ptr = SD(HBA_ptr)->next;
+       }
+    } else {
+       scsi_init_free((void *)status, 512);
     }
-    } else 
-        scsi_init_free((void *)status, 512);
-    
+
     scsi_init_free((void *)dma_scratch, 512);
 
-    DBG(DPT_DEBUG,DELAY(1200));
+    DBG(DPT_DEBUG, DELAY(1200));
 
-    return (registered_HBAs);
+    return(registered_HBAs);
 }
 
 #ifdef MODULE
 /* Eventually this will go into an include file, but this will be later */
 Scsi_Host_Template driver_template = EATA_DMA;
-
 #include "scsi_module.c"
 #endif
 
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
index 025dcc790d1d7dd35a0e06c5bc1abf93d572a814..c8758cb4d13a3fcd401bab51b882b682a1ee3c6b 100644 (file)
 * Header file for eata_dma.c Linux EATA-DMA SCSI driver *
 * (c) 1993,94,95 Michael Neuffer                        *
 *********************************************************
-* last change: 95/04/10                                 *
+* last change: 95/06/20                                 *
 ********************************************************/
 
 
 #ifndef _EATA_DMA_H
 #define _EATA_DMA_H
 
-#define VER_MAJOR 2
-#define VER_MINOR 3
-#define VER_SUB   "5r"
+#ifndef HOSTS_C
 
-/************************************************************************
- * Here you can configure your drives that are using a non-standard     *
- * geometry.                                                            *
- * To enable this set HARDCODED to 1                                    *
- * If you have only one drive that need reconfiguration, set ID1 to -1  *
- ************************************************************************/
-#define HARDCODED     0          /* Here are drives running in emu. mode   */
+#include "eata_generic.h"
+
+
+#define VER_MAJOR 2
+#define VER_MINOR 5
+#define VER_SUB   "6a"
 
-#define ID0           0          /* SCSI ID of "IDE" drive mapped to C:    
-                                  * If you're not sure check your config
-                                 * utility that came with your controller
-                                 */
-#define HEADS0       13          /* Number of emulated heads of this drive */  
-#define SECTORS0     38          /* Number of emulated sectors             */ 
-#define CYLINDER0   719          /* Number of emulated cylinders           */
-   
-#define ID1           1          /* SCSI ID of "IDE" drive mapped to D:    */
-#define HEADS1       16          /* Number of emulated heads of this drive */ 
-#define SECTORS1     62          /* Number of emulated sectors             */
-#define CYLINDER1  1024          /* Number of emulated cylinders           */
 
 /************************************************************************
  * Here you can switch parts of the code on and of                      *
  ************************************************************************/
 
 #define CHECKPAL        0        /* EISA pal checking on/off            */
-#define EATA_DMA_PROC   0        /* proc-fs support                     */
 
 /************************************************************************
  * Debug options.                                                       * 
  * Enable DEBUG and whichever options you require.                      *
  ************************************************************************/
-#define DEBUG_EATA     1       /* Enable debug code.                   */
+#define DEBUG_EATA      1       /* Enable debug code.                   */
 #define DPT_DEBUG       0       /* Bobs special                         */
-#define DBG_DELAY       0      /* Build in delays so debug messages can be
+#define DBG_DELAY       0       /* Build in delays so debug messages can be
                                 * be read before they vanish of the top of
-                                * the screen!
-                                */
-#define DBG_PROBE      0       /* Debug probe routines.                */
+                                * the screen!                          */
+#define DBG_PROBE       0       /* Debug probe routines.                */
 #define DBG_PCI         0       /* Trace PCI routines                   */
 #define DBG_EISA        0       /* Trace EISA routines                  */
 #define DBG_ISA         0       /* Trace ISA routines                   */ 
 #define DBG_BLINK       0       /* Trace Blink check                    */
 #define DBG_PIO         0       /* Trace get_config_PIO                 */
-#define DBG_COM        0       /* Trace command call                   */
-#define DBG_QUEUE      0       /* Trace command queueing.              */
-#define DBG_INTR       0       /* Trace interrupt service routine.     */
-#define DBG_INTR2      0       /* Trace interrupt service routine.     */
-#define DBG_INTR3       0       /* Trace interrupt service routine.     */
+#define DBG_COM         0       /* Trace command call                   */
+#define DBG_QUEUE       0       /* Trace command queueing.              */
+#define DBG_QUEUE2      0       /* Trace command queueing SG.           */
+#define DBG_INTR        0       /* Trace interrupt service routine.     */
+#define DBG_INTR2       0       /* Trace interrupt service routine.     */
+#define DBG_INTR3       0       /* Trace get_board_data interrupts.     */
 #define DBG_PROC        0       /* Debug proc-fs related statistics     */
+#define DBG_PROC_WRITE  0
 #define DBG_REGISTER    0       /* */
-#define DBG_ABNORM     1       /* Debug abnormal actions (reset, abort)*/
+#define DBG_ABNORM      1       /* Debug abnormal actions (reset, abort)*/
 
 #if DEBUG_EATA 
-#define DBG(x, y)      if ((x)) {y;} 
+#define DBG(x, y)   if ((x)) {y;} 
 #else
 #define DBG(x, y)
 #endif
 
-
-#define EATA_DMA {                   \
-       NULL, NULL,                  \
-        "EATA (Extended Attachment) driver", \
-        eata_detect,                 \
-        eata_release,                \
-        eata_info,                   \
-        eata_command,                \
-        eata_queue,                  \
-        eata_abort,                  \
-        eata_reset,                  \
-        NULL, /* Slave attach */     \
-       scsicam_bios_param,          \
-        0,      /* Canqueue     */   \
-        0,      /* this_id      */   \
-        0,      /* sg_tablesize */   \
-        0,      /* cmd_per_lun  */   \
-        0,      /* present      */   \
-        1,      /* True if ISA  */   \
-       ENABLE_CLUSTERING }
+#endif /* !HOSTS_C */
 
 int eata_detect(Scsi_Host_Template *);
 const char *eata_info(struct Scsi_Host *);
 int eata_command(Scsi_Cmnd *);
-int eata_queue(Scsi_Cmnd *, void *(done)(Scsi_Cmnd *));
+int eata_queue(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 int eata_abort(Scsi_Cmnd *);
 int eata_reset(Scsi_Cmnd *);
+int eata_proc_info(char *, char **, off_t, int, int, int);
+#ifdef MODULE
 int eata_release(struct Scsi_Host *);
-
-/*********************************************
- * Misc. definitions                         *
- *********************************************/
-
-#ifndef TRUE
-# define TRUE 1
-#endif
-#ifndef FALSE
-# define FALSE 0
+#else
+#define eata_release NULL  
 #endif
 
-#define R_LIMIT 0x20000
-
-#define MAXISA     4
-#define MAXEISA   16  
-#define MAXPCI    16
-#define MAXIRQ    16 
-#define MAXTARGET  8
-
-#define MAX_PCI_DEVICES   32             /* Maximum # Of Devices Per Bus   */
-#define MAX_METHOD_2      16             /* Max Devices For Method 2       */
-#define MAX_PCI_BUS       16             /* Maximum # Of Busses Allowed    */
-
-#define SG_SIZE           64 
-
-#define C_P_L_CURRENT_MAX 16  /* Until this limit in the mm is removed    
-                              * Kernels < 1.1.86 died horrible deaths
-                              * if you used values >2. The memory management
-                              * since pl1.1.86 seems to cope with up to 10
-                              * queued commands per device. 
-                               * Since 1.2.0 the memory management seems to 
-                               * have no more problems......
-                              */
-#define C_P_L_DIV          3  /* 1 <= C_P_L_DIV <= 8            
-                              * You can use this parameter to fine-tune
-                              * the driver. Depending on the number of 
-                              * devices and their speed and ability to queue 
-                              * commands, you will get the best results with a
-                              * value
-                              * ~= numdevices-(devices_unable_to_queue_commands/2)
-                              * The reason for this is that the disk driver 
-                              * tends to flood the queue, so that other 
-                              * drivers have problems to queue commands 
-                              * themselves. This can for example result in 
-                              * the effect that the tape stops during disk 
-                              * accesses. 
-                              */
-
-#define FREE       0
-#define USED       1
-#define TIMEOUT    2
-#define RESET      4
-#define LOCKED     8
-
-#define HD(cmd)  ((hostdata *)&(cmd->host->hostdata))
-#define CD(cmd)  ((struct eata_ccb *)(cmd->host_scribble))
-#define SD(host) ((hostdata *)&(host->hostdata))
-
-#define DELAY(x) { int i; i = jiffies + x; while (jiffies < i); }
-#define DEL2(x)  { ulong i; for (i = 0; i < 0xffff*x; i++); }
-
-/***********************************************
- *    EATA Command & Register definitions      *
- ***********************************************/
-#define PCI_REG_DPTconfig        0x40    
-#define PCI_REG_PumpModeAddress  0x44    
-#define PCI_REG_PumpModeData     0x48    
-#define PCI_REG_ConfigParam1     0x50    
-#define PCI_REG_ConfigParam2     0x54    
-
-
-#define EATA_CMD_PIO_READ_CONFIG 0xf0
-#define EATA_CMD_PIO_SET_CONFIG  0xf1
-#define EATA_CMD_PIO_SEND_CP     0xf2
-#define EATA_CMD_PIO_RECEIVE_SP  0xf3
-#define EATA_CMD_PIO_TRUNC       0xf4
-
-#define EATA_CMD_RESET           0xf9
-
-#define EATA_CMD_DMA_READ_CONFIG 0xfd
-#define EATA_CMD_DMA_SET_CONFIG  0xfe
-#define EATA_CMD_DMA_SEND_CP     0xff
-
-#define ECS_EMULATE_SENSE        0xd4
-
-#define HA_WCOMMAND 0x07        /* command register offset   */
-#define HA_WDMAADDR 0x02        /* DMA address LSB offset    */  
-#define HA_RAUXSTAT 0x08        /* aux status register offset*/
-#define HA_RSTATUS  0x07        /* status register offset    */
-#define HA_RDATA    0x00        /* data register (16bit)     */
-
-#define HA_ABUSY    0x01        /* aux busy bit              */
-#define HA_AIRQ     0x02        /* aux IRQ pending bit       */
-#define HA_SERROR   0x01        /* pr. command ended in error*/
-#define HA_SMORE    0x02        /* more data soon to come    */
-#define HA_SCORR    0x04        /* data corrected            */
-#define HA_SDRQ     0x08        /* data request active       */
-#define HA_SSC      0x10        /* seek complete             */
-#define HA_SFAULT   0x20        /* write fault               */
-#define HA_SREADY   0x40        /* drive ready               */
-#define HA_SBUSY    0x80        /* drive busy                */
-#define HA_SDRDY    HA_SSC+HA_SREADY+HA_SDRQ 
-
-#define HA_NO_ERROR      0x00
-#define HA_ERR_SEL_TO    0x01
-#define HA_ERR_CMD_TO    0x02
-#define HA_ERR_RESET     0x03
-#define HA_INIT_POWERUP  0x04
-#define HA_UNX_BUSPHASE  0x05
-#define HA_UNX_BUS_FREE  0x06
-#define HA_BUS_PARITY    0x07
-#define HA_SCSI_HUNG     0x08
-#define HA_UNX_MSGRJCT   0x09
-#define HA_RESET_STUCK   0x0a
-#define HA_RSENSE_FAIL   0x0b
-#define HA_PARITY_ERR    0x0c
-#define HA_CP_ABORT_NA   0x0d
-#define HA_CP_ABORTED    0x0e
-#define HA_CP_RESET_NA   0x0f
-#define HA_CP_RESET      0x10
-
-/**********************************************
- * Message definitions                        *
- **********************************************/
-
-struct reg_bit {        /* reading this one will clear the interrupt   */
-  unchar error:1;     /* previous command ended in an error           */
-  unchar more:1;      /* more DATA coming soon, poll BSY & DRQ (PIO) */
-  unchar corr:1;      /* data read was successfully corrected with ECC*/
-  unchar drq:1;       /* data request active  */     
-  unchar sc:1;        /* seek complete        */
-  unchar fault:1;     /* write fault          */
-  unchar ready:1;     /* drive ready          */
-  unchar busy:1;      /* controller busy      */
-};
-
-struct reg_abit {       /* reading this won't clear the interrupt */
-  unchar abusy:1;     /* auxiliary busy                         */
-  unchar irq:1;       /* set when drive interrupt is asserted   */
-  unchar dummy:6;
-};
-
-struct eata_register {             /* EATA register set */
-  unchar data_reg[2];          /* R, couldn't figure this one out          */
-  unchar cp_addr[4];           /* W, CP address register                   */
-  union { 
-    unchar command;            /* W, command code: [read|set] conf, send CP*/
-    struct reg_bit status;     /* R, see register_bit1                     */
-    unchar statusunchar;
-  } ovr;   
-  struct reg_abit aux_stat;    /* R, see register_bit2                     */
-};
-
-/**********************************************
- *  Other  definitions                        *
- **********************************************/
-
-struct eata_sg_list
-{
-  ulong data;
-  ulong len;
-};
-
-struct get_conf {          /* Read Configuration Array  */
-  ulong  len;                 /* Should return 0x22                    */
-  unchar sig[4];              /* Signature MUST be "EATA"              */
-  unchar    version2:4,
-             version:4;       /* EATA Version level                    */
-  unchar OCS_enabled:1,              /* Overlap Command Support enabled        */
-         TAR_support:1,              /* SCSI Target Mode supported             */
-              TRNXFR:1,              /* Truncate Transfer Cmd not necessary    */
-                              /* Only used in PIO Mode                         */
-        MORE_support:1,              /* MORE supported (only PIO Mode)         */
-         DMA_support:1,              /* DMA supported Driver uses only         */
-                              /* this mode                             */
-           DMA_valid:1,       /* DRQ value in Byte 30 is valid         */
-                 ATA:1,       /* ATA device connected (not supported)  */
-           HAA_valid:1;       /* Hostadapter Address is valid          */
-
-  ushort cppadlen;           /* Number of pad unchars send after CD data */
-                              /* set to zero for DMA commands          */
-  unchar scsi_id[4];          /* SCSI ID of controller 2-0 Byte 0 res.  */
-                              /* if not, zero is returned              */
-  ulong  cplen;                      /* CP length: number of valid cp unchars  */
-  ulong  splen;                      /* Number of unchars returned after       */ 
-                              /* Receive SP command                    */
-  ushort queuesiz;           /* max number of queueable CPs            */
-  ushort dummy;
-  ushort SGsiz;                      /* max number of SG table entries         */
-  unchar    IRQ:4,            /* IRQ used this HA                      */
-         IRQ_TR:1,            /* IRQ Trigger: 0=edge, 1=level          */
-         SECOND:1,            /* This is a secondary controller                */  
-    DMA_channel:2;            /* DRQ index, DRQ is 2comp of DRQX       */
-  unchar sync;                /* device at ID 7 tru 0 is running in    */
-                              /* synchronous mode, this will disappear  */
-  unchar   DSBLE:1,           /* ISA i/o addressing is disabled         */
-         FORCADR:1,           /* i/o address has been forced            */
-                :6;
-  unchar  MAX_ID:5,           /* Max number of SCSI target IDs          */
-        MAX_CHAN:3;           /* Number of SCSI busses on HBA           */
-  unchar MAX_LUN;             /* Max number of LUNs                     */
-  unchar        :5,          
-         ID_qest:1,           /* Raidnum ID is questionable             */
-          is_PCI:1,           /* HBA is PCI                             */
-         is_EISA:1;           /* HBA is EISA                            */
-  unchar unused[478]; 
-};
-
-struct eata_ccb {             /* Send Command Packet structure      */
-  unchar SCSI_Reset:1,        /* Cause a SCSI Bus reset on the cmd  */
-           HBA_Init:1,        /* Cause Controller to reinitialize   */
-       Auto_Req_Sen:1,        /* Do Auto Request Sense on errors    */
-            scatter:1,        /* Data Ptr points to a SG Packet     */
-             Resrvd:1,        /* RFU                                */
-          Interpret:1,        /* Interpret the SCSI cdb of own use  */
-            DataOut:1,        /* Data Out phase with command        */
-             DataIn:1;        /* Data In phase with command         */
-  unchar reqlen;             /* Request Sense Length               */ 
-                              /* Valid if Auto_Req_Sen=1            */
-  unchar unused[3];
-  unchar  FWNEST:1,           /* send cmd to phys RAID component*/
-         unused2:7;
-  unchar Phsunit:1,           /* physical unit on mirrored pair        */
-            I_AT:1,           /* inhibit address translation    */
-         I_HBA_C:1,           /* HBA Inhibit caching            */
-         unused3:5;
-
-  unchar cp_id;               /* SCSI Device ID of target       */ 
-  unchar    cp_lun:3,
-                  :2,
-         cp_luntar:1,         /* CP is for target ROUTINE       */
-         cp_dispri:1,         /* Grant disconnect privilege     */
-       cp_identify:1;         /* Always TRUE                    */         
-  unchar cp_msg1;             /* Message bytes 0-3              */
-  unchar cp_msg2;
-  unchar cp_msg3;
-  unchar cp_cdb[12];                 /* Command Descriptor Block       */
-  ulong  cp_datalen;         /* Data Transfer Length           */
-                              /* If scatter=1 len of sg package */
-  void *cp_viraddr;           /* address of this ccb            */
-  ulong cp_dataDMA;          /* Data Address, if scatter=1     */
-                              /* address of scatter packet      */  
-  ulong cp_statDMA;           /* address for Status Packet      */ 
-  ulong cp_reqDMA;            /* Request Sense Address, used if */
-                              /* CP command ends with error     */
-  ulong timeout;
-  unchar retries;
-  unchar status;              /* status of this queueslot       */
-  struct eata_sg_list sg_list[SG_SIZE];
-  Scsi_Cmnd *cmd;             /* address of cmd                 */
-};
-
-
-struct eata_sp {
-  unchar hba_stat:7,          /* HBA status                     */
-              EOC:1;          /* True if command finished       */
-  unchar scsi_stat;           /* Target SCSI status             */       
-  unchar reserved[2];
-  ulong  residue_len;         /* Number of unchars not transferred */
-  struct eata_ccb *ccb;       /* Address set in COMMAND PACKET  */
-  unchar msg[12];
-};
-
-typedef struct hstd {
-  char   vendor[9];
-  char   name[18];
-  char   revision[6];
-  char   EATA_revision;
-  unchar bustype;              /* bustype of HBA             */
-  unchar channel;              /* no. of scsi channel        */
-  unchar state;                /* state of HBA               */
-  unchar primary;              /* true if primary            */
-  ulong  reads[13];
-  ulong  writes[13];
-  unchar t_state[MAXTARGET];   /* state of Target (RESET,..) */
-  uint   t_timeout[MAXTARGET]; /* timeouts on target         */
-  uint   last_ccb;             /* Last used ccb              */
-  struct Scsi_Host *next;         
-  struct Scsi_Host *prev;
-  struct eata_sp sp;           /* status packet              */ 
-  struct eata_ccb ccb[0];      /* ccb array begins here      */
-}hostdata;
-
-
-
-/* structure for max. 2 emulated drives */
-struct drive_geom_emul {
-  unchar trans;                 /* translation flag 1=transl */
-  unchar channel;               /* SCSI channel number       */
-  unchar HBA;                   /* HBA number (prim/sec)     */
-  unchar id;                    /* drive id                  */
-  unchar lun;                   /* drive lun                 */
-  uint   heads;                 /* number of heads           */
-  uint   sectors;               /* number of sectors         */
-  uint   cylinder;              /* number of cylinders       */
-};
+#define EATA_DMA {                   \
+       NULL, NULL,                  \
+       eata_proc_info,/* procinfo */        \
+       "eata_dma",    /* proc dir entry */  \
+       PROC_SCSI_EATA,/* proc dir inode */  \
+       "EATA (Extended Attachment) driver", \
+       eata_detect,                 \
+       eata_release,                \
+       NULL, NULL,                  \
+       eata_queue,                  \
+       eata_abort,                  \
+       eata_reset,                  \
+       NULL,   /* Slave attach */   \
+       scsicam_bios_param,          \
+       0,      /* Canqueue     */   \
+       0,      /* this_id      */   \
+       0,      /* sg_tablesize */   \
+       0,      /* cmd_per_lun  */   \
+       0,      /* present      */   \
+       1,      /* True if ISA  */   \
+       ENABLE_CLUSTERING }
 
-struct geom_emul {
-  int bios_drives;               /* number of emulated drives */
-  struct drive_geom_emul drv[2]; /* drive structures          */
-};
 
-#endif /* _EATA_H */
+#endif /* _EATA_DMA_H */
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c
new file mode 100644 (file)
index 0000000..3a5d8f5
--- /dev/null
@@ -0,0 +1,409 @@
+
+#define MAX_SCSI_DEVICE_CODE 10
+const char *const scsi_dev_types[MAX_SCSI_DEVICE_CODE] =
+{
+    "Direct-Access    ",
+    "Sequential-Access",
+    "Printer          ",
+    "Processor        ",
+    "WORM             ",
+    "CD-ROM           ",
+    "Scanner          ",
+    "Optical Device   ",
+    "Medium Changer   ",
+    "Communications   "
+};
+
+
+void swap_statistics(u8 *p)
+{
+    u32 y;
+    u32 *lp, h_lp;
+    u16 *sp, h_sp;
+    u8 *bp;
+    
+    lp = (u32 *)p;
+    sp = ((short *)lp) + 1;         /* Convert Header */
+    h_sp = *sp = ntohs(*sp);
+    lp++;
+
+    do {
+       sp = (u16 *)lp;           /* Convert SubHeader */
+    *sp = ntohs(*sp);
+    bp = (u8 *) lp;
+    y = *(bp + 3);
+    lp++;
+    for (h_lp = (u32)lp; (u32)lp < h_lp + ((u32)*(bp + 3)); lp++)
+       *lp = ntohl(*lp);
+    }while ((u32)lp < ((u32)p) + 4 + h_sp);
+
+}
+
+/*
+ * eata_set_info
+ * buffer : pointer to the data that has been written to the hostfile
+ * length : number of bytes written to the hostfile
+ * HBA_ptr: pointer to the Scsi_Host struct
+ */
+int eata_set_info(char *buffer, int length, struct Scsi_Host *HBA_ptr)
+{
+    DBG(DBG_PROC_WRITE, printk("%s\n", buffer));
+    return(-ENOSYS);  /* Currently this is a no-op */
+}
+
+/*
+ * eata_proc_info
+ * inout : decides on the direction of the dataflow and the meaning of the variables
+ * buffer: If inout==FALSE data is beeing written to it else read from it
+ * *start: If inout==FALSE start of the valid data in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer else number of bytes in the buffer
+ */
+int eata_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+{
+
+    Scsi_Device *scd;
+    struct Scsi_Host *HBA_ptr;
+    Scsi_Cmnd scmd;
+    static u8 buff[512];
+    static u8 buff2[512];
+    hst_cmd_stat *rhcs, *whcs;
+    coco         *cc;
+    scsitrans    *st;
+    scsimod      *sm;
+    hobu         *hb;
+    scbu         *sb;
+    boty         *bt;
+    memco        *mc;
+    firm         *fm;
+    subinf       *si; 
+    pcinf        *pi;
+    arrlim       *al;
+    int i, x; 
+    int   size, len = 0;
+    off_t begin = 0;
+    off_t pos = 0;
+
+    HBA_ptr = first_HBA;
+    for (i = 1; i <= registered_HBAs; i++) {
+       if (HBA_ptr->host_no == hostno)
+           break;
+       HBA_ptr = SD(HBA_ptr)->next;
+    }        
+
+    if(inout == TRUE) /* Has data been writen to the file ? */ 
+       return(eata_set_info(buffer, length, HBA_ptr));
+
+    if (offset == 0)
+       memset(buff, 0, sizeof(buff));
+
+    cc = (coco *)     (buff + 0x148);
+    st = (scsitrans *)(buff + 0x164); 
+    sm = (scsimod *)  (buff + 0x16c);
+    hb = (hobu *)     (buff + 0x172);
+    sb = (scbu *)     (buff + 0x178);
+    bt = (boty *)     (buff + 0x17e);
+    mc = (memco *)    (buff + 0x186);
+    fm = (firm *)     (buff + 0x18e);
+    si = (subinf *)   (buff + 0x196); 
+    pi = (pcinf *)    (buff + 0x19c);
+    al = (arrlim *)   (buff + 0x1a2);
+
+    size = sprintf(buffer+len, "EATA (Extended Attachment) driver version: "
+                  "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
+    len += size; pos = begin + len;
+    size = sprintf(buffer + len, "queued commands:     %10ld\n"
+                  "processed interrupts:%10ld\n", queue_counter, int_counter);
+    len += size; pos = begin + len;
+
+    if(SD(HBA_ptr)->bustype == IS_EISA)
+       goto devices;
+    
+    scmd.cmnd[0] = LOG_SENSE;
+    scmd.cmnd[1] = 0;
+    scmd.cmnd[2] = 0x33 + (3<<6);
+    scmd.cmnd[3] = 0;
+    scmd.cmnd[4] = 0;
+    scmd.cmnd[5] = 0;
+    scmd.cmnd[6] = 0;
+    scmd.cmnd[7] = 0x00;
+    scmd.cmnd[8] = 0x66;
+    scmd.cmnd[9] = 0;
+    scmd.cmd_len = 10;
+    
+    scmd.host = HBA_ptr; 
+    scmd.target = HBA_ptr->this_id; 
+    scmd.lun = 0; 
+    scmd.channel = 0;
+    
+    scmd.use_sg = 0;
+    scmd.request_bufflen = 0x66;
+    scmd.request_buffer = buff + 0x144;
+    HBA_interpret = TRUE;
+    
+    eata_queue(&scmd, (void *) eata_scsi_done);
+    while (internal_command_finished == FALSE)
+       barrier();
+    
+    size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
+                  HBA_ptr->host_no, SD(HBA_ptr)->name);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Firmware revision: v%s\n", 
+                  SD(HBA_ptr)->revision);
+    len += size;
+    pos = begin + len;
+    size = sprintf(buffer + len, "Hardware Configuration:\n");
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt,
+                  (cc->intt == TRUE)?"level":"edge");
+    len += size; 
+    pos = begin + len;
+    if (HBA_ptr->dma_channel == 0xff)
+       size = sprintf(buffer + len, "DMA: BUSMASTER\n");
+    else
+       size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "CPU: MC680%02d %dMHz\n", bt->cpu_type,
+                  bt->cpu_speed);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Host Bus: %s\n", 
+                  (SD(HBA_ptr)->bustype == IS_PCI)?"PCI ":
+                  (SD(HBA_ptr)->bustype == IS_EISA)?"EISA":"ISA ");
+    
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "SCSI Bus:%s%s Speed: %sMB/sec. %s\n",
+                  (sb->wide == TRUE)?" WIDE":"", 
+                  (sb->dif == TRUE)?" DIFFERENTIAL":"",
+                  (sb->speed == 0)?"5":(sb->speed == 1)?"10":"20",
+                  (sb->ext == TRUE)?"With external cable detection":"");
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "SCSI channel expansion Module: %s installed\n",
+                  (bt->sx1 == TRUE)?"SX1 (one channel)":
+                  ((bt->sx2 == TRUE)?"SX2 (two channels)":"not"));
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "SmartRAID hardware: %spresent.\n",
+                  (cc->srs == TRUE)?"":"not ");
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "    Type: %s\n",
+                  ((cc->key == TRUE)?((bt->dmi == TRUE)?"integrated"
+                                      :((bt->dm4 == TRUE)?"DM401X"
+                                      :(bt->dm4k == TRUE)?"DM4000"
+                                      :"-"))
+                                      :"-"));
+    len += size; 
+    pos = begin + len;
+    
+    size = sprintf(buffer + len, "    Max array groups:              %d\n",
+                  (al->code == 0x0e)?al->max_groups:7);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "    Max drives per RAID 0 array:   %d\n",
+                  (al->code == 0x0e)?al->raid0_drv:7);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "    Max drives per RAID 3/5 array: %d\n",
+                  (al->code == 0x0e)?al->raid35_drv:7);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Cache Module: %sinstalled.\n",
+                  (cc->csh)?"":"not ");
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "    Type: %s\n",
+                  ((cc->csh == TRUE)?((bt->cmi == TRUE)?"integrated"
+                                      :((bt->cm4 == TRUE)?"CM401X"
+                                      :((bt->cm4k == TRUE)?"CM4000"
+                                      :"-")))
+                                      :"-"));
+    len += size; 
+    pos = begin + len;
+    for (x = 0; x <= 3; x++) {
+       size = sprintf(buffer + len, "    Bank%d: %dMB with%s ECC\n",x,
+                      mc->banksize[x] & 0x7f, 
+                      (mc->banksize[x] & 0x80)?"":"out");
+       len += size; 
+       pos = begin + len;      
+    }   
+    size = sprintf(buffer + len, "Timer Modification: %sinstalled\n",
+                  (cc->tmr == TRUE)?"":"not ");
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "NVRAM: %spresent\n",
+                  (cc->nvr == TRUE)?"":"not ");
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "SmartROM: %senabled\n",
+                  (bt->srom == TRUE)?"not ":"");
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "HBA indicates %salarm.\n",
+                  (bt->alrm == TRUE)?"":"no ");
+    len += size; 
+    pos = begin + len;
+    
+    if (pos < offset) {
+       len = 0;
+       begin = pos;
+    }
+    if (pos > offset + length)
+       goto stop_output; 
+    
+    scmd.cmnd[0] = LOG_SENSE;
+    scmd.cmnd[1] = 0;
+    scmd.cmnd[2] = 0x32 + (3<<6); 
+    scmd.cmnd[3] = 0;
+    scmd.cmnd[4] = 0;
+    scmd.cmnd[5] = 0;
+    scmd.cmnd[6] = 0;
+    scmd.cmnd[7] = 0x01;
+    scmd.cmnd[8] = 0x44;
+    scmd.cmnd[9] = 0;
+    scmd.cmd_len = 10;
+    scmd.host = HBA_ptr; 
+    scmd.target = HBA_ptr->this_id; 
+    scmd.lun = 0; 
+    scmd.channel = 0;
+    scmd.use_sg = 0;
+    scmd.request_bufflen = 0x144;
+    scmd.request_buffer = buff2;
+    HBA_interpret = TRUE;
+    
+    eata_queue(&scmd, (void *) eata_scsi_done);
+    while (internal_command_finished == FALSE)
+       barrier();
+    
+    swap_statistics(buff2);
+    rhcs = (hst_cmd_stat *)(buff2 + 0x2c); 
+    whcs = (hst_cmd_stat *)(buff2 + 0x8c);           
+    
+    for (x = 0; x <= 11; x++) {
+       SD(HBA_ptr)->reads[x] += rhcs->sizes[x];
+       SD(HBA_ptr)->writes[x] += whcs->sizes[x];
+       SD(HBA_ptr)->reads[12] += rhcs->sizes[x];
+       SD(HBA_ptr)->writes[12] += whcs->sizes[x];
+    }
+    size = sprintf(buffer + len, "Host Disk Command Statistics:\n"
+                  "         Reads:      Writes:\n");
+    len += size; 
+    pos = begin + len;
+    for (x = 0; x <= 10; x++) {
+       size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x,
+                      SD(HBA_ptr)->reads[x], 
+                      SD(HBA_ptr)->writes[x]);
+       len += size; 
+       pos = begin + len;
+    }
+    size = sprintf(buffer+len,">1024k:%12u %12u\n",
+                  SD(HBA_ptr)->reads[11], 
+                  SD(HBA_ptr)->writes[11]);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer+len,"Sum   :%12u %12u\n",
+                  SD(HBA_ptr)->reads[12], 
+                  SD(HBA_ptr)->writes[12]);
+    len += size; 
+    pos = begin + len;
+    
+    if (pos < offset) {
+       len = 0;
+       begin = pos;
+    }
+    if (pos > offset + length)
+       goto stop_output;
+
+ devices:    
+    scd = scsi_devices;
+    
+    size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+    len += size; 
+    pos = begin + len;
+    
+    while (scd) {
+       if (scd->host == HBA_ptr) {
+           
+           size = sprintf(buffer + len, "Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
+                          scd->channel, scd->id, scd->lun);
+           for (x = 0; x < 8; x++) {
+               if (scd->vendor[x] >= 0x20)
+                   size += sprintf(buffer + len + size, "%c", scd->vendor[x]);
+               else
+                   size += sprintf(buffer + len + size," ");
+           }
+           size += sprintf(buffer + len + size, " Model: ");
+           for (x = 0; x < 16; x++) {
+               if (scd->model[x] >= 0x20)
+                   size +=  sprintf(buffer + len + size, "%c", scd->model[x]);
+               else
+                   size += sprintf(buffer + len + size, " ");
+           }
+           size += sprintf(buffer + len + size, " Rev: ");
+           for (x = 0; x < 4; x++) {
+               if (scd->rev[x] >= 0x20)
+                   size += sprintf(buffer + len + size, "%c", scd->rev[x]);
+               else
+                   size += sprintf(buffer + len + size, " ");
+           }
+           size += sprintf(buffer + len + size, "\n");
+           
+           size += sprintf(buffer + len + size, "  Type:   %s ",
+                           scd->type < MAX_SCSI_DEVICE_CODE ? 
+                           scsi_dev_types[(int)scd->type] : "Unknown          " );
+           size += sprintf(buffer + len + size, "               ANSI"
+                           " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
+           if (scd->scsi_level == 2)
+               size += sprintf(buffer + len + size, " CCS\n");
+           else
+               size += sprintf(buffer + len + size, "\n");
+           len += size; 
+           pos = begin + len;
+           
+           if (pos < offset) {
+               len = 0;
+               begin = pos;
+           }
+           if (pos > offset + length)
+               goto stop_output;
+       }
+       scd = scd->next;
+    }
+    
+ stop_output:
+    DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
+    *start=buffer+(offset-begin);   /* Start of wanted data */
+    len-=(offset-begin);            /* Start slop */
+    if(len>length)
+       len = length;               /* Ending slop */
+    DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
+    
+    return (len);     
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/eata_dma_proc.h b/drivers/scsi/eata_dma_proc.h
new file mode 100644 (file)
index 0000000..1457d86
--- /dev/null
@@ -0,0 +1,260 @@
+
+struct lun_map {
+    __u8   id:5,
+        chan:3;
+    __u8 lun;
+};
+
+typedef struct emul_pp {
+    __u8 p_code:6,
+          null:1,
+        p_save:1;
+    __u8 p_length;
+    __u16 cylinder;
+    __u8 heads;
+    __u8 sectors;
+    __u8 null2;
+    __u8 s_lunmap:4,
+             ems:1;
+    __u16 drive_type;   /* In Little Endian ! */
+    struct lun_map lunmap[4];
+}emulpp;
+
+
+/* Log Sense pages */
+
+typedef struct log_sheader {
+    __u8 page_code,
+        reserved;
+    __u16 length;
+}logsh;
+
+
+/* Log Sense Statistics */
+
+typedef struct read_command_statistics {
+    __u16 code;        /* 0x01 */
+    __u8  flags;
+    __u8  length;      /* 0x24 */
+    __u32 h_commands,
+         uncached,
+         la_cmds,
+         la_blks,
+         la_hits,
+         missed,
+         hits,
+         seq_la_blks,
+         seq_la_hits;
+}r_cmd_stat;
+
+typedef struct write_command_statistics {
+    __u16 code;        /* 0x03 */
+    __u8  flags;
+    __u8  length;      /* 0x28 */
+    __u32 h_commands,
+         uncached,
+         thru,
+         bypass,
+         soft_err,
+         hits,
+         b_idle,
+         b_activ,
+         b_blks,
+         b_blks_clean;
+}w_cmd_stat;
+
+typedef struct host_command_statistics {
+    __u16 code;          /* 0x02, 0x04 */
+    __u8  flags;
+    __u8  length;        /* 0x30 */
+    __u32 sizes[12];
+}hst_cmd_stat;
+
+typedef struct physical_command_statistics {
+    __u16 code;          /* 0x06, 0x07 */ 
+    __u8  flags;
+    __u8  length;        /* 0x34 */
+    __u32 sizes[13]; 
+}phy_cmd_stat;
+
+typedef struct misc_device_statistics {
+    __u16 code;           /* 0x05 */
+    __u8  flags;
+    __u8  length;         /* 0x10 */
+    __u32 disconnect,
+         pass_thru,
+         sg_commands,
+         stripe_boundary_crosses;
+}msc_stats;
+/* Configuration Pages */
+
+typedef struct controller_configuration {
+    __u16 code;           /* 0x01 */
+    __u8  flags;
+    __u8  length;         /* 0x02 */
+    __u8  intt:1,
+          sec:1,
+          csh:1,
+          key:1,
+          tmr:1,
+          srs:1,
+          nvr:1;
+    __u8  interrupt;
+}coco;
+
+typedef struct controller_hardware_errors {
+    __u16 code;           /* 0x02 */
+    __u8  flags;
+    __u8  length;         /* 0x02 */
+    __u8  unused:1,
+            per:1;
+    __u8  interrupt;
+}coher;
+
+typedef struct memory_map {
+    __u16 code;           /* 0x03, 0x04 */
+    __u8  flags;
+    __u8  length;         /* 0x04 */
+    __u32 memory_map;
+}mema;
+
+typedef struct scsi_transfer {
+    __u16 code;           /* 0x05 */
+    __u8  flags;
+    __u8  length;         /* 0x04 */
+    __u8  offset,
+         period;
+    __u16 speed;
+}scsitrans;
+
+typedef struct scsi_modes {
+    __u16 code;           /* 0x06 */
+    __u8  flags;
+    __u8  length;         /* 0x02 */
+    __u8  que:1,
+        cdis:1,
+        wtru:1,
+        dasd:1,
+         ncr:1,
+        awre:1;
+    __u8  reserved;
+}scsimod;
+
+typedef struct host_bus {
+    __u16 code;           /* 0x07 */
+    __u8  flags;
+    __u8  length;         /* 0x02 */
+    __u8  speed:6,
+           pci:1,
+          eisa:1;
+    __u8  reserved;
+}hobu;
+
+typedef struct scsi_bus {
+    __u16 code;           /* 0x08 */
+    __u8  flags;
+    __u8  length;         /* 0x02 */
+    __u8  speed:4,
+           res:1,
+           ext:1,
+          wide:1,
+           dif:1;
+    __u8 busnum;
+}scbu;
+
+typedef struct board_type {
+    __u16 code;           /* 0x09 */
+    __u8  flags;
+    __u8  length;         /* 0x04 */
+    __u8  unused:1,
+            cmi:1,
+            dmi:1,
+           cm4k:1,
+            cm4:1,
+           dm4k:1,
+            dm4:1,
+            hba:1;
+    __u8  cpu_type,
+         cpu_speed;
+    __u8    sx1:1,
+           sx2:1,
+       unused2:4,
+          alrm:1,
+          srom:1;
+}boty;
+
+typedef struct memory_config {
+    __u16 code;           /* 0x0a */
+    __u8  flags;
+    __u8  length;         /* 0x04 */
+    __u8  banksize[4];
+}memco;
+
+typedef struct firmware_info {
+    __u16 code;           /* 0x0b */
+    __u8  flags;
+    __u8  length;         /* 0x04 */
+    __u8  dnld:1,
+        bs528:1,
+          fmt:1,
+        fw528:1;
+    __u8  unused1,
+         fw_type,
+         unused;
+}firm;
+
+typedef struct subsystem_info {
+    __u16 code;           /* 0x0c */
+    __u8  flags;
+    __u8  length;         /* 0x02 */
+    __u8  shlf:1,
+         swap:1,
+         noss:1;
+    __u8  reserved;
+}subinf;
+
+typedef struct per_channel_info {
+    __u16 code;           /* 0x0d */
+    __u8  flags;
+    __u8  length;         /* 0x02 */
+    __u8  channel;
+    __u8  shlf:1,
+         swap:1,
+         noss:1,
+          srs:1,
+          que:1,
+          ext:1,
+         wide:1,
+         diff:1;
+}pcinf;
+
+typedef struct array_limits {
+    __u16 code;           /* 0x0e */
+    __u8  flags;
+    __u8  length;         /* 0x04 */
+    __u8  max_groups,
+         raid0_drv,
+         raid35_drv,
+         unused;
+}arrlim;
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
+
diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h
new file mode 100644 (file)
index 0000000..ef7f571
--- /dev/null
@@ -0,0 +1,378 @@
+/********************************************************
+* Header file for eata_dma.c and eata_pio.c             *
+* Linux EATA SCSI drivers                               *
+* (c) 1993,94,95 Michael Neuffer                        *
+*********************************************************
+* last change: 95/06/20                                 *
+********************************************************/
+
+
+#ifndef _EATA_GENERIC_H
+#define _EATA_GENERIC_H
+
+
+
+/*********************************************
+ * Misc. definitions                         *
+ *********************************************/
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define min(a,b) ((a<b)?(a):(b))
+
+#define R_LIMIT 0x20000
+
+#define MAXISA     4
+#define MAXEISA   16  
+#define MAXPCI    16
+#define MAXIRQ    16 
+#define MAXTARGET 16
+#define MAXCHANNEL 3
+
+#define IS_ISA     'I'
+#define IS_EISA    'E'
+#define IS_PCI     'P'
+
+#define BROKEN_INQUIRY  1
+
+#define EATA_SIGNATURE  0x45415441     /* BIG ENDIAN coded "EATA" sig.   */
+#define EATA_CP_SIZE    44
+
+#define MAX_PCI_DEVICES 32             /* Maximum # Of Devices Per Bus   */
+#define MAX_METHOD_2    16             /* Max Devices For Method 2       */
+#define MAX_PCI_BUS     16             /* Maximum # Of Busses Allowed    */
+
+#define SG_SIZE         64 
+#define SG_SIZE_BIG     509            /* max. 509 */
+
+#define C_P_L_DIV       2 /* 1 <= C_P_L_DIV <= 8            
+                          * You can use this parameter to fine-tune
+                          * the driver. Depending on the number of 
+                          * devices and their speed and ability to queue 
+                          * commands, you will get the best results with a
+                          * value
+                          * ~= numdevices-(devices_unable_to_queue_commands/2)
+                          * The reason for this is that the disk driver 
+                          * tends to flood the queue, so that other 
+                          * drivers have problems to queue commands 
+                          * themselves. This can for example result in 
+                          * the effect that the tape stops during disk 
+                          * accesses. 
+                          */
+
+#define FREE       0
+#define OK         0
+#define NO_TIMEOUT 0
+#define USED       1
+#define TIMEOUT    2
+#define RESET      4
+#define LOCKED     8
+
+#define HD(cmd)  ((hostdata *)&(cmd->host->hostdata))
+#define CD(cmd)  ((struct eata_ccb *)(cmd->host_scribble))
+#define SD(host) ((hostdata *)&(host->hostdata))
+
+#define DELAY(x) { __u32 i; i = jiffies + x; while (jiffies < i); }
+#define DEL2(x)  { __u32 i; for (i = 0; i < 0xffff * x; i++); }
+
+/***********************************************
+ *    EATA Command & Register definitions      *
+ ***********************************************/
+#define PCI_REG_DPTconfig        0x40    
+#define PCI_REG_PumpModeAddress  0x44    
+#define PCI_REG_PumpModeData     0x48    
+#define PCI_REG_ConfigParam1     0x50    
+#define PCI_REG_ConfigParam2     0x54    
+
+
+#define EATA_CMD_PIO_SETUPTEST   0xc6
+#define EATA_CMD_PIO_READ_CONFIG 0xf0
+#define EATA_CMD_PIO_SET_CONFIG  0xf1
+#define EATA_CMD_PIO_SEND_CP     0xf2
+#define EATA_CMD_PIO_RECEIVE_SP  0xf3
+#define EATA_CMD_PIO_TRUNC       0xf4
+
+#define EATA_CMD_RESET           0xf9
+#define EATA_CMD_IMMEDIATE       0xfa
+
+#define EATA_CMD_DMA_READ_CONFIG 0xfd
+#define EATA_CMD_DMA_SET_CONFIG  0xfe
+#define EATA_CMD_DMA_SEND_CP     0xff
+
+#define ECS_EMULATE_SENSE        0xd4
+
+
+#define GENERIC_ABORT  0x00 
+#define SPECIFIC_RESET 0x01
+#define BUS_RESET      0x02
+#define SPECIFIC_ABORT 0x03
+#define QUIET_INTR     0x04
+#define COLD_BOOT_HBA  0x06        /* Only as a last resort     */
+#define FORCE_IO       0x07
+
+
+#define HA_WCOMMAND    0x07        /* command register offset   */
+#define HA_WCOMMAND2   0x06        /* immediate command offset  */
+#define HA_WSUBCODE    0x05 
+#define HA_WSUBLUN     0x04 
+#define HA_WDMAADDR    0x02        /* DMA address LSB offset    */  
+#define HA_RAUXSTAT    0x08        /* aux status register offset*/
+#define HA_RSTATUS     0x07        /* status register offset    */
+#define HA_RDATA       0x00        /* data register (16bit)     */
+
+#define HA_ABUSY       0x01        /* aux busy bit              */
+#define HA_AIRQ        0x02        /* aux IRQ pending bit       */
+#define HA_SERROR      0x01        /* pr. command ended in error*/
+#define HA_SMORE       0x02        /* more data soon to come    */
+#define HA_SCORR       0x04        /* data corrected            */
+#define HA_SDRQ        0x08        /* data request active       */
+#define HA_SSC         0x10        /* seek complete             */
+#define HA_SFAULT      0x20        /* write fault               */
+#define HA_SREADY      0x40        /* drive ready               */
+#define HA_SBUSY       0x80        /* drive busy                */
+#define HA_SDRDY       HA_SSC+HA_SREADY+HA_SDRQ 
+
+/**********************************************
+ * Message definitions                        *
+ **********************************************/
+
+#define HA_NO_ERROR      0x00   /* No Error                             */
+#define HA_ERR_SEL_TO    0x01   /* Selection Timeout                    */
+#define HA_ERR_CMD_TO    0x02   /* Command Timeout                      */
+#define HA_ERR_RESET     0x03   /* SCSI Bus Reset Received              */
+#define HA_INIT_POWERUP  0x04   /* Initial Controller Power-up          */
+#define HA_UNX_BUSPHASE  0x05   /* Unexpected Bus Phase                 */
+#define HA_UNX_BUS_FREE  0x06   /* Unexpected Bus Free                  */
+#define HA_BUS_PARITY    0x07   /* Bus Parity Error                     */
+#define HA_SCSI_HUNG     0x08   /* SCSI Hung                            */
+#define HA_UNX_MSGRJCT   0x09   /* Unexpected Message Rejected          */
+#define HA_RESET_STUCK   0x0a   /* SCSI Bus Reset Stuck                 */
+#define HA_RSENSE_FAIL   0x0b   /* Auto Request-Sense Failed            */
+#define HA_PARITY_ERR    0x0c   /* Controller Ram Parity Error          */
+#define HA_CP_ABORT_NA   0x0d   /* Abort Message sent to non-active cmd */
+#define HA_CP_ABORTED    0x0e   /* Abort Message sent to active cmd     */
+#define HA_CP_RESET_NA   0x0f   /* Reset Message sent to non-active cmd */
+#define HA_CP_RESET      0x10   /* Reset Message sent to active cmd     */
+#define HA_ECC_ERR       0x11   /* Controller Ram ECC Error             */
+#define HA_PCI_PARITY    0x12   /* PCI Parity Error                     */
+#define HA_PCI_MABORT    0x13   /* PCI Master Abort                     */
+#define HA_PCI_TABORT    0x14   /* PCI Target Abort                     */
+#define HA_PCI_STABORT   0x15   /* PCI Signaled Target Abort            */
+
+/**********************************************
+ *  Other  definitions                        *
+ **********************************************/
+
+struct reg_bit {      /* reading this one will clear the interrupt    */
+    __u8 error:1;     /* previous command ended in an error           */
+    __u8 more:1;      /* more DATA coming soon, poll BSY & DRQ (PIO)  */
+    __u8 corr:1;      /* data read was successfully corrected with ECC*/
+    __u8 drq:1;       /* data request active  */     
+    __u8 sc:1;        /* seek complete        */
+    __u8 fault:1;     /* write fault          */
+    __u8 ready:1;     /* drive ready          */
+    __u8 busy:1;      /* controller busy      */
+};
+
+struct reg_abit {     /* reading this won't clear the interrupt */
+    __u8 abusy:1;     /* auxiliary busy                         */
+    __u8 irq:1;       /* set when drive interrupt is asserted   */
+    __u8 dummy:6;
+};
+
+struct eata_register {      /* EATA register set */
+    __u8 data_reg[2];       /* R, couldn't figure this one out          */
+    __u8 cp_addr[4];        /* W, CP address register                   */
+    union { 
+       __u8 command;       /* W, command code: [read|set] conf, send CP*/
+       struct reg_bit status;  /* R, see register_bit1                 */
+       __u8 statusbyte;
+    } ovr;   
+    struct reg_abit aux_stat; /* R, see register_bit2                   */
+};
+
+struct get_conf {             /* Read Configuration Array               */
+    __u32  len;               /* Should return 0x22, 0x24, etc          */
+    __u32 signature;          /* Signature MUST be "EATA"               */
+    __u8    version2:4,
+            version:4;       /* EATA Version level                     */
+    __u8 OCS_enabled:1,       /* Overlap Command Support enabled        */
+        TAR_support:1,       /* SCSI Target Mode supported             */
+             TRNXFR:1,       /* Truncate Transfer Cmd not necessary    */
+                             /* Only used in PIO Mode                  */
+       MORE_support:1,       /* MORE supported (only PIO Mode)         */
+        DMA_support:1,       /* DMA supported Driver uses only         */
+                             /* this mode                              */
+          DMA_valid:1,       /* DRQ value in Byte 30 is valid          */
+                ATA:1,       /* ATA device connected (not supported)   */
+          HAA_valid:1;       /* Hostadapter Address is valid           */
+
+    __u16 cppadlen;           /* Number of pad bytes send after CD data */
+                             /* set to zero for DMA commands           */
+    __u8 scsi_id[4];          /* SCSI ID of controller 2-0 Byte 0 res.  */
+                             /* if not, zero is returned               */
+    __u32  cplen;             /* CP length: number of valid cp bytes    */
+    __u32  splen;             /* Number of bytes returned after         */ 
+                             /* Receive SP command                     */
+    __u16 queuesiz;           /* max number of queueable CPs            */
+    __u16 dummy;
+    __u16 SGsiz;              /* max number of SG table entries         */
+    __u8    IRQ:4,            /* IRQ used this HA                       */
+        IRQ_TR:1,            /* IRQ Trigger: 0=edge, 1=level           */
+        SECOND:1,            /* This is a secondary controller         */  
+    DMA_channel:2;            /* DRQ index, DRQ is 2comp of DRQX        */
+    __u8 sync;                /* device at ID 7 tru 0 is running in     */
+                             /* synchronous mode, this will disappear  */
+    __u8   DSBLE:1,           /* ISA i/o addressing is disabled         */
+        FORCADR:1,           /* i/o address has been forced            */
+         SG_64K:1,
+         SG_UAE:1,
+               :4;
+    __u8  MAX_ID:5,           /* Max number of SCSI target IDs          */
+       MAX_CHAN:3;           /* Number of SCSI busses on HBA           */
+    __u8 MAX_LUN;             /* Max number of LUNs                     */
+    __u8        :3,
+        AUTOTRM:1,
+        M1_inst:1,
+        ID_qest:1,           /* Raidnum ID is questionable             */
+         is_PCI:1,           /* HBA is PCI                             */
+        is_EISA:1;           /* HBA is EISA                            */
+    __u8 unused[478]; 
+};
+
+struct eata_sg_list
+{
+    __u32 data;
+    __u32 len;
+};
+
+struct eata_ccb {             /* Send Command Packet structure      */
+    __u8 SCSI_Reset:1,        /* Cause a SCSI Bus reset on the cmd  */
+          HBA_Init:1,        /* Cause Controller to reinitialize   */
+       Auto_Req_Sen:1,        /* Do Auto Request Sense on errors    */
+           scatter:1,        /* Data Ptr points to a SG Packet     */
+            Resrvd:1,        /* RFU                                */
+         Interpret:1,        /* Interpret the SCSI cdb of own use  */
+           DataOut:1,        /* Data Out phase with command        */
+            DataIn:1;        /* Data In phase with command         */
+    __u8 reqlen;              /* Request Sense Length               */ 
+                             /* Valid if Auto_Req_Sen=1            */
+    __u8 unused[3];
+    __u8  FWNEST:1,           /* send cmd to phys RAID component*/
+        unused2:7;
+    __u8 Phsunit:1,           /* physical unit on mirrored pair */
+           I_AT:1,           /* inhibit address translation    */
+        I_HBA_C:1,           /* HBA inhibit caching            */
+        unused3:5;
+
+    __u8     cp_id:5,         /* SCSI Device ID of target       */ 
+       cp_channel:3;         /* SCSI Channel # of HBA          */
+    __u8    cp_lun:3,
+                 :2,
+        cp_luntar:1,         /* CP is for target ROUTINE       */
+        cp_dispri:1,         /* Grant disconnect privilege     */
+       cp_identify:1;         /* Always TRUE                    */         
+    __u8 cp_msg1;             /* Message bytes 0-3              */
+    __u8 cp_msg2;
+    __u8 cp_msg3;
+    __u8 cp_cdb[12];          /* Command Descriptor Block       */
+    __u32 cp_datalen;         /* Data Transfer Length           */
+                             /* If scatter=1 len of sg package */
+    void *cp_viraddr;         /* address of this ccb            */
+    __u32 cp_dataDMA;         /* Data Address, if scatter=1     *
+                              * address of scatter packet      */  
+    __u32 cp_statDMA;         /* address for Status Packet      */ 
+    __u32 cp_reqDMA;          /* Request Sense Address, used if */
+                             /* CP command ends with error     */
+                             /* Additional CP info begins here */
+    __u32 timeout;
+    __u8 retries;
+    __u8 status;              /* status of this queueslot       */
+
+    Scsi_Cmnd *cmd;           /* address of cmd                 */
+    struct eata_sg_list *sg_list;
+};
+
+
+struct eata_sp {
+    __u8 hba_stat:7,          /* HBA status                     */
+             EOC:1;          /* True if command finished       */
+    __u8 scsi_stat;           /* Target SCSI status             */       
+    __u8 reserved[2];
+    __u32  residue_len;       /* Number of bytes not transferred */
+    struct eata_ccb *ccb;     /* Address set in COMMAND PACKET  */
+    __u8 msg[12];
+};
+
+typedef struct hstd {
+    __u8   vendor[9];
+    __u8   name[18];
+    __u8   revision[6];
+    __u8   EATA_revision;
+    __u8   bustype;              /* bustype of HBA             */
+    __u8   channel;              /* # of avail. scsi channels  */
+    __u8   state;                /* state of HBA               */
+    __u8   primary;              /* true if primary            */
+    __u8   broken_INQUIRY:1;     /* This is an EISA HBA with   *
+                                 * broken INQUIRY             */
+    __u32  reads[13];
+    __u32  writes[13];
+                                /* state of Target (RESET,..) */
+    __u8   t_state[MAXCHANNEL][MAXTARGET];   
+                                /* timeouts on target         */
+    __u32  t_timeout[MAXCHANNEL][MAXTARGET]; 
+    __u32  last_ccb;             /* Last used ccb              */
+    __u32  cplen;                /* size of CP in words        */
+    __u16  cppadlen;             /* pad length of cp in words  */
+    __u8   hostid;               /* SCSI ID of HBA             */
+    __u8   devflags;             /* bits set for detected devices */
+    __u8   moresupport;          /* HBA supports MORE flag     */
+    struct Scsi_Host *next;         
+    struct Scsi_Host *prev;
+    struct eata_sp sp;           /* status packet              */ 
+    struct eata_ccb ccb[0];      /* ccb array begins here      */
+}hostdata;
+
+/* structure for max. 2 emulated drives */
+struct drive_geom_emul {
+    __u8  trans;                 /* translation flag 1=transl */
+    __u8  channel;               /* SCSI channel number       */
+    __u8  HBA;                   /* HBA number (prim/sec)     */
+    __u8  id;                    /* drive id                  */
+    __u8  lun;                   /* drive lun                 */
+    __u32 heads;                 /* number of heads           */
+    __u32 sectors;               /* number of sectors         */
+    __u32 cylinder;              /* number of cylinders       */
+};
+
+struct geom_emul {
+    __u8 bios_drives;            /* number of emulated drives */
+    struct drive_geom_emul drv[2]; /* drive structures        */
+};
+
+#endif /* _EATA_GENERIC_H */
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
new file mode 100644 (file)
index 0000000..99f7bc6
--- /dev/null
@@ -0,0 +1,1051 @@
+/************************************************************
+ *                                                          *
+ *               Linux EATA SCSI PIO driver                 *
+ *                                                          *
+ *  based on the CAM document CAM/89-004 rev. 2.0c,         *
+ *  DPT's driver kit, some internal documents and source,   *
+ *  and several other Linux scsi drivers and kernel docs.   *
+ *                                                          *
+ *  The driver currently:                                   *
+ *      -supports all EATA-PIO boards                       *
+ *      -only supports DASD devices                         *
+ *                                                          *
+ *  (c)1993,94,95 Michael Neuffer, Alfred Arnold            *
+ *                neuffer@goofy.zdv.uni-mainz.de            *
+ *                a.arnold@kfa-juelich.de                   * 
+ *                                                          *
+ *  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 kernel; if not, write to *
+ *  the Free Software Foundation, Inc., 675 Mass Ave,       *
+ *  Cambridge, MA 02139, USA.                               *
+ *                                                          *
+ ************************************************************
+ *  last change: 95/06/20 OS: Linux 1.3.3 + pre1.3 SCSI pat.*
+ ************************************************************/
+
+/* Look in eata_pio.h for configuration information */
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/in.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#include "eata_pio.h"
+#include "eata_dma_proc.h"
+#include "scsi.h"
+#include "sd.h"
+
+static uint ISAbases[MAXISA] =
+{0x1F0, 0x170, 0x330, 0x230};
+static uint ISAirqs[MAXISA] =
+{14,12,15,11};
+static unchar EISAbases[] =
+{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+static uint registered_HBAs = 0;
+static struct Scsi_Host *last_HBA = NULL;
+static struct Scsi_Host *first_HBA = NULL;
+static unchar reg_IRQ[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static unchar reg_IRQL[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static uint internal_command_finished = TRUE;
+
+static ulong int_counter = 0;
+static ulong queue_counter = 0;
+
+void hprint(char *str)
+{
+    char *hptr =(char *) 0x000b0000;
+    char *hptr2=(char *) 0x000b00a0; 
+    char *hptr3=(char *) 0x000b0f00;
+    int z;
+    
+    memmove(hptr,hptr2,24*80*2);
+    for (z=0; z<strlen(str); z++)
+       hptr3[z*2]=str[z];
+    for (; z<80; z++)
+       hptr3[z*2]=' ';
+}
+
+void eata_pio_scsi_done (Scsi_Cmnd * SCpnt)
+{
+    return;
+}   
+
+#include "eata_pio_proc.c"
+#ifdef MODULE
+int eata_pio_release(struct Scsi_Host *sh)
+{
+    if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq);
+    else reg_IRQ[sh->irq]--;
+    if (SD(sh)->channel == 0) {
+       if (sh->io_port && sh->n_io_port)
+           release_region(sh->io_port, sh->n_io_port);
+    }
+    return(TRUE);
+}
+#endif
+
+void IncStat(Scsi_Pointer *SCp, uint Increment)
+{
+    SCp->ptr+=Increment; 
+    if ((SCp->this_residual-=Increment)==0)
+    {
+       if ((--SCp->buffers_residual)==0) SCp->Status=FALSE;
+       else
+       {
+           SCp->buffer++;
+           SCp->ptr=SCp->buffer->address;
+           SCp->this_residual=SCp->buffer->length;
+       }
+    }
+}
+
+void eata_pio_int_handler(int irq, struct pt_regs * regs)
+{
+    uint eata_stat = 0xfffff;
+    Scsi_Cmnd *cmd;
+    hostdata *hd;
+    struct eata_ccb *cp;
+    uint base;
+    ulong flags;
+    uint x,z;
+    struct Scsi_Host *sh;
+    ushort zwickel=0;
+    unchar stat,odd;
+    
+    save_flags(flags);
+    cli();
+    
+    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) {
+       if (sh->irq != irq)
+           continue;
+       if (inb((uint)sh->base + HA_RSTATUS) & HA_SBUSY)
+           continue;
+       
+       int_counter++;
+       
+       hd=SD(sh);
+       
+       cp = &hd->ccb[0];
+       cmd = cp->cmd;
+       base = (uint) cmd->host->base;
+       
+       do
+       {
+           stat=inb(base+HA_RSTATUS);
+           if (stat&HA_SDRQ)
+               if (cp->DataIn)
+               {
+                   z=256; odd=FALSE;
+                   while ((cmd->SCp.Status)&&((z>0)||(odd)))
+                   {
+                       if (odd) 
+                       { 
+                           *(cmd->SCp.ptr)=zwickel>>8; 
+                           IncStat(&cmd->SCp,1);
+                           odd=FALSE;
+                       }
+                       x=min(z,cmd->SCp.this_residual/2);
+                       insw(base+HA_RDATA,cmd->SCp.ptr,x);
+                       z-=x; 
+                       IncStat(&cmd->SCp,2*x);
+                       if ((z>0)&&(cmd->SCp.this_residual==1))
+                       {
+                           zwickel=inw(base+HA_RDATA); 
+                           *(cmd->SCp.ptr)=zwickel&0xff;
+                           IncStat(&cmd->SCp,1); z--; 
+                           odd=TRUE;
+                       }
+                   }
+                   while (z>0) {
+                       zwickel=inw(base+HA_RDATA); 
+                       z--;
+                   } 
+               }
+               else /* cp->DataOut */
+               {
+                   odd=FALSE; z=256;
+                   while ((cmd->SCp.Status)&&((z>0)||(odd)))
+                   {
+                       if (odd)
+                       {
+                           zwickel+=*(cmd->SCp.ptr)<<8; 
+                           IncStat(&cmd->SCp,1);
+                           outw(zwickel,base+HA_RDATA); 
+                           z--; 
+                           odd=FALSE; 
+                       }
+                       x=min(z,cmd->SCp.this_residual/2);
+                       outsw(base+HA_RDATA,cmd->SCp.ptr,x);
+                       z-=x; 
+                       IncStat(&cmd->SCp,2*x);
+                       if ((z>0)&&(cmd->SCp.this_residual==1))
+                       {
+                           zwickel=*(cmd->SCp.ptr); 
+                           zwickel&=0xff;
+                           IncStat(&cmd->SCp,1); 
+                           odd=TRUE;
+                       }  
+                   }
+                   while (z>0||odd) {
+                       outw(zwickel,base+HA_RDATA); 
+                       z--; 
+                       odd=FALSE;
+                   }
+               }
+       }
+       while ((stat&HA_SDRQ)||((stat&HA_SMORE)&&hd->moresupport));
+       
+       /* terminate handler if HBA goes busy again, i.e. transfers
+        * more data */
+       
+       if (stat&HA_SBUSY) break;
+       
+       /* OK, this is quite stupid, but I haven't found any correct
+        * way to get HBA&SCSI status so far */
+       
+       if (!(inb(base+HA_RSTATUS)&HA_SERROR))
+       {
+           cmd->result=(DID_OK<<16); 
+           hd->devflags|=(1<<cp->cp_id);
+       }
+       else if (hd->devflags&1<<cp->cp_id) 
+           cmd->result=(DID_OK<<16)+0x02;
+       else cmd->result=(DID_NO_CONNECT<<16);
+       
+       if (cp->status == LOCKED) {
+           cp->status = FREE;
+           eata_stat = inb(base + HA_RSTATUS);
+           printk("eata_pio: int_handler, freeing locked queueslot\n");
+           DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+           restore_flags(flags);
+           return;
+       }
+       
+#if DBG_INTR2
+       if (stat != 0x50) 
+           printk("stat: %#.2x, result: %#.8x\n", stat, cmd->result); 
+       DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+#endif
+       
+       cp->status = FREE;   /* now we can release the slot  */
+       
+       restore_flags(flags);
+       if(cmd->scsi_done != eata_pio_scsi_done) cmd->scsi_done(cmd);
+       else internal_command_finished = TRUE;
+       save_flags(flags);
+       cli();
+    }
+    restore_flags(flags);
+    
+    return;
+}
+
+inline uint eata_pio_send_command(uint base, unchar command)
+{
+    uint loop = R_LIMIT;
+    
+    while (inb(base + HA_RSTATUS) & HA_SBUSY)
+       if (--loop == 0)
+           return(TRUE);
+    
+    outb(command, base + HA_WCOMMAND);
+    return(FALSE);
+}
+
+int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+    uint x, y;
+    long flags;
+    uint base;
+    
+    hostdata *hd;
+    struct Scsi_Host *sh;
+    struct eata_ccb *cp;
+    
+    save_flags(flags);
+    cli();
+    
+    queue_counter++;
+    
+    if (done == (void *)eata_pio_scsi_done) { 
+       if (internal_command_finished == TRUE)
+           internal_command_finished = FALSE;
+       else 
+           cmd->result = (DID_ERROR << 16) + QUEUE_FULL;
+    }
+    
+    hd = HD(cmd);
+    sh = cmd->host;
+    base = (uint) sh->base;
+    
+    /* use only slot 0, as 2001 can handle only one cmd at a time */
+    
+    y = x = 0;
+    
+    if (hd->ccb[y].status!=FREE) { 
+       
+       DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n",sh->can_queue,x,y));
+#if DEBUG_EATA
+       panic("eata_pio: run out of queue slots cmdno:%ld intrno: %ld\n", 
+             queue_counter, int_counter);
+#else
+       panic("eata_pio: run out of queue slots....\n");
+#endif
+    }
+    
+    cp = &hd->ccb[y];
+    
+    memset(cp, 0, sizeof(struct eata_ccb));
+    memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+       
+    cp->status = USED;      /* claim free slot */
+
+    DBG(DBG_QUEUE, printk("eata_pio_queue pid %ld, target: %x, lun: %x, y %d\n",
+                         cmd->pid, cmd->target, cmd->lun, y));
+    DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
+    
+    cmd->scsi_done = (void *)done;
+    
+    switch (cmd->cmnd[0]) {
+    case CHANGE_DEFINITION: case COMPARE:         case COPY:
+    case COPY_VERIFY:       case LOG_SELECT:      case MODE_SELECT:
+    case MODE_SELECT_10:    case SEND_DIAGNOSTIC: case WRITE_BUFFER:
+    case FORMAT_UNIT:       case REASSIGN_BLOCKS: case RESERVE:
+    case SEARCH_EQUAL:      case SEARCH_HIGH:     case SEARCH_LOW:
+    case WRITE_6:           case WRITE_10:        case WRITE_VERIFY:
+    case UPDATE_BLOCK:      case WRITE_LONG:      case WRITE_SAME:      
+    case SEARCH_HIGH_12:    case SEARCH_EQUAL_12: case SEARCH_LOW_12:
+    case WRITE_12:          case WRITE_VERIFY_12: case SET_WINDOW: 
+    case MEDIUM_SCAN:       case SEND_VOLUME_TAG:            
+    case 0xea:      /* alternate number for WRITE LONG */
+       cp->DataOut = TRUE; /* Output mode */
+       break;
+    case TEST_UNIT_READY:
+    default:
+       cp->DataIn = TRUE;  /* Input mode  */
+    }
+    
+    cp->Interpret = (cmd->target==hd->hostid);
+    cp->cp_datalen=htonl((ulong)cmd->request_bufflen);
+    cp->Auto_Req_Sen = FALSE;
+    cp->cp_reqDMA = htonl(0);
+    cp->reqlen = 0;
+    
+    cp->cp_id = cmd->target;
+    cp->cp_lun = cmd->lun;
+    cp->cp_dispri = FALSE;
+    cp->cp_identify = TRUE;
+    memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+    
+    cp->cp_statDMA = htonl(0);
+    
+    cp->cp_viraddr = cp;
+    cp->cmd = cmd;
+    cmd->host_scribble = (char *)&hd->ccb[y];   
+    
+    if (cmd->use_sg==0)
+    { 
+       cmd->SCp.buffers_residual=1;
+       cmd->SCp.ptr=cmd->request_buffer;
+       cmd->SCp.this_residual=cmd->request_bufflen;
+       cmd->SCp.buffer=NULL;
+    }
+    else
+    {
+       cmd->SCp.buffer=cmd->request_buffer;
+       cmd->SCp.buffers_residual=cmd->use_sg;
+       cmd->SCp.ptr=cmd->SCp.buffer->address;
+       cmd->SCp.this_residual=cmd->SCp.buffer->length;
+    }
+    cmd->SCp.Status=(cmd->SCp.this_residual!=0);  /* TRUE as long as bytes 
+                                                    are to transfer */ 
+    
+    if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) 
+    {
+       cmd->result = DID_ERROR << 16;
+       printk("eata_pio_queue target %d, pid %ld, HBA busy, returning DID_ERROR, done.\n",
+              cmd->target, cmd->pid);
+       restore_flags(flags);
+       if(done != (void *)eata_pio_scsi_done) done(cmd);
+       return (0);
+    }
+    while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+    outsw(base + HA_RDATA, cp, hd->cplen);
+    outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
+    for (x=0; x<hd->cppadlen; x++) outw(0, base + HA_RDATA);
+    
+    DBG(DBG_QUEUE,printk("Queued base %#.4lx pid: %ld target: %x lun: %x "
+                        "slot %d irq %d\n", (long)sh->base, cmd->pid, 
+                        cmd->target, cmd->lun, y, sh->irq));
+    DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
+    
+    restore_flags(flags);
+    return (0);
+}
+
+int eata_pio_abort(Scsi_Cmnd * cmd)
+{
+    ulong flags;
+    uint loop = R_LIMIT;
+    
+    save_flags(flags);
+    cli();
+    
+    DBG(DBG_ABNORM, printk("eata_pio_abort called pid: %ld target: %x lun: %x reason %x\n",
+                          cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
+    DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+    
+    
+    while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
+       if (--loop == 0) {
+           printk("eata_pio: abort, timeout error.\n");
+           restore_flags(flags);
+           DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+           return (SCSI_ABORT_ERROR);
+       }
+    if (CD(cmd)->status == FREE) {
+       DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n")); 
+       restore_flags(flags);
+       return (SCSI_ABORT_NOT_RUNNING);
+    }
+    if (CD(cmd)->status == USED) {
+       DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
+       restore_flags(flags);
+       return (SCSI_ABORT_BUSY);  /* SNOOZE */ 
+    }
+    if (CD(cmd)->status == RESET) {
+       restore_flags(flags);
+       printk("eata_pio: abort, command reset error.\n");
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_ABORT_ERROR);
+    }
+    if (CD(cmd)->status == LOCKED) {
+       restore_flags(flags);
+       DBG(DBG_ABNORM, printk("eata_pio: abort, queue slot locked.\n"));
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_ABORT_NOT_RUNNING);
+    } else
+       panic("eata_pio: abort: invalid slot status\n");
+}
+
+int eata_pio_reset(Scsi_Cmnd * cmd)
+{
+    uint x, z, time, limit = 0;
+    ulong flags;
+    unchar success = FALSE;
+    Scsi_Cmnd *sp; 
+    
+    save_flags(flags);
+    cli();
+    hprint("reset");
+    DBG(DBG_ABNORM, printk("eata_pio_reset called pid:%ld target: %x lun: %x "
+                          "reason %x\n", cmd->pid, cmd->target, cmd->lun, 
+                          cmd->abort_reason));
+
+    if (HD(cmd)->state == RESET) {
+       printk("eata_pio_reset: exit, already in reset.\n");
+       restore_flags(flags);
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_RESET_ERROR);
+    }
+    
+    for (z = 0; z < MAXTARGET; z++) {
+       HD(cmd)->t_state[0][z] = RESET;
+       HD(cmd)->t_timeout[0][z] = NO_TIMEOUT;
+    }
+    
+    /* force all slots to be free */
+    
+    for (x = 0; x < cmd->host->can_queue; x++) {
+       
+       if (HD(cmd)->ccb[x].status == FREE) 
+           continue;
+       
+       sp = HD(cmd)->ccb[x].cmd;
+       HD(cmd)->ccb[x].status = RESET;
+       printk("eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       
+       if (sp == NULL)
+           panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+    }
+    
+    /* hard reset the HBA  */
+    outb((uint) cmd->host->base+HA_WCOMMAND, EATA_CMD_RESET);
+    
+    DBG(DBG_ABNORM, printk("eata_pio_reset: board reset done.\n"));
+    HD(cmd)->state = RESET;
+    
+    time = jiffies;
+    while (jiffies < (time + 300) && limit++ < 10000000);
+    
+    DBG(DBG_ABNORM, printk("eata_pio_reset: interrupts disabled, loops %d.\n", limit));
+    DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+    
+    for (x = 0; x < cmd->host->can_queue; x++) {
+       
+       /* Skip slots already set free by interrupt */
+       if (HD(cmd)->ccb[x].status != RESET)
+           continue;
+       
+       sp = HD(cmd)->ccb[x].cmd;
+       sp->result = DID_RESET << 16;
+       
+       /* This mailbox is terminated */
+       printk("eata_pio_reset: resetted ccb %d.\n",x);
+       HD(cmd)->ccb[x].status = FREE;
+       
+       restore_flags(flags);
+       sp->scsi_done(sp);
+       cli();
+    }
+    
+    HD(cmd)->state = FALSE;
+    restore_flags(flags);
+    
+    if (success) { /* hmmm... */
+       DBG(DBG_ABNORM, printk("eata_pio_reset: exit, success.\n"));
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_RESET_SUCCESS);
+    } else {
+       DBG(DBG_ABNORM, printk("eata_pio_reset: exit, wakeup.\n"));
+       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       return (SCSI_RESET_PUNT);
+    }
+}
+
+char * get_pio_board_data(ulong base, uint irq, uint id, ulong cplen, ushort cppadlen)
+{
+    struct eata_ccb cp;
+    static char buff[256];
+    int z;
+    
+    memset(&cp, 0, sizeof(struct eata_ccb));
+    memset(buff, 0, sizeof(buff));
+    
+    cp.DataIn = TRUE;     
+    cp.Interpret = TRUE;   /* Interpret command */
+    
+    cp.cp_datalen = htonl(254);  
+    cp.cp_dataDMA = htonl(0);
+    
+    cp.cp_id = id;
+    cp.cp_lun = 0;
+    
+    cp.cp_cdb[0] = INQUIRY;
+    cp.cp_cdb[1] = 0;
+    cp.cp_cdb[2] = 0;
+    cp.cp_cdb[3] = 0;
+    cp.cp_cdb[4] = 254;
+    cp.cp_cdb[5] = 0;
+    
+    if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP)) return (NULL);
+    while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+    outsw(base + HA_RDATA, &cp, cplen);
+    outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
+    for (z=0; z<cppadlen; z++) outw(0, base + HA_RDATA);
+    
+    while (inb(base + HA_RSTATUS) & HA_SBUSY);
+    if (inb(base + HA_RSTATUS) & HA_SERROR)
+       return (NULL);
+    else if (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+       return (NULL);
+    else
+    {
+       insw(base+HA_RDATA, &buff, 127);
+       while (inb(base+HA_RSTATUS)&HA_SDRQ) inw(base+HA_RDATA);
+       return (buff);
+    }
+}
+
+int get_pio_conf_PIO(u32 base, struct get_conf *buf)
+{
+    ulong loop = R_LIMIT;
+    int z;
+    ushort *p;
+    
+    if(check_region(base, 9))  
+       return (FALSE);
+    
+    memset(buf, 0, sizeof(struct get_conf));
+    
+    while (inb(base + HA_RSTATUS) & HA_SBUSY)
+       if (--loop == 0) 
+           return (FALSE);
+    
+    DBG(DBG_PIO && DBG_PROBE,
+       printk("Issuing PIO READ CONFIG to HBA at %#x\n", base));
+    eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
+
+    loop = R_LIMIT;
+    for (p = (ushort *) buf; 
+        (long)p <= ((long)buf + (sizeof(struct get_conf)/ 2)); p++) {
+       while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+           if (--loop == 0)
+               return (FALSE);
+
+       loop = R_LIMIT;
+       *p = inw(base + HA_RDATA);
+    }
+    if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {            /* Error ? */
+       if (htonl(EATA_SIGNATURE) == buf->signature) {
+           DBG(DBG_PIO&&DBG_PROBE, printk("EATA Controller found at %#4x "
+                                          "EATA Level: %x\n", base, 
+                                          (uint) (buf->version)));
+           
+           while (inb(base + HA_RSTATUS) & HA_SDRQ) 
+               inw(base + HA_RDATA);
+           if(ALLOW_DMA_BOARDS == FALSE) {
+               for (z = 0; z < MAXISA; z++)
+                   if (base == ISAbases[z]) {
+                       buf->IRQ = ISAirqs[z]; 
+                       break;
+                   }
+           }
+           return (TRUE);
+       } 
+    } else {
+       DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer "
+                             "for HBA at %x\n", base));
+    }
+    return (FALSE);
+}
+
+void print_pio_config(struct get_conf *gc)
+{
+    printk("Please check values: (read config data)\n");
+    printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n",
+          (uint) ntohl(gc->len), gc->version,
+          gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
+    printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n",
+          gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
+          gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
+    printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n",
+          gc->IRQ, gc->IRQ_TR, gc->FORCADR, 
+          gc->MAX_CHAN, gc->ID_qest);
+    DBG(DPT_DEBUG, DELAY(1400));
+}
+
+static uint print_selftest(uint base)
+{
+    unchar buffer[512];
+#ifdef VERBOSE_SETUP
+    int z;
+#endif
+    
+    printk("eata_pio: executing controller self test & setup...\n");
+    while (inb(base+HA_RSTATUS)&HA_SBUSY);
+    outb(EATA_CMD_PIO_SETUPTEST,base+HA_WCOMMAND);
+    do {
+       while (inb(base+HA_RSTATUS)&HA_SBUSY)
+           /* nothing */ ;
+       if (inb(base+HA_RSTATUS)&HA_SDRQ)
+       {
+           insw(base+HA_RDATA,&buffer,256);
+#ifdef VERBOSE_SETUP
+           /* no beeps please... */
+           for (z=0; z < 511 && buffer[z]; z++)
+               if (buffer[z] != 7) printk("%c", buffer[z]);
+#endif
+       }
+    } while (inb(base+HA_RSTATUS)&(HA_SBUSY|HA_SDRQ));
+    
+    return (!(inb(base+HA_RSTATUS)&HA_SERROR)); 
+}
+
+int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
+{
+    ulong size = 0;
+    char *buff;
+    ulong cplen;
+    ushort cppadlen;
+    struct Scsi_Host *sh;
+    hostdata *hd;
+    
+    DBG(DBG_REGISTER, print_pio_config(gc));
+    
+    if (gc->DMA_support == TRUE) {
+       printk("HBA at %#.4lx supports DMA. Please use EATA-DMA driver.\n",base);
+       if(ALLOW_DMA_BOARDS == FALSE)
+           return (FALSE);
+    }
+    
+    if ((buff = get_pio_board_data((uint)base, gc->IRQ, gc->scsi_id[3], 
+                              cplen   =(htonl(gc->cplen   )+1)/2, 
+                              cppadlen=(htons(gc->cppadlen)+1)/2)) == NULL)
+    {
+       printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (ulong) base);
+       return (FALSE);
+    }
+    
+    if (print_selftest(base) == FALSE && ALLOW_DMA_BOARDS == FALSE)
+    {
+       printk("HBA at %#lx failed while performing self test & setup.\n", 
+              (ulong) base);
+       return (FALSE);
+    }
+    
+    if (!reg_IRQ[gc->IRQ]) {    /* Interrupt already registered ? */
+       if (!request_irq(gc->IRQ, eata_pio_int_handler, SA_INTERRUPT, 
+                        "EATA-PIO")){
+           reg_IRQ[gc->IRQ]++;
+           if (!gc->IRQ_TR)
+               reg_IRQL[gc->IRQ] = TRUE;   /* IRQ is edge triggered */
+       } else {
+           printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
+           return (FALSE);
+       }
+    } else {            /* More than one HBA on this IRQ */
+       if (reg_IRQL[gc->IRQ] == TRUE) {
+           printk("Can't support more than one HBA on this IRQ,\n"
+                  "  if the IRQ is edge triggered. Sorry.\n");
+           return (FALSE);
+       } else
+           reg_IRQ[gc->IRQ]++;
+    }
+    
+    request_region(base, 8, "eata_pio");
+    
+    size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
+    
+    sh = scsi_register(tpnt, size);
+    hd = SD(sh);                   
+    
+    memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)));
+    memset(hd->reads, 0, sizeof(ulong) * 26); 
+    
+    strncpy(SD(sh)->vendor, &buff[8], 8);
+    SD(sh)->vendor[8] = 0;
+    strncpy(SD(sh)->name, &buff[16], 17);
+    SD(sh)->name[17] = 0;
+    SD(sh)->revision[0] = buff[32];
+    SD(sh)->revision[1] = buff[33];
+    SD(sh)->revision[2] = buff[34];
+    SD(sh)->revision[3] = '.';
+    SD(sh)->revision[4] = buff[35];
+    SD(sh)->revision[5] = 0;
+    switch (ntohl(gc->len)) {
+    case 0x1c:
+       SD(sh)->EATA_revision = 'a';
+       break;
+    case 0x1e:
+       SD(sh)->EATA_revision = 'b';
+       break;
+    case 0x22:
+       SD(sh)->EATA_revision = 'c';
+       break;
+    default:
+       SD(sh)->EATA_revision = '?';
+    }
+    SD(sh)->cplen=cplen;
+    SD(sh)->cppadlen=cppadlen;
+    SD(sh)->hostid=gc->scsi_id[3];
+    SD(sh)->devflags=1<<gc->scsi_id[3];
+    SD(sh)->moresupport=gc->MORE_support;
+    sh->base = (char *) base;
+    sh->io_port = (ushort) base;
+    sh->n_io_port = 8;
+    sh->irq = gc->IRQ;
+    sh->dma_channel = 0xfe;  /* PIO */
+    sh->this_id = gc->scsi_id[3];
+    sh->can_queue = 1;
+    sh->cmd_per_lun = 1;
+    sh->sg_tablesize = SG_ALL;
+    
+    hd->channel = 0;
+    
+    if(ntohl(gc->len) >= 0x22) {
+       if (gc->is_PCI == TRUE)
+           hd->bustype = IS_PCI;
+       else if (gc->is_EISA == TRUE)
+           hd->bustype = IS_EISA;
+       else
+           hd->bustype = IS_ISA;
+    } else {
+       if (buff[21] == '4')
+           hd->bustype = IS_PCI;
+       else if (buff[21] == '2')
+           hd->bustype = IS_EISA;
+       else
+           hd->bustype = IS_ISA;
+    }
+  
+    sh->max_id = 8;
+    sh->max_lun = 8;
+
+    if (gc->SECOND)
+       hd->primary = FALSE;
+    else
+       hd->primary = TRUE;
+    
+    sh->unchecked_isa_dma = FALSE; /* We can only do PIO */
+    
+    hd->next = NULL;    /* build a linked list of all HBAs */
+    hd->prev = last_HBA;
+    if(hd->prev != NULL)
+       SD(hd->prev)->next = sh;
+    last_HBA = sh;
+    if (first_HBA == NULL)
+       first_HBA = sh;
+    registered_HBAs++;
+    return (1);
+}
+
+void find_pio_ISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
+{
+    int i;
+    
+    for (i = 0; i < MAXISA; i++) {  
+       if (ISAbases[i]) {  
+           if (get_pio_conf_PIO(ISAbases[i], buf) == TRUE){
+               register_pio_HBA(ISAbases[i], buf, tpnt);
+           }
+           ISAbases[i] = 0;
+       }
+    }
+    return;
+}
+
+void find_pio_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
+{
+    u32 base;
+    int i;
+
+#if CHECKPAL
+    u8 pal1, pal2, pal3;
+#endif
+
+    for (i = 0; i < MAXEISA; i++) {
+       if (EISAbases[i] == TRUE) { /* Still a possibility ?          */
+
+           base = 0x1c88 + (i * 0x1000);
+#if CHECKPAL
+           pal1 = inb((u16)base - 8);
+           pal2 = inb((u16)base - 7);
+           pal3 = inb((u16)base - 6);
+
+           if (((pal1 == 0x12) && (pal2 == 0x14)) ||
+               ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) ||
+               ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
+               DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
+                                     (int)pal1, (int)pal2, (int)pal3));
+#endif
+               if (get_pio_conf_PIO(base, buf) == TRUE) {
+                   DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
+                   if (buf->IRQ) {
+                       register_pio_HBA(base, buf, tpnt);
+                   } else
+                       printk("eata_dma: No valid IRQ. HBA removed from list\n");
+               }
+               /* Nothing found here so we take it from the list */
+               EISAbases[i] = 0;
+#if CHECKPAL
+           }
+#endif
+       }
+    }
+    return;
+}
+
+void find_pio_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
+{
+
+#ifndef CONFIG_PCI
+    printk("Kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
+#else
+    
+    u8 pci_bus, pci_device_fn;
+    static s16 pci_index = 0;   /* Device index to PCI BIOS calls */
+    u32 base = 0;
+    u16 com_adr;
+    u16 rev_device;
+    u32 error, i, x;
+
+    if (pcibios_present()) {
+       for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
+           if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, 
+                                   pci_index, &pci_bus, &pci_device_fn))
+               break;
+           DBG(DBG_PROBE && DBG_PCI, 
+               printk("eata_pio: HBA at bus %d, device %d,"
+                      " function %d, index %d\n", (s32)pci_bus, 
+                      (s32)((pci_device_fn & 0xf8) >> 3),
+                      (s32)(pci_device_fn & 7), pci_index));
+           
+           if (!(error = pcibios_read_config_word(pci_bus, pci_device_fn, 
+                                      PCI_CLASS_DEVICE, &rev_device))) {
+               if (rev_device == PCI_CLASS_STORAGE_SCSI) {
+                   if (!(error = pcibios_read_config_word(pci_bus, 
+                                              pci_device_fn, PCI_COMMAND, 
+                                              (u16 *) & com_adr))) {
+                       if (!((com_adr & PCI_COMMAND_IO) && 
+                             (com_adr & PCI_COMMAND_MASTER))) {
+                           printk("HBA has IO or BUSMASTER mode disabled\n");
+                           continue;
+                       }
+                   } else
+                       printk("eata_pio: error %x while reading "
+                              "PCI_COMMAND\n", error);
+               } else
+                   printk("DEVICECLASSID %x didn't match\n", rev_device);
+           } else {
+               printk("eata_pio: error %x while reading PCI_CLASS_BASE\n", 
+                      error);
+               continue;
+           }
+           
+           if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                      PCI_BASE_ADDRESS_0, (int *) &base))){
+               
+               /* Check if the address is valid */
+               if (base & 0x01) {
+                   base &= 0xfffffffe;
+                   /* EISA tag there ? */
+                   if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
+                       continue;   /* Jep, it's forced, so move on  */
+                   base += 0x10;   /* Now, THIS is the real address */
+                   if (base != 0x1f8) {
+                       /* We didn't find it in the primary search */
+                       if (get_pio_conf_PIO(base, buf) == TRUE) {
+                           if (buf->FORCADR)   /* If the address is forced */
+                               continue;       /* we'll find it later      */
+                           
+                           /* OK. We made it till here, so we can go now  
+                            * and register it. We  only have to check and 
+                            * eventually remove it from the EISA and ISA list 
+                            */
+                           
+                           register_pio_HBA(base, buf, tpnt);
+                           
+                           if (base < 0x1000) {
+                               for (x = 0; x < MAXISA; ++x) {
+                                   if (ISAbases[x] == base) {
+                                       ISAbases[x] = 0;
+                                       break;
+                                   }
+                               }
+                           } else if ((base & 0x0fff) == 0x0c88) {
+                               x = (base >> 12) & 0x0f;
+                               EISAbases[x] = 0;
+                           }
+                           continue;  /* break; */
+                       }
+                   }
+               }
+           } else
+               printk("eata_pio: error %x while reading "
+                      "PCI_BASE_ADDRESS_0\n", error);
+       }
+    } else
+       printk("No BIOS32 extensions present. This eata_pio release "
+              "still depends on it.\n"
+              "Skipping scan for PCI HBAs. Sorry.\n");
+#endif /* #ifndef CONFIG_PCI */
+    return;
+}
+
+
+int eata_pio_detect(Scsi_Host_Template * tpnt)
+{
+    struct Scsi_Host *HBA_ptr;
+    struct get_conf gc;
+    int i;
+    
+    DBG((DBG_PROBE && DBG_DELAY) || DPT_DEBUG,
+       printk("Using lots of delays to let you read the debugging output\n"));
+    
+#ifndef DBG_EISA
+
+printk("DBG_EISA not defined !!!\n");
+
+#endif
+
+    find_pio_PCI(&gc, tpnt);
+
+    find_pio_EISA(&gc, tpnt);
+
+    find_pio_ISA(&gc, tpnt);
+    
+    for (i = 0; i <= MAXIRQ; i++)
+       if (reg_IRQ[i])
+           request_irq(i, eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO");
+    
+    HBA_ptr = first_HBA;
+  
+    if (registered_HBAs != 0) {
+       printk("EATA (Extended Attachment) PIO driver version: %d.%d%s\n"
+              "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n"
+              "            Alfred Arnold,   a.arnold@kfa-juelich.de\n"
+              "This release only supports DASD devices (harddisks)\n",
+              VER_MAJOR, VER_MINOR, VER_SUB);
+       
+       printk("Registered HBAs:\n");
+       printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr: QS: SG: CPL:\n");
+       for (i = 1; i <= registered_HBAs; i++) {
+           printk("scsi%-2d: %.10s v%s 2.0%c  %s %#.4x   %2d   %d   %d   %c  %2d  %2d  %2d\n", 
+                  HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
+                  SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')?
+                  "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
+                  (uint) HBA_ptr->base, HBA_ptr->irq, 
+                  SD(HBA_ptr)->channel, HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N', 
+                  HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+           HBA_ptr = SD(HBA_ptr)->next;
+       }
+    }
+    DBG(DPT_DEBUG,DELAY(1200));
+    
+    return (registered_HBAs);
+}
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = EATA_PIO;
+
+#include "scsi_module.c"
+#endif
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/eata_pio.h b/drivers/scsi/eata_pio.h
new file mode 100644 (file)
index 0000000..6d9ea3f
--- /dev/null
@@ -0,0 +1,120 @@
+/********************************************************
+* Header file for eata_pio.c Linux EATA-PIO SCSI driver *
+* (c) 1993,94,95 Michael Neuffer                        *
+*********************************************************
+* last change: 95/06/21                                 *
+********************************************************/
+
+
+#ifndef _EATA_PIO_H
+#define _EATA_PIO_H
+
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/scsicam.h>
+
+#ifndef HOSTS_C
+#include "eata_generic.h"
+
+#define VER_MAJOR 0
+#define VER_MINOR 0
+#define VER_SUB   "1a"
+
+/************************************************************************
+ * Here you can switch parts of the code on and of                      *
+ ************************************************************************/
+
+#define VERBOSE_SETUP                   /* show startup screen of 2001 */
+#define ALLOW_DMA_BOARDS 1
+
+/************************************************************************
+ * Debug options.                                                       * 
+ * Enable DEBUG and whichever options you require.                      *
+ ************************************************************************/
+#define DEBUG_EATA      1   /* Enable debug code.                       */
+#define DPT_DEBUG       0   /* Bobs special                             */
+#define DBG_DELAY       0   /* Build in delays so debug messages can be
+                            * be read before they vanish of the top of
+                            * the screen!
+                            */
+#define DBG_PROBE       0   /* Debug probe routines.                    */
+#define DBG_ISA         0   /* Trace ISA routines                       */ 
+#define DBG_EISA        0   /* Trace EISA routines                      */ 
+#define DBG_PCI         0   /* Trace PCI routines                       */ 
+#define DBG_PIO         0   /* Trace get_config_PIO                     */
+#define DBG_COM         0   /* Trace command call                       */
+#define DBG_QUEUE       0   /* Trace command queueing.                  */
+#define DBG_INTR        0   /* Trace interrupt service routine.         */
+#define DBG_INTR2       0   /* Trace interrupt service routine.         */
+#define DBG_PROC        0   /* Debug proc-fs related statistics         */
+#define DBG_PROC_WRITE  0
+#define DBG_REGISTER    0   /* */
+#define DBG_ABNORM      1   /* Debug abnormal actions (reset, abort)    */
+
+#if DEBUG_EATA 
+#define DBG(x, y)   if ((x)) {y;} 
+#else
+#define DBG(x, y)
+#endif
+
+#endif /* !HOSTS_C */
+
+int eata_pio_detect(Scsi_Host_Template *);
+const char *eata_pio_info(struct Scsi_Host *);
+int eata_pio_command(Scsi_Cmnd *);
+int eata_pio_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int eata_pio_abort(Scsi_Cmnd *);
+int eata_pio_reset(Scsi_Cmnd *);
+int eata_pio_proc_info(char *, char **, off_t, int, int, int);
+#ifdef MODULE
+int eata_pio_release(struct Scsi_Host *);
+#else
+#define eata_pio_release NULL  
+#endif
+
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
+
+#define EATA_PIO {                   \
+       NULL, NULL,                  \
+       eata_pio_proc_info,/* procinfo       */  \
+       "eata_pio",        /* proc dir entry */  \
+       PROC_SCSI_EATA_PIO,/* proc dir inode */  \
+        "EATA (Extended Attachment) PIO driver",\
+       eata_pio_detect,             \
+       eata_pio_release,            \
+       NULL, NULL,                  \
+       eata_pio_queue,              \
+       eata_pio_abort,              \
+       eata_pio_reset,              \
+       NULL,   /* Slave attach */   \
+       scsicam_bios_param,          \
+       0,      /* Canqueue     */   \
+       0,      /* this_id      */   \
+       0,      /* sg_tablesize */   \
+       0,      /* cmd_per_lun  */   \
+       0,      /* present      */   \
+       1,      /* True if ISA  */   \
+       ENABLE_CLUSTERING }
+
+#endif /* _EATA_PIO_H */
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
diff --git a/drivers/scsi/eata_pio_proc.c b/drivers/scsi/eata_pio_proc.c
new file mode 100644 (file)
index 0000000..9362827
--- /dev/null
@@ -0,0 +1,179 @@
+
+#define MAX_SCSI_DEVICE_CODE 10
+const char *const pio_scsi_dev_types[MAX_SCSI_DEVICE_CODE] =
+{
+    "Direct-Access    ",
+    "Sequential-Access",
+    "Printer          ",
+    "Processor        ",
+    "WORM             ",
+    "CD-ROM           ",
+    "Scanner          ",
+    "Optical Device   ",
+    "Medium Changer   ",
+    "Communications   "
+};
+
+/*
+ * eata_set_info
+ * buffer : pointer to the data that has been written to the hostfile
+ * length : number of bytes written to the hostfile
+ * HBA_ptr: pointer to the Scsi_Host struct
+ */
+int eata_pio_set_info(char *buffer, int length, struct Scsi_Host *HBA_ptr)
+{
+    DBG(DBG_PROC_WRITE, printk("%s\n", buffer));
+    return(-ENOSYS);  /* Currently this is a no-op */
+}
+
+/*
+ * eata_proc_info
+ * inout : decides on the direction of the dataflow and the meaning of the variables
+ * buffer: If inout==FALSE data is beeing written to it else read from it
+ * *start: If inout==FALSE start of the valid data in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer else number of bytes in the buffer
+ */
+int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+{
+
+    Scsi_Device *scd;
+    struct Scsi_Host *HBA_ptr;
+    static u8 buff[512];
+    int i, x; 
+    int   size, len = 0;
+    off_t begin = 0;
+    off_t pos = 0;
+
+    HBA_ptr = first_HBA;
+    for (i = 1; i <= registered_HBAs; i++) {
+       if (HBA_ptr->host_no == hostno)
+           break;
+       HBA_ptr = SD(HBA_ptr)->next;
+    }        
+
+    if(inout == TRUE) /* Has data been writen to the file ? */ 
+       return(eata_pio_set_info(buffer, length, HBA_ptr));
+
+    if (offset == 0)
+       memset(buff, 0, sizeof(buff));
+
+    size = sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
+                  "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
+    len += size; pos = begin + len;
+    size = sprintf(buffer + len, "queued commands:     %10ld\n"
+                  "processed interrupts:%10ld\n", queue_counter, int_counter);
+    len += size; pos = begin + len;
+    
+    size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
+                  HBA_ptr->host_no, SD(HBA_ptr)->name);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Firmware revision: v%s\n", 
+                  SD(HBA_ptr)->revision);
+    len += size;
+    pos = begin + len;
+    size = sprintf(buffer + len, "IO: PIO\n");
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Host Bus: %s\n", 
+                  (SD(HBA_ptr)->bustype == 'P')?"PCI ":
+                  (SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ");
+    
+    len += size; 
+    pos = begin + len;
+    
+    if (pos < offset) {
+       len = 0;
+       begin = pos;
+    }
+    if (pos > offset + length)
+       goto stop_output;
+    
+    scd = scsi_devices;
+    
+    size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+    len += size; 
+    pos = begin + len;
+    
+    while (scd) {
+       if (scd->host == HBA_ptr) {
+           
+           size = sprintf(buffer + len, "Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
+                          scd->channel, scd->id, scd->lun);
+           for (x = 0; x < 8; x++) {
+               if (scd->vendor[x] >= 0x20)
+                   size += sprintf(buffer + len + size, "%c", scd->vendor[x]);
+               else
+                   size += sprintf(buffer + len + size," ");
+           }
+           size += sprintf(buffer + len + size, " Model: ");
+           for (x = 0; x < 16; x++) {
+               if (scd->model[x] >= 0x20)
+                   size +=  sprintf(buffer + len + size, "%c", scd->model[x]);
+               else
+                   size += sprintf(buffer + len + size, " ");
+           }
+           size += sprintf(buffer + len + size, " Rev: ");
+           for (x = 0; x < 4; x++) {
+               if (scd->rev[x] >= 0x20)
+                   size += sprintf(buffer + len + size, "%c", scd->rev[x]);
+               else
+                   size += sprintf(buffer + len + size, " ");
+           }
+           size += sprintf(buffer + len + size, "\n");
+           
+           size += sprintf(buffer + len + size, "  Type:   %s ",
+                           scd->type < MAX_SCSI_DEVICE_CODE ? 
+                           pio_scsi_dev_types[(int)scd->type] : "Unknown          " );
+           size += sprintf(buffer + len + size, "               ANSI"
+                           " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
+           if (scd->scsi_level == 2)
+               size += sprintf(buffer + len + size, " CCS\n");
+           else
+               size += sprintf(buffer + len + size, "\n");
+           len += size; 
+           pos = begin + len;
+           
+           if (pos < offset) {
+               len = 0;
+               begin = pos;
+           }
+           if (pos > offset + length)
+               goto stop_output;
+       }
+       scd = scd->next;
+    }
+    
+ stop_output:
+    DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
+    *start=buffer+(offset-begin);   /* Start of wanted data */
+    len-=(offset-begin);            /* Start slop */
+    if(len>length)
+       len = length;               /* Ending slop */
+    DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
+    
+    return (len);     
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
index 23e9fa8904bc5ca0cca9b373f93d60fa389675ef..89f04754e048daa8f779ac1e2ee70f8747f3b54d 100644 (file)
 
  **************************************************************************/
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 #include <linux/sched.h>
 #include <asm/io.h>
 #include "../block/blk.h"
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+#include <linux/proc_fs.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
-
+  
 #define VERSION          "$Revision: 5.31 $"
 
 /* START OF USER DEFINABLE OPTIONS */
@@ -419,9 +424,9 @@ static void print_banner( struct Scsi_Host *shpnt )
           (unsigned)bios_base, shpnt->this_id );
 
                                /* If this driver works for later FD PCI
-                                   boards, we will have to modify banner
-                                   for additional PCI cards, but for now if
-                                   it's PCI it's a TMC-3260 - JTM */
+                                  boards, we will have to modify banner
+                                  for additional PCI cards, but for now if
+                                  it's PCI it's a TMC-3260 - JTM */
    printk( "scsi%d <fdomain>: %s chip at 0x%x irq ",
           shpnt->host_no,
           chip == tmc1800 ? "TMC-1800"
@@ -471,7 +476,7 @@ static int fdomain_is_valid_port( int port )
       if (inb( port + LSB_ID_Code ) != 0x27) return 0;
       if (inb( port + MSB_ID_Code ) != 0x61) return 0;
       chip = tmc1800;
-   } else {                                /* test for 0xe960 id */
+   } else {                                /* test for 0xe960 id */
       if (inb( port + MSB_ID_Code ) != 0x60) return 0;
       chip = tmc18c50;
 
@@ -493,8 +498,8 @@ static int fdomain_is_valid_port( int port )
 #else
 
                                /* That should have worked, but appears to
-                                   have problems.  Lets assume it is an
-                                   18c30 if the RAM is disabled. */
+                                  have problems.  Lets assume it is an
+                                  18c30 if the RAM is disabled. */
 
       if (inb( port + Configuration2 ) & 0x02) {
         chip      = tmc18c30;
@@ -1024,7 +1029,7 @@ static int fdomain_arbitrate( void )
    outb( adapter_mask, port_base + SCSI_Data_NoACK ); /* Set our id bit */
    outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
 
-   timeout = jiffies + 50;                   /* 500 mS */
+   timeout = jiffies + 50;                   /* 500 mS */
    while (jiffies < timeout) {
       status = inb( TMC_Status_port );        /* Read adapter status */
       if (status & 0x02)                     /* Arbitration complete */
@@ -1057,12 +1062,12 @@ static int fdomain_select( int target )
    /* Stop arbitration and enable parity */
    outb( PARITY_MASK, TMC_Cntl_port ); 
 
-   timeout = jiffies + 35;             /* 350mS -- because of timeouts
+   timeout = jiffies + 35;             /* 350mS -- because of timeouts
                                           (was 250mS) */
 
    while (jiffies < timeout) {
       status = inb( SCSI_Status_port ); /* Read adapter status */
-      if (status & 1) {                        /* Busy asserted */
+      if (status & 1) {                        /* Busy asserted */
         /* Enable SCSI Bus (on error, should make bus idle with 0) */
         outb( 0x80, SCSI_Cntl_port );
         return 0;
@@ -1109,10 +1114,10 @@ void fdomain_16x0_intr( int irq, struct pt_regs * regs )
    unsigned data_count;
 
                                /* The fdomain_16x0_intr is only called via
-                                   the interrupt handler.  The goal of the
-                                   sti() here is to allow other
-                                   interruptions while this routine is
-                                   running. */
+                                  the interrupt handler.  The goal of the
+                                  sti() here is to allow other
+                                  interruptions while this routine is
+                                  running. */
 
    sti();                      /* Yes, we really want sti() here */
    
@@ -1840,7 +1845,7 @@ int fdomain_16x0_biosparam( Scsi_Disk *disk, int dev, int *info_array )
       retcode = kernel_scsi_ioctl( disk->device,
                                   SCSI_IOCTL_SEND_COMMAND,
                                   (void *)buf );
-      if (!retcode                                 /* SCSI command ok */
+      if (!retcode                                 /* SCSI command ok */
          && data[511] == 0xaa && data[510] == 0x55 /* Partition table valid */
          && data[0x1c2]) {                         /* Partition type */
 
@@ -1848,7 +1853,7 @@ int fdomain_16x0_biosparam( Scsi_Disk *disk, int dev, int *info_array )
 
            Start: 0x1b3h
            Offset: 0 = partition status
-                   1 = starting head
+                   1 = starting head
                    2 = starting sector and cylinder (word, encoded)
                    4 = partition type
                    5 = ending head
@@ -1863,23 +1868,23 @@ int fdomain_16x0_biosparam( Scsi_Disk *disk, int dev, int *info_array )
            3) partitions never divide cylinders
 
            Note that (1) may be FALSE for NetBSD (and other BSD flavors),
-            as well as for Linux.  Note also, that Linux doesn't pay any
-            attention to the fields that are used by this algorithm -- it
-            only uses the absolute sector data.  Recent versions of Linux's
-            fdisk(1) will fill this data in correctly, and forthcoming
-            versions will check for consistency.
+           as well as for Linux.  Note also, that Linux doesn't pay any
+           attention to the fields that are used by this algorithm -- it
+           only uses the absolute sector data.  Recent versions of Linux's
+           fdisk(1) will fill this data in correctly, and forthcoming
+           versions will check for consistency.
 
            Checking for a non-zero partition type is not part of the
-            Future Domain algorithm, but it seemed to be a reasonable thing
-            to do, especially in the Linux and BSD worlds. */
+           Future Domain algorithm, but it seemed to be a reasonable thing
+           to do, especially in the Linux and BSD worlds. */
 
         info_array[0] = data[0x1c3] + 1;           /* heads */
         info_array[1] = data[0x1c4] & 0x3f;        /* sectors */
       } else {
 
         /* Note that this new method guarantees that there will always be
-            less than 1024 cylinders on a platter.  This is good for drives
-            up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
+           less than 1024 cylinders on a platter.  This is good for drives
+           up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
 
         if ((unsigned int)size >= 0x7e0000U) {
            info_array[0] = 0xff; /* heads   = 255 */
@@ -1898,3 +1903,10 @@ int fdomain_16x0_biosparam( Scsi_Disk *disk, int dev, int *info_array )
    
    return 0;
 }
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = FDOMAIN_16X0;
+
+#include "scsi_module.c"
+#endif
index 97f35da5314fb4d75488751e15c7a12e54aa1cb3..93908ae048f8e281ecb89c367d319d74e2310b46 100644 (file)
@@ -33,9 +33,14 @@ int        fdomain_16x0_reset( Scsi_Cmnd * );
 int        fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
 int        fdomain_16x0_biosparam( Disk *, int, int * );
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 #define FDOMAIN_16X0 { NULL,                             \
                       NULL,                             \
-                      NULL,                             \
+                      generic_proc_info,                \
+                      "fdomain",                        \
+                      PROC_SCSI_FUTURE_DOMAIN,          \
+                      NULL,                             \
                       fdomain_16x0_detect,              \
                       NULL,                             \
                       fdomain_16x0_info,                \
@@ -47,7 +52,7 @@ int        fdomain_16x0_biosparam( Disk *, int, int * );
                       fdomain_16x0_biosparam,           \
                       1,                                \
                       6,                                \
-                      64,                               \
+                      64,                               \
                       1,                                \
                       0,                                \
                       0,                                \
index dd6408ed4324bd12b8b9a0cdb84ffebd81318c22..e1b230cfc20b136a44179926b880379fd30971fd 100644 (file)
@@ -53,8 +53,9 @@ int generic_NCR5380_reset(Scsi_Cmnd *);
 
 #ifdef HOSTS_C
 
-#define GENERIC_NCR5380 {NULL, NULL, "Trantor T128/T128F/T228",        \
-       generic_NCR5380_detect, NULL, NULL, NULL,       \
+#define GENERIC_NCR5380 {NULL, NULL, generic_proc_info, "g_NCR5380",    \
+       PROC_SCSI_GENERIC_NCR5380, "Trantor T128/T128F/T228",           \
+       generic_NCR5380_detect, NULL, NULL, NULL,                       \
        generic_NCR5380_queue_command, generic_NCR5380_abort,           \
        generic_NCR5380_reset, NULL,                                    \
        NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,            \
index 862f0a5abb1146d8b85aae4fa04391e50336322b..d4549b3a5179682e231feb04fbf04360a2098426 100644 (file)
@@ -1,19 +1,19 @@
 /*
- *     hosts.c Copyright (C) 1992 Drew Eckhardt
- *             Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *  hosts.c Copyright (C) 1992 Drew Eckhardt
+ *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
- *     mid to lowlevel SCSI driver interface
- *             Initial versions: Drew Eckhardt
- *             Subsequent revisions: Eric Youngdale
+ *  mid to lowlevel SCSI driver interface
+ *      Initial versions: Drew Eckhardt
+ *      Subsequent revisions: Eric Youngdale
  *
- *     <drew@colorado.edu>
+ *  <drew@colorado.edu>
  */
 
 
 /*
- *     This file contains the medium level SCSI
- *     host interface initialization, as well as the scsi_hosts array of SCSI
- *     hosts currently present in the system.
+ *  This file contains the medium level SCSI
+ *  host interface initialization, as well as the scsi_hosts array of SCSI
+ *  hosts currently present in the system.
  */
 
 #include <linux/config.h>
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/proc_fs.h>
 
 #include "scsi.h"
 
 #include "eata_dma.h"
 #endif
 
+#ifdef CONFIG_SCSI_EATA_PIO
+#include "eata_pio.h"
+#endif
+
 #ifdef CONFIG_SCSI_U14_34F
 #include "u14-34f.h"
 #endif
@@ -113,257 +118,274 @@ static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hos
 */
 
 /*
- *     The scsi host entries should be in the order you wish the
- *     cards to be detected.  A driver may appear more than once IFF
- *     it can deal with being detected (and therefore initialized)
- *     with more than one simultaneous host number, can handle being
- *     reentrant, etc.
+ *  The scsi host entries should be in the order you wish the
+ *  cards to be detected.  A driver may appear more than once IFF
+ *  it can deal with being detected (and therefore initialized)
+ *  with more than one simultaneous host number, can handle being
+ *  reentrant, etc.
  *
- *     They may appear in any order, as each SCSI host  is told which host number it is
- *     during detection.
+ *  They may appear in any order, as each SCSI host is told which host 
+ *  number it is during detection.
  */
 
 /* This is a placeholder for controllers that are not configured into
  the system - we do this to ensure that the controller numbering is
  always consistent, no matter how the kernel is configured. */
* the system - we do this to ensure that the controller numbering is
* always consistent, no matter how the kernel is configured. */
 
 #define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
-               NULL, NULL, 0, 0, 0, 0, 0, 0}
+                          NULL, NULL, 0, 0, 0, 0, 0, 0}
 
 /*
- *     When figure is run, we don't want to link to any object code.  Since
- *     the macro for each host will contain function pointers, we cannot
- *     use it and instead must use a "blank" that does no such
- *     idiocy.
+ *  When figure is run, we don't want to link to any object code.  Since
+ *  the macro for each host will contain function pointers, we cannot
+ *  use it and instead must use a "blank" that does no such
+ *  idiocy.
  */
 
 Scsi_Host_Template * scsi_hosts = NULL;
 
 static Scsi_Host_Template builtin_scsi_hosts[] =
-       {
+{
 #ifdef CONFIG_SCSI_U14_34F
-       ULTRASTOR_14_34F,
+    ULTRASTOR_14_34F,
 #endif
 #ifdef CONFIG_SCSI_ULTRASTOR
-       ULTRASTOR_14F,
+    ULTRASTOR_14F,
 #endif
 #ifdef CONFIG_SCSI_AHA152X
-       AHA152X,
+    AHA152X,
 #endif
 /* Buslogic must come before aha1542.c */
 #ifdef CONFIG_SCSI_BUSLOGIC
-       BUSLOGIC,
+    BUSLOGIC,
 #endif
 #ifdef CONFIG_SCSI_AHA1542
-       AHA1542,
+    AHA1542,
 #endif
 #ifdef CONFIG_SCSI_AHA1740
-       AHA1740,
+    AHA1740,
 #endif
 #ifdef CONFIG_SCSI_AIC7XXX
-       AIC7XXX,
+    AIC7XXX,
 #endif
 #ifdef CONFIG_SCSI_FUTURE_DOMAIN
-       FDOMAIN_16X0,
+    FDOMAIN_16X0,
 #endif
 #ifdef CONFIG_SCSI_IN2000
-       IN2000,
+    IN2000,
 #endif
 #ifdef CONFIG_SCSI_GENERIC_NCR5380
-       GENERIC_NCR5380,
+    GENERIC_NCR5380,
 #endif
 #ifdef CONFIG_SCSI_QLOGIC
-       QLOGIC,
+    QLOGIC,
 #endif
 #ifdef CONFIG_SCSI_PAS16
-       MV_PAS16,
+    MV_PAS16,
 #endif
 #ifdef CONFIG_SCSI_SEAGATE
-       SEAGATE_ST0X,
+    SEAGATE_ST0X,
 #endif
 #ifdef CONFIG_SCSI_T128
-       TRANTOR_T128,
+    TRANTOR_T128,
 #endif
 #ifdef CONFIG_SCSI_NCR53C7xx
-       NCR53c7xx,
+    NCR53c7xx,
 #endif
 #ifdef CONFIG_SCSI_EATA_DMA
-       EATA_DMA,
+    EATA_DMA,
+#endif
+#ifdef CONFIG_SCSI_EATA_PIO
+    EATA_PIO,
 #endif
 #ifdef CONFIG_SCSI_7000FASST
-       WD7000,
+    WD7000,
 #endif
 #ifdef CONFIG_SCSI_EATA
-       EATA,
+    EATA,
 #endif
 #ifdef CONFIG_SCSI_DEBUG
-       SCSI_DEBUG,
+    SCSI_DEBUG,
 #endif
-       };
+};
 
 #define MAX_SCSI_HOSTS (sizeof(builtin_scsi_hosts) / sizeof(Scsi_Host_Template))
 
+
 /*
- *     Our semaphores and timeout counters, where size depends on MAX_SCSI_HOSTS here.
+ *  Our semaphores and timeout counters, where size depends on 
+ *      MAX_SCSI_HOSTS here.
  */
 
 struct Scsi_Host * scsi_hostlist = NULL;
-struct Scsi_Device_Template * scsi_devicelist;
+struct Scsi_Device_Template * scsi_devicelist = NULL;
 
 int max_scsi_hosts = 0;
 int next_scsi_host = 0;
 
 void
 scsi_unregister(struct Scsi_Host * sh){
-       struct Scsi_Host * shpnt;
-
-       if(scsi_hostlist == sh)
-               scsi_hostlist = sh->next;
-       else {
-               shpnt = scsi_hostlist;
-               while(shpnt->next != sh) shpnt = shpnt->next;
-               shpnt->next = shpnt->next->next;
-       };
-
-        /* If we are removing the last host registered, it is safe to reuse
-           its host number (this avoids "holes" at boot time) (DB) */
-        if (max_scsi_hosts == next_scsi_host && !scsi_loadable_module_flag)
-           max_scsi_hosts--;
-
-       next_scsi_host--;
-       scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + sh->extra_bytes);
+    struct Scsi_Host * shpnt;
+    
+    if(scsi_hostlist == sh)
+       scsi_hostlist = sh->next;
+    else {
+       shpnt = scsi_hostlist;
+       while(shpnt->next != sh) shpnt = shpnt->next;
+       shpnt->next = shpnt->next->next;
+    }
+    
+    /* If we are removing the last host registered, it is safe to reuse
+     * its host number (this avoids "holes" at boot time) (DB) 
+     */
+    if (max_scsi_hosts == next_scsi_host && !scsi_loadable_module_flag)
+       max_scsi_hosts--;
+    
+    next_scsi_host--;
+    scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + sh->extra_bytes);
 }
 
 /* We call this when we come across a new host adapter. We only do this
-   once we are 100% sure that we want to use this host adapter -  it is a
-   pain to reverse this, so we try and avoid it */
+ * once we are 100% sure that we want to use this host adapter -  it is a
+ * pain to reverse this, so we try and avoid it 
+ */
 
 struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
-       struct Scsi_Host * retval, *shpnt;
-       retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
-                                                     (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
-       retval->host_busy = 0;
-       retval->block = NULL;
-       retval->wish_block = 0;
-       if(j > 0xffff) panic("Too many extra bytes requested\n");
-       retval->extra_bytes = j;
-       retval->loaded_as_module = scsi_loadable_module_flag;
-       retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */
-       next_scsi_host++;
-       retval->host_queue = NULL;
-       retval->host_wait = NULL;
-       retval->last_reset = 0;
-       retval->irq = 0;
-       retval->dma_channel = 0xff;
-       retval->io_port = 0;
-       retval->forbidden_addr = 0;
-       retval->forbidden_size = 0;
-       retval->hostt = tpnt;
-       retval->next = NULL;
+    struct Scsi_Host * retval, *shpnt;
+    retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
+                                                 (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
+    retval->host_busy = 0;
+    retval->block = NULL;
+    retval->wish_block = 0;
+    if(j > 0xffff) panic("Too many extra bytes requested\n");
+    retval->extra_bytes = j;
+    retval->loaded_as_module = scsi_loadable_module_flag;
+    retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */
+    next_scsi_host++;
+    retval->host_queue = NULL;
+    retval->host_wait = NULL;
+    retval->last_reset = 0;
+    retval->irq = 0;
+    retval->dma_channel = 0xff;
+
+    /* These three are default values which can be overridden */
+    retval->max_channel = 0; 
+    retval->max_id = 8;      
+    retval->max_lun = 8;
+
+    retval->io_port = 0;
+    retval->forbidden_addr = 0;
+    retval->forbidden_size = 0;
+    retval->hostt = tpnt;
+    retval->next = NULL;
 #ifdef DEBUG
-       printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
-#endif
-
-       /* The next four are the default values which can be overridden
-          if need be */
-       retval->this_id = tpnt->this_id;
-       retval->can_queue = tpnt->can_queue;
-       retval->sg_tablesize = tpnt->sg_tablesize;
-       retval->cmd_per_lun = tpnt->cmd_per_lun;
-       retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
-
-       if(!scsi_hostlist)
-               scsi_hostlist = retval;
-       else
-       {
-               shpnt = scsi_hostlist;
-               while(shpnt->next) shpnt = shpnt->next;
-               shpnt->next = retval;
-       }
-
-       return retval;
+    printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
+#endif
+
+    /* The next six are the default values which can be overridden
+     * if need be */
+    retval->this_id = tpnt->this_id;
+    retval->can_queue = tpnt->can_queue;
+    retval->sg_tablesize = tpnt->sg_tablesize;
+    retval->cmd_per_lun = tpnt->cmd_per_lun;
+    retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
+    retval->use_clustering = tpnt->use_clustering;   
+    if(!scsi_hostlist)
+       scsi_hostlist = retval;
+    else
+    {
+       shpnt = scsi_hostlist;
+       while(shpnt->next) shpnt = shpnt->next;
+       shpnt->next = retval;
+    }
+    
+    return retval;
 }
 
 int
 scsi_register_device(struct Scsi_Device_Template * sdpnt)
 {
-  if(sdpnt->next) panic("Device already registered");
-  sdpnt->next = scsi_devicelist;
-  scsi_devicelist = sdpnt;
-  return 0;
+    if(sdpnt->next) panic("Device already registered");
+    sdpnt->next = scsi_devicelist;
+    scsi_devicelist = sdpnt;
+    return 0;
 }
 
 unsigned int scsi_init()
 {
-       static int called = 0;
-       int i, pcount;
-       Scsi_Host_Template * tpnt;
-       struct Scsi_Host * shpnt;
-       const char * name;
-
-       if(called) return 0;
-
-       called = 1;
-       for (tpnt = &builtin_scsi_hosts[0], i = 0; i < MAX_SCSI_HOSTS; ++i, tpnt++)
+    static int called = 0;
+    int i, pcount;
+    Scsi_Host_Template * tpnt;
+    struct Scsi_Host * shpnt;
+    const char * name;
+    
+    if(called) return 0;
+    
+    called = 1;
+    for (tpnt = &builtin_scsi_hosts[0], i = 0; i < MAX_SCSI_HOSTS; ++i, tpnt++)
+    {
+       /*
+        * Initialize our semaphores.  -1 is interpreted to mean
+        * "inactive" - where as 0 will indicate a time out condition.
+        */
+       
+       pcount = next_scsi_host;
+       if ((tpnt->detect) &&
+           (tpnt->present =
+            tpnt->detect(tpnt)))
        {
-               /*
-                * Initialize our semaphores.  -1 is interpreted to mean
-                * "inactive" - where as 0 will indicate a time out condition.
-                */
-
-               pcount = next_scsi_host;
-               if ((tpnt->detect) &&
-                   (tpnt->present =
-                    tpnt->detect(tpnt)))
-               {
-                       /* The only time this should come up is when people use
-                          some kind of patched driver of some kind or another. */
-                       if(pcount == next_scsi_host) {
-                               if(tpnt->present > 1)
-                                       panic("Failure to register low-level scsi driver");
-                               /* The low-level driver failed to register a driver.  We
-                                  can do this now. */
-                               scsi_register(tpnt,0);
-                       };
-                       tpnt->next = scsi_hosts;
-                       scsi_hosts = tpnt;
-               }
-       }
-
-
-       for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-           {
-             if(shpnt->hostt->info)
-               name = shpnt->hostt->info(shpnt);
-             else
-               name = shpnt->hostt->name;
-             printk ("scsi%d : %s\n", /* And print a little message */
-                     shpnt->host_no, name);
+           /* The only time this should come up is when people use
+            * some kind of patched driver of some kind or another. */
+           if(pcount == next_scsi_host) {
+               if(tpnt->present > 1)
+                   panic("Failure to register low-level scsi driver");
+               /* The low-level driver failed to register a driver.  We
+                * can do this now. */
+               scsi_register(tpnt,0);
            }
-
-       printk ("scsi : %d host%s.\n", next_scsi_host,
-               (next_scsi_host == 1) ? "" : "s");
-
-       scsi_make_blocked_list();
-
-       /* Now attach the high level drivers */
+           tpnt->next = scsi_hosts;
+           scsi_hosts = tpnt;
+       }
+    }
+    
+    /* Add the drivers to /proc/scsi */
+#if CONFIG_PROC_FS 
+    build_proc_dir_entries();    
+#endif
+    
+    for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+    {
+       if(shpnt->hostt->info)
+           name = shpnt->hostt->info(shpnt);
+       else
+           name = shpnt->hostt->name;
+       printk ("scsi%d : %s\n", /* And print a little message */
+               shpnt->host_no, name);
+    }
+    
+    printk ("scsi : %d host%s.\n", next_scsi_host,
+           (next_scsi_host == 1) ? "" : "s");
+    
+    scsi_make_blocked_list();
+    
+    /* Now attach the high level drivers */
 #ifdef CONFIG_BLK_DEV_SD
-       scsi_register_device(&sd_template);
+    scsi_register_device(&sd_template);
 #endif
 #ifdef CONFIG_BLK_DEV_SR
-       scsi_register_device(&sr_template);
+    scsi_register_device(&sr_template);
 #endif
 #ifdef CONFIG_CHR_DEV_ST
-       scsi_register_device(&st_template);
+    scsi_register_device(&st_template);
 #endif
 #ifdef CONFIG_CHR_DEV_SG
-       scsi_register_device(&sg_template);
+    scsi_register_device(&sg_template);
 #endif
-
+    
 #if 0      
-       max_scsi_hosts = next_scsi_host;
+    max_scsi_hosts = next_scsi_host;
 #endif
-       return 0;
+    return 0;
 }
 
 
@@ -383,7 +405,7 @@ void scsi_mem_init(unsigned long memory_end)
                }
            }
        }
-      next_host:
+    next_host:
        continue;
     }
 }
@@ -395,12 +417,14 @@ void scsi_mem_init(unsigned long memory_end)
  * of the file.
  * ---------------------------------------------------------------------------
  * Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
  * End:
  */
index 01b5f29c18a017c3d40b6bfd8d67ce1efecc7df2..c62a92652c4dbd33338aee89078d81be91fa58c9 100644 (file)
@@ -1,28 +1,29 @@
 /*
- *     hosts.h Copyright (C) 1992 Drew Eckhardt 
- *     mid to low-level SCSI driver interface header by        
- *             Drew Eckhardt 
+ *  hosts.h Copyright (C) 1992 Drew Eckhardt 
+ *  mid to low-level SCSI driver interface header by    
+ *      Drew Eckhardt 
  *
- *     <drew@colorado.edu>
+ *  <drew@colorado.edu>
  *
  *       Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  * 
- *     Further modified by Eric Youngdale to support multiple host adapters
- *     of the same type.
+ *  Further modified by Eric Youngdale to support multiple host adapters
+ *  of the same type.
  */
 
 #ifndef _HOSTS_H
 #define _HOSTS_H
 
 /*
-       $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.3 1993/09/24 12:21:00 drew Exp drew $
+    $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.3 1993/09/24 12:21:00 drew Exp drew $
 */
 
 
 /* It is senseless to set SG_ALL any higher than this - the performance
-   does not get any better, and it wastes memory */
+ *  does not get any better, and it wastes memory 
+ */
 #define SG_NONE 0
 #define SG_ALL 0xff
 
 #define ENABLE_CLUSTERING 1
 
 /* The various choices mean:
  NONE: Self evident.  Host adapter is not capable of scatter-gather.
  ALL:  Means that the host adapter module can do scatter-gather,
        and that there is no limit to the size of the table to which
-        we scatter/gather data.
-  Anything else:  Indicates the maximum number of chains that can be
-        used in one scatter-gather request.
-*/
* NONE: Self evident.  Host adapter is not capable of scatter-gather.
* ALL:  Means that the host adapter module can do scatter-gather,
*       and that there is no limit to the size of the table to which
*       we scatter/gather data.
* Anything else:  Indicates the maximum number of chains that can be
*       used in one scatter-gather request.
+ */
 
 /*
      The Scsi_Host_Template type has all that is needed to interface with a SCSI
      host in a device independent matter.  There is one entry for each different
      type of host adapter that is supported on the system.
-*/
* The Scsi_Host_Template type has all that is needed to interface with a SCSI
* host in a device independent matter.  There is one entry for each different
* type of host adapter that is supported on the system.
+ */
 
 typedef struct scsi_disk Disk;
 
 typedef struct  SHT
-       {
-
-         /* Used with loadable modules so we can construct a linked list. */
-         struct SHT * next;
-
-         /* Used with loadable modules so that we know when it is safe to unload */
-         int * usage_count;
-
-       /*
-               The name pointer is a pointer to the name of the SCSI
-               device detected.
-       */
-
-       char *name;
-
-       /*
-               The detect function shall return non zero on detection,
-               indicating the number of host adapters of this particular
-               type were found.  It should also
-               initialize all data necessary for this particular
-               SCSI driver.  It is passed the host number, so this host
-               knows where the first entry is in the scsi_hosts[] array.
-
-               Note that the detect routine MUST not call any of the mid level
-               functions to queue commands because things are not guaranteed
-               to be set up yet.  The detect routine can send commands to
-               the host adapter as long as the program control will not be
-               passed to scsi.c in the processing of the command.  Note
-               especially that scsi_malloc/scsi_free must not be called.
-       */
-
-       int (* detect)(struct SHT *); 
-
-         /* Used with loadable modules to unload the host structures.  Note:
-          there is a default action built into the modules code which may
-          be sufficient for most host adapters.  Thus you may not have to supply
-          this at all. */
-       int (*release)(struct Scsi_Host *);
-       /*
-               The info function will return whatever useful
-               information the developer sees fit.  If not provided, then
-               the name field will be used instead.
-       */
-
-        const char *(* info)(struct Scsi_Host *);
-
-       /*
-               The command function takes a target, a command (this is a SCSI 
-               command formatted as per the SCSI spec, nothing strange), a 
-               data buffer pointer, and data buffer length pointer.  The return
-               is a status int, bit fielded as follows : 
-               Byte    What
-               0       SCSI status code
-               1       SCSI 1 byte message
-               2       host error return.
-               3       mid level error return
-       */
-
-       int (* command)(Scsi_Cmnd *);
-
-        /*
-                The QueueCommand function works in a similar manner
-                to the command function.  It takes an additional parameter,
-                void (* done)(int host, int code) which is passed the host 
-               # and exit result when the command is complete.  
-               Host number is the POSITION IN THE hosts array of THIS
-               host adapter.
-        */
-
-        int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-
-       /*
-               Since the mid level driver handles time outs, etc, we want to 
-               be able to abort the current command.  Abort returns 0 if the 
-               abortion was successful.  The field SCpnt->abort reason
-               can be filled in with the appropriate reason why we wanted
-               the abort in the first place, and this will be used
-               in the mid-level code instead of the host_byte().
-               If non-zero, the code passed to it 
-               will be used as the return code, otherwise 
-               DID_ABORT  should be returned.
-
-               Note that the scsi driver should "clean up" after itself, 
-               resetting the bus, etc.  if necessary. 
-       */
-
-       int (* abort)(Scsi_Cmnd *);
-
-       /*
-               The reset function will reset the SCSI bus.  Any executing 
-               commands should fail with a DID_RESET in the host byte.
-               The Scsi_Cmnd  is passed so that the reset routine can figure
-               out which host adapter should be reset, and also which command
-               within the command block was responsible for the reset in
-               the first place.  Some hosts do not implement a reset function,
-               and these hosts must call scsi_request_sense(SCpnt) to keep
-               the command alive.
-       */ 
-
-       int (* reset)(Scsi_Cmnd *);
-       /*
-               This function is used to select synchronous communications,
-               which will result in a higher data throughput.  Not implemented
-               yet.
-       */ 
-
-       int (* slave_attach)(int, int);
-       /*
-               This function determines the bios parameters for a given
-               harddisk.  These tend to be numbers that are made up by
-               the host adapter.  Parameters:
-               size, device number, list (heads, sectors, cylinders)
-       */ 
-
-       int (* bios_param)(Disk *, int, int []);
-       
-       /*
-               This determines if we will use a non-interrupt driven
-               or an interrupt driven scheme,  It is set to the maximum number
-               of simultaneous commands a given host adapter will accept.
-       */
-       int can_queue;
-
-       /*
-               In many instances, especially where disconnect / reconnect are 
-               supported, our host also has an ID on the SCSI bus.  If this is 
-               the case, then it must be reserved.  Please set this_id to -1 if
-               your setup is in single initiator mode, and the host lacks an 
-               ID.
-       */
-       
-       int this_id;
-
-       /*
-               This determines the degree to which the host adapter is capable
-               of scatter-gather.
-       */
-
-       short unsigned int sg_tablesize;
-
-       /*
-         True if this host adapter can make good use of linked commands.
-         This will allow more than one command to be queued to a given
-         unit on a given host.  Set this to the maximum number of command
-         blocks to be provided for each device.  Set this to 1 for one
-         command block per lun, 2 for two, etc.  Do not set this to 0.
-         You should make sure that the host adapter will do the right thing
-         before you try setting this above 1.
-        */
-
-       short cmd_per_lun;
-       /*
-               present contains counter indicating how many boards of this
-               type were found when we did the scan.
-       */
-
-       unsigned char present;  
-       /*
-         true if this host adapter uses unchecked DMA onto an ISA bus.
-       */
-       unsigned unchecked_isa_dma:1;
-       /*
-         true if this host adapter can make good use of clustering.
-         I originally thought that if the tablesize was large that it
-         was a waste of CPU cycles to prepare a cluster list, but
-         it works out that the Buslogic is faster if you use a smaller
-         number of segments (i.e. use clustering).  I guess it is
-         inefficient.
-       */
-       unsigned use_clustering:1;
-       } Scsi_Host_Template;
+{
+    
+    /* Used with loadable modules so we can construct a linked list. */
+    struct SHT * next;
+    
+    /* Used with loadable modules so that we know when it is safe to unload */
+    int * usage_count;
+    
+    /* proc-fs info function.
+     * Can be used to export driver statistics and other infos to the world 
+     * outside the kernel ie. userspace and it also provides an interface
+     * to feed the driver with information. Check eata_dma_proc.c for reference.
+     */
+    int (*proc_info)(char *, char **, off_t, int, int, int);
+    
+    /* driver name that will appear in the /proc/scsi directory */
+    char *procname;
+    
+    /* low_ino of the drivers /proc/scsi entry. Defined in proc_fs.h */
+    unsigned short low_ino;
+    
+    /*
+     * The name pointer is a pointer to the name of the SCSI
+     * device detected.
+     */
+    char *name;
+    
+    /*
+     * The detect function shall return non zero on detection,
+     * indicating the number of host adapters of this particular
+     * type were found.  It should also
+     * initialize all data necessary for this particular
+     * SCSI driver.  It is passed the host number, so this host
+     * knows where the first entry is in the scsi_hosts[] array.
+     * 
+     * Note that the detect routine MUST not call any of the mid level
+     * functions to queue commands because things are not guaranteed
+     * to be set up yet.  The detect routine can send commands to
+     * the host adapter as long as the program control will not be
+     * passed to scsi.c in the processing of the command.  Note
+     * especially that scsi_malloc/scsi_free must not be called.
+     */
+    int (* detect)(struct SHT *); 
+    
+    /* Used with loadable modules to unload the host structures.  Note:
+     * there is a default action built into the modules code which may
+     * be sufficient for most host adapters.  Thus you may not have to supply
+     * this at all. 
+     */
+    int (*release)(struct Scsi_Host *);
+
+    /*
+     * The info function will return whatever useful
+     * information the developer sees fit.  If not provided, then
+     * the name field will be used instead.
+     */
+    const char *(* info)(struct Scsi_Host *);
+    
+    /*
+     * The command function takes a target, a command (this is a SCSI 
+     * command formatted as per the SCSI spec, nothing strange), a 
+     * data buffer pointer, and data buffer length pointer.  The return
+     * is a status int, bit fielded as follows : 
+     * Byte What
+     * 0    SCSI status code
+     * 1    SCSI 1 byte message
+     * 2    host error return.
+     * 3    mid level error return
+     */
+    int (* command)(Scsi_Cmnd *);
+
+    /*
+     * The QueueCommand function works in a similar manner
+     * to the command function.  It takes an additional parameter,
+     * void (* done)(int host, int code) which is passed the host 
+     * # and exit result when the command is complete.  
+     * Host number is the POSITION IN THE hosts array of THIS
+     * host adapter.
+     */
+    int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+    
+    /*
+     * Since the mid level driver handles time outs, etc, we want to 
+     * be able to abort the current command.  Abort returns 0 if the 
+     * abortion was successful.  The field SCpnt->abort reason
+     * can be filled in with the appropriate reason why we wanted
+     * the abort in the first place, and this will be used
+     * in the mid-level code instead of the host_byte().
+     * If non-zero, the code passed to it 
+     * will be used as the return code, otherwise 
+     * DID_ABORT  should be returned.
+     * 
+     * Note that the scsi driver should "clean up" after itself, 
+     * resetting the bus, etc.  if necessary. 
+     */
+    int (* abort)(Scsi_Cmnd *);
+
+    /*
+     * The reset function will reset the SCSI bus.  Any executing 
+     * commands should fail with a DID_RESET in the host byte.
+     * The Scsi_Cmnd  is passed so that the reset routine can figure
+     * out which host adapter should be reset, and also which command
+     * within the command block was responsible for the reset in
+     * the first place.  Some hosts do not implement a reset function,
+     * and these hosts must call scsi_request_sense(SCpnt) to keep
+     * the command alive.
+     */ 
+    int (* reset)(Scsi_Cmnd *);
+
+    /*
+     * This function is used to select synchronous communications,
+     * which will result in a higher data throughput.  Not implemented
+     * yet.
+     */ 
+    int (* slave_attach)(int, int);
+    
+    /*
+     * This function determines the bios parameters for a given
+     * harddisk.  These tend to be numbers that are made up by
+     * the host adapter.  Parameters:
+     * size, device number, list (heads, sectors, cylinders)
+     */ 
+    int (* bios_param)(Disk *, int, int []);
+    
+    /*
+     * This determines if we will use a non-interrupt driven
+     * or an interrupt driven scheme,  It is set to the maximum number
+     * of simultaneous commands a given host adapter will accept.
+     */
+    int can_queue;
+
+    /*
+     * In many instances, especially where disconnect / reconnect are 
+     * supported, our host also has an ID on the SCSI bus.  If this is 
+     * the case, then it must be reserved.  Please set this_id to -1 if
+     * your setup is in single initiator mode, and the host lacks an 
+     * ID.
+     */
+    int this_id;
+
+    /*
+     * This determines the degree to which the host adapter is capable
+     * of scatter-gather.
+     */
+    short unsigned int sg_tablesize;
+
+    /*
+     * True if this host adapter can make good use of linked commands.
+     * This will allow more than one command to be queued to a given
+     * unit on a given host.  Set this to the maximum number of command
+     * blocks to be provided for each device.  Set this to 1 for one
+     * command block per lun, 2 for two, etc.  Do not set this to 0.
+     * You should make sure that the host adapter will do the right thing
+     * before you try setting this above 1.
+     */
+    short cmd_per_lun;
+
+    /*
+     * present contains counter indicating how many boards of this
+     * type were found when we did the scan.
+     */
+    unsigned char present;  
+    
+    /*
+     * true if this host adapter uses unchecked DMA onto an ISA bus.
+     */
+    unsigned unchecked_isa_dma:1;
+    
+    /*
+     * true if this host adapter can make good use of clustering.
+     * I originally thought that if the tablesize was large that it
+     * was a waste of CPU cycles to prepare a cluster list, but
+     * it works out that the Buslogic is faster if you use a smaller
+     * number of segments (i.e. use clustering).  I guess it is
+     * inefficient.
+     */
+    unsigned use_clustering:1;
+
+} Scsi_Host_Template;
 
 /*
      The scsi_hosts array is the array containing the data for all 
      possible <supported> scsi hosts.   This is similar to the
      Scsi_Host_Template, except that we have one entry for each
      actual physical host adapter on the system, stored as a linked
      list.  Note that if there are 2 aha1542 boards, then there will
      be two Scsi_Host entries, but only 1 Scsi_Host_Template entries.
-*/
* The scsi_hosts array is the array containing the data for all 
* possible <supported> scsi hosts.   This is similar to the
* Scsi_Host_Template, except that we have one entry for each
* actual physical host adapter on the system, stored as a linked
* list.  Note that if there are 2 aha1542 boards, then there will
* be two Scsi_Host entries, but only 1 Scsi_Host_Template entries.
+ */
 
 struct Scsi_Host
-       {
-               struct Scsi_Host * next;
-               unsigned short extra_bytes;
-               volatile unsigned char host_busy;
-               char host_no;  /* Used for IOCTL_GET_IDLUN */
-               int last_reset;
-               struct wait_queue *host_wait;
-               Scsi_Cmnd *host_queue; 
-               Scsi_Host_Template * hostt;
-
-               /* Pointer to a circularly linked list - this indicates the hosts
-                  that should be locked out of performing I/O while we have an active
-                  command on this host. */
-               struct Scsi_Host * block;
-               unsigned wish_block:1;
-
-               /* These parameters should be set by the detect routine */
-               unsigned char *base;
-               unsigned int io_port;
-               unsigned char n_io_port;
-               unsigned char irq;
-               unsigned char dma_channel;
-
-               /*
-                 Set these if there are conflicts between memory
-                 in the < 1mb region and regions at 16mb multiples.
-                 The address must be on a page boundary.
-               */
-               unsigned long forbidden_addr;
-               unsigned long forbidden_size;
-
-               /*
-                 The rest can be copied from the template, or specifically
-                 initialized, as required.
-               */
-               
-               int this_id;
-               int can_queue;
-               short cmd_per_lun;
-               short unsigned int sg_tablesize;
-               unsigned unchecked_isa_dma:1;
-               /*
-                  True if this host was loaded as a loadable module
-               */
-               unsigned loaded_as_module:1;
-               
-               int hostdata[0];  /* Used for storage of host specific stuff */
-       };
+{
+    struct Scsi_Host * next;
+    unsigned short extra_bytes;
+    volatile unsigned char host_busy;
+    char host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
+    int last_reset;
+    struct wait_queue *host_wait;
+    Scsi_Cmnd *host_queue; 
+    Scsi_Host_Template * hostt;
+    
+    /*
+     *  These three parameters can be used to allow for wide scsi,
+     *  and for host adapters that support multiple busses 
+     *  The first two should be set to 1 more than the actual max id
+     *  or lun (i.e. 8 for normal systems).
+     */
+    unsigned int max_id;
+    unsigned int max_lun;
+    unsigned int max_channel;
+   
+    /*
+     * Pointer to a circularly linked list - this indicates the hosts
+     * that should be locked out of performing I/O while we have an active
+     * command on this host. 
+     */
+    struct Scsi_Host * block;
+    unsigned wish_block:1;
+    
+    /* These parameters should be set by the detect routine */
+    unsigned char *base;
+    unsigned int  io_port;
+    unsigned char n_io_port;
+    unsigned char irq;
+    unsigned char dma_channel;
+    
+    /*
+     * Set these if there are conflicts between memory
+     * in the < 1mb region and regions at 16mb multiples.
+     * The address must be on a page boundary.
+     */
+    unsigned long forbidden_addr;
+    unsigned long forbidden_size;
+    
+    /*
+     * The rest can be copied from the template, or specifically
+     * initialized, as required.
+     */
+    
+    int this_id;
+    int can_queue;
+    short cmd_per_lun;
+    short unsigned int sg_tablesize;
+    unsigned unchecked_isa_dma:1;
+    unsigned use_clustering:1;
+    /*
+     * True if this host was loaded as a loadable module
+     */
+    unsigned loaded_as_module:1;
+    
+    int hostdata[0];  /* Used for storage of host specific stuff */
+};
 
 extern struct Scsi_Host * scsi_hostlist;
 extern struct Scsi_Device_Template * scsi_devicelist;
@@ -284,19 +306,21 @@ extern struct Scsi_Device_Template * scsi_devicelist;
 extern Scsi_Host_Template * scsi_hosts;
 
 /*
-       scsi_init initializes the scsi hosts.
-*/
-
+ *  scsi_init initializes the scsi hosts.
+ */
 
-/* We use these goofy things because the MM is not set up when we init
-   the scsi subsystem.  By using these functions we can write code that
-   looks normal.  Also, it makes it possible to use the same code for a
-   loadable module. */
+/* 
+ * We use these goofy things because the MM is not set up when we init
+ * the scsi subsystem.  By using these functions we can write code that
+ * looks normal.  Also, it makes it possible to use the same code for a
+ * loadable module. 
+ */
 
 extern void * scsi_init_malloc(unsigned int size, int priority);
 extern void scsi_init_free(char * ptr, unsigned int size);
 
-void scan_scsis (struct Scsi_Host * shpnt);
+void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded,
+                unchar hchannel, unchar hid, unchar hlun);
 
 extern int next_scsi_host;
 
@@ -310,20 +334,22 @@ extern int scsicam_bios_param (Disk *, int, int *);
 
 struct Scsi_Device_Template
 {
-  struct Scsi_Device_Template * next;
-  char * name;
-  char * tag;
-  unsigned char scsi_type;
-  unsigned char major;
-  unsigned char nr_dev;  /* Number currently attached */
-  unsigned char dev_noticed; /* Number of devices detected. */
-  unsigned char dev_max; /* Current size of arrays */
-  unsigned blk:1;  /* 0 if character device */
-  int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
-  void (*init)(void);  /* Sizes arrays based upon number of devices detected */
-  void (*finish)(void);  /* Perform initialization after attachment */
-  int (*attach)(Scsi_Device *); /* Attach devices to arrays */
-  void (*detach)(Scsi_Device *);
+    struct Scsi_Device_Template * next;
+    char * name;
+    char * tag;
+    int * usage_count;            /* Used for loadable modules */
+    unsigned char scsi_type;
+    unsigned char major;
+    unsigned char nr_dev;         /* Number currently attached */
+    unsigned char dev_noticed;    /* Number of devices detected. */
+    unsigned char dev_max;        /* Current size of arrays */
+    unsigned blk:1;               /* 0 if character device */
+    int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
+    void (*init)(void);           /* Sizes arrays based upon number of devices
+                                  *  detected */
+    void (*finish)(void);         /* Perform initialization after attachment */
+    int (*attach)(Scsi_Device *); /* Attach devices to arrays */
+    void (*detach)(Scsi_Device *);
 };
 
 extern struct Scsi_Device_Template sd_template;
@@ -345,10 +371,10 @@ extern void scsi_unregister_module(int, void *);
 
 
 /*
- * This is an ugly hack.  If we expect to be able to load devices at run time, we need
- * to leave extra room in some of the data structures.  Doing a realloc to enlarge
- * the structures would be riddled with race conditions, so until a better solution 
- * is discovered, we use this crude approach
+ * This is an ugly hack.  If we expect to be able to load devices at run time,
+ * we need to leave extra room in some of the data structures.  Doing a 
+ * realloc to enlarge the structures would be riddled with race conditions, 
+ * so until a better solution is discovered, we use this crude approach
  */
 #define SD_EXTRA_DEVS 2
 #define ST_EXTRA_DEVS 2
@@ -363,12 +389,14 @@ extern void scsi_unregister_module(int, void *);
  * of the file.
  * ---------------------------------------------------------------------------
  * Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
  * End:
  */
index 1669732fe133f13e8411201a97d5d6bfb201dda0..0f87ed9605511a78a2a33f68666ec4045990a786 100644 (file)
  * larger SCSI hard drives (untested).
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 #include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
-
 #include <linux/sched.h>
+#include <linux/proc_fs.h>
 #include <asm/dma.h>
-
 #include <asm/system.h>
 #include <asm/io.h>
 #include "../block/blk.h"
@@ -235,7 +238,7 @@ DEB(printk("FIr:%d %02x %08x %08x\n", in2000_datalen,fic,count2,(unsigned int)in
          else if(fic > 64) count = 512;
            else if (fic > 32) count = 256;
              else if ( count2 < in2000_datalen ) /* if drive has < what we want */
-               count = in2000_datalen - count2;        /* FIFO has the rest */
+               count = in2000_datalen - count2;        /* FIFO has the rest */
        if ( count > in2000_datalen )   /* count2 is lesser of FIFO & rqst */
            count2 = in2000_datalen >> 1;       /* converted to word count */
        else
@@ -544,7 +547,7 @@ int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     outb(CONTROL,INSTAT);      /* WD BUS Mode */
     outb(0x4C,INDATA);
     if ( in2000_datalen )              /* if data xfer cmd */
-        outb(0,ININTR);                /* Enable FIFO intrpt some boards? */
+       outb(0,ININTR);         /* Enable FIFO intrpt some boards? */
     outb(COMMAND,INSTAT);
     outb(0,INNLED);
     outb(8,INDATA);            /* Select w/ATN & Transfer */
index a7564391c736f3492ca5b282da42057d9fef4ae6..764c518ab321f040c58e72b4a841cf95e59e75a2 100644 (file)
@@ -101,6 +101,7 @@ int in2000_abort(Scsi_Cmnd *);
 int in2000_reset(Scsi_Cmnd *);
 int in2000_biosparam(Disk *, int, int*);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
 
 #ifndef NULL
        #define NULL 0
@@ -108,12 +109,14 @@ int in2000_biosparam(Disk *, int, int*);
 
 /* next may be "SG_NONE" or "SG_ALL" or nr. of (1k) blocks per R/W Cmd. */
 #define IN2000_SG SG_ALL
-#define IN2000 {NULL, NULL, "Always IN2000", in2000_detect, NULL,      \
+#define IN2000 {NULL, NULL, generic_proc_info,  \
+               "in2000", PROC_SCSI_IN2000, \
+               "Always IN2000", in2000_detect, NULL,   \
                NULL, in2000_command,           \
                in2000_queuecommand,            \
                in2000_abort,                   \
                in2000_reset,                   \
-               NULL,                           \
+               NULL,                           \
                in2000_biosparam,               \
                1, 7, IN2000_SG, 1, 0, 0}
 
index 2ffbdf633734c0f0c9abcfdd3e61e25d55cda1e0..d5e9157294850ef4a988186d4bbbb3d72eb3f3b4 100644 (file)
  *     (255 is the IRQ_NONE constant in NCR5380.h)
  */
  
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 #include <asm/system.h>
 #include <linux/signal.h>
+#include <linux/proc_fs.h>
 #include <linux/sched.h>
 #include <asm/io.h>
 #include "../block/blk.h"
@@ -138,7 +143,7 @@ static struct override {
     [] = PAS16_OVERRIDE;
 #else
     [4] = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
-        {0,IRQ_AUTO}};
+       {0,IRQ_AUTO}};
 #endif
 
 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
@@ -156,18 +161,18 @@ static struct base {
 
 unsigned short  pas16_offset[ 8 ] =
     {
-        0x1c00,    /* OUTPUT_DATA_REG */
-        0x1c01,    /* INITIATOR_COMMAND_REG */
-        0x1c02,    /* MODE_REG */
-        0x1c03,    /* TARGET_COMMAND_REG */
-        0x3c00,    /* STATUS_REG ro, SELECT_ENABLE_REG wo */
-        0x3c01,    /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
-        0x3c02,    /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
-                    * START_DMA_TARGET_RECEIVE_REG wo
-                    */
-        0x3c03,    /* RESET_PARITY_INTERRUPT_REG ro,
-                    * START_DMA_INITIATOR_RECEIVE_REG wo
-                    */
+       0x1c00,    /* OUTPUT_DATA_REG */
+       0x1c01,    /* INITIATOR_COMMAND_REG */
+       0x1c02,    /* MODE_REG */
+       0x1c03,    /* TARGET_COMMAND_REG */
+       0x3c00,    /* STATUS_REG ro, SELECT_ENABLE_REG wo */
+       0x3c01,    /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
+       0x3c02,    /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
+                   * START_DMA_TARGET_RECEIVE_REG wo
+                   */
+       0x3c03,    /* RESET_PARITY_INTERRUPT_REG ro,
+                   * START_DMA_INITIATOR_RECEIVE_REG wo
+                   */
     };
 
 
@@ -205,13 +210,13 @@ void      init_board( unsigned short io_port, int irq, int force_irq )
        unsigned int    tmp;
        unsigned int    pas_irq_code;
 
-        /* Initialize the SCSI part of the board */
+       /* Initialize the SCSI part of the board */
 
-        outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG );  /* Timeout counter */
-        outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET );   /* Reset TC */
-        outb( 0x01, io_port + WAIT_STATE );   /* 1 Wait state */
+       outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG );  /* Timeout counter */
+       outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET );   /* Reset TC */
+       outb( 0x01, io_port + WAIT_STATE );   /* 1 Wait state */
 
-        NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+       NCR5380_read( RESET_PARITY_INTERRUPT_REG );
 
        /* Set the SCSI interrupt pointer without mucking up the sound
         * interrupt pointer in the same byte.
@@ -311,13 +316,13 @@ void pas16_setup(char *str, int *ints) {
     static int commandline_current = 0;
     int i;
     if (ints[0] != 2) 
-        printk("pas16_setup : usage pas16=io_port,irq\n");
+       printk("pas16_setup : usage pas16=io_port,irq\n");
     else 
-        if (commandline_current < NO_OVERRIDES) {
-            overrides[commandline_current].io_port = (unsigned short) ints[1];
-            overrides[commandline_current].irq = ints[2];
-            for (i = 0; i < NO_BASES; ++i)
-                if (bases[i].io_port == (unsigned short) ints[1]) {
+       if (commandline_current < NO_OVERRIDES) {
+           overrides[commandline_current].io_port = (unsigned short) ints[1];
+           overrides[commandline_current].irq = ints[2];
+           for (i = 0; i < NO_BASES; ++i)
+               if (bases[i].io_port == (unsigned short) ints[1]) {
                    bases[i].noauto = 1;
                    break;
                }
@@ -359,12 +364,12 @@ int pas16_detect(Scsi_Host_Template * tpnt) {
 #if (PDEBUG & PDEBUG_INIT)
     printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port);
 #endif
-               if ( !bases[current_base].noauto &&
+               if ( !bases[current_base].noauto &&
                     pas16_hw_detect( current_base ) ){
-                       io_port = bases[current_base].io_port;
+                       io_port = bases[current_base].io_port;
                        init_board( io_port, default_irqs[ current_base ], 0 ); 
 #if (PDEBUG & PDEBUG_INIT)
-                       printk("scsi-pas16 : detected board.\n");
+                       printk("scsi-pas16 : detected board.\n");
 #endif
                }
     }
@@ -397,8 +402,8 @@ int pas16_detect(Scsi_Host_Template * tpnt) {
        if (instance->irq == IRQ_NONE) {
            printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
            printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
-            /* Disable 5380 interrupts, leave drive params the same */
-            outb( 0x4d, io_port + SYS_CONFIG_4 );
+           /* Disable 5380 interrupts, leave drive params the same */
+           outb( 0x4d, io_port + SYS_CONFIG_4 );
            outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
        }
 
@@ -450,11 +455,11 @@ int pas16_biosparam(Disk * disk, int dev, int * ip)
   ip[1] = 32;
   ip[2] = size >> 11;          /* I think I have it as /(32*64) */
   if( ip[2] > 1024 ) {         /* yes, >, not >= */
-        ip[0]=255;
-        ip[1]=63;
-        ip[2]=size/(63*255);
-        if( ip[2] > 1023 )     /* yes >1023... */
-                ip[2] = 1023;
+       ip[0]=255;
+       ip[1]=63;
+       ip[2]=size/(63*255);
+       if( ip[2] > 1023 )      /* yes >1023... */
+               ip[2] = 1023;
   }
 
   return 0;
@@ -477,7 +482,7 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
     int len) {
     register unsigned char  *d = dst;
     register unsigned short reg = (unsigned short) (instance->io_port + 
-        P_DATA_REG_OFFSET);
+       P_DATA_REG_OFFSET);
     register i = len;
 
     while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) );
@@ -485,7 +490,7 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
     insb( reg, d, i );
 
     if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
-        outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+       outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
        printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
            instance->host_no);
        return -1;
@@ -517,7 +522,7 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
     outsb( reg, s, i );
 
     if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
-        outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+       outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
        printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
            instance->host_no);
        return -1;
index b2aede01c28f5c4dc4a622089f585a05ea02b0ad..f90a06593c67a82cba22641ba6f24f79eece6325 100644 (file)
@@ -120,6 +120,8 @@ int pas16_detect(Scsi_Host_Template *);
 int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int pas16_reset(Scsi_Cmnd *);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 #ifndef NULL
 #define NULL 0
 #endif
@@ -140,7 +142,8 @@ int pas16_reset(Scsi_Cmnd *);
 
 #ifdef HOSTS_C
 
-#define MV_PAS16 {NULL, NULL, "Pro Audio Spectrum-16 SCSI",            \
+#define MV_PAS16 {NULL, NULL, generic_proc_info, "pas16",  PROC_SCSI_PAS16, \
+       "Pro Audio Spectrum-16 SCSI",           \
        pas16_detect, NULL, NULL,                                       \
        NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL,      \
        pas16_biosparam,                                                \
index e1b82addf669df012540a3c7f0cb89960d4197f6..0ad4d17bc217e77c0b02862ab28d667ce2325597 100644 (file)
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
+#include <linux/proc_fs.h>
 #include <linux/unistd.h>
 #include <asm/io.h>
 #include <asm/irq.h>
index eb30cfa9103fddd7d87991add5554a0f2753a9c6..ab6af1c591f581236a6f51257625edc7f14966f7 100644 (file)
@@ -9,6 +9,8 @@ int qlogic_abort(Scsi_Cmnd *);
 int qlogic_reset(Scsi_Cmnd *);
 int qlogic_biosparam(Disk *,int,int[]);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 #ifndef NULL
 #define NULL (0)
 #endif
@@ -16,6 +18,9 @@ int qlogic_biosparam(Disk *,int,int[]);
 #define QLOGIC {               \
        NULL,                   \
        NULL,                   \
+       generic_proc_info,      \
+       "qlogic",               \
+       PROC_SCSI_QLOGIC,       \
        NULL,                   \
        qlogic_detect,          \
        NULL,                   \
index 746a31b70ee71c90ad92474e0c593c17aeae0caa..16d743c2e646310f1326fd1cd600c6c842df86cb 100644 (file)
@@ -1,21 +1,24 @@
 /*
- *     scsi.c Copyright (C) 1992 Drew Eckhardt
- *            Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *  scsi.c Copyright (C) 1992 Drew Eckhardt
+ *         Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
- *     generic mid-level SCSI driver
- *             Initial versions: Drew Eckhardt
- *             Subsequent revisions: Eric Youngdale
+ *  generic mid-level SCSI driver
+ *      Initial versions: Drew Eckhardt
+ *      Subsequent revisions: Eric Youngdale
  *
- *     <drew@colorado.edu>
+ *  <drew@colorado.edu>
  *
- *     Bug correction thanks go to :
- *             Rik Faith <faith@cs.unc.edu>
- *             Tommy Thorn <tthorn>
- *             Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
+ *  Bug correction thanks go to :
+ *      Rik Faith <faith@cs.unc.edu>
+ *      Tommy Thorn <tthorn>
+ *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
  *
- *       Modified by Eric Youngdale ericy@cais.com to
- *       add scatter-gather, multiple outstanding request, and other
- *       enhancements.
+ *  Modified by Eric Youngdale ericy@cais.com to
+ *  add scatter-gather, multiple outstanding request, and other
+ *  enhancements.
+ *
+ *  Native multichannel and wide scsi support added 
+ *  by Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
  */
 
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
 #include <linux/ioport.h>
+#include <linux/kernel.h>
 
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
 #include "constants.h"
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
 #undef USE_STATIC_SCSI_MEMORY
 
 /*
@@ -52,29 +64,29 @@ static int time_start;
 static int time_elapsed;
 static volatile struct Scsi_Host * host_active = NULL;
 #define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
-                  || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
+                         || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
 
 #define MAX_SCSI_DEVICE_CODE 10
 const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
 {
- "Direct-Access    ",
- "Sequential-Access",
- "Printer          ",
- "Processor        ",
- "WORM             ",
- "CD-ROM           ",
- "Scanner          ",
- "Optical Device   ",
- "Medium Changer   ",
- "Communications   "
   "Direct-Access    ",
   "Sequential-Access",
   "Printer          ",
   "Processor        ",
   "WORM             ",
   "CD-ROM           ",
   "Scanner          ",
   "Optical Device   ",
   "Medium Changer   ",
   "Communications   "
 };
 
 
 /*
      global variables :
      scsi_devices an array of these specifying the address for each
      (host, id, LUN)
-*/
* global variables :
* scsi_devices an array of these specifying the address for each
* (host, id, LUN)
+ */
 
 Scsi_Device * scsi_devices = NULL;
 
@@ -86,27 +98,33 @@ static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
 /* This variable is merely a hook so that we can debug the kernel with gdb. */
 Scsi_Cmnd * last_cmnd = NULL;
 
+/* This is the pointer to the /proc/scsi code. 
+ * It is only initialized to !=0 if the scsi code is present 
+ */ 
+extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, off_t offset, int length, int inout); 
+extern int dispatch_scsi_info(int ino, char *buffer, char **start, off_t offset, int length, int inout); 
+
 /*
- *     As the scsi do command functions are intelligent, and may need to
- *     redo a command, we need to keep track of the last command
- *     executed on each one.
+ *  As the scsi do command functions are intelligent, and may need to
+ *  redo a command, we need to keep track of the last command
+ *  executed on each one.
  */
 
-#define WAS_RESET      0x01
-#define WAS_TIMEDOUT   0x02
-#define WAS_SENSE      0x04
-#define IS_RESETTING   0x08
-#define IS_ABORTING    0x10
+#define WAS_RESET       0x01
+#define WAS_TIMEDOUT    0x02
+#define WAS_SENSE       0x04
+#define IS_RESETTING    0x08
+#define IS_ABORTING     0x10
 #define ASKED_FOR_SENSE 0x20
 
 /*
- *     This is the number  of clock ticks we should wait before we time out
- *     and abort the command.  This is for  where the scsi.c module generates
- *     the command, not where it originates from a higher level, in which
- *     case the timeout is specified there.
+ *  This is the number  of clock ticks we should wait before we time out
+ *  and abort the command.  This is for  where the scsi.c module generates
+ *  the command, not where it originates from a higher level, in which
+ *  case the timeout is specified there.
  *
- *     ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
- *     respectively.
+ *  ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
+ *  respectively.
  */
 
 #ifdef DEBUG_TIMEOUT
@@ -115,19 +133,19 @@ static void scsi_dump_status(void);
 
 
 #ifdef DEBUG
-       #define SCSI_TIMEOUT (5*HZ)
+    #define SCSI_TIMEOUT (5*HZ)
 #else
-       #define SCSI_TIMEOUT (1*HZ)
+    #define SCSI_TIMEOUT (1*HZ)
 #endif
 
 #ifdef DEBUG
-       #define SENSE_TIMEOUT SCSI_TIMEOUT
-       #define ABORT_TIMEOUT SCSI_TIMEOUT
-       #define RESET_TIMEOUT SCSI_TIMEOUT
+    #define SENSE_TIMEOUT SCSI_TIMEOUT
+    #define ABORT_TIMEOUT SCSI_TIMEOUT
+    #define RESET_TIMEOUT SCSI_TIMEOUT
 #else
-       #define SENSE_TIMEOUT (5*HZ/10)
-       #define RESET_TIMEOUT (5*HZ/10)
-       #define ABORT_TIMEOUT (5*HZ/10)
+    #define SENSE_TIMEOUT (5*HZ/10)
+    #define RESET_TIMEOUT (5*HZ/10)
+    #define ABORT_TIMEOUT (5*HZ/10)
 #endif
 
 #define MIN_RESET_DELAY (1*HZ)
@@ -136,148 +154,153 @@ static void scsi_dump_status(void);
 #define MIN_RESET_PERIOD (10*HZ)
 
 /* The following devices are known not to tolerate a lun != 0 scan for
-   one reason or another.  Some will respond to all luns, others will
-   lock up. */
+ * one reason or another.  Some will respond to all luns, others will
+ * lock up. 
+ */
 
-     struct blist{
-       char * vendor;
-       char * model;
-       char * revision; /* Latest revision known to be bad.  Not used yet */
-     };
+struct blist{
+    char * vendor;
+    char * model;
+    char * revision; /* Latest revision known to be bad.  Not used yet */
+};
 
 static struct blist blacklist[] =
 {
-   {"CHINON","CD-ROM CDS-431","H42"},  /* Locks up if polled for lun != 0 */
-   {"CHINON","CD-ROM CDS-535","Q14"}, /* Lockup if polled for lun != 0 */
-   {"DENON","DRD-25X","V"},   /* A cdrom that locks up when probed at lun != 0 */
-   {"HITACHI","DK312C","CM81"},   /* Responds to all lun - dtg */
-   {"HITACHI","DK314C","CR21" }, /* responds to all lun */
-   {"IMS", "CDD521/10","2.06"},   /* Locks-up when LUN>0 polled. */
-   {"MAXTOR","XT-3280","PR02"},   /* Locks-up when LUN>0 polled. */
-   {"MAXTOR","XT-4380S","B3C"},   /* Locks-up when LUN>0 polled. */
-   {"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */
-   {"MAXTOR","XT-4170S","B5A"},   /* Locks-up sometimes when LUN>0 polled. */
-   {"MAXTOR","XT-8760S","B7B"},   /* guess what? */
-   {"NEC","CD-ROM DRIVE:841","1.0"},  /* Locks-up when LUN>0 polled. */
-   {"RODIME","RO3000S","2.33"},  /* Locks up if polled for lun != 0 */
-   {"SEAGATE", "ST157N", "\004|j"}, /* causes failed REQUEST SENSE on lun 1 for aha152x
-                                    * controller, which causes SCSI code to reset bus.*/
-   {"SEAGATE", "ST296","921"},   /* Responds to all lun */
-   {"SONY","CD-ROM CDU-541","4.3d"},
-   {"SONY","CD-ROM CDU-55S","1.0i"},
-   {"TANDBERG","TDC 3600","U07"},  /* Locks up if polled for lun != 0 */
-   {"TEAC","CD-ROM","1.06"},   /* causes failed REQUEST SENSE on lun 1 for seagate
-                                * controller, which causes SCSI code to reset bus.*/
-   {"TEXEL","CD-ROM","1.06"},   /* causes failed REQUEST SENSE on lun 1 for seagate
-                                * controller, which causes SCSI code to reset bus.*/
-   {"QUANTUM","LPS525S","3110"},/* Locks sometimes if polled for lun != 0 */
-   {"QUANTUM","PD1225S","3110"},/* Locks sometimes if polled for lun != 0 */
-   {"MEDIAVIS","CDR-H93MV","1.31"},  /* Locks up if polled for lun != 0 */
-   {"SANKYO", "CP525","6.64"},  /* causes failed REQ SENSE, extra reset */
-   {"HP", "C1750A", "3226"},    /* scanjet iic */
-   {"HP", "C1790A", ""},       /* scanjet iip */
-   {"HP", "C2500A", ""},       /* scanjet iicx */
-   {NULL, NULL, NULL}};
+{"CHINON","CD-ROM CDS-431","H42"}, /* Locks up if polled for lun != 0 */
+{"CHINON","CD-ROM CDS-535","Q14"}, /* Locks up if polled for lun != 0 */
+{"DENON","DRD-25X","V"},           /* Locks up if probed for lun != 0 */
+{"HITACHI","DK312C","CM81"},       /* Responds to all lun - dtg */
+{"HITACHI","DK314C","CR21" },      /* responds to all lun */
+{"IMS", "CDD521/10","2.06"},       /* Locks-up when LUN>0 polled. */
+{"MAXTOR","XT-3280","PR02"},       /* Locks-up when LUN>0 polled. */
+{"MAXTOR","XT-4380S","B3C"},       /* Locks-up when LUN>0 polled. */
+{"MAXTOR","MXT-1240S","I1.2"},     /* Locks up when LUN>0 polled */
+{"MAXTOR","XT-4170S","B5A"},       /* Locks-up sometimes when LUN>0 polled. */
+{"MAXTOR","XT-8760S","B7B"},       /* guess what? */
+{"NEC","CD-ROM DRIVE:841","1.0"},  /* Locks-up when LUN>0 polled. */
+{"RODIME","RO3000S","2.33"},       /* Locks up if polled for lun != 0 */
+{"SEAGATE", "ST157N", "\004|j"},   /* causes failed REQUEST SENSE on lun 1 
+                                   * for aha152x controller, which causes 
+                                   * SCSI code to reset bus.*/
+{"SEAGATE", "ST296","921"},        /* Responds to all lun */
+{"SONY","CD-ROM CDU-541","4.3d"},
+{"SONY","CD-ROM CDU-55S","1.0i"},
+{"TANDBERG","TDC 3600","U07"},     /* Locks up if polled for lun != 0 */
+{"TEAC","CD-ROM","1.06"},          /* causes failed REQUEST SENSE on lun 1 
+                                   * for seagate controller, which causes 
+                                   * SCSI code to reset bus.*/
+{"TEXEL","CD-ROM","1.06"},         /* causes failed REQUEST SENSE on lun 1 
+                                   * for seagate controller, which causes 
+                                   * SCSI code to reset bus.*/
+{"QUANTUM","LPS525S","3110"},      /* Locks sometimes if polled for lun != 0 */
+{"QUANTUM","PD1225S","3110"},      /* Locks sometimes if polled for lun != 0 */
+{"MEDIAVIS","CDR-H93MV","1.31"},   /* Locks up if polled for lun != 0 */
+{"SANKYO", "CP525","6.64"},        /* causes failed REQ SENSE, extra reset */
+{"HP", "C1750A", "3226"},          /* scanjet iic */
+{"HP", "C1790A", ""},              /* scanjet iip */
+{"HP", "C2500A", ""},              /* scanjet iicx */
+{NULL, NULL, NULL}
+};
 
 static int blacklisted(unsigned char * response_data){
-  int i = 0;
-  unsigned char * pnt;
-  for(i=0; 1; i++){
-    if(blacklist[i].vendor == NULL) return 0;
-    pnt = &response_data[8];
-    while(*pnt && *pnt == ' ') pnt++;
-    if(memcmp(blacklist[i].vendor, pnt,
-              strlen(blacklist[i].vendor))) continue;
-    pnt = &response_data[16];
-    while(*pnt && *pnt == ' ') pnt++;
-    if(memcmp(blacklist[i].model, pnt,
-              strlen(blacklist[i].model))) continue;
-    return 1;
-  }
+    int i = 0;
+    unsigned char * pnt;
+    for(i=0; 1; i++){
+       if(blacklist[i].vendor == NULL) return 0;
+       pnt = &response_data[8];
+       while(*pnt && *pnt == ' ') pnt++;
+       if(memcmp(blacklist[i].vendor, pnt,
+                 strlen(blacklist[i].vendor))) continue;
+       pnt = &response_data[16];
+       while(*pnt && *pnt == ' ') pnt++;
+       if(memcmp(blacklist[i].model, pnt,
+                 strlen(blacklist[i].model))) continue;
+       return 1;
+    }
 }
 
 /*
- *     As the actual SCSI command runs in the background, we must set up a
- *     flag that tells scan_scsis() when the result it has is valid.
- *     scan_scsis can set the_result to -1, and watch for it to become the
- *     actual return code for that call.  the scan_scsis_done function() is
- *     our user specified completion function that is passed on to the
- *     scsi_do_cmd() function.
+ *  As the actual SCSI command runs in the background, we must set up a
+ *  flag that tells scan_scsis() when the result it has is valid.
+ *  scan_scsis can set the_result to -1, and watch for it to become the
+ *  actual return code for that call.  the scan_scsis_done function() is
+ *  our user specified completion function that is passed on to the
+ *  scsi_do_cmd() function.
  */
 
 volatile int in_scan_scsis = 0;
 static int the_result;
 
 void scsi_make_blocked_list(void)  {
-  int block_count = 0, index;
-  unsigned int flags;
-  struct Scsi_Host * sh[128], * shpnt;
-
-  /*
-   * Create a circular linked list from the scsi hosts which have
-   * the "wish_block" field in the Scsi_Host structure set.
-   * The blocked list should include all the scsi hosts using ISA DMA.
-   * In some systems, using two dma channels simultaneously causes
-   * unpredictable results.
-   * Among the scsi hosts in the blocked list, only one host at a time
-   * is allowed to have active commands queued. The transition from
-   * one active host to the next one is allowed only when host_busy == 0
-   * for the active host (which implies host_busy == 0 for all the hosts
-   * in the list). Moreover for block devices the transition to a new
-   * active host is allowed only when a request is completed, since a
-   * block device request can be divided into multiple scsi commands
-   * (when there are few sg lists or clustering is disabled).
-   *
-   * (DB, 4 Feb 1995)
-   */
-
-  save_flags(flags);
-  cli();
-  host_active = NULL;
-
-  for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
-
+    int block_count = 0, index;
+    unsigned int flags;
+    struct Scsi_Host * sh[128], * shpnt;
+    
+    /*
+     * Create a circular linked list from the scsi hosts which have
+     * the "wish_block" field in the Scsi_Host structure set.
+     * The blocked list should include all the scsi hosts using ISA DMA.
+     * In some systems, using two dma channels simultaneously causes
+     * unpredictable results.
+     * Among the scsi hosts in the blocked list, only one host at a time
+     * is allowed to have active commands queued. The transition from
+     * one active host to the next one is allowed only when host_busy == 0
+     * for the active host (which implies host_busy == 0 for all the hosts
+     * in the list). Moreover for block devices the transition to a new
+     * active host is allowed only when a request is completed, since a
+     * block device request can be divided into multiple scsi commands
+     * (when there are few sg lists or clustering is disabled).
+     *
+     * (DB, 4 Feb 1995)
+     */
+    
+    save_flags(flags);
+    cli();
+    host_active = NULL;
+    
+    for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
+       
 #if 0
-     /*
-      * Is this is a candidate for the blocked list?
-      * Useful to put into the blocked list all the hosts whose driver
-      * does not know about the host->block feature.
-      */
-     if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1;
+       /*
+        * Is this is a candidate for the blocked list?
+        * Useful to put into the blocked list all the hosts whose driver
+        * does not know about the host->block feature.
+        */
+       if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1;
 #endif
-
-     if (shpnt->wish_block) sh[block_count++] = shpnt;
-     }
-
-  if (block_count == 1) sh[0]->block = NULL;
-
-  else if (block_count > 1) {
-
-     for(index = 0; index < block_count - 1; index++) {
-       sh[index]->block = sh[index + 1];
+       
+       if (shpnt->wish_block) sh[block_count++] = shpnt;
+    }
+    
+    if (block_count == 1) sh[0]->block = NULL;
+    
+    else if (block_count > 1) {
+       
+       for(index = 0; index < block_count - 1; index++) {
+           sh[index]->block = sh[index + 1];
+           printk("scsi%d : added to blocked host list.\n",
+                  sh[index]->host_no);
+       }
+       
+       sh[block_count - 1]->block = sh[0];
        printk("scsi%d : added to blocked host list.\n",
               sh[index]->host_no);
-       }
-
-     sh[block_count - 1]->block = sh[0];
-     printk("scsi%d : added to blocked host list.\n",
-           sh[index]->host_no);
-     }
-
-  restore_flags(flags);
-  }
+    }
+    
+    restore_flags(flags);
+}
 
 static void scan_scsis_done (Scsi_Cmnd * SCpnt)
-       {
-
+{
+    
 #ifdef DEBUG
-       printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
+    printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
 #endif
-       SCpnt->request.dev = 0xfffe;
-
-       if (SCpnt->request.sem != NULL)
-         up(SCpnt->request.sem);
-       }
+    SCpnt->request.dev = 0xfffe;
+    
+    if (SCpnt->request.sem != NULL)
+       up(SCpnt->request.sem);
+}
 
 #ifdef CONFIG_SCSI_MULTI_LUN
 static int max_scsi_luns = 8;
@@ -293,862 +316,952 @@ void scsi_luns_setup(char *str, int *ints) {
 }
 
 /*
- *     Detecting SCSI devices :
- *     We scan all present host adapter's busses,  from ID 0 to ID 6.
- *     We use the INQUIRY command, determine device type, and pass the ID /
- *     lun address of all sequential devices to the tape driver, all random
- *     devices to the disk driver.
+ *  Detecting SCSI devices :
+ *  We scan all present host adapter's busses,  from ID 0 to ID 6.
+ *  We use the INQUIRY command, determine device type, and pass the ID /
+ *  lun address of all sequential devices to the tape driver, all random
+ *  devices to the disk driver.
  */
 
-void scan_scsis (struct Scsi_Host * shpnt)
+void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, 
+                unchar hchannel, unchar hid, unchar hlun)
 {
-  int dev, lun, type;
-  unsigned char scsi_cmd [12];
-  unsigned char scsi_result0 [256];
-  unsigned char * scsi_result;
-  Scsi_Device * SDpnt, *SDtail;
-  struct Scsi_Device_Template * sdtpnt;
-  Scsi_Cmnd  *SCpnt;
-
-  ++in_scan_scsis;
-  lun = 0;
-  type = -1;
-  SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC|GFP_DMA);
-  SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
-  SDtail = scsi_devices;
-
-  if(scsi_devices) while(SDtail->next) SDtail = SDtail->next;
-
-  /* Make sure we have something that is valid for DMA purposes */
-  scsi_result = ((current == task[0]  || !shpnt->unchecked_isa_dma)
-                ?  &scsi_result0[0] : scsi_malloc(512));
-
-
-  shpnt->host_queue = SCpnt;  /* We need this so that commands can time out */
-
-  for (dev = 0; dev < 8; ++dev)
-    if (shpnt->this_id != dev)
-
-/*
- * We need the for so our continue, etc. work fine.
- */
-      for (lun = 0; lun < max_scsi_luns; ++lun)
-       {
-         memset(SDpnt, 0, sizeof(Scsi_Device));
-         SDpnt->host = shpnt;
-         SDpnt->id = dev;
-         SDpnt->lun = lun;
-
-         /* Some low level driver could use device->type (DB) */
-         SDpnt->type = -1;
-/*
- * Assume that the device will have handshaking problems, and then
- * fix this field later if it turns out it doesn't.
- */
-         SDpnt->borken = 1;
-
-         scsi_cmd[0] = TEST_UNIT_READY;
-         scsi_cmd[1] = lun << 5;
-         scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
-
-         memset(SCpnt, 0,  sizeof(Scsi_Cmnd));
-         SCpnt->host = SDpnt->host;
-         SCpnt->device = SDpnt;
-         SCpnt->target = SDpnt->id;
-         SCpnt->lun = SDpnt->lun;
-
-         /* Used for mutex if loading devices after boot */
-         SCpnt->request.sem = NULL;
-
-         SCpnt->request.dev = 0xffff; /* Mark not busy */
-
-         scsi_do_cmd (SCpnt, (void *)  scsi_cmd, (void *) scsi_result,
-                      256,  scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
-
-         /* Wait for command to finish. Use simple wait if we are booting, else
-            do it right and use a mutex */
-
-         if (current == task[0])
-             while (SCpnt->request.dev != 0xfffe) barrier();
-         else if (SCpnt->request.dev != 0xfffe) {
-             struct semaphore sem = MUTEX_LOCKED;
-
-             SCpnt->request.sem = &sem;
-             down(&sem);
-
-             /* Hmm.. Have to ask about this one */
-             while (SCpnt->request.dev != 0xfffe) schedule();
-             }
+    int dev, lun, type, channel;
+    unsigned char scsi_cmd [12];
+    unsigned char scsi_result0 [256];
+    unsigned char * scsi_result;
+    Scsi_Device * SDpnt, *SDtail;
+    struct Scsi_Device_Template * sdtpnt;
+    Scsi_Cmnd  *SCpnt;
+    
+    ++in_scan_scsis;
+    lun = 0;
+    type = -1;
+    SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC|GFP_DMA);
+    SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
+    SDtail = scsi_devices;
+    
+    if(scsi_devices) while(SDtail->next) SDtail = SDtail->next;
+    
+    /* Make sure we have something that is valid for DMA purposes */
+    scsi_result = ((current->pid == 0  || !shpnt->unchecked_isa_dma)
+                  ?  &scsi_result0[0] : scsi_malloc(512));
+    
+    if(scsi_result == NULL) {
+       printk("Unable to obtain scsi_result buffer\n");
+       goto leave;
+    }
+    
+    shpnt->host_queue = SCpnt; /* We need this so that commands can time out */
+
+    if(hardcoded == 1) {
+       channel = hchannel;
+       dev = hid;
+       lun = hlun;
+       goto crude;
+    }
 
+    for (channel = 0; channel <= shpnt->max_channel; channel++)
+    {
+       for (dev = 0; dev < shpnt->max_id; ++dev) {
+           if (shpnt->this_id != dev) {
+               
+               /*
+                * We need the for so our continue, etc. work fine.
+                */
+               for (lun = 0; lun < (max_scsi_luns < shpnt->max_lun ? 
+                                    max_scsi_luns : shpnt->max_lun); ++lun)
+               {
+               crude:
+                   memset(SDpnt, 0, sizeof(Scsi_Device));
+                   SDpnt->host = shpnt;
+                   SDpnt->id = dev;
+                   SDpnt->lun = lun;
+                   SDpnt->channel = channel;
+
+                   /* Some low level driver could use device->type (DB) */
+                   SDpnt->type = -1;
+                   /*
+                    * Assume that the device will have handshaking problems, 
+                    * and then fix this field later if it turns out it doesn't
+                    */
+                   SDpnt->borken = 1;
+                   
+                   scsi_cmd[0] = TEST_UNIT_READY;
+                   scsi_cmd[1] = lun << 5;
+                   scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+                   
+                   memset(SCpnt, 0,  sizeof(Scsi_Cmnd));
+                   SCpnt->host = SDpnt->host;
+                   SCpnt->device = SDpnt;
+                   SCpnt->target = SDpnt->id;
+                   SCpnt->lun = SDpnt->lun;
+                   SCpnt->channel = SDpnt->channel;
+
+                   /* Used for mutex if loading devices after boot */
+                   SCpnt->request.sem = NULL;
+                   
+                   SCpnt->request.dev = 0xffff; /* Mark not busy */
+                   
+                   scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
+                                (void *) scsi_result,
+                                256,  scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
+                   
+                   /* 
+                    * Wait for command to finish. Use simple wait if we are 
+                    * booting, else do it right and use a mutex 
+                    */
+                   
+                   if (current->pid == 0)
+                       while (SCpnt->request.dev != 0xfffe) 
+                           barrier();
+                   else if (SCpnt->request.dev != 0xfffe) {
+                       struct semaphore sem = MUTEX_LOCKED;
+                       
+                       SCpnt->request.sem = &sem;
+                       down(&sem);
+                       
+                       /* Hmm.. Have to ask about this one */
+                       while (SCpnt->request.dev != 0xfffe) schedule();
+                   }
+                   
 #if defined(DEBUG) || defined(DEBUG_INIT)
-         printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
-         printk("scsi: return code %08x\n", SCpnt->result);
+                   printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
+                   printk("scsi: return code %08x\n", SCpnt->result);
 #endif
 
-
-         if(SCpnt->result) {
-           if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
-                (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
-               ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
-             if (SCpnt->sense_buffer[2] &0xe0)
-               continue; /* No devices here... */
-             if(((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
-                ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION))
-               continue;
-           }
-           else
-             break;
-         }
-
+                   if(SCpnt->result) {
+                       if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
+                            (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
+                           ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
+                           if (SCpnt->sense_buffer[2] &0xe0)
+                               continue; /* No devices here... */
+                           if(((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
+                              ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION))
+                               continue;
+                       }
+                       else
+                           break;
+                   }
+                   
 #if defined (DEBUG) || defined(DEBUG_INIT)
-         printk("scsi: performing INQUIRY\n");
-#endif
-
-         /*
-          * Build an INQUIRY command block.
-          */
-         scsi_cmd[0] = INQUIRY;
-         scsi_cmd[1] = (lun << 5) & 0xe0;
-         scsi_cmd[2] = 0;
-         scsi_cmd[3] = 0;
-         scsi_cmd[4] = 255;
-         scsi_cmd[5] = 0;
-
-         SCpnt->request.dev = 0xffff; /* Mark not busy */
-         SCpnt->cmd_len = 0;
-
-         scsi_do_cmd (SCpnt, (void *)  scsi_cmd, (void *) scsi_result,
-                      256,  scan_scsis_done, SCSI_TIMEOUT, 3);
-
-         if (current == task[0])
-             while (SCpnt->request.dev != 0xfffe) barrier();
-         else if (SCpnt->request.dev != 0xfffe) {
-             struct semaphore sem = MUTEX_LOCKED;
-
-             SCpnt->request.sem = &sem;
-             down(&sem);
-
-             /* Hmm.. Have to ask about this one */
-             while (SCpnt->request.dev != 0xfffe) schedule();
-             }
-
-         the_result = SCpnt->result;
-
-#if defined(DEBUG) || defined(DEBUG_INIT)
-         if (!the_result)
-           printk("scsi: INQUIRY successful\n");
-         else
-           printk("scsi: INQUIRY failed with code %08x\n", the_result);
-#endif
-
-         if(the_result) break;
-
-         /* skip other luns on this device */
-
-         if (!the_result)
-           {
-               /* It would seem some TOSHIBA CD-ROM gets things wrong */
-               if (!strncmp(scsi_result+8,"TOSHIBA",7) &&
-                   !strncmp(scsi_result+16,"CD-ROM",6) &&
-                   scsi_result[0] == TYPE_DISK) {
-                       scsi_result[0] = TYPE_ROM;
-                       scsi_result[1] |= 0x80;  /* removable */
-               }
-
-             if (!strncmp(scsi_result+8,"NEC",3)) {
-                 if (!strncmp(scsi_result+16,"CD-ROM DRIVE:84 ",16) ||
-                     !strncmp(scsi_result+16,"CD-ROM DRIVE:25",15))
-                     SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR;
-                 else
-                     SDpnt->manufacturer = SCSI_MAN_NEC;
-             } else if (!strncmp(scsi_result+8,"TOSHIBA",7))
-                 SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
-             else
-                 SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
-
-             SDpnt->removable = (0x80 &
-                                 scsi_result[1]) >> 7;
-             SDpnt->lockable = SDpnt->removable;
-             SDpnt->changed = 0;
-             SDpnt->access_count = 0;
-             SDpnt->busy = 0;
-/*
- *     Currently, all sequential devices are assumed to be tapes,
- *     all random devices disk, with the appropriate read only
- *     flags set for ROM / WORM treated as RO.
- */
-
-             switch (type = (scsi_result[0] & 0x1f))
-               {
-               case TYPE_TAPE :
-               case TYPE_DISK :
-               case TYPE_MOD :
-               case TYPE_PROCESSOR :
-               case TYPE_SCANNER :
-                 SDpnt->writeable = 1;
-                 break;
-               case TYPE_WORM :
-               case TYPE_ROM :
-                 SDpnt->writeable = 0;
-                 break;
-               default :
-#if 0
-#ifdef DEBUG
-                 printk("scsi: unknown type %d\n", type);
-                 print_inquiry(scsi_result);
-#endif
-                 type = -1;
+                   printk("scsi: performing INQUIRY\n");
 #endif
-               }
-
-             SDpnt->soft_reset =
-               (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
-             SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
-             SDpnt->type = (type & 0x1f);
-
-             if (type != -1)
-               {
-                 print_inquiry(scsi_result);
-
-                 for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-                   if(sdtpnt->detect) SDpnt->attached +=
-                     (*sdtpnt->detect)(SDpnt);
-
-                 SDpnt->scsi_level = scsi_result[2] & 0x07;
-                 if (SDpnt->scsi_level >= 2 ||
-                     (SDpnt->scsi_level == 1 &&
-                      (scsi_result[3] & 0x0f) == 1))
-                   SDpnt->scsi_level++;
-/*
- * Set the tagged_queue flag for SCSI-II devices that purport to support
- * tagged queuing in the INQUIRY data.
- */
-
-                 SDpnt->tagged_queue = 0;
-
-                 if ((SDpnt->scsi_level >= SCSI_2) &&
-                     (scsi_result[7] & 2)) {
-                   SDpnt->tagged_supported = 1;
-                   SDpnt->current_tag = 0;
-                 }
-
-/*
- * Accommodate drivers that want to sleep when they should be in a polling
- * loop.
- */
-
-                 SDpnt->disconnect = 0;
-
-/*
- * Some revisions of the Texel CD ROM drives have handshaking
- * problems when used with the Seagate controllers.  Before we
- * know what type of device we're talking to, we assume it's
- * borken and then change it here if it turns out that it isn't
- * a TEXEL drive.
- */
-
-                 if(strncmp("TEXEL", (char *) &scsi_result[8], 5) != 0 ||
-                    strncmp("CD-ROM", (char *) &scsi_result[16], 6) != 0
-/*
- * XXX 1.06 has problems, some one should figure out the others too so
- * ALL TEXEL drives don't suffer in performance, especially when I finish
- * integrating my seagate patches which do multiple I_T_L nexuses.
- */
 
-#ifdef notyet
-                    || (strncmp("1.06", (char *) &scsi_result[[, 4) != 0)))
-#endif
-                                )
-                   SDpnt->borken = 0;
-
-
-                 /* These devices need this "key" to unlock the device
-                    so we can use it */
-                 if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
-                    (memcmp("Floptical   F*8I", &scsi_result[16], 16) == 0
-                     || memcmp("I325VM", &scsi_result[16], 6) == 0)) {
-                   printk("Unlocked floptical drive.\n");
-                   SDpnt->lockable = 0;
-                   scsi_cmd[0] = MODE_SENSE;
+                   /*
+                    * Build an INQUIRY command block.
+                    */
+                   scsi_cmd[0] = INQUIRY;
                    scsi_cmd[1] = (lun << 5) & 0xe0;
-                   scsi_cmd[2] = 0x2e;
+                   scsi_cmd[2] = 0;
                    scsi_cmd[3] = 0;
-                   scsi_cmd[4] = 0x2a;
+                   scsi_cmd[4] = 255;
                    scsi_cmd[5] = 0;
-
+                   
                    SCpnt->request.dev = 0xffff; /* Mark not busy */
                    SCpnt->cmd_len = 0;
 
-                   scsi_do_cmd (SCpnt, (void *)  scsi_cmd,
-                                (void *) scsi_result, 0x2a,  scan_scsis_done,
-                                SCSI_TIMEOUT, 3);
-
-                   if (current == task[0])
-                       while (SCpnt->request.dev != 0xfffe) barrier();
+                   scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
+                                (void *) scsi_result,
+                                256,  scan_scsis_done, SCSI_TIMEOUT, 3);
+                   
+                   if (current->pid == 0)
+                       while (SCpnt->request.dev != 0xfffe) 
+                           barrier();
                    else if (SCpnt->request.dev != 0xfffe) {
                        struct semaphore sem = MUTEX_LOCKED;
-
+                       
                        SCpnt->request.sem = &sem;
                        down(&sem);
-
+                       
                        /* Hmm.. Have to ask about this one */
                        while (SCpnt->request.dev != 0xfffe) schedule();
+                   }
+                   
+                   the_result = SCpnt->result;
+                   
+#if defined(DEBUG) || defined(DEBUG_INIT)
+                   if (!the_result)
+                       printk("scsi: INQUIRY successful\n");
+                   else
+                       printk("scsi: INQUIRY failed with code %08x\n", the_result);
+#endif
+                   
+                   if(the_result) break;
+                   
+                   /* skip other luns on this device */
+                   
+                   if (!the_result)
+                   {
+                       /* It would seem some TOSHIBA CDROM 
+                        * gets things wrong 
+                        */
+                       if (!strncmp(scsi_result+8,"TOSHIBA",7) &&
+                           !strncmp(scsi_result+16,"CD-ROM",6) &&
+                           scsi_result[0] == TYPE_DISK) {
+                           scsi_result[0] = TYPE_ROM;
+                           scsi_result[1] |= 0x80;  /* removable */
                        }
-                 }
-                 /* Add this device to the linked list at the end */
-                 if(SDtail)
-                   SDtail->next = SDpnt;
-                 else
-                   scsi_devices = SDpnt;
-                 SDtail = SDpnt;
-
-                 SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
-                 /* Some scsi devices cannot be polled for lun != 0
-                    due to firmware bugs */
-                 if(blacklisted(scsi_result)) break;
-                 /* Old drives like the MAXTOR XT-3280 say vers=0 */
-                 if ((scsi_result[2] & 0x07) == 0)
-                   break;
-                 /* Some scsi-1 peripherals do not handle lun != 0.
-                    I am assuming that scsi-2 peripherals do better */
-                 if((scsi_result[2] & 0x07) == 1 &&
-                    (scsi_result[3] & 0x0f) == 0) break;
-               }
-           }       /* if result == DID_OK ends */
-       }       /* for lun ends */
-
-  shpnt->host_queue = NULL;  /* No longer needed here */
-
-  /* Last device block does not exist.  Free memory. */
-  scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
-
-  scsi_init_free((char *) SCpnt, sizeof(Scsi_Cmnd));
-
-
-  /* If we allocated a buffer so we could do DMA, free it now */
-  if (scsi_result != &scsi_result0[0]) scsi_free(scsi_result, 512);
+                       
+                       if (!strncmp(scsi_result+8,"NEC",3)) {
+                           if (!strncmp(scsi_result+16,"CD-ROM DRIVE:84 ",16) || 
+                               !strncmp(scsi_result+16,"CD-ROM DRIVE:25",15))
+                               SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR;
+                           else
+                               SDpnt->manufacturer = SCSI_MAN_NEC;
+                       } else if (!strncmp(scsi_result+8,"TOSHIBA",7))
+                           SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
+                       else
+                           SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
+                       
+                       memcpy(SDpnt->vendor, scsi_result+8, 8);
+                       memcpy(SDpnt->model, scsi_result+16, 16);
+                       memcpy(SDpnt->rev, scsi_result+32, 4);
+                       SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+                       SDpnt->lockable = SDpnt->removable;
+                       SDpnt->changed = 0;
+                       SDpnt->access_count = 0;
+                       SDpnt->busy = 0;
+                       /*
+                        * Currently, all sequential devices are assumed to be
+                        * tapes, all random devices disk, with the appropriate
+                        * read only flags set for ROM / WORM treated as RO.
+                        */
+                       
+                       switch (type = (scsi_result[0] & 0x1f))
+                       {
+                       case TYPE_TAPE :
+                       case TYPE_DISK :
+                       case TYPE_MOD :
+                       case TYPE_PROCESSOR :
+                       case TYPE_SCANNER :
+                           SDpnt->writeable = 1;
+                           break;
+                       case TYPE_WORM :
+                       case TYPE_ROM :
+                           SDpnt->writeable = 0;
+                           break;
+                       default :
+#if 0
+#ifdef DEBUG
+                           printk("scsi: unknown type %d\n", type);
+                           print_inquiry(scsi_result);
+#endif
+                           type = -1;
+#endif
+                       }
+                       
+                       SDpnt->soft_reset =
+                           (scsi_result[7] & 1) && ((scsi_result[3] &7) == 2);
+                       SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
+                       SDpnt->type = (type & 0x1f);
+                       
+                       if (type != -1)
+                       {
+                           print_inquiry(scsi_result);
+                           
+                           for(sdtpnt = scsi_devicelist; sdtpnt; 
+                               sdtpnt = sdtpnt->next)
+                               if(sdtpnt->detect) SDpnt->attached +=
+                                   (*sdtpnt->detect)(SDpnt);
+                           
+                           SDpnt->scsi_level = scsi_result[2] & 0x07;
+                           if (SDpnt->scsi_level >= 2 ||
+                               (SDpnt->scsi_level == 1 &&
+                                (scsi_result[3] & 0x0f) == 1))
+                               SDpnt->scsi_level++;
+                           /*
+                            * Set the tagged_queue flag for SCSI-II devices 
+                            * that purport to support
+                            * tagged queuing in the INQUIRY data.
+                            */
+                           
+                           SDpnt->tagged_queue = 0;
+                           
+                           if ((SDpnt->scsi_level >= SCSI_2) &&
+                               (scsi_result[7] & 2)) {
+                               SDpnt->tagged_supported = 1;
+                               SDpnt->current_tag = 0;
+                           }
+                           
+                           /*
+                            * Accommodate drivers that want to sleep when 
+                            * they should be in a polling loop.
+                            */
 
-  in_scan_scsis = 0;
+                           SDpnt->disconnect = 0;
+                           
+                           /*
+                            * Some revisions of the Texel CD ROM drives have 
+                            * handshaking problems when used with the Seagate
+                            * controllers.  Before we know what type of device
+                            * we're talking to, we assume it's borken and then
+                            * change it here if it turns out that it isn't
+                            * a TEXEL drive.
+                            */
+                           if((strncmp("SONY",(char *) &scsi_result[8], 4)!= 0
+                               || strncmp("CD-ROM CDU-8001",
+                                          (char *) &scsi_result[16], 15) != 0)
+                              && (strncmp("TEXEL", 
+                                          (char *) &scsi_result[8], 5) != 0 
+                                  || strncmp("CD-ROM", 
+                                             (char *) &scsi_result[16], 6) != 0
+                               /*
+                                * XXX 1.06 has problems, some one should 
+                                * figure out the others too so ALL TEXEL 
+                                * drives don't suffer in performance, 
+                                * especially when I finish integrating my 
+                                * seagate patches which do multiple I_T_L 
+                                * nexuses.
+                                */
+                               
+#ifdef notyet
+                               || (strncmp("1.06", 
+                                           (char *) &scsi_result, 4) != 0)
+#endif
+                               ))
+                               SDpnt->borken = 0;
+                           
+                           
+                           /* These devices need this "key" to unlock the
+                            * devices so we can use it 
+                            */
+                           if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
+                              (memcmp("Floptical   F*8I", 
+                                      &scsi_result[16], 16) == 0
+                               || memcmp("I325VM", 
+                                         &scsi_result[16], 6) == 0)) {
+                               printk("Unlocked floptical drive.\n");
+                               SDpnt->lockable = 0;
+                               scsi_cmd[0] = MODE_SENSE;
+                               scsi_cmd[1] = (lun << 5) & 0xe0;
+                               scsi_cmd[2] = 0x2e;
+                               scsi_cmd[3] = 0;
+                               scsi_cmd[4] = 0x2a;
+                               scsi_cmd[5] = 0;
+                               
+                               SCpnt->request.dev = 0xffff; /* Mark not busy */
+                               SCpnt->cmd_len = 0;
+                               
+                               scsi_do_cmd (SCpnt, (void *)  scsi_cmd,
+                                            (void *) scsi_result, 0x2a,  
+                                            scan_scsis_done, SCSI_TIMEOUT, 3);
+                               
+                               if (current->pid == 0)
+                                   while (SCpnt->request.dev != 0xfffe);
+                               else if (SCpnt->request.dev != 0xfffe) {
+                                   struct semaphore sem = MUTEX_LOCKED;
+                                   
+                                   SCpnt->request.sem = &sem;
+                                   down(&sem);
+                                   
+                                   /* Hmm.. Have to ask about this one */
+                                   while (SCpnt->request.dev != 0xfffe) 
+                                       schedule();
+                               }
+                           }
+                           /* Add this device to the linked list at the end */
+                           if(SDtail)
+                               SDtail->next = SDpnt;
+                           else
+                               scsi_devices = SDpnt;
+                           SDtail = SDpnt;
+                           
+                           SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
+                           /* Some scsi devices cannot be polled for lun != 0
+                            * due to firmware bugs 
+                            */
+                           if(blacklisted(scsi_result)) break;
+                           /* Old drives like the MAXTOR XT-3280 say vers=0 */
+                           if ((scsi_result[2] & 0x07) == 0)
+                               break;
+                           /* Some scsi-1 peripherals do not handle lun != 0.
+                            * I am assuming that scsi-2 peripherals do better 
+                            */
+                           if((scsi_result[2] & 0x07) == 1 &&
+                              (scsi_result[3] & 0x0f) == 0) break;
+                       }
+                   }       /* if result == DID_OK ends */
+
+                   if(hardcoded == 1)
+                       goto leave;
+               } /* for lun ends */
+           } /* if this_id != id ends */
+       } /* for dev ends */
+    } /* for channel ends */
+    
+ leave:
+    shpnt->host_queue = NULL;  /* No longer needed here */
+    
+    
+    /* Last device block does not exist.  Free memory. */
+    if(SDpnt != NULL)
+       scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
+    
+    if(SDpnt != NULL)
+       scsi_init_free((char *) SCpnt, sizeof(Scsi_Cmnd));
+    
+    /* If we allocated a buffer so we could do DMA, free it now */
+    if (scsi_result != &scsi_result0[0] && scsi_result != NULL) 
+       scsi_free(scsi_result, 512);
+    
+    in_scan_scsis = 0;
 }       /* scan_scsis  ends */
 
 /*
- *     Flag bits for the internal_timeout array
+ *  Flag bits for the internal_timeout array
  */
 
 #define NORMAL_TIMEOUT 0
 #define IN_ABORT 1
 #define IN_RESET 2
+
 /*
      This is our time out function, called when the timer expires for a
      given host adapter.  It will attempt to abort the currently executing
      command, that failing perform a kernel panic.
-*/
* This is our time out function, called when the timer expires for a
* given host adapter.  It will attempt to abort the currently executing
* command, that failing perform a kernel panic.
+ */
 
 static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
-       {
-
-       switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
-               {
-               case NORMAL_TIMEOUT:
-                       if (!in_scan_scsis) {
+{
+    
+    switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
+    {
+    case NORMAL_TIMEOUT:
+       if (!in_scan_scsis) {
 #ifdef DEBUG_TIMEOUT
-                         scsi_dump_status();
+           scsi_dump_status();
 #endif
-                       }
-
-                       if (!scsi_abort (SCpnt, DID_TIME_OUT, pid))
-                               return;
-               case IN_ABORT:
-                       printk("SCSI host %d abort() timed out - resetting\n",
-                               SCpnt->host->host_no);
-                       if (!scsi_reset (SCpnt))
-                               return;
-               case IN_RESET:
-               case (IN_ABORT | IN_RESET):
-                 /* This might be controversial, but if there is a bus hang,
-                    you might conceivably want the machine up and running
-                    esp if you have an ide disk. */
-                       printk("Unable to reset scsi host %d - ",SCpnt->host->host_no);
-                       printk("probably a SCSI bus hang.\n");
-                       return;
-
-               default:
-                       INTERNAL_ERROR;
-               }
-
        }
+       
+       if (!scsi_abort (SCpnt, DID_TIME_OUT, pid))
+           return;
+    case IN_ABORT:
+       printk("SCSI host %d abort() timed out - resetting\n",
+              SCpnt->host->host_no);
+       if (!scsi_reset (SCpnt))
+           return;
+    case IN_RESET:
+    case (IN_ABORT | IN_RESET):
+       /* This might be controversial, but if there is a bus hang,
+        * you might conceivably want the machine up and running
+        * esp if you have an ide disk. 
+        */
+       printk("Unable to reset scsi host %d - ", SCpnt->host->host_no);
+       printk("probably a SCSI bus hang.\n");
+       return;
+       
+    default:
+       INTERNAL_ERROR;
+    }
+    
+}
 
 
 /* This function takes a quick look at a request, and decides if it
-can be queued now, or if there would be a stall while waiting for
-something else to finish.  This routine assumes that interrupts are
-turned off when entering the routine.  It is the responsibility
-of the calling code to ensure that this is the case. */
+ * can be queued now, or if there would be a stall while waiting for
+ * something else to finish.  This routine assumes that interrupts are
+ * turned off when entering the routine.  It is the responsibility
+ * of the calling code to ensure that this is the case. 
+ */
 
 Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
 {
-  Scsi_Cmnd * SCpnt = NULL;
-  int tablesize;
-  struct buffer_head * bh, *bhp;
-
-  if (!device)
-    panic ("No device passed to request_queueable().\n");
-
-  if (req && req->dev <= 0)
-    panic("Invalid device in request_queueable");
-
-  SCpnt =  device->host->host_queue;
+    Scsi_Cmnd * SCpnt = NULL;
+    int tablesize;
+    struct buffer_head * bh, *bhp;
+    
+    if (!device)
+       panic ("No device passed to request_queueable().\n");
+    
+    if (req && req->dev <= 0)
+       panic("Invalid device in request_queueable");
+    
+    SCpnt =  device->host->host_queue;
     while(SCpnt){
-      if(SCpnt->target == device->id &&
-        SCpnt->lun == device->lun)
-       if(SCpnt->request.dev < 0) break;
-      SCpnt = SCpnt->next;
+       if(SCpnt->target == device->id && SCpnt->lun == device->lun 
+          && SCpnt->channel == device->channel)
+           if(SCpnt->request.dev < 0) break;
+       SCpnt = SCpnt->next;
     }
-
-  if (!SCpnt) return NULL;
-
-  if (SCSI_BLOCK(device->host)) return NULL;
-
-  if (req) {
-    memcpy(&SCpnt->request, req, sizeof(struct request));
-    tablesize = device->host->sg_tablesize;
-    bhp = bh = req->bh;
-    if(!tablesize) bh = NULL;
-    /* Take a quick look through the table to see how big it is.  We already
-       have our copy of req, so we can mess with that if we want to.  */
-    while(req->nr_sectors && bh){
+    
+    if (!SCpnt) return NULL;
+    
+    if (SCSI_BLOCK(device->host)) return NULL;
+    
+    if (req) {
+       memcpy(&SCpnt->request, req, sizeof(struct request));
+       tablesize = device->host->sg_tablesize;
+       bhp = bh = req->bh;
+       if(!tablesize) bh = NULL;
+       /* Take a quick look through the table to see how big it is.  
+        * We already have our copy of req, so we can mess with that 
+        * if we want to. 
+        */
+       while(req->nr_sectors && bh){
            bhp = bhp->b_reqnext;
            if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
            req->nr_sectors -= bh->b_size >> 9;
            req->sector += bh->b_size >> 9;
            if(!tablesize) break;
            bh = bhp;
-    }
-    if(req->nr_sectors && bh && bh->b_reqnext){  /* Any leftovers? */
-      SCpnt->request.bhtail = bh;
-      req->bh = bh->b_reqnext; /* Divide request */
-      bh->b_reqnext = NULL;
-      bh = req->bh;
-
-      /* Now reset things so that req looks OK */
-      SCpnt->request.nr_sectors -= req->nr_sectors;
-      req->current_nr_sectors = bh->b_size >> 9;
-      req->buffer = bh->b_data;
-      SCpnt->request.sem = NULL; /* Wait until whole thing done */
+       }
+       if(req->nr_sectors && bh && bh->b_reqnext){  /* Any leftovers? */
+           SCpnt->request.bhtail = bh;
+           req->bh = bh->b_reqnext; /* Divide request */
+           bh->b_reqnext = NULL;
+           bh = req->bh;
+           
+           /* Now reset things so that req looks OK */
+           SCpnt->request.nr_sectors -= req->nr_sectors;
+           req->current_nr_sectors = bh->b_size >> 9;
+           req->buffer = bh->b_data;
+           SCpnt->request.sem = NULL; /* Wait until whole thing done */
+       } else {
+           req->dev = -1;
+           wake_up(&wait_for_request);
+       }
     } else {
-      req->dev = -1;
-      wake_up(&wait_for_request);
+       SCpnt->request.dev = 0xffff; /* Busy, but no request */
+       SCpnt->request.sem = NULL;   /* And no one is waiting for the device 
+                                     * either */
     }
-  } else {
-    SCpnt->request.dev = 0xffff; /* Busy, but no request */
-    SCpnt->request.sem = NULL;  /* And no one is waiting for the device either */
-  }
-
-  SCpnt->use_sg = 0;  /* Reset the scatter-gather flag */
-  SCpnt->old_use_sg  = 0;
-  SCpnt->transfersize = 0;
-  SCpnt->underflow = 0;
-  SCpnt->cmd_len = 0;
-  return SCpnt;
+    
+    SCpnt->use_sg = 0;               /* Reset the scatter-gather flag */
+    SCpnt->old_use_sg  = 0;
+    SCpnt->transfersize = 0;
+    SCpnt->underflow = 0;
+    SCpnt->cmd_len = 0;
+#if 1
+/* Since not everyone seems to set the device info correctly
+ * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+ */ 
+    SCpnt->channel = device->channel;
+    SCpnt->lun = device->lun;
+    SCpnt->target = device->id;
+#endif
+    return SCpnt;
 }
 
 /* This function returns a structure pointer that will be valid for
-the device.  The wait parameter tells us whether we should wait for
-the unit to become free or not.  We are also able to tell this routine
-not to return a descriptor if the host is unable to accept any more
-commands for the time being.  We need to keep in mind that there is no
-guarantee that the host remain not busy.  Keep in mind the
-request_queueable function also knows the internal allocation scheme
-of the packets for each device */
+ * the device.  The wait parameter tells us whether we should wait for
+ * the unit to become free or not.  We are also able to tell this routine
+ * not to return a descriptor if the host is unable to accept any more
+ * commands for the time being.  We need to keep in mind that there is no
+ * guarantee that the host remain not busy.  Keep in mind the
+ * request_queueable function also knows the internal allocation scheme
+ * of the packets for each device 
+ */
 
 Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
                             int wait)
 {
-  int dev = -1;
-  struct request * req = NULL;
-  int tablesize;
-  unsigned int flags;
-  struct buffer_head * bh, *bhp;
-  struct Scsi_Host * host;
-  Scsi_Cmnd * SCpnt = NULL;
-  Scsi_Cmnd * SCwait = NULL;
-
-  if (!device)
-    panic ("No device passed to allocate_device().\n");
-
-  if (reqp) req = *reqp;
-
-    /* See if this request has already been queued by an interrupt routine */
-  if (req && (dev = req->dev) <= 0) return NULL;
-
-  host = device->host;
-
-  if (intr_count && SCSI_BLOCK(host)) return NULL;
-
-  while (1==1){
-    SCpnt = host->host_queue;
-    while(SCpnt){
-      if(SCpnt->target == device->id &&
-        SCpnt->lun == device->lun) {
-       SCwait = SCpnt;
-       if(SCpnt->request.dev < 0) break;
-      }
-      SCpnt = SCpnt->next;
-    }
-    save_flags(flags);
-    cli();
+    int dev = -1;
+    struct request * req = NULL;
+    int tablesize;
+    unsigned int flags;
+    struct buffer_head * bh, *bhp;
+    struct Scsi_Host * host;
+    Scsi_Cmnd * SCpnt = NULL;
+    Scsi_Cmnd * SCwait = NULL;
+    
+    if (!device)
+       panic ("No device passed to allocate_device().\n");
+    
+    if (reqp) req = *reqp;
+    
     /* See if this request has already been queued by an interrupt routine */
-    if (req && ((req->dev < 0) || (req->dev != dev))) {
-      restore_flags(flags);
-      return NULL;
-    }
-    if (!SCpnt || SCpnt->request.dev >= 0)  /* Might have changed */
-      {
-       restore_flags(flags);
-       if(!wait) return NULL;
-       if (!SCwait) {
-         printk("Attempt to allocate device target %d, lun %d\n",
-                device->id ,device->lun);
-         panic("No device found in allocate_device\n");
+    if (req && (dev = req->dev) <= 0) return NULL;
+    
+    host = device->host;
+    
+    if (intr_count && SCSI_BLOCK(host)) return NULL;
+    
+    while (1==1){
+       SCpnt = host->host_queue;
+       while(SCpnt){
+           if(SCpnt->target == device->id && SCpnt->lun == device->lun
+              && SCpnt->channel == device->channel) {
+               SCwait = SCpnt;
+               if(SCpnt->request.dev < 0) break;
+           }
+           SCpnt = SCpnt->next;
        }
-       SCSI_SLEEP(&device->device_wait,
-                  (SCwait->request.dev > 0));
-      } else {
-       if (req) {
-         memcpy(&SCpnt->request, req, sizeof(struct request));
-         tablesize = device->host->sg_tablesize;
-         bhp = bh = req->bh;
-         if(!tablesize) bh = NULL;
-         /* Take a quick look through the table to see how big it is.  We already
-            have our copy of req, so we can mess with that if we want to.  */
-         while(req->nr_sectors && bh){
-           bhp = bhp->b_reqnext;
-           if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
-           req->nr_sectors -= bh->b_size >> 9;
-           req->sector += bh->b_size >> 9;
-           if(!tablesize) break;
-           bh = bhp;
-         }
-         if(req->nr_sectors && bh && bh->b_reqnext){  /* Any leftovers? */
-           SCpnt->request.bhtail = bh;
-           req->bh = bh->b_reqnext; /* Divide request */
-           bh->b_reqnext = NULL;
-           bh = req->bh;
-           /* Now reset things so that req looks OK */
-           SCpnt->request.nr_sectors -= req->nr_sectors;
-           req->current_nr_sectors = bh->b_size >> 9;
-           req->buffer = bh->b_data;
-           SCpnt->request.sem = NULL; /* Wait until whole thing done */
-         }
-         else
-           {
-             req->dev = -1;
-             *reqp = req->next;
-             wake_up(&wait_for_request);
+       save_flags(flags);
+       cli();
+       /* See if this request has already been queued by an interrupt routine
+        */
+       if (req && ((req->dev < 0) || (req->dev != dev))) {
+           restore_flags(flags);
+           return NULL;
+       }
+       if (!SCpnt || SCpnt->request.dev >= 0)  /* Might have changed */
+       {
+           restore_flags(flags);
+           if(!wait) return NULL;
+           if (!SCwait) {
+               printk("Attempt to allocate device channel %d, target %d, "
+                      "lun %d\n", device->channel, device->id, device->lun);
+               panic("No device found in allocate_device\n");
            }
+           SCSI_SLEEP(&device->device_wait,
+                      (SCwait->request.dev > 0));
        } else {
-         SCpnt->request.dev = 0xffff; /* Busy */
-         SCpnt->request.sem = NULL;  /* And no one is waiting for this to complete */
+           if (req) {
+               memcpy(&SCpnt->request, req, sizeof(struct request));
+               tablesize = device->host->sg_tablesize;
+               bhp = bh = req->bh;
+               if(!tablesize) bh = NULL;
+               /* Take a quick look through the table to see how big it is.  
+                * We already have our copy of req, so we can mess with that 
+                * if we want to.  
+                */
+               while(req->nr_sectors && bh){
+                   bhp = bhp->b_reqnext;
+                   if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
+                   req->nr_sectors -= bh->b_size >> 9;
+                   req->sector += bh->b_size >> 9;
+                   if(!tablesize) break;
+                   bh = bhp;
+               }
+               if(req->nr_sectors && bh && bh->b_reqnext){/* Any leftovers? */
+                   SCpnt->request.bhtail = bh;
+                   req->bh = bh->b_reqnext; /* Divide request */
+                   bh->b_reqnext = NULL;
+                   bh = req->bh;
+                   /* Now reset things so that req looks OK */
+                   SCpnt->request.nr_sectors -= req->nr_sectors;
+                   req->current_nr_sectors = bh->b_size >> 9;
+                   req->buffer = bh->b_data;
+                   SCpnt->request.sem = NULL; /* Wait until whole thing done*/
+               }
+               else
+               {
+                   req->dev = -1;
+                   *reqp = req->next;
+                   wake_up(&wait_for_request);
+               }
+           } else {
+               SCpnt->request.dev = 0xffff; /* Busy */
+               SCpnt->request.sem = NULL;   /* And no one is waiting for this 
+                                             * to complete */
+           }
+           restore_flags(flags);
+           break;
        }
-       restore_flags(flags);
-       break;
-      }
-  }
-
-  SCpnt->use_sg = 0;  /* Reset the scatter-gather flag */
-  SCpnt->old_use_sg  = 0;
-  SCpnt->transfersize = 0;      /* No default transfer size */
-  SCpnt->cmd_len = 0;
-  SCpnt->underflow = 0;         /* Do not flag underflow conditions */
-  return SCpnt;
+    }
+    
+    SCpnt->use_sg = 0;            /* Reset the scatter-gather flag */
+    SCpnt->old_use_sg  = 0;
+    SCpnt->transfersize = 0;      /* No default transfer size */
+    SCpnt->cmd_len = 0;
+    SCpnt->underflow = 0;         /* Do not flag underflow conditions */
+#if 1
+/* Since not everyone seems to set the device info correctly
+ * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+ */ 
+    SCpnt->channel = device->channel;
+    SCpnt->lun = device->lun;
+    SCpnt->target = device->id;
+#endif
+    return SCpnt;
 }
 
 /*
      This is inline because we have stack problemes if we recurse to deeply.
-*/
* This is inline because we have stack problemes if we recurse to deeply.
+ */
 
 inline void internal_cmnd (Scsi_Cmnd * SCpnt)
-       {
-       int temp;
-       struct Scsi_Host * host;
-       unsigned int flags;
+{
+    int temp;
+    struct Scsi_Host * host;
+    unsigned int flags;
 #ifdef DEBUG_DELAY
-       int clock;
+    int clock;
 #endif
-
-       host = SCpnt->host;
-
-/*
-       We will wait MIN_RESET_DELAY clock ticks after the last reset so
-       we can avoid the drive not being ready.
-*/
-save_flags(flags);
-sti();
-temp = host->last_reset + MIN_RESET_DELAY;
-while (jiffies < temp);
-restore_flags(flags);
-
-update_timeout(SCpnt, SCpnt->timeout_per_command);
-
-/*
-       We will use a queued command if possible, otherwise we will emulate the
-       queuing and calling of completion function ourselves.
-*/
+    
+    host = SCpnt->host;
+    
+    /*
+     * We will wait MIN_RESET_DELAY clock ticks after the last reset so
+     * we can avoid the drive not being ready.
+     */
+    save_flags(flags);
+    sti();
+    temp = host->last_reset + MIN_RESET_DELAY;
+    while (jiffies < temp);
+    restore_flags(flags);
+    
+    update_timeout(SCpnt, SCpnt->timeout_per_command);
+    
+    /*
+     * We will use a queued command if possible, otherwise we will emulate the
+     * queuing and calling of completion function ourselves.
+     */
 #ifdef DEBUG
-       printk("internal_cmnd (host = %d, target = %d, command = %p, buffer = %p, \n"
-               "bufflen = %d, done = %p)\n", SCpnt->host->host_no, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
+    printk("internal_cmnd (host = %d, channel = %d, target = %d, "
+          "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", 
+          SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, 
+          SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
 #endif
-
-       if (host->can_queue)
-               {
+    
+    if (host->can_queue)
+    {
 #ifdef DEBUG
        printk("queuecommand : routine at %p\n",
-               host->hostt->queuecommand);
+              host->hostt->queuecommand);
 #endif
-                 /* This locking tries to prevent all sorts of races between
-                    queuecommand and the interrupt code.  In effect,
-                    we are only allowed to be in queuecommand once at
-                    any given time, and we can only be in the interrupt
-                    handler and the queuecommand function at the same time
-                    when queuecommand is called while servicing the
-                    interrupt. */
-
-               if(!intr_count && SCpnt->host->irq)
-                 disable_irq(SCpnt->host->irq);
-
-               host->hostt->queuecommand (SCpnt, scsi_done);
-
-               if(!intr_count && SCpnt->host->irq)
-                 enable_irq(SCpnt->host->irq);
-               }
-       else
-               {
-
+       /* This locking tries to prevent all sorts of races between
+        * queuecommand and the interrupt code.  In effect,
+        * we are only allowed to be in queuecommand once at
+        * any given time, and we can only be in the interrupt
+        * handler and the queuecommand function at the same time
+        * when queuecommand is called while servicing the
+        * interrupt. 
+        */
+       
+       if(!intr_count && SCpnt->host->irq)
+           disable_irq(SCpnt->host->irq);
+       
+       host->hostt->queuecommand (SCpnt, scsi_done);
+       
+       if(!intr_count && SCpnt->host->irq)
+           enable_irq(SCpnt->host->irq);
+    }
+    else
+    {
+       
 #ifdef DEBUG
        printk("command() :  routine at %p\n", host->hostt->command);
 #endif
-               temp=host->hostt->command (SCpnt);
-               SCpnt->result = temp;
+       temp=host->hostt->command (SCpnt);
+       SCpnt->result = temp;
 #ifdef DEBUG_DELAY
-       clock = jiffies + 4*HZ;
+       clock = jiffies + 4 * HZ;
        while (jiffies < clock);
-       printk("done(host = %d, result = %04x) : routine at %08x\n", host->host_no, temp);
+       printk("done(host = %d, result = %04x) : routine at %08x\n", 
+              host->host_no, temp);
 #endif
-               scsi_done(SCpnt);
-               }
+       scsi_done(SCpnt);
+    }
 #ifdef DEBUG
-       printk("leaving internal_cmnd()\n");
+    printk("leaving internal_cmnd()\n");
 #endif
-       }
+}
 
 static void scsi_request_sense (Scsi_Cmnd * SCpnt)
-       {
-       unsigned int flags;
-
-       save_flags(flags);
-       cli();
-       SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
-       update_timeout(SCpnt, SENSE_TIMEOUT);
-       restore_flags(flags);
-
-
-       memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
-               sizeof(generic_sense));
-
-       SCpnt->cmnd[1] = SCpnt->lun << 5;
-       SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
-
-       SCpnt->request_buffer = &SCpnt->sense_buffer;
-       SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
-       SCpnt->use_sg = 0;
-       SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-       internal_cmnd (SCpnt);
-       }
+{
+    unsigned int flags;
+    
+    save_flags(flags);
+    cli();
+    SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
+    update_timeout(SCpnt, SENSE_TIMEOUT);
+    restore_flags(flags);
+    
+    
+    memcpy ((void *) SCpnt->cmnd , (void *) generic_sense, 
+           sizeof(generic_sense));
+    
+    SCpnt->cmnd[1] = SCpnt->lun << 5;
+    SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+    
+    SCpnt->request_buffer = &SCpnt->sense_buffer;
+    SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+    SCpnt->use_sg = 0;
+    SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+    internal_cmnd (SCpnt);
+}
 
 
 
 /*
      scsi_do_cmd sends all the commands out to the low-level driver.  It
      handles the specifics required for each low level driver - ie queued
      or non queued.  It also prevents conflicts when different high level
      drivers go for the same host at the same time.
-*/
* scsi_do_cmd sends all the commands out to the low-level driver.  It
* handles the specifics required for each low level driver - ie queued
* or non queued.  It also prevents conflicts when different high level
* drivers go for the same host at the same time.
+ */
 
 void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
                  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
-                 int timeout, int retries
-                  )
-       {
-       unsigned long flags;
-       struct Scsi_Host * host = SCpnt->host;
-
+                 int timeout, int retries)
+{
+    unsigned long flags;
+    struct Scsi_Host * host = SCpnt->host;
+    
 #ifdef DEBUG
-       {
+    {
        int i;
        int target = SCpnt->target;
-       printk ("scsi_do_cmd (host = %d, target = %d, buffer =%p, "
-               "bufflen = %d, done = %p, timeout = %d, retries = %d)\n"
-               "command : " , host->host_no, target, buffer, bufflen, done, timeout, retries);
+       printk ("scsi_do_cmd (host = %d, channel = %d target = %d, "
+               "buffer =%p, bufflen = %d, done = %p, timeout = %d, "
+               "retries = %d)\n"
+               "command : " , host->host_no, SCpnt->channel, target, buffer, 
+               bufflen, done, timeout, retries);
        for (i = 0; i < 10; ++i)
-               printk ("%02x  ", ((unsigned char *) cmnd)[i]);
+           printk ("%02x  ", ((unsigned char *) cmnd)[i]);
        printk("\n");
-      }
+    }
 #endif
+    
+    if (!host)
+    {
+       panic ("Invalid or not present host.\n");
+    }
+    
+    
+    /*
+     * We must prevent reentrancy to the lowlevel host driver.  This prevents
+     * it - we enter a loop until the host we want to talk to is not busy.
+     * Race conditions are prevented, as interrupts are disabled in between the
+     * time we check for the host being not busy, and the time we mark it busy
+     * ourselves.
+     */
 
-       if (!host)
-               {
-               panic ("Invalid or not present host.\n");
-               }
-
-
-/*
-       We must prevent reentrancy to the lowlevel host driver.  This prevents
-       it - we enter a loop until the host we want to talk to is not busy.
-       Race conditions are prevented, as interrupts are disabled in between the
-       time we check for the host being not busy, and the time we mark it busy
-       ourselves.
-*/
-
-       save_flags(flags);
-       cli();
-       SCpnt->pid = scsi_pid++;
-
-       while (SCSI_BLOCK(host)) {
-          restore_flags(flags);
-          SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
-          cli();
-          }
-
-       if (host->block) host_active = host;
-
-       host->host_busy++;
+    save_flags(flags);
+    cli();
+    SCpnt->pid = scsi_pid++;
+    
+    while (SCSI_BLOCK(host)) {
        restore_flags(flags);
-
-/*
-       Our own function scsi_done (which marks the host as not busy, disables
-       the timeout counter, etc) will be called by us or by the
-       scsi_hosts[host].queuecommand() function needs to also call
-       the completion function for the high level driver.
-
-*/
-
-       memcpy ((void *) SCpnt->data_cmnd , (void *) cmnd, 12);
+       SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
+       cli();
+    }
+    
+    if (host->block) host_active = host;
+    
+    host->host_busy++;
+    restore_flags(flags);
+    
+    /*
+     * Our own function scsi_done (which marks the host as not busy, disables
+     * the timeout counter, etc) will be called by us or by the
+     * scsi_hosts[host].queuecommand() function needs to also call
+     * the completion function for the high level driver.
+     */
+    
+    memcpy ((void *) SCpnt->data_cmnd , (void *) cmnd, 12);
 #if 0
-       SCpnt->host = host;
-       SCpnt->target = target;
-       SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);
+    SCpnt->host = host;
+    SCpnt->channel = channel;
+    SCpnt->target = target;
+    SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);
 #endif
-       SCpnt->bufflen = bufflen;
-       SCpnt->buffer = buffer;
-       SCpnt->flags=0;
-       SCpnt->retries=0;
-       SCpnt->allowed=retries;
-       SCpnt->done = done;
-       SCpnt->timeout_per_command = timeout;
-
-       memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 12);
-       /* Zero the sense buffer.  Some host adapters automatically request
-          sense on error.  0 is not a valid sense code.  */
-       memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
-       SCpnt->request_buffer = buffer;
-       SCpnt->request_bufflen = bufflen;
-       SCpnt->old_use_sg = SCpnt->use_sg;
-       if (SCpnt->cmd_len == 0)
-               SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-       SCpnt->old_cmd_len = SCpnt->cmd_len;
-
-       /* Start the timer ticking.  */
-
-       SCpnt->internal_timeout = 0;
-       SCpnt->abort_reason = 0;
-       internal_cmnd (SCpnt);
+    SCpnt->bufflen = bufflen;
+    SCpnt->buffer = buffer;
+    SCpnt->flags=0;
+    SCpnt->retries=0;
+    SCpnt->allowed=retries;
+    SCpnt->done = done;
+    SCpnt->timeout_per_command = timeout;
+
+    memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 12);
+    /* Zero the sense buffer.  Some host adapters automatically request
+     * sense on error.  0 is not a valid sense code.  
+     */
+    memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
+    SCpnt->request_buffer = buffer;
+    SCpnt->request_bufflen = bufflen;
+    SCpnt->old_use_sg = SCpnt->use_sg;
+    if (SCpnt->cmd_len == 0)
+       SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+    SCpnt->old_cmd_len = SCpnt->cmd_len;
+
+    /* Start the timer ticking.  */
+
+    SCpnt->internal_timeout = 0;
+    SCpnt->abort_reason = 0;
+    internal_cmnd (SCpnt);
 
 #ifdef DEBUG
-       printk ("Leaving scsi_do_cmd()\n");
+    printk ("Leaving scsi_do_cmd()\n");
 #endif
-       }
+}
 
 
 
 /*
      The scsi_done() function disables the timeout timer for the scsi host,
      marks the host as not busy, and calls the user specified completion
      function for that host's current command.
-*/
* The scsi_done() function disables the timeout timer for the scsi host,
* marks the host as not busy, and calls the user specified completion
* function for that host's current command.
+ */
 
 static void reset (Scsi_Cmnd * SCpnt)
 {
 #ifdef DEBUG
-       printk("scsi: reset(%d)\n", SCpnt->host->host_no);
+    printk("scsi: reset(%d, channel %d)\n", SCpnt->host->host_no, 
+          SCpnt->channel);
 #endif
 
-       SCpnt->flags |= (WAS_RESET | IS_RESETTING);
-       scsi_reset(SCpnt);
+    SCpnt->flags |= (WAS_RESET | IS_RESETTING);
+    scsi_reset(SCpnt);
 
 #ifdef DEBUG
-       printk("performing request sense\n");
+    printk("performing request sense\n");
 #endif
 
 #if 0  /* FIXME - remove this when done */
-       if(SCpnt->flags & NEEDS_JUMPSTART) {
-         SCpnt->flags &= ~NEEDS_JUMPSTART;
-         scsi_request_sense (SCpnt);
-       }
+    if(SCpnt->flags & NEEDS_JUMPSTART) {
+       SCpnt->flags &= ~NEEDS_JUMPSTART;
+       scsi_request_sense (SCpnt);
+    }
 #endif
 }
 
 
 
 static int check_sense (Scsi_Cmnd * SCpnt)
-       {
-  /* If there is no sense information, request it.  If we have already
-     requested it, there is no point in asking again - the firmware must be
-     confused. */
-  if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
-    if(!(SCpnt->flags & ASKED_FOR_SENSE))
-      return SUGGEST_SENSE;
-    else
-      return SUGGEST_RETRY;
-      }
-
-  SCpnt->flags &= ~ASKED_FOR_SENSE;
-
+{
+    /* If there is no sense information, request it.  If we have already
+     * requested it, there is no point in asking again - the firmware must
+     * be confused. 
+     */
+    if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
+       if(!(SCpnt->flags & ASKED_FOR_SENSE))
+           return SUGGEST_SENSE;
+       else
+           return SUGGEST_RETRY;
+    }
+    
+    SCpnt->flags &= ~ASKED_FOR_SENSE;
+    
 #ifdef DEBUG_INIT
-       printk("scsi%d : ", SCpnt->host->host_no);
-       print_sense("", SCpnt);
-       printk("\n");
+    printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
+    print_sense("", SCpnt);
+    printk("\n");
 #endif
-               if (SCpnt->sense_buffer[2] &0xe0)
-                 return SUGGEST_ABORT;
-
-               switch (SCpnt->sense_buffer[2] & 0xf)
-               {
-               case NO_SENSE:
-                       return 0;
-               case RECOVERED_ERROR:
-                       return SUGGEST_IS_OK;
-
-               case ABORTED_COMMAND:
-                       return SUGGEST_RETRY;
-               case NOT_READY:
-               case UNIT_ATTENTION:
-                       return SUGGEST_ABORT;
-
-               /* these three are not supported */
-               case COPY_ABORTED:
-               case VOLUME_OVERFLOW:
-               case MISCOMPARE:
-
-               case MEDIUM_ERROR:
-                       return SUGGEST_REMAP;
-               case BLANK_CHECK:
-               case DATA_PROTECT:
-               case HARDWARE_ERROR:
-               case ILLEGAL_REQUEST:
-               default:
-                       return SUGGEST_ABORT;
-               }
-             }
+    if (SCpnt->sense_buffer[2] & 0xe0)
+       return SUGGEST_ABORT;
+    
+    switch (SCpnt->sense_buffer[2] & 0xf)
+    {
+    case NO_SENSE:
+       return 0;
+    case RECOVERED_ERROR:
+       return SUGGEST_IS_OK;
+       
+    case ABORTED_COMMAND:
+       return SUGGEST_RETRY;
+    case NOT_READY:
+    case UNIT_ATTENTION:
+       return SUGGEST_ABORT;
+       
+    /* these three are not supported */
+    case COPY_ABORTED:
+    case VOLUME_OVERFLOW:
+    case MISCOMPARE:
+       
+    case MEDIUM_ERROR:
+       return SUGGEST_REMAP;
+    case BLANK_CHECK:
+    case DATA_PROTECT:
+    case HARDWARE_ERROR:
+    case ILLEGAL_REQUEST:
+    default:
+       return SUGGEST_ABORT;
+    }
+}
 
 /* This function is the mid-level interrupt routine, which decides how
  *  to handle error conditions.  Each invocation of this function must
@@ -1168,665 +1281,669 @@ static int check_sense (Scsi_Cmnd * SCpnt)
  *      called again once the reset is complete.
  *
  *      If none of the above actions are taken, the drive in question
- * will hang. If more than one of the above actions are taken by
- * scsi_done, then unpredictable behavior will result.
+ *      will hang. If more than one of the above actions are taken by
+ *      scsi_done, then unpredictable behavior will result.
  */
 static void scsi_done (Scsi_Cmnd * SCpnt)
-       {
-       int status=0;
-       int exit=0;
-       int checked;
-       int oldto;
-       struct Scsi_Host * host = SCpnt->host;
-       int result = SCpnt->result;
-       oldto = update_timeout(SCpnt, 0);
-
+{
+    int status=0;
+    int exit=0;
+    int checked;
+    int oldto;
+    struct Scsi_Host * host = SCpnt->host;
+    int result = SCpnt->result;
+    oldto = update_timeout(SCpnt, 0);
+    
 #ifdef DEBUG_TIMEOUT
-       if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
-                         result, SCpnt->target, SCpnt->lun);
+    if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
+                     result, SCpnt->target, SCpnt->lun);
 #endif
-
-       /* If we requested an abort, (and we got it) then fix up the return
-          status to say why */
-       if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
-         SCpnt->result = result = (result & 0xff00ffff) |
+    
+    /* If we requested an abort, (and we got it) then fix up the return
+     *  status to say why 
+     */
+    if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
+       SCpnt->result = result = (result & 0xff00ffff) |
            (SCpnt->abort_reason << 16);
 
 
 #define FINISHED 0
 #define MAYREDO  1
-#define REDO    3
+#define REDO     3
 #define PENDING  4
 
 #ifdef DEBUG
-       printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
+    printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
 #endif
 
-       if(SCpnt->flags & WAS_SENSE)
+    if(SCpnt->flags & WAS_SENSE)
+    {
+       SCpnt->use_sg = SCpnt->old_use_sg;
+       SCpnt->cmd_len = SCpnt->old_cmd_len;
+    }
+
+    switch (host_byte(result))
+    {
+    case DID_OK:
+       if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
+           /* Failed to obtain sense information */
        {
-               SCpnt->use_sg = SCpnt->old_use_sg;
-               SCpnt->cmd_len = SCpnt->old_cmd_len;
+           SCpnt->flags &= ~WAS_SENSE;
+           SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+           
+           if (!(SCpnt->flags & WAS_RESET))
+           {
+               printk("scsi%d : channel %d target %d lun %d request sense"
+                      " failed, performing reset.\n",
+                      SCpnt->host->host_no, SCpnt->channel, SCpnt->target, 
+                      SCpnt->lun);
+               reset(SCpnt);
+               return;
+           }
+           else
+           {
+               exit = (DRIVER_HARD | SUGGEST_ABORT);
+               status = FINISHED;
+           }
        }
-
-       switch (host_byte(result))
+       else switch(msg_byte(result))
        {
-       case DID_OK:
-               if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
-                       /* Failed to obtain sense information */
-                       {
-                       SCpnt->flags &= ~WAS_SENSE;
-                       SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-
-                       if (!(SCpnt->flags & WAS_RESET))
-                               {
-                               printk("scsi%d : target %d lun %d request sense failed, performing reset.\n",
-                                       SCpnt->host->host_no, SCpnt->target, SCpnt->lun);
-                               reset(SCpnt);
-                               return;
-                               }
-                       else
-                               {
-                               exit = (DRIVER_HARD | SUGGEST_ABORT);
-                               status = FINISHED;
-                               }
-                       }
-               else switch(msg_byte(result))
-                       {
-                       case COMMAND_COMPLETE:
-                       switch (status_byte(result))
-                       {
-                       case GOOD:
-                               if (SCpnt->flags & WAS_SENSE)
-                                       {
+       case COMMAND_COMPLETE:
+           switch (status_byte(result))
+           {
+           case GOOD:
+               if (SCpnt->flags & WAS_SENSE)
+               {
 #ifdef DEBUG
-       printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");
+                   printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");
 #endif
-
-                                       SCpnt->flags &= ~WAS_SENSE;
-                                       SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-
-                                       switch (checked = check_sense(SCpnt))
-                                       {
-                                       case SUGGEST_SENSE:
-                                       case 0:
+                   SCpnt->flags &= ~WAS_SENSE;
+                   SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+                   
+                   switch (checked = check_sense(SCpnt))
+                   {
+                   case SUGGEST_SENSE:
+                   case 0:
 #ifdef DEBUG
-       printk("NO SENSE.  status = REDO\n");
+                       printk("NO SENSE.  status = REDO\n");
 #endif
-
-                                               update_timeout(SCpnt, oldto);
-                                               status = REDO;
-                                               break;
-                                       case SUGGEST_IS_OK:
-                                               break;
-                                       case SUGGEST_REMAP:
-                                       case SUGGEST_RETRY:
+                       update_timeout(SCpnt, oldto);
+                       status = REDO;
+                       break;
+                   case SUGGEST_IS_OK:
+                       break;
+                   case SUGGEST_REMAP:
+                   case SUGGEST_RETRY:
 #ifdef DEBUG
-       printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
+                       printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
 #endif
-
-                                               status = MAYREDO;
-                                               exit = DRIVER_SENSE | SUGGEST_RETRY;
-                                               break;
-                                       case SUGGEST_ABORT:
+                       status = MAYREDO;
+                       exit = DRIVER_SENSE | SUGGEST_RETRY;
+                       break;
+                   case SUGGEST_ABORT:
 #ifdef DEBUG
-       printk("SENSE SUGGEST ABORT - status = FINISHED");
+                       printk("SENSE SUGGEST ABORT - status = FINISHED");
 #endif
-
-                                               status = FINISHED;
-                                               exit =  DRIVER_SENSE | SUGGEST_ABORT;
-                                               break;
-                                       default:
-                                               printk ("Internal error %s %d \n", __FILE__,
-                                                       __LINE__);
-                                       }
-                                       }
-                               else
-                                       {
+                       status = FINISHED;
+                       exit =  DRIVER_SENSE | SUGGEST_ABORT;
+                       break;
+                   default:
+                       printk ("Internal error %s %d \n", __FILE__,
+                               __LINE__);
+                   }
+               }
+               else
+               {
 #ifdef DEBUG
-       printk("COMMAND COMPLETE message returned, status = FINISHED. \n");
+                   printk("COMMAND COMPLETE message returned, status = FINISHED. \n");
 #endif
-
-                                       exit =  DRIVER_OK;
-                                       status = FINISHED;
-                                       }
-                               break;
-
-                       case CHECK_CONDITION:
-                               switch (check_sense(SCpnt))
-                                 {
-                                 case 0:
-                                   update_timeout(SCpnt, oldto);
-                                   status = REDO;
-                                   break;
-                                 case SUGGEST_REMAP:
-                                 case SUGGEST_RETRY:
-                                   status = MAYREDO;
-                                   exit = DRIVER_SENSE | SUGGEST_RETRY;
-                                   break;
-                                 case SUGGEST_ABORT:
-                                   status = FINISHED;
-                                   exit =  DRIVER_SENSE | SUGGEST_ABORT;
-                                   break;
-                                 case SUGGEST_SENSE:
-                               scsi_request_sense (SCpnt);
-                               status = PENDING;
-                               break;
-                                 }
-                               break;
-
-                       case CONDITION_GOOD:
-                       case INTERMEDIATE_GOOD:
-                       case INTERMEDIATE_C_GOOD:
-                               break;
-
-                       case BUSY:
-                               update_timeout(SCpnt, oldto);
-                               status = REDO;
-                               break;
-
-                       case RESERVATION_CONFLICT:
-                               printk("scsi%d : RESERVATION CONFLICT performing reset.\n",
-                                       SCpnt->host->host_no);
-                               reset(SCpnt);
-                               return;
+                   exit =  DRIVER_OK;
+                   status = FINISHED;
+               }
+               break;
+               
+           case CHECK_CONDITION:
+               switch (check_sense(SCpnt))
+               {
+               case 0:
+                   update_timeout(SCpnt, oldto);
+                   status = REDO;
+                   break;
+               case SUGGEST_REMAP:
+               case SUGGEST_RETRY:
+                   status = MAYREDO;
+                   exit = DRIVER_SENSE | SUGGEST_RETRY;
+                   break;
+               case SUGGEST_ABORT:
+                   status = FINISHED;
+                   exit =  DRIVER_SENSE | SUGGEST_ABORT;
+                   break;
+               case SUGGEST_SENSE:
+                   scsi_request_sense (SCpnt);
+                   status = PENDING;
+                   break;
+               }
+               break;
+               
+           case CONDITION_GOOD:
+           case INTERMEDIATE_GOOD:
+           case INTERMEDIATE_C_GOOD:
+               break;
+               
+           case BUSY:
+               update_timeout(SCpnt, oldto);
+               status = REDO;
+               break;
+               
+           case RESERVATION_CONFLICT:
+               printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
+                      " reset.\n", SCpnt->host->host_no, SCpnt->channel);
+               reset(SCpnt);
+               return;
 #if 0
-                               exit = DRIVER_SOFT | SUGGEST_ABORT;
-                               status = MAYREDO;
-                               break;
+               exit = DRIVER_SOFT | SUGGEST_ABORT;
+               status = MAYREDO;
+               break;
 #endif
-                       default:
-                               printk ("Internal error %s %d \n"
-                                       "status byte = %d \n", __FILE__,
-                                       __LINE__, status_byte(result));
-
-                       }
-                       break;
-                       default:
-                               panic("scsi: unsupported message byte %d received\n", msg_byte(result));
-                       }
-                       break;
-       case DID_TIME_OUT:
+           default:
+               printk ("Internal error %s %d \n"
+                       "status byte = %d \n", __FILE__,
+                       __LINE__, status_byte(result));
+               
+           }
+           break;
+       default:
+           panic("scsi: unsupported message byte %d received\n", 
+                 msg_byte(result));
+       }
+       break;
+    case DID_TIME_OUT:
 #ifdef DEBUG
        printk("Host returned DID_TIME_OUT - ");
 #endif
-
-               if (SCpnt->flags & WAS_TIMEDOUT)
-                       {
+       
+       if (SCpnt->flags & WAS_TIMEDOUT)
+       {
 #ifdef DEBUG
-       printk("Aborting\n");
+           printk("Aborting\n");
 #endif
-                       exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
-                       }
-               else
-                       {
+           exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
+       }
+       else
+       {
 #ifdef DEBUG
-                       printk ("Retrying.\n");
+           printk ("Retrying.\n");
 #endif
-                       SCpnt->flags  |= WAS_TIMEDOUT;
-                       SCpnt->internal_timeout &= ~IN_ABORT;
-                       status = REDO;
-                       }
-               break;
-       case DID_BUS_BUSY:
-       case DID_PARITY:
-               status = REDO;
-               break;
-       case DID_NO_CONNECT:
+           SCpnt->flags  |= WAS_TIMEDOUT;
+           SCpnt->internal_timeout &= ~IN_ABORT;
+           status = REDO;
+       }
+       break;
+    case DID_BUS_BUSY:
+    case DID_PARITY:
+       status = REDO;
+       break;
+    case DID_NO_CONNECT:
 #ifdef DEBUG
-               printk("Couldn't connect.\n");
+       printk("Couldn't connect.\n");
 #endif
-               exit  = (DRIVER_HARD | SUGGEST_ABORT);
+       exit  = (DRIVER_HARD | SUGGEST_ABORT);
+       break;
+    case DID_ERROR:
+       status = MAYREDO;
+       exit = (DRIVER_HARD | SUGGEST_ABORT);
+       break;
+    case DID_BAD_TARGET:
+    case DID_ABORT:
+       exit = (DRIVER_INVALID | SUGGEST_ABORT);
+       break;
+    case DID_RESET:
+       if (SCpnt->flags & IS_RESETTING)
+       {
+           SCpnt->flags &= ~IS_RESETTING;
+           status = REDO;
+           break;
+       }
+       
+       if(msg_byte(result) == GOOD &&
+          status_byte(result) == CHECK_CONDITION) {
+           switch (check_sense(SCpnt)) {
+           case 0:
+               update_timeout(SCpnt, oldto);
+               status = REDO;
                break;
-       case DID_ERROR:
+           case SUGGEST_REMAP:
+           case SUGGEST_RETRY:
                status = MAYREDO;
-               exit = (DRIVER_HARD | SUGGEST_ABORT);
+               exit = DRIVER_SENSE | SUGGEST_RETRY;
                break;
-       case DID_BAD_TARGET:
-       case DID_ABORT:
-               exit = (DRIVER_INVALID | SUGGEST_ABORT);
+           case SUGGEST_ABORT:
+               status = FINISHED;
+               exit =  DRIVER_SENSE | SUGGEST_ABORT;
                break;
-       case DID_RESET:
-               if (SCpnt->flags & IS_RESETTING)
-                       {
-                       SCpnt->flags &= ~IS_RESETTING;
-                       status = REDO;
-                       break;
-                       }
-
-               if(msg_byte(result) == GOOD &&
-                     status_byte(result) == CHECK_CONDITION) {
-                       switch (check_sense(SCpnt)) {
-                       case 0:
-                           update_timeout(SCpnt, oldto);
-                           status = REDO;
-                           break;
-                       case SUGGEST_REMAP:
-                       case SUGGEST_RETRY:
-                           status = MAYREDO;
-                           exit = DRIVER_SENSE | SUGGEST_RETRY;
-                           break;
-                       case SUGGEST_ABORT:
-                           status = FINISHED;
-                           exit =  DRIVER_SENSE | SUGGEST_ABORT;
-                           break;
-                       case SUGGEST_SENSE:
-                             scsi_request_sense (SCpnt);
-                             status = PENDING;
-                             break;
-                       }
-               } else {
-               status=REDO;
-               exit = SUGGEST_RETRY;
-               }
+           case SUGGEST_SENSE:
+               scsi_request_sense (SCpnt);
+               status = PENDING;
                break;
-       default :
-               exit = (DRIVER_ERROR | SUGGEST_DIE);
+           }
+       } else {
+           status=REDO;
+           exit = SUGGEST_RETRY;
        }
-
-       switch (status)
-               {
-               case FINISHED:
-               case PENDING:
-                       break;
-               case MAYREDO:
-
+       break;
+    default :
+       exit = (DRIVER_ERROR | SUGGEST_DIE);
+    }
+    
+    switch (status)
+    {
+    case FINISHED:
+    case PENDING:
+       break;
+    case MAYREDO:
 #ifdef DEBUG
        printk("In MAYREDO, allowing %d retries, have %d\n",
               SCpnt->allowed, SCpnt->retries);
 #endif
-
-                       if ((++SCpnt->retries) < SCpnt->allowed)
-                       {
-                       if ((SCpnt->retries >= (SCpnt->allowed >> 1))
-                           && !(jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
-                           && !(SCpnt->flags & WAS_RESET))
-                               {
-                                       printk("scsi%d : resetting for second half of retries.\n",
-                                               SCpnt->host->host_no);
-                                       reset(SCpnt);
-                                       break;
-                               }
-
-                       }
-                       else
-                               {
-                               status = FINISHED;
-                               break;
-                               }
-                       /* fall through to REDO */
-
-               case REDO:
-
-                       if (SCpnt->flags & WAS_SENSE)
-                               scsi_request_sense(SCpnt);
-                       else
-                         {
-                           memcpy ((void *) SCpnt->cmnd,
-                                   (void*) SCpnt->data_cmnd,
-                                   sizeof(SCpnt->data_cmnd));
-                           SCpnt->request_buffer = SCpnt->buffer;
-                           SCpnt->request_bufflen = SCpnt->bufflen;
-                           SCpnt->use_sg = SCpnt->old_use_sg;
-                           SCpnt->cmd_len = SCpnt->old_cmd_len;
-                           internal_cmnd (SCpnt);
-                         }
-                       break;
-               default:
-                       INTERNAL_ERROR;
-               }
-
-
-       if (status == FINISHED) {
+       if ((++SCpnt->retries) < SCpnt->allowed)
+       {
+           if ((SCpnt->retries >= (SCpnt->allowed >> 1))
+               && !(jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
+               && !(SCpnt->flags & WAS_RESET))
+           {
+               printk("scsi%d channel %d : resetting for second half of retries.\n",
+                      SCpnt->host->host_no, SCpnt->channel);
+               reset(SCpnt);
+               break;
+           }
+           
+       }
+       else
+       {
+           status = FINISHED;
+           break;
+       }
+       /* fall through to REDO */
+       
+    case REDO:
+       
+       if (SCpnt->flags & WAS_SENSE)
+           scsi_request_sense(SCpnt);
+       else
+       {
+           memcpy ((void *) SCpnt->cmnd,
+                   (void*) SCpnt->data_cmnd,
+                   sizeof(SCpnt->data_cmnd));
+           SCpnt->request_buffer = SCpnt->buffer;
+           SCpnt->request_bufflen = SCpnt->bufflen;
+           SCpnt->use_sg = SCpnt->old_use_sg;
+           SCpnt->cmd_len = SCpnt->old_cmd_len;
+           internal_cmnd (SCpnt);
+       }
+       break;
+    default:
+       INTERNAL_ERROR;
+    }
+    
+    if (status == FINISHED) {
 #ifdef DEBUG
-          printk("Calling done function - at address %p\n", SCpnt->done);
+       printk("Calling done function - at address %p\n", SCpnt->done);
 #endif
-          host->host_busy--; /* Indicate that we are free */
-
-          if (host->block && host->host_busy == 0) {
-             host_active = NULL;
-
-             /* For block devices "wake_up" is done in end_scsi_request */
-             if (MAJOR(SCpnt->request.dev) != SCSI_DISK_MAJOR &&
-                       MAJOR(SCpnt->request.dev) != SCSI_CDROM_MAJOR) {
-                struct Scsi_Host * next;
-
-                for (next = host->block; next != host; next = next->block)
+       host->host_busy--; /* Indicate that we are free */
+       
+       if (host->block && host->host_busy == 0) {
+           host_active = NULL;
+           
+           /* For block devices "wake_up" is done in end_scsi_request */
+           if (MAJOR(SCpnt->request.dev) != SCSI_DISK_MAJOR &&
+               MAJOR(SCpnt->request.dev) != SCSI_CDROM_MAJOR) {
+               struct Scsi_Host * next;
+               
+               for (next = host->block; next != host; next = next->block)
                    wake_up(&next->host_wait);
-                }
-
-             }
-
-          wake_up(&host->host_wait);
-          SCpnt->result = result | ((exit & 0xff) << 24);
-          SCpnt->use_sg = SCpnt->old_use_sg;
-          SCpnt->cmd_len = SCpnt->old_cmd_len;
-          SCpnt->done (SCpnt);
-          }
-
+           }
+           
+       }
+       
+       wake_up(&host->host_wait);
+       SCpnt->result = result | ((exit & 0xff) << 24);
+       SCpnt->use_sg = SCpnt->old_use_sg;
+       SCpnt->cmd_len = SCpnt->old_cmd_len;
+       SCpnt->done (SCpnt);
+    }
+    
 #undef FINISHED
 #undef REDO
 #undef MAYREDO
 #undef PENDING
-       }
+}
 
 /*
      The scsi_abort function interfaces with the abort() function of the host
      we are aborting, and causes the current command to not complete.  The
      caller should deal with any error messages or status returned on the
      next call.
-
      This will not be called reentrantly for a given host.
-*/
* The scsi_abort function interfaces with the abort() function of the host
* we are aborting, and causes the current command to not complete.  The
* caller should deal with any error messages or status returned on the
* next call.
+ * 
* This will not be called reentrantly for a given host.
+ */
 
 /*
      Since we're nice guys and specified that abort() and reset()
      can be non-reentrant.  The internal_timeout flags are used for
      this.
-*/
* Since we're nice guys and specified that abort() and reset()
* can be non-reentrant.  The internal_timeout flags are used for
* this.
+ */
 
 
 int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
-       {
-       int oldto;
-       unsigned long flags;
-       struct Scsi_Host * host = SCpnt->host;
-
-       while(1)
-               {
-               save_flags(flags);
-               cli();
+{
+    int oldto;
+    unsigned long flags;
+    struct Scsi_Host * host = SCpnt->host;
+    
+    while(1)
+    {
+       save_flags(flags);
+       cli();
+       
+       /*
+        * Protect against races here.  If the command is done, or we are
+        * on a different command forget it.
+        */
+       if (SCpnt->request.dev == -1 || pid != SCpnt->pid) {
+           restore_flags(flags);
+           return 0;
+       }
 
-               /*
-                * Protect against races here.  If the command is done, or we are
-                * on a different command forget it.
+       if (SCpnt->internal_timeout & IN_ABORT)
+       {
+           restore_flags(flags);
+           while (SCpnt->internal_timeout & IN_ABORT)
+               barrier();
+       }
+       else
+       {
+           SCpnt->internal_timeout |= IN_ABORT;
+           oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
+           
+           if ((SCpnt->flags & IS_RESETTING) &&
+               SCpnt->device->soft_reset) {
+               /* OK, this command must have died when we did the
+                *  reset.  The device itself must have lied. 
                 */
-               if (SCpnt->request.dev == -1 || pid != SCpnt->pid) {
-                 restore_flags(flags);
-                 return 0;
-               }
-
-               if (SCpnt->internal_timeout & IN_ABORT)
-                       {
-                       restore_flags(flags);
-                       while (SCpnt->internal_timeout & IN_ABORT)
-                               barrier();
-                       }
-               else
-                       {
-                       SCpnt->internal_timeout |= IN_ABORT;
-                       oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
-
-                       if ((SCpnt->flags & IS_RESETTING) &&
-                           SCpnt->device->soft_reset) {
-                         /* OK, this command must have died when we did the
-                            reset.  The device itself must have lied. */
-                         printk("Stale command on %d:%d appears to have died when"
-                                " the bus was reset\n", SCpnt->target, SCpnt->lun);
-                       }
-
+               printk("Stale command on %d %d:%d appears to have died when"
+                      " the bus was reset\n", 
+                      SCpnt->channel, SCpnt->target, SCpnt->lun);
+           }
+           
+           restore_flags(flags);
+           if (!host->host_busy) {
+               SCpnt->internal_timeout &= ~IN_ABORT;
+               update_timeout(SCpnt, oldto);
+               return 0;
+           }
+           printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
+                  " channel %d, id %d, lun %d ",
+                  SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel, 
+                  (int) SCpnt->target, (int) SCpnt->lun);
+           print_command (SCpnt->cmnd);
+           if (SCpnt->request.dev == -1 || pid != SCpnt->pid)
+               return 0;
+           SCpnt->abort_reason = why;
+           switch(host->hostt->abort(SCpnt)) {
+               /* We do not know how to abort.  Try waiting another
+                * time increment and see if this helps. Set the
+                * WAS_TIMEDOUT flag set so we do not try this twice
+                */
+           case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
+                                  * this is too severe 
+                                  */
+           case SCSI_ABORT_SNOOZE:
+               if(why == DID_TIME_OUT) {
+                   save_flags(flags);
+                   cli();
+                   SCpnt->internal_timeout &= ~IN_ABORT;
+                   if(SCpnt->flags & WAS_TIMEDOUT) {
                        restore_flags(flags);
-                       if (!host->host_busy) {
-                         SCpnt->internal_timeout &= ~IN_ABORT;
-                         update_timeout(SCpnt, oldto);
-                         return 0;
-                       }
-                       printk("scsi : aborting command due to timeout : pid %lu, scsi%d, id %d, lun %d ",
-                              SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->target, (int)
-                              SCpnt->lun);
-                       print_command (SCpnt->cmnd);
-                       if (SCpnt->request.dev == -1 || pid != SCpnt->pid)
-                         return 0;
-                       SCpnt->abort_reason = why;
-                       switch(host->hostt->abort(SCpnt)) {
-                         /* We do not know how to abort.  Try waiting another
-                            time increment and see if this helps. Set the
-                            WAS_TIMEDOUT flag set so we do not try this twice
-                            */
-                       case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
-                                                this is too severe */
-                       case SCSI_ABORT_SNOOZE:
-                         if(why == DID_TIME_OUT) {
-                           save_flags(flags);
-                           cli();
-                           SCpnt->internal_timeout &= ~IN_ABORT;
-                           if(SCpnt->flags & WAS_TIMEDOUT) {
-                             restore_flags(flags);
-                             return 1; /* Indicate we cannot handle this.
-                                          We drop down into the reset handler
-                                          and try again */
-                           } else {
-                             SCpnt->flags |= WAS_TIMEDOUT;
-                             oldto = SCpnt->timeout_per_command;
-                             update_timeout(SCpnt, oldto);
-                           }
-                           restore_flags(flags);
-                         }
-                         return 0;
-                       case SCSI_ABORT_PENDING:
-                         if(why != DID_TIME_OUT) {
-                           save_flags(flags);
-                           cli();
-                           update_timeout(SCpnt, oldto);
-                           restore_flags(flags);
-                         }
-                         return 0;
-                       case SCSI_ABORT_SUCCESS:
-                         /* We should have already aborted this one.  No
-                            need to adjust timeout */
-                       case SCSI_ABORT_NOT_RUNNING:
-                         SCpnt->internal_timeout &= ~IN_ABORT;
-                         update_timeout(SCpnt, 0);
-                         return 0;
-                       case SCSI_ABORT_ERROR:
-                       default:
-                         SCpnt->internal_timeout &= ~IN_ABORT;
-                         return 1;
-                       }
-                     }
-             }
-      }
+                       return 1; /* Indicate we cannot handle this.
+                                  * We drop down into the reset handler
+                                  * and try again 
+                                  */
+                   } else {
+                       SCpnt->flags |= WAS_TIMEDOUT;
+                       oldto = SCpnt->timeout_per_command;
+                       update_timeout(SCpnt, oldto);
+                   }
+                   restore_flags(flags);
+               }
+               return 0;
+           case SCSI_ABORT_PENDING:
+               if(why != DID_TIME_OUT) {
+                   save_flags(flags);
+                   cli();
+                   update_timeout(SCpnt, oldto);
+                   restore_flags(flags);
+               }
+               return 0;
+           case SCSI_ABORT_SUCCESS:
+               /* We should have already aborted this one.  No
+                * need to adjust timeout 
+                */
+           case SCSI_ABORT_NOT_RUNNING:
+               SCpnt->internal_timeout &= ~IN_ABORT;
+               update_timeout(SCpnt, 0);
+               return 0;
+           case SCSI_ABORT_ERROR:
+           default:
+               SCpnt->internal_timeout &= ~IN_ABORT;
+               return 1;
+           }
+       }
+    }
+}
 
 int scsi_reset (Scsi_Cmnd * SCpnt)
-       {
-       int temp, oldto;
-       unsigned long flags;
-       Scsi_Cmnd * SCpnt1;
-       struct Scsi_Host * host = SCpnt->host;
+{
+    int temp, oldto;
+    unsigned long flags;
+    Scsi_Cmnd * SCpnt1;
+    struct Scsi_Host * host = SCpnt->host;
 
 #ifdef DEBUG
-       printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",host->host_no);
+    printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",
+          host->host_no);
 #endif
-       while (1) {
-               save_flags(flags);
-               cli();
-               if (SCpnt->internal_timeout & IN_RESET)
-                       {
-                       restore_flags(flags);
-                       while (SCpnt->internal_timeout & IN_RESET)
-                               barrier();
-                       }
-               else
-                       {
-                       SCpnt->internal_timeout |= IN_RESET;
-                       oldto = update_timeout(SCpnt, RESET_TIMEOUT);
-
-                       if (host->host_busy)
-                               {
-                               restore_flags(flags);
-                               SCpnt1 = host->host_queue;
-                               while(SCpnt1) {
-                                 if (SCpnt1->request.dev > 0) {
+    while (1) {
+       save_flags(flags);
+       cli();
+       if (SCpnt->internal_timeout & IN_RESET)
+       {
+           restore_flags(flags);
+           while (SCpnt->internal_timeout & IN_RESET)
+               barrier();
+       }
+       else
+       {
+           SCpnt->internal_timeout |= IN_RESET;
+           oldto = update_timeout(SCpnt, RESET_TIMEOUT);
+           
+           if (host->host_busy)
+           {
+               restore_flags(flags);
+               SCpnt1 = host->host_queue;
+               while(SCpnt1) {
+                   if (SCpnt1->request.dev > 0) {
 #if 0
-                                   if (!(SCpnt1->flags & IS_RESETTING) &&
-                                     !(SCpnt1->internal_timeout & IN_ABORT))
-                                   scsi_abort(SCpnt1, DID_RESET, SCpnt->pid);
+                       if (!(SCpnt1->flags & IS_RESETTING) &&
+                           !(SCpnt1->internal_timeout & IN_ABORT))
+                           scsi_abort(SCpnt1, DID_RESET, SCpnt->pid);
 #endif
-                                   SCpnt1->flags |= IS_RESETTING;
-                                 }
-                                 SCpnt1 = SCpnt1->next;
-                               }
-
-                               host->last_reset = jiffies;
-                               temp = host->hostt->reset(SCpnt);
-                               host->last_reset = jiffies;
-                               }
-                       else
-                               {
-                               if (!host->block) host->host_busy++;
-                               restore_flags(flags);
-                               host->last_reset = jiffies;
-                               temp = host->hostt->reset(SCpnt);
-                               host->last_reset = jiffies;
-                               if (!host->block) host->host_busy--;
-                               }
-
+                       SCpnt1->flags |= IS_RESETTING;
+                   }
+                   SCpnt1 = SCpnt1->next;
+               }
+               
+               host->last_reset = jiffies;
+               temp = host->hostt->reset(SCpnt);
+               host->last_reset = jiffies;
+           }
+           else
+           {
+               if (!host->block) host->host_busy++;
+               restore_flags(flags);
+               host->last_reset = jiffies;
+               temp = host->hostt->reset(SCpnt);
+               host->last_reset = jiffies;
+               if (!host->block) host->host_busy--;
+           }
+           
 #ifdef DEBUG
-                       printk("scsi reset function returned %d\n", temp);
+           printk("scsi reset function returned %d\n", temp);
 #endif
-                       switch(temp) {
-                       case SCSI_RESET_SUCCESS:
-                         save_flags(flags);
-                         cli();
-                         SCpnt->internal_timeout &= ~IN_RESET;
-                         update_timeout(SCpnt, oldto);
-                         restore_flags(flags);
-                         return 0;
-                       case SCSI_RESET_PENDING:
-                         return 0;
-                       case SCSI_RESET_PUNT:
-                       case SCSI_RESET_WAKEUP:
-                         SCpnt->internal_timeout &= ~IN_RESET;
-                         scsi_request_sense (SCpnt);
-                         return 0;
-                       case SCSI_RESET_SNOOZE:
-                         /* In this case, we set the timeout field to 0
-                            so that this command does not time out any more,
-                            and we return 1 so that we get a message on the
-                            screen. */
-                         save_flags(flags);
-                         cli();
-                         SCpnt->internal_timeout &= ~IN_RESET;
-                         update_timeout(SCpnt, 0);
-                         restore_flags(flags);
-                         /* If you snooze, you lose... */
-                       case SCSI_RESET_ERROR:
-                       default:
-                         return 1;
-                       }
-
-                       return temp;
-                       }
-               }
+           switch(temp) {
+           case SCSI_RESET_SUCCESS:
+               save_flags(flags);
+               cli();
+               SCpnt->internal_timeout &= ~IN_RESET;
+               update_timeout(SCpnt, oldto);
+               restore_flags(flags);
+               return 0;
+           case SCSI_RESET_PENDING:
+               return 0;
+           case SCSI_RESET_PUNT:
+           case SCSI_RESET_WAKEUP:
+               SCpnt->internal_timeout &= ~IN_RESET;
+               scsi_request_sense (SCpnt);
+               return 0;
+           case SCSI_RESET_SNOOZE:
+               /* In this case, we set the timeout field to 0
+                * so that this command does not time out any more,
+                * and we return 1 so that we get a message on the
+                * screen. 
+                */
+               save_flags(flags);
+               cli();
+               SCpnt->internal_timeout &= ~IN_RESET;
+               update_timeout(SCpnt, 0);
+               restore_flags(flags);
+               /* If you snooze, you lose... */
+           case SCSI_RESET_ERROR:
+           default:
+               return 1;
+           }
+           
+           return temp;
        }
+    }
+}
 
 
 static void scsi_main_timeout(void)
-       {
-       /*
-               We must not enter update_timeout with a timeout condition still pending.
-       */
-
-       int timed_out, pid;
-       unsigned long flags;
-       struct Scsi_Host * host;
-       Scsi_Cmnd * SCpnt = NULL;
-
-       do {
-               save_flags(flags);
-               cli();
-
-               update_timeout(NULL, 0);
+{
+    /*
+     * We must not enter update_timeout with a timeout condition still pending.
+     */
+    
+    int timed_out, pid;
+    unsigned long flags;
+    struct Scsi_Host * host;
+    Scsi_Cmnd * SCpnt = NULL;
+    
+    do {
+       save_flags(flags);
+       cli();
+       
+       update_timeout(NULL, 0);
        /*
-               Find all timers such that they have 0 or negative (shouldn't happen)
-               time remaining on them.
-       */
-
-               timed_out = 0;
-               for(host = scsi_hostlist; host; host = host->next) {
-                 for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
-                   if (SCpnt->timeout == -1)
-                     {
-                       SCpnt->timeout = 0;
-                       pid = SCpnt->pid;
-                       restore_flags(flags);
-                       scsi_times_out(SCpnt, pid);
-                       ++timed_out;
-                       save_flags(flags);
-                       cli();
-                     }
+        * Find all timers such that they have 0 or negative (shouldn't happen)
+        * time remaining on them.
+        */
+       
+       timed_out = 0;
+       for(host = scsi_hostlist; host; host = host->next) {
+           for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
+               if (SCpnt->timeout == -1)
+               {
+                   SCpnt->timeout = 0;
+                   pid = SCpnt->pid;
+                   restore_flags(flags);
+                   scsi_times_out(SCpnt, pid);
+                   ++timed_out;
+                   save_flags(flags);
+                   cli();
                }
-             } while (timed_out);
-       restore_flags(flags);
-      }
+       }
+    } while (timed_out);
+    restore_flags(flags);
+}
 
 /*
      The strategy is to cause the timer code to call scsi_times_out()
      when the soonest timeout is pending.
      The arguments are used when we are queueing a new command, because
      we do not want to subtract the time used from this time, but when we
      set the timer, we want to take this value into account.
-*/
* The strategy is to cause the timer code to call scsi_times_out()
* when the soonest timeout is pending.
* The arguments are used when we are queueing a new command, because
* we do not want to subtract the time used from this time, but when we
* set the timer, we want to take this value into account.
+ */
 
 static int update_timeout(Scsi_Cmnd * SCset, int timeout)
-       {
-       unsigned int least, used;
-       unsigned int oldto;
-       unsigned long flags;
-       struct Scsi_Host * host;
-       Scsi_Cmnd * SCpnt = NULL;
-
-       save_flags(flags);
-       cli();
-
-/*
-       Figure out how much time has passed since the last time the timeouts
-       were updated
-*/
-       used = (time_start) ? (jiffies - time_start) : 0;
+{
+    unsigned int least, used;
+    unsigned int oldto;
+    unsigned long flags;
+    struct Scsi_Host * host;
+    Scsi_Cmnd * SCpnt = NULL;
 
-/*
-       Find out what is due to timeout soonest, and adjust all timeouts for
-       the amount of time that has passed since the last time we called
-       update_timeout.
-*/
+    save_flags(flags);
+    cli();
 
-       oldto = 0;
+    /*
+     * Figure out how much time has passed since the last time the timeouts
+     * were updated
+     */
+    used = (time_start) ? (jiffies - time_start) : 0;
 
-       if(SCset){
-         oldto = SCset->timeout - used;
-         SCset->timeout = timeout + used;
-       }
+    /*
+     * Find out what is due to timeout soonest, and adjust all timeouts for
+     * the amount of time that has passed since the last time we called
+     * update_timeout.
+     */
 
-       least = 0xffffffff;
+    oldto = 0;
+    
+    if(SCset){
+       oldto = SCset->timeout - used;
+       SCset->timeout = timeout + used;
+    }
 
-       for(host = scsi_hostlist; host; host = host->next)
-         for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
+    least = 0xffffffff;
+    
+    for(host = scsi_hostlist; host; host = host->next)
+       for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
            if (SCpnt->timeout > 0) {
-             SCpnt->timeout -= used;
-             if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
-             if(SCpnt->timeout > 0 && SCpnt->timeout < least)
-               least = SCpnt->timeout;
+               SCpnt->timeout -= used;
+               if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
+               if(SCpnt->timeout > 0 && SCpnt->timeout < least)
+                   least = SCpnt->timeout;
            }
-
-/*
-       If something is due to timeout again, then we will set the next timeout
-       interrupt to occur.  Otherwise, timeouts are disabled.
-*/
-
-       if (least != 0xffffffff)
-               {
-               time_start = jiffies;
-               timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
-               timer_active |= 1 << SCSI_TIMER;
-               }
-       else
-               {
-               timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
-               timer_active &= ~(1 << SCSI_TIMER);
-               }
-       restore_flags(flags);
-       return oldto;
-       }
+    
+    /*
+     * If something is due to timeout again, then we will set the next timeout
+     * interrupt to occur.  Otherwise, timeouts are disabled.
+     */
+    
+    if (least != 0xffffffff)
+    {
+       time_start = jiffies;
+       timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
+       timer_active |= 1 << SCSI_TIMER;
+    }
+    else
+    {
+       timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
+       timer_active &= ~(1 << SCSI_TIMER);
+    }
+    restore_flags(flags);
+    return oldto;
+}
 
 
 static unsigned char * dma_malloc_freelist = NULL;
@@ -1842,77 +1959,78 @@ static void scsi_unregister_host(Scsi_Host_Template *);
 
 void *scsi_malloc(unsigned int len)
 {
-  unsigned int nbits, mask;
-  unsigned long flags;
-  int i, j;
-  if((len & 0x1ff) || len > (1<<MALLOC_PAGEBITS))
-    return NULL;
-
-  save_flags(flags);
-  cli();
-  nbits = len >> 9;
-  mask = (1 << nbits) - 1;
-
-  for(i=0;i < (dma_sectors >> (MALLOC_PAGEBITS - 9)); i++)
-    for(j=0; j<=(sizeof(*dma_malloc_freelist) * 8) - nbits; j++){
-      if ((dma_malloc_freelist[i] & (mask << j)) == 0){
-       dma_malloc_freelist[i] |= (mask << j);
-       restore_flags(flags);
-       dma_free_sectors -= nbits;
+    unsigned int nbits, mask;
+    unsigned long flags;
+    int i, j;
+    if((len & 0x1ff) || len > (1<<MALLOC_PAGEBITS))
+       return NULL;
+    
+    save_flags(flags);
+    cli();
+    nbits = len >> 9;
+    mask = (1 << nbits) - 1;
+    
+    for(i=0;i < (dma_sectors >> (MALLOC_PAGEBITS - 9)); i++)
+       for(j=0; j<=(sizeof(*dma_malloc_freelist) * 8) - nbits; j++){
+           if ((dma_malloc_freelist[i] & (mask << j)) == 0){
+               dma_malloc_freelist[i] |= (mask << j);
+               restore_flags(flags);
+               dma_free_sectors -= nbits;
 #ifdef DEBUG
-       printk("SMalloc: %d %p ",len, dma_malloc_pages[i] + (j << 9));
+               printk("SMalloc: %d %p ",len, dma_malloc_pages[i] + (j << 9));
 #endif
-       return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
-      }
-    }
-  restore_flags(flags);
-  return NULL;  /* Nope.  No more */
+               return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
+           }
+       }
+    restore_flags(flags);
+    return NULL;  /* Nope.  No more */
 }
 
 int scsi_free(void *obj, unsigned int len)
 {
-  int page, sector, nbits, mask;
-  long offset;
-  unsigned long flags;
-
+    int page, sector, nbits, mask;
+    long offset;
+    unsigned long flags;
+    
 #ifdef DEBUG
-  printk("Sfree %p %d\n",obj, len);
+    printk("Sfree %p %d\n",obj, len);
 #endif
-
-   offset = -1;
-  for (page = 0; page < (dma_sectors >> 3); page++)
+    
+    offset = -1;
+    for (page = 0; page < (dma_sectors >> 3); page++)
        if ((unsigned long) obj >= (unsigned long) dma_malloc_pages[page] &&
-               (unsigned long) obj < (unsigned long) dma_malloc_pages[page] + (1 << MALLOC_PAGEBITS))
-               {
-                       offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
-                       break;
-               }
-
-  if (page == (dma_sectors >> 3)) panic("Bad offset");
-  sector = offset >> 9;
-  if(sector >= dma_sectors) panic ("Bad page");
-
-  sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1);
-  nbits = len >> 9;
-  mask = (1 << nbits) - 1;
-
-  if ((mask << sector) > 0xffff) panic ("Bad memory alignment");
-
-  save_flags(flags);
-  cli();
-  if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector))
-    panic("Trying to free unused memory");
-
-  dma_free_sectors += nbits;
-  dma_malloc_freelist[page] &= ~(mask << sector);
-  restore_flags(flags);
-  return 0;
+           (unsigned long) obj < (unsigned long) dma_malloc_pages[page] 
+           + (1 << MALLOC_PAGEBITS))
+       {
+           offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
+           break;
+       }
+    
+    if (page == (dma_sectors >> 3)) panic("Bad offset");
+    sector = offset >> 9;
+    if(sector >= dma_sectors) panic ("Bad page");
+    
+    sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1);
+    nbits = len >> 9;
+    mask = (1 << nbits) - 1;
+    
+    if ((mask << sector) > 0xffff) panic ("Bad memory alignment");
+    
+    save_flags(flags);
+    cli();
+    if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector))
+       panic("Trying to free unused memory");
+    
+    dma_free_sectors += nbits;
+    dma_malloc_freelist[page] &= ~(mask << sector);
+    restore_flags(flags);
+    return 0;
 }
 
-
-/* These are special functions that can be used to obtain memory at boot time.
-   They act line a malloc function, but they simply take memory from the
  pool */
+/*
+ * These are special functions that can be used to obtain memory at boot time.
+ * They act line a malloc function, but they simply take memory from the pool 
+ */
 
 static unsigned long scsi_init_memory_start = 0;
 static unsigned long scsi_memory_lower_value = 0;
@@ -1921,234 +2039,312 @@ int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
 
 void * scsi_init_malloc(unsigned int size, int priority)
 {
-  unsigned long retval;
-
-/* Use the statically allocated memory instead of kmalloc  (DB) */
+    unsigned long retval;
+    
+    /* Use the statically allocated memory instead of kmalloc  (DB) */
 #if defined(USE_STATIC_SCSI_MEMORY)
-  if(scsi_loadable_module_flag && !(priority & GFP_DMA))
+    if(scsi_loadable_module_flag && !(priority & GFP_DMA))
 #else
-  if(scsi_loadable_module_flag)
+       if(scsi_loadable_module_flag)
 #endif
-    retval = (unsigned long) kmalloc(size, priority);
-  else {
-    /*
-     * Keep all memory aligned on 16-byte boundaries. Some host adaptors
-     * (e.g. BusLogic BT-445S) require DMA buffers to be aligned that way.
-     */
-    size = (size + 15) & ~15;
-
-    if(scsi_loadable_module_flag &&
-       (scsi_init_memory_start + size) > scsi_memory_upper_value) {
-       retval = 0;
-       printk("scsi_init_malloc: no more statically allocated memory.\n");
-       }
-    else {
-       retval = scsi_init_memory_start;
-       scsi_init_memory_start += size;
-       }
-    }
-  memset((void *) retval, 0, size);
-  return (void *) retval;
+       {
+           /*
+            * For buffers used by the DMA pool, we assume page aligned 
+            * structures.
+            */
+           if(size == PAGE_SIZE)
+               retval = (unsigned long) __get_dma_pages(priority & GFP_LEVEL_MASK, 0);
+           else
+               retval = (unsigned long) kmalloc(size, priority);
+       } else {
+           /*
+            * Keep all memory aligned on 16-byte boundaries. Some host 
+            * adaptors (e.g. BusLogic BT-445S) require DMA buffers to be 
+            * aligned that way.
+            */
+           size = (size + 15) & ~15;
+           
+           if(scsi_loadable_module_flag &&
+              (scsi_init_memory_start + size) > scsi_memory_upper_value) {
+               retval = 0;
+               printk("scsi_init_malloc: no more statically allocated memory.\n");
+           }
+           else {
+               retval = scsi_init_memory_start;
+               scsi_init_memory_start += size;
+           }
+       }
+    memset((void *) retval, 0, size);
+    return (void *) retval;
 }
 
 
 void scsi_init_free(char * ptr, unsigned int size)
-{ /* We need to compare addresses to see whether this was kmalloc'd or not */
-
-  if((unsigned long) ptr >= scsi_init_memory_start ||
-     (unsigned long) ptr <  scsi_memory_lower_value) kfree(ptr);
-  else {
-    size = (size + 15) & ~15; /* Use the same alignment as scsi_init_malloc() */
+{ 
+    /* We need to compare addresses to see whether this was kmalloc'd or not */
+    
+    if((unsigned long) ptr >= scsi_init_memory_start ||
+       (unsigned long) ptr <  scsi_memory_lower_value) {
+       /*
+        * We need this special code here because the DMA pool assumes
+        * page aligned data.  Besides, it is wasteful to allocate
+        * page sized chunks with kmalloc.
+        */
+       if(size == PAGE_SIZE)
+           free_pages((unsigned long)ptr, 0);
+       else
+           kfree(ptr);
+    } else {
+       /* Use the same alignment as scsi_init_malloc() */
+       size = (size + 15) & ~15;
+       
+       if(((unsigned long) ptr) + size == scsi_init_memory_start)
+           scsi_init_memory_start = (unsigned long) ptr;
+    }
+}
 
-    if(((unsigned long) ptr) + size == scsi_init_memory_start)
-      scsi_init_memory_start = (unsigned long) ptr;
+void scsi_build_commandblocks(Scsi_Device * SDpnt)
+{
+    int j;
+    Scsi_Cmnd * SCpnt;
+    struct Scsi_Host * host = NULL;
+    
+    for(j=0;j<SDpnt->host->cmd_per_lun;j++){
+       SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
+       SCpnt->host = SDpnt->host;
+       SCpnt->device = SDpnt;
+       SCpnt->target = SDpnt->id;
+       SCpnt->lun = SDpnt->lun;
+       SCpnt->channel = SDpnt->channel;
+       SCpnt->request.dev = -1; /* Mark not busy */
+       SCpnt->use_sg = 0;
+       SCpnt->old_use_sg = 0;
+       SCpnt->old_cmd_len = 0;
+       SCpnt->timeout = 0;
+       SCpnt->underflow = 0;
+       SCpnt->transfersize = 0;
+       SCpnt->host_scribble = NULL;
+       host = SDpnt->host;
+       if(host->host_queue)
+           host->host_queue->prev = SCpnt;
+       SCpnt->next = host->host_queue;
+       SCpnt->prev = NULL;
+       host->host_queue = SCpnt;
     }
 }
 
 /*
      scsi_dev_init() is our initialization routine, which in turn calls host
      initialization, bus scanning, and sd/st initialization routines.  It
      should be called from main().
-*/
* scsi_dev_init() is our initialization routine, which in turn calls host
* initialization, bus scanning, and sd/st initialization routines.  It
* should be called from main().
+ */
 
-unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end)
-       {
-       struct Scsi_Host * host = NULL;
-       Scsi_Device * SDpnt;
-       struct Scsi_Host * shpnt;
-       struct Scsi_Device_Template * sdtpnt;
-       Scsi_Cmnd * SCpnt;
-       int i;
+unsigned long scsi_dev_init (unsigned long memory_start, unsigned long memory_end)
+{
+    struct Scsi_Host * host = NULL;
+    Scsi_Device * SDpnt;
+    struct Scsi_Host * shpnt;
+    struct Scsi_Device_Template * sdtpnt;
+    int i;
 #ifdef FOO_ON_YOU
-       return;
+    return;
 #endif
 
-       /* Init a few things so we can "malloc" memory. */
-       scsi_loadable_module_flag = 0;
-       /* Align everything on 16-byte boundaries. */
-       scsi_init_memory_start = (memory_start + 15) & ~ 15;
-       scsi_memory_lower_value = scsi_init_memory_start;
+    /* Yes we're here... */
+    dispatch_scsi_info_ptr = dispatch_scsi_info;
 
-       timer_table[SCSI_TIMER].fn = scsi_main_timeout;
-       timer_table[SCSI_TIMER].expires = 0;
+    /* Init a few things so we can "malloc" memory. */
+    scsi_loadable_module_flag = 0;
+    
+    /* Align everything on 16-byte boundaries. */
+    scsi_init_memory_start = (memory_start + 15) & ~ 15;
+    scsi_memory_lower_value = scsi_init_memory_start;
+    
+    timer_table[SCSI_TIMER].fn = scsi_main_timeout;
+    timer_table[SCSI_TIMER].expires = 0;
 
-       /* initialize all hosts */
-       scsi_init();
+    /* initialize all hosts */
+    scsi_init();
 
-       scsi_devices = (Scsi_Device *) NULL;
+    scsi_devices = (Scsi_Device *) NULL;
 
-       for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-         scan_scsis(shpnt);           /* scan for scsi devices */
+    for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+       scan_scsis(shpnt,0,0,0,0);           /* scan for scsi devices */
 
-       printk("scsi : detected ");
-       for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-         if (sdtpnt->dev_noticed && sdtpnt->name)
+    printk("scsi : detected ");
+    for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+       if (sdtpnt->dev_noticed && sdtpnt->name)
            printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
-           (sdtpnt->dev_noticed != 1) ? "s" : "");
-       printk("total.\n");
+                  (sdtpnt->dev_noticed != 1) ? "s" : "");
+    printk("total.\n");
+    
+    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+       if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
 
+    for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
+       SDpnt->scsi_request_fn = NULL;
        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-         if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
-
-       for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
-         int j;
-         SDpnt->scsi_request_fn = NULL;
-         for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-             if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-
-         if(SDpnt->attached){
-           for(j=0;j<SDpnt->host->cmd_per_lun;j++){
-             SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
-             SCpnt->host = SDpnt->host;
-             SCpnt->device = SDpnt;
-             SCpnt->target = SDpnt->id;
-             SCpnt->lun = SDpnt->lun;
-             SCpnt->request.dev = -1; /* Mark not busy */
-             SCpnt->use_sg = 0;
-             SCpnt->old_use_sg = 0;
-             SCpnt->old_cmd_len = 0;
-             SCpnt->timeout = 0;
-             SCpnt->underflow = 0;
-             SCpnt->transfersize = 0;
-             SCpnt->host_scribble = NULL;
-             host = SDpnt->host;
-             if(host->host_queue)
-               host->host_queue->prev = SCpnt;
-             SCpnt->next = host->host_queue;
-             SCpnt->prev = NULL;
-             host->host_queue = SCpnt;
-           }
-         }
-       }
-
-       if (scsi_devicelist)
-         dma_sectors = 16;  /* Base value we use */
-
-       if (memory_end-1 > ISA_DMA_THRESHOLD)
-         scsi_need_isa_bounce_buffers = 1;
-       else
-         scsi_need_isa_bounce_buffers = 0;
-
-       for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
-         host = SDpnt->host;
-
-         if(SDpnt->type != TYPE_TAPE)
+           if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
+       if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+    }
+    
+    if (scsi_devicelist)
+       dma_sectors = 16;  /* Base value we use */
+    
+    if (memory_end-1 > ISA_DMA_THRESHOLD)
+       scsi_need_isa_bounce_buffers = 1;
+    else
+       scsi_need_isa_bounce_buffers = 0;
+    
+    for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
+       host = SDpnt->host;
+       
+       if(SDpnt->type != TYPE_TAPE)
            dma_sectors += ((host->sg_tablesize *
                             sizeof(struct scatterlist) + 511) >> 9) *
-                              host->cmd_per_lun;
-
-         if(host->unchecked_isa_dma &&
-            memory_end - 1 > ISA_DMA_THRESHOLD &&
-            SDpnt->type != TYPE_TAPE) {
+                                host->cmd_per_lun;
+       
+       if(host->unchecked_isa_dma &&
+          memory_end - 1 > ISA_DMA_THRESHOLD &&
+          SDpnt->type != TYPE_TAPE) {
            dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
-             host->cmd_per_lun;
+               host->cmd_per_lun;
            need_isa_buffer++;
-         }
        }
-
-       dma_sectors = (dma_sectors + 15) & 0xfff0;
-       dma_free_sectors = dma_sectors;  /* This must be a multiple of 16 */
-
-       dma_malloc_freelist = (unsigned char *)
-         scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
-       memset(dma_malloc_freelist, 0, dma_sectors >> 3);
-
-       dma_malloc_pages = (unsigned char **)
-         scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
-       memset(dma_malloc_pages, 0, dma_sectors >> 1);
-
-       for(i=0; i< dma_sectors >> 3; i++)
-         dma_malloc_pages[i] = (unsigned char *)
+    }
+    
+    dma_sectors = (dma_sectors + 15) & 0xfff0;
+    dma_free_sectors = dma_sectors;  /* This must be a multiple of 16 */
+    
+    dma_malloc_freelist = (unsigned char *)
+       scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
+    memset(dma_malloc_freelist, 0, dma_sectors >> 3);
+    
+    dma_malloc_pages = (unsigned char **)
+       scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
+    memset(dma_malloc_pages, 0, dma_sectors >> 1);
+    
+    for(i=0; i< dma_sectors >> 3; i++)
+       dma_malloc_pages[i] = (unsigned char *)
            scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-
-
-       /* OK, now we finish the initialization by doing spin-up, read
-          capacity, etc, etc */
-       for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-         if(sdtpnt->finish && sdtpnt->nr_dev)
+    
+    /* OK, now we finish the initialization by doing spin-up, read
+     * capacity, etc, etc 
+     */
+    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+       if(sdtpnt->finish && sdtpnt->nr_dev)
            (*sdtpnt->finish)();
-
-       scsi_loadable_module_flag = 1;
-
-
-/* This allocates statically some extra memory to be used for modules,
-   until the kmalloc problem is fixed (DB) */
-
+    
+    scsi_loadable_module_flag = 1;
+    
+    /* This allocates statically some extra memory to be used for modules,
+     * until the kmalloc problem is fixed (DB) 
+     */
+    
 #if defined(USE_STATIC_SCSI_MEMORY)
-       scsi_memory_upper_value = scsi_init_memory_start + 256 * 1024;
-       printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
-               (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
-               (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
-               (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
-       return scsi_memory_upper_value;
+    scsi_memory_upper_value = scsi_init_memory_start + 256 * 1024;
+    printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
+           (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
+           (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
+           (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+    return scsi_memory_upper_value;
 #else
-       return scsi_init_memory_start;
+    return scsi_init_memory_start;
 #endif
-       }
+}
 
 static void print_inquiry(unsigned char *data)
 {
-       int i;
+    int i;
+    
+    printk("  Vendor: ");
+    for (i = 8; i < 16; i++)
+    {
+       if (data[i] >= 0x20 && i < data[4] + 5)
+           printk("%c", data[i]);
+       else
+           printk(" ");
+    }
+    
+    printk("  Model: ");
+    for (i = 16; i < 32; i++)
+    {
+       if (data[i] >= 0x20 && i < data[4] + 5)
+           printk("%c", data[i]);
+       else
+           printk(" ");
+    }
+    
+    printk("  Rev: ");
+    for (i = 32; i < 36; i++)
+    {
+       if (data[i] >= 0x20 && i < data[4] + 5)
+           printk("%c", data[i]);
+       else
+           printk(" ");
+    }
+    
+    printk("\n");
+    
+    i = data[0] & 0x1f;
+    
+    printk("  Type:   %s ",
+          i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown          " );
+    printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
+    if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
+       printk(" CCS\n");
+    else
+       printk("\n");
+}
 
-       printk("  Vendor: ");
-       for (i = 8; i < 16; i++)
-               {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-               }
 
-       printk("  Model: ");
-       for (i = 16; i < 32; i++)
-               {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-               }
+#ifdef CONFIG_PROC_FS
+int scsi_proc_info(char *buffer, char **start, off_t offset, int length, 
+                   int hostno, int inout)
+{
+    Scsi_Device *scd;
+    struct Scsi_Host *HBA_ptr;
+    int  parameter[4];
+    char *p;
 
-       printk("  Rev: ");
-       for (i = 32; i < 36; i++)
-               {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-               }
+    scd = scsi_devices;
+    HBA_ptr = scsi_hostlist;
 
-       printk("\n");
+    if(inout == 0)    /* We can only write to this file right now */
+       return(-ENOSYS);  /* This is still a no-op */
 
-       i = data[0] & 0x1f;
+    if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
+       return(-EINVAL);
 
-       printk("  Type:   %s ",
-              i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown          " );
-       printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
-       if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
-         printk(" CCS\n");
-       else
-         printk("\n");
+    if(!strncmp("singledevice", buffer + 5, 12)) {
+       p = buffer + 17;
+
+       parameter[0] = simple_strtoul(p , &p, 0);
+       parameter[1] = simple_strtoul(p , &p, 0);
+       parameter[2] = simple_strtoul(p , &p, 0);
+       parameter[3] = simple_strtoul(p , &p, 0);
+
+       while(scd && scd->host->host_no != parameter[0] 
+             && scd->channel != parameter[1] 
+             && scd->id != parameter[2] 
+             && scd->lun != parameter[3]) {
+           scd = scd->next;
+       }
+       if(scd)
+           return(-ENOSYS);  /* We do not yet support unplugging */
+       while(HBA_ptr && HBA_ptr->host_no != parameter[0])
+           HBA_ptr = HBA_ptr->next;
+
+       if(!HBA_ptr)
+           return(-ENXIO);
+
+       scan_scsis (HBA_ptr, 1, parameter[1], parameter[2], parameter[3]);
+       return(0);
+    }
+    return(-EINVAL);
 }
+#endif
+
 
 /*
  * This entry point should be called by a loadable module if it is trying
@@ -2156,165 +2352,166 @@ static void print_inquiry(unsigned char *data)
  */
 static int scsi_register_host(Scsi_Host_Template * tpnt)
 {
-  int pcount;
-  struct Scsi_Host * shpnt;
-  struct Scsi_Host * host = NULL;
-  unsigned long flags;
-  Scsi_Device * SDpnt;
-  Scsi_Cmnd * SCpnt;
-  struct Scsi_Device_Template * sdtpnt;
-  int j, i;
-  const char * name;
-
-  if (tpnt->next || !tpnt->detect) return 1;  /* Must be already loaded, or
-                                              no detect routine available */
-  pcount = next_scsi_host;
-  if ((tpnt->present = tpnt->detect(tpnt)))
+    int pcount;
+    struct Scsi_Host * shpnt;
+    struct Scsi_Host * host = NULL;
+    unsigned long flags;
+    Scsi_Device * SDpnt;
+    struct Scsi_Device_Template * sdtpnt;
+    int i;
+    const char * name;
+    
+    if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or
+                                              * no detect routine available 
+                                              */
+    pcount = next_scsi_host;
+    if ((tpnt->present = tpnt->detect(tpnt)))
     {
-      if(pcount == next_scsi_host) {
-       if(tpnt->present > 1) {
-         printk("Failure to register low-level scsi driver");
-         scsi_unregister_host(tpnt);
-         return 1;
+       if(pcount == next_scsi_host) {
+           if(tpnt->present > 1) {
+               printk("Failure to register low-level scsi driver");
+               scsi_unregister_host(tpnt);
+               return 1;
+           }
+           /* The low-level driver failed to register a driver.  We
+            *  can do this now. 
+            */
+           scsi_register(tpnt,0);
        }
-       /* The low-level driver failed to register a driver.  We
-          can do this now. */
-       scsi_register(tpnt,0);
-      }
-      tpnt->next = scsi_hosts; /* Add to the linked list */
-      scsi_hosts = tpnt;
-
-      for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-       if(shpnt->hostt == tpnt)
-         {
-           if(tpnt->info)
-             name = tpnt->info(shpnt);
-           else
-             name = tpnt->name;
-           printk ("scsi%d : %s\n", /* And print a little message */
-                   shpnt->host_no, name);
-         }
-
-      printk ("scsi : %d host%s.\n", next_scsi_host,
+       tpnt->next = scsi_hosts; /* Add to the linked list */
+       scsi_hosts = tpnt;
+       
+       /* Add the new driver to /proc/scsi */
+#if CONFIG_PROC_FS 
+       build_proc_dir_entries();
+#endif
+       
+       for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+           if(shpnt->hostt == tpnt)
+           {
+               if(tpnt->info)
+                   name = tpnt->info(shpnt);
+               else
+                   name = tpnt->name;
+               printk ("scsi%d : %s\n", /* And print a little message */
+                       shpnt->host_no, name);
+           }
+       
+       printk ("scsi : %d host%s.\n", next_scsi_host,
                (next_scsi_host == 1) ? "" : "s");
-
-      scsi_make_blocked_list();
-
-      /* The next step is to call scan_scsis here.  This generates the
-        Scsi_Devices entries */
-
-      for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-       if(shpnt->hostt == tpnt) scan_scsis(shpnt);
-
-      for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-       if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
-
-      /* Next we create the Scsi_Cmnd structures for this host */
-
-      for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
-       if(SDpnt->host->hostt == tpnt)
-         {
-           for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-             if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-           if(SDpnt->attached){
-             for(j=0;j<SDpnt->host->cmd_per_lun;j++){
-               SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
-               SCpnt->host = SDpnt->host;
-               SCpnt->device = SDpnt;
-               SCpnt->target = SDpnt->id;
-               SCpnt->lun = SDpnt->lun;
-               SCpnt->request.dev = -1; /* Mark not busy */
-               SCpnt->request.sem = NULL;
-               SCpnt->use_sg = 0;
-               SCpnt->old_use_sg = 0;
-               SCpnt->underflow = 0;
-               SCpnt->timeout = 0;
-               SCpnt->transfersize = 0;
-               SCpnt->host_scribble = NULL;
-               host = SDpnt->host;
-               SCpnt->next = host->host_queue;
-               SCpnt->prev = NULL;
-               host->host_queue = SCpnt;
-               if(host->host_queue)
-                 host->host_queue->prev = SCpnt;
-             }
+       
+       scsi_make_blocked_list();
+       
+       /* The next step is to call scan_scsis here.  This generates the
+        * Scsi_Devices entries 
+        */
+       
+       for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+           if(shpnt->hostt == tpnt) scan_scsis(shpnt,0,0,0,0);
+       
+       for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+           if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
+       
+       /* Next we create the Scsi_Cmnd structures for this host */
+       
+       for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+           if(SDpnt->host->hostt == tpnt)
+           {
+               for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+                   if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
+               if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
            }
-         }
+       
        /* Next, check to see if we need to extend the DMA buffer pool */
-      {
-         unsigned char * new_dma_malloc_freelist = NULL;
-         unsigned int new_dma_sectors = 0;
-         unsigned int new_need_isa_buffer = 0;
-         unsigned char ** new_dma_malloc_pages = NULL;
-
-         if (scsi_devicelist)
-           new_dma_sectors = 16;  /* Base value we use */
-
-         for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
+    {
+       unsigned char * new_dma_malloc_freelist = NULL;
+       unsigned int new_dma_sectors = 0;
+       unsigned int new_need_isa_buffer = 0;
+       unsigned char ** new_dma_malloc_pages = NULL;
+       
+       new_dma_sectors = 16;  /* Base value we use */
+       if (scsi_devicelist)
+           for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+               new_dma_sectors += 8;  /* Increment for each host */
+       
+       for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
            host = SDpnt->host;
-
+           
            if(SDpnt->type != TYPE_TAPE)
-             new_dma_sectors += ((host->sg_tablesize *
-                                  sizeof(struct scatterlist) + 511) >> 9) *
-                                    host->cmd_per_lun;
-
+               new_dma_sectors += ((host->sg_tablesize *
+                                    sizeof(struct scatterlist) + 511) >> 9) *
+                                        host->cmd_per_lun;
+           
            if(host->unchecked_isa_dma &&
               scsi_need_isa_bounce_buffers &&
               SDpnt->type != TYPE_TAPE) {
-             new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
-               host->cmd_per_lun;
-             new_need_isa_buffer++;
+               new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
+                   host->cmd_per_lun;
+               new_need_isa_buffer++;
            }
-         }
-
-         new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
-
-         new_dma_malloc_freelist = (unsigned char *)
+       }
+       
+       new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
+       
+       /*
+        * We never shrink the buffers - this leads to
+        * race conditions that I would rather not even think
+        * about right now.
+        */
+       if( new_dma_sectors < dma_sectors )
+           new_dma_sectors = dma_sectors;
+       
+       new_dma_malloc_freelist = (unsigned char *)
            scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
-         memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
-
-         new_dma_malloc_pages = (unsigned char **)
+       memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
+       
+       new_dma_malloc_pages = (unsigned char **)
            scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
-         memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
-
-         for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++)
-           new_dma_malloc_pages[i] = (unsigned char *)
+       memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
+       
+       /*
+        * If we need more buffers, expand the list.
+        */
+       if( new_dma_sectors > dma_sectors ) { 
+           for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++)
+               new_dma_malloc_pages[i] = (unsigned char *)
              scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-
-
-         /* When we dick with the actual DMA list, we need to protect things */
-
-         save_flags(flags);
-         cli();
-         memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
-         scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
-         dma_malloc_freelist = new_dma_malloc_freelist;
-
-         memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
-         scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
-
-         dma_free_sectors += new_dma_sectors - dma_sectors;
-         dma_malloc_pages = new_dma_malloc_pages;
-         dma_sectors = new_dma_sectors;
-         need_isa_buffer = new_need_isa_buffer;
-         restore_flags(flags);
-
-
        }
-      /* This does any final handling that is required. */
-      for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-       if(sdtpnt->finish && sdtpnt->nr_dev)
-         (*sdtpnt->finish)();
+       
+       /* When we dick with the actual DMA list, we need to 
+        * protect things 
+        */
+       save_flags(flags);
+       cli();
+       memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
+       scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+       dma_malloc_freelist = new_dma_malloc_freelist;
+       
+       memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
+       scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
+       
+       dma_free_sectors += new_dma_sectors - dma_sectors;
+       dma_malloc_pages = new_dma_malloc_pages;
+       dma_sectors = new_dma_sectors;
+       need_isa_buffer = new_need_isa_buffer;
+       restore_flags(flags);
     }
-
+       
+       /* This does any final handling that is required. */
+       for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+           if(sdtpnt->finish && sdtpnt->nr_dev)
+               (*sdtpnt->finish)();
+    }
+    
 #if defined(USE_STATIC_SCSI_MEMORY)
-  printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
-         (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
-         (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
-         (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+    printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
+           (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
+           (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
+           (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
 #endif
-
-  return 0;
+    
+    MOD_INC_USE_COUNT;
+    return 0;
 }
 
 /*
@@ -2323,226 +2520,455 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
  */
 static void scsi_unregister_host(Scsi_Host_Template * tpnt)
 {
-  Scsi_Host_Template * SHT, *SHTp;
-  Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
-  Scsi_Cmnd * SCpnt;
-  unsigned long flags;
-  struct Scsi_Device_Template * sdtpnt;
-  struct Scsi_Host * shpnt, *sh1;
-  int pcount;
-
-  /* First verify that this host adapter is completely free with no pending
-     commands */
-
-  for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
-    if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->usage_count
-                                && *sdpnt->host->hostt->usage_count) return;
-
-  for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    Scsi_Host_Template * SHT, *SHTp;
+    Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
+    Scsi_Cmnd * SCpnt;
+    unsigned long flags;
+    struct Scsi_Device_Template * sdtpnt;
+    struct Scsi_Host * shpnt, *sh1;
+    int pcount;
+    
+    /* First verify that this host adapter is completely free with no pending
+     commands */
+    
+    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
+       if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->usage_count
+          && *sdpnt->host->hostt->usage_count) return;
+    
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
     {
-      if (shpnt->hostt != tpnt) continue;
-      for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
+       if (shpnt->hostt != tpnt) continue;
+       for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
        {
-         save_flags(flags);
-         cli();
-         if(SCpnt->request.dev != -1) {
+           save_flags(flags);
+           cli();
+           if(SCpnt->request.dev != -1) {
+               restore_flags(flags);
+               for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
+                   if(SCpnt->request.dev == 0xffe0) SCpnt->request.dev = -1;
+               printk("Device busy???\n");
+               return;
+           }
+           SCpnt->request.dev = 0xffe0;  /* Mark as busy */
            restore_flags(flags);
-           for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
-             if(SCpnt->request.dev == 0xffe0) SCpnt->request.dev = -1;
-           printk("Device busy???\n");
-           return;
-         }
-         SCpnt->request.dev = 0xffe0;  /* Mark as busy */
-         restore_flags(flags);
        }
     }
-  /* Next we detach the high level drivers from the Scsi_Device structures */
-
-  for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
-    if(sdpnt->host->hostt == tpnt)
-      {
-       for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-         if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt);
-       /* If something still attached, punt */
-       if (sdpnt->attached) {
-         printk("Attached usage count = %d\n", sdpnt->attached);
-         return;
+    /* Next we detach the high level drivers from the Scsi_Device structures */
+    
+    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
+       if(sdpnt->host->hostt == tpnt)
+       {
+           for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+               if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt);
+           /* If something still attached, punt */
+           if (sdpnt->attached) {
+               printk("Attached usage count = %d\n", sdpnt->attached);
+               return;
+           }
        }
-      }
-
-  /* Next we free up the Scsi_Cmnd structures for this host */
-
-  for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
-    if(sdpnt->host->hostt == tpnt)
-      while (sdpnt->host->host_queue) {
-       SCpnt = sdpnt->host->host_queue->next;
-       scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
-       sdpnt->host->host_queue = SCpnt;
-       if (SCpnt) SCpnt->prev = NULL;
-      }
-
-  /* Next free up the Scsi_Device structures for this host */
-
-  sdppnt = NULL;
-  for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1)
+    
+    /* Next we free up the Scsi_Cmnd structures for this host */
+    
+    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
+       if(sdpnt->host->hostt == tpnt)
+           while (sdpnt->host->host_queue) {
+               SCpnt = sdpnt->host->host_queue->next;
+               scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
+               sdpnt->host->host_queue = SCpnt;
+               if (SCpnt) SCpnt->prev = NULL;
+           }
+    
+    /* Next free up the Scsi_Device structures for this host */
+    
+    sdppnt = NULL;
+    for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1)
     {
-      sdpnt1 = sdpnt->next;
-      if (sdpnt->host->hostt == tpnt) {
-       if (sdppnt)
-         sdppnt->next = sdpnt->next;
-       else
-         scsi_devices = sdpnt->next;
-       scsi_init_free((char *) sdpnt, sizeof (Scsi_Device));
-      } else
-       sdppnt = sdpnt;
+       sdpnt1 = sdpnt->next;
+       if (sdpnt->host->hostt == tpnt) {
+           if (sdppnt)
+               sdppnt->next = sdpnt->next;
+           else
+               scsi_devices = sdpnt->next;
+           scsi_init_free((char *) sdpnt, sizeof (Scsi_Device));
+       } else
+           sdppnt = sdpnt;
     }
-
-  /* Next we go through and remove the instances of the individual hosts
-     that were detected */
-
-  shpnt = scsi_hostlist;
-  while(shpnt) {
-   sh1 = shpnt->next;
-    if(shpnt->hostt == tpnt) {
-      if(shpnt->loaded_as_module) {
-       pcount = next_scsi_host;
-       if(tpnt->release)
-         (*tpnt->release)(shpnt);
-       else {
-         /* This is the default case for the release function.  It should do the right
-            thing for most correctly written host adapters. */
-         if (shpnt->irq) free_irq(shpnt->irq);
-         if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel);
-         if (shpnt->io_port && shpnt->n_io_port)
-           release_region(shpnt->io_port, shpnt->n_io_port);
+    
+    /* Next we go through and remove the instances of the individual hosts
+     * that were detected */
+    
+    shpnt = scsi_hostlist;
+    while(shpnt) {
+       sh1 = shpnt->next;
+       if(shpnt->hostt == tpnt) {
+           if(shpnt->loaded_as_module) {
+               pcount = next_scsi_host;
+               if(tpnt->release)
+                   (*tpnt->release)(shpnt);
+               else {
+                   /* This is the default case for the release function.  
+                    * It should do the right thing for most correctly 
+                    * written host adapters. 
+                    */
+                   if (shpnt->irq) free_irq(shpnt->irq);
+                   if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel);
+                   if (shpnt->io_port && shpnt->n_io_port)
+                       release_region(shpnt->io_port, shpnt->n_io_port);
+               }
+               if(pcount == next_scsi_host) scsi_unregister(shpnt);
+               tpnt->present--;
+           }
        }
-       if(pcount == next_scsi_host) scsi_unregister(shpnt);
-       tpnt->present--;
-      }
+       shpnt = sh1;
     }
-    shpnt = sh1;
-  }
-
-  printk ("scsi : %d host%s.\n", next_scsi_host,
-         (next_scsi_host == 1) ? "" : "s");
-
+    
+    printk ("scsi : %d host%s.\n", next_scsi_host,
+           (next_scsi_host == 1) ? "" : "s");
+    
 #if defined(USE_STATIC_SCSI_MEMORY)
-  printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
-         (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
-         (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
-         (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+    printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
+           (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
+           (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
+           (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+#endif
+    
+    scsi_make_blocked_list();
+    
+    /* There were some hosts that were loaded at boot time, so we cannot
+       do any more than this */
+    if (tpnt->present) return;
+    
+    /* OK, this is the very last step.  Remove this host adapter from the
+       linked list. */
+    for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next)
+       if(SHT == tpnt) {
+           if(SHTp)
+               SHTp->next = SHT->next;
+           else
+               scsi_hosts = SHT->next;
+           SHT->next = NULL;
+           break;
+       }
+    
+    /* Rebuild the /proc/scsi directory entries */
+#if CONFIG_PROC_FS 
+    build_proc_dir_entries();
 #endif
+    MOD_DEC_USE_COUNT;
+}
+
+/*
+ * This entry point should be called by a loadable module if it is trying
+ * add a high level scsi driver to the system.
+ */
+static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
+{
+    Scsi_Device * SDpnt;
+    int previous_attachment;
+    
+    if (tpnt->next) return 1;
+    
+    scsi_register_device(tpnt);
+    /*
+     * First scan the devices that we know about, and see if we notice them.
+     */
+    
+    for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+       if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
+    
+    /*
+     * If any of the devices would match this driver, then perform the
+     * init function.  +
+     */
+    if(tpnt->init && tpnt->dev_noticed) (*tpnt->init)();
+    
+    /*
+     * Now actually connect the devices to the new driver.
+     */
+    for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+    {
+       previous_attachment = SDpnt->attached;
+       if(tpnt->attach)  (*tpnt->attach)(SDpnt);
+       /*
+        * If this driver attached to the device, and we no longer
+        * have anything attached, release the scso command blocks.
+        */
+       if(SDpnt->attached && previous_attachment == 0)
+           scsi_build_commandblocks(SDpnt);
+    }
+    
+    /*
+     * This does any final handling that is required. 
+     */
+    if(tpnt->finish && tpnt->nr_dev)  (*tpnt->finish)();
+    MOD_INC_USE_COUNT;
+    return 0;
+}
 
-  scsi_make_blocked_list();
-
-  /* There were some hosts that were loaded at boot time, so we cannot
-     do any more than this */
-  if (tpnt->present) return;
-
-  /* OK, this is the very last step.  Remove this host adapter from the
-     linked list. */
-  for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next)
-    if(SHT == tpnt) {
-      if(SHTp)
-       SHTp->next = SHT->next;
-      else
-       scsi_hosts = SHT->next;
-      SHT->next = NULL;
-      break;
+static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
+{
+    Scsi_Device * SDpnt;
+    Scsi_Cmnd * SCpnt;
+    struct Scsi_Device_Template * spnt;
+    struct Scsi_Device_Template * prev_spnt;
+    
+    /*
+     * If we are busy, this is not going to fly.
+     */
+    if( *tpnt->usage_count != 0) return 0;
+    /*
+     * Next, detach the devices from the driver.
+     */
+    
+    for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+    {
+       if(tpnt->detach) (*tpnt->detach)(SDpnt);
+       if(SDpnt->attached == 0)
+       {
+           /*
+            * Nobody is using this device any more.  Free all of the
+            * command structures.
+            */
+           for(SCpnt = SDpnt->host->host_queue; SCpnt; SCpnt = SCpnt->next)
+           {
+               if(SCpnt->device == SDpnt)
+               {
+                   if(SCpnt->prev != NULL)
+                       SCpnt->prev->next = SCpnt->next;
+                   if(SCpnt->next != NULL)
+                       SCpnt->next->prev = SCpnt->prev;
+                   if(SCpnt == SDpnt->host->host_queue)
+                       SDpnt->host->host_queue = SCpnt->next;
+                   scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
+               }
+           }
+       }
+    }
+    /*
+     * Extract the template from the linked list.
+     */
+    spnt = scsi_devicelist;
+    prev_spnt = NULL;
+    while(spnt != tpnt)
+    {
+       prev_spnt = spnt;
+       spnt = spnt->next;
     }
+    if(prev_spnt == NULL)
+       scsi_devicelist = tpnt->next;
+    else
+       prev_spnt->next = spnt->next;
+    
+    MOD_DEC_USE_COUNT;
+    /*
+     * Final cleanup for the driver is done in the driver sources in the 
+     * cleanup function.
+     */
+    return 0;
 }
 
+
 int scsi_register_module(int module_type, void * ptr)
 {
-  switch(module_type){
-  case MODULE_SCSI_HA:
-    return scsi_register_host((Scsi_Host_Template *) ptr);
-    /* The rest of these are not yet implemented */
-
-    /* Load constants.o */
-  case MODULE_SCSI_CONST:
-
-    /* Load specialized ioctl handler for some device.  Intended for cdroms that
-       have non-SCSI2 audio command sets. */
-  case MODULE_SCSI_IOCTL:
-
-    /* Load upper level device handler of some kind */
-  case MODULE_SCSI_DEV:
-  default:
-    return 1;
-  }
+    switch(module_type){
+    case MODULE_SCSI_HA:
+       return scsi_register_host((Scsi_Host_Template *) ptr);
+       
+       /* Load upper level device handler of some kind */
+    case MODULE_SCSI_DEV:
+       return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
+       /* The rest of these are not yet implemented */
+       
+       /* Load constants.o */
+    case MODULE_SCSI_CONST:
+       
+       /* Load specialized ioctl handler for some device.  Intended for 
+        * cdroms that have non-SCSI2 audio command sets. */
+    case MODULE_SCSI_IOCTL:
+       
+    default:
+       return 1;
+    }
 }
 
 void scsi_unregister_module(int module_type, void * ptr)
 {
-  switch(module_type) {
-  case MODULE_SCSI_HA:
-    scsi_unregister_host((Scsi_Host_Template *) ptr);
-    break;
-    /* The rest of these are not yet implemented. */
-  case MODULE_SCSI_CONST:
-  case MODULE_SCSI_IOCTL:
-  case MODULE_SCSI_DEV:
-  default:
-  }
-  return;
+    switch(module_type) {
+    case MODULE_SCSI_HA:
+       scsi_unregister_host((Scsi_Host_Template *) ptr);
+       break;
+    case MODULE_SCSI_DEV:
+       scsi_unregister_device((struct Scsi_Device_Template *) ptr);
+       break;
+       /* The rest of these are not yet implemented. */
+    case MODULE_SCSI_CONST:
+    case MODULE_SCSI_IOCTL:
+       break;
+    default:
+    }
+    return;
 }
 
 #ifdef DEBUG_TIMEOUT
 static void
 scsi_dump_status(void)
 {
-  int i;
-  struct Scsi_Host * shpnt;
-  Scsi_Cmnd * SCpnt;
-  printk("Dump of scsi parameters:\n");
-  i = 0;
-  for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
-      {
-       /*  (0) 0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x      */
-       printk("(%d) %d:%d:%d (%4.4x %ld %ld %ld %ld) (%d %d %x) (%d %d %d) %x %x %x\n",
-              i++, SCpnt->host->host_no,
-              SCpnt->target,
-              SCpnt->lun,
-              SCpnt->request.dev,
-              SCpnt->request.sector,
-              SCpnt->request.nr_sectors,
-              SCpnt->request.current_nr_sectors,
-              SCpnt->use_sg,
-              SCpnt->retries,
-              SCpnt->allowed,
-              SCpnt->flags,
-              SCpnt->timeout_per_command,
-              SCpnt->timeout,
-              SCpnt->internal_timeout,
-              SCpnt->cmnd[0],
-              SCpnt->sense_buffer[2],
-              SCpnt->result);
-      }
-  printk("wait_for_request = %p\n", wait_for_request);
-  /* Now dump the request lists for each block device */
-  printk("Dump of pending block device requests\n");
-  for(i=0; i<MAX_BLKDEV; i++)
-    if(blk_dev[i].current_request)
-      {
-       struct request * req;
-       printk("%d: ", i);
-       req = blk_dev[i].current_request;
-       while(req) {
-         printk("(%x %d %ld %ld %ld) ",
-                req->dev,
-                req->cmd,
-                req->sector,
-                req->nr_sectors,
-                req->current_nr_sectors);
-         req = req->next;
+    int i;
+    struct Scsi_Host * shpnt;
+    Scsi_Cmnd * SCpnt;
+    printk("Dump of scsi parameters:\n");
+    i = 0;
+    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+       for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
+       {
+           /*  (0) 0:0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x      */
+           printk("(%d) %d:%d:%d:%d (%4.4x %ld %ld %ld %ld) (%d %d %x) (%d %d %d) %x %x %x\n",
+                  i++, SCpnt->host->host_no,
+                  SCpnt->channel,
+                  SCpnt->target,
+                  SCpnt->lun,
+                  SCpnt->request.dev,
+                  SCpnt->request.sector,
+                  SCpnt->request.nr_sectors,
+                  SCpnt->request.current_nr_sectors,
+                  SCpnt->use_sg,
+                  SCpnt->retries,
+                  SCpnt->allowed,
+                  SCpnt->flags,
+                  SCpnt->timeout_per_command,
+                  SCpnt->timeout,
+                  SCpnt->internal_timeout,
+                  SCpnt->cmnd[0],
+                  SCpnt->sense_buffer[2],
+                  SCpnt->result);
+       }
+    printk("wait_for_request = %p\n", wait_for_request);
+    /* Now dump the request lists for each block device */
+    printk("Dump of pending block device requests\n");
+    for(i=0; i<MAX_BLKDEV; i++)
+       if(blk_dev[i].current_request)
+       {
+           struct request * req;
+           printk("%d: ", i);
+           req = blk_dev[i].current_request;
+           while(req) {
+               printk("(%x %d %ld %ld %ld) ",
+                      req->dev,
+                      req->cmd,
+                      req->sector,
+                      req->nr_sectors,
+                      req->current_nr_sectors);
+               req = req->next;
+           }
+           printk("\n");
        }
-       printk("\n");
-      }
 }
 #endif
 
+
+#ifdef MODULE
+/* 
+extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+extern int        scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+*/
+
+struct symbol_table scsi_symbol_table = {
+#include <linux/symtab_begin.h>
+#ifdef CONFIG_MODVERSIONS
+    { (void *)1 /* Version version :-) */, "_Using_Versions" },
+#endif
+    X(scsi_register_module),
+    X(scsi_unregister_module),
+    X(scsi_free),
+    X(scsi_malloc),
+    X(scsi_register),
+    X(scsi_unregister),
+    X(scsicam_bios_param),
+    X(allocate_device),
+    X(scsi_do_cmd),
+    X(scsi_command_size),
+    X(scsi_init_malloc),
+    X(scsi_init_free),
+    X(scsi_ioctl),
+    X(print_command),
+    X(print_sense),
+    X(dma_free_sectors),
+    X(kernel_scsi_ioctl),
+    X(need_isa_buffer),
+    X(request_queueable),
+/*
+ * These are here only while I debug the rest of the scsi stuff.
+ */
+    X(scsi_hostlist),
+    X(scsi_hosts),
+    X(scsi_devicelist),
+    X(scsi_devices),
+
+    /********************************************************
+     * Do not add anything below this line,
+     * as the stacked modules depend on this!
+     */
+#include <linux/symtab_end.h>
+};
+
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void) {
+    timer_table[SCSI_TIMER].fn = scsi_main_timeout;
+    timer_table[SCSI_TIMER].expires = 0;
+    register_symtab(&scsi_symbol_table);
+    scsi_loadable_module_flag = 1;
+    
+    dma_sectors = PAGE_SIZE / 512;
+    /*
+     * Set up a minimal DMA buffer list - this will be used during scan_scsis
+     * in some cases.
+     */
+    
+    /* One bit per sector to indicate free/busy */
+    dma_malloc_freelist = (unsigned char *)
+       scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
+    memset(dma_malloc_freelist, 0, dma_sectors >> 3);
+    
+    /* One pointer per page for the page list */
+    dma_malloc_pages = (unsigned char **)
+       scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
+    dma_malloc_pages[0] = (unsigned char *)
+       scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+    return 0;
+}
+
+void cleanup_module( void) 
+{
+    int i;
+    
+    if (MOD_IN_USE) {
+       printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+       return;
+    }
+    
+    /* No, we're not here anymore. Don't show the /proc/scsi files. */
+    dispatch_scsi_info_ptr = 0L;
+
+    /*
+     * Free up the DMA pool.
+     */
+    for(i=0; i < dma_sectors >> 3; i++)
+       scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
+    scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
+    scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+    
+    timer_table[SCSI_TIMER].fn = NULL;
+    timer_table[SCSI_TIMER].expires = 0;
+    /*
+     * Supposedly you just do this, and the last symtab registered will
+     * be removed.  If someone else registered a symtab, this could
+     * blow up in our faces.  FIXME.
+     */
+    register_symtab(0);
+}
+#endif /* MODULE */
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
@@ -2550,12 +2976,14 @@ scsi_dump_status(void)
  * of the file.
  * ---------------------------------------------------------------------------
  * Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
  * End:
  */
index f3e7dc3bf681960fb110e5a80ee0f65f3508bfe2..990059c145cc828b993deb61d389fbfef52d3cde 100644 (file)
@@ -1,9 +1,9 @@
 /*
- *     scsi.h Copyright (C) 1992 Drew Eckhardt 
- *     generic SCSI package header file by
- *             Drew Eckhardt 
+ *  scsi.h Copyright (C) 1992 Drew Eckhardt 
+ *  generic SCSI package header file by
+ *      Drew Eckhardt 
  *
- *     <drew@colorado.edu>
+ *  <drew@colorado.edu>
  *
  *       Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
  *       add scatter-gather, multiple outstanding request, and other
 #define _SCSI_H
 
 /*
-       $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
+    $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
 
-       For documentation on the OPCODES, MESSAGES, and SENSE values,
-       please consult the SCSI standard.
+    For documentation on the OPCODES, MESSAGES, and SENSE values,
+    please consult the SCSI standard.
 
 */
 
 /*
-       SCSI opcodes
-*/
*      SCSI opcodes
+ */
 
-#define TEST_UNIT_READY        0x00
-#define REZERO_UNIT            0x01
-#define REQUEST_SENSE          0x03
-#define FORMAT_UNIT            0x04
-#define READ_BLOCK_LIMITS      0x05
-#define REASSIGN_BLOCKS                0x07
-#define READ_6                 0x08
-#define WRITE_6                        0x0a
-#define SEEK_6                 0x0b
-#define READ_REVERSE           0x0f
-#define WRITE_FILEMARKS                0x10
-#define SPACE                  0x11
-#define INQUIRY                        0x12
-#define RECOVER_BUFFERED_DATA  0x14
-#define MODE_SELECT            0x15
-#define RESERVE                        0x16
-#define RELEASE                        0x17
-#define COPY                   0x18
-#define ERASE                  0x19
-#define MODE_SENSE             0x1a
-#define START_STOP             0x1b
-#define RECEIVE_DIAGNOSTIC     0x1c
-#define SEND_DIAGNOSTIC                0x1d
-#define ALLOW_MEDIUM_REMOVAL   0x1e
-
-#define SET_WINDOW              0x24
-#define READ_CAPACITY          0x25
-#define READ_10                        0x28
-#define WRITE_10               0x2a
-#define SEEK_10                        0x2b
-#define WRITE_VERIFY           0x2e
-#define VERIFY                 0x2f
-#define SEARCH_HIGH            0x30
-#define SEARCH_EQUAL           0x31
-#define SEARCH_LOW             0x32
-#define SET_LIMITS             0x33
-#define PRE_FETCH              0x34
-#define READ_POSITION          0x34
-#define SYNCHRONIZE_CACHE      0x35
-#define LOCK_UNLOCK_CACHE      0x36
-#define READ_DEFECT_DATA       0x37
-#define MEDIUM_SCAN             0x38
-#define COMPARE                        0x39
-#define COPY_VERIFY            0x3a
-#define WRITE_BUFFER           0x3b
-#define READ_BUFFER            0x3c
-#define UPDATE_BLOCK            0x3d
-#define READ_LONG              0x3e
-#define WRITE_LONG              0x3f
-#define CHANGE_DEFINITION      0x40
-#define WRITE_SAME             0x41
-#define LOG_SELECT             0x4c
-#define LOG_SENSE              0x4d
-#define MODE_SELECT_10         0x55
-#define MODE_SENSE_10          0x5a
-#define WRITE_12                0xaa
-#define WRITE_VERIFY_12         0xae
-#define SEARCH_HIGH_12          0xb0
-#define SEARCH_EQUAL_12         0xb1
-#define SEARCH_LOW_12           0xb2
-#define SEND_VOLUME_TAG         0xb6
+#define TEST_UNIT_READY       0x00
+#define REZERO_UNIT           0x01
+#define REQUEST_SENSE         0x03
+#define FORMAT_UNIT           0x04
+#define READ_BLOCK_LIMITS     0x05
+#define REASSIGN_BLOCKS       0x07
+#define READ_6                0x08
+#define WRITE_6               0x0a
+#define SEEK_6                0x0b
+#define READ_REVERSE          0x0f
+#define WRITE_FILEMARKS       0x10
+#define SPACE                 0x11
+#define INQUIRY               0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT           0x15
+#define RESERVE               0x16
+#define RELEASE               0x17
+#define COPY                  0x18
+#define ERASE                 0x19
+#define MODE_SENSE            0x1a
+#define START_STOP            0x1b
+#define RECEIVE_DIAGNOSTIC    0x1c
+#define SEND_DIAGNOSTIC       0x1d
+#define ALLOW_MEDIUM_REMOVAL  0x1e
+
+#define SET_WINDOW            0x24
+#define READ_CAPACITY         0x25
+#define READ_10               0x28
+#define WRITE_10              0x2a
+#define SEEK_10               0x2b
+#define WRITE_VERIFY          0x2e
+#define VERIFY                0x2f
+#define SEARCH_HIGH           0x30
+#define SEARCH_EQUAL          0x31
+#define SEARCH_LOW            0x32
+#define SET_LIMITS            0x33
+#define PRE_FETCH             0x34
+#define READ_POSITION         0x34
+#define SYNCHRONIZE_CACHE     0x35
+#define LOCK_UNLOCK_CACHE     0x36
+#define READ_DEFECT_DATA      0x37
+#define MEDIUM_SCAN           0x38
+#define COMPARE               0x39
+#define COPY_VERIFY           0x3a
+#define WRITE_BUFFER          0x3b
+#define READ_BUFFER           0x3c
+#define UPDATE_BLOCK          0x3d
+#define READ_LONG             0x3e
+#define WRITE_LONG            0x3f
+#define CHANGE_DEFINITION     0x40
+#define WRITE_SAME            0x41
+#define LOG_SELECT            0x4c
+#define LOG_SENSE             0x4d
+#define MODE_SELECT_10        0x55
+#define MODE_SENSE_10         0x5a
+#define WRITE_12              0xaa
+#define WRITE_VERIFY_12       0xae
+#define SEARCH_HIGH_12        0xb0
+#define SEARCH_EQUAL_12       0xb1
+#define SEARCH_LOW_12         0xb2
+#define SEND_VOLUME_TAG       0xb6
+#define WRITE_LONG_2          0xea
 
 extern void scsi_make_blocked_list(void);
 extern volatile int in_scan_scsis;
@@ -93,190 +94,168 @@ extern const unsigned char scsi_command_size[8];
 #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
 
 /*
      MESSAGE CODES
-*/
*  MESSAGE CODES
+ */
 
-#define COMMAND_COMPLETE       0x00
-#define EXTENDED_MESSAGE       0x01
-#define        EXTENDED_MODIFY_DATA_POINTER    0x00
-#define        EXTENDED_SDTR                   0x01
-#define        EXTENDED_EXTENDED_IDENTIFY      0x02    /* SCSI-I only */
-#define        EXTENDED_WDTR                   0x03
-#define SAVE_POINTERS          0x02
-#define RESTORE_POINTERS       0x03
-#define DISCONNECT             0x04
-#define INITIATOR_ERROR                0x05
-#define ABORT                  0x06
-#define MESSAGE_REJECT         0x07
-#define NOP                    0x08
-#define MSG_PARITY_ERROR       0x09
-#define LINKED_CMD_COMPLETE    0x0a
-#define LINKED_FLG_CMD_COMPLETE        0x0b
-#define BUS_DEVICE_RESET       0x0c
-
-#define INITIATE_RECOVERY      0x0f                    /* SCSI-II only */
-#define RELEASE_RECOVERY       0x10                    /* SCSI-II only */
-
-#define SIMPLE_QUEUE_TAG       0x20
-#define HEAD_OF_QUEUE_TAG      0x21
-#define ORDERED_QUEUE_TAG      0x22
-
-#define IDENTIFY_BASE          0x80
+#define COMMAND_COMPLETE    0x00
+#define EXTENDED_MESSAGE    0x01
+#define     EXTENDED_MODIFY_DATA_POINTER    0x00
+#define     EXTENDED_SDTR                   0x01
+#define     EXTENDED_EXTENDED_IDENTIFY      0x02    /* SCSI-I only */
+#define     EXTENDED_WDTR                   0x03
+#define SAVE_POINTERS       0x02
+#define RESTORE_POINTERS    0x03
+#define DISCONNECT          0x04
+#define INITIATOR_ERROR     0x05
+#define ABORT               0x06
+#define MESSAGE_REJECT      0x07
+#define NOP                 0x08
+#define MSG_PARITY_ERROR    0x09
+#define LINKED_CMD_COMPLETE 0x0a
+#define LINKED_FLG_CMD_COMPLETE 0x0b
+#define BUS_DEVICE_RESET    0x0c
+
+#define INITIATE_RECOVERY   0x0f            /* SCSI-II only */
+#define RELEASE_RECOVERY    0x10            /* SCSI-II only */
+
+#define SIMPLE_QUEUE_TAG    0x20
+#define HEAD_OF_QUEUE_TAG   0x21
+#define ORDERED_QUEUE_TAG   0x22
+
+#define IDENTIFY_BASE       0x80
 #define IDENTIFY(can_disconnect, lun)   (IDENTIFY_BASE |\
-                                        ((can_disconnect) ?  0x40 : 0) |\
-                                        ((lun) & 0x07)) 
+                    ((can_disconnect) ?  0x40 : 0) |\
+                    ((lun) & 0x07)) 
 
-                                
+                
 /*
-       Status codes
-*/
-
-#define GOOD                   0x00
-#define CHECK_CONDITION                0x01
-#define CONDITION_GOOD         0x02
-#define BUSY                   0x04
-#define INTERMEDIATE_GOOD      0x08
-#define INTERMEDIATE_C_GOOD    0x0a
-#define RESERVATION_CONFLICT   0x0c
-#define QUEUE_FULL              0x1a
+ *  Status codes
+ */
 
-#define STATUS_MASK            0x1e
-       
+#define GOOD                 0x00
+#define CHECK_CONDITION      0x01
+#define CONDITION_GOOD       0x02
+#define BUSY                 0x04
+#define INTERMEDIATE_GOOD    0x08
+#define INTERMEDIATE_C_GOOD  0x0a
+#define RESERVATION_CONFLICT 0x0c
+#define QUEUE_FULL           0x1a
+
+#define STATUS_MASK          0x1e
+    
 /*
-       the return of the status word will be in the following format :
-       The low byte is the status returned by the SCSI command, 
-       with vendor specific bits masked.
-
-       The next byte is the message which followed the SCSI status.
-       This allows a stos to be used, since the Intel is a little
-       endian machine.
-
-       The final byte is a host return code, which is one of the following.
-
-       IE 
-       lsb             msb
-       status  msg     host code       
+ *  the return of the status word will be in the following format :
+ *  The low byte is the status returned by the SCSI command, 
+ *  with vendor specific bits masked.
+ *  
+ *  The next byte is the message which followed the SCSI status.
+ *  This allows a stos to be used, since the Intel is a little
+ *  endian machine.
+ *  
+ *  The final byte is a host return code, which is one of the following.
+ *  
+ *  IE 
+ *  lsb     msb
+ *  status  msg host code   
+ *  
+ *  Our errors returned by OUR driver, NOT SCSI message.  Or'd with
+ *  SCSI message passed back to driver <IF any>.
+ */
 
-        Our errors returned by OUR driver, NOT SCSI message.  Or'd with
-        SCSI message passed back to driver <IF any>.
-*/
 
-/*     NO error                                                        */
-#define DID_OK                         0x00
-/*     Couldn't connect before timeout period                          */
-#define DID_NO_CONNECT         0x01
-/*     BUS stayed busy through time out period                         */
-#define DID_BUS_BUSY           0x02
-/*     TIMED OUT for other reason                                      */
-#define DID_TIME_OUT           0x03
-/*     BAD target.                                                     */
-#define DID_BAD_TARGET         0x04
-/*     Told to abort for some other reason                             */
-#define        DID_ABORT               0x05
-/*
-       Parity error
-*/
-#define DID_PARITY             0x06
-/*
-       Internal error
-*/
-#define DID_ERROR              0x07    
-/*
-       Reset by somebody.
-*/
-#define DID_RESET              0x08
-/*
-       Got an interrupt we weren't expecting.
-*/
-#define        DID_BAD_INTR            0x09
+#define DID_OK          0x00 /* NO error                                */
+#define DID_NO_CONNECT  0x01 /* Couldn't connect before timeout period  */
+#define DID_BUS_BUSY    0x02 /* BUS stayed busy through time out period */
+#define DID_TIME_OUT    0x03 /* TIMED OUT for other reason              */
+#define DID_BAD_TARGET  0x04 /* BAD target.                             */
+#define DID_ABORT       0x05 /* Told to abort for some other reason     */
+#define DID_PARITY      0x06 /* Parity error                            */
+#define DID_ERROR       0x07 /* Internal error                          */
+#define DID_RESET       0x08 /* Reset by somebody.                      */
+#define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */ 
+#define DRIVER_OK       0x00 /* Driver status                           */ 
 
 /*
-       Driver status
-*/ 
-#define DRIVER_OK              0x00
-
-/*
-       These indicate the error that occurred, and what is available.
-*/
+ *  These indicate the error that occurred, and what is available.
+ */
 
-#define DRIVER_BUSY            0x01
-#define DRIVER_SOFT            0x02
-#define DRIVER_MEDIA           0x03
-#define DRIVER_ERROR           0x04    
+#define DRIVER_BUSY         0x01
+#define DRIVER_SOFT         0x02
+#define DRIVER_MEDIA        0x03
+#define DRIVER_ERROR        0x04    
 
-#define DRIVER_INVALID         0x05
-#define DRIVER_TIMEOUT         0x06
-#define DRIVER_HARD            0x07
+#define DRIVER_INVALID      0x05
+#define DRIVER_TIMEOUT      0x06
+#define DRIVER_HARD         0x07
 
-#define SUGGEST_RETRY          0x10
-#define SUGGEST_ABORT          0x20 
-#define SUGGEST_REMAP          0x30
-#define SUGGEST_DIE            0x40
-#define SUGGEST_SENSE          0x80
-#define SUGGEST_IS_OK          0xff
+#define SUGGEST_RETRY       0x10
+#define SUGGEST_ABORT       0x20 
+#define SUGGEST_REMAP       0x30
+#define SUGGEST_DIE         0x40
+#define SUGGEST_SENSE       0x80
+#define SUGGEST_IS_OK       0xff
 
-#define DRIVER_SENSE           0x08
+#define DRIVER_SENSE        0x08
 
-#define DRIVER_MASK 0x0f
-#define SUGGEST_MASK 0xf0
+#define DRIVER_MASK         0x0f
+#define SUGGEST_MASK        0xf0
 
 /*
+ *  SENSE KEYS
+ */
 
-       SENSE KEYS
-*/
-
-#define NO_SENSE               0x00
-#define RECOVERED_ERROR                0x01
-#define NOT_READY              0x02
-#define MEDIUM_ERROR           0x03
-#define        HARDWARE_ERROR          0x04
-#define ILLEGAL_REQUEST                0x05
-#define UNIT_ATTENTION         0x06
-#define DATA_PROTECT           0x07
-#define BLANK_CHECK            0x08
-#define COPY_ABORTED           0x0a
-#define ABORTED_COMMAND                0x0b
-#define        VOLUME_OVERFLOW         0x0d
-#define MISCOMPARE             0x0e
+#define NO_SENSE            0x00
+#define RECOVERED_ERROR     0x01
+#define NOT_READY           0x02
+#define MEDIUM_ERROR        0x03
+#define HARDWARE_ERROR      0x04
+#define ILLEGAL_REQUEST     0x05
+#define UNIT_ATTENTION      0x06
+#define DATA_PROTECT        0x07
+#define BLANK_CHECK         0x08
+#define COPY_ABORTED        0x0a
+#define ABORTED_COMMAND     0x0b
+#define VOLUME_OVERFLOW     0x0d
+#define MISCOMPARE          0x0e
 
 
 /*
-       DEVICE TYPES
+ *  DEVICE TYPES
+ */
 
-*/
+#define TYPE_DISK           0x00
+#define TYPE_TAPE           0x01
+#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
+#define TYPE_WORM           0x04    /* Treated as ROM by our system */
+#define TYPE_ROM            0x05
+#define TYPE_SCANNER        0x06
+#define TYPE_MOD            0x07    /* Magneto-optical disk - 
+                                    * - treated as TYPE_DISK */
+#define TYPE_NO_LUN         0x7f
 
-#define TYPE_DISK      0x00
-#define TYPE_TAPE      0x01
-#define TYPE_PROCESSOR 0x03    /* HP scanners use this */
-#define TYPE_WORM      0x04    /* Treated as ROM by our system */
-#define TYPE_ROM       0x05
-#define TYPE_SCANNER   0x06
-#define TYPE_MOD       0x07  /* Magneto-optical disk - treated as TYPE_DISK */
-#define TYPE_NO_LUN    0x7f
 
+#define MAX_COMMAND_SIZE    12
 
-#define MAX_COMMAND_SIZE 12
 /*
-       SCSI command sets
-
-*/
+ *  SCSI command sets
+ */
 
-#define SCSI_UNKNOWN   0
-#define        SCSI_1          1
-#define        SCSI_1_CCS      2
-#define        SCSI_2          3
+#define SCSI_UNKNOWN    0
+#define SCSI_1          1
+#define SCSI_1_CCS      2
+#define SCSI_2          3
 
 /*
      Every SCSI command starts with a one byte OP-code.
      The next byte's high three bits are the LUN of the
      device.  Any multi-byte quantities are stored high byte
      first, and may have a 5 bit MSB in the same byte
      as the LUN.
-*/
*  Every SCSI command starts with a one byte OP-code.
*  The next byte's high three bits are the LUN of the
*  device.  Any multi-byte quantities are stored high byte
*  first, and may have a 5 bit MSB in the same byte
*  as the LUN.
+ */
 
 /*
       Manufacturers list
-*/
*      Manufacturers list
+ */
 
 #define SCSI_MAN_UNKNOWN     0
 #define SCSI_MAN_NEC         1
@@ -284,70 +263,91 @@ extern const unsigned char scsi_command_size[8];
 #define SCSI_MAN_NEC_OLDCDR  3
 
 /*
-       The scsi_device struct contains what we know about each given scsi
-       device.
-*/
+ *  As the scsi do command functions are intelligent, and may need to
+ *  redo a command, we need to keep track of the last command
+ *  executed on each one.
+ */
+
+#define WAS_RESET       0x01
+#define WAS_TIMEDOUT    0x02
+#define WAS_SENSE       0x04
+#define IS_RESETTING    0x08
+#define IS_ABORTING     0x10
+#define ASKED_FOR_SENSE 0x20
+
+/*
+ *  The scsi_device struct contains what we know about each given scsi
+ *  device.
+ */
 
 typedef struct scsi_device {
-        struct scsi_device * next; /* Used for linked list */
-       unsigned char id, lun;
-       unsigned int manufacturer; /* Manufacturer of device, for using vendor-specific cmd's */
-       int attached;          /* # of high level drivers attached to this */
-       int access_count;       /* Count of open channels/mounts */
-       struct wait_queue * device_wait;  /* Used to wait if device is busy */
-       struct Scsi_Host * host;
-       void (*scsi_request_fn)(void); /* Used to jumpstart things after an ioctl */
-       void *hostdata;                   /* available to low-level driver */
-       char type;
-       char scsi_level;
-       unsigned writeable:1;
-       unsigned removable:1; 
-       unsigned random:1;
-       unsigned changed:1;     /* Data invalid due to media change */
-       unsigned busy:1;        /* Used to prevent races */
-       unsigned lockable:1;    /* Able to prevent media removal */
-       unsigned borken:1;      /* Tell the Seagate driver to be 
-                                  painfully slow on this device */ 
-       unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
-       unsigned tagged_queue:1;   /*SCSI-II tagged queuing enabled */
-       unsigned disconnect:1;     /* can disconnect */
-       unsigned soft_reset:1;          /* Uses soft reset option */
-       unsigned char current_tag; /* current tag */
-       unsigned sync:1;        /* Negotiate for sync transfers */
-       unsigned char sync_min_period;  /* Not less than this period */
-       unsigned char sync_max_offset;  /* Not greater than this offset */
+    struct scsi_device * next;      /* Used for linked list */
+
+    unsigned char id, lun, channel;
+
+    unsigned int manufacturer;      /* Manufacturer of device, for using 
+                                    * vendor-specific cmd's */
+    int attached;                   /* # of high level drivers attached to 
+                                    * this */
+    int access_count;               /* Count of open channels/mounts */
+    struct wait_queue * device_wait;/* Used to wait if device is busy */
+    struct Scsi_Host * host;
+    void (*scsi_request_fn)(void);  /* Used to jumpstart things after an 
+                                    * ioctl */
+    void *hostdata;                 /* available to low-level driver */
+    char type;
+    char scsi_level;
+    char vendor[8], model[16], rev[4];
+    unsigned writeable:1;
+    unsigned removable:1; 
+    unsigned random:1;
+    unsigned changed:1;             /* Data invalid due to media change */
+    unsigned busy:1;                /* Used to prevent races */
+    unsigned lockable:1;            /* Able to prevent media removal */
+    unsigned borken:1;              /* Tell the Seagate driver to be 
+                                    * painfully slow on this device */ 
+    unsigned tagged_supported:1;    /* Supports SCSI-II tagged queuing */
+    unsigned tagged_queue:1;        /* SCSI-II tagged queuing enabled */
+    unsigned disconnect:1;          /* can disconnect */
+    unsigned soft_reset:1;          /* Uses soft reset option */
+    unsigned sync:1;                /* Negotiate for sync transfers */
+    unsigned char current_tag;      /* current tag */
+    unsigned char sync_min_period;  /* Not less than this period */
+    unsigned char sync_max_offset;  /* Not greater than this offset */
 } Scsi_Device;
+
 /*
      Use these to separate status msg and our bytes
-*/
*  Use these to separate status msg and our bytes
+ */
 
 #define status_byte(result) (((result) >> 1) & 0xf)
-#define msg_byte(result) (((result) >> 8) & 0xff)
-#define host_byte(result) (((result) >> 16) & 0xff)
+#define msg_byte(result)    (((result) >> 8) & 0xff)
+#define host_byte(result)   (((result) >> 16) & 0xff)
 #define driver_byte(result) (((result) >> 24) & 0xff)
-#define suggestion(result) (driver_byte(result) & SUGGEST_MASK)
+#define suggestion(result)  (driver_byte(result) & SUGGEST_MASK)
 
-#define sense_class(sense) (((sense) >> 4) & 0x7)
-#define sense_error(sense) ((sense) & 0xf)
-#define sense_valid(sense) ((sense) & 0x80);
+#define sense_class(sense)  (((sense) >> 4) & 0x7)
+#define sense_error(sense)  ((sense) & 0xf)
+#define sense_valid(sense)  ((sense) & 0x80);
 
 /*
      These are the SCSI devices available on the system.
-*/
*  These are the SCSI devices available on the system.
+ */
 
 extern Scsi_Device * scsi_devices;
+
 /*
      Initializes all SCSI devices.  This scans all scsi busses.
-*/
*  Initializes all SCSI devices.  This scans all scsi busses.
+ */ 
 
 extern unsigned long scsi_dev_init (unsigned long, unsigned long);
 
 struct scatterlist {
-     char *  address; /* Location data is to be transferred to */
-     char * alt_address; /* Location of actual if address is a 
-                           dma indirect buffer.  NULL otherwise */
-     unsigned int length;
-     };
+    char *  address;    /* Location data is to be transferred to */
+    char * alt_address; /* Location of actual if address is a 
+                        * dma indirect buffer.  NULL otherwise */
+    unsigned int length;
+};
 
 #ifdef __alpha__
 # define ISA_DMA_THRESHOLD (~0UL)
@@ -363,59 +363,59 @@ struct scatterlist {
  * and reset functions must correctly indicate what it has done.
  */
 
-/* We did not do anything.  Wait
-   some more for this command to complete, and if this does not work, try
  something more serious. */ 
+/* We did not do anything.  
+ * Wait some more for this command to complete, and if this does not work, 
* try something more serious. */ 
 #define SCSI_ABORT_SNOOZE 0
 
 /* This means that we were able to abort the command.  We have already
-   called the mid-level done function, and do not expect an interrupt that will
  lead to another call to the mid-level done function for this command */
+ * called the mid-level done function, and do not expect an interrupt that 
* will lead to another call to the mid-level done function for this command */
 #define SCSI_ABORT_SUCCESS 1
 
 /* We called for an abort of this command, and we should get an interrupt 
  when this succeeds.  Thus we should not restore the timer for this
  command in the mid-level abort function. */
* when this succeeds.  Thus we should not restore the timer for this
* command in the mid-level abort function. */
 #define SCSI_ABORT_PENDING 2
 
 /* Unable to abort - command is currently on the bus.  Grin and bear it. */
 #define SCSI_ABORT_BUSY 3
 
 /* The command is not active in the low level code. Command probably
  finished. */
* finished. */
 #define SCSI_ABORT_NOT_RUNNING 4
 
 /* Something went wrong.  The low level driver will indicate the correct
- error condition when it calls scsi_done, so the mid-level abort function
- can simply wait until this comes through */
error condition when it calls scsi_done, so the mid-level abort function
can simply wait until this comes through */
 #define SCSI_ABORT_ERROR 5
 
 /* We do not know how to reset the bus, or we do not want to.  Bummer.
  Anyway, just wait a little more for the command in question, and hope that
  it eventually finishes.  If it never finishes, the SCSI device could
  hang, so use this with caution. */
* Anyway, just wait a little more for the command in question, and hope that
* it eventually finishes.  If it never finishes, the SCSI device could
* hang, so use this with caution. */
 #define SCSI_RESET_SNOOZE 0
 
 /* We do not know how to reset the bus, or we do not want to.  Bummer.
  We have given up on this ever completing.  The mid-level code will
  request sense information to decide how to proceed from here. */
* We have given up on this ever completing.  The mid-level code will
* request sense information to decide how to proceed from here. */
 #define SCSI_RESET_PUNT 1
 
 /* This means that we were able to reset the bus.  We have restarted all of
  the commands that should be restarted, and we should be able to continue
  on normally from here.  We do not expect any interrupts that will return
  DID_RESET to any of the other commands in the host_queue, and the mid-level
  code does not need to do anything special to keep the commands alive. */
* the commands that should be restarted, and we should be able to continue
* on normally from here.  We do not expect any interrupts that will return
* DID_RESET to any of the other commands in the host_queue, and the mid-level
* code does not need to do anything special to keep the commands alive. */
 #define SCSI_RESET_SUCCESS 2
 
 /* We called for a reset of this bus, and we should get an interrupt 
  when this succeeds.  Each command should get its own status
  passed up to scsi_done, but this has not happened yet. */
* when this succeeds.  Each command should get its own status
* passed up to scsi_done, but this has not happened yet. */
 #define SCSI_RESET_PENDING 3
 
 /* We did a reset, but do not expect an interrupt to signal DID_RESET.
  This tells the upper level code to request the sense info, and this
  should keep the command alive. */
* This tells the upper level code to request the sense info, and this
* should keep the command alive. */
 #define SCSI_RESET_WAKEUP 4
 
 /* Something went wrong, and we do not know how to fix it. */
@@ -423,118 +423,120 @@ struct scatterlist {
 
 void *   scsi_malloc(unsigned int);
 int      scsi_free(void *, unsigned int);
-extern unsigned int dma_free_sectors;   /* How much room do we have left */
+extern unsigned int dma_free_sectors;  /* How much room do we have left */
 extern unsigned int need_isa_buffer;   /* True if some devices need indirection
-                                buffers */
+                                       * buffers */
 
 /*
-       The Scsi_Cmnd structure is used by scsi.c internally, and for communication with
      low level drivers that support multiple outstanding commands.
-*/
+ * The Scsi_Cmnd structure is used by scsi.c internally, and for communication
* with low level drivers that support multiple outstanding commands.
+ */
 typedef struct scsi_pointer {
-  char * ptr;                     /* data pointer */
-  int this_residual;              /* left in this buffer */
-  struct scatterlist *buffer;     /* which buffer */
-  int buffers_residual;           /* how many buffers left */
-
-  volatile int Status;
-  volatile int Message;
-  volatile int have_data_in;
-  volatile int sent_command;
-  volatile int phase;
+    char * ptr;                     /* data pointer */
+    int this_residual;              /* left in this buffer */
+    struct scatterlist *buffer;     /* which buffer */
+    int buffers_residual;           /* how many buffers left */
+    
+    volatile int Status;
+    volatile int Message;
+    volatile int have_data_in;
+    volatile int sent_command;
+    volatile int phase;
 } Scsi_Pointer;
 
 typedef struct scsi_cmnd {
-       struct Scsi_Host * host;
-       Scsi_Device * device;
-       unsigned char target, lun;
-       unsigned char cmd_len;
-       unsigned char old_cmd_len;
-       struct scsi_cmnd *next, *prev;  
-
-/* These elements define the operation we are about to perform */
-       unsigned char cmnd[12];
-       unsigned request_bufflen; /* Actual request size */
-
-       void * request_buffer;  /* Actual requested buffer */
-
-/* These elements define the operation we ultimately want to perform */
-       unsigned char data_cmnd[12];
-       unsigned short old_use_sg;  /* We save  use_sg here when requesting
-                                      sense info */
-       unsigned short use_sg;  /* Number of pieces of scatter-gather */
-       unsigned short sglist_len;  /* size of malloc'd scatter-gather list */
-       unsigned short abort_reason;  /* If the mid-level code requests an
-                                        abort, this is the reason. */
-       unsigned bufflen;     /* Size of data buffer */
-       void *buffer;   /* Data buffer */
-
-       unsigned underflow;     /* Return error if less than this amount is 
-                                  transfered */
-
-       unsigned transfersize;  /* How much we are guaranteed to transfer with
-                                  each SCSI transfer (ie, between disconnect /
-                                  reconnects.   Probably == sector size */
-       
-       
-       
-       struct request request;  /* A copy of the command we are working on*/
-
-       unsigned char sense_buffer[16];  /* Sense for this command, if needed*/
+    struct Scsi_Host * host;
+    Scsi_Device * device;
+    unsigned char target, lun, channel;
+    unsigned char cmd_len;
+    unsigned char old_cmd_len;
+    struct scsi_cmnd *next, *prev;  
+    
+    /* These elements define the operation we are about to perform */
+    unsigned char cmnd[12];
+    unsigned request_bufflen;   /* Actual request size */
+    
+    void * request_buffer;      /* Actual requested buffer */
+    
+    /* These elements define the operation we ultimately want to perform */
+    unsigned char data_cmnd[12];
+    unsigned short old_use_sg;  /* We save  use_sg here when requesting
+                                * sense info */
+    unsigned short use_sg;      /* Number of pieces of scatter-gather */
+    unsigned short sglist_len;  /* size of malloc'd scatter-gather list */
+    unsigned short abort_reason;/* If the mid-level code requests an
+                                * abort, this is the reason. */
+    unsigned bufflen;           /* Size of data buffer */
+    void *buffer;               /* Data buffer */
+    
+    unsigned underflow;         /* Return error if less than this amount is 
+                                * transfered */
+    
+    unsigned transfersize;      /* How much we are guaranteed to transfer with
+                                * each SCSI transfer (ie, between disconnect /
+                                * reconnects.   Probably == sector size */
+    
+    
+    struct request request;     /* A copy of the command we are working on */
+
+    unsigned char sense_buffer[16];  /* Sense for this command, if needed */
+
+
+    int retries;
+    int allowed;
+    int timeout_per_command, timeout_total, timeout;
+
+    /*
+     *  We handle the timeout differently if it happens when a reset, 
+     *  abort, etc are in process. 
+     */
+    unsigned volatile char internal_timeout;
+    
+    unsigned flags;
+    
+    /* These variables are for the cdrom only. Once we have variable size 
+     * buffers in the buffer cache, they will go away. */
+    int this_count; 
+    /* End of special cdrom variables */
+    
+    /* Low-level done function - can be used by low-level driver to point
+     *  to completion function.  Not used by mid/upper level code. */
+    void (*scsi_done)(struct scsi_cmnd *);  
+    void (*done)(struct scsi_cmnd *);  /* Mid-level done function */
+    
+    /*
+     * The following fields can be written to by the host specific code. 
+     * Everything else should be left alone. 
+     */
+    
+    Scsi_Pointer SCp;   /* Scratchpad used by some host adapters */
+    
+    unsigned char * host_scribble; /* The host adapter is allowed to
+                                   * call scsi_malloc and get some memory
+                                   * and hang it here.  The host adapter
+                                   * is also expected to call scsi_free
+                                   * to release this memory.  (The memory
+                                   * obtained by scsi_malloc is guaranteed
+                                   * to be at an address < 16Mb). */
+    
+    int result;                    /* Status code from lower level driver */
+    
+    unsigned char tag;             /* SCSI-II queued command tag */
+    unsigned long pid;             /* Process ID, starts at 0 */
+} Scsi_Cmnd;         
 
-
-       int retries;
-       int allowed;
-       int timeout_per_command, timeout_total, timeout;
 /*
- *     We handle the timeout differently if it happens when a reset, 
- *     abort, etc are in process. 
+ *  scsi_abort aborts the current command that is executing on host host.
+ *  The error code, if non zero is returned in the host byte, otherwise 
+ *  DID_ABORT is returned in the hostbyte.
  */
 
-       unsigned volatile char internal_timeout;
-
-       unsigned flags;
-               
-/* These variables are for the cdrom only.  Once we have variable size buffers
-   in the buffer cache, they will go away. */
-       int this_count; 
-/* End of special cdrom variables */
-       
-       /* Low-level done function - can be used by low-level driver to point
-        to completion function.  Not used by mid/upper level code. */
-       void (*scsi_done)(struct scsi_cmnd *);  
-       void (*done)(struct scsi_cmnd *);  /* Mid-level done function */
-
-/* The following fields can be written to by the host specific code. 
-   Everything else should be left alone. */
-
-       Scsi_Pointer SCp;   /* Scratchpad used by some host adapters */
-
-       unsigned char * host_scribble; /* The host adapter is allowed to
-                                         call scsi_malloc and get some memory
-                                         and hang it here.  The host adapter
-                                         is also expected to call scsi_free
-                                         to release this memory.  (The memory
-                                         obtained by scsi_malloc is guaranteed
-                                         to be at an address < 16Mb). */
-
-       int result;                   /* Status code from lower level driver */
-
-       unsigned char tag;              /* SCSI-II queued command tag */
-       unsigned long pid;              /* Process ID, starts at 0 */
-       } Scsi_Cmnd;             
-
-/*
-       scsi_abort aborts the current command that is executing on host host.
-       The error code, if non zero is returned in the host byte, otherwise 
-       DID_ABORT is returned in the hostbyte.
-*/
-
 extern int scsi_abort (Scsi_Cmnd *, int code, int pid);
 
 extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
-                  void *buffer, unsigned bufflen, void (*done)(struct scsi_cmnd *),
-                  int timeout, int retries);
+                        void *buffer, unsigned bufflen, 
+                        void (*done)(struct scsi_cmnd *),
+                        int timeout, int retries);
 
 
 extern Scsi_Cmnd * allocate_device(struct request **, Scsi_Device *, int);
@@ -544,22 +546,31 @@ extern int scsi_reset (Scsi_Cmnd *);
 
 extern int max_scsi_hosts;
 
+extern void build_proc_dir_entries(void);
+
+extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+extern int        scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+extern void print_command(unsigned char *);
+extern void print_sense(char *,  Scsi_Cmnd *);
+
+
 #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
 #include "hosts.h"
+
 static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
 {
-       struct request * req;
-       struct buffer_head * bh;
-
-       req = &SCpnt->request;
-       req->errors = 0;
-       if (!uptodate) {
-               printk(DEVICE_NAME " I/O error: dev %04x, sector %lu\n",
-                      req->dev,req->sector);
-       }
-
-       do {
-         if ((bh = req->bh) != NULL) {
+    struct request * req;
+    struct buffer_head * bh;
+    
+    req = &SCpnt->request;
+    req->errors = 0;
+    if (!uptodate) {
+       printk(DEVICE_NAME " I/O error: dev %04x, sector %lu\n",
+              req->dev,req->sector);
+    }
+    
+    do {
+       if ((bh = req->bh) != NULL) {
            req->bh = bh->b_reqnext;
            req->nr_sectors -= bh->b_size >> 9;
            req->sector += bh->b_size >> 9;
@@ -568,74 +579,74 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
            unlock_buffer(bh);
            sectors -= bh->b_size >> 9;
            if ((bh = req->bh) != NULL) {
-             req->current_nr_sectors = bh->b_size >> 9;
-             if (req->nr_sectors < req->current_nr_sectors) {
-               req->nr_sectors = req->current_nr_sectors;
-               printk("end_scsi_request: buffer-list destroyed\n");
-             }
+               req->current_nr_sectors = bh->b_size >> 9;
+               if (req->nr_sectors < req->current_nr_sectors) {
+                   req->nr_sectors = req->current_nr_sectors;
+                   printk("end_scsi_request: buffer-list destroyed\n");
+               }
            }
-         }
-       } while(sectors && bh);
-       if (req->bh){
-         req->buffer = bh->b_data;
-         return SCpnt;
-       };
-       DEVICE_OFF(req->dev);
-       if (req->sem != NULL) {
-               up(req->sem);
        }
-
-        if (SCpnt->host->block) {
-           struct Scsi_Host * next;
-
-           for (next = SCpnt->host->block; next != SCpnt->host;
-                                                   next = next->block)
-              wake_up(&next->host_wait);
-           }
-
-       req->dev = -1;
-       wake_up(&wait_for_request);
-       wake_up(&SCpnt->device->device_wait);
-       return NULL;
+    } while(sectors && bh);
+    if (req->bh){
+       req->buffer = bh->b_data;
+       return SCpnt;
+    };
+    DEVICE_OFF(req->dev);
+    if (req->sem != NULL) {
+       up(req->sem);
+    }
+    
+    if (SCpnt->host->block) {
+       struct Scsi_Host * next;
+       
+       for (next = SCpnt->host->block; next != SCpnt->host;
+            next = next->block)
+           wake_up(&next->host_wait);
+    }
+    
+    req->dev = -1;
+    wake_up(&wait_for_request);
+    wake_up(&SCpnt->device->device_wait);
+    return NULL;
 }
 
 
 /* This is just like INIT_REQUEST, but we need to be aware of the fact
  that an interrupt may start another request, so we run this with interrupts
-   turned off */
-
* that an interrupt may start another request, so we run this with interrupts
+ * turned off 
+ */
 #define INIT_SCSI_REQUEST \
-       if (!CURRENT) {\
-               CLEAR_INTR; \
-               restore_flags(flags);   \
-               return; \
-       } \
-       if (MAJOR(CURRENT->dev) != MAJOR_NR) \
-               panic(DEVICE_NAME ": request list destroyed"); \
-       if (CURRENT->bh) { \
-               if (!CURRENT->bh->b_lock) \
-                       panic(DEVICE_NAME ": block not locked"); \
-       }
+    if (!CURRENT) {\
+       CLEAR_INTR; \
+       restore_flags(flags);   \
+       return; \
+    } \
+    if (MAJOR(CURRENT->dev) != MAJOR_NR) \
+       panic(DEVICE_NAME ": request list destroyed"); \
+    if (CURRENT->bh) { \
+       if (!CURRENT->bh->b_lock) \
+           panic(DEVICE_NAME ": block not locked"); \
+    }
 #endif
 
-#define SCSI_SLEEP(QUEUE, CONDITION) {                         \
-       if (CONDITION) {                                        \
-               struct wait_queue wait = { current, NULL};      \
-               add_wait_queue(QUEUE, &wait);                   \
-        for(;;) {                                              \
-               current->state = TASK_UNINTERRUPTIBLE;          \
-               if (CONDITION) {                                \
-                   if (intr_count)                              \
-                      panic("scsi: trying to call schedule() in interrupt" \
-                            ", file %s, line %d.\n", __FILE__, __LINE__);  \
-                  schedule();                                  \
-                  }                                            \
-               else                                            \
-                   break;                                      \
-               }                                               \
-               remove_wait_queue(QUEUE, &wait);                \
-               current->state = TASK_RUNNING;                  \
-       }; }
+#define SCSI_SLEEP(QUEUE, CONDITION) {              \
+    if (CONDITION) {                    \
+       struct wait_queue wait = { current, NULL};  \
+       add_wait_queue(QUEUE, &wait);           \
+       for(;;) {                           \
+       current->state = TASK_UNINTERRUPTIBLE;      \
+       if (CONDITION) {                \
+                  if (intr_count)                              \
+                     panic("scsi: trying to call schedule() in interrupt" \
+                           ", file %s, line %d.\n", __FILE__, __LINE__);  \
+          schedule();                  \
+          }                            \
+           else                        \
+                  break;                                       \
+       }                       \
+       remove_wait_queue(QUEUE, &wait);        \
+       current->state = TASK_RUNNING;          \
+    }; }
 
 #endif
 
@@ -646,12 +657,14 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
  * of the file.
  * ---------------------------------------------------------------------------
  * Local variables:
- * c-indent-level: 8
+ * c-indent-level: 
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
  * End:
  */
index b9db52b977f211f744dcae4e9a77c48c6a41704f..4611768a4c38ead3057b6e583c11eb335dff726a 100644 (file)
@@ -7,6 +7,10 @@
  *  anything out of the ordinary is seen.
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/genhd.h>
 #include <linux/fs.h>
+#include <linux/proc_fs.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -36,7 +46,7 @@
 /* Number of real scsi disks that will be detected ahead of time */
 static int NR_REAL=-1;
 
-#define NR_BLK_DEV     12
+#define NR_BLK_DEV  12
 #ifndef MAJOR_NR
 #define MAJOR_NR 8
 #endif
@@ -61,42 +71,45 @@ static int npart = 0;
 #define VERIFY_DEBUG(RW) 1
 #else
 
-#define VERIFY1_DEBUG(RW)                                              \
-      if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");};                  \
-      start = 0;                                                       \
-      if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1];             \
-      if (bh){                                                 \
-       if (bh->b_size != 1024) panic ("Wrong bh size");        \
-       if ((bh->b_blocknr << 1) + start != block)              \
-         {  printk("Wrong bh block# %d %d ",bh->b_blocknr, block);  \
-         panic ("Wrong bh block#");};  \
+#define VERIFY1_DEBUG(RW)                           \
+    if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");};         \
+    start = 0;                          \
+    if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1];        \
+    if (bh){                            \
+       if (bh->b_size != 1024) panic ("Wrong bh size");    \
+       if ((bh->b_blocknr << 1) + start != block)          \
+       {   printk("Wrong bh block# %d %d ",bh->b_blocknr, block);  \
+           panic ("Wrong bh block#"); \
+       };  \
        if (bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\
-      };
+    };
 
 #if 0
 /* This had been in the VERIFY_DEBUG macro, but it fails if there is already
-   a disk on the system */
-      if ((SCpnt->request.dev & 0xfff0) != ((target + NR_REAL) << 4) +(MAJOR_NR << 8)){        \
-       printk("Dev #s %x %x ",SCpnt->request.dev, target);                     \
-       panic ("Bad target");};                                         \
+ * a disk on the system */
+    if ((SCpnt->request.dev & 0xfff0) != ((target + NR_REAL) << 4) +(MAJOR_NR << 8)){   \
+       printk("Dev #s %x %x ",SCpnt->request.dev, target);         \
+       panic ("Bad target");\
+    };                      \
 
 #endif
 
-#define VERIFY_DEBUG(RW)                                               \
-      if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");};     \
-      start = 0;                                                       \
-      if ((SCpnt->request.dev & 0xf) > npart) panic ("Bad partition"); \
-      if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1];             \
-      if (SCpnt->request.cmd != RW) panic ("Wrong  operation");                \
-      if (SCpnt->request.sector + start != block) panic("Wrong block.");       \
-      if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks");        \
-      if (SCpnt->request.bh){                                                  \
-       if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
-       if ((SCpnt->request.bh->b_blocknr << 1) + start != block)               \
-         {  printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block);  \
-         panic ("Wrong bh block#");};  \
+#define VERIFY_DEBUG(RW)                            \
+    if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");};    \
+    start = 0;                          \
+    if ((SCpnt->request.dev & 0xf) > npart) panic ("Bad partition");    \
+    if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1];        \
+    if (SCpnt->request.cmd != RW) panic ("Wrong  operation");       \
+    if (SCpnt->request.sector + start != block) panic("Wrong block.");  \
+    if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks");   \
+    if (SCpnt->request.bh){                         \
+       if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
+       if ((SCpnt->request.bh->b_blocknr << 1) + start != block)           \
+       {   printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block);  \
+           panic ("Wrong bh block#"); \
+       };  \
        if (SCpnt->request.bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\
-      };
+    };
 #endif
 
 static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, };
@@ -108,48 +121,48 @@ static volatile unsigned int timeout[SCSI_DEBUG_MAILBOXES] ={0,};
 static char sense_buffer[128] = {0,};
 
 static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
-  int i;
+    int i;
 #if 0
-  unsigned char * pnt;
+    unsigned char * pnt;
 #endif
-  unsigned int * lpnt;
-  struct scatterlist * sgpnt = NULL;
-  printk("use_sg: %d",SCpnt->use_sg);
-  if (SCpnt->use_sg){
-    sgpnt = (struct scatterlist *) SCpnt->buffer;
-    for(i=0; i<SCpnt->use_sg; i++) {
-      lpnt = (int *) sgpnt[i].alt_address;
-      printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
-      if (lpnt) printk(" (Alt %x) ",lpnt[15]);
+    unsigned int * lpnt;
+    struct scatterlist * sgpnt = NULL;
+    printk("use_sg: %d",SCpnt->use_sg);
+    if (SCpnt->use_sg){
+       sgpnt = (struct scatterlist *) SCpnt->buffer;
+       for(i=0; i<SCpnt->use_sg; i++) {
+           lpnt = (int *) sgpnt[i].alt_address;
+           printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+           if (lpnt) printk(" (Alt %x) ",lpnt[15]);
+       };
+    } else {
+       printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+              SCpnt->bufflen);
+       lpnt = (int *) SCpnt->request.buffer;
+       if (lpnt) printk(" (Alt %x) ",lpnt[15]);
+    };
+    lpnt = (unsigned int *) SCpnt;
+    for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
+       if ((i & 7) == 0) printk("\n");
+       printk("%x ",*lpnt++);
+    };
+    printk("\n");
+    if (flag == 0) return;
+    lpnt = (unsigned int *) sgpnt[0].alt_address;
+    for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
+       if ((i & 7) == 0) printk("\n");
+       printk("%x ",*lpnt++);
     };
-  } else {
-    printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
-          SCpnt->bufflen);
-    lpnt = (int *) SCpnt->request.buffer;
-    if (lpnt) printk(" (Alt %x) ",lpnt[15]);
-  };
-  lpnt = (unsigned int *) SCpnt;
-  for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
-    if ((i & 7) == 0) printk("\n");
-    printk("%x ",*lpnt++);
-  };
-  printk("\n");
-  if (flag == 0) return;
-  lpnt = (unsigned int *) sgpnt[0].alt_address;
-  for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
-    if ((i & 7) == 0) printk("\n");
-    printk("%x ",*lpnt++);
-  };
 #if 0
-  printk("\n");
-  lpnt = (unsigned int *) sgpnt[0].address;
-  for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
-    if ((i & 7) == 0) printk("\n");
-    printk("%x ",*lpnt++);
-  };
-  printk("\n");
+    printk("\n");
+    lpnt = (unsigned int *) sgpnt[0].address;
+    for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
+       if ((i & 7) == 0) printk("\n");
+       printk("%x ",*lpnt++);
+    };
+    printk("\n");
 #endif
-  printk("DMA free %d sectors.\n", dma_free_sectors);
+    printk("DMA free %d sectors.\n", dma_free_sectors);
 }
 
 int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
@@ -168,252 +181,254 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     int i;
     sgcount = 0;
     sgpnt = NULL;
-
+    
     DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;});
     
     buff = (unsigned char *) SCpnt->request_buffer;
-
+    
     if(target>=1 || SCpnt->lun != 0) {
-      SCpnt->result =  DID_NO_CONNECT << 16;
-      done(SCpnt);
-      return 0;
+       SCpnt->result =  DID_NO_CONNECT << 16;
+       done(SCpnt);
+       return 0;
     };
     
     switch(*cmd){
     case REQUEST_SENSE:
-      printk("Request sense...\n");
+       printk("Request sense...\n");
 #ifndef DEBUG
-      { int i;
-       printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
-       for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
-       printk("\n");
-      };
+       { 
+           int i;
+           printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
+           for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
+           printk("\n");
+       };
 #endif
-      memset(buff, 0, bufflen);
-      memcpy(buff, sense_buffer, bufflen);
-      memset(sense_buffer, 0, sizeof(sense_buffer));
-      SCpnt->result = 0;
-      done(SCpnt); 
-      return 0;
+       memset(buff, 0, bufflen);
+       memcpy(buff, sense_buffer, bufflen);
+       memset(sense_buffer, 0, sizeof(sense_buffer));
+       SCpnt->result = 0;
+       done(SCpnt); 
+       return 0;
     case ALLOW_MEDIUM_REMOVAL:
-      if(cmd[4]) printk("Medium removal inhibited...");
-      else printk("Medium removal enabled...");
-      scsi_debug_errsts = 0;
-      break;
+       if(cmd[4]) printk("Medium removal inhibited...");
+       else printk("Medium removal enabled...");
+       scsi_debug_errsts = 0;
+       break;
     case INQUIRY:
-      printk("Inquiry...(%x %d)\n", buff, bufflen);
-      memset(buff, 0, bufflen);
-      buff[0] = TYPE_DISK;
-      buff[1] = 0x80;  /* Removable disk */
-      buff[2] = 1;
-      buff[4] = 33 - 5;
-      memcpy(&buff[8],"Foo Inc",7);
-      memcpy(&buff[16],"XYZZY",5);
-      memcpy(&buff[32],"1",1);
-      scsi_debug_errsts = 0;
-      break;
-    case TEST_UNIT_READY:
-      printk("Test unit ready.\n");
-      if (buff)
+       printk("Inquiry...(%x %d)\n", buff, bufflen);
        memset(buff, 0, bufflen);
-      scsi_debug_errsts = 0;
-      break;
+       buff[0] = TYPE_DISK;
+       buff[1] = 0x80;  /* Removable disk */
+       buff[2] = 1;
+       buff[4] = 33 - 5;
+       memcpy(&buff[8],"Foo Inc",7);
+       memcpy(&buff[16],"XYZZY",5);
+       memcpy(&buff[32],"1",1);
+       scsi_debug_errsts = 0;
+       break;
+    case TEST_UNIT_READY:
+       printk("Test unit ready.\n");
+       if (buff)
+           memset(buff, 0, bufflen);
+       scsi_debug_errsts = 0;
+       break;
     case READ_CAPACITY:
-      printk("Read Capacity\n");
-      if(NR_REAL < 0) NR_REAL = (SCpnt->request.dev >> 4) & 0x0f;
-      memset(buff, 0, bufflen);
-      buff[0] = (CAPACITY >> 24);
-      buff[1] = (CAPACITY >> 16) & 0xff;
-      buff[2] = (CAPACITY >> 8) & 0xff;
-      buff[3] = CAPACITY & 0xff;
-      buff[6] = 2; /* 512 byte sectors */
-      scsi_debug_errsts = 0;
-      break;
+       printk("Read Capacity\n");
+       if(NR_REAL < 0) NR_REAL = (SCpnt->request.dev >> 4) & 0x0f;
+       memset(buff, 0, bufflen);
+       buff[0] = (CAPACITY >> 24);
+       buff[1] = (CAPACITY >> 16) & 0xff;
+       buff[2] = (CAPACITY >> 8) & 0xff;
+       buff[3] = CAPACITY & 0xff;
+       buff[6] = 2; /* 512 byte sectors */
+       scsi_debug_errsts = 0;
+       break;
     case READ_10:
     case READ_6:
 #ifdef DEBUG
-      printk("Read...");
+       printk("Read...");
 #endif
-      if ((*cmd) == READ_10)
-       block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); 
-      else 
-       block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-      VERIFY_DEBUG(READ);
+       if ((*cmd) == READ_10)
+           block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); 
+       else 
+           block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
+       VERIFY_DEBUG(READ);
 #if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
-      {
+    {
        int delay = SCSI_SETUP_LATENCY;
        double usec;
-
+       
        usec = 0.0;
        usec = (SCpnt->request.nr_sectors << 9) * 1.0e6 / SCSI_DATARATE;
        delay += usec;
        if(delay) usleep(delay);
-      };
+    };
 #endif
-
+       
 #ifdef DEBUG
-      printk("(r%d)",SCpnt->request.nr_sectors);
+       printk("(r%d)",SCpnt->request.nr_sectors);
 #endif
-      nbytes = bufflen;
-      if(SCpnt->use_sg){
-       sgcount = 0;
-       sgpnt = (struct scatterlist *) buff;
-       buff = sgpnt[sgcount].address;
-       bufflen = sgpnt[sgcount].length;
-       bh = SCpnt->request.bh;
-      };
-      scsi_debug_errsts = 0;
-      do{
-       VERIFY1_DEBUG(READ);
-/* For the speedy test, we do not even want to fill the buffer with anything */
+       nbytes = bufflen;
+       if(SCpnt->use_sg){
+           sgcount = 0;
+           sgpnt = (struct scatterlist *) buff;
+           buff = sgpnt[sgcount].address;
+           bufflen = sgpnt[sgcount].length;
+           bh = SCpnt->request.bh;
+       };
+       scsi_debug_errsts = 0;
+       do{
+           VERIFY1_DEBUG(READ);
+           /* For the speedy test, we do not even want to fill the buffer with anything */
 #ifndef SPEEDY
-       memset(buff, 0, bufflen);
+           memset(buff, 0, bufflen);
 #endif
-/* If this is block 0, then we want to read the partition table for this
-   device.  Let's make one up */
-       if(block == 0 && target == 0) {
-         *((unsigned short *) (buff+510)) = 0xAA55;
-         p = (struct partition* ) (buff + 0x1be);
-         npart = 0;
-         while(starts[npart+1]){
-           p->start_sect = starts[npart];
-           p->nr_sects = starts[npart+1] - starts [npart];
-           p->sys_ind = 0x81;  /* Linux partition */
-           p++;
-           npart++;
-         };
-         scsi_debug_errsts = 0;
-         break;
-       };
+           /* If this is block 0, then we want to read the partition table for this
+            * device.  Let's make one up */
+           if(block == 0 && target == 0) {
+               *((unsigned short *) (buff+510)) = 0xAA55;
+               p = (struct partition* ) (buff + 0x1be);
+               npart = 0;
+               while(starts[npart+1]){
+                   p->start_sect = starts[npart];
+                   p->nr_sects = starts[npart+1] - starts [npart];
+                   p->sys_ind = 0x81;  /* Linux partition */
+                   p++;
+                   npart++;
+               };
+               scsi_debug_errsts = 0;
+               break;
+           };
 #ifdef DEBUG
-       if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors,
-              SCpnt->request.current_nr_sectors);
+           if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors,
+                                     SCpnt->request.current_nr_sectors);
 #endif
-
+           
 #if 0
-       /* Simulate a disk change */
-       if(block == 0xfff0) {
-         sense_buffer[0] = 0x70;
-         sense_buffer[2] = UNIT_ATTENTION;
-         starts[0] += 10;
-         starts[1] += 10;
-         starts[2] += 10;
-        
+           /* Simulate a disk change */
+           if(block == 0xfff0) {
+               sense_buffer[0] = 0x70;
+               sense_buffer[2] = UNIT_ATTENTION;
+               starts[0] += 10;
+               starts[1] += 10;
+               starts[2] += 10;
+               
 #ifdef DEBUG
-      { int i;
-       printk("scsi_debug: Filling sense buffer:");
-       for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
-       printk("\n");
-      };
+               { 
+                   int i;
+                   printk("scsi_debug: Filling sense buffer:");
+                   for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
+                   printk("\n");
+               };
 #endif
-         scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
-         break;
-       } /* End phony disk change code */
+               scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+               break;
+           } /* End phony disk change code */
 #endif
-
+           
 #ifndef SPEEDY
-       memcpy(buff, &target, sizeof(target));
-       memcpy(buff+sizeof(target), cmd, 24);
-       memcpy(buff+60, &block, sizeof(block));
-       memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd));
+           memcpy(buff, &target, sizeof(target));
+           memcpy(buff+sizeof(target), cmd, 24);
+           memcpy(buff+60, &block, sizeof(block));
+           memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd));
 #endif
-       nbytes -= bufflen;
-       if(SCpnt->use_sg){
+           nbytes -= bufflen;
+           if(SCpnt->use_sg){
 #ifndef SPEEDY
-         memcpy(buff+128, bh, sizeof(struct buffer_head));
+               memcpy(buff+128, bh, sizeof(struct buffer_head));
 #endif
-         block += bufflen >> 9;
-         bh = bh->b_reqnext;
-         sgcount++;
-         if (nbytes) {
-           if(!bh) panic("Too few blocks for linked request.");
-           buff = sgpnt[sgcount].address;
-           bufflen = sgpnt[sgcount].length;
-         };
-       }
-      } while(nbytes);
-
-      SCpnt->result = 0;
-      (done)(SCpnt);
-      return;
-
-      if (SCpnt->use_sg && !scsi_debug_errsts)
-       if(bh) scsi_dump(SCpnt, 0);
-      break;
+               block += bufflen >> 9;
+               bh = bh->b_reqnext;
+               sgcount++;
+               if (nbytes) {
+                   if(!bh) panic("Too few blocks for linked request.");
+                   buff = sgpnt[sgcount].address;
+                   bufflen = sgpnt[sgcount].length;
+               };
+           }
+       } while(nbytes);
+       
+       SCpnt->result = 0;
+       (done)(SCpnt);
+       return;
+       
+       if (SCpnt->use_sg && !scsi_debug_errsts)
+           if(bh) scsi_dump(SCpnt, 0);
+       break;
     case WRITE_10:
     case WRITE_6:
 #ifdef DEBUG
-      printk("Write\n");
+       printk("Write\n");
 #endif
-      if ((*cmd) == WRITE_10)
-       block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); 
-      else 
-       block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-      VERIFY_DEBUG(WRITE);
-/*      printk("(w%d)",SCpnt->request.nr_sectors); */
-      if (SCpnt->use_sg){
-       if ((bufflen >> 9) != SCpnt->request.nr_sectors)
-         panic ("Trying to write wrong number of blocks\n");
-       sgpnt = (struct scatterlist *) buff;
-       buff = sgpnt[sgcount].address;
-      };
+       if ((*cmd) == WRITE_10)
+           block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); 
+       else 
+           block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
+       VERIFY_DEBUG(WRITE);
+       /*      printk("(w%d)",SCpnt->request.nr_sectors); */
+       if (SCpnt->use_sg){
+           if ((bufflen >> 9) != SCpnt->request.nr_sectors)
+               panic ("Trying to write wrong number of blocks\n");
+           sgpnt = (struct scatterlist *) buff;
+           buff = sgpnt[sgcount].address;
+       };
 #if 0
-      if (block != *((unsigned long *) (buff+60))) {
-       printk("%x %x :",block,  *((unsigned long *) (buff+60)));
-       scsi_dump(SCpnt,1);
-       panic("Bad block written.\n");
-      };
+       if (block != *((unsigned long *) (buff+60))) {
+           printk("%x %x :",block,  *((unsigned long *) (buff+60)));
+           scsi_dump(SCpnt,1);
+           panic("Bad block written.\n");
+       };
 #endif
-      scsi_debug_errsts = 0;
-      break;
-     default:
-      printk("Unknown command %d\n",*cmd);
-      SCpnt->result =  DID_NO_CONNECT << 16;
-      done(SCpnt);
-      return 0;
+       scsi_debug_errsts = 0;
+       break;
+    default:
+       printk("Unknown command %d\n",*cmd);
+       SCpnt->result =  DID_NO_CONNECT << 16;
+       done(SCpnt);
+       return 0;
     };
-
-   save_flags(flags); 
-   cli();
+    
+    save_flags(flags); 
+    cli();
     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){
-      if (SCint[i] == 0) break;
+       if (SCint[i] == 0) break;
     };
-
+    
     if (i >= SCSI_DEBUG_MAILBOXES || SCint[i] != 0) 
-      panic("Unable to find empty SCSI_DEBUG command slot.\n");
-
+       panic("Unable to find empty SCSI_DEBUG command slot.\n");
+    
     SCint[i] = SCpnt;
-
+    
     if (done) {
        DEB(printk("scsi_debug_queuecommand: now waiting for interrupt "););
        if (do_done[i])
-         printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");
+           printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");
        else
-         do_done[i] = done;
+           do_done[i] = done;
     }
     else
-      printk("scsi_debug_queuecommand: done cant be NULL\n");
-
+       printk("scsi_debug_queuecommand: done cant be NULL\n");
+    
 #ifdef IMMEDIATE
     SCpnt->result = scsi_debug_errsts;
     scsi_debug_intr_handle();  /* No timer - do this one right away */
 #else
     timeout[i] = jiffies+DISK_SPEED;
-
-/* If no timers active, then set this one */
+    
+    /* If no timers active, then set this one */
     if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) {
-      timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];
-      timer_active |= 1 << SCSI_DEBUG_TIMER;
+       timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];
+       timer_active |= 1 << SCSI_DEBUG_TIMER;
     };
-
+    
     SCpnt->result = scsi_debug_errsts;
     restore_flags(flags);
-
+    
 #if 0
     printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies);
 #endif
 #endif
-
+    
     return 0;
 }
 
@@ -429,14 +444,14 @@ int scsi_debug_command(Scsi_Cmnd * SCpnt)
 {
     DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n"));
     scsi_debug_queuecommand(SCpnt, internal_done);
-
+    
     while (!internal_done_flag);
     internal_done_flag = 0;
     return internal_done_errcode;
 }
 
 /* A "high" level interrupt handler.  This should be called once per jiffy
- to simulate a regular scsi disk.  We use a timer to do this. */
to simulate a regular scsi disk.  We use a timer to do this. */
 
 static void scsi_debug_intr_handle(void)
 {
@@ -445,71 +460,71 @@ static void scsi_debug_intr_handle(void)
     void (*my_done)(Scsi_Cmnd *); 
     unsigned long flags;
     int to;
-
+    
 #ifndef IMMEDIATE
     timer_table[SCSI_DEBUG_TIMER].expires = 0;
     timer_active &= ~(1 << SCSI_DEBUG_TIMER);
 #endif
-
 repeat:
+    
+ repeat:
     save_flags(flags);
     cli();
     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
-      if (SCint[i] == 0) continue;
+       if (SCint[i] == 0) continue;
 #ifndef IMMEDIATE
-      if (timeout[i] == 0) continue;
-      if (timeout[i] <= jiffies) break;
+       if (timeout[i] == 0) continue;
+       if (timeout[i] <= jiffies) break;
 #else
-      break;
+       break;
 #endif
     };
-
+    
     if(i == SCSI_DEBUG_MAILBOXES){
 #ifndef IMMEDIATE
-      pending = INT_MAX;
-      for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
-       if (SCint[i] == 0) continue;
-       if (timeout[i] == 0) continue;
-       if (timeout[i] <= jiffies) {restore_flags(flags); goto repeat;};
-       if (timeout[i] > jiffies) {
-         if (pending > timeout[i]) pending = timeout[i];
-         continue;
+       pending = INT_MAX;
+       for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
+           if (SCint[i] == 0) continue;
+           if (timeout[i] == 0) continue;
+           if (timeout[i] <= jiffies) {restore_flags(flags); goto repeat;};
+           if (timeout[i] > jiffies) {
+               if (pending > timeout[i]) pending = timeout[i];
+               continue;
+           };
        };
-      };
-      if (pending && pending != INT_MAX) {
-       timer_table[SCSI_DEBUG_TIMER].expires = 
-         (pending <= jiffies ? jiffies+1 : pending);
-       timer_active |= 1 << SCSI_DEBUG_TIMER;
-      };
-      restore_flags(flags);
+       if (pending && pending != INT_MAX) {
+           timer_table[SCSI_DEBUG_TIMER].expires = 
+               (pending <= jiffies ? jiffies+1 : pending);
+           timer_active |= 1 << SCSI_DEBUG_TIMER;
+       };
+       restore_flags(flags);
 #endif
-      return;
+       return;
     };
-
+    
     if(i < SCSI_DEBUG_MAILBOXES){
-      timeout[i] = 0;
-      my_done = do_done[i];
-      do_done[i] = NULL;
-      to = timeout[i];
-      timeout[i] = 0;
-      SCtmp = (Scsi_Cmnd *) SCint[i];
-      SCint[i] = NULL;
-      restore_flags(flags);
-
-      if (!my_done) {
-       printk("scsi_debug_intr_handle: Unexpected interrupt\n"); 
-       return;
-      }
-      
+       timeout[i] = 0;
+       my_done = do_done[i];
+       do_done[i] = NULL;
+       to = timeout[i];
+       timeout[i] = 0;
+       SCtmp = (Scsi_Cmnd *) SCint[i];
+       SCint[i] = NULL;
+       restore_flags(flags);
+       
+       if (!my_done) {
+           printk("scsi_debug_intr_handle: Unexpected interrupt\n"); 
+           return;
+       }
+       
 #ifdef DEBUG
-      printk("In intr_handle...");
-      printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
-      printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
+       printk("In intr_handle...");
+       printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
+       printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
 #endif
-
-      my_done(SCtmp);
+       
+       my_done(SCtmp);
 #ifdef DEBUG
-      printk("Called done.\n");
+       printk("Called done.\n");
 #endif
     };
     goto repeat;
@@ -530,38 +545,38 @@ int scsi_debug_abort(Scsi_Cmnd * SCpnt)
     int j;
     void (*my_done)(Scsi_Cmnd *);
     unsigned long flags;
-
+    
     DEB(printk("scsi_debug_abort\n"));
     SCpnt->result = SCpnt->abort_reason << 16;
     for(j=0;j<SCSI_DEBUG_MAILBOXES; j++) {
-      if(SCpnt == SCint[j]) {
-       my_done = do_done[j];
-       my_done(SCpnt);
-        save_flags(flags);
-       cli();
-       timeout[j] = 0;
-       SCint[j] = NULL;
-       do_done[j] = NULL;
-       restore_flags(flags);
-      };
+       if(SCpnt == SCint[j]) {
+           my_done = do_done[j];
+           my_done(SCpnt);
+           save_flags(flags);
+           cli();
+           timeout[j] = 0;
+           SCint[j] = NULL;
+           do_done[j] = NULL;
+           restore_flags(flags);
+       };
     };
     return 0;
 }
 
 int scsi_debug_biosparam(Disk * disk, int dev, int* info){
-  int size = disk->capacity;
-  info[0] = 32;
-  info[1] = 64;
-  info[2] = (size + 2047) >> 11;
-  if (info[2] >= 1024) info[2] = 1024;
-  return 0;
+    int size = disk->capacity;
+    info[0] = 32;
+    info[1] = 64;
+    info[2] = (size + 2047) >> 11;
+    if (info[2] >= 1024) info[2] = 1024;
+    return 0;
 }
 
 int scsi_debug_reset(Scsi_Cmnd * SCpnt)
 {
     int i;
     unsigned long flags;
-
+    
     void (*my_done)(Scsi_Cmnd *);
     DEB(printk("scsi_debug_reset called\n"));
     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
@@ -575,14 +590,38 @@ int scsi_debug_reset(Scsi_Cmnd * SCpnt)
       do_done[i] = NULL;
       timeout[i] = 0;
       restore_flags(flags);
-    };
+  };
     return 0;
 }
 
 const char *scsi_debug_info(void)
 {
-    static char buffer[] = " ";                        /* looks nicer without anything here */
+    static char buffer[] = " ";         /* looks nicer without anything here */
     return buffer;
 }
 
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = SCSI_DEBUG;
 
+#include "scsi_module.c"
+#endif
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
index 25fe199ea05de2937542228c44b382f0140b616d..2cc95e6ccb467921d0341925a154889388ee48d3 100644 (file)
@@ -9,13 +9,16 @@ int scsi_debug_abort(Scsi_Cmnd *);
 int scsi_debug_biosparam(Disk *, int, int[]);
 int scsi_debug_reset(Scsi_Cmnd *);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 #ifndef NULL
        #define NULL 0
 #endif
 
 #define SCSI_DEBUG_MAILBOXES 8
 
-#define SCSI_DEBUG {NULL, NULL, "SCSI DEBUG", scsi_debug_detect, NULL, \
+#define SCSI_DEBUG {NULL, NULL, generic_proc_info, "scsi_debug", \
+               PROC_SCSI_SCSI_DEBUG, "SCSI DEBUG", scsi_debug_detect, NULL, \
                NULL, scsi_debug_command,               \
                scsi_debug_queuecommand,                        \
                scsi_debug_abort,                               \
index a5a5f56f0c144d2296de77d95d613497ab8705f5..9f5e753f273d2075f19339a0d8d3772d4247c883 100644 (file)
@@ -13,7 +13,7 @@
 #include "hosts.h"
 #include "scsi_ioctl.h"
 
-#define MAX_RETRIES 5  
+#define MAX_RETRIES 5   
 #define MAX_TIMEOUT 900
 #define MAX_BUF 4096
 
 
 static int ioctl_probe(struct Scsi_Host * host, void *buffer)
 {
-       int temp;
-       unsigned int len,slen;
-       const char * string;
-       
-       if ((temp = host->hostt->present) && buffer) {
-               len = get_user ((unsigned int *) buffer);
-               if(host->hostt->info)
-                 string = host->hostt->info(host);
-               else 
-                 string = host->hostt->name;
-               if(string) {
-                 slen = strlen(string);
-                 if (len > slen)
-                   len = slen + 1;
-                 verify_area(VERIFY_WRITE, buffer, len);
-                 memcpy_tofs (buffer, string, len);
-               }
+    int temp;
+    unsigned int len,slen;
+    const char * string;
+    
+    if ((temp = host->hostt->present) && buffer) {
+       len = get_user ((unsigned int *) buffer);
+       if(host->hostt->info)
+           string = host->hostt->info(host);
+       else 
+           string = host->hostt->name;
+       if(string) {
+           slen = strlen(string);
+           if (len > slen)
+               len = slen + 1;
+           verify_area(VERIFY_WRITE, buffer, len);
+           memcpy_tofs (buffer, string, len);
        }
-       return temp;
+    }
+    return temp;
 }
 
 /*
@@ -78,53 +78,53 @@ static int ioctl_probe(struct Scsi_Host * host, void *buffer)
 
 static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
 {
-  struct request * req;
-  
-  req = &SCpnt->request;
-  req->dev = 0xfffe; /* Busy, but indicate request done */
-  
-  if (req->sem != NULL) {
-    up(req->sem);
-  }
-}      
+    struct request * req;
+    
+    req = &SCpnt->request;
+    req->dev = 0xfffe; /* Busy, but indicate request done */
+    
+    if (req->sem != NULL) {
+       up(req->sem);
+    }
+}   
 
 static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
 {
-       int result;
-       Scsi_Cmnd * SCpnt;
-
-       SCpnt = allocate_device(NULL, dev, 1);
-       scsi_do_cmd(SCpnt,  cmd, NULL,  0,
-                       scsi_ioctl_done,  MAX_TIMEOUT,
-                       MAX_RETRIES);
-
-       if (SCpnt->request.dev != 0xfffe){
-         struct semaphore sem = MUTEX_LOCKED;
-         SCpnt->request.sem = &sem;
-         down(&sem);
-         /* Hmm.. Have to ask about this one */
-         while (SCpnt->request.dev != 0xfffe) schedule();
-       };
-
-       if(driver_byte(SCpnt->result) != 0)
-         switch(SCpnt->sense_buffer[2] & 0xf) {
-         case ILLEGAL_REQUEST:
+    int result;
+    Scsi_Cmnd * SCpnt;
+    
+    SCpnt = allocate_device(NULL, dev, 1);
+    scsi_do_cmd(SCpnt,  cmd, NULL,  0,
+               scsi_ioctl_done,  MAX_TIMEOUT,
+               MAX_RETRIES);
+    
+    if (SCpnt->request.dev != 0xfffe){
+       struct semaphore sem = MUTEX_LOCKED;
+       SCpnt->request.sem = &sem;
+       down(&sem);
+       /* Hmm.. Have to ask about this one */
+       while (SCpnt->request.dev != 0xfffe) schedule();
+    };
+    
+    if(driver_byte(SCpnt->result) != 0)
+       switch(SCpnt->sense_buffer[2] & 0xf) {
+       case ILLEGAL_REQUEST:
            if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
            else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
            break;
-         case NOT_READY: /* This happens if there is no disc in drive */
+       case NOT_READY: /* This happens if there is no disc in drive */
            if(dev->removable){
-             printk("Device not ready.  Make sure there is a disc in the drive.\n");
-             break;
+               printk("Device not ready.  Make sure there is a disc in the drive.\n");
+               break;
            };
-         case UNIT_ATTENTION:
+       case UNIT_ATTENTION:
            if (dev->removable){
-             dev->changed = 1;
-             SCpnt->result = 0; /* This is no longer considered an error */
-             printk("Disc change detected.\n");
-             break;
+               dev->changed = 1;
+               SCpnt->result = 0; /* This is no longer considered an error */
+               printk("Disc change detected.\n");
+               break;
            };
-         default: /* Fall through for non-removable media */
+       default: /* Fall through for non-removable media */
            printk("SCSI CD error: host %d id %d lun %d return code = %x\n",
                   dev->host->host_no,
                   dev->id,
@@ -134,167 +134,171 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
                   sense_class(SCpnt->sense_buffer[0]),
                   sense_error(SCpnt->sense_buffer[0]),
                   SCpnt->sense_buffer[2] & 0xf);
-
-         };
-
-       result = SCpnt->result;
-       SCpnt->request.dev = -1;
-       wake_up(&SCpnt->device->device_wait);
-       return result;
+           
+       };
+    
+    result = SCpnt->result;
+    SCpnt->request.dev = -1;
+    wake_up(&SCpnt->device->device_wait);
+    return result;
 }
 
 static int ioctl_command(Scsi_Device *dev, void *buffer)
 {
-       char * buf;
-       char cmd[12];
-       char * cmd_in;
-       Scsi_Cmnd * SCpnt;
-       unsigned char opcode;
-       int inlen, outlen, cmdlen;
-       int needed, buf_needed;
-       int result;
-
-       if (!buffer)
-               return -EINVAL;
-       
-       inlen = get_user((unsigned int *) buffer);
-       outlen = get_user( ((unsigned int *) buffer) + 1);
-
-       cmd_in = (char *) ( ((int *)buffer) + 2);
-       opcode = get_user(cmd_in); 
-
-       needed = buf_needed = (inlen > outlen ? inlen : outlen);
-       if(buf_needed){
-         buf_needed = (buf_needed + 511) & ~511;
-         if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
-         buf = (char *) scsi_malloc(buf_needed);
-         if (!buf) return -ENOMEM;
-         memset(buf, 0, buf_needed);
-       } else
-         buf = NULL;
-
-       memcpy_fromfs ((void *) cmd,  cmd_in,  cmdlen = COMMAND_SIZE (opcode));
-       memcpy_fromfs ((void *) buf,  (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);
-
-       cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
-
+    char * buf;
+    char cmd[12];
+    char * cmd_in;
+    Scsi_Cmnd * SCpnt;
+    unsigned char opcode;
+    int inlen, outlen, cmdlen;
+    int needed, buf_needed;
+    int result;
+    
+    if (!buffer)
+       return -EINVAL;
+    
+       inlen = get_user((unsigned int *) buffer);
+       outlen = get_user( ((unsigned int *) buffer) + 1);
+  
+       cmd_in = (char *) ( ((int *)buffer) + 2);
+       opcode = get_user(cmd_in); 
+    
+    needed = buf_needed = (inlen > outlen ? inlen : outlen);
+    if(buf_needed){
+       buf_needed = (buf_needed + 511) & ~511;
+       if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
+       buf = (char *) scsi_malloc(buf_needed);
+       if (!buf) return -ENOMEM;
+       memset(buf, 0, buf_needed);
+    } else
+       buf = NULL;
+    
+    memcpy_fromfs ((void *) cmd,  cmd_in,  cmdlen = COMMAND_SIZE (opcode));
+    memcpy_fromfs ((void *) buf,  (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);
+    
+    cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
+    
 #ifndef DEBUG_NO_CMD
-       
-       SCpnt = allocate_device(NULL, dev, 1);
-
-       scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,  MAX_TIMEOUT, 
-                       MAX_RETRIES);
-
-       if (SCpnt->request.dev != 0xfffe){
-         struct semaphore sem = MUTEX_LOCKED;
-         SCpnt->request.sem = &sem;
-         down(&sem);
-         /* Hmm.. Have to ask about this one */
-         while (SCpnt->request.dev != 0xfffe) schedule();
-       };
-
-
-       /* If there was an error condition, pass the info back to the user. */
-       if(SCpnt->result) {
-         result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer));
-         if (result)
+    
+    SCpnt = allocate_device(NULL, dev, 1);
+    
+    scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,  MAX_TIMEOUT, 
+               MAX_RETRIES);
+    
+    if (SCpnt->request.dev != 0xfffe){
+       struct semaphore sem = MUTEX_LOCKED;
+       SCpnt->request.sem = &sem;
+       down(&sem);
+       /* Hmm.. Have to ask about this one */
+       while (SCpnt->request.dev != 0xfffe) schedule();
+    };
+    
+    
+    /* If there was an error condition, pass the info back to the user. */
+    if(SCpnt->result) {
+       result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer));
+       if (result)
            return result;
-         memcpy_tofs((void *) cmd_in,  SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
-       } else {
-
-         result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF  : outlen);
-         if (result)
+       memcpy_tofs((void *) cmd_in,  SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
+    } else {
+       
+       result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF  : outlen);
+       if (result)
            return result;
-         memcpy_tofs ((void *) cmd_in,  buf,  (outlen > MAX_BUF) ? MAX_BUF  : outlen);
-       };
-       result = SCpnt->result;
-       SCpnt->request.dev = -1;  /* Mark as not busy */
-       if (buf) scsi_free(buf, buf_needed);
-
-       if(SCpnt->device->scsi_request_fn)
-         (*SCpnt->device->scsi_request_fn)();
-
-       wake_up(&SCpnt->device->device_wait);
-       return result;
+       memcpy_tofs ((void *) cmd_in,  buf,  (outlen > MAX_BUF) ? MAX_BUF  : outlen);
+    };
+    result = SCpnt->result;
+    SCpnt->request.dev = -1;  /* Mark as not busy */
+    if (buf) scsi_free(buf, buf_needed);
+    
+    if(SCpnt->device->scsi_request_fn)
+       (*SCpnt->device->scsi_request_fn)();
+    
+    wake_up(&SCpnt->device->device_wait);
+    return result;
 #else
-       {
+    {
        int i;
        printk("scsi_ioctl : device %d.  command = ", dev->id);
        for (i = 0; i < 12; ++i)
-               printk("%02x ", cmd[i]);
+           printk("%02x ", cmd[i]);
        printk("\nbuffer =");
        for (i = 0; i < 20; ++i)
-               printk("%02x ", buf[i]);
+           printk("%02x ", buf[i]);
        printk("\n");
        printk("inlen = %d, outlen = %d, cmdlen = %d\n",
-               inlen, outlen, cmdlen);
+              inlen, outlen, cmdlen);
        printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
-       }
-       return 0;
+    }
+    return 0;
 #endif
 }
 
 /*
      the scsi_ioctl() function differs from most ioctls in that it does
      not take a major/minor number as the dev filed.  Rather, it takes
      a pointer to a scsi_devices[] element, a structure. 
-*/
* the scsi_ioctl() function differs from most ioctls in that it does
* not take a major/minor number as the dev filed.  Rather, it takes
* a pointer to a scsi_devices[] element, a structure. 
+ */
 int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
 {
-        char scsi_cmd[12];
-
-       /* No idea how this happens.... */
-       if (!dev) return -ENXIO;
-       
-       switch (cmd) {
-               case SCSI_IOCTL_GET_IDLUN:
-                       verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-                       put_user(dev->id + (dev->lun << 8) + 
-                                (dev->host->host_no << 16), (unsigned int *) arg);
-                       return 0;
-               case SCSI_IOCTL_TAGGED_ENABLE:
-                       if(!suser())  return -EACCES;
-                       if(!dev->tagged_supported) return -EINVAL;
-                       dev->tagged_queue = 1;
-                       dev->current_tag = 1;
-                       break;
-               case SCSI_IOCTL_TAGGED_DISABLE:
-                       if(!suser())  return -EACCES;
-                       if(!dev->tagged_supported) return -EINVAL;
-                       dev->tagged_queue = 0;
-                       dev->current_tag = 0;
-                       break;
-               case SCSI_IOCTL_PROBE_HOST:
-                       return ioctl_probe(dev->host, arg);
-               case SCSI_IOCTL_SEND_COMMAND:
-                       if(!suser())  return -EACCES;
-                       return ioctl_command((Scsi_Device *) dev, arg);
-               case SCSI_IOCTL_DOORLOCK:
-                       if (!dev->removable || !dev->lockable) return 0;
-                       scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-                       scsi_cmd[1] = dev->lun << 5;
-                       scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-                       scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
-                       return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
-                       break;
-               case SCSI_IOCTL_DOORUNLOCK:
-                       if (!dev->removable || !dev->lockable) return 0;
-                       scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-                       scsi_cmd[1] = dev->lun << 5;
-                       scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-                       scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
-                       return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
-               case SCSI_IOCTL_TEST_UNIT_READY:
-                       scsi_cmd[0] = TEST_UNIT_READY;
-                       scsi_cmd[1] = dev->lun << 5;
-                       scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-                       scsi_cmd[4] = 0;
-                       return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
-                       break;
-               default :                       
-                       return -EINVAL;
-       }
+    char scsi_cmd[12];
+    
+    /* No idea how this happens.... */
+    if (!dev) return -ENXIO;
+    
+    switch (cmd) {
+    case SCSI_IOCTL_GET_IDLUN:
+       verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+       put_user(dev->id + (dev->lun << 8) + (dev->host->host_no << 16) +
+                   /* This has been added to support 
+                    * multichannel HBAs, it might cause 
+                    * problems with some software */ 
+                   (dev->channel << 24), 
+                   (unsigned long *) arg);
+       return 0;
+    case SCSI_IOCTL_TAGGED_ENABLE:
+       if(!suser())  return -EACCES;
+       if(!dev->tagged_supported) return -EINVAL;
+       dev->tagged_queue = 1;
+       dev->current_tag = 1;
+       break;
+    case SCSI_IOCTL_TAGGED_DISABLE:
+       if(!suser())  return -EACCES;
+       if(!dev->tagged_supported) return -EINVAL;
+       dev->tagged_queue = 0;
+       dev->current_tag = 0;
+       break;
+    case SCSI_IOCTL_PROBE_HOST:
+       return ioctl_probe(dev->host, arg);
+    case SCSI_IOCTL_SEND_COMMAND:
+       if(!suser())  return -EACCES;
+       return ioctl_command((Scsi_Device *) dev, arg);
+    case SCSI_IOCTL_DOORLOCK:
+       if (!dev->removable || !dev->lockable) return 0;
+       scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+       scsi_cmd[1] = dev->lun << 5;
+       scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+       scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
+       return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
+       break;
+    case SCSI_IOCTL_DOORUNLOCK:
+       if (!dev->removable || !dev->lockable) return 0;
+       scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+       scsi_cmd[1] = dev->lun << 5;
+       scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+       scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
+       return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
+    case SCSI_IOCTL_TEST_UNIT_READY:
+       scsi_cmd[0] = TEST_UNIT_READY;
+       scsi_cmd[1] = dev->lun << 5;
+       scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+       scsi_cmd[4] = 0;
+       return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
+       break;
+    default :           
        return -EINVAL;
+    }
+    return -EINVAL;
 }
 
 /*
@@ -303,28 +307,30 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
  */
 
 int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) {
-  unsigned long oldfs;
-  int tmp;
-  oldfs = get_fs();
-  set_fs(get_ds());
-  tmp = scsi_ioctl (dev, cmd, arg);
-  set_fs(oldfs);
-  return tmp;
+    unsigned long oldfs;
+    int tmp;
+    oldfs = get_fs();
+    set_fs(get_ds());
+    tmp = scsi_ioctl (dev, cmd, arg);
+    set_fs(oldfs);
+    return tmp;
 }
 
 /*
- * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Overrides for Emacs so that we almost 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-indent-level: 4
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
  * End:
  */
index e6d7a607d512df9f9e6b80d34005ae1d5a37fdef..c054de5dc6a0a69ae7586380002d4181a36b49bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     scsi_module.c Copyright (1994, 1995) Eric Youngdale.
+ *  scsi_module.c Copyright (1994, 1995) Eric Youngdale.
  *
  * Support for loading low-level scsi drivers using the linux kernel loadable
  * module interface.
 char kernel_version[] = UTS_RELEASE;
 
 int init_module(void) {
-       driver_template.usage_count = &mod_use_count_;
-       scsi_register_module(MODULE_SCSI_HA, &driver_template);
-       return (driver_template.present == 0);
+    driver_template.usage_count = &mod_use_count_;
+    scsi_register_module(MODULE_SCSI_HA, &driver_template);
+    return (driver_template.present == 0);
 }
 
 void cleanup_module( void) {
-       if (MOD_IN_USE) {
-               printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
-             }
-       scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+    if (MOD_IN_USE) {
+       printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+       return;
+    }
+    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
 }
 
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
new file mode 100644 (file)
index 0000000..10785b6
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * linux/drivers/scsi/scsi_proc.c
+ *
+ * The functions in this file provide an interface between
+ * the PROC file system and the SCSI device drivers
+ * It is mainly used for debugging, statistics and to pass 
+ * information directly to the lowlevel driver.
+ *
+ * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de 
+ * Version: 0.99.5   last change: 95/06/28
+ * 
+ * generic command parser provided by: 
+ * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
+ */
+
+
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+#include <linux/errno.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+
+#ifndef TRUE
+#define TRUE  1
+#define FALSE 0
+#endif
+
+extern struct proc_dir_entry scsi_dir[];
+extern struct proc_dir_entry scsi_hba_dir[];
+extern int scsi_proc_info(char *, char **, off_t, int, int, int);
+
+int get_hba_index(int ino)
+{
+    Scsi_Host_Template *tpnt = scsi_hosts;
+    struct Scsi_Host *hpnt = scsi_hostlist;
+    uint x = 0;
+
+    while (tpnt) {
+       if (ino == tpnt->low_ino) 
+               return(x);
+       x += 3;
+       while (hpnt) {
+           hpnt = hpnt->next;
+           x++;
+       }
+       tpnt = tpnt->next;
+    }
+    return(0);
+}
+
+/* generic_proc_info
+ * Used if the driver currently has no own support for /proc/scsi
+ */
+int generic_proc_info(char *buffer, char **start, off_t offset, 
+                    int length, int inode, int inout)
+{
+    int len, pos, begin;
+
+    if(inout == TRUE)
+       return(-ENOSYS);  /* This is a no-op */
+    
+    begin = 0;
+    pos = len = sprintf(buffer, 
+                       "The driver does not yet support the proc-fs\n");
+    if(pos < offset)
+    {
+       len = 0;
+       begin = pos;
+    }
+    
+    *start = buffer + (offset - begin);   /* Start of wanted data */
+    len -= (offset - begin);
+    if(len > length)
+       len = length;
+    
+    return(len);
+}
+
+/* dispatch_scsi_info is the central dispatcher 
+ * It is the interface between the proc-fs and the SCSI subsystem code
+ */
+extern int dispatch_scsi_info(int ino, char *buffer, char **start, 
+                             off_t offset, int length, int func)
+{
+    struct Scsi_Host *hpnt = scsi_hostlist;
+
+    if(func != 2) {    
+       if(ino == PROC_SCSI_SCSI) 
+           return(scsi_proc_info(buffer, start, offset, length, 
+                                 hpnt->host_no, func));
+       while(hpnt) {
+           if (ino == (hpnt->host_no + PROC_SCSI_FILE)) 
+               return(hpnt->hostt->proc_info(buffer, start, offset, length, 
+                                             hpnt->host_no, func));
+           hpnt = hpnt->next;
+       }
+       return(-EBADF);
+    } else
+       return(get_hba_index(ino));
+}
+
+inline uint count_templates(void)
+{
+    Scsi_Host_Template *tpnt = scsi_hosts;
+    uint x = 0;
+    
+    while (tpnt) {
+       tpnt = tpnt->next;
+       x++;
+    }
+    return (x);
+}
+
+void build_proc_dir_hba_entries(void)
+{
+    Scsi_Host_Template *tpnt = scsi_hosts;
+    struct Scsi_Host *hpnt = scsi_hostlist;
+    static char names[PROC_SCSI_LAST - PROC_SCSI_FILE][3];
+    uint x, y;
+    
+    x = y = 0;
+
+    while (tpnt) {
+       scsi_hba_dir[x].low_ino = tpnt->low_ino;
+       scsi_hba_dir[x].namelen = 1;
+       scsi_hba_dir[x++].name = ".";
+       scsi_hba_dir[x].low_ino = PROC_SCSI;
+       scsi_hba_dir[x].namelen = 2;
+       scsi_hba_dir[x++].name = "..";
+           
+       while (hpnt) {
+           if (tpnt == hpnt->hostt) {
+               scsi_hba_dir[x].low_ino = PROC_SCSI_FILE + hpnt->host_no;
+               scsi_hba_dir[x].namelen = sprintf(names[y],"%d",hpnt->host_no);
+               scsi_hba_dir[x].name = names[y];
+               y++;
+               x++;
+           }
+           hpnt = hpnt->next;
+       }
+       
+       scsi_hba_dir[x].low_ino = 0;
+       scsi_hba_dir[x].namelen = 0;
+       scsi_hba_dir[x++].name = NULL;
+       tpnt = tpnt->next;
+    }    
+}
+
+void build_proc_dir_entries(void)
+{
+    Scsi_Host_Template *tpnt = scsi_hosts;
+    
+    uint newnum; 
+    uint x;
+    
+    newnum = count_templates();
+    
+    scsi_dir[0].low_ino = PROC_SCSI;
+    scsi_dir[0].namelen = 1;
+    scsi_dir[0].name = ".";
+    scsi_dir[1].low_ino = PROC_ROOT_INO;
+    scsi_dir[1].namelen = 2;
+    scsi_dir[1].name = "..";
+    scsi_dir[2].low_ino = PROC_SCSI_SCSI;
+    scsi_dir[2].namelen = 4;
+    scsi_dir[2].name = "scsi";
+    for(x = 3; x < newnum + 3; x++, tpnt = tpnt->next) {
+       scsi_dir[x].low_ino = tpnt->low_ino;
+       scsi_dir[x].namelen = strlen(tpnt->procname);
+       scsi_dir[x].name = tpnt->procname;
+    }
+    scsi_dir[x].low_ino = 0;
+    scsi_dir[x].namelen = 0;
+    scsi_dir[x].name = NULL;
+    
+    build_proc_dir_hba_entries();
+}
+
+
+/*
+ *  parseHandle *parseInit(char *buf, char *cmdList, int cmdNum); 
+ *             gets a pointer to a null terminated data buffer
+ *             and a list of commands with blanks as delimiter 
+ *      in between. 
+ *      The commands have to be alphanumerically sorted. 
+ *      cmdNum has to contain the number of commands.
+ *             On success, a pointer to a handle structure
+ *             is returned, NULL on failure
+ *
+ *     int parseOpt(parseHandle *handle, char **param);
+ *             processes the next parameter. On success, the
+ *             index of the appropriate command in the cmdList
+ *             is returned, starting with zero.
+ *             param points to the null terminated parameter string.
+ *             On failure, -1 is returned.
+ *
+ *     The databuffer buf may only contain pairs of commands
+ *         options, separated by blanks:
+ *             <Command> <Parameter> [<Command> <Parameter>]*
+ */
+
+typedef struct
+{
+    char *buf,                            /* command buffer  */
+        *cmdList,                         /* command list    */
+        *bufPos,                          /* actual position */
+        **cmdPos,                         /* cmdList index   */
+        cmdNum;                           /* cmd number      */
+} parseHandle;
+       
+
+inline int parseFree (parseHandle *handle)               /* free memory     */
+{
+    kfree (handle->cmdPos);
+    kfree (handle);
+    
+    return(-1);
+}
+
+       
+parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
+{
+    char        *ptr;                               /* temp pointer    */
+    parseHandle *handle;                            /* new handle      */
+    
+    if (!buf || !cmdList)                           /* bad input ?     */
+       return(NULL);
+    if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), 1)) == 0)
+       return(NULL);                               /* out of memory   */
+    if ((handle->cmdPos = (char**) kmalloc(sizeof(int), cmdNum)) == 0) {
+       kfree(handle);
+       return(NULL);                               /* out of memory   */
+    }
+    
+    handle->buf     = handle->bufPos = buf;         /* init handle     */
+    handle->cmdList = cmdList;
+    handle->cmdNum  = cmdNum;
+    
+    handle->cmdPos[cmdNum = 0] = cmdList;
+    for (ptr = cmdList; *ptr; ptr++) {          /* scan command string */
+       if(*ptr == ' ') {                       /* and insert zeroes   */
+           *ptr++ = 0;
+           handle->cmdPos[++cmdNum] = ptr++;
+       } 
+    }
+    return(handle);
+}
+
+
+int parseOpt(parseHandle *handle, char **param)
+{
+    int  cmdIndex = 0, 
+        cmdLen = 0;
+    char *startPos;
+    
+    if (!handle)                                    /* invalid handle  */
+       return(parseFree(handle));
+    /* skip spaces     */  
+    for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
+    if (!*(handle->bufPos))
+       return(parseFree(handle));                  /* end of data     */
+    
+    startPos = handle->bufPos;                      /* store cmd start */
+    for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++)
+    {                                               /* no string end?  */
+       for (;;)
+       {
+           if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
+               break;                              /* char matches ?  */
+           else
+               if (memcmp(startPos, (char*)(handle->cmdPos[++cmdIndex]), cmdLen))
+                   return(parseFree(handle));      /* unknown command */
+           
+           if (cmdIndex >= handle->cmdNum)
+               return(parseFree(handle));          /* unknown command */     
+       }
+       
+       cmdLen++;                                   /* next char       */
+    }
+    
+    /* Get param. First skip all blanks, then insert zero after param  */
+    
+    for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
+    *param = handle->bufPos; 
+    
+    for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
+    *(handle->bufPos++) = 0;
+    
+    return(cmdIndex);
+}
+
+
+/*
+ * Overrides for Emacs so that we get a uniform tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
index 65b44d4d03ac5ae4d8f59cfbdf79b0fad95a5669..f981198958c43d745ce488ab6a1f9ee3b478f39b 100644 (file)
@@ -64,7 +64,7 @@ int scsicam_bios_param (Disk *disk, /* SCSI disk */
 
 /*
  * Function : static int partsize(struct buffer_head *bh, unsigned long 
- *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int secs);
+ *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
  *
  * Purpose : to determine the BIOS mapping used to create the partition
  *     table, storing the results in *cyls, *hds, and *secs 
@@ -129,7 +129,7 @@ static int partsize(struct buffer_head *bh, unsigned long capacity,
 
 /*
  * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
- *     unsigned int *hds, unsigned int secs);
+ *     unsigned int *hds, unsigned int *secs);
  *
  * Purpose : to determine a near-optimal int 0x13 mapping for a
  *     SCSI disk in terms of lost space of size capacity, storing
index f4a53ed7e14e375a8235f522cc82d5886e54749f..ac7adcae6118b9f3c9add701c5c351a8784d5671 100644 (file)
@@ -1,19 +1,19 @@
 /*
- *     sd.c Copyright (C) 1992 Drew Eckhardt 
- *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *      sd.c Copyright (C) 1992 Drew Eckhardt 
+ *           Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
- *     Linux scsi disk driver
- *             Initial versions: Drew Eckhardt 
- *             Subsequent revisions: Eric Youngdale
+ *      Linux scsi disk driver
+ *              Initial versions: Drew Eckhardt 
+ *              Subsequent revisions: Eric Youngdale
  *
- *     <drew@colorado.edu>
+ *      <drew@colorado.edu>
  *
  *       Modified by Eric Youngdale ericy@cais.com to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  *
- *      Modified by Eric Youngdale eric@aib.com to support loadable
- *      low-level scsi drivers.
+ *       Modified by Eric Youngdale eric@aib.com to support loadable
+ *       low-level scsi drivers.
  */
 
 #include <linux/fs.h>
 #include <linux/genhd.h>
 
 /*
-static const char RCSid[] = "$Header:";
-*/
+ *  static const char RCSid[] = "$Header:";
+ */
 
 #define MAX_RETRIES 5
 
 /*
- *     Time out in seconds for disks and Magneto-opticals (which are slower).
+ *  Time out in seconds for disks and Magneto-opticals (which are slower).
  */
 
-#define SD_TIMEOUT 600
+#define SD_TIMEOUT 700
 #define SD_MOD_TIMEOUT 750
 
-#define CLUSTERABLE_DEVICE(SC) (SC->host->hostt->use_clustering && \
-                           SC->device->type != TYPE_MOD)
+#define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \
+                               SC->device->type != TYPE_MOD)
 
 struct hd_struct * sd;
 int revalidate_scsidisk(int dev, int maxusage);
@@ -56,7 +56,7 @@ int revalidate_scsidisk(int dev, int maxusage);
 Scsi_Disk * rscsi_disks = NULL;
 static int * sd_sizes;
 static int * sd_blocksizes;
-static int * sd_hardsizes;             /* Hardware sector size */
+static int * sd_hardsizes;              /* Hardware sector size */
 
 extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
@@ -73,1112 +73,1160 @@ static int sd_attach(Scsi_Device *);
 static int sd_detect(Scsi_Device *);
 static void sd_detach(Scsi_Device *);
 
-struct Scsi_Device_Template sd_template = {NULL, "disk", "sd", TYPE_DISK, 
-                                            SCSI_DISK_MAJOR, 0, 0, 0, 1,
-                                            sd_detect, sd_init,
-                                            sd_finish, sd_attach, sd_detach};
+struct Scsi_Device_Template sd_template = 
+{ NULL, "disk", "sd", NULL, TYPE_DISK, 
+      SCSI_DISK_MAJOR, 0, 0, 0, 1,
+      sd_detect, sd_init,
+      sd_finish, sd_attach, sd_detach
+};
 
 static int sd_open(struct inode * inode, struct file * filp)
 {
-        int target;
-       target =  DEVICE_NR(MINOR(inode->i_rdev));
-
-       if(target >= sd_template.dev_max || !rscsi_disks[target].device)
-         return -ENXIO;   /* No such device */
+    int target;
+    target =  DEVICE_NR(MINOR(inode->i_rdev));
+    
+    if(target >= sd_template.dev_max || !rscsi_disks[target].device)
+       return -ENXIO;   /* No such device */
+    
+    /* 
+     * Make sure that only one process can do a check_change_disk at one time.
+     * This is also used to lock out further access when the partition table 
+     * is being re-read. 
+     */
+    
+    while (rscsi_disks[target].device->busy)
+    barrier();   
+    if(rscsi_disks[target].device->removable) {
+       check_disk_change(inode->i_rdev);
        
-/* Make sure that only one process can do a check_change_disk at one time.
- This is also used to lock out further access when the partition table is being re-read. */
-
-       while (rscsi_disks[target].device->busy)
-         barrier();
-
-       if(rscsi_disks[target].device->removable) {
-         check_disk_change(inode->i_rdev);
-
-         if(!rscsi_disks[target].device->access_count)
+       if(!rscsi_disks[target].device->access_count)
            sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
-       };
-       /*
-        * See if we are requesting a non-existent partition.  Do this
-        * after checking for disk change.
-        */
-       if(sd_sizes[MINOR(inode->i_rdev)] == 0)
-         return -ENXIO;
+    };
 
-       rscsi_disks[target].device->access_count++;
-       if (rscsi_disks[target].device->host->hostt->usage_count)
-         (*rscsi_disks[target].device->host->hostt->usage_count)++;
-       return 0;
+    /*
+     * See if we are requesting a non-existent partition.  Do this
+     * after checking for disk change.
+     */
+    if(sd_sizes[MINOR(inode->i_rdev)] == 0)
+       return -ENXIO;
+    
+    rscsi_disks[target].device->access_count++;
+    if (rscsi_disks[target].device->host->hostt->usage_count)
+       (*rscsi_disks[target].device->host->hostt->usage_count)++;
+    if(sd_template.usage_count) (*sd_template.usage_count)++;
+    return 0;
 }
 
 static void sd_release(struct inode * inode, struct file * file)
 {
-        int target;
-       sync_dev(inode->i_rdev);
-
-       target =  DEVICE_NR(MINOR(inode->i_rdev));
-
-       rscsi_disks[target].device->access_count--;
-       if (rscsi_disks[target].device->host->hostt->usage_count)
-         (*rscsi_disks[target].device->host->hostt->usage_count)--;
-
-       if(rscsi_disks[target].device->removable) {
-         if(!rscsi_disks[target].device->access_count)
+    int target;
+    sync_dev(inode->i_rdev);
+    
+    target =  DEVICE_NR(MINOR(inode->i_rdev));
+    
+    rscsi_disks[target].device->access_count--;
+    if (rscsi_disks[target].device->host->hostt->usage_count)
+       (*rscsi_disks[target].device->host->hostt->usage_count)--;
+    if(sd_template.usage_count) (*sd_template.usage_count)--;
+    
+    if(rscsi_disks[target].device->removable) {
+       if(!rscsi_disks[target].device->access_count)
            sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
-       };
+    }
 }
 
 static void sd_geninit(void);
 
 static struct file_operations sd_fops = {
-       NULL,                   /* lseek - default */
-       block_read,             /* read - general block-dev read */
-       block_write,            /* write - general block-dev write */
-       NULL,                   /* readdir - bad */
-       NULL,                   /* select */
-       sd_ioctl,               /* ioctl */
-       NULL,                   /* mmap */
-       sd_open,                /* open code */
-       sd_release,             /* release */
-       block_fsync,            /* fsync */
-       NULL,                   /* fasync */
-       check_scsidisk_media_change,  /* Disk change */
-       fop_revalidate_scsidisk     /* revalidate */
+    NULL,                        /* lseek - default */
+    block_read,                  /* read - general block-dev read */
+    block_write,                 /* write - general block-dev write */
+    NULL,                        /* readdir - bad */
+    NULL,                        /* select */
+    sd_ioctl,                    /* ioctl */
+    NULL,                        /* mmap */
+    sd_open,                     /* open code */
+    sd_release,                  /* release */
+    block_fsync,                 /* fsync */
+    NULL,                        /* fasync */
+    check_scsidisk_media_change, /* Disk change */
+    fop_revalidate_scsidisk      /* revalidate */
 };
 
 static struct gendisk sd_gendisk = {
-       MAJOR_NR,               /* Major number */
-       "sd",           /* Major name */
-       4,              /* Bits to shift to get real from partition */
-       1 << 4,         /* Number of partitions per real */
-       0,              /* maximum number of real */
-       sd_geninit,     /* init function */
-       NULL,           /* hd struct */
-       NULL,   /* block sizes */
-       0,              /* number */
-       NULL,   /* internal */
-       NULL            /* next */
+    MAJOR_NR,                    /* Major number */
+    "sd",                        /* Major name */
+    4,                           /* Bits to shift to get real from partition */
+    1 << 4,                      /* Number of partitions per real */
+    0,                           /* maximum number of real */
+    sd_geninit,                  /* init function */
+    NULL,                        /* hd struct */
+    NULL,                        /* block sizes */
+    0,                           /* number */
+    NULL,                        /* internal */
+    NULL                         /* next */
 };
 
 static void sd_geninit (void)
 {
-       int i;
-
-       for (i = 0; i < sd_template.dev_max; ++i)
-         if(rscsi_disks[i].device) 
+    int i;
+    
+    for (i = 0; i < sd_template.dev_max; ++i)
+       if(rscsi_disks[i].device) 
            sd[i << 4].nr_sects = rscsi_disks[i].capacity;
 #if 0
-       /* No longer needed - we keep track of this as we attach/detach */
-       sd_gendisk.nr_real = sd_template.dev_max;
+    /* No longer needed - we keep track of this as we attach/detach */
+    sd_gendisk.nr_real = sd_template.dev_max;
 #endif
 }
 
 /*
      rw_intr is the interrupt routine for the device driver.  It will
      be notified on the end of a SCSI read / write, and
      will take on of several actions based on success or failure.
-*/
* rw_intr is the interrupt routine for the device driver.  It will
* be notified on the end of a SCSI read / write, and
* will take on of several actions based on success or failure.
+ */
 
 static void rw_intr (Scsi_Cmnd *SCpnt)
 {
-  int result = SCpnt->result;
-  int this_count = SCpnt->bufflen >> 9;
-
+    int result = SCpnt->result;
+    int this_count = SCpnt->bufflen >> 9;
+    
 #ifdef DEBUG
-  printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.dev), SCpnt->host->host_no, result);
+    printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.dev), 
+          SCpnt->host->host_no, result);
 #endif
+    
+    /*
+     * First case : we assume that the command succeeded.  One of two things 
+     * will happen here.  Either we will be finished, or there will be more
+     * sectors that we were unable to read last time.
+     */
 
-/*
-  First case : we assume that the command succeeded.  One of two things will
-  happen here.  Either we will be finished, or there will be more
-  sectors that we were unable to read last time.
-*/
-
-  if (!result) {
-
+    if (!result) {
+       
 #ifdef DEBUG
-    printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.dev), SCpnt->request.nr_sectors);
-    printk("use_sg is %d\n ",SCpnt->use_sg);
+       printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.dev),
+              SCpnt->request.nr_sectors);
+       printk("use_sg is %d\n ",SCpnt->use_sg);
 #endif
-    if (SCpnt->use_sg) {
-      struct scatterlist * sgpnt;
-      int i;
-      sgpnt = (struct scatterlist *) SCpnt->buffer;
-      for(i=0; i<SCpnt->use_sg; i++) {
+       if (SCpnt->use_sg) {
+           struct scatterlist * sgpnt;
+           int i;
+           sgpnt = (struct scatterlist *) SCpnt->buffer;
+           for(i=0; i<SCpnt->use_sg; i++) {
 #ifdef DEBUG
-       printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+               printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, 
+                      sgpnt[i].length);
 #endif
-       if (sgpnt[i].alt_address) {
-         if (SCpnt->request.cmd == READ)
-           memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
-         scsi_free(sgpnt[i].address, sgpnt[i].length);
-       };
-      };
-      scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
-    } else {
-      if (SCpnt->buffer != SCpnt->request.buffer) {
+               if (sgpnt[i].alt_address) {
+                   if (SCpnt->request.cmd == READ)
+                       memcpy(sgpnt[i].alt_address, sgpnt[i].address, 
+                              sgpnt[i].length);
+                   scsi_free(sgpnt[i].address, sgpnt[i].length);
+               };
+           };
+
+           /* Free list of scatter-gather pointers */
+           scsi_free(SCpnt->buffer, SCpnt->sglist_len);  
+       } else {
+           if (SCpnt->buffer != SCpnt->request.buffer) {
 #ifdef DEBUG
-       printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
-                  SCpnt->bufflen);
-#endif 
-         if (SCpnt->request.cmd == READ)
-           memcpy(SCpnt->request.buffer, SCpnt->buffer,
-                  SCpnt->bufflen);
-         scsi_free(SCpnt->buffer, SCpnt->bufflen);
-      };
-    };
-/*
*     If multiple sectors are requested in one buffer, then
- *     they will have been finished off by the first command.  If
*     not, then we have a multi-buffer command.
- */
-    if (SCpnt->request.nr_sectors > this_count)
-      {
-       SCpnt->request.errors = 0;
-       
-       if (!SCpnt->request.bh)
-         {
+               printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+                      SCpnt->bufflen);
+#endif  
+               if (SCpnt->request.cmd == READ)
+                   memcpy(SCpnt->request.buffer, SCpnt->buffer,
+                          SCpnt->bufflen);
+               scsi_free(SCpnt->buffer, SCpnt->bufflen);
+           };
+       };
+       /*
       * If multiple sectors are requested in one buffer, then
+        * they will have been finished off by the first command.
       * If not, then we have a multi-buffer command.
       */
+       if (SCpnt->request.nr_sectors > this_count)
+       {
+           SCpnt->request.errors = 0;
+           
+           if (!SCpnt->request.bh)
+           {
 #ifdef DEBUG
-           printk("sd%c : handling page request, no buffer\n",
-                  'a' + MINOR(SCpnt->request.dev));
+               printk("sd%c : handling page request, no buffer\n",
+                      'a' + MINOR(SCpnt->request.dev));
 #endif
-/*
-  The SCpnt->request.nr_sectors field is always done in 512 byte sectors,
-  even if this really isn't the case.
-*/
-           panic("sd.c: linked page request (%lx %x)",
-                 SCpnt->request.sector, this_count);
-         }
-      }
-    SCpnt = end_scsi_request(SCpnt, 1, this_count);
-    requeue_sd_request(SCpnt);
-    return;
-  }
-
-/* Free up any indirection buffers we allocated for DMA purposes. */
+               /*
+                * The SCpnt->request.nr_sectors field is always done in 
+                * 512 byte sectors, even if this really isn't the case.
+                */
+               panic("sd.c: linked page request (%lx %x)",
+                     SCpnt->request.sector, this_count);
+           }
+       }
+       SCpnt = end_scsi_request(SCpnt, 1, this_count);
+       requeue_sd_request(SCpnt);
+       return;
+    }
+    
+    /* Free up any indirection buffers we allocated for DMA purposes. */
     if (SCpnt->use_sg) {
-      struct scatterlist * sgpnt;
-      int i;
-      sgpnt = (struct scatterlist *) SCpnt->buffer;
-      for(i=0; i<SCpnt->use_sg; i++) {
+       struct scatterlist * sgpnt;
+       int i;
+       sgpnt = (struct scatterlist *) SCpnt->buffer;
+       for(i=0; i<SCpnt->use_sg; i++) {
 #ifdef DEBUG
-       printk("err: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+           printk("err: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
                   SCpnt->bufflen);
 #endif
-       if (sgpnt[i].alt_address) {
-         scsi_free(sgpnt[i].address, sgpnt[i].length);
+           if (sgpnt[i].alt_address) {
+               scsi_free(sgpnt[i].address, sgpnt[i].length);
+           };
        };
-      };
-      scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
+       scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
     } else {
 #ifdef DEBUG
-      printk("nosgerr: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
-                  SCpnt->bufflen);
+       printk("nosgerr: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+              SCpnt->bufflen);
 #endif
-      if (SCpnt->buffer != SCpnt->request.buffer)
-       scsi_free(SCpnt->buffer, SCpnt->bufflen);
+       if (SCpnt->buffer != SCpnt->request.buffer)
+           scsi_free(SCpnt->buffer, SCpnt->bufflen);
     };
+    
+    /*
+     * Now, if we were good little boys and girls, Santa left us a request
+     * sense buffer.  We can extract information from this, so we
+     * can choose a block to remap, etc.
+     */
 
-/*
-       Now, if we were good little boys and girls, Santa left us a request
-       sense buffer.  We can extract information from this, so we
-       can choose a block to remap, etc.
-*/
-
-        if (driver_byte(result) != 0) {
-         if (suggestion(result) == SUGGEST_REMAP) {
+    if (driver_byte(result) != 0) {
+       if (suggestion(result) == SUGGEST_REMAP) {
 #ifdef REMAP
-/*
-       Not yet implemented.  A read will fail after being remapped,
-       a write will call the strategy routine again.
-*/
+           /*
+            * Not yet implemented.  A read will fail after being remapped,
+            * a write will call the strategy routine again.
+            */
            if rscsi_disks[DEVICE_NR(SCpnt->request.dev)].remap
-             {
+           {
                result = 0;
-             }
+           }
            else
-             
 #endif
-           }
-
-         if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
+       }
+       
+       if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
            if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
-             if(rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->removable) {
-             /* detected disc change.  set a bit and quietly refuse    */
-             /* further access.                                        */
-             
-               rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->changed = 1;
-               SCpnt = end_scsi_request(SCpnt, 0, this_count);
-               requeue_sd_request(SCpnt);
-               return;
-             }
+               if(rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->removable) {
+                   /* detected disc change.  set a bit and quietly refuse
+                    * further access.
+                    */  
+                   rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->changed = 1;
+                   SCpnt = end_scsi_request(SCpnt, 0, this_count);
+                   requeue_sd_request(SCpnt);
+                   return;
+               }
            }
-         }
-         
-
-/*     If we had an ILLEGAL REQUEST returned, then we may have
-performed an unsupported command.  The only thing this should be would
-be a ten byte read where only a six byte read was supported.  Also,
-on a system where READ CAPACITY failed, we have have read past the end
-of the         disk. 
-*/
+       }
+       
+       
+       /* If we had an ILLEGAL REQUEST returned, then we may have
+        * performed an unsupported command.  The only thing this should be 
+        * would be a ten byte read where only a six byte read was supported.
+        * Also, on a system where READ CAPACITY failed, we have have read 
+        * past the end of the disk. 
+        */
 
-         if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
+       if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
            if (rscsi_disks[DEVICE_NR(SCpnt->request.dev)].ten) {
-             rscsi_disks[DEVICE_NR(SCpnt->request.dev)].ten = 0;
-             requeue_sd_request(SCpnt);
-             result = 0;
+               rscsi_disks[DEVICE_NR(SCpnt->request.dev)].ten = 0;
+               requeue_sd_request(SCpnt);
+               result = 0;
            } else {
+               /* ???? */
            }
-         }
-       }  /* driver byte != 0 */
-       if (result) {
-               printk("SCSI disk error : host %d id %d lun %d return code = %x\n",
-                      rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->host->host_no,
-                      rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->id,
-                      rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->lun, result);
-
-               if (driver_byte(result) & DRIVER_SENSE)
-                       print_sense("sd", SCpnt);
-               SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
-               requeue_sd_request(SCpnt);
-               return;
        }
+    }  /* driver byte != 0 */
+    if (result) {
+       printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n",
+              rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->host->host_no,
+              rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->channel,
+          rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->id,
+            rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->lun, result);
+       
+       if (driver_byte(result) & DRIVER_SENSE)
+           print_sense("sd", SCpnt);
+       SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
+       requeue_sd_request(SCpnt);
+       return;
+    }
 }
 
 /*
      requeue_sd_request() is the request handler function for the sd driver.
      Its function in life is to take block device requests, and translate
      them to SCSI commands.
-*/
* requeue_sd_request() is the request handler function for the sd driver.
* Its function in life is to take block device requests, and translate
* them to SCSI commands.
+ */
 
 static void do_sd_request (void)
 {
-  Scsi_Cmnd * SCpnt = NULL;
-  struct request * req = NULL;
-  unsigned long flags;
-  int flag = 0;
-
-  save_flags(flags);
-  while (1==1){
-    cli();
-    if (CURRENT != NULL && CURRENT->dev == -1) {
-      restore_flags(flags);
-      return;
-    };
-
-    INIT_SCSI_REQUEST;
-
-
-/* We have to be careful here.  allocate_device will get a free pointer, but
-   there is no guarantee that it is queueable.  In normal usage, we want to
-   call this, because other types of devices may have the host all tied up,
-   and we want to make sure that we have at least one request pending for this
-   type of device.   We can also come through here while servicing an
-   interrupt, because of the need to start another command.  If we call
-   allocate_device more than once, then the system can wedge if the command
-   is not queueable.  The request_queueable function is safe because it checks
-   to make sure that the host is able to take another command before it returns
-   a pointer.  */
-
-    if (flag++ == 0)
-      SCpnt = allocate_device(&CURRENT,
-                             rscsi_disks[DEVICE_NR(MINOR(CURRENT->dev))].device, 0); 
-    else SCpnt = NULL;
-
-    /*
-     * The following restore_flags leads to latency problems.  FIXME.
-     * Using a "sti()" gets rid of the latency problems but causes
-     * race conditions and crashes.
-     */
-    restore_flags(flags);
+    Scsi_Cmnd * SCpnt = NULL;
+    struct request * req = NULL;
+    unsigned long flags;
+    int flag = 0;
+    
+    save_flags(flags);
+    while (1==1){
+       cli();
+       if (CURRENT != NULL && CURRENT->dev == -1) {
+           restore_flags(flags);
+           return;
+       };
+       
+       INIT_SCSI_REQUEST;
+               
+       /* We have to be careful here. allocate_device will get a free pointer,
+        * but there is no guarantee that it is queueable.  In normal usage, 
+        * we want to call this, because other types of devices may have the 
+        * host all tied up, and we want to make sure that we have at least 
+        * one request pending for this type of device. We can also come 
+        * through here while servicing an interrupt, because of the need to 
+        * start another command. If we call allocate_device more than once, 
+        * then the system can wedge if the command is not queueable. The 
+        * request_queueable function is safe because it checks to make sure 
+        * that the host is able to take another command before it returns
+        * a pointer.  
+        */
 
-/* This is a performance enhancement.  We dig down into the request list and
-   try and find a queueable request (i.e. device not busy, and host able to
-   accept another command.  If we find one, then we queue it. This can
-   make a big difference on systems with more than one disk drive.  We want
-   to have the interrupts off when monkeying with the request list, because
-   otherwise the kernel might try and slip in a request in between somewhere. */
+       if (flag++ == 0)
+           SCpnt = allocate_device(&CURRENT,
+                                   rscsi_disks[DEVICE_NR(MINOR(CURRENT->dev))].device, 0); 
+       else SCpnt = NULL;
+       
+       /*
+        * The following restore_flags leads to latency problems.  FIXME.
+        * Using a "sti()" gets rid of the latency problems but causes
+        * race conditions and crashes.
+        */
+       restore_flags(flags);
+
+       /* This is a performance enhancement. We dig down into the request 
+        * list and try and find a queueable request (i.e. device not busy, 
+        * and host able to accept another command. If we find one, then we 
+        * queue it. This can make a big difference on systems with more than 
+        * one disk drive.  We want to have the interrupts off when monkeying 
+        * with the request list, because otherwise the kernel might try and 
+        * slip in a request in between somewhere. 
+        */
 
-    if (!SCpnt && sd_template.nr_dev > 1){
-      struct request *req1;
-      req1 = NULL;
-      cli();
-      req = CURRENT;
-      while(req){
-       SCpnt = request_queueable(req,
-                                 rscsi_disks[DEVICE_NR(MINOR(req->dev))].device);
-       if(SCpnt) break;
-       req1 = req;
-       req = req->next;
-      };
-      if (SCpnt && req->dev == -1) {
-       if (req == CURRENT) 
-         CURRENT = CURRENT->next;
-       else
-         req1->next = req->next;
-      };
-      restore_flags(flags);
-    };
-    
-    if (!SCpnt) return; /* Could not find anything to do */
-        
-    /* Queue command */
-    requeue_sd_request(SCpnt);
-  };  /* While */
+       if (!SCpnt && sd_template.nr_dev > 1){
+           struct request *req1;
+           req1 = NULL;
+           cli();
+           req = CURRENT;
+           while(req){
+               SCpnt = request_queueable(req, rscsi_disks[DEVICE_NR(MINOR(req->dev))].device);
+               if(SCpnt) break;
+               req1 = req;
+               req = req->next;
+           };
+           if (SCpnt && req->dev == -1) {
+               if (req == CURRENT) 
+                   CURRENT = CURRENT->next;
+               else
+                   req1->next = req->next;
+           };
+           restore_flags(flags);
+       };
+       
+       if (!SCpnt) return; /* Could not find anything to do */
+       
+       /* Queue command */
+       requeue_sd_request(SCpnt);
+    };  /* While */
 }    
 
 static void requeue_sd_request (Scsi_Cmnd * SCpnt)
 {
-       int dev, block, this_count;
-       unsigned char cmd[10];
-       int bounce_size, contiguous;
-       int max_sg;
-       struct buffer_head * bh, *bhp;
-       char * buff, *bounce_buffer;
-
-repeat:
-
-       if(!SCpnt || SCpnt->request.dev <= 0) {
-         do_sd_request();
-         return;
-       }
-
-       dev =  MINOR(SCpnt->request.dev);
-       block = SCpnt->request.sector;
-       this_count = 0;
-
-#ifdef DEBUG
-       printk("Doing sd request, dev = %d, block = %d\n", dev, block);
-#endif
-
-       if (dev >= (sd_template.dev_max << 4) || 
-           !rscsi_disks[DEVICE_NR(dev)].device ||
-           block + SCpnt->request.nr_sectors > sd[dev].nr_sects)
-               {
-               SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-               goto repeat;
-               }
-
-       block += sd[dev].start_sect;
-       dev = DEVICE_NR(dev);
-
-       if (rscsi_disks[dev].device->changed)
-               {
-/*
- * quietly refuse to do anything to a changed disc until the changed bit has been reset
- */
-               /* printk("SCSI disk has been changed.  Prohibiting further I/O.\n");   */
-               SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-               goto repeat;
-               }
+    int dev, block, this_count;
+    unsigned char cmd[10];
+    int bounce_size, contiguous;
+    int max_sg;
+    struct buffer_head * bh, *bhp;
+    char * buff, *bounce_buffer;
+    
+ repeat:
+    
+    if(!SCpnt || SCpnt->request.dev <= 0) {
+       do_sd_request();
+       return;
+    }
+    
+    dev =  MINOR(SCpnt->request.dev);
+    block = SCpnt->request.sector;
+    this_count = 0;
 
 #ifdef DEBUG
-       printk("sd%c : real dev = /dev/sd%c, block = %d\n", 'a' + MINOR(SCpnt->request.dev), dev, block);
+    printk("Doing sd request, dev = %d, block = %d\n", dev, block);
 #endif
-
+    
+    if (dev >= (sd_template.dev_max << 4) || 
+       !rscsi_disks[DEVICE_NR(dev)].device ||
+       block + SCpnt->request.nr_sectors > sd[dev].nr_sects)
+    {
+       SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+       goto repeat;
+    }
+    
+    block += sd[dev].start_sect;
+    dev = DEVICE_NR(dev);
+    
+    if (rscsi_disks[dev].device->changed)
+    {
        /*
-        * If we have a 1K hardware sectorsize, prevent access to single
-        * 512 byte sectors.  In theory we could handle this - in fact
-        * the scsi cdrom driver must be able to handle this because
-        * we typically use 1K blocksizes, and cdroms typically have
-        * 2K hardware sectorsizes.  Of course, things are simpler
-        * with the cdrom, since it is read-only.  For performance
-        * reasons, the filesystems should be able to handle this
-        * and not force the scsi disk driver to use bounce buffers
-        * for this.
+        * quietly refuse to do anything to a changed disc until the changed 
+        * bit has been reset
         */
-       if (rscsi_disks[dev].sector_size == 1024)
-         if((block & 1) || (SCpnt->request.nr_sectors & 1)) {
-               printk("sd.c:Bad block number requested");
-               SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-               goto repeat;
+       /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
+       SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+       goto repeat;
+    }
+    
+#ifdef DEBUG
+    printk("sd%c : real dev = /dev/sd%c, block = %d\n", 
+          'a' + MINOR(SCpnt->request.dev), dev, block);
+#endif
+    
+    /*
+     * If we have a 1K hardware sectorsize, prevent access to single
+     * 512 byte sectors.  In theory we could handle this - in fact
+     * the scsi cdrom driver must be able to handle this because
+     * we typically use 1K blocksizes, and cdroms typically have
+     * 2K hardware sectorsizes.  Of course, things are simpler
+     * with the cdrom, since it is read-only.  For performance
+     * reasons, the filesystems should be able to handle this
+     * and not force the scsi disk driver to use bounce buffers
+     * for this.
+     */
+    if (rscsi_disks[dev].sector_size == 1024)
+       if((block & 1) || (SCpnt->request.nr_sectors & 1)) {
+           printk("sd.c:Bad block number requested");
+           SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+           goto repeat;
        }
-       
-       switch (SCpnt->request.cmd)
-               {
-               case WRITE :
-                       if (!rscsi_disks[dev].device->writeable)
-                               {
-                               SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-                               goto repeat;
-                               }
-                       cmd[0] = WRITE_6;
-                       break;
-               case READ :
-                       cmd[0] = READ_6;
-                       break;
-               default :
-                       panic ("Unknown sd command %d\n", SCpnt->request.cmd);
-                     }
-
-       SCpnt->this_count = 0;
-
-       /* If the host adapter can deal with very large scatter-gather
-          requests, it is a waste of time to cluster */
-       contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 :1);
-       bounce_buffer = NULL;
-       bounce_size = (SCpnt->request.nr_sectors << 9);
-
-       /* First see if we need a bounce buffer for this request.  If we do, make sure
-          that we can allocate a buffer.  Do not waste space by allocating a bounce
-          buffer if we are straddling the 16Mb line */
-
-       
-       if (contiguous && SCpnt->request.bh &&
-           ((long) SCpnt->request.bh->b_data) + (SCpnt->request.nr_sectors << 9) - 1 > 
-           ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) {
-         if(((long) SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
+    
+    switch (SCpnt->request.cmd)
+    {
+    case WRITE :
+       if (!rscsi_disks[dev].device->writeable)
+       {
+           SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+           goto repeat;
+       }
+       cmd[0] = WRITE_6;
+       break;
+    case READ :
+       cmd[0] = READ_6;
+       break;
+    default :
+       panic ("Unknown sd command %d\n", SCpnt->request.cmd);
+    }
+    
+    SCpnt->this_count = 0;
+    
+    /* If the host adapter can deal with very large scatter-gather
+     * requests, it is a waste of time to cluster 
+     */
+    contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 :1);
+    bounce_buffer = NULL;
+    bounce_size = (SCpnt->request.nr_sectors << 9);
+    
+    /* First see if we need a bounce buffer for this request. If we do, make 
+     * sure that we can allocate a buffer. Do not waste space by allocating 
+     * a bounce buffer if we are straddling the 16Mb line 
+     */ 
+    if (contiguous && SCpnt->request.bh &&
+       ((long) SCpnt->request.bh->b_data) 
+       + (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD 
+       && SCpnt->host->unchecked_isa_dma) {
+       if(((long) SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
            bounce_buffer = (char *) scsi_malloc(bounce_size);
-         if(!bounce_buffer) contiguous = 0;
-       };
-
-       if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
-         for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp, 
-             bhp = bhp->b_reqnext) {
+       if(!bounce_buffer) contiguous = 0;
+    };
+    
+    if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
+       for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp, 
+           bhp = bhp->b_reqnext) {
            if(!CONTIGUOUS_BUFFERS(bh,bhp)) { 
-             if(bounce_buffer) scsi_free(bounce_buffer, bounce_size);
-             contiguous = 0;
-             break;
+               if(bounce_buffer) scsi_free(bounce_buffer, bounce_size);
+               contiguous = 0;
+               break;
            } 
-         };
-       if (!SCpnt->request.bh || contiguous) {
-
-         /* case of page request (i.e. raw device), or unlinked buffer */
-         this_count = SCpnt->request.nr_sectors;
-         buff = SCpnt->request.buffer;
-         SCpnt->use_sg = 0;
-
-       } else if (SCpnt->host->sg_tablesize == 0 ||
-                  (need_isa_buffer && 
-                   dma_free_sectors <= 10)) {
-
-         /* Case of host adapter that cannot scatter-gather.  We also
-          come here if we are running low on DMA buffer memory.  We set
-          a threshold higher than that we would need for this request so
-          we leave room for other requests.  Even though we would not need
-          it all, we need to be conservative, because if we run low enough
-          we have no choice but to panic. */
-
-         if (SCpnt->host->sg_tablesize != 0 &&
-             need_isa_buffer && 
-             dma_free_sectors <= 10)
+       };
+    if (!SCpnt->request.bh || contiguous) {
+       
+       /* case of page request (i.e. raw device), or unlinked buffer */
+       this_count = SCpnt->request.nr_sectors;
+       buff = SCpnt->request.buffer;
+       SCpnt->use_sg = 0;
+       
+    } else if (SCpnt->host->sg_tablesize == 0 ||
+              (need_isa_buffer && dma_free_sectors <= 10)) {
+       
+       /* Case of host adapter that cannot scatter-gather.  We also
+        * come here if we are running low on DMA buffer memory.  We set
+        * a threshold higher than that we would need for this request so
+        * we leave room for other requests.  Even though we would not need
+        * it all, we need to be conservative, because if we run low enough
+        * we have no choice but to panic. 
+        */
+       if (SCpnt->host->sg_tablesize != 0 &&
+           need_isa_buffer && 
+           dma_free_sectors <= 10)
            printk("Warning: SCSI DMA buffer space running low.  Using non scatter-gather I/O.\n");
-
-         this_count = SCpnt->request.current_nr_sectors;
-         buff = SCpnt->request.buffer;
-         SCpnt->use_sg = 0;
-
-       } else {
-
-         /* Scatter-gather capable host adapter */
-         struct scatterlist * sgpnt;
-         int count, this_count_max;
-         int counted;
-
-         bh = SCpnt->request.bh;
-         this_count = 0;
-         this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff);
-         count = 0;
-         bhp = NULL;
-         while(bh) {
+       
+       this_count = SCpnt->request.current_nr_sectors;
+       buff = SCpnt->request.buffer;
+       SCpnt->use_sg = 0;
+       
+    } else {
+       
+       /* Scatter-gather capable host adapter */
+       struct scatterlist * sgpnt;
+       int count, this_count_max;
+       int counted;
+       
+       bh = SCpnt->request.bh;
+       this_count = 0;
+       this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff);
+       count = 0;
+       bhp = NULL;
+       while(bh) {
            if ((this_count + (bh->b_size >> 9)) > this_count_max) break;
            if(!bhp || !CONTIGUOUS_BUFFERS(bhp,bh) ||
               !CLUSTERABLE_DEVICE(SCpnt) ||
               (SCpnt->host->unchecked_isa_dma &&
-              ((unsigned long) bh->b_data-1) == ISA_DMA_THRESHOLD)) {
-             if (count < SCpnt->host->sg_tablesize) count++;
-             else break;
+               ((unsigned long) bh->b_data-1) == ISA_DMA_THRESHOLD)) {
+               if (count < SCpnt->host->sg_tablesize) count++;
+               else break;
            };
            this_count += (bh->b_size >> 9);
            bhp = bh;
            bh = bh->b_reqnext;
-         };
+       };
 #if 0
-         if(SCpnt->host->unchecked_isa_dma &&
-            ((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--;
+       if(SCpnt->host->unchecked_isa_dma &&
+          ((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--;
 #endif
-         SCpnt->use_sg = count;  /* Number of chains */
-         count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes*/
-         while( count < (SCpnt->use_sg * sizeof(struct scatterlist))) 
+       SCpnt->use_sg = count;  /* Number of chains */
+       count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes */
+       while( count < (SCpnt->use_sg * sizeof(struct scatterlist))) 
            count = count << 1;
-         SCpnt->sglist_len = count;
-         max_sg = count / sizeof(struct scatterlist);
-         if(SCpnt->host->sg_tablesize < max_sg) max_sg = SCpnt->host->sg_tablesize;
-         sgpnt = (struct scatterlist * ) scsi_malloc(count);
-         memset(sgpnt, 0, count);  /* Zero so it is easy to fill */
-         if (!sgpnt) {
+       SCpnt->sglist_len = count;
+       max_sg = count / sizeof(struct scatterlist);
+       if(SCpnt->host->sg_tablesize < max_sg) 
+           max_sg = SCpnt->host->sg_tablesize;
+       sgpnt = (struct scatterlist * ) scsi_malloc(count);
+       if (!sgpnt) {
            printk("Warning - running *really* short on DMA buffers\n");
-           SCpnt->use_sg = 0;  /* No memory left - bail out */
+           SCpnt->use_sg = 0;    /* No memory left - bail out */
            this_count = SCpnt->request.current_nr_sectors;
            buff = SCpnt->request.buffer;
-         } else {
+       } else {
+           memset(sgpnt, 0, count);  /* Zero so it is easy to fill, but only
+                                      * if memory is available 
+                                      */
            buff = (char *) sgpnt;
            counted = 0;
            for(count = 0, bh = SCpnt->request.bh, bhp = bh->b_reqnext;
                count < SCpnt->use_sg && bh; 
                count++, bh = bhp) {
-
-             bhp = bh->b_reqnext;
-
-             if(!sgpnt[count].address) sgpnt[count].address = bh->b_data;
-             sgpnt[count].length += bh->b_size;
-             counted += bh->b_size >> 9;
-
-             if (((long) sgpnt[count].address) + sgpnt[count].length - 1 > 
-                 ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
-                 !sgpnt[count].alt_address) {
-               sgpnt[count].alt_address = sgpnt[count].address;
-               /* We try and avoid exhausting the DMA pool, since it is easier
-                  to control usage here.  In other places we might have a more
-                  pressing need, and we would be screwed if we ran out */
-               if(dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
-                 sgpnt[count].address = NULL;
-               } else {
-                 sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
-               };
-/* If we start running low on DMA buffers, we abort the scatter-gather
-   operation, and free all of the memory we have allocated.  We want to
-   ensure that all scsi operations are able to do at least a non-scatter/gather
-   operation */
-               if(sgpnt[count].address == NULL){ /* Out of dma memory */
+               
+               bhp = bh->b_reqnext;
+               
+               if(!sgpnt[count].address) sgpnt[count].address = bh->b_data;
+               sgpnt[count].length += bh->b_size;
+               counted += bh->b_size >> 9;
+               
+               if (((long) sgpnt[count].address) + sgpnt[count].length - 1 > 
+                   ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
+                   !sgpnt[count].alt_address) {
+                   sgpnt[count].alt_address = sgpnt[count].address;
+                   /* We try and avoid exhausting the DMA pool, since it is 
+                    * easier to control usage here. In other places we might 
+                    * have a more pressing need, and we would be screwed if 
+                    * we ran out */
+                   if(dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
+                       sgpnt[count].address = NULL;
+                   } else {
+                       sgpnt[count].address = 
+                           (char *) scsi_malloc(sgpnt[count].length);
+                   };
+                   /* If we start running low on DMA buffers, we abort the 
+                    * scatter-gather operation, and free all of the memory 
+                    * we have allocated.  We want to ensure that all scsi 
+                    * operations are able to do at least a non-scatter/gather
+                    * operation */
+                   if(sgpnt[count].address == NULL){ /* Out of dma memory */
 #if 0
-                 printk("Warning: Running low on SCSI DMA buffers");
-                 /* Try switching back to a non scatter-gather operation. */
-                 while(--count >= 0){
-                   if(sgpnt[count].alt_address) 
-                     scsi_free(sgpnt[count].address, sgpnt[count].length);
-                 };
-                 this_count = SCpnt->request.current_nr_sectors;
-                 buff = SCpnt->request.buffer;
-                 SCpnt->use_sg = 0;
-                 scsi_free(sgpnt, SCpnt->sglist_len);
+                       printk("Warning: Running low on SCSI DMA buffers");
+                       /* Try switching back to a non s-g operation. */
+                       while(--count >= 0){
+                           if(sgpnt[count].alt_address) 
+                               scsi_free(sgpnt[count].address, 
+                                         sgpnt[count].length);
+                       };
+                       this_count = SCpnt->request.current_nr_sectors;
+                       buff = SCpnt->request.buffer;
+                       SCpnt->use_sg = 0;
+                       scsi_free(sgpnt, SCpnt->sglist_len);
 #endif
-                 SCpnt->use_sg = count;
-                 this_count = counted -= bh->b_size >> 9;
-                 break;
-               };
-
-             };
-
-             /* Only cluster buffers if we know that we can supply DMA buffers
-                large enough to satisfy the request.  Do not cluster a new
-                request if this would mean that we suddenly need to start
-                using DMA bounce buffers */
-             if(bhp && CONTIGUOUS_BUFFERS(bh,bhp) && CLUSTERABLE_DEVICE(SCpnt)) {
-               char * tmp;
-
-               if (((long) sgpnt[count].address) + sgpnt[count].length +
-                   bhp->b_size - 1 > ISA_DMA_THRESHOLD && 
-                   (SCpnt->host->unchecked_isa_dma) &&
-                   !sgpnt[count].alt_address) continue;
-
-               if(!sgpnt[count].alt_address) {count--; continue; }
-               if(dma_free_sectors > 10)
-                 tmp = (char *) scsi_malloc(sgpnt[count].length + bhp->b_size);
-               else {
-                 tmp = NULL;
-                 max_sg = SCpnt->use_sg;
-               };
-               if(tmp){
-                 scsi_free(sgpnt[count].address, sgpnt[count].length);
-                 sgpnt[count].address = tmp;
-                 count--;
-                 continue;
+                       SCpnt->use_sg = count;
+                       this_count = counted -= bh->b_size >> 9;
+                       break;
+                   };
+                   
                };
-
-               /* If we are allowed another sg chain, then increment counter so we
-                  can insert it.  Otherwise we will end up truncating */
-
-               if (SCpnt->use_sg < max_sg) SCpnt->use_sg++;
-             };  /* contiguous buffers */
+               
+               /* Only cluster buffers if we know that we can supply DMA 
+                * buffers large enough to satisfy the request. Do not cluster
+                * a new request if this would mean that we suddenly need to 
+                * start using DMA bounce buffers */
+               if(bhp && CONTIGUOUS_BUFFERS(bh,bhp) 
+                  && CLUSTERABLE_DEVICE(SCpnt)) {
+                   char * tmp;
+                   
+                   if (((long) sgpnt[count].address) + sgpnt[count].length +
+                       bhp->b_size - 1 > ISA_DMA_THRESHOLD && 
+                       (SCpnt->host->unchecked_isa_dma) &&
+                       !sgpnt[count].alt_address) continue;
+                   
+                   if(!sgpnt[count].alt_address) {count--; continue; }
+                   if(dma_free_sectors > 10)
+                       tmp = (char *) scsi_malloc(sgpnt[count].length 
+                                                  + bhp->b_size);
+                   else {
+                       tmp = NULL;
+                       max_sg = SCpnt->use_sg;
+                   };
+                   if(tmp){
+                       scsi_free(sgpnt[count].address, sgpnt[count].length);
+                       sgpnt[count].address = tmp;
+                       count--;
+                       continue;
+                   };
+                   
+                   /* If we are allowed another sg chain, then increment 
+                    * counter so we can insert it.  Otherwise we will end 
+                    up truncating */
+                   
+                   if (SCpnt->use_sg < max_sg) SCpnt->use_sg++;
+               };  /* contiguous buffers */
            }; /* for loop */
-
-           this_count = counted; /* This is actually how many we are going to transfer */
-
-           if(count < SCpnt->use_sg || SCpnt->use_sg > SCpnt->host->sg_tablesize){
-             bh = SCpnt->request.bh;
-             printk("Use sg, count %d %x %d\n", SCpnt->use_sg, count, dma_free_sectors);
-             printk("maxsg = %x, counted = %d this_count = %d\n", max_sg, counted, this_count);
-             while(bh){
-               printk("[%p %lx] ", bh->b_data, bh->b_size);
-               bh = bh->b_reqnext;
-             };
-             if(SCpnt->use_sg < 16)
-               for(count=0; count<SCpnt->use_sg; count++)
-                 printk("{%d:%p %p %d}  ", count,
-                        sgpnt[count].address,
-                        sgpnt[count].alt_address,
-                        sgpnt[count].length);
-             panic("Ooops");
+           
+           /* This is actually how many we are going to transfer */
+           this_count = counted; 
+           
+           if(count < SCpnt->use_sg || SCpnt->use_sg 
+              > SCpnt->host->sg_tablesize){
+               bh = SCpnt->request.bh;
+               printk("Use sg, count %d %x %d\n", 
+                      SCpnt->use_sg, count, dma_free_sectors);
+               printk("maxsg = %x, counted = %d this_count = %d\n", 
+                      max_sg, counted, this_count);
+               while(bh){
+                   printk("[%p %lx] ", bh->b_data, bh->b_size);
+                   bh = bh->b_reqnext;
+               };
+               if(SCpnt->use_sg < 16)
+                   for(count=0; count<SCpnt->use_sg; count++)
+                       printk("{%d:%p %p %d}  ", count,
+                              sgpnt[count].address,
+                              sgpnt[count].alt_address,
+                              sgpnt[count].length);
+               panic("Ooops");
            };
-
+           
            if (SCpnt->request.cmd == WRITE)
-             for(count=0; count<SCpnt->use_sg; count++)
-               if(sgpnt[count].alt_address)
-                 memcpy(sgpnt[count].address, sgpnt[count].alt_address, 
-                        sgpnt[count].length);
-         };  /* Able to malloc sgpnt */
-       };  /* Host adapter capable of scatter-gather */
-
-/* Now handle the possibility of DMA to addresses > 16Mb */
-
-       if(SCpnt->use_sg == 0){
-         if (((long) buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && 
+               for(count=0; count<SCpnt->use_sg; count++)
+                   if(sgpnt[count].alt_address)
+                       memcpy(sgpnt[count].address, sgpnt[count].alt_address, 
+                              sgpnt[count].length);
+       };  /* Able to malloc sgpnt */
+    };  /* Host adapter capable of scatter-gather */
+    
+    /* Now handle the possibility of DMA to addresses > 16Mb */
+    
+    if(SCpnt->use_sg == 0){
+       if (((long) buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && 
            (SCpnt->host->unchecked_isa_dma)) {
            if(bounce_buffer)
-             buff = bounce_buffer;
+               buff = bounce_buffer;
            else
-             buff = (char *) scsi_malloc(this_count << 9);
+               buff = (char *) scsi_malloc(this_count << 9);
            if(buff == NULL) {  /* Try backing off a bit if we are low on mem*/
-             this_count = SCpnt->request.current_nr_sectors;
-             buff = (char *) scsi_malloc(this_count << 9);
-             if(!buff) panic("Ran out of DMA buffers.");
+               this_count = SCpnt->request.current_nr_sectors;
+               buff = (char *) scsi_malloc(this_count << 9);
+               if(!buff) panic("Ran out of DMA buffers.");
            };
            if (SCpnt->request.cmd == WRITE)
-             memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
-         };
+               memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
        };
+    };
 #ifdef DEBUG
-       printk("sd%c : %s %d/%d 512 byte blocks.\n", 'a' + MINOR(SCpnt->request.dev),
-               (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
-               this_count, SCpnt->request.nr_sectors);
+    printk("sd%c : %s %d/%d 512 byte blocks.\n", 
+          'a' + MINOR(SCpnt->request.dev),
+          (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+          this_count, SCpnt->request.nr_sectors);
 #endif
-
-       cmd[1] = (SCpnt->lun << 5) & 0xe0;
-
-       if (rscsi_disks[dev].sector_size == 1024){
-         if(block & 1) panic("sd.c:Bad block number requested");
-         if(this_count & 1) panic("sd.c:Bad block number requested");
-         block = block >> 1;
-         this_count = this_count >> 1;
-       };
-
-       if (rscsi_disks[dev].sector_size == 256){
-         block = block << 1;
-         this_count = this_count << 1;
-       };
-
-       if (((this_count > 0xff) ||  (block > 0x1fffff)) && rscsi_disks[dev].ten)
-               {
-               if (this_count > 0xffff)
-                       this_count = 0xffff;
-
-               cmd[0] += READ_10 - READ_6 ;
-               cmd[2] = (unsigned char) (block >> 24) & 0xff;
-               cmd[3] = (unsigned char) (block >> 16) & 0xff;
-               cmd[4] = (unsigned char) (block >> 8) & 0xff;
-               cmd[5] = (unsigned char) block & 0xff;
-               cmd[6] = cmd[9] = 0;
-               cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
-               cmd[8] = (unsigned char) this_count & 0xff;
-               }
-       else
-               {
-               if (this_count > 0xff)
-                       this_count = 0xff;
-
-               cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
-               cmd[2] = (unsigned char) ((block >> 8) & 0xff);
-               cmd[3] = (unsigned char) block & 0xff;
-               cmd[4] = (unsigned char) this_count;
-               cmd[5] = 0;
-               }
-
-/*
- * We shouldn't disconnect in the middle of a sector, so with a dumb 
- * host adapter, it's safe to assume that we can at least transfer 
- * this many bytes between each connect / disconnect.  
- */
-
-        SCpnt->transfersize = rscsi_disks[dev].sector_size;
-        SCpnt->underflow = this_count << 9; 
-       scsi_do_cmd (SCpnt, (void *) cmd, buff, 
-                    this_count * rscsi_disks[dev].sector_size,
-                    rw_intr, 
-                    (SCpnt->device->type == TYPE_DISK ? 
-                                    SD_TIMEOUT : SD_MOD_TIMEOUT),
-                    MAX_RETRIES);
+    
+    cmd[1] = (SCpnt->lun << 5) & 0xe0;
+    
+    if (rscsi_disks[dev].sector_size == 1024){
+       if(block & 1) panic("sd.c:Bad block number requested");
+       if(this_count & 1) panic("sd.c:Bad block number requested");
+       block = block >> 1;
+       this_count = this_count >> 1;
+    };
+    
+    if (rscsi_disks[dev].sector_size == 256){
+       block = block << 1;
+       this_count = this_count << 1;
+    };
+    
+    if (((this_count > 0xff) ||  (block > 0x1fffff)) && rscsi_disks[dev].ten)
+    {
+       if (this_count > 0xffff)
+           this_count = 0xffff;
+       
+       cmd[0] += READ_10 - READ_6 ;
+       cmd[2] = (unsigned char) (block >> 24) & 0xff;
+       cmd[3] = (unsigned char) (block >> 16) & 0xff;
+       cmd[4] = (unsigned char) (block >> 8) & 0xff;
+       cmd[5] = (unsigned char) block & 0xff;
+       cmd[6] = cmd[9] = 0;
+       cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
+       cmd[8] = (unsigned char) this_count & 0xff;
+    }
+    else
+    {
+       if (this_count > 0xff)
+           this_count = 0xff;
+       
+       cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+       cmd[2] = (unsigned char) ((block >> 8) & 0xff);
+       cmd[3] = (unsigned char) block & 0xff;
+       cmd[4] = (unsigned char) this_count;
+       cmd[5] = 0;
+    }
+    
+    /*
    * We shouldn't disconnect in the middle of a sector, so with a dumb 
    * host adapter, it's safe to assume that we can at least transfer 
    * this many bytes between each connect / disconnect.  
    */
+    
+    SCpnt->transfersize = rscsi_disks[dev].sector_size;
+    SCpnt->underflow = this_count << 9; 
+    scsi_do_cmd (SCpnt, (void *) cmd, buff, 
+                this_count * rscsi_disks[dev].sector_size,
+                rw_intr, 
+                (SCpnt->device->type == TYPE_DISK ? 
+                 SD_TIMEOUT : SD_MOD_TIMEOUT),
+                MAX_RETRIES);
 }
 
 static int check_scsidisk_media_change(dev_t full_dev){
-        int retval;
-       int target;
-       struct inode inode;
-       int flag = 0;
-
-       target =  DEVICE_NR(MINOR(full_dev));
-
-       if (target >= sd_template.dev_max ||
-           !rscsi_disks[target].device) {
-               printk("SCSI disk request error: invalid device.\n");
-               return 0;
-       };
-
-       if(!rscsi_disks[target].device->removable) return 0;
-
-       inode.i_rdev = full_dev;  /* This is all we really need here */
-       retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
-
-       if(retval){ /* Unable to test, unit probably not ready.  This usually
-                    means there is no disc in the drive.  Mark as changed,
-                    and we will figure it out later once the drive is
-                    available again.  */
-
-         rscsi_disks[target].device->changed = 1;
-         return 1; /* This will force a flush, if called from
-                      check_disk_change */
-       };
-
-       retval = rscsi_disks[target].device->changed;
-       if(!flag) rscsi_disks[target].device->changed = 0;
-       return retval;
+    int retval;
+    int target;
+    struct inode inode;
+    int flag = 0;
+    
+    target =  DEVICE_NR(MINOR(full_dev));
+    
+    if (target >= sd_template.dev_max ||
+       !rscsi_disks[target].device) {
+       printk("SCSI disk request error: invalid device.\n");
+       return 0;
+    };
+    
+    if(!rscsi_disks[target].device->removable) return 0;
+    
+    inode.i_rdev = full_dev;  /* This is all we really need here */
+    retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
+    
+    if(retval){ /* Unable to test, unit probably not ready.  This usually
+                * means there is no disc in the drive.  Mark as changed,
+                * and we will figure it out later once the drive is
+                * available again.  */
+       
+       rscsi_disks[target].device->changed = 1;
+       return 1; /* This will force a flush, if called from
+                  * check_disk_change */
+    };
+    
+    retval = rscsi_disks[target].device->changed;
+    if(!flag) rscsi_disks[target].device->changed = 0;
+    return retval;
 }
 
 static void sd_init_done (Scsi_Cmnd * SCpnt)
 {
-  struct request * req;
-  
-  req = &SCpnt->request;
-  req->dev = 0xfffe; /* Busy, but indicate request done */
-  
-  if (req->sem != NULL) {
-    up(req->sem);
-  }
+    struct request * req;
+    
+    req = &SCpnt->request;
+    req->dev = 0xfffe; /* Busy, but indicate request done */
+    
+    if (req->sem != NULL) {
+       up(req->sem);
+    }
 }
 
 static int sd_init_onedisk(int i)
 {
-  unsigned char cmd[10];
-  unsigned char *buffer;
-  unsigned long spintime;
-  int the_result, retries;
-  Scsi_Cmnd * SCpnt;
-
-  /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is considered
-     a fatal error, and many devices report such an error just after a scsi
-     bus reset. */
-
-  SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1);
-  buffer = (unsigned char *) scsi_malloc(512);
-
-  spintime = 0;
-
-  /* Spin up drives, as required.  Only do this at boot time */
-  if (current == task[0]){
-    do{
-      cmd[0] = TEST_UNIT_READY;
-      cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
-      memset ((void *) &cmd[2], 0, 8);
-      SCpnt->request.dev = 0xffff;  /* Mark as really busy again */
-      SCpnt->cmd_len = 0;
-      SCpnt->sense_buffer[0] = 0;
-      SCpnt->sense_buffer[2] = 0;
-      
-      scsi_do_cmd (SCpnt,
-                  (void *) cmd, (void *) buffer,
-                  512, sd_init_done,  SD_TIMEOUT,
-                  MAX_RETRIES);
-      
-      while(SCpnt->request.dev != 0xfffe) barrier();
-      
-      the_result = SCpnt->result;
-      
-      /* Look for non-removable devices that return NOT_READY.  Issue command
-        to spin up drive for these cases. */
-      if(the_result && !rscsi_disks[i].device->removable && 
-        SCpnt->sense_buffer[2] == NOT_READY) {
-       int time1;
-       if(!spintime){
-         printk( "sd%c: Spinning up disk...", 'a' + i );
-         cmd[0] = START_STOP;
-         cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
-         cmd[1] |= 1;  /* Return immediately */
-         memset ((void *) &cmd[2], 0, 8);
-         cmd[4] = 1; /* Start spin cycle */
-         SCpnt->request.dev = 0xffff;  /* Mark as really busy again */
-         SCpnt->cmd_len = 0;
-         SCpnt->sense_buffer[0] = 0;
-         SCpnt->sense_buffer[2] = 0;
-         
-         scsi_do_cmd (SCpnt,
-                      (void *) cmd, (void *) buffer,
-                      512, sd_init_done,  SD_TIMEOUT,
-                      MAX_RETRIES);
-         
-         while(SCpnt->request.dev != 0xfffe) barrier();
-
-         spintime = jiffies;
-       };
-
-       time1 = jiffies;
-       while(jiffies < time1 + HZ); /* Wait 1 second for next try */
-       printk( "." );
-      };
-    } while(the_result && spintime && spintime+100*HZ > jiffies);
-    if (spintime) {
-       if (the_result)
-           printk( "not responding...\n" );
-       else
-           printk( "ready\n" );
-    }
-  };  /* current == task[0] */
-
-
-  retries = 3;
-  do {
-    cmd[0] = READ_CAPACITY;
-    cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
-    memset ((void *) &cmd[2], 0, 8);
-    memset ((void *) buffer, 0, 8);
-    SCpnt->request.dev = 0xffff;  /* Mark as really busy again */
-    SCpnt->cmd_len = 0;
-    SCpnt->sense_buffer[0] = 0;
-    SCpnt->sense_buffer[2] = 0;
-    
-    scsi_do_cmd (SCpnt,
-                (void *) cmd, (void *) buffer,
-                8, sd_init_done,  SD_TIMEOUT,
-                MAX_RETRIES);
+    unsigned char cmd[10];
+    unsigned char *buffer;
+    unsigned long spintime;
+    int the_result, retries;
+    Scsi_Cmnd * SCpnt;
     
-    if (current == task[0])
-      while(SCpnt->request.dev != 0xfffe) barrier();
-    else
-      if (SCpnt->request.dev != 0xfffe){
-       struct semaphore sem = MUTEX_LOCKED;
-       SCpnt->request.sem = &sem;
-       down(&sem);
-       /* Hmm.. Have to ask about this one.. */
-       while (SCpnt->request.dev != 0xfffe) schedule();
-      };
-    
-    the_result = SCpnt->result;
-    retries--;
-
-  } while(the_result && retries);
-
-  SCpnt->request.dev = -1;  /* Mark as not busy */
-
-  wake_up(&SCpnt->device->device_wait); 
-
-  /* Wake up a process waiting for device*/
-
-  /*
-   *   The SCSI standard says "READ CAPACITY is necessary for self configuring software"
-   *   While not mandatory, support of READ CAPACITY is strongly encouraged.
-   *   We used to die if we couldn't successfully do a READ CAPACITY.
-   *   But, now we go on about our way.  The side effects of this are
-   *
-   *   1.  We can't know block size with certainty.  I have said "512 bytes is it"
-   *           as this is most common.
-   *
-   *   2.  Recovery from when some one attempts to read past the end of the raw device will
-   *       be slower.
-   */
-
-  if (the_result)
+    /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is 
+     * considered a fatal error, and many devices report such an error 
+     * just after a scsi bus reset. */
+    
+    SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1);
+    buffer = (unsigned char *) scsi_malloc(512);
+    
+    spintime = 0;
+    
+    /* Spin up drives, as required.  Only do this at boot time */
+    if (current->pid == 0){
+       do{
+           retries = 0;
+           while(retries < 3)
+           {
+               cmd[0] = TEST_UNIT_READY;
+               cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+               memset ((void *) &cmd[2], 0, 8);
+               SCpnt->request.dev = 0xffff;  /* Mark as really busy again */
+               SCpnt->cmd_len = 0;
+               SCpnt->sense_buffer[0] = 0;
+               SCpnt->sense_buffer[2] = 0;
+               
+               scsi_do_cmd (SCpnt,
+                            (void *) cmd, (void *) buffer,
+                            512, sd_init_done,  SD_TIMEOUT,
+                            MAX_RETRIES);
+               
+               while(SCpnt->request.dev != 0xfffe) barrier();
+               
+               the_result = SCpnt->result;
+               retries++;
+               if(   the_result == 0
+                  || SCpnt->sense_buffer[2] != UNIT_ATTENTION)
+                   break;
+           }
+           
+           /* Look for non-removable devices that return NOT_READY.  
+            * Issue command to spin up drive for these cases. */
+           if(the_result && !rscsi_disks[i].device->removable && 
+              SCpnt->sense_buffer[2] == NOT_READY) {
+               int time1;
+               if(!spintime){
+                   printk( "sd%c: Spinning up disk...", 'a' + i );
+                   cmd[0] = START_STOP;
+                   cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+                   cmd[1] |= 1;  /* Return immediately */
+                   memset ((void *) &cmd[2], 0, 8);
+                   cmd[4] = 1; /* Start spin cycle */
+                   /* Mark as really busy again */
+                   SCpnt->request.dev = 0xffff; 
+                   SCpnt->cmd_len = 0;
+                   SCpnt->sense_buffer[0] = 0;
+                   SCpnt->sense_buffer[2] = 0;
+                   
+                   scsi_do_cmd (SCpnt,
+                                (void *) cmd, (void *) buffer,
+                                512, sd_init_done,  SD_TIMEOUT,
+                                MAX_RETRIES);
+                   
+                   while(SCpnt->request.dev != 0xfffe)
+           barrier();
+                   
+                   spintime = jiffies;
+               };
+               
+               time1 = jiffies;
+               while(jiffies < time1 + HZ); /* Wait 1 second for next try */
+               printk( "." );
+           };
+       } while(the_result && spintime && spintime+100*HZ > jiffies);
+       if (spintime) {
+           if (the_result)
+               printk( "not responding...\n" );
+           else
+               printk( "ready\n" );
+       }
+    };  /* current->pid == 0 */
+    
+    
+    retries = 3;
+    do {
+       cmd[0] = READ_CAPACITY;
+       cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+       memset ((void *) &cmd[2], 0, 8);
+       memset ((void *) buffer, 0, 8);
+       SCpnt->request.dev = 0xffff;  /* Mark as really busy again */
+       SCpnt->cmd_len = 0;
+       SCpnt->sense_buffer[0] = 0;
+       SCpnt->sense_buffer[2] = 0;
+       
+       scsi_do_cmd (SCpnt,
+                    (void *) cmd, (void *) buffer,
+                    8, sd_init_done,  SD_TIMEOUT,
+                    MAX_RETRIES);
+       
+       if (current->pid == 0)
+           while(SCpnt->request.dev != 0xfffe)
+       barrier();
+       else
+           if (SCpnt->request.dev != 0xfffe){
+               struct semaphore sem = MUTEX_LOCKED;
+               SCpnt->request.sem = &sem;
+               down(&sem);
+               /* Hmm.. Have to ask about this one.. */
+               while (SCpnt->request.dev != 0xfffe) 
+           schedule();
+           };
+       
+       the_result = SCpnt->result;
+       retries--;
+       
+    } while(the_result && retries);
+    
+    SCpnt->request.dev = -1;  /* Mark as not busy */
+    
+    wake_up(&SCpnt->device->device_wait); 
+    
+    /* Wake up a process waiting for device */
+    
+    /*
+     * The SCSI standard says: 
+     * "READ CAPACITY is necessary for self configuring software"
+     *  While not mandatory, support of READ CAPACITY is strongly encouraged.
+     *  We used to die if we couldn't successfully do a READ CAPACITY.
+     *  But, now we go on about our way.  The side effects of this are
+     *
+     *  1. We can't know block size with certainty. I have said "512 bytes 
+     *     is it" as this is most common.
+     *
+     *  2. Recovery from when some one attempts to read past the end of the 
+     *     raw device will be slower.
+     */
+    
+    if (the_result)
     {
-      printk ("sd%c : READ CAPACITY failed.\n"
-             "sd%c : status = %x, message = %02x, host = %d, driver = %02x \n",
-             'a' + i, 'a' + i,
-             status_byte(the_result),
-             msg_byte(the_result),
-             host_byte(the_result),
-             driver_byte(the_result)
-             );
-      if (driver_byte(the_result)  & DRIVER_SENSE)
-       printk("sd%c : extended sense code = %1x \n", 'a' + i, SCpnt->sense_buffer[2] & 0xf);
-      else
-       printk("sd%c : sense not available. \n", 'a' + i);
-
-      printk("sd%c : block size assumed to be 512 bytes, disk size 1GB.  \n", 'a' + i);
-      rscsi_disks[i].capacity = 0x1fffff;
-      rscsi_disks[i].sector_size = 512;
-
-      /* Set dirty bit for removable devices if not ready - sometimes drives
-        will not report this properly. */
-      if(rscsi_disks[i].device->removable && 
-        SCpnt->sense_buffer[2] == NOT_READY)
-       rscsi_disks[i].device->changed = 1;
-
+       printk ("sd%c : READ CAPACITY failed.\n"
+               "sd%c : status = %x, message = %02x, host = %d, driver = %02x \n",
+               'a' + i, 'a' + i,
+               status_byte(the_result),
+               msg_byte(the_result),
+               host_byte(the_result),
+               driver_byte(the_result)
+               );
+       if (driver_byte(the_result)  & DRIVER_SENSE)
+           printk("sd%c : extended sense code = %1x \n", 
+                  'a' + i, SCpnt->sense_buffer[2] & 0xf);
+       else
+           printk("sd%c : sense not available. \n", 'a' + i);
+       
+       printk("sd%c : block size assumed to be 512 bytes, disk size 1GB.  \n",
+              'a' + i);
+       rscsi_disks[i].capacity = 0x1fffff;
+       rscsi_disks[i].sector_size = 512;
+       
+       /* Set dirty bit for removable devices if not ready - sometimes drives
+        * will not report this properly. */
+       if(rscsi_disks[i].device->removable && 
+          SCpnt->sense_buffer[2] == NOT_READY)
+           rscsi_disks[i].device->changed = 1;
+       
     }
-  else
+    else
     {
-      rscsi_disks[i].capacity = (buffer[0] << 24) |
-       (buffer[1] << 16) |
-         (buffer[2] << 8) |
-           buffer[3];
-
-      rscsi_disks[i].sector_size = (buffer[4] << 24) |
-       (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
-
-      if (rscsi_disks[i].sector_size != 512 &&
-         rscsi_disks[i].sector_size != 1024 &&
-         rscsi_disks[i].sector_size != 256)
+       rscsi_disks[i].capacity = (buffer[0] << 24) |
+           (buffer[1] << 16) |
+               (buffer[2] << 8) |
+                   buffer[3];
+       
+       rscsi_disks[i].sector_size = (buffer[4] << 24) |
+           (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+       
+       if (rscsi_disks[i].sector_size != 512 &&
+           rscsi_disks[i].sector_size != 1024 &&
+           rscsi_disks[i].sector_size != 256)
        {
-         printk ("sd%c : unsupported sector size %d.\n",
-                 'a' + i, rscsi_disks[i].sector_size);
-         if(rscsi_disks[i].device->removable){
-           rscsi_disks[i].capacity = 0;
-         } else {
-           printk ("scsi : deleting disk entry.\n");
-           rscsi_disks[i].device = NULL;
-           sd_template.nr_dev--;
-           return i;
-         };
+           printk ("sd%c : unsupported sector size %d.\n",
+                   'a' + i, rscsi_disks[i].sector_size);
+           if(rscsi_disks[i].device->removable){
+               rscsi_disks[i].capacity = 0;
+           } else {
+               printk ("scsi : deleting disk entry.\n");
+               rscsi_disks[i].device = NULL;
+               sd_template.nr_dev--;
+               return i;
+           };
        }
     {
-       /*
-          The msdos fs need to know the hardware sector size
-          So I have created this table. See ll_rw_blk.c
-          Jacques Gelinas (Jacques@solucorp.qc.ca)
-       */
-       int m;
-       int hard_sector = rscsi_disks[i].sector_size;
-       /* There is 16 minor allocated for each devices */
-       for (m=i<<4; m<((i+1)<<4); m++){
-         sd_hardsizes[m] = hard_sector;
-       }
-       printk ("SCSI Hardware sector size is %d bytes on device sd%c\n"
-         ,hard_sector,i+'a');
+       /*
+        * The msdos fs need to know the hardware sector size
+        * So I have created this table. See ll_rw_blk.c
+        * Jacques Gelinas (Jacques@solucorp.qc.ca)
+        */
+       int m;
+       int hard_sector = rscsi_disks[i].sector_size;
+       /* There is 16 minor allocated for each devices */
+       for (m=i<<4; m<((i+1)<<4); m++){
+           sd_hardsizes[m] = hard_sector;
+       }
+       printk ("SCSI Hardware sector size is %d bytes on device sd%c\n",
+               hard_sector,i+'a');
     }
-      if(rscsi_disks[i].sector_size == 1024)
-       rscsi_disks[i].capacity <<= 1;  /* Change this into 512 byte sectors */
-      if(rscsi_disks[i].sector_size == 256)
-       rscsi_disks[i].capacity >>= 1;  /* Change this into 512 byte sectors */
+       if(rscsi_disks[i].sector_size == 1024)
+           rscsi_disks[i].capacity <<= 1;  /* Change into 512 byte sectors */
+       if(rscsi_disks[i].sector_size == 256)
+           rscsi_disks[i].capacity >>= 1;  /* Change into 512 byte sectors */
     }
-
-  rscsi_disks[i].ten = 1;
-  rscsi_disks[i].remap = 1;
-  scsi_free(buffer, 512);
-  return i;
+    
+    rscsi_disks[i].ten = 1;
+    rscsi_disks[i].remap = 1;
+    scsi_free(buffer, 512);
+    return i;
 }
 
 /*
      The sd_init() function looks at all SCSI drives present, determines
      their size, and reads partition table entries for them.
-*/
* The sd_init() function looks at all SCSI drives present, determines
* their size, and reads partition table entries for them.
+ */
 
 
 static void sd_init()
 {
-       int i;
-       static int sd_registered = 0;
-
-       if (sd_template.dev_noticed == 0) return;
-
-       if(!sd_registered) {
+    int i;
+    static int sd_registered = 0;
+    
+    if (sd_template.dev_noticed == 0) return;
+    
+    if(!sd_registered) {
          if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) {
-           printk("Unable to get major %d for SCSI disk\n",MAJOR_NR);
-           return;
+             printk("Unable to get major %d for SCSI disk\n",MAJOR_NR);
+             return;
          }
          sd_registered++;
-       }
-
-       /* We do not support attaching loadable devices yet. */
-       if(rscsi_disks) return;
-
-       sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
-
-       rscsi_disks = (Scsi_Disk *) 
-         scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
-       memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
-
-       sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
+      }
+    
+    /* We do not support attaching loadable devices yet. */
+    if(rscsi_disks) return;
+    
+    sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
+    
+    rscsi_disks = (Scsi_Disk *) 
+       scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
+    memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
+    
+    sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
+                                       sizeof(int), GFP_ATOMIC);
+    memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
+    
+    sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
+                                            sizeof(int), GFP_ATOMIC);
+    
+    sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
                                            sizeof(int), GFP_ATOMIC);
-       memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
-
-       sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
-                                                sizeof(int), GFP_ATOMIC);
-
-       sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * 
-                                                  sizeof(struct hd_struct), GFP_ATOMIC);
-
-       for(i=0;i<(sd_template.dev_max << 4);i++){
-               sd_blocksizes[i] = 1024;
-               sd_hardsizes[i] = 512;
-       }
-       blksize_size[MAJOR_NR] = sd_blocksizes;
-       hardsect_size[MAJOR_NR] = sd_hardsizes;
-       sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
-                                                  sizeof(struct hd_struct),
-                                                  GFP_ATOMIC);
-
-
-       sd_gendisk.max_nr = sd_template.dev_max;
-       sd_gendisk.part = sd;
-       sd_gendisk.sizes = sd_sizes;
-       sd_gendisk.real_devices = (void *) rscsi_disks;
-
+    
+    for(i=0;i<(sd_template.dev_max << 4);i++){
+       sd_blocksizes[i] = 1024;
+       sd_hardsizes[i] = 512;
+    }
+    blksize_size[MAJOR_NR] = sd_blocksizes;
+    hardsect_size[MAJOR_NR] = sd_hardsizes;
+    sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
+                                              sizeof(struct hd_struct),
+                                              GFP_ATOMIC);
+    
+    
+    sd_gendisk.max_nr = sd_template.dev_max;
+    sd_gendisk.part = sd;
+    sd_gendisk.sizes = sd_sizes;
+    sd_gendisk.real_devices = (void *) rscsi_disks;
+    
 }
 
 static void sd_finish()
 {
-        int i;
-
-       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-
-       sd_gendisk.next = gendisk_head;
-       gendisk_head = &sd_gendisk;
-
-       for (i = 0; i < sd_template.dev_max; ++i)
-           if (!rscsi_disks[i].capacity && 
-                 rscsi_disks[i].device)
-             {
-               i = sd_init_onedisk(i);
-               if (scsi_loadable_module_flag 
-                   && !rscsi_disks[i].has_part_table) {
-                 sd_sizes[i << 4] = rscsi_disks[i].capacity;
-                 revalidate_scsidisk(i << 4, 0);
-               }
-               rscsi_disks[i].has_part_table = 1;
-             }
-
-       /* If our host adapter is capable of scatter-gather, then we increase
-          the read-ahead to 16 blocks (32 sectors).  If not, we use
-          a two block (4 sector) read ahead. */
-       if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize)
-         read_ahead[MAJOR_NR] = 120;
-       /* 64 sector read-ahead */
-       else
-         read_ahead[MAJOR_NR] = 4;  /* 4 sector read-ahead */
-       
-       return;
+    int i;
+    
+    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+    
+    sd_gendisk.next = gendisk_head;
+    gendisk_head = &sd_gendisk;
+    
+    for (i = 0; i < sd_template.dev_max; ++i)
+       if (!rscsi_disks[i].capacity && 
+           rscsi_disks[i].device)
+       {
+           i = sd_init_onedisk(i);
+           if (scsi_loadable_module_flag 
+               && !rscsi_disks[i].has_part_table) {
+               sd_sizes[i << 4] = rscsi_disks[i].capacity;
+               revalidate_scsidisk(i << 4, 0);
+           }
+           rscsi_disks[i].has_part_table = 1;
+       }
+    
+    /* If our host adapter is capable of scatter-gather, then we increase
+     * the read-ahead to 16 blocks (32 sectors).  If not, we use
+     * a two block (4 sector) read ahead. 
+     */
+    if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize)
+       read_ahead[MAJOR_NR] = 120;
+    /* 64 sector read-ahead */
+    else
+       read_ahead[MAJOR_NR] = 4;  /* 4 sector read-ahead */
+    
+    return;
 }
 
 static int sd_detect(Scsi_Device * SDp){
-  if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
-
-  printk("Detected scsi disk sd%c at scsi%d, id %d, lun %d\n", 
-        'a'+ (sd_template.dev_noticed++),
-        SDp->host->host_no , SDp->id, SDp->lun); 
-
-        return 1;
-
+    if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
+    
+    printk("Detected scsi disk sd%c at scsi%d, channel %d, id %d, lun %d\n", 
+          'a'+ (sd_template.dev_noticed++),
+          SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); 
+    
+    return 1;
 }
 
 static int sd_attach(Scsi_Device * SDp){
-   Scsi_Disk * dpnt;
-   int i;
-
-   if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
-
-   if(sd_template.nr_dev >= sd_template.dev_max) {
+    Scsi_Disk * dpnt;
+    int i;
+    
+    if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
+    
+    if(sd_template.nr_dev >= sd_template.dev_max) {
        SDp->attached--;
        return 1;
-   }
-   
-   for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++) 
-     if(!dpnt->device) break;
-
-   if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)");
-
-   SDp->scsi_request_fn = do_sd_request;
-   rscsi_disks[i].device = SDp;
-   rscsi_disks[i].has_part_table = 0;
-   sd_template.nr_dev++;
-   sd_gendisk.nr_real++;
-   return 0;
+    }
+    
+    for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++) 
+       if(!dpnt->device) break;
+    
+    if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)");
+    
+    SDp->scsi_request_fn = do_sd_request;
+    rscsi_disks[i].device = SDp;
+    rscsi_disks[i].has_part_table = 0;
+    sd_template.nr_dev++;
+    sd_gendisk.nr_real++;
+    return 0;
 }
 
 #define DEVICE_BUSY rscsi_disks[target].device->busy
@@ -1188,111 +1236,177 @@ static int sd_attach(Scsi_Device * SDp){
 #define GENDISK_STRUCT sd_gendisk
 
 /* This routine is called to flush all partitions and partition tables
  for a changed scsi disk, and then re-read the new partition table.
  If we are revalidating a disk because of a media change, then we
  enter with usage == 0.  If we are using an ioctl, we automatically have
  usage == 1 (we need an open channel to use an ioctl :-), so this
  is our limit.
* for a changed scsi disk, and then re-read the new partition table.
* If we are revalidating a disk because of a media change, then we
* enter with usage == 0.  If we are using an ioctl, we automatically have
* usage == 1 (we need an open channel to use an ioctl :-), so this
* is our limit.
  */
 int revalidate_scsidisk(int dev, int maxusage){
-         int target, major;
-         struct gendisk * gdev;
-         unsigned long flags;
-         int max_p;
-         int start;
-         int i;
-
-         target =  DEVICE_NR(MINOR(dev));
-         gdev = &GENDISK_STRUCT;
-
-         save_flags(flags);
-         cli();
-         if (DEVICE_BUSY || USAGE > maxusage) {
-           restore_flags(flags);
-           printk("Device busy for revalidation (usage=%d)\n", USAGE);
-           return -EBUSY;
-         };
-         DEVICE_BUSY = 1;
-         restore_flags(flags);
-
-         max_p = gdev->max_p;
-         start = target << gdev->minor_shift;
-         major = MAJOR_NR << 8;
-
-         for (i=max_p - 1; i >=0 ; i--) {
-           sync_dev(major | start | i);
-           invalidate_inodes(major | start | i);
-           invalidate_buffers(major | start | i);
-           gdev->part[start+i].start_sect = 0;
-           gdev->part[start+i].nr_sects = 0;
-         };
-
+    int target, major;
+    struct gendisk * gdev;
+    unsigned long flags;
+    int max_p;
+    int start;
+    int i;
+    
+    target =  DEVICE_NR(MINOR(dev));
+    gdev = &GENDISK_STRUCT;
+    
+    save_flags(flags);
+    cli();
+    if (DEVICE_BUSY || USAGE > maxusage) {
+       restore_flags(flags);
+       printk("Device busy for revalidation (usage=%d)\n", USAGE);
+       return -EBUSY;
+    };
+    DEVICE_BUSY = 1;
+    restore_flags(flags);
+    
+    max_p = gdev->max_p;
+    start = target << gdev->minor_shift;
+    major = MAJOR_NR << 8;
+    
+    for (i=max_p - 1; i >=0 ; i--) {
+       sync_dev(major | start | i);
+       invalidate_inodes(major | start | i);
+       invalidate_buffers(major | start | i);
+       gdev->part[start+i].start_sect = 0;
+       gdev->part[start+i].nr_sects = 0;
+    };
+    
 #ifdef MAYBE_REINIT
-         MAYBE_REINIT;
+    MAYBE_REINIT;
 #endif
-
-         gdev->part[start].nr_sects = CAPACITY;
-         resetup_one_dev(gdev, target);
-
-         DEVICE_BUSY = 0;
-         return 0;
+    
+    gdev->part[start].nr_sects = CAPACITY;
+    resetup_one_dev(gdev, target);
+    
+    DEVICE_BUSY = 0;
+    return 0;
 }
 
 static int fop_revalidate_scsidisk(dev_t dev){
-  return revalidate_scsidisk(dev, 0);
+    return revalidate_scsidisk(dev, 0);
 }
 
 
 static void sd_detach(Scsi_Device * SDp)
 {
-  Scsi_Disk * dpnt;
-  int i;
-  int max_p;
-  int major;
-  int start;
-  
-  for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++) 
-    if(dpnt->device == SDp) {
+    Scsi_Disk * dpnt;
+    int i;
+    int max_p;
+    int major;
+    int start;
+    
+    for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++) 
+       if(dpnt->device == SDp) {
+           
+           /* If we are disconnecting a disk driver, sync and invalidate 
+            * everything */
+           max_p = sd_gendisk.max_p;
+           start = i << sd_gendisk.minor_shift;
+           major = MAJOR_NR << 8;
+           
+           for (i=max_p - 1; i >=0 ; i--) {
+               sync_dev(major | start | i);
+               invalidate_inodes(major | start | i);
+               invalidate_buffers(major | start | i);
+               sd_gendisk.part[start+i].start_sect = 0;
+               sd_gendisk.part[start+i].nr_sects = 0;
+               sd_sizes[start+i] = 0;
+           };
+           
+           dpnt->has_part_table = 0;
+           dpnt->device = NULL;
+           dpnt->capacity = 0;
+           SDp->attached--;
+           sd_template.dev_noticed--;
+           sd_template.nr_dev--;
+           sd_gendisk.nr_real--;
+           return;
+       }
+    return;
+}
 
-      /* If we are disconnecting a disk driver, sync and invalidate everything */
-      max_p = sd_gendisk.max_p;
-      start = i << sd_gendisk.minor_shift;
-      major = MAJOR_NR << 8;
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
 
-      for (i=max_p - 1; i >=0 ; i--) {
-       sync_dev(major | start | i);
-       invalidate_inodes(major | start | i);
-       invalidate_buffers(major | start | i);
-       sd_gendisk.part[start+i].start_sect = 0;
-       sd_gendisk.part[start+i].nr_sects = 0;
-       sd_sizes[start+i] = 0;
-      };
-      
-      dpnt->has_part_table = 0;
-      dpnt->device = NULL;
-      dpnt->capacity = 0;
-      SDp->attached--;
-      sd_template.dev_noticed--;
-      sd_template.nr_dev--;
-      sd_gendisk.nr_real--;
-      return;
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void) {
+    sd_template.usage_count = &mod_use_count_;
+    return scsi_register_module(MODULE_SCSI_DEV, &sd_template);
+}
+
+void cleanup_module( void) 
+{
+    struct gendisk * prev_sdgd;
+    struct gendisk * sdgd;
+    
+    if (MOD_IN_USE) {
+       printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+       return;
+    }
+    scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
+    unregister_blkdev(SCSI_GENERIC_MAJOR, "sd");
+    if( rscsi_disks != NULL )
+    {
+       scsi_init_free((char *) rscsi_disks,
+                      (sd_template.dev_noticed + SD_EXTRA_DEVS) 
+                      * sizeof(Scsi_Disk));
+       
+       scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int));
+       scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int));
+       scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int));
+       scsi_init_free((char *) sd, 
+                      (sd_template.dev_max << 4) * sizeof(struct hd_struct));
+       /*
+        * Now remove sd_gendisk from the linked list
+        */
+       sdgd = gendisk_head;
+       prev_sdgd = NULL;
+       while(sdgd != &sd_gendisk)
+       {
+           prev_sdgd = sdgd;
+           sdgd = sdgd->next;
+       }
+       
+       if(sdgd != &sd_gendisk)
+           printk("sd_gendisk not in disk chain.\n");
+       else {
+           if(prev_sdgd != NULL)
+               prev_sdgd->next = sdgd->next;
+           else
+               gendisk_head = sdgd->next;
+       }
     }
-  return;
+    
+    blksize_size[MAJOR_NR] = NULL;
+    blk_dev[MAJOR_NR].request_fn = NULL;
+    blk_size[MAJOR_NR] = NULL;  
+    hardsect_size[MAJOR_NR] = NULL;
+    read_ahead[MAJOR_NR] = 0;
+    sd_template.dev_max = 0;
 }
+#endif /* MODULE */
 
 /*
- * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Overrides for Emacs so that we almost 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-indent-level: 4
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
  * End:
  */
index e35079f761076e8c65e68fcd722cd1d674cdda10..453cc900a95bb82b11d034731d6dbb5db53e1133 100644 (file)
@@ -1,16 +1,16 @@
 /*
- *     sd.h Copyright (C) 1992 Drew Eckhardt 
- *     SCSI disk driver header file by
- *             Drew Eckhardt 
+ *      sd.h Copyright (C) 1992 Drew Eckhardt 
+ *      SCSI disk driver header file by
+ *              Drew Eckhardt 
  *
- *     <drew@colorado.edu>
+ *      <drew@colorado.edu>
  *
  *       Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  */
 #ifndef _SD_H
-       #define _SD_H
+#define _SD_H
 /*
        $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/sd.h,v 1.1 1992/07/24 06:27:38 root Exp root $
 */
 #endif
 
 /*
      This is an arbitrary constant, and may be changed to whatever
      suits your purposes.  Note that smaller will get you a few bytes
      more in kernel space if that is your thing.
-*/
*  This is an arbitrary constant, and may be changed to whatever
*  suits your purposes.  Note that smaller will get you a few bytes
*  more in kernel space if that is your thing.
+ */
 
 extern struct hd_struct * sd;
 
 typedef struct scsi_disk {
-               unsigned capacity;              /* size in blocks */
-               unsigned sector_size;           /* size in bytes */
-               Scsi_Device  *device;           
-               unsigned char sector_bit_size;  /* sector_size = 2 to the  bit size power */
-               unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
-               unsigned ten:1;                 /* support ten byte read / write */
-               unsigned remap:1;               /* support remapping  */
-               unsigned has_part_table:1;      /* has partition table */
-               } Scsi_Disk;
-       
+    unsigned capacity;              /* size in blocks */
+    unsigned sector_size;           /* size in bytes */
+    Scsi_Device  *device;           
+    unsigned char sector_bit_size;  /* sector_size = 2 to the  bit size power */
+    unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
+    unsigned ten:1;                 /* support ten byte read / write */
+    unsigned remap:1;               /* support remapping  */
+    unsigned has_part_table:1;      /* has partition table */
+} Scsi_Disk;
+
 extern Scsi_Disk * rscsi_disks;
 
 #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: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
+
index a97f793a3089e4d11745d6f482e6e6d5c93429dd..33c410d754ba25b301733ed397bb75a538470bf0 100644 (file)
@@ -17,58 +17,59 @@ extern int revalidate_scsidisk(int, int);
 
 int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
 {
-       int dev = inode->i_rdev;
-       int error;
-       struct Scsi_Host * host;
-       int diskinfo[4];
-       struct hd_geometry *loc = (struct hd_geometry *) arg;
-
-       switch (cmd) {
-               case HDIO_REQ:   /* Return BIOS disk parameters */
-                       if (!loc)  return -EINVAL;
-                       error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
-                       if (error)
-                               return error;
-                       host = rscsi_disks[MINOR(dev) >> 4].device->host;
-                       diskinfo[0] = 0;
-                       diskinfo[1] = 0;
-                       diskinfo[2] = 0;
-                       if(host->hostt->bios_param != NULL)
-                             host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4],
-                                                         dev,
-                                                         &diskinfo[0]);
-                       put_user(diskinfo[0], &loc->heads);
-                       put_user(diskinfo[1], &loc->sectors);
-                       put_user(diskinfo[2], &loc->cylinders);
-                       put_user(sd[MINOR(inode->i_rdev)].start_sect, &loc->start);
-                       return 0;
-               case BLKGETSIZE:   /* Return device size */
-                       if (!arg)  return -EINVAL;
-                       error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
-                       if (error)
-                               return error;
-                       put_user(sd[MINOR(inode->i_rdev)].nr_sects,
-                                (long *) arg);
-                       return 0;
-               case BLKRASET:
-                       if(!suser())  return -EACCES;
-                       if(!inode->i_rdev) return -EINVAL;
-                       if(arg > 0xff) return -EINVAL;
-                       read_ahead[MAJOR(inode->i_rdev)] = arg;
-                       return 0;
-               case BLKFLSBUF:
-                       if(!suser())  return -EACCES;
-                       if(!inode->i_rdev) return -EINVAL;
-                       fsync_dev(inode->i_rdev);
-                       invalidate_buffers(inode->i_rdev);
-                       return 0;
-
-               case BLKRRPART: /* Re-read partition tables */
-                       return revalidate_scsidisk(dev, 1);
-               default:
-                       return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg);
-       }
+    int dev = inode->i_rdev;
+    int error;
+    struct Scsi_Host * host;
+    int diskinfo[4];
+    struct hd_geometry *loc = (struct hd_geometry *) arg;
+    
+    switch (cmd) {
+    case HDIO_REQ:   /* Return BIOS disk parameters */
+       if (!loc)  return -EINVAL;
+       error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
+       if (error)
+           return error;
+       host = rscsi_disks[MINOR(dev) >> 4].device->host;
+       diskinfo[0] = 0;
+       diskinfo[1] = 0;
+       diskinfo[2] = 0;
+       if(host->hostt->bios_param != NULL)
+           host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4],
+                                   dev,
+                                   &diskinfo[0]);
+       put_user(diskinfo[0], &loc->heads);
+       put_user(diskinfo[1], &loc->sectors);
+       put_user(diskinfo[2], &loc->cylinders);
+       put_user(sd[MINOR(inode->i_rdev)].start_sect, &loc->start);
+       return 0;
+    case BLKGETSIZE:   /* Return device size */
+       if (!arg)  return -EINVAL;
+       error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+       if (error)
+           return error;
+       put_user(sd[MINOR(inode->i_rdev)].nr_sects,
+                (long *) arg);
+       return 0;
+    case BLKRASET:
+       if(!suser())  return -EACCES;
+       if(!inode->i_rdev) return -EINVAL;
+       if(arg > 0xff) return -EINVAL;
+       read_ahead[MAJOR(inode->i_rdev)] = arg;
+       return 0;
+    case BLKFLSBUF:
+       if(!suser())  return -EACCES;
+       if(!inode->i_rdev) return -EINVAL;
+       fsync_dev(inode->i_rdev);
+       invalidate_buffers(inode->i_rdev);
+       return 0;
+       
+    case BLKRRPART: /* Re-read partition tables */
+       return revalidate_scsidisk(dev, 1);
+    default:
+       return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg);
+    }
 }
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
@@ -76,12 +77,14 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
  * of the file.
  * ---------------------------------------------------------------------------
  * Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
  * End:
  */
index 5ea690a533fd3d823c5c5f4a5b5ea5098f0264bb..00a697e6631107fa43483bcc773c058b5cbdd7c6 100644 (file)
@@ -46,6 +46,9 @@
  *     transfer rate if handshaking isn't working correctly.
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -53,6 +56,7 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/config.h>
+#include <linux/proc_fs.h>
 
 #include "../block/blk.h"
 #include "scsi.h"
@@ -294,7 +298,7 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt)
                }
 
       /* If the user specified the controller type from the command line,
-         controller_type will be non-zero, so don't try and detect one */
+        controller_type will be non-zero, so don't try and detect one */
 
        if (!controller_type) {
 #ifdef OVERRIDE
@@ -375,7 +379,7 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt)
 #ifdef LINKED
                " LINKED"
 #endif
-              "\n", tpnt->name);
+             "\n", tpnt->name);
                return 1;
                }
        else
@@ -389,10 +393,10 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt)
         
 const char *seagate_st0x_info(struct Scsi_Host * shpnt) {
       static char buffer[64];
-        sprintf(buffer, "%s at irq %d, address 0x%05X", 
+       sprintf(buffer, "%s at irq %d, address 0x%05X", 
                (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR,
                irq, (unsigned int)base_address);
-        return buffer;
+       return buffer;
 }
 
 /*
@@ -707,9 +711,9 @@ static int internal_command(unsigned char target, unsigned char lun, const void
                        }
 
                buffer=current_buffer;  
-                cmnd=current_cmnd;      /* WDE add */
-                data=current_data;      /* WDE add */
-                len=current_bufflen;    /* WDE add */
+               cmnd=current_cmnd;      /* WDE add */
+               data=current_data;      /* WDE add */
+               len=current_bufflen;    /* WDE add */
                nobuffs=current_nobuffs;
 
 /*
@@ -778,7 +782,7 @@ connect_loop :
 
 #if !defined (ARBITRATE) 
                while (((STATUS |  STATUS | STATUS) & 
-                        (STAT_BSY | STAT_SEL)) && 
+                        (STAT_BSY | STAT_SEL)) && 
                         (!st0x_aborted) && (jiffies < clock));
 
                if (jiffies > clock)
@@ -894,7 +898,7 @@ connect_loop :
 
 /* Establish current pointers.  Take into account scatter / gather */
 
-        if ((nobuffs = SCint->use_sg)) {
+       if ((nobuffs = SCint->use_sg)) {
 #if (DEBUG & DEBUG_SG)
        {
        int i;
@@ -906,17 +910,17 @@ connect_loop :
        }
 #endif
                
-                buffer = (struct scatterlist *) SCint->buffer;
-                len = buffer->length;
-                data = (unsigned char *) buffer->address;
-        } else {
+               buffer = (struct scatterlist *) SCint->buffer;
+               len = buffer->length;
+               data = (unsigned char *) buffer->address;
+       } else {
 #if (DEBUG & DEBUG_SG)
        printk("scsi%d : scatter gather not requested.\n", hostno);
 #endif
-                buffer = NULL;
-                len = SCint->request_bufflen;
-                data = (unsigned char *) SCint->request_buffer;
-        }
+               buffer = NULL;
+               len = SCint->request_bufflen;
+               data = (unsigned char *) SCint->request_buffer;
+       }
 
 #if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT))
        printk("scsi%d : len = %d\n", hostno, len);
@@ -1034,12 +1038,12 @@ connect_loop :
 #ifdef FAST 
 if (!len) {
 #if 0 
-        printk("scsi%d: underflow to target %d lun %d \n", 
-                hostno, target, lun);
-        st0x_aborted = DID_ERROR;
-        fast = 0;
+       printk("scsi%d: underflow to target %d lun %d \n", 
+               hostno, target, lun);
+       st0x_aborted = DID_ERROR;
+       fast = 0;
 #endif
-        break;
+       break;
 }
 
 if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
@@ -1048,12 +1052,12 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
 #endif
        ) {
 #if (DEBUG & DEBUG_FAST) 
-        printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
-               "         len = %d, data = %08x\n", hostno, SCint->underflow, 
-               SCint->transfersize, len, data);
+       printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
+              "         len = %d, data = %08x\n", hostno, SCint->underflow, 
+              SCint->transfersize, len, data);
 #endif
 
-        __asm__("
+       __asm__("
        cld;
 "
 #ifdef FAST32
@@ -1063,14 +1067,14 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
 "
 #else
 "1:    lodsb;
-        movb %%al, (%%edi);
+       movb %%al, (%%edi);
 "
 #endif
 "      loop 1b;" : :
-        /* input */
-        "D" (st0x_dr), "S" (data), "c" (SCint->transfersize) :
-        /* clobbered */
-        "eax", "ecx", "esi" );
+       /* input */
+       "D" (st0x_dr), "S" (data), "c" (SCint->transfersize) :
+       /* clobbered */
+       "eax", "ecx", "esi" );
 
        len -= transfersize;
        data += transfersize;
@@ -1105,8 +1109,8 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
 
        cld
 
-       movl _st0x_cr_sr, %%ebx
-       movl _st0x_dr, %%edi
+       movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%ebx
+       movl " SYMBOL_NAME_STR(st0x_dr) ", %%edi
        
 1:     movb (%%ebx), %%al\n"
 /*
@@ -1140,16 +1144,16 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
 "eax", "ebx", "edi"); 
 }
 
-                        if (!len && nobuffs) {
-                                --nobuffs;
-                                ++buffer;
-                                len = buffer->length;
-                                data = (unsigned char *) buffer->address;
+                       if (!len && nobuffs) {
+                               --nobuffs;
+                               ++buffer;
+                               len = buffer->length;
+                               data = (unsigned char *) buffer->address;
 #if (DEBUG & DEBUG_SG)
        printk("scsi%d : next scatter-gather buffer len = %d address = %08x\n",
                hostno, len, data);
 #endif
-                        }
+                       }
                        break;
 
                case REQ_DATAIN : 
@@ -1175,11 +1179,11 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
 #endif
        ) {
 #if (DEBUG & DEBUG_FAST) 
-        printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
-               "         len = %d, data = %08x\n", hostno, SCint->underflow, 
-               SCint->transfersize, len, data);
+       printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
+              "         len = %d, data = %08x\n", hostno, SCint->underflow, 
+              SCint->transfersize, len, data);
 #endif
-        __asm__("
+       __asm__("
        cld;
 "
 #ifdef FAST32
@@ -1189,15 +1193,15 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
 "
 #else
 "1:    movb (%%esi), %%al;
-        stosb;
+       stosb;
 "
 #endif
 
 "      loop 1b;" : :
-        /* input */
-        "S" (st0x_dr), "D" (data), "c" (SCint->transfersize) :
-        /* clobbered */
-        "eax", "ecx", "edi");
+       /* input */
+       "S" (st0x_dr), "D" (data), "c" (SCint->transfersize) :
+       /* clobbered */
+       "eax", "ecx", "edi");
 
        len -= transfersize;
        data += transfersize;
@@ -1241,8 +1245,8 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
        jz 2f
 
        cld
-       movl _st0x_cr_sr, %%esi
-       movl _st0x_dr, %%ebx
+       movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%esi
+       movl " SYMBOL_NAME_STR(st0x_dr) ", %%ebx
 
 1:     movb (%%esi), %%al\n"
 /*
@@ -1286,16 +1290,16 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
 #endif
 }
        
-                        if (!len && nobuffs) {
-                                --nobuffs;
-                                ++buffer;
-                                len = buffer->length;
-                                data = (unsigned char *) buffer->address;
+                       if (!len && nobuffs) {
+                               --nobuffs;
+                               ++buffer;
+                               len = buffer->length;
+                               data = (unsigned char *) buffer->address;
 #if (DEBUG & DEBUG_SG)
        printk("scsi%d : next scatter-gather buffer len = %d address = %08x\n",
                hostno, len, data);
 #endif
-                        }
+                       }
 
                        break;
 
@@ -1358,9 +1362,9 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
                        switch (message = DATA) {
                        case DISCONNECT :
                                should_reconnect = 1;
-                                current_data = data;    /* WDE add */
+                               current_data = data;    /* WDE add */
                                current_buffer = buffer;
-                                current_bufflen = len;  /* WDE add */
+                               current_bufflen = len;  /* WDE add */
                                current_nobuffs = nobuffs;
 #ifdef LINKED
                                linked_connected = 0;
@@ -1392,7 +1396,7 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
                                break;
                        case SAVE_POINTERS :
                                current_buffer = buffer;
-                                current_bufflen = len;  /* WDE add */
+                               current_bufflen = len;  /* WDE add */
                                current_data = data;    /* WDE mod */
                                current_nobuffs = nobuffs;
 #if (DEBUG & PHASE_MSGIN)
@@ -1471,7 +1475,7 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
        printk("\n");
 #endif
        printk("scsi%d : status = ", hostno);
-        print_status(status);
+       print_status(status);
        printk("message = %02x\n", message);
 #endif
 
@@ -1697,3 +1701,10 @@ printk("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %
     
   return result;
 }
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = SEAGATE_ST0X;
+
+#include "scsi_module.c"
+#endif
index 4f6ef3efd7c35ceda763a66f9de2a9024712124a..e885f02d617881c1673e5dcd738e7930018403f5 100644 (file)
@@ -26,7 +26,10 @@ int seagate_st0x_reset(Scsi_Cmnd *);
 
 int seagate_st0x_biosparam(Disk *, int, int*);
 
-#define SEAGATE_ST0X  {NULL, NULL, NULL, seagate_st0x_detect,          \
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
+#define SEAGATE_ST0X  {  NULL, NULL, generic_proc_info, "seagate", \
+                        PROC_SCSI_SEAGATE, NULL, seagate_st0x_detect,  \
                         NULL,                                          \
                         seagate_st0x_info, seagate_st0x_command,       \
                         seagate_st0x_queue_command, seagate_st0x_abort, \
index cfd0706cdda457703932944e3a28906aab46ffe1..248bf80f11c44a5c0230485b7e877e16006cc54d 100644 (file)
@@ -1,11 +1,15 @@
 /*
-   History:
-    Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user 
-     process control of SCSI devices.
-    Development Sponsored by Killy Corp. NY NY
-    
-    Borrows code from st driver.
-*/
+ *  History:
+ *  Started: Aug 9 by Lawrence Foard (entropy@world.std.com), 
+ *           to allow user process control of SCSI devices.
+ *  Development Sponsored by Killy Corp. NY NY
+ *   
+ *  Borrows code from st driver.
+ */
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif /* MODULE */
 
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -32,410 +36,445 @@ static int sg_detect(Scsi_Device *);
 static void sg_detach(Scsi_Device *);
 
 
-struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", 0xff, 
-                                            SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
-                                            sg_detect, sg_init,
-                                            NULL, sg_attach, sg_detach};
+struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff, 
+                                              SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
+                                              sg_detect, sg_init,
+                                              NULL, sg_attach, sg_detach};
 
 #ifdef SG_BIG_BUFF
-static char *big_buff;
+static char *big_buff = NULL;
 static struct wait_queue *big_wait;   /* wait for buffer available */
 static int big_inuse=0;
 #endif
 
 struct scsi_generic
- {
-  Scsi_Device *device;
-  int users;   /* how many people have it open? */
-  struct wait_queue *generic_wait; /* wait for device to be available */
-  struct wait_queue *read_wait;    /* wait for response */
-  struct wait_queue *write_wait;   /* wait for free buffer */
-  int timeout; /* current default value for device */
-  int buff_len; /* length of current buffer */
-  char *buff;   /* the buffer */
-  struct sg_header header; /* header of pending command */
-  char exclude; /* opened for exclusive access */
-  char pending;  /* don't accept writes now */
-  char complete; /* command complete allow a read */
- };
+{
+    Scsi_Device *device;
+    int users;   /* how many people have it open? */
+    struct wait_queue *generic_wait; /* wait for device to be available */
+    struct wait_queue *read_wait;    /* wait for response */
+    struct wait_queue *write_wait;   /* wait for free buffer */
+    int timeout; /* current default value for device */
+    int buff_len; /* length of current buffer */
+    char *buff;   /* the buffer */
+    struct sg_header header; /* header of pending command */
+    char exclude; /* opened for exclusive access */
+    char pending;  /* don't accept writes now */
+    char complete; /* command complete allow a read */
+};
 
 static struct scsi_generic *scsi_generics=NULL;
 static void sg_free(char *buff,int size);
 
 static int sg_ioctl(struct inode * inode,struct file * file,
-            unsigned int cmd_in, unsigned long arg)
- {
-  int dev = MINOR(inode->i_rdev);
-  if ((dev<0) || (dev>=sg_template.dev_max))
-   return -ENXIO;
-  switch(cmd_in)
-   {
+                   unsigned int cmd_in, unsigned long arg)
+{
+    int dev = MINOR(inode->i_rdev);
+    if ((dev<0) || (dev>=sg_template.dev_max))
+       return -ENXIO;
+    switch(cmd_in)
+    {
     case SG_SET_TIMEOUT:
-     scsi_generics[dev].timeout=get_user((int *) arg);
-     return 0;
+       scsi_generics[dev].timeout=get_user((int *) arg);
+       return 0;
     case SG_GET_TIMEOUT:
-     return scsi_generics[dev].timeout;
+       return scsi_generics[dev].timeout;
     default:
-     return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
-   }
- }
+       return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
+    }
+}
 
 static int sg_open(struct inode * inode, struct file * filp)
- {
-  int dev=MINOR(inode->i_rdev);
-  int flags=filp->f_flags;
-  if (dev>=sg_template.dev_max || !scsi_generics[dev].device)
-   return -ENXIO;
-  if (O_RDWR!=(flags & O_ACCMODE))
-   return -EACCES;
-  if (flags & O_EXCL)
-   {
-    while(scsi_generics[dev].users)
-     {
-      if (flags & O_NONBLOCK)
-       return -EBUSY;
-      interruptible_sleep_on(&scsi_generics[dev].generic_wait);
-      if (current->signal & ~current->blocked)
-       return -ERESTARTSYS;
-     }
-    scsi_generics[dev].exclude=1;
-   }
-  else
-   while(scsi_generics[dev].exclude)
+{
+    int dev=MINOR(inode->i_rdev);
+    int flags=filp->f_flags;
+    if (dev>=sg_template.dev_max || !scsi_generics[dev].device)
+       return -ENXIO;
+    if (O_RDWR!=(flags & O_ACCMODE))
+       return -EACCES;
+    if (flags & O_EXCL)
     {
-     if (flags & O_NONBLOCK)
-      return -EBUSY;
-     interruptible_sleep_on(&scsi_generics[dev].generic_wait);
-     if (current->signal & ~current->blocked)
-      return -ERESTARTSYS;
+       while(scsi_generics[dev].users)
+       {
+           if (flags & O_NONBLOCK)
+               return -EBUSY;
+           interruptible_sleep_on(&scsi_generics[dev].generic_wait);
+           if (current->signal & ~current->blocked)
+               return -ERESTARTSYS;
+       }
+       scsi_generics[dev].exclude=1;
     }
-  if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
-   {
-    if (scsi_generics[dev].buff != NULL)
-      sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
-    scsi_generics[dev].buff=NULL;
-    scsi_generics[dev].pending=0;
-   }
-  if (!scsi_generics[dev].users)
-   scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT;
-  if (scsi_generics[dev].device->host->hostt->usage_count)
-    (*scsi_generics[dev].device->host->hostt->usage_count)++;
-  scsi_generics[dev].users++;
-  return 0;
- }
+    else
+       while(scsi_generics[dev].exclude)
+       {
+           if (flags & O_NONBLOCK)
+               return -EBUSY;
+           interruptible_sleep_on(&scsi_generics[dev].generic_wait);
+           if (current->signal & ~current->blocked)
+               return -ERESTARTSYS;
+       }
+    if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
+    {
+       if (scsi_generics[dev].buff != NULL)
+           sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
+       scsi_generics[dev].buff=NULL;
+       scsi_generics[dev].pending=0;
+    }
+    if (!scsi_generics[dev].users)
+       scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT;
+    if (scsi_generics[dev].device->host->hostt->usage_count)
+       (*scsi_generics[dev].device->host->hostt->usage_count)++;
+    if(sg_template.usage_count) (*sg_template.usage_count)++;
+    scsi_generics[dev].users++;
+    return 0;
+}
 
 static void sg_close(struct inode * inode, struct file * filp)
- {
-  int dev=MINOR(inode->i_rdev);
-  scsi_generics[dev].users--;
-  if (scsi_generics[dev].device->host->hostt->usage_count)
-    (*scsi_generics[dev].device->host->hostt->usage_count)--;
-  scsi_generics[dev].exclude=0;
-  wake_up(&scsi_generics[dev].generic_wait);
- }
+{
+    int dev=MINOR(inode->i_rdev);
+    scsi_generics[dev].users--;
+    if (scsi_generics[dev].device->host->hostt->usage_count)
+       (*scsi_generics[dev].device->host->hostt->usage_count)--;
+    if(sg_template.usage_count) (*sg_template.usage_count)--;
+    scsi_generics[dev].exclude=0;
+    wake_up(&scsi_generics[dev].generic_wait);
+}
 
 static char *sg_malloc(int size)
- {
-  if (size<=4096)
-   return (char *) scsi_malloc(size);
+{
+    if (size<=4096)
+       return (char *) scsi_malloc(size);
 #ifdef SG_BIG_BUFF
-  if (size<SG_BIG_BUFF)
-   {
-    while(big_inuse)
-     {
-      interruptible_sleep_on(&big_wait);
-      if (current->signal & ~current->blocked)
-       return NULL;
-     }
-    big_inuse=1;
-    return big_buff;
-   }
+    if (size<SG_BIG_BUFF)
+    {
+       while(big_inuse)
+       {
+           interruptible_sleep_on(&big_wait);
+           if (current->signal & ~current->blocked)
+               return NULL;
+       }
+       big_inuse=1;
+       return big_buff;
+    }
 #endif   
-  return NULL;
- }
+    return NULL;
+}
 
 static void sg_free(char *buff,int size) 
- {
+{
 #ifdef SG_BIG_BUFF
-  if (buff==big_buff)
-   {
-    big_inuse=0;
-    wake_up(&big_wait);
-    return;
-   }
+    if (buff==big_buff)
+    {
+       big_inuse=0;
+       wake_up(&big_wait);
+       return;
+    }
 #endif
-  scsi_free(buff,size);
- }
+    scsi_free(buff,size);
+}
 
 static int sg_read(struct inode *inode,struct file *filp,char *buf,int count)
- {
-  int dev=MINOR(inode->i_rdev);
-  int i;
-  struct scsi_generic *device=&scsi_generics[dev];
-  if ((i=verify_area(VERIFY_WRITE,buf,count)))
-   return i;
-  while(!device->pending || !device->complete)
-   {
-    if (filp->f_flags & O_NONBLOCK)
-     return -EWOULDBLOCK;
-    interruptible_sleep_on(&device->read_wait);
-    if (current->signal & ~current->blocked)
-     return -ERESTARTSYS;
-   }
-  device->header.pack_len=device->header.reply_len;
-  device->header.result=0;
-  if (count>=sizeof(struct sg_header))
-   {
-    memcpy_tofs(buf,&device->header,sizeof(struct sg_header));
-    buf+=sizeof(struct sg_header);
-    if (count>device->header.pack_len)
-     count=device->header.pack_len;
-    if (count > sizeof(struct sg_header)) {
-       memcpy_tofs(buf,device->buff,count-sizeof(struct sg_header));
+{
+    int dev=MINOR(inode->i_rdev);
+    int i;
+    struct scsi_generic *device=&scsi_generics[dev];
+    if ((i=verify_area(VERIFY_WRITE,buf,count)))
+       return i;
+    while(!device->pending || !device->complete)
+    {
+       if (filp->f_flags & O_NONBLOCK)
+           return -EWOULDBLOCK;
+       interruptible_sleep_on(&device->read_wait);
+       if (current->signal & ~current->blocked)
+           return -ERESTARTSYS;
+    }
+    device->header.pack_len=device->header.reply_len;
+    device->header.result=0;
+    if (count>=sizeof(struct sg_header))
+    {
+       memcpy_tofs(buf,&device->header,sizeof(struct sg_header));
+       buf+=sizeof(struct sg_header);
+       if (count>device->header.pack_len)
+           count=device->header.pack_len;
+       if (count > sizeof(struct sg_header)) {
+           memcpy_tofs(buf,device->buff,count-sizeof(struct sg_header));
+       }
     }
-   }
-  else
-   count=0;
-  sg_free(device->buff,device->buff_len);
-  device->buff = NULL;
-  device->pending=0;
-  wake_up(&device->write_wait);
-  return count;
- }
+    else
+       count=0;
+    sg_free(device->buff,device->buff_len);
+    device->buff = NULL;
+    device->pending=0;
+    wake_up(&device->write_wait);
+    return count;
+}
 
 static void sg_command_done(Scsi_Cmnd * SCpnt)
- {
-  int dev=SCpnt->request.dev;
-  struct scsi_generic *device=&scsi_generics[dev];
-  if (!device->pending)
-   {
-    printk("unexpected done for sg %d\n",dev);
+{
+    int dev=SCpnt->request.dev;
+    struct scsi_generic *device=&scsi_generics[dev];
+    if (!device->pending)
+    {
+       printk("unexpected done for sg %d\n",dev);
+       SCpnt->request.dev=-1;
+       return;
+    }
+    memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
+    if (SCpnt->sense_buffer[0])
+    {
+       device->header.result=EIO;
+    }
+    else
+       device->header.result=SCpnt->result;
+    device->complete=1;
     SCpnt->request.dev=-1;
-    return;
-   }
-  memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
-  if (SCpnt->sense_buffer[0])
-   {
-    device->header.result=EIO;
-   }
-  else
-   device->header.result=SCpnt->result;
-  device->complete=1;
-  SCpnt->request.dev=-1;
-  wake_up(&scsi_generics[dev].read_wait);
- }
+    wake_up(&scsi_generics[dev].read_wait);
+}
 
 static int sg_write(struct inode *inode,struct file *filp,char *buf,int count)
- {
-  int dev=MINOR(inode->i_rdev);
-  Scsi_Cmnd *SCpnt;
-  int bsize,size,amt,i;
-  unsigned char opcode;
-  unsigned char cmnd[MAX_COMMAND_SIZE];
-  struct scsi_generic *device=&scsi_generics[dev];
-
-  if ((i=verify_area(VERIFY_READ,buf,count)))
-   return i;
-  /*
-   * The minimum scsi command length is 6 bytes.  If we get anything less than this,
-   * it is clearly bogus.
-   */
-  if (count<(sizeof(struct sg_header) + 6))
-   return -EIO;
-  /* make sure we can fit */
-  while(device->pending)
-   {
-    if (filp->f_flags & O_NONBLOCK)
-     return -EWOULDBLOCK;
+{
+    int dev=MINOR(inode->i_rdev);
+    Scsi_Cmnd *SCpnt;
+    int bsize,size,amt,i;
+    unsigned char opcode;
+    unsigned char cmnd[MAX_COMMAND_SIZE];
+    struct scsi_generic *device=&scsi_generics[dev];
+    
+    if ((i=verify_area(VERIFY_READ,buf,count)))
+       return i;
+    /*
+     * The minimum scsi command length is 6 bytes.  If we get anything less than this,
+     * it is clearly bogus.
+     */
+    if (count<(sizeof(struct sg_header) + 6))
+       return -EIO;
+    /* make sure we can fit */
+    while(device->pending)
+    {
+       if (filp->f_flags & O_NONBLOCK)
+           return -EWOULDBLOCK;
 #ifdef DEBUG
-    printk("sg_write: sleeping on pending request\n");
+       printk("sg_write: sleeping on pending request\n");
 #endif     
-    interruptible_sleep_on(&device->write_wait);
-    if (current->signal & ~current->blocked)
-     return -ERESTARTSYS;
-   }
-  device->pending=1;
-  device->complete=0;
-  memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
-  /* fix input size */
-  device->header.pack_len=count;
-  buf+=sizeof(struct sg_header);
-  bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len;
-  bsize-=sizeof(struct sg_header);
-  amt=bsize;
-  if (!bsize)
-   bsize++;
-  bsize=(bsize+511) & ~511;
-  if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
-   {
-    device->pending=0;
-    wake_up(&device->write_wait);
-    return -ENOMEM;
-   }
+       interruptible_sleep_on(&device->write_wait);
+       if (current->signal & ~current->blocked)
+           return -ERESTARTSYS;
+    }
+    device->pending=1;
+    device->complete=0;
+    memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
+    /* fix input size */
+    device->header.pack_len=count;
+    buf+=sizeof(struct sg_header);
+    bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len;
+    bsize-=sizeof(struct sg_header);
+    amt=bsize;
+    if (!bsize)
+       bsize++;
+    bsize=(bsize+511) & ~511;
+    if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
+    {
+       device->pending=0;
+       wake_up(&device->write_wait);
+       return -ENOMEM;
+    }
 #ifdef DEBUG
-  printk("allocating device\n");
+    printk("allocating device\n");
 #endif
-  if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
-   {
-    device->pending=0;
-    wake_up(&device->write_wait);
-    sg_free(device->buff,device->buff_len);
-    device->buff = NULL;
-    return -EWOULDBLOCK;
-   } 
+    if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
+    {
+       device->pending=0;
+       wake_up(&device->write_wait);
+       sg_free(device->buff,device->buff_len);
+       device->buff = NULL;
+       return -EWOULDBLOCK;
+    
 #ifdef DEBUG
-  printk("device allocated\n");
+    printk("device allocated\n");
 #endif    
-  /* now issue command */
-  SCpnt->request.dev=dev;
-  SCpnt->sense_buffer[0]=0;
-  opcode = get_user(buf);
-  size=COMMAND_SIZE(opcode);
-  if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
-  SCpnt->cmd_len = size;
-  /*
-   * Verify that the user has actually passed enough bytes for this command.
-   */
-  if (count<(sizeof(struct sg_header) + size))
+    /* now issue command */
+    SCpnt->request.dev=dev;
+    SCpnt->sense_buffer[0]=0;
+    opcode = get_user(buf);
+    size=COMMAND_SIZE(opcode);
+    if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
+    SCpnt->cmd_len = size;
+    amt-=device->header.pack_len>device->header.reply_len ? size : 0;
+    /*
+     * Verify that the user has actually passed enough bytes for this command.
+     */
+    if (count<(sizeof(struct sg_header) + size))
     {
-      device->pending=0;
-      wake_up(&device->write_wait);
-      sg_free(device->buff,device->buff_len);
-      device->buff = NULL;
-      return -EIO;
+       device->pending=0;
+       wake_up(&device->write_wait);
+       sg_free(device->buff,device->buff_len);
+       device->buff = NULL;
+       return -EIO;
     }
-
-  memcpy_fromfs(cmnd,buf,size);
-  buf+=size;
-  memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
-  cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5);
+    
+    memcpy_fromfs(cmnd,buf,size);
+    buf+=size;
+    memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
+    cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5);
 #ifdef DEBUG
-  printk("do cmd\n");
+    printk("do cmd\n");
 #endif
-  scsi_do_cmd (SCpnt,(void *) cmnd,
-               (void *) device->buff,amt,
-              sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
+    scsi_do_cmd (SCpnt,(void *) cmnd,
+                (void *) device->buff,amt,
+                sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
 #ifdef DEBUG
-  printk("done cmd\n");
+    printk("done cmd\n");
 #endif               
-  return count;
- }
+    return count;
+}
 
 static struct file_operations sg_fops = {
-   NULL,            /* lseek */
-   sg_read,         /* read */
-   sg_write,        /* write */
-   NULL,            /* readdir */
-   NULL,            /* select */
-   sg_ioctl,        /* ioctl */
-   NULL,            /* mmap */
-   sg_open,         /* open */
-   sg_close,        /* release */
-   NULL                    /* fsync */
+    NULL,            /* lseek */
+    sg_read,         /* read */
+    sg_write,        /* write */
+    NULL,            /* readdir */
+    NULL,            /* select */
+    sg_ioctl,        /* ioctl */
+    NULL,            /* mmap */
+    sg_open,         /* open */
+    sg_close,        /* release */
+    NULL             /* fsync */
 };
 
 
 static int sg_detect(Scsi_Device * SDp){
-  ++sg_template.dev_noticed;
-  return 1;
+    ++sg_template.dev_noticed;
+    return 1;
 }
 
 /* Driver initialization */
 static void sg_init()
- {
-   static int sg_registered = 0;
-   
-   if (sg_template.dev_noticed == 0) return;
-
-   if(!sg_registered) {
-     if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) 
-       {
-        printk("Unable to get major %d for generic SCSI device\n",
-               SCSI_GENERIC_MAJOR);
-        return;
-       }
-     sg_registered++;
-   }
-
-   /* If we have already been through here, return */
-   if(scsi_generics) return;
-
+{
+    static int sg_registered = 0;
+    
+    if (sg_template.dev_noticed == 0) return;
+    
+    if(!sg_registered) {
+       if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) 
+       {
+           printk("Unable to get major %d for generic SCSI device\n",
+                  SCSI_GENERIC_MAJOR);
+           return;
+       }
+       sg_registered++;
+    }
+    
+    /* If we have already been through here, return */
+    if(scsi_generics) return;
+    
 #ifdef DEBUG
-  printk("sg: Init generic device.\n");
+    printk("sg: Init generic device.\n");
 #endif
-
+    
 #ifdef SG_BIG_BUFF
-  big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA);
+    big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA);
 #endif
-
-   scsi_generics = (struct scsi_generic *) 
-     scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) 
-                     * sizeof(struct scsi_generic), GFP_ATOMIC);
-   memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS)
-         * sizeof(struct scsi_generic));
-
-   sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS;
- }
+    
+    scsi_generics = (struct scsi_generic *) 
+       scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) 
+                        * sizeof(struct scsi_generic), GFP_ATOMIC);
+    memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS)
+          * sizeof(struct scsi_generic));
+    
+    sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS;
+}
 
 static int sg_attach(Scsi_Device * SDp)
- {
-   struct scsi_generic * gpnt;
-   int i;
-
-   if(sg_template.nr_dev >= sg_template.dev_max) 
-     {
-       SDp->attached--;
-       return 1;
-     }
+{
+    struct scsi_generic * gpnt;
+    int i;
+    
+    if(sg_template.nr_dev >= sg_template.dev_max) 
+    {
+       SDp->attached--;
+       return 1;
+    }
+    
+    for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
+       if(!gpnt->device) break;
+    
+    if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)");
+    
+    scsi_generics[i].device=SDp;
+    scsi_generics[i].users=0;
+    scsi_generics[i].generic_wait=NULL;
+    scsi_generics[i].read_wait=NULL;
+    scsi_generics[i].write_wait=NULL;
+    scsi_generics[i].buff=NULL;
+    scsi_generics[i].exclude=0;
+    scsi_generics[i].pending=0;
+    scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT;
+    sg_template.nr_dev++;
+    return 0;
+};
 
-   for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
-     if(!gpnt->device) break;
 
-   if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)");
 
-   scsi_generics[i].device=SDp;
-   scsi_generics[i].users=0;
-   scsi_generics[i].generic_wait=NULL;
-   scsi_generics[i].read_wait=NULL;
-   scsi_generics[i].write_wait=NULL;
-   scsi_generics[i].buff=NULL;
-   scsi_generics[i].exclude=0;
-   scsi_generics[i].pending=0;
-   scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT;
-   sg_template.nr_dev++;
-   return 0;
- };
+static void sg_detach(Scsi_Device * SDp)
+{
+    struct scsi_generic * gpnt;
+    int i;
+    
+    for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
+       if(gpnt->device == SDp) {
+           gpnt->device = NULL;
+           SDp->attached--;
+           sg_template.nr_dev--;
+           return;
+       }
+    return;
+}
 
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
 
+int init_module(void) {
+    sg_template.usage_count = &mod_use_count_;
+    return scsi_register_module(MODULE_SCSI_DEV, &sg_template);
+}
 
-static void sg_detach(Scsi_Device * SDp)
+void cleanup_module( void) 
 {
-  struct scsi_generic * gpnt;
-  int i;
-  
-  for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
-    if(gpnt->device == SDp) {
-      gpnt->device = NULL;
-      SDp->attached--;
-      sg_template.nr_dev--;
-      return;
+    if (MOD_IN_USE) {
+       printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+       return;
+    }
+    scsi_unregister_module(MODULE_SCSI_DEV, &sg_template);
+    unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
+    
+    if(scsi_generics != NULL) {
+       scsi_init_free((char *) scsi_generics,
+                      (sg_template.dev_noticed + SG_EXTRA_DEVS) 
+                      * sizeof(struct scsi_generic));
     }
-  return;
+    sg_template.dev_max = 0;
+#ifdef SG_BIG_BUFF
+    if(big_buff != NULL)
+       scsi_init_free(big_buff, SG_BIG_BUFF);
+#endif
 }
+#endif /* MODULE */
 
 /*
- * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Overrides for Emacs so that we almost 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-indent-level: 4
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
  * End:
  */
index 241a132f8618e99d8d5443ca37fc331b2ebe2aec..dc7d94684faf31a67ab20409e7f66ff657678467 100644 (file)
@@ -31,6 +31,6 @@ struct sg_header
 #define SG_DEFAULT_RETRIES 1
 
 #define SG_MAX_QUEUE 4 /* maximum outstanding request, arbitrary, may be
-                          changed if sufficient DMA buffer room available */
+                         changed if sufficient DMA buffer room available */
 
 #define SG_BIG_BUFF 32768
index 5d58df15a479d72308f57bff3292b1bb3f561a8f..f5538dc007c320da98cfbdd9a6321feeeae63563 100644 (file)
@@ -1,20 +1,18 @@
 /*
- *      sr.c Copyright (C) 1992 David Giller
+ *  sr.c Copyright (C) 1992 David Giller
  *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
- *      adapted from:
+ *  adapted from:
  *     sd.c Copyright (C) 1992 Drew Eckhardt 
  *     Linux scsi disk driver by
- *             Drew Eckhardt 
+ *             Drew Eckhardt <drew@colorado.edu>
  *
- *     <drew@colorado.edu>
+ *      Modified by Eric Youngdale ericy@cais.com to
+ *      add scatter-gather, multiple outstanding request, and other
+ *      enhancements.
  *
- *       Modified by Eric Youngdale ericy@cais.com to
- *       add scatter-gather, multiple outstanding request, and other
- *       enhancements.
- *
- *      Modified by Eric Youngdale eric@aib.com to support loadable
- *      low-level scsi drivers.
+ *         Modified by Eric Youngdale eric@aib.com to support loadable
+ *         low-level scsi drivers.
  */
 
 #include <linux/fs.h>
@@ -43,12 +41,12 @@ static int sr_attach(Scsi_Device *);
 static int sr_detect(Scsi_Device *);
 static void sr_detach(Scsi_Device *);
 
-struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", TYPE_ROM, 
-                                            SCSI_CDROM_MAJOR, 0, 0, 0, 1,
-                                            sr_detect, sr_init,
-                                            sr_finish, sr_attach, sr_detach};
+struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM, 
+                                              SCSI_CDROM_MAJOR, 0, 0, 0, 1,
+                                              sr_detect, sr_init,
+                                              sr_finish, sr_attach, sr_detach};
 
-Scsi_CD * scsi_CDs;
+Scsi_CD * scsi_CDs = NULL;
 static int * sr_sizes;
 
 static int * sr_blocksizes;
@@ -65,21 +63,22 @@ static void sr_release(struct inode * inode, struct file * file)
 {
        sync_dev(inode->i_rdev);
        if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count)
-         sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+       sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
        if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
-         (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
+       (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
+       if(sr_template.usage_count) (*sr_template.usage_count)--;
 }
 
 static struct file_operations sr_fops = 
 {
        NULL,                   /* lseek - default */
        block_read,             /* read - general block-dev read */
-       block_write,            /* write - general block-dev write */
+       block_write,    /* write - general block-dev write */
        NULL,                   /* readdir - bad */
        NULL,                   /* select */
        sr_ioctl,               /* ioctl */
        NULL,                   /* mmap */
-       sr_open,                /* special open code */
+       sr_open,        /* special open code */
        sr_release,             /* release */
        NULL,                   /* fsync */
        NULL,                   /* fasync */
@@ -101,33 +100,33 @@ int check_cdrom_media_change(dev_t full_dev){
        int retval, target;
        struct inode inode;
        int flag = 0;
-
+    
        target =  MINOR(full_dev);
-
+    
        if (target >= sr_template.nr_dev) {
                printk("CD-ROM request error: invalid device.\n");
                return 0;
        };
-
+    
        inode.i_rdev = full_dev;  /* This is all we really need here */
        retval = sr_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
-
+    
        if(retval){ /* Unable to test, unit probably not ready.  This usually
-                    means there is no disc in the drive.  Mark as changed,
-                    and we will figure it out later once the drive is
-                    available again.  */
-
-         scsi_CDs[target].device->changed = 1;
-         return 1; /* This will force a flush, if called from
-                      check_disk_change */
+                * means there is no disc in the drive.  Mark as changed,
+                * and we will figure it out later once the drive is
+                * available again.  */
+       
+       scsi_CDs[target].device->changed = 1;
+       return 1; /* This will force a flush, if called from
+                  * check_disk_change */
        };
-
+    
        retval = scsi_CDs[target].device->changed;
        if(!flag) {
-         scsi_CDs[target].device->changed = 0;
-         /* If the disk changed, the capacity will now be different,
-            so we force a re-read of this information */
-         if (retval) scsi_CDs[target].needs_sector_size = 1;
+       scsi_CDs[target].device->changed = 0;
+       /* If the disk changed, the capacity will now be different,
+        * so we force a re-read of this information */
+       if (retval) scsi_CDs[target].needs_sector_size = 1;
        };
        return retval;
 }
@@ -141,100 +140,100 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
 {
        int result = SCpnt->result;
        int this_count = SCpnt->this_count;
-
+    
 #ifdef DEBUG
        printk("sr.c done: %x %x\n",result, SCpnt->request.bh->b_data);
 #endif
        if (!result)
-               { /* No error */
-                 if (SCpnt->use_sg == 0) {
+    { /* No error */
+       if (SCpnt->use_sg == 0) {
                    if (SCpnt->buffer != SCpnt->request.buffer)
-                     {
-                       int offset;
-                       offset = (SCpnt->request.sector % 4) << 9;
-                       memcpy((char *)SCpnt->request.buffer, 
-                              (char *)SCpnt->buffer + offset, 
-                              this_count << 9);
-                       /* Even though we are not using scatter-gather, we look
-                          ahead and see if there is a linked request for the
-                          other half of this buffer.  If there is, then satisfy
-                          it. */
-                       if((offset == 0) && this_count == 2 &&
-                          SCpnt->request.nr_sectors > this_count && 
-                          SCpnt->request.bh &&
-                          SCpnt->request.bh->b_reqnext &&
-                          SCpnt->request.bh->b_reqnext->b_size == 1024) {
-                         memcpy((char *)SCpnt->request.bh->b_reqnext->b_data, 
-                                (char *)SCpnt->buffer + 1024, 
-                                1024);
-                         this_count += 2;
-                       };
-                       
-                       scsi_free(SCpnt->buffer, 2048);
-                     }
-                 } else {
+           {
+               int offset;
+               offset = (SCpnt->request.sector % 4) << 9;
+               memcpy((char *)SCpnt->request.buffer, 
+                      (char *)SCpnt->buffer + offset, 
+                      this_count << 9);
+               /* Even though we are not using scatter-gather, we look
+                * ahead and see if there is a linked request for the
+                * other half of this buffer.  If there is, then satisfy
+                * it. */
+               if((offset == 0) && this_count == 2 &&
+                  SCpnt->request.nr_sectors > this_count && 
+                  SCpnt->request.bh &&
+                  SCpnt->request.bh->b_reqnext &&
+                  SCpnt->request.bh->b_reqnext->b_size == 1024) {
+                   memcpy((char *)SCpnt->request.bh->b_reqnext->b_data, 
+                          (char *)SCpnt->buffer + 1024, 
+                          1024);
+                   this_count += 2;
+               };
+               
+               scsi_free(SCpnt->buffer, 2048);
+           }
+       } else {
                    struct scatterlist * sgpnt;
                    int i;
                    sgpnt = (struct scatterlist *) SCpnt->buffer;
                    for(i=0; i<SCpnt->use_sg; i++) {
-                     if (sgpnt[i].alt_address) {
-                       if (sgpnt[i].alt_address != sgpnt[i].address) {
-                         memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
-                       };
-                       scsi_free(sgpnt[i].address, sgpnt[i].length);
-                     };
+               if (sgpnt[i].alt_address) {
+                   if (sgpnt[i].alt_address != sgpnt[i].address) {
+                       memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+                   };
+                   scsi_free(sgpnt[i].address, sgpnt[i].length);
+               };
                    };
                    scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
                    if(SCpnt->request.sector % 4) this_count -= 2;
-/* See   if there is a padding record at the end that needs to be removed */
+           /* See   if there is a padding record at the end that needs to be removed */
                    if(this_count > SCpnt->request.nr_sectors)
-                     this_count -= 2;
-                 };
-
+               this_count -= 2;
+       };
+       
 #ifdef DEBUG
                printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors, 
                       this_count);
 #endif
                if (SCpnt->request.nr_sectors > this_count)
-                       {        
+       {        
                        SCpnt->request.errors = 0;
                        if (!SCpnt->request.bh)
                            panic("sr.c: linked page request (%lx %x)",
-                                 SCpnt->request.sector, this_count);
-                       }
-
-                 SCpnt = end_scsi_request(SCpnt, 1, this_count);  /* All done */
-                 requeue_sr_request(SCpnt);
-                 return;
-               } /* Normal completion */
-
+                     SCpnt->request.sector, this_count);
+       }
+       
+       SCpnt = end_scsi_request(SCpnt, 1, this_count);  /* All done */
+       requeue_sr_request(SCpnt);
+       return;
+    } /* Normal completion */
+    
        /* We only come through here if we have an error of some kind */
-
-/* Free up any indirection buffers we allocated for DMA purposes. */
+    
+    /* Free up any indirection buffers we allocated for DMA purposes. */
        if (SCpnt->use_sg) {
-         struct scatterlist * sgpnt;
-         int i;
-         sgpnt = (struct scatterlist *) SCpnt->buffer;
-         for(i=0; i<SCpnt->use_sg; i++) {
+       struct scatterlist * sgpnt;
+       int i;
+       sgpnt = (struct scatterlist *) SCpnt->buffer;
+       for(i=0; i<SCpnt->use_sg; i++) {
            if (sgpnt[i].alt_address) {
-             scsi_free(sgpnt[i].address, sgpnt[i].length);
+               scsi_free(sgpnt[i].address, sgpnt[i].length);
            };
-         };
-         scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
+       };
+       scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
        } else {
-         if (SCpnt->buffer != SCpnt->request.buffer)
+       if (SCpnt->buffer != SCpnt->request.buffer)
            scsi_free(SCpnt->buffer, SCpnt->bufflen);
        };
-
+    
        if (driver_byte(result) != 0) {
                if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
                        if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
-                               /* detected disc change.  set a bit and quietly refuse  */
-                               /* further access.                                      */
-                   
+                               /* detected disc change.  set a bit and quietly refuse 
+                                * further access.      */
+               
                                scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->changed = 1;
                                SCpnt = end_scsi_request(SCpnt, 0, this_count);
-                               requeue_sr_request(SCpnt);
+               requeue_sr_request(SCpnt);
                                return;
                        }
                }
@@ -250,35 +249,35 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
                                result = 0;
                                return;
                        } else {
-                         SCpnt = end_scsi_request(SCpnt, 0, this_count);
-                         requeue_sr_request(SCpnt); /* Do next request */
-                         return;
+               SCpnt = end_scsi_request(SCpnt, 0, this_count);
+               requeue_sr_request(SCpnt); /* Do next request */
+               return;
                        }
-
+           
                }
-
+       
                if (SCpnt->sense_buffer[2] == NOT_READY) {
                        printk("CDROM not ready.  Make sure you have a disc in the drive.\n");
                        SCpnt = end_scsi_request(SCpnt, 0, this_count);
                        requeue_sr_request(SCpnt); /* Do next request */
                        return;
                };
-             }
+    }
        
        /* We only get this far if we have an error we have not recognized */
        if(result) {
-         printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", 
-                scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->host->host_no, 
-                scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->id,
-                scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->lun,
-                result);
+       printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", 
+              scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->host->host_no, 
+              scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->id,
+              scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->lun,
+              result);
            
-         if (status_byte(result) == CHECK_CONDITION)
-                 print_sense("sr", SCpnt);
-         
-         SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
-         requeue_sr_request(SCpnt);
-  }
+       if (status_byte(result) == CHECK_CONDITION)
+           print_sense("sr", SCpnt);
+       
+       SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
+       requeue_sr_request(SCpnt);
+    }
 }
 
 /*
@@ -300,200 +299,201 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
 
 static void sr_photocd(struct inode *inode)
 {
-  unsigned long   sector,min,sec,frame;
-  unsigned char   buf[40];    /* the buffer for the ioctl */
-  unsigned char   *cmd;       /* the scsi-command */
-  unsigned char   *send;      /* the data we send to the drive ... */
-  unsigned char   *rec;       /* ... and get back */
-  int             rc,is_xa,no_multi;
-
-  if (scsi_CDs[MINOR(inode->i_rdev)].xa_flags & 0x02) {
+    unsigned long   sector,min,sec,frame;
+    unsigned char   buf[40];    /* the buffer for the ioctl */
+    unsigned char   *cmd;       /* the scsi-command */
+    unsigned char   *send;      /* the data we send to the drive ... */
+    unsigned char   *rec;       /* ... and get back */
+    int             rc,is_xa,no_multi;
+    
+    if (scsi_CDs[MINOR(inode->i_rdev)].xa_flags & 0x02) {
 #ifdef DEBUG
-    printk("sr_photocd: CDROM and/or the driver does not support multisession CD's");
+       printk("sr_photocd: CDROM and/or the driver does not support multisession CD's");
 #endif
-    return;
-  }
-  
-  if (!suser()) {
-    /* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed for me.
-     * That's why mpcd_sector will be initialized with zero, because I'm not
-     * able to get the right value. Necessary only if access_count is 1, else
-     * no disk change happened since the last call of this function and we can
-     * keep the old value.
-     */
-    if (1 == scsi_CDs[MINOR(inode->i_rdev)].device->access_count) {
-      scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = 0;
-      scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
+       return;
     }
-    return;
-  }
-
-  sector   = 0;
-  is_xa    = 0;
-  no_multi = 0;
-  cmd = rec = &buf[8];
-
-  switch(scsi_CDs[MINOR(inode->i_rdev)].device->manufacturer) {
-
-  case SCSI_MAN_NEC:
+    
+    if (!suser()) {
+       /* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed for me.
+        * That's why mpcd_sector will be initialized with zero, because I'm not
+        * able to get the right value. Necessary only if access_count is 1, else
+        * no disk change happened since the last call of this function and we can
+        * keep the old value.
+        */
+       if (1 == scsi_CDs[MINOR(inode->i_rdev)].device->access_count) {
+           scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = 0;
+           scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
+       }
+       return;
+    }
+    
+    sector   = 0;
+    is_xa    = 0;
+    no_multi = 0;
+    cmd = rec = &buf[8];
+    
+    switch(scsi_CDs[MINOR(inode->i_rdev)].device->manufacturer) {
+       
+    case SCSI_MAN_NEC:
 #ifdef DEBUG
-    printk("sr_photocd: use NEC code\n");
+       printk("sr_photocd: use NEC code\n");
 #endif
-    memset(buf,0,40);
-    *((unsigned long*)buf)   = 0x0;   /* we send nothing...     */
-    *((unsigned long*)buf+1) = 0x16;  /* and receive 0x16 bytes */
-    cmd[0] = 0xde;
-    cmd[1] = 0x03;
-    cmd[2] = 0xb0;
-    rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+       memset(buf,0,40);
+       *((unsigned long*)buf)   = 0x0;   /* we send nothing...     */
+       *((unsigned long*)buf+1) = 0x16;  /* and receive 0x16 bytes */
+       cmd[0] = 0xde;
+       cmd[1] = 0x03;
+       cmd[2] = 0xb0;
+       rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
                           SCSI_IOCTL_SEND_COMMAND, buf);
-    if (rc != 0) {
-      printk("sr_photocd: ioctl error (NEC): 0x%x\n",rc);
-      break;
-    }
-    if (rec[14] != 0 && rec[14] != 0xb0) {
-      printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
-      no_multi = 1;
-      break;
-    }
-    min   = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;
-    sec   = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;
-    frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;
-    sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
-    is_xa  = (rec[14] == 0xb0);
+       if (rc != 0) {
+           printk("sr_photocd: ioctl error (NEC): 0x%x\n",rc);
+           break;
+       }
+       if (rec[14] != 0 && rec[14] != 0xb0) {
+           printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
+           no_multi = 1;
+           break;
+       }
+       min   = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;
+       sec   = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;
+       frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;
+       sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+       is_xa  = (rec[14] == 0xb0);
 #ifdef DEBUG
-    if (sector) {
-      printk("sr_photocd: multisession CD detected. start: %lu\n",sector);
-    }
+       if (sector) {
+           printk("sr_photocd: multisession CD detected. start: %lu\n",sector);
+       }
 #endif
-    break;
-
-  case SCSI_MAN_TOSHIBA:
+       break;
+       
+    case SCSI_MAN_TOSHIBA:
 #ifdef DEBUG
-    printk("sr_photocd: use TOSHIBA code\n");
+       printk("sr_photocd: use TOSHIBA code\n");
 #endif
-    
-    /* we request some disc information (is it a XA-CD ?,
-       where starts the last session ?) */
-    memset(buf,0,40);
-    *((unsigned long*)buf)   = 0;
-    *((unsigned long*)buf+1) = 4;  /* we receive 4 bytes from the drive */
-    cmd[0] = 0xc7;
-    cmd[1] = 3;
-    rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-                          SCSI_IOCTL_SEND_COMMAND, buf);
-    if (rc != 0) {
-      if (rc == 0x28000002) {
-       /* Got a "not ready" - error. No chance to find out if this is
-          because there is no CD in the drive or because the drive
-          don't knows multisession CD's. So I need to do an extra check... */
-       if (kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-                             SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
-         printk("sr_photocd: drive not ready\n");
-       } else {
-         printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
-         no_multi = 1;
+       
+       /* we request some disc information (is it a XA-CD ?,
+        * where starts the last session ?) */
+       memset(buf,0,40);
+       *((unsigned long*)buf)   = 0;
+       *((unsigned long*)buf+1) = 4;  /* we receive 4 bytes from the drive */
+       cmd[0] = 0xc7;
+       cmd[1] = 3;
+       rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+                              SCSI_IOCTL_SEND_COMMAND, buf);
+       if (rc != 0) {
+           if (rc == 0x28000002) {
+               /* Got a "not ready" - error. No chance to find out if this is
+                * because there is no CD in the drive or because the drive
+                * don't knows multisession CD's. So I need to do an extra check... */
+               if (kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+                                     SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
+                   printk("sr_photocd: drive not ready\n");
+               } else {
+                   printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
+                   no_multi = 1;
+               }
+           } else
+               printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
+           break; /* if the first ioctl fails, we don't call the second one */
        }
-      } else
-       printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
-      break; /* if the first ioctl fails, we don't call the second one */
-    }
-    is_xa  = (rec[0] == 0x20);
-    min    = (unsigned long) rec[1]/16*10 + (unsigned long) rec[1]%16;
-    sec    = (unsigned long) rec[2]/16*10 + (unsigned long) rec[2]%16;
-    frame  = (unsigned long) rec[3]/16*10 + (unsigned long) rec[3]%16;
-    sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
-    if (sector) {
-      sector -= CD_BLOCK_OFFSET;
+       is_xa  = (rec[0] == 0x20);
+       min    = (unsigned long) rec[1]/16*10 + (unsigned long) rec[1]%16;
+       sec    = (unsigned long) rec[2]/16*10 + (unsigned long) rec[2]%16;
+       frame  = (unsigned long) rec[3]/16*10 + (unsigned long) rec[3]%16;
+       sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+       if (sector) {
+           sector -= CD_BLOCK_OFFSET;
 #ifdef DEBUG
-      printk("sr_photocd: multisession CD detected: start: %lu\n",sector);
+           printk("sr_photocd: multisession CD detected: start: %lu\n",sector);
 #endif
-    }
-
-    /* now we do a get_density... */
-    memset(buf,0,40);
-    *((unsigned long*)buf)   = 0;
-    *((unsigned long*)buf+1) = 12;
-    cmd[0] = 0x1a;
-    cmd[2] = 1;
-    cmd[4] = 12;
-    rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-                          SCSI_IOCTL_SEND_COMMAND, buf);
-    if (rc != 0) {
-      printk("sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc);
-      break;
-    }
+       }
+       
+       /* now we do a get_density... */
+       memset(buf,0,40);
+       *((unsigned long*)buf)   = 0;
+       *((unsigned long*)buf+1) = 12;
+       cmd[0] = 0x1a;
+       cmd[2] = 1;
+       cmd[4] = 12;
+       rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+                              SCSI_IOCTL_SEND_COMMAND, buf);
+       if (rc != 0) {
+           printk("sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc);
+           break;
+       }
 #ifdef DEBUG
-    printk("sr_photocd: get_density: 0x%x\n",rec[4]);
+       printk("sr_photocd: get_density: 0x%x\n",rec[4]);
 #endif
-    
-    /* ...and only if necessary a set_density */
-    if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) {
+       
+       /* ...and only if necessary a set_density */
+       if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) {
 #ifdef DEBUG
-      printk("sr_photocd: doing set_density\n");
+           printk("sr_photocd: doing set_density\n");
 #endif
-      memset(buf,0,40);
-      *((unsigned long*)buf)   = 12;  /* sending 12 bytes... */
-      *((unsigned long*)buf+1) = 0;
-      cmd[0] = 0x15;
-      cmd[1] = (1 << 4);
-      cmd[4] = 12;
-      send = &cmd[6];                 /* this is a 6-Byte command          */
-      send[ 3] = 0x08;                /* the data for the command          */
-      send[ 4] = (is_xa) ? 0x81 : 0;  /* density 0x81 for XA-CD's, 0 else  */
-      send[10] = 0x08;
-      rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-                            SCSI_IOCTL_SEND_COMMAND, buf);
-      if (rc != 0) {
-       printk("sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
-      }
-      /* The set_density command may have changed the sector size or capacity. */
-      scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
-    }
-    break;
-
-  case SCSI_MAN_NEC_OLDCDR:
-  case SCSI_MAN_UNKNOWN:
-  default:
-    sector = 0;
-    no_multi = 1;
-    break; }
-
-  scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
-  if (is_xa)
-    scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x01;
-  else
-    scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
-  if (no_multi)
-    scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x02;
-  return;
+           memset(buf,0,40);
+           *((unsigned long*)buf)   = 12;  /* sending 12 bytes... */
+           *((unsigned long*)buf+1) = 0;
+           cmd[0] = 0x15;
+           cmd[1] = (1 << 4);
+           cmd[4] = 12;
+           send = &cmd[6];                 /* this is a 6-Byte command          */
+           send[ 3] = 0x08;                /* the data for the command          */
+           send[ 4] = (is_xa) ? 0x81 : 0;  /* density 0x81 for XA-CD's, 0 else  */
+           send[10] = 0x08;
+           rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+                                  SCSI_IOCTL_SEND_COMMAND, buf);
+           if (rc != 0) {
+               printk("sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
+           }
+           /* The set_density command may have changed the sector size or capacity. */
+           scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
+       }
+       break;
+       
+    case SCSI_MAN_NEC_OLDCDR:
+    case SCSI_MAN_UNKNOWN:
+    default:
+       sector = 0;
+       no_multi = 1;
+       break; }
+    
+    scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
+    if (is_xa)
+       scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x01;
+    else
+       scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
+    if (no_multi)
+       scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x02;
+    return;
 }
 
 static int sr_open(struct inode * inode, struct file * filp)
 {
        if(MINOR(inode->i_rdev) >= sr_template.nr_dev || 
           !scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO;   /* No such device */
-
+    
        if (filp->f_mode & 2)  
            return -EROFS;
-
-        check_disk_change(inode->i_rdev);
-
+    
+    check_disk_change(inode->i_rdev);
+    
        if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
-         sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
+       sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
        if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
-         (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;
-
+       (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;
+       if(sr_template.usage_count) (*sr_template.usage_count)++;
+    
        sr_photocd(inode);
-
+    
        /* If this device did not have media in the drive at boot time, then
-          we would have been unable to get the sector size.  Check to see if
-          this is the case, and try again.
-          */
-
+        * we would have been unable to get the sector size.  Check to see if
+        * this is the case, and try again.
+     */
+    
        if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)
-         get_sectorsize(MINOR(inode->i_rdev));
-
+       get_sectorsize(MINOR(inode->i_rdev));
+    
        return 0;
 }
 
@@ -502,67 +502,67 @@ static int sr_open(struct inode * inode, struct file * filp)
  * do_sr_request() is the request handler function for the sr driver.  Its function in life 
  * is to take block device requests, and translate them to SCSI commands.
  */
-       
+
 static void do_sr_request (void)
 {
-  Scsi_Cmnd * SCpnt = NULL;
-  struct request * req = NULL;
-  unsigned long flags;
-  int flag = 0;
-
-  while (1==1){
-    save_flags(flags);
-    cli();
-    if (CURRENT != NULL && CURRENT->dev == -1) {
-      restore_flags(flags);
-      return;
-    };
-    
-    INIT_SCSI_REQUEST;
-
-    if (flag++ == 0)
-      SCpnt = allocate_device(&CURRENT,
-                             scsi_CDs[DEVICE_NR(MINOR(CURRENT->dev))].device, 0); 
-    else SCpnt = NULL;
-    restore_flags(flags);
-
-/* This is a performance enhancement.  We dig down into the request list and
-   try and find a queueable request (i.e. device not busy, and host able to
-   accept another command.  If we find one, then we queue it. This can
-   make a big difference on systems with more than one disk drive.  We want
-   to have the interrupts off when monkeying with the request list, because
-   otherwise the kernel might try and slip in a request in between somewhere. */
-
-    if (!SCpnt && sr_template.nr_dev > 1){
-      struct request *req1;
-      req1 = NULL;
-      save_flags(flags);
-      cli();
-      req = CURRENT;
-      while(req){
-       SCpnt = request_queueable(req,
-                                 scsi_CDs[DEVICE_NR(MINOR(req->dev))].device);
-       if(SCpnt) break;
-       req1 = req;
-       req = req->next;
-      };
-      if (SCpnt && req->dev == -1) {
-       if (req == CURRENT) 
-         CURRENT = CURRENT->next;
-       else
-         req1->next = req->next;
-      };
-      restore_flags(flags);
-    };
+    Scsi_Cmnd * SCpnt = NULL;
+    struct request * req = NULL;
+    unsigned long flags;
+    int flag = 0;
     
-    if (!SCpnt)
-      return; /* Could not find anything to do */
-    
-  wake_up(&wait_for_request);
+    while (1==1){
+       save_flags(flags);
+       cli();
+       if (CURRENT != NULL && CURRENT->dev == -1) {
+           restore_flags(flags);
+           return;
+       };
+       
+       INIT_SCSI_REQUEST;
+       
+       if (flag++ == 0)
+           SCpnt = allocate_device(&CURRENT,
+                                   scsi_CDs[DEVICE_NR(MINOR(CURRENT->dev))].device, 0); 
+       else SCpnt = NULL;
+       restore_flags(flags);
+       
+       /* This is a performance enhancement.  We dig down into the request list and
+        * try and find a queueable request (i.e. device not busy, and host able to
+        * accept another command.  If we find one, then we queue it. This can
+        * make a big difference on systems with more than one disk drive.  We want
+        * to have the interrupts off when monkeying with the request list, because
+        * otherwise the kernel might try and slip in a request in between somewhere. */
+       
+       if (!SCpnt && sr_template.nr_dev > 1){
+           struct request *req1;
+           req1 = NULL;
+           save_flags(flags);
+           cli();
+           req = CURRENT;
+           while(req){
+               SCpnt = request_queueable(req,
+                                         scsi_CDs[DEVICE_NR(MINOR(req->dev))].device);
+               if(SCpnt) break;
+               req1 = req;
+               req = req->next;
+           };
+           if (SCpnt && req->dev == -1) {
+               if (req == CURRENT) 
+                   CURRENT = CURRENT->next;
+               else
+                   req1->next = req->next;
+           };
+           restore_flags(flags);
+       };
+       
+       if (!SCpnt)
+           return; /* Could not find anything to do */
+       
+       wake_up(&wait_for_request);
 
-/* Queue command */
-  requeue_sr_request(SCpnt);
-  };  /* While */
+       /* Queue command */
+       requeue_sr_request(SCpnt);
+    };  /* While */
 }    
 
 void requeue_sr_request (Scsi_Cmnd * SCpnt)
@@ -570,174 +570,175 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
        unsigned int dev, block, realcount;
        unsigned char cmd[10], *buffer, tries;
        int this_count, start, end_rec;
-
+    
        tries = 2;
-
     repeat:
+    
+ repeat:
        if(!SCpnt || SCpnt->request.dev <= 0) {
-         do_sr_request();
-         return;
+       do_sr_request();
+       return;
        }
-
+    
        dev =  MINOR(SCpnt->request.dev);
        block = SCpnt->request.sector;  
        buffer = NULL;
        this_count = 0;
-
+    
        if (dev >= sr_template.nr_dev)
-               {
+    {
                /* printk("CD-ROM request error: invalid device.\n");                   */
                SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
                tries = 2;
                goto repeat;
-               }
-
+    }
+    
        if (!scsi_CDs[dev].use)
-               {
+    {
                /* printk("CD-ROM request error: device marked not in use.\n");         */
                SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
                tries = 2;
                goto repeat;
-               }
-
+    }
+    
        if (scsi_CDs[dev].device->changed)
-               {
-/* 
- * quietly refuse to do anything to a changed disc until the changed bit has been reset
- */
+    {
+       /* 
+        * quietly refuse to do anything to a changed disc 
+        * until the changed bit has been reset
+        */
                /* printk("CD-ROM has been changed.  Prohibiting further I/O.\n");      */
                SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
                tries = 2;
                goto repeat;
-               }
+    }
        
        switch (SCpnt->request.cmd)
-               {
-               case WRITE:             
-                       SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-                       goto repeat;
-                       break;
-               case READ : 
-                       cmd[0] = READ_6;
-                       break;
-               default : 
-                       panic ("Unknown sr command %d\n", SCpnt->request.cmd);
-               }
+    {
+    case WRITE:                
+       SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+       goto repeat;
+       break;
+    case READ : 
+       cmd[0] = READ_6;
+       break;
+    default : 
+       panic ("Unknown sr command %d\n", SCpnt->request.cmd);
+    }
        
        cmd[1] = (SCpnt->lun << 5) & 0xe0;
-
-/*
-           Now do the grungy work of figuring out which sectors we need, and
-          where in memory we are going to put them.
-
-          The variables we need are:
-
-          this_count= number of 512 byte sectors being read 
-          block     = starting cdrom sector to read.
-          realcount = # of cdrom sectors to read
-
-          The major difference between a scsi disk and a scsi cdrom
-is that we will always use scatter-gather if we can, because we can
-work around the fact that the buffer cache has a block size of 1024,
-and we have 2048 byte sectors.  This code should work for buffers that
-are any multiple of 512 bytes long.  */
-
+    
+    /*
+     * Now do the grungy work of figuring out which sectors we need, and
+        * where in memory we are going to put them.
+     * 
+        * The variables we need are:
+     * 
+        * this_count= number of 512 byte sectors being read 
+        * block     = starting cdrom sector to read.
+        * realcount = # of cdrom sectors to read
+     * 
+        * The major difference between a scsi disk and a scsi cdrom
+     * is that we will always use scatter-gather if we can, because we can
+     * work around the fact that the buffer cache has a block size of 1024,
+     * and we have 2048 byte sectors.  This code should work for buffers that
+     * are any multiple of 512 bytes long.  */
+    
        SCpnt->use_sg = 0;
-
+    
        if (SCpnt->host->sg_tablesize > 0 &&
            (!need_isa_buffer ||
-           dma_free_sectors >= 10)) {
-         struct buffer_head * bh;
-         struct scatterlist * sgpnt;
-         int count, this_count_max;
-         bh = SCpnt->request.bh;
-         this_count = 0;
-         count = 0;
-         this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4;
-         /* Calculate how many links we can use.  First see if we need
-          a padding record at the start */
-         this_count = SCpnt->request.sector % 4;
-         if(this_count) count++;
-         while(bh && count < SCpnt->host->sg_tablesize) {
+        dma_free_sectors >= 10)) {
+       struct buffer_head * bh;
+       struct scatterlist * sgpnt;
+       int count, this_count_max;
+       bh = SCpnt->request.bh;
+       this_count = 0;
+       count = 0;
+       this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4;
+       /* Calculate how many links we can use.  First see if we need
+        * a padding record at the start */
+       this_count = SCpnt->request.sector % 4;
+       if(this_count) count++;
+       while(bh && count < SCpnt->host->sg_tablesize) {
            if ((this_count + (bh->b_size >> 9)) > this_count_max) break;
            this_count += (bh->b_size >> 9);
            count++;
            bh = bh->b_reqnext;
-         };
-         /* Fix up in case of an odd record at the end */
-         end_rec = 0;
-         if(this_count % 4) {
+       };
+       /* Fix up in case of an odd record at the end */
+       end_rec = 0;
+       if(this_count % 4) {
            if (count < SCpnt->host->sg_tablesize) {
-             count++;
-             end_rec = (4 - (this_count % 4)) << 9;
-             this_count += 4 - (this_count % 4);
+               count++;
+               end_rec = (4 - (this_count % 4)) << 9;
+               this_count += 4 - (this_count % 4);
            } else {
-             count--;
-             this_count -= (this_count % 4);
+               count--;
+               this_count -= (this_count % 4);
            };
-         };
-         SCpnt->use_sg = count;  /* Number of chains */
-         count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes*/
-         while( count < (SCpnt->use_sg * sizeof(struct scatterlist))) 
+       };
+       SCpnt->use_sg = count;  /* Number of chains */
+       count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes*/
+       while( count < (SCpnt->use_sg * sizeof(struct scatterlist))) 
            count = count << 1;
-         SCpnt->sglist_len = count;
-         sgpnt = (struct scatterlist * ) scsi_malloc(count);
-         if (!sgpnt) {
+       SCpnt->sglist_len = count;
+       sgpnt = (struct scatterlist * ) scsi_malloc(count);
+       if (!sgpnt) {
            printk("Warning - running *really* short on DMA buffers\n");
            SCpnt->use_sg = 0;  /* No memory left - bail out */
-         } else {
+       } else {
            buffer = (unsigned char *) sgpnt;
            count = 0;
            bh = SCpnt->request.bh;
            if(SCpnt->request.sector % 4) {
-             sgpnt[count].length = (SCpnt->request.sector % 4) << 9;
-             sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
-             if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
-             sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete
-                                                                 if needed */
-             count++;
+               sgpnt[count].length = (SCpnt->request.sector % 4) << 9;
+               sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
+               if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
+               sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete
+                                                                   if needed */
+               count++;
            };
            for(bh = SCpnt->request.bh; count < SCpnt->use_sg; 
                count++, bh = bh->b_reqnext) {
-             if (bh) { /* Need a placeholder at the end of the record? */
-               sgpnt[count].address = bh->b_data;
-               sgpnt[count].length = bh->b_size;
-               sgpnt[count].alt_address = NULL;
-             } else {
-               sgpnt[count].address = (char *) scsi_malloc(end_rec);
-               if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
-               sgpnt[count].length = end_rec;
-               sgpnt[count].alt_address = sgpnt[count].address;
-               if (count+1 != SCpnt->use_sg) panic("Bad sr request list");
-               break;
-             };
-             if (((long) sgpnt[count].address) + sgpnt[count].length > 
-                 ISA_DMA_THRESHOLD & (SCpnt->host->unchecked_isa_dma)) {
-               sgpnt[count].alt_address = sgpnt[count].address;
-               /* We try and avoid exhausting the DMA pool, since it is easier
-                  to control usage here.  In other places we might have a more
-                  pressing need, and we would be screwed if we ran out */
-               if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
-                 sgpnt[count].address = NULL;
+               if (bh) { /* Need a placeholder at the end of the record? */
+                   sgpnt[count].address = bh->b_data;
+                   sgpnt[count].length = bh->b_size;
+                   sgpnt[count].alt_address = NULL;
                } else {
-                 sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
+                   sgpnt[count].address = (char *) scsi_malloc(end_rec);
+                   if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
+                   sgpnt[count].length = end_rec;
+                   sgpnt[count].alt_address = sgpnt[count].address;
+                   if (count+1 != SCpnt->use_sg) panic("Bad sr request list");
+                   break;
                };
-/* If we start running low on DMA buffers, we abort the scatter-gather
-   operation, and free all of the memory we have allocated.  We want to
-   ensure that all scsi operations are able to do at least a non-scatter/gather
-   operation */
-               if(sgpnt[count].address == NULL){ /* Out of dma memory */
-                 printk("Warning: Running low on SCSI DMA buffers");
-                 /* Try switching back to a non scatter-gather operation. */
-                 while(--count >= 0){
-                   if(sgpnt[count].alt_address) 
-                     scsi_free(sgpnt[count].address, sgpnt[count].length);
-                 };
-                 SCpnt->use_sg = 0;
-                 scsi_free(buffer, SCpnt->sglist_len);
-                 break;
-               }; /* if address == NULL */
-             };  /* if need DMA fixup */
+               if (((long) sgpnt[count].address) + sgpnt[count].length > ISA_DMA_THRESHOLD &&
+                 SCpnt->host->unchecked_isa_dma) {
+                   sgpnt[count].alt_address = sgpnt[count].address;
+                   /* We try and avoid exhausting the DMA pool, since it is easier
+                    * to control usage here.  In other places we might have a more
+                    * pressing need, and we would be screwed if we ran out */
+                   if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
+                       sgpnt[count].address = NULL;
+                   } else {
+                       sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
+                   };
+                   /* If we start running low on DMA buffers, we abort the scatter-gather
+                    * operation, and free all of the memory we have allocated.  We want to
+                    * ensure that all scsi operations are able to do at least a non-scatter/gather
+                    * operation */
+                   if(sgpnt[count].address == NULL){ /* Out of dma memory */
+                       printk("Warning: Running low on SCSI DMA buffers");
+                       /* Try switching back to a non scatter-gather operation. */
+                       while(--count >= 0){
+                           if(sgpnt[count].alt_address) 
+                               scsi_free(sgpnt[count].address, sgpnt[count].length);
+                       };
+                       SCpnt->use_sg = 0;
+                       scsi_free(buffer, SCpnt->sglist_len);
+                       break;
+                   }; /* if address == NULL */
+               };  /* if need DMA fixup */
            };  /* for loop to fill list */
 #ifdef DEBUG
            printk("SR: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector,
@@ -745,59 +746,59 @@ are any multiple of 512 bytes long.  */
                   SCpnt->request.current_nr_sectors,
                   SCpnt->request.nr_sectors);
            for(count=0; count<SCpnt->use_sg; count++)
-             printk("SGlist: %d %x %x %x\n", count,
-                    sgpnt[count].address, 
-                    sgpnt[count].alt_address, 
-                    sgpnt[count].length);
+               printk("SGlist: %d %x %x %x\n", count,
+                      sgpnt[count].address, 
+                      sgpnt[count].alt_address, 
+                      sgpnt[count].length);
 #endif
-         };  /* Able to allocate scatter-gather list */
+       };  /* Able to allocate scatter-gather list */
        };
        
        if (SCpnt->use_sg == 0){
-         /* We cannot use scatter-gather.  Do this the old fashion way */
-         if (!SCpnt->request.bh)       
+       /* We cannot use scatter-gather.  Do this the old fashion way */
+       if (!SCpnt->request.bh)         
            this_count = SCpnt->request.nr_sectors;
-         else
+       else
            this_count = (SCpnt->request.bh->b_size >> 9);
-         
-         start = block % 4;
-         if (start)
+       
+       start = block % 4;
+       if (start)
            {                             
-             this_count = ((this_count > 4 - start) ? 
-                           (4 - start) : (this_count));
-             buffer = (unsigned char *) scsi_malloc(2048);
+           this_count = ((this_count > 4 - start) ? 
+                         (4 - start) : (this_count));
+           buffer = (unsigned char *) scsi_malloc(2048);
            } 
-         else if (this_count < 4)
+       else if (this_count < 4)
            {
-             buffer = (unsigned char *) scsi_malloc(2048);
+           buffer = (unsigned char *) scsi_malloc(2048);
            }
-         else
+       else
            {
-             this_count -= this_count % 4;
-             buffer = (unsigned char *) SCpnt->request.buffer;
-             if (((long) buffer) + (this_count << 9) > ISA_DMA_THRESHOLD & 
-                 (SCpnt->host->unchecked_isa_dma))
+           this_count -= this_count % 4;
+           buffer = (unsigned char *) SCpnt->request.buffer;
+           if (((long) buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &&
+               SCpnt->host->unchecked_isa_dma)
                buffer = (unsigned char *) scsi_malloc(this_count << 9);
            }
        };
-
+    
        if (scsi_CDs[dev].sector_size == 2048)
-         block = block >> 2; /* These are the sectors that the cdrom uses */
+       block = block >> 2; /* These are the sectors that the cdrom uses */
        else
-         block = block & 0xfffffffc;
-
+       block = block & 0xfffffffc;
+    
        realcount = (this_count + 3) / 4;
-
+    
        if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2;
-
+    
        if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten) 
-               {
+    {
                if (realcount > 0xffff)
-                       {
+       {
                        realcount = 0xffff;
                        this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
-                       }
-
+       }
+       
                cmd[0] += READ_10 - READ_6 ;
                cmd[2] = (unsigned char) (block >> 24) & 0xff;
                cmd[3] = (unsigned char) (block >> 16) & 0xff;
@@ -806,269 +807,310 @@ are any multiple of 512 bytes long.  */
                cmd[6] = cmd[9] = 0;
                cmd[7] = (unsigned char) (realcount >> 8) & 0xff;
                cmd[8] = (unsigned char) realcount & 0xff;
-               }
+    }
        else
-               {
-                 if (realcount > 0xff)
-                   {
-                     realcount = 0xff;
-                     this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
-                   }
-                 
-                 cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
-                 cmd[2] = (unsigned char) ((block >> 8) & 0xff);
-                 cmd[3] = (unsigned char) block & 0xff;
-                 cmd[4] = (unsigned char) realcount;
-                 cmd[5] = 0;
-               }   
-
+    {
+       if (realcount > 0xff)
+       {
+           realcount = 0xff;
+           this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
+       }
+       
+       cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+       cmd[2] = (unsigned char) ((block >> 8) & 0xff);
+       cmd[3] = (unsigned char) block & 0xff;
+       cmd[4] = (unsigned char) realcount;
+       cmd[5] = 0;
+    }   
+    
 #ifdef DEBUG
-       
-         int i;
-         printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
-         printk("Use sg: %d\n", SCpnt->use_sg);
-         printk("Dumping command: ");
-         for(i=0; i<12; i++) printk("%2.2x ", cmd[i]);
-         printk("\n");
-       };
+    { 
+       int i;
+       printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
+       printk("Use sg: %d\n", SCpnt->use_sg);
+       printk("Dumping command: ");
+       for(i=0; i<12; i++) printk("%2.2x ", cmd[i]);
+       printk("\n");
+    };
 #endif
-
-/* Some dumb host adapters can speed transfers by knowing the
- * minimum transfersize in advance.
- *
- * We shouldn't disconnect in the middle of a sector, but the cdrom
- * sector size can be larger than the size of a buffer and the
- * transfer may be split to the size of a buffer.  So it's safe to
- * assume that we can at least transfer the minimum of the buffer
- * size (1024) and the sector size between each connect / disconnect.
- */
-
-        SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
-                        1024 : scsi_CDs[dev].sector_size;
-
+    
+    /* Some dumb host adapters can speed transfers by knowing the
    * minimum transfersize in advance.
    *
    * We shouldn't disconnect in the middle of a sector, but the cdrom
    * sector size can be larger than the size of a buffer and the
    * transfer may be split to the size of a buffer.  So it's safe to
    * assume that we can at least transfer the minimum of the buffer
    * size (1024) and the sector size between each connect / disconnect.
    */
+    
+    SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
+       1024 : scsi_CDs[dev].sector_size;
+    
        SCpnt->this_count = this_count;
        scsi_do_cmd (SCpnt, (void *) cmd, buffer, 
-                    realcount * scsi_CDs[dev].sector_size, 
-                    rw_intr, SR_TIMEOUT, MAX_RETRIES);
+                realcount * scsi_CDs[dev].sector_size, 
+                rw_intr, SR_TIMEOUT, MAX_RETRIES);
 }
 
 static int sr_detect(Scsi_Device * SDp){
-  
-  if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
-
-  printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n", 
-        sr_template.dev_noticed++,
-        SDp->host->host_no , SDp->id, SDp->lun); 
-
-        return 1;
+    
+    if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
+    
+    printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", 
+          sr_template.dev_noticed++,
+          SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); 
+    
+    return 1;
 }
 
 static int sr_attach(Scsi_Device * SDp){
-  Scsi_CD * cpnt;
-  int i;
-  
-  if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1;
-  
-  if (sr_template.nr_dev >= sr_template.dev_max)
+    Scsi_CD * cpnt;
+    int i;
+    
+    if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1;
+    
+    if (sr_template.nr_dev >= sr_template.dev_max)
     {
        SDp->attached--;
        return 1;
     }
-  
-  for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++) 
-    if(!cpnt->device) break;
-  
-  if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)");
-  
-  SDp->scsi_request_fn = do_sr_request;
-  scsi_CDs[i].device = SDp;
-  sr_template.nr_dev++;
-  if(sr_template.nr_dev > sr_template.dev_max)
-    panic ("scsi_devices corrupt (sr)");
-  return 0;
+    
+    for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++) 
+       if(!cpnt->device) break;
+    
+    if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)");
+    
+    SDp->scsi_request_fn = do_sr_request;
+    scsi_CDs[i].device = SDp;
+    sr_template.nr_dev++;
+    if(sr_template.nr_dev > sr_template.dev_max)
+       panic ("scsi_devices corrupt (sr)");
+    return 0;
 }
-     
+
 
 static void sr_init_done (Scsi_Cmnd * SCpnt)
 {
-  struct request * req;
-  
-  req = &SCpnt->request;
-  req->dev = 0xfffe; /* Busy, but indicate request done */
-  
-  if (req->sem != NULL) {
-    up(req->sem);
-  }
+    struct request * req;
+    
+    req = &SCpnt->request;
+    req->dev = 0xfffe; /* Busy, but indicate request done */
+    
+    if (req->sem != NULL) {
+       up(req->sem);
+    }
 }
 
 static void get_sectorsize(int i){
-  unsigned char cmd[10];
-  unsigned char *buffer;
-  int the_result, retries;
-  Scsi_Cmnd * SCpnt;
-  
-  buffer = (unsigned char *) scsi_malloc(512);
-  SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1);
-
-  retries = 3;
-  do {
-    cmd[0] = READ_CAPACITY;
-    cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
-    memset ((void *) &cmd[2], 0, 8);
-    SCpnt->request.dev = 0xffff;  /* Mark as really busy */
-    SCpnt->cmd_len = 0;
-    
-    memset(buffer, 0, 8);
-
-    scsi_do_cmd (SCpnt,
-                (void *) cmd, (void *) buffer,
-                512, sr_init_done,  SR_TIMEOUT,
-                MAX_RETRIES);
+    unsigned char cmd[10];
+    unsigned char *buffer;
+    int the_result, retries;
+    Scsi_Cmnd * SCpnt;
     
-    if (current == task[0])
-      while(SCpnt->request.dev != 0xfffe) barrier();
-    else
-      if (SCpnt->request.dev != 0xfffe){
-       struct semaphore sem = MUTEX_LOCKED;
-       SCpnt->request.sem = &sem;
-       down(&sem);
-       /* Hmm.. Have to ask about this */
-       while (SCpnt->request.dev != 0xfffe) schedule();
-      };
-    
-    the_result = SCpnt->result;
-    retries--;
-    
-  } while(the_result && retries);
-  
-  SCpnt->request.dev = -1;  /* Mark as not busy */
-  
-  wake_up(&SCpnt->device->device_wait); 
-
-  if (the_result) {
-    scsi_CDs[i].capacity = 0x1fffff;
-    scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
-    scsi_CDs[i].needs_sector_size = 1;
-  } else {
-    scsi_CDs[i].capacity = (buffer[0] << 24) |
-      (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
-    scsi_CDs[i].sector_size = (buffer[4] << 24) |
-      (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
-    if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048;
-    if(scsi_CDs[i].sector_size != 2048 && 
-       scsi_CDs[i].sector_size != 512) {
-      printk ("scd%d : unsupported sector size %d.\n",
-             i, scsi_CDs[i].sector_size);
-      scsi_CDs[i].capacity = 0;
-      scsi_CDs[i].needs_sector_size = 1;
+    buffer = (unsigned char *) scsi_malloc(512);
+    SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1);
+    
+    retries = 3;
+    do {
+       cmd[0] = READ_CAPACITY;
+       cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+       memset ((void *) &cmd[2], 0, 8);
+       SCpnt->request.dev = 0xffff;  /* Mark as really busy */
+       SCpnt->cmd_len = 0;
+       
+       memset(buffer, 0, 8);
+       
+       scsi_do_cmd (SCpnt,
+                    (void *) cmd, (void *) buffer,
+                    512, sr_init_done,  SR_TIMEOUT,
+                    MAX_RETRIES);
+       
+       if (current->pid == 0)
+           while(SCpnt->request.dev != 0xfffe)
+               barrier();
+       else
+           if (SCpnt->request.dev != 0xfffe){
+               struct semaphore sem = MUTEX_LOCKED;
+               SCpnt->request.sem = &sem;
+               down(&sem);
+               /* Hmm.. Have to ask about this */
+               while (SCpnt->request.dev != 0xfffe) schedule();
+           };
+       
+       the_result = SCpnt->result;
+       retries--;
+       
+    } while(the_result && retries);
+    
+    SCpnt->request.dev = -1;  /* Mark as not busy */
+    
+    wake_up(&SCpnt->device->device_wait); 
+    
+    if (the_result) {
+       scsi_CDs[i].capacity = 0x1fffff;
+       scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
+       scsi_CDs[i].needs_sector_size = 1;
+    } else {
+       scsi_CDs[i].capacity = (buffer[0] << 24) |
+           (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+       scsi_CDs[i].sector_size = (buffer[4] << 24) |
+           (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+       if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048;
+       if(scsi_CDs[i].sector_size != 2048 && 
+          scsi_CDs[i].sector_size != 512) {
+           printk ("scd%d : unsupported sector size %d.\n",
+                   i, scsi_CDs[i].sector_size);
+           scsi_CDs[i].capacity = 0;
+           scsi_CDs[i].needs_sector_size = 1;
+       };
+       if(scsi_CDs[i].sector_size == 2048)
+           scsi_CDs[i].capacity *= 4;
+       scsi_CDs[i].needs_sector_size = 0;
+       sr_sizes[i] = scsi_CDs[i].capacity;
     };
-    if(scsi_CDs[i].sector_size == 2048)
-      scsi_CDs[i].capacity *= 4;
-    scsi_CDs[i].needs_sector_size = 0;
-    sr_sizes[i] = scsi_CDs[i].capacity;
-  };
-  scsi_free(buffer, 512);
+    scsi_free(buffer, 512);
 }
 
 static void sr_init()
 {
        int i;
        static int sr_registered = 0;
-
+    
        if(sr_template.dev_noticed == 0) return;
-
+    
        if(!sr_registered) {
-         if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
+       if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
            printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
            return;
-         }
-         sr_registered++;
        }
-
+       sr_registered++;
+       }
+    
        
        if (scsi_CDs) return;
        sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
        scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
        memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
-
+    
        sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
        memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
-
+    
        sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * 
-                                                sizeof(int), GFP_ATOMIC);
+                                            sizeof(int), GFP_ATOMIC);
        for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
        blksize_size[MAJOR_NR] = sr_blocksizes;
-
+    
 }
 
 void sr_finish()
 {
-  int i;
-
+    int i;
+    
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
        blk_size[MAJOR_NR] = sr_sizes;  
-
+    
        for (i = 0; i < sr_template.nr_dev; ++i)
-               {
-                 /* If we have already seen this, then skip it.  Comes up
-                    with loadable modules. */
-                 if (scsi_CDs[i].capacity) continue;
-                 scsi_CDs[i].capacity = 0x1fffff;
-                 scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
-                 scsi_CDs[i].needs_sector_size = 1;
+    {
+       /* If we have already seen this, then skip it.  Comes up
+        * with loadable modules. */
+       if (scsi_CDs[i].capacity) continue;
+       scsi_CDs[i].capacity = 0x1fffff;
+       scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
+       scsi_CDs[i].needs_sector_size = 1;
 #if 0
-                 /* seems better to leave this for later */
-                 get_sectorsize(i);
-                 printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
+       /* seems better to leave this for later */
+       get_sectorsize(i);
+       printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
 #endif
-                 scsi_CDs[i].use = 1;
-                 scsi_CDs[i].ten = 1;
-                 scsi_CDs[i].remap = 1;
-                 sr_sizes[i] = scsi_CDs[i].capacity;
-               }
-
-
+       scsi_CDs[i].use = 1;
+       scsi_CDs[i].ten = 1;
+       scsi_CDs[i].remap = 1;
+       sr_sizes[i] = scsi_CDs[i].capacity;
+    }
+    
+    
        /* If our host adapter is capable of scatter-gather, then we increase
-          the read-ahead to 16 blocks (32 sectors).  If not, we use
-          a two block (4 sector) read ahead. */
+        * the read-ahead to 16 blocks (32 sectors).  If not, we use
+        * a two block (4 sector) read ahead. */
        if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize)
-         read_ahead[MAJOR_NR] = 32;  /* 32 sector read-ahead.  Always removable. */
+       read_ahead[MAJOR_NR] = 32;  /* 32 sector read-ahead.  Always removable. */
        else
-         read_ahead[MAJOR_NR] = 4;  /* 4 sector read-ahead */
-
+       read_ahead[MAJOR_NR] = 4;  /* 4 sector read-ahead */
+    
        return;
 }      
 
 static void sr_detach(Scsi_Device * SDp)
 {
-  Scsi_CD * cpnt;
-  int i, major;
-  
-  major = MAJOR_NR << 8;
+    Scsi_CD * cpnt;
+    int i, major;
+    
+    major = MAJOR_NR << 8;
+    
+    for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++) 
+       if(cpnt->device == SDp) {
+           /*
+            * Since the cdrom is read-only, no need to sync the device.
+            * We should be kind to our buffer cache, however.
+            */
+           invalidate_inodes(major | i);
+           invalidate_buffers(major | i);
+           
+           /*
+            * Reset things back to a sane state so that one can re-load a new
+            * driver (perhaps the same one).
+            */
+           cpnt->device = NULL;
+           cpnt->capacity = 0;
+           SDp->attached--;
+           sr_template.nr_dev--;
+           sr_template.dev_noticed--;
+           sr_sizes[i] = 0;
+           return;
+       }
+    return;
+}
+
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
 
-  for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++) 
-    if(cpnt->device == SDp) {
-      /*
-       * Since the cdrom is read-only, no need to sync the device.
-       * We should be kind to our buffer cache, however.
-       */
-      invalidate_inodes(major | i);
-      invalidate_buffers(major | i);
+char kernel_version[] = UTS_RELEASE;
 
-      /*
-       * Reset things back to a sane state so that one can re-load a new
-       * driver (perhaps the same one).
-       */
-      cpnt->device = NULL;
-      cpnt->capacity = 0;
-      SDp->attached--;
-      sr_template.nr_dev--;
-      sr_template.dev_noticed--;
-      sr_sizes[i] = 0;
-      return;
+int init_module(void) {
+    sr_template.usage_count = &mod_use_count_;
+    return scsi_register_module(MODULE_SCSI_DEV, &sr_template);
+}
+
+void cleanup_module( void) 
+{
+    int i;
+    
+    if (MOD_IN_USE) {
+       printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+       return;
     }
-  return;
+    scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
+    unregister_blkdev(SCSI_GENERIC_MAJOR, "sr");
+    if(scsi_CDs != NULL) {
+       scsi_init_free((char *) scsi_CDs,
+                      (sr_template.dev_noticed + SR_EXTRA_DEVS) 
+                      * sizeof(Scsi_CD));
+       
+       scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int));
+       scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int));
+    }
+    
+    blksize_size[MAJOR_NR] = NULL;
+    blk_dev[MAJOR_NR].request_fn = NULL;
+    blk_size[MAJOR_NR] = NULL; 
+    read_ahead[MAJOR_NR] = 0;
+    
+    sr_template.dev_max = 0;
 }
+#endif /* MODULE */
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
@@ -1077,12 +1119,14 @@ static void sr_detach(Scsi_Device * SDp)
  * of the file.
  * ---------------------------------------------------------------------------
  * Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
  * End:
  */
index f28d2ce0a2d28d5136e571a38d3cf5380f1322a7..5ca6ba54bb55939496a83fc922e96cfc079e1c0a 100644 (file)
@@ -22,14 +22,14 @@ extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
 
 static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
 {
-  struct request * req;
-  
-  req = &SCpnt->request;
-  req->dev = 0xfffe; /* Busy, but indicate request done */
-  
-  if (req->sem != NULL) {
-    up(req->sem);
-  }
+    struct request * req;
+    
+    req = &SCpnt->request;
+    req->dev = 0xfffe; /* Busy, but indicate request done */
+    
+    if (req->sem != NULL) {
+       up(req->sem);
+    }
 }
 
 /* We do our own retries because we want to know what the specific
@@ -38,39 +38,39 @@ static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
 
 static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength)
 {
-       Scsi_Cmnd * SCpnt;
-       int result;
-
-       SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
-       scsi_do_cmd(SCpnt,
-                   (void *) sr_cmd, buffer, buflength, sr_ioctl_done, 
-                   IOCTL_TIMEOUT, IOCTL_RETRIES);
-
-
-       if (SCpnt->request.dev != 0xfffe){
-         struct semaphore sem = MUTEX_LOCKED;
-         SCpnt->request.sem = &sem;
-         down(&sem);
-         /* Hmm.. Have to ask about this */
-         while (SCpnt->request.dev != 0xfffe) schedule();
-       };
-
-       result = SCpnt->result;
-
-/* Minimal error checking.  Ignore cases we know about, and report the rest. */
-       if(driver_byte(result) != 0)
-         switch(SCpnt->sense_buffer[2] & 0xf) {
-         case UNIT_ATTENTION:
+    Scsi_Cmnd * SCpnt;
+    int result;
+    
+    SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
+    scsi_do_cmd(SCpnt,
+               (void *) sr_cmd, buffer, buflength, sr_ioctl_done, 
+               IOCTL_TIMEOUT, IOCTL_RETRIES);
+    
+    
+    if (SCpnt->request.dev != 0xfffe){
+       struct semaphore sem = MUTEX_LOCKED;
+       SCpnt->request.sem = &sem;
+       down(&sem);
+       /* Hmm.. Have to ask about this */
+       while (SCpnt->request.dev != 0xfffe) schedule();
+    };
+    
+    result = SCpnt->result;
+    
+    /* Minimal error checking.  Ignore cases we know about, and report the rest. */
+    if(driver_byte(result) != 0)
+       switch(SCpnt->sense_buffer[2] & 0xf) {
+       case UNIT_ATTENTION:
            scsi_CDs[target].device->changed = 1;
            printk("Disc change detected.\n");
            break;
-         case NOT_READY: /* This happens if there is no disc in drive */
+       case NOT_READY: /* This happens if there is no disc in drive */
            printk("CDROM not ready.  Make sure there is a disc in the drive.\n");
            break;
-         case ILLEGAL_REQUEST:
+       case ILLEGAL_REQUEST:
            printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n");
            break;
-         default:
+       default:
            printk("SCSI CD error: host %d id %d lun %d return code = %03x\n", 
                   scsi_CDs[target].device->host->host_no, 
                   scsi_CDs[target].device->id,
@@ -82,354 +82,354 @@ static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned
                   SCpnt->sense_buffer[2] & 0xf);
            
        };
-
-       result = SCpnt->result;
-       SCpnt->request.dev = -1; /* Deallocate */
-       wake_up(&SCpnt->device->device_wait);
-       /* Wake up a process waiting for device*/
-       return result;
+    
+    result = SCpnt->result;
+    SCpnt->request.dev = -1; /* Deallocate */
+    wake_up(&SCpnt->device->device_wait);
+    /* Wake up a process waiting for device*/
+    return result;
 }
 
 int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
 {
-        u_char         sr_cmd[10];
-
-       int dev = inode->i_rdev;
-       int result, target, err;
-
-       target = MINOR(dev);
-
-       if (target >= sr_template.nr_dev ||
-           !scsi_CDs[target].device) return -ENXIO;
-
-       switch (cmd) 
-               {
-               /* Sun-compatible */
-               case CDROMPAUSE:
-
-                       sr_cmd[0] = SCMD_PAUSE_RESUME;
-                       sr_cmd[1] = scsi_CDs[target].device->lun << 5;
-                       sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0;
-                       sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0;
-                       sr_cmd[8] = 0;
-                       sr_cmd[9] = 0;
-
-                       result = do_ioctl(target, sr_cmd, NULL, 255);
-                       return result;
-
-               case CDROMRESUME:
-
-                       sr_cmd[0] = SCMD_PAUSE_RESUME;
-                       sr_cmd[1] = scsi_CDs[target].device->lun << 5;
-                       sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0;
-                       sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0;
-                       sr_cmd[8] = 1;
-                       sr_cmd[9] = 0;
-
-                       result = do_ioctl(target, sr_cmd, NULL, 255);
-
-                       return result;
-
-               case CDROMPLAYMSF:
-                       {
-                       struct cdrom_msf msf;
-                       memcpy_fromfs(&msf, (void *) arg, sizeof(msf));
-
-                       sr_cmd[0] = SCMD_PLAYAUDIO_MSF;
-                       sr_cmd[1] = scsi_CDs[target].device->lun << 5;
-                       sr_cmd[2] = 0;
-                       sr_cmd[3] = msf.cdmsf_min0;
-                       sr_cmd[4] = msf.cdmsf_sec0;
-                       sr_cmd[5] = msf.cdmsf_frame0;
-                       sr_cmd[6] = msf.cdmsf_min1;
-                       sr_cmd[7] = msf.cdmsf_sec1;
-                       sr_cmd[8] = msf.cdmsf_frame1;
-                       sr_cmd[9] = 0;
-
-                       result = do_ioctl(target, sr_cmd, NULL, 255);
-                       return result;
-                       }
-
-               case CDROMPLAYTRKIND:
-                       {
-                       struct cdrom_ti ti;
-                       memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
-
-                       sr_cmd[0] = SCMD_PLAYAUDIO_TI;
-                       sr_cmd[1] = scsi_CDs[target].device->lun << 5;
-                       sr_cmd[2] = 0;
-                       sr_cmd[3] = 0;
-                       sr_cmd[4] = ti.cdti_trk0;
-                       sr_cmd[5] = ti.cdti_ind0;
-                       sr_cmd[6] = 0;
-                       sr_cmd[7] = ti.cdti_trk1;
-                       sr_cmd[8] = ti.cdti_ind1;
-                       sr_cmd[9] = 0;
-
-                       result = do_ioctl(target, sr_cmd, NULL, 255);
-
-                       return result;
-                       }
-
-               case CDROMREADTOCHDR:
-                       {
-                       struct cdrom_tochdr tochdr;
-                       char * buffer;
-
-                       sr_cmd[0] = SCMD_READ_TOC;
-                       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
-                       sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-                       sr_cmd[6] = 0;
-                       sr_cmd[7] = 0;              /* MSB of length (12) */
-                       sr_cmd[8] = 12;             /* LSB of length */
-                       sr_cmd[9] = 0;
-
-                       buffer = (unsigned char *) scsi_malloc(512);
-                       if(!buffer) return -ENOMEM;
-
-                       result = do_ioctl(target, sr_cmd, buffer, 12);
-
-                       tochdr.cdth_trk0 = buffer[2];
-                       tochdr.cdth_trk1 = buffer[3];
-
-                       scsi_free(buffer, 512);
-
-                       err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tochdr));
-                       if (err)
-                               return err;
-                       memcpy_tofs ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr));
-                       
-                       return result;
-                       }
-
-               case CDROMREADTOCENTRY:
-                       {
-                       struct cdrom_tocentry tocentry;
-                       char * buffer;
-
-                       verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
-                       memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry));
-
-                       sr_cmd[0] = SCMD_READ_TOC;
-                       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
-                       sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-                       sr_cmd[6] = tocentry.cdte_track;
-                       sr_cmd[7] = 0;             /* MSB of length (12)  */
-                       sr_cmd[8] = 12;            /* LSB of length */
-                       sr_cmd[9] = 0;
-
-                       buffer = (unsigned char *) scsi_malloc(512);
-                       if(!buffer) return -ENOMEM;
-
-                       result = do_ioctl (target, sr_cmd, buffer, 12);
-
-                       if (tocentry.cdte_format == CDROM_MSF) {
-                         tocentry.cdte_addr.msf.minute = buffer[9];
-                         tocentry.cdte_addr.msf.second = buffer[10];
-                         tocentry.cdte_addr.msf.frame = buffer[11];
-                         tocentry.cdte_ctrl = buffer[5] & 0xf;
-                       }
-                       else
-                         tocentry.cdte_addr.lba = (int) buffer[0];
-
-                       scsi_free(buffer, 512);
-
-                       err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tocentry));
-                       if (err)
-                               return err;
-                       memcpy_tofs ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry));
-
-                       return result;
-                       }
-
-               case CDROMSTOP:
-                       sr_cmd[0] = START_STOP;
-                       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
-                       sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
-                       sr_cmd[4] = 0;
-
-                       result = do_ioctl(target, sr_cmd, NULL, 255);
-                       return result;
-                       
-               case CDROMSTART:
-                       sr_cmd[0] = START_STOP;
-                       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
-                       sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
-                       sr_cmd[4] = 1;
-
-                       result = do_ioctl(target, sr_cmd, NULL, 255);
-                       return result;
-
-               case CDROMEJECT:
-                       if (scsi_CDs[target].device -> access_count != 1)
-                               return -EBUSY;
-
-                       sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
-                       sr_cmd[0] = START_STOP;
-                       sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1;
-                       sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
-                       sr_cmd[4] = 0x02;
-
-                       if (!(result = do_ioctl(target, sr_cmd, NULL, 255)))
-                         scsi_CDs[target].device -> changed = 1;
-
-                       return result;
-
-               case CDROMVOLCTRL:
-                       {
-                         char * buffer, * mask;
-                         struct cdrom_volctrl volctrl;
-
-                         verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
-                         memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl));
-
-                         /* First we get the current params so we can just twiddle the volume */
-
-                         sr_cmd[0] = MODE_SENSE;
-                         sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
-                         sr_cmd[2] = 0xe;    /* Want mode page 0xe, CDROM audio params */
-                         sr_cmd[3] = 0;
-                         sr_cmd[4] = 28;
-                         sr_cmd[5] = 0;
-
-                         buffer = (unsigned char *) scsi_malloc(512);
-                         if(!buffer) return -ENOMEM;
-
-                         if ((result = do_ioctl (target, sr_cmd, buffer, 28))) {
-                           printk ("Hosed while obtaining audio mode page\n");
-                           scsi_free(buffer, 512);
-                           return result;
-                         }
-
-                         sr_cmd[0] = MODE_SENSE;
-                         sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
-                         sr_cmd[2] = 0x4e;   /* Want the mask for mode page 0xe */
-                         sr_cmd[3] = 0;
-                         sr_cmd[4] = 28;
-                         sr_cmd[5] = 0;
-
-                         mask = (unsigned char *) scsi_malloc(512);
-                         if(!mask) {
-                           scsi_free(buffer, 512);
-                           return -ENOMEM;
-                         };
-
-                         if ((result = do_ioctl (target, sr_cmd, mask, 28))) {
-                           printk ("Hosed while obtaining mask for audio mode page\n");
-                           scsi_free(buffer, 512);
-                           scsi_free(mask, 512);
-                           return result;
-                         }
-
-                         /* Now mask and substitute our own volume and reuse the rest */
-                         buffer[0] = 0;  /* Clear reserved field */
-
-                         buffer[21] = volctrl.channel0 & mask[21];
-                         buffer[23] = volctrl.channel1 & mask[23];
-                         buffer[25] = volctrl.channel2 & mask[25];
-                         buffer[27] = volctrl.channel3 & mask[27];
-
-                         sr_cmd[0] = MODE_SELECT;
-                         sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10;    /* Params are SCSI-2 */
-                         sr_cmd[2] = sr_cmd[3] = 0;
-                         sr_cmd[4] = 28;
-                         sr_cmd[5] = 0;
-
-                         result = do_ioctl (target, sr_cmd, buffer, 28);
-                         scsi_free(buffer, 512);
-                         scsi_free(mask, 512);
-                         return result;
-                       }
-
-               case CDROMSUBCHNL:
-                       {
-                         struct cdrom_subchnl subchnl;
-                         char * buffer;
-                         
-                         sr_cmd[0] = SCMD_READ_SUBCHANNEL;
-                         sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
-                         sr_cmd[2] = 0x40;    /* I do want the subchannel info */
-                         sr_cmd[3] = 0x01;    /* Give me current position info */
-                         sr_cmd[4] = sr_cmd[5] = 0;
-                         sr_cmd[6] = 0;
-                         sr_cmd[7] = 0;
-                         sr_cmd[8] = 16;
-                         sr_cmd[9] = 0;
-
-                         buffer = (unsigned char*) scsi_malloc(512);
-                         if(!buffer) return -ENOMEM;
-
-                         result = do_ioctl(target, sr_cmd, buffer, 16);
-
-                         subchnl.cdsc_audiostatus = buffer[1];
-                         subchnl.cdsc_format = CDROM_MSF;
-                         subchnl.cdsc_ctrl = buffer[5] & 0xf;
-                         subchnl.cdsc_trk = buffer[6];
-                         subchnl.cdsc_ind = buffer[7];
-
-                         subchnl.cdsc_reladdr.msf.minute = buffer[13];
-                         subchnl.cdsc_reladdr.msf.second = buffer[14];
-                         subchnl.cdsc_reladdr.msf.frame = buffer[15];
-                         subchnl.cdsc_absaddr.msf.minute = buffer[9];
-                         subchnl.cdsc_absaddr.msf.second = buffer[10];
-                         subchnl.cdsc_absaddr.msf.frame = buffer[11];
-
-                         scsi_free(buffer, 512);
-
-                         err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl));
-                         if (err)
-                                 return err;
-                         memcpy_tofs ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
-                         return result;
-                       }
-
-               case CDROMREADMODE2:
-                       return -EINVAL;
-               case CDROMREADMODE1:
-                       return -EINVAL;
-                       
-               /* block-copy from ../block/sbpcd.c with some adjustments... */
-               case CDROMMULTISESSION: /* tell start-of-last-session to user */
-                       {
-                         struct cdrom_multisession  ms_info;
-                         long                       lba;
-                         
-                         err = verify_area(VERIFY_READ, (void *) arg,
-                                           sizeof(struct cdrom_multisession));
-                         if (err) return (err);
-                       
-                         memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
-
-                         if (ms_info.addr_format==CDROM_MSF) { /* MSF-bin requested */
-                           lba = scsi_CDs[target].mpcd_sector+CD_BLOCK_OFFSET;
-                           ms_info.addr.msf.minute = lba / (CD_SECS*CD_FRAMES);
-                           lba %= CD_SECS*CD_FRAMES;
-                           ms_info.addr.msf.second = lba / CD_FRAMES;
-                           ms_info.addr.msf.frame  = lba % CD_FRAMES;
-                         } else if (ms_info.addr_format==CDROM_LBA) /* lba requested */
-                           ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
-                         else return (-EINVAL);
-                       
-                         ms_info.xa_flag=scsi_CDs[target].xa_flags & 0x01;
-                                                 
-                         err=verify_area(VERIFY_WRITE,(void *) arg,
-                                         sizeof(struct cdrom_multisession));
-                         if (err) return (err);
-
-                         memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
-                         return (0);
-                       }
+    u_char  sr_cmd[10];
+    
+    int dev = inode->i_rdev;
+    int result, target, err;
+    
+    target = MINOR(dev);
+    
+    if (target >= sr_template.nr_dev ||
+       !scsi_CDs[target].device) return -ENXIO;
+    
+    switch (cmd) 
+    {
+       /* Sun-compatible */
+    case CDROMPAUSE:
+       
+       sr_cmd[0] = SCMD_PAUSE_RESUME;
+       sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+       sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0;
+       sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0;
+       sr_cmd[8] = 0;
+       sr_cmd[9] = 0;
+       
+       result = do_ioctl(target, sr_cmd, NULL, 255);
+       return result;
+       
+    case CDROMRESUME:
+       
+       sr_cmd[0] = SCMD_PAUSE_RESUME;
+       sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+       sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0;
+       sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0;
+       sr_cmd[8] = 1;
+       sr_cmd[9] = 0;
+       
+       result = do_ioctl(target, sr_cmd, NULL, 255);
+       
+       return result;
+       
+    case CDROMPLAYMSF:
+    {
+       struct cdrom_msf msf;
+       memcpy_fromfs(&msf, (void *) arg, sizeof(msf));
+       
+       sr_cmd[0] = SCMD_PLAYAUDIO_MSF;
+       sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+       sr_cmd[2] = 0;
+       sr_cmd[3] = msf.cdmsf_min0;
+       sr_cmd[4] = msf.cdmsf_sec0;
+       sr_cmd[5] = msf.cdmsf_frame0;
+       sr_cmd[6] = msf.cdmsf_min1;
+       sr_cmd[7] = msf.cdmsf_sec1;
+       sr_cmd[8] = msf.cdmsf_frame1;
+       sr_cmd[9] = 0;
+       
+       result = do_ioctl(target, sr_cmd, NULL, 255);
+       return result;
+    }
+       
+    case CDROMPLAYTRKIND:
+    {
+       struct cdrom_ti ti;
+       memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
+       
+       sr_cmd[0] = SCMD_PLAYAUDIO_TI;
+       sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+       sr_cmd[2] = 0;
+       sr_cmd[3] = 0;
+       sr_cmd[4] = ti.cdti_trk0;
+       sr_cmd[5] = ti.cdti_ind0;
+       sr_cmd[6] = 0;
+       sr_cmd[7] = ti.cdti_trk1;
+       sr_cmd[8] = ti.cdti_ind1;
+       sr_cmd[9] = 0;
+       
+       result = do_ioctl(target, sr_cmd, NULL, 255);
+       
+       return result;
+    }
+       
+    case CDROMREADTOCHDR:
+    {
+       struct cdrom_tochdr tochdr;
+       char * buffer;
+       
+       sr_cmd[0] = SCMD_READ_TOC;
+       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
+       sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
+       sr_cmd[6] = 0;
+       sr_cmd[7] = 0;              /* MSB of length (12) */
+       sr_cmd[8] = 12;             /* LSB of length */
+       sr_cmd[9] = 0;
+       
+       buffer = (unsigned char *) scsi_malloc(512);
+       if(!buffer) return -ENOMEM;
+       
+       result = do_ioctl(target, sr_cmd, buffer, 12);
+       
+       tochdr.cdth_trk0 = buffer[2];
+       tochdr.cdth_trk1 = buffer[3];
+       
+       scsi_free(buffer, 512);
+       
+       err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tochdr));
+       if (err)
+           return err;
+       memcpy_tofs ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr));
+       
+       return result;
+    }
+       
+    case CDROMREADTOCENTRY:
+    {
+       struct cdrom_tocentry tocentry;
+       char * buffer;
+       
+       verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
+       memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry));
+       
+       sr_cmd[0] = SCMD_READ_TOC;
+       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
+       sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
+       sr_cmd[6] = tocentry.cdte_track;
+       sr_cmd[7] = 0;             /* MSB of length (12)  */
+       sr_cmd[8] = 12;            /* LSB of length */
+       sr_cmd[9] = 0;
+       
+       buffer = (unsigned char *) scsi_malloc(512);
+       if(!buffer) return -ENOMEM;
+       
+       result = do_ioctl (target, sr_cmd, buffer, 12);
+       
+       if (tocentry.cdte_format == CDROM_MSF) {
+           tocentry.cdte_addr.msf.minute = buffer[9];
+           tocentry.cdte_addr.msf.second = buffer[10];
+           tocentry.cdte_addr.msf.frame = buffer[11];
+           tocentry.cdte_ctrl = buffer[5] & 0xf;
+       }
+       else
+           tocentry.cdte_addr.lba = (int) buffer[0];
+       
+       scsi_free(buffer, 512);
+       
+       err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tocentry));
+       if (err)
+           return err;
+       memcpy_tofs ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry));
+       
+       return result;
+    }
+       
+    case CDROMSTOP:
+       sr_cmd[0] = START_STOP;
+       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
+       sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
+       sr_cmd[4] = 0;
+       
+       result = do_ioctl(target, sr_cmd, NULL, 255);
+       return result;
+       
+    case CDROMSTART:
+       sr_cmd[0] = START_STOP;
+       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
+       sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
+       sr_cmd[4] = 1;
+       
+       result = do_ioctl(target, sr_cmd, NULL, 255);
+       return result;
+       
+    case CDROMEJECT:
+       if (scsi_CDs[target].device -> access_count != 1)
+           return -EBUSY;
+       
+       sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+       sr_cmd[0] = START_STOP;
+       sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1;
+       sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
+       sr_cmd[4] = 0x02;
+       
+       if (!(result = do_ioctl(target, sr_cmd, NULL, 255)))
+           scsi_CDs[target].device -> changed = 1;
+       
+       return result;
+       
+    case CDROMVOLCTRL:
+    {
+       char * buffer, * mask;
+       struct cdrom_volctrl volctrl;
+       
+       verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
+       memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl));
+       
+       /* First we get the current params so we can just twiddle the volume */
+       
+       sr_cmd[0] = MODE_SENSE;
+       sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
+       sr_cmd[2] = 0xe;    /* Want mode page 0xe, CDROM audio params */
+       sr_cmd[3] = 0;
+       sr_cmd[4] = 28;
+       sr_cmd[5] = 0;
+       
+       buffer = (unsigned char *) scsi_malloc(512);
+       if(!buffer) return -ENOMEM;
+       
+       if ((result = do_ioctl (target, sr_cmd, buffer, 28))) {
+           printk ("Hosed while obtaining audio mode page\n");
+           scsi_free(buffer, 512);
+           return result;
+       }
+       
+       sr_cmd[0] = MODE_SENSE;
+       sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
+       sr_cmd[2] = 0x4e;   /* Want the mask for mode page 0xe */
+       sr_cmd[3] = 0;
+       sr_cmd[4] = 28;
+       sr_cmd[5] = 0;
+       
+       mask = (unsigned char *) scsi_malloc(512);
+       if(!mask) {
+           scsi_free(buffer, 512);
+           return -ENOMEM;
+       };
 
-               case BLKRASET:
-                       if(!suser())  return -EACCES;
-                       if(!inode->i_rdev) return -EINVAL;
-                       if(arg > 0xff) return -EINVAL;
-                       read_ahead[MAJOR(inode->i_rdev)] = arg;
-                       return 0;
-               RO_IOCTLS(dev,arg);
-               default:
-                       return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
-               }
+       if ((result = do_ioctl (target, sr_cmd, mask, 28))) {
+           printk ("Hosed while obtaining mask for audio mode page\n");
+           scsi_free(buffer, 512);
+           scsi_free(mask, 512);
+           return result;
+       }
+       
+       /* Now mask and substitute our own volume and reuse the rest */
+       buffer[0] = 0;  /* Clear reserved field */
+       
+       buffer[21] = volctrl.channel0 & mask[21];
+       buffer[23] = volctrl.channel1 & mask[23];
+       buffer[25] = volctrl.channel2 & mask[25];
+       buffer[27] = volctrl.channel3 & mask[27];
+       
+       sr_cmd[0] = MODE_SELECT;
+       sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10;    /* Params are SCSI-2 */
+       sr_cmd[2] = sr_cmd[3] = 0;
+       sr_cmd[4] = 28;
+       sr_cmd[5] = 0;
+       
+       result = do_ioctl (target, sr_cmd, buffer, 28);
+       scsi_free(buffer, 512);
+       scsi_free(mask, 512);
+       return result;
+    }
+       
+    case CDROMSUBCHNL:
+    {
+       struct cdrom_subchnl subchnl;
+       char * buffer;
+       
+       sr_cmd[0] = SCMD_READ_SUBCHANNEL;
+       sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
+       sr_cmd[2] = 0x40;    /* I do want the subchannel info */
+       sr_cmd[3] = 0x01;    /* Give me current position info */
+       sr_cmd[4] = sr_cmd[5] = 0;
+       sr_cmd[6] = 0;
+       sr_cmd[7] = 0;
+       sr_cmd[8] = 16;
+       sr_cmd[9] = 0;
+       
+       buffer = (unsigned char*) scsi_malloc(512);
+       if(!buffer) return -ENOMEM;
+       
+       result = do_ioctl(target, sr_cmd, buffer, 16);
+       
+       subchnl.cdsc_audiostatus = buffer[1];
+       subchnl.cdsc_format = CDROM_MSF;
+       subchnl.cdsc_ctrl = buffer[5] & 0xf;
+       subchnl.cdsc_trk = buffer[6];
+       subchnl.cdsc_ind = buffer[7];
+       
+       subchnl.cdsc_reladdr.msf.minute = buffer[13];
+       subchnl.cdsc_reladdr.msf.second = buffer[14];
+       subchnl.cdsc_reladdr.msf.frame = buffer[15];
+       subchnl.cdsc_absaddr.msf.minute = buffer[9];
+       subchnl.cdsc_absaddr.msf.second = buffer[10];
+       subchnl.cdsc_absaddr.msf.frame = buffer[11];
+       
+       scsi_free(buffer, 512);
+       
+       err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl));
+       if (err)
+           return err;
+       memcpy_tofs ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
+       return result;
+    }
+       
+    case CDROMREADMODE2:
+       return -EINVAL;
+    case CDROMREADMODE1:
+       return -EINVAL;
+       
+       /* block-copy from ../block/sbpcd.c with some adjustments... */
+    case CDROMMULTISESSION: /* tell start-of-last-session to user */
+    {
+       struct cdrom_multisession  ms_info;
+       long                       lba;
+       
+       err = verify_area(VERIFY_READ, (void *) arg,
+                         sizeof(struct cdrom_multisession));
+       if (err) return (err);
+       
+       memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
+       
+       if (ms_info.addr_format==CDROM_MSF) { /* MSF-bin requested */
+           lba = scsi_CDs[target].mpcd_sector+CD_BLOCK_OFFSET;
+           ms_info.addr.msf.minute = lba / (CD_SECS*CD_FRAMES);
+           lba %= CD_SECS*CD_FRAMES;
+           ms_info.addr.msf.second = lba / CD_FRAMES;
+           ms_info.addr.msf.frame  = lba % CD_FRAMES;
+       } else if (ms_info.addr_format==CDROM_LBA) /* lba requested */
+           ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
+       else return (-EINVAL);
+       
+       ms_info.xa_flag=scsi_CDs[target].xa_flags & 0x01;
+       
+       err=verify_area(VERIFY_WRITE,(void *) arg,
+                       sizeof(struct cdrom_multisession));
+       if (err) return (err);
+       
+       memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
+       return (0);
+    }
+       
+    case BLKRASET:
+       if(!suser())  return -EACCES;
+       if(!inode->i_rdev) return -EINVAL;
+       if(arg > 0xff) return -EINVAL;
+       read_ahead[MAJOR(inode->i_rdev)] = arg;
+       return 0;
+       RO_IOCTLS(dev,arg);
+    default:
+       return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
+    }
 }
 
 /*
@@ -439,12 +439,14 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
  * of the file.
  * ---------------------------------------------------------------------------
  * Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
  * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
  * End:
  */
index 384fb64625459b990d67e4ec72213df975732f12..9c9795999b9710d07efa689358334385c3976d30 100644 (file)
 
   Last modified: Sat Feb 18 10:51:25 1995 by root@kai.home
 */
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif /* MODULE */
 
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -87,14 +91,14 @@ static int st_buffer_size = ST_BUFFER_SIZE;
 static int st_write_threshold = ST_WRITE_THRESHOLD;
 static int st_max_buffers = ST_MAX_BUFFERS;
 
-static Scsi_Tape * scsi_tapes;
+static Scsi_Tape * scsi_tapes = NULL;
 
 static void st_init(void);
 static int st_attach(Scsi_Device *);
 static int st_detect(Scsi_Device *);
 static void st_detach(Scsi_Device *);
 
-struct Scsi_Device_Template st_template = {NULL, "tape", "st", TYPE_TAPE, 
+struct Scsi_Device_Template st_template = {NULL, "tape", "st", NULL, TYPE_TAPE, 
                                             SCSI_TAPE_MAJOR, 0, 0, 0, 0,
                                             st_detect, st_init,
                                             NULL, st_attach, st_detach};
@@ -467,8 +471,8 @@ scsi_tape_open(struct inode * inode, struct file * filp)
     cmd[0] = TEST_UNIT_READY;
     SCpnt->request.dev = dev;
     scsi_do_cmd(SCpnt,
-                (void *) cmd, (void *) (STp->buffer)->b_data,
-                0, st_sleep_done, ST_LONG_TIMEOUT,
+               (void *) cmd, (void *) (STp->buffer)->b_data,
+               0, st_sleep_done, ST_LONG_TIMEOUT,
                MAX_READY_RETRIES);
 
 
@@ -504,11 +508,11 @@ scsi_tape_open(struct inode * inode, struct file * filp)
     if ((STp->buffer)->last_result_fatal != 0) {
       if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
          (SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE) {
-        (STp->mt_status)->mt_fileno = STp->drv_block = 0 ;
+       (STp->mt_status)->mt_fileno = STp->drv_block = 0 ;
        printk("st%d: No tape.\n", dev);
        STp->ready = ST_NO_TAPE;
       } else {
-        (STp->mt_status)->mt_fileno = STp->drv_block = (-1);
+       (STp->mt_status)->mt_fileno = STp->drv_block = (-1);
        STp->ready = ST_NOT_READY;
       }
       SCpnt->request.dev = -1;  /* Mark as not busy */
@@ -529,7 +533,7 @@ scsi_tape_open(struct inode * inode, struct file * filp)
     cmd[0] = READ_BLOCK_LIMITS;
     SCpnt->request.dev = dev;
     scsi_do_cmd(SCpnt,
-                (void *) cmd, (void *) (STp->buffer)->b_data,
+               (void *) cmd, (void *) (STp->buffer)->b_data,
                6, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
 
 
@@ -564,8 +568,8 @@ scsi_tape_open(struct inode * inode, struct file * filp)
     cmd[4] = 12;
     SCpnt->request.dev = dev;
     scsi_do_cmd(SCpnt,
-                (void *) cmd, (void *) (STp->buffer)->b_data,
-                12, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
+               (void *) cmd, (void *) (STp->buffer)->b_data,
+               12, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
 
 
     /* this must be done with interrupts off */
@@ -650,6 +654,7 @@ scsi_tape_open(struct inode * inode, struct file * filp)
 
     if (scsi_tapes[dev].device->host->hostt->usage_count)
       (*scsi_tapes[dev].device->host->hostt->usage_count)++;
+    if(st_template.usage_count) (*st_template.usage_count)++;
 
     return 0;
 }
@@ -739,6 +744,7 @@ scsi_tape_close(struct inode * inode, struct file * filp)
 
     if (scsi_tapes[dev].device->host->hostt->usage_count)
       (*scsi_tapes[dev].device->host->hostt->usage_count)--;
+    if(st_template.usage_count) (*st_template.usage_count)--;
 
     return;
 }
@@ -845,7 +851,7 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
                    (STp->buffer)->buffer_bytes, b_point, do_count);
 
       if (STp->block_size == 0)
-        blks = transfer = do_count;
+       blks = transfer = do_count;
       else {
        blks = ((STp->buffer)->buffer_bytes + do_count) /
          STp->block_size;
@@ -1675,10 +1681,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
        STp->drv_block = 0;
      }
      undone = (
-          (SCpnt->sense_buffer[3] << 24) +
-          (SCpnt->sense_buffer[4] << 16) +
-          (SCpnt->sense_buffer[5] << 8) +
-          SCpnt->sense_buffer[6] );
+         (SCpnt->sense_buffer[3] << 24) +
+         (SCpnt->sense_buffer[4] << 16) +
+         (SCpnt->sense_buffer[5] << 8) +
+         SCpnt->sense_buffer[6] );
      if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) {
        if (fileno >= 0)
         (STp->mt_status)->mt_fileno = fileno - undone ;
@@ -1759,7 +1765,7 @@ st_ioctl(struct inode * inode,struct file * file,
 
      i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(mtc));
      if (i)
-        return i;
+       return i;
 
      memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop));
 
@@ -1972,9 +1978,9 @@ static int st_detect(Scsi_Device * SDp)
 {
   if(SDp->type != TYPE_TAPE) return 0;
 
-  printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n", 
+  printk("Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", 
         st_template.dev_noticed++,
-        SDp->host->host_no , SDp->id, SDp->lun); 
+        SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); 
   
   return 1;
 }
@@ -2070,3 +2076,38 @@ static void st_detach(Scsi_Device * SDp)
     }
   return;
 }
+
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void) {
+  st_template.usage_count = &mod_use_count_;
+  return scsi_register_module(MODULE_SCSI_DEV, &st_template);
+}
+
+void cleanup_module( void) 
+{
+  int i;
+
+  if (MOD_IN_USE) {
+    printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+    return;
+  }
+  scsi_unregister_module(MODULE_SCSI_DEV, &st_template);
+  unregister_chrdev(SCSI_GENERIC_MAJOR, "st");
+  if(scsi_tapes != NULL) {
+    scsi_init_free((char *) scsi_tapes,
+                  (st_template.dev_noticed + ST_EXTRA_DEVS) 
+                  * sizeof(Scsi_Tape));
+    
+    for (i=0; i < st_nbr_buffers; i++) {
+      scsi_init_free((char *) st_buffers[i],
+                    sizeof(ST_buffer) - 1 + st_buffer_size);
+    }
+    
+    scsi_init_free((char *) st_buffers, st_nbr_buffers * sizeof(ST_buffer *));
+  }
+  st_template.dev_max = 0;
+}
+#endif /* MODULE */
index fcd4020563fa43a7b4f7b6ef5f85ec1c9a8975b3..f1a21ced8495e220c331b2269ab392fdcf471c3f 100644 (file)
@@ -117,7 +117,8 @@ int t128_reset(Scsi_Cmnd *);
 
 #ifdef HOSTS_C
 
-#define TRANTOR_T128 {NULL, NULL, "Trantor T128/T128F/T228", t128_detect, NULL,  \
+#define TRANTOR_T128 {NULL, NULL, generic_proc_info, "t128", PROC_SCSI_T128, \
+       "Trantor T128/T128F/T228", t128_detect, NULL,  \
        NULL,                                                   \
        NULL, t128_queue_command, t128_abort, t128_reset, NULL,         \
        t128_biosparam,                                                 \
index 933c9cbbfda1d8a889cca253fba613ba0f582336..dd4d264da306ccdff746d20af3f7afe58dbd3e17 100644 (file)
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <linux/proc_fs.h>
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -336,7 +337,7 @@ static int board_inquiry(unsigned int j) {
 }
 
 static inline int port_detect(ushort *port_base, unsigned int j, 
-                              Scsi_Host_Template * tpnt) {
+                             Scsi_Host_Template * tpnt) {
    unsigned char irq, dma_channel, subversion;
    unsigned char in_byte;
 
@@ -358,8 +359,8 @@ static inline int port_detect(ushort *port_base, unsigned int j,
       unsigned char heads;
       unsigned char sectors;
       } mapping_table[4] = { 
-           { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
-           };
+          { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
+          };
 
    struct config_1 {
       unsigned char bios_segment: 3;
@@ -381,7 +382,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
 
    if(check_region(*port_base, REGION_SIZE)) {
       printk("%s: address 0x%03x in use, skipping probe.\n", 
-             name, *port_base);
+            name, *port_base);
       return FALSE;
       }
 
@@ -407,7 +408,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
 
    if (subversion == ISA && request_dma(dma_channel, driver_name)) {
       printk("%s: unable to allocate DMA channel %u, detaching.\n",
-             name, dma_channel);
+            name, dma_channel);
       free_irq(irq);
       return FALSE;
       }
@@ -487,20 +488,20 @@ static inline int port_detect(ushort *port_base, unsigned int j,
       HD(j)->board_id[40] = 0;
 
       if (strcmp(&HD(j)->board_id[32], "06000600")) {
-         printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
-         printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
-                BN(j), &HD(j)->board_id[32]);
-         sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
-         sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
-         }
+        printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
+        printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
+               BN(j), &HD(j)->board_id[32]);
+        sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
+        sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
+        }
       }
 
    printk("%s: PORT 0x%03x, BIOS 0x%05x, IRQ %u, DMA %u, SG %d, "\
-          "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port, 
-          (int)sh[j]->base, sh[j]->irq, 
-          sh[j]->dma_channel, sh[j]->sg_tablesize, 
-          sh[j]->can_queue, sh[j]->cmd_per_lun,
-          sh[j]->hostt->use_clustering);
+         "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port, 
+         (int)sh[j]->base, sh[j]->irq, 
+         sh[j]->dma_channel, sh[j]->sg_tablesize, 
+         sh[j]->can_queue, sh[j]->cmd_per_lun,
+         sh[j]->hostt->use_clustering);
    return TRUE;
 }
 
@@ -574,18 +575,18 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
       if (i >= sh[j]->can_queue) i = 0;
 
       if (HD(j)->cp_stat[i] == FREE) {
-         HD(j)->last_cp_used = i;
-         break;
-         }
+        HD(j)->last_cp_used = i;
+        break;
+        }
       }
 
    if (k == sh[j]->can_queue) {
       printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
 
       if (HD(j)->in_reset) 
-         printk("%s: qcomm, already in reset.\n", BN(j));
+        printk("%s: qcomm, already in reset.\n", BN(j));
       else if (u14_34f_reset(SCpnt) == SCSI_RESET_SUCCESS) 
-         panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
+        panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
 
       SCpnt->result = DID_BUS_BUSY << 16; 
       SCpnt->host_scribble = NULL;
@@ -604,7 +605,7 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    SCpnt->host_scribble = (unsigned char *) &cpp->index;
 
    if (do_trace) printk("%s: qcomm, mbox %d, target %d, pid %ld.\n",
-                        BN(j), i, SCpnt->target, SCpnt->pid);
+                       BN(j), i, SCpnt->target, SCpnt->pid);
 
    cpp->opcode = OP_SCSI;
    cpp->xdir = DTD_SCSI;
@@ -630,7 +631,7 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
       SCpnt->result = DID_ERROR << 16;
       SCpnt->host_scribble = NULL;
       printk("%s: qcomm, target %d, pid %ld, adapter busy, DID_ERROR, done.\n", 
-             BN(j), SCpnt->target, SCpnt->pid);
+            BN(j), SCpnt->target, SCpnt->pid);
       restore_flags(flags);
       done(SCpnt);
       return 0;
@@ -656,13 +657,13 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
 
    if (SCarg->host_scribble == NULL) {
       printk("%s: abort, target %d, pid %ld inactive.\n",
-             BN(j), SCarg->target, SCarg->pid);
+            BN(j), SCarg->target, SCarg->pid);
       return SCSI_ABORT_NOT_RUNNING;
       }
 
    i = *(unsigned int *)SCarg->host_scribble;
    printk("%s: abort, mbox %d, target %d, pid %ld.\n",
-          BN(j), i, SCarg->target, SCarg->pid);
+         BN(j), i, SCarg->target, SCarg->pid);
 
    if (i >= sh[j]->can_queue)
       panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -683,8 +684,8 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
       printk("%s: abort, mbox %d is in use.\n", BN(j), i);
 
       if (SCarg != HD(j)->cp[i].SCpnt)
-         panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
-               BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+        panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+              BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
 
       restore_flags(flags);
       return SCSI_ABORT_SNOOZE;
@@ -714,7 +715,7 @@ int u14_34f_reset(Scsi_Cmnd * SCarg) {
    cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
    printk("%s: reset, enter, target %d, pid %ld.\n", 
-          BN(j), SCarg->target, SCarg->pid);
+         BN(j), SCarg->target, SCarg->pid);
 
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
@@ -740,27 +741,27 @@ int u14_34f_reset(Scsi_Cmnd * SCarg) {
       if (HD(j)->cp_stat[i] == FREE) continue;
 
       if (HD(j)->cp_stat[i] == LOCKED) {
-         HD(j)->cp_stat[i] = FREE;
-         printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
-         continue;
-         }
+        HD(j)->cp_stat[i] = FREE;
+        printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+        continue;
+        }
 
       SCpnt = HD(j)->cp[i].SCpnt;
       HD(j)->cp_stat[i] = IN_RESET;
       printk("%s: reset, mbox %d in reset, pid %ld.\n",
-             BN(j), i, SCpnt->pid);
+            BN(j), i, SCpnt->pid);
 
       if (SCpnt == NULL)
-         panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+        panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
 
       if (SCpnt->host_scribble == NULL)
-         panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+        panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
 
       if (*(unsigned int *)SCpnt->host_scribble != i) 
-         panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+        panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
 
       if (SCpnt->scsi_done == NULL) 
-         panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+        panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
 
       if (SCpnt == SCarg) arg_done = TRUE;
       }
@@ -798,7 +799,7 @@ int u14_34f_reset(Scsi_Cmnd * SCarg) {
       HD(j)->cp_stat[i] = LOCKED;
 
       printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
-             BN(j), i, SCpnt->pid);
+            BN(j), i, SCpnt->pid);
       restore_flags(flags);
       SCpnt->scsi_done(SCpnt);
       cli();
@@ -843,7 +844,7 @@ static void u14_34f_interrupt_handler(int irq, struct pt_regs * regs) {
       }
 
    if (do_trace) printk("%s: ihdlr, enter, irq %d, calls %d.\n", 
-                        driver_name, irq, calls[irq]);
+                       driver_name, irq, calls[irq]);
 
    /* Service all the boards configured on this irq */
    for (j = 0; sh[j] != NULL; j++) {
@@ -854,156 +855,156 @@ static void u14_34f_interrupt_handler(int irq, struct pt_regs * regs) {
 
       /* Loop until all interrupts for a board are serviced */
       while (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED) {
-         total_loops++;
-         loops++;
-
-         if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
-                              BN(j), HD(j)->iocount);
-
-         spp = (struct mscp *)inl(sh[j]->io_port + REG_ICM);
-
-         /* Clear interrupt pending flag */
-         outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
-
-         i = spp - HD(j)->cp;
-
-         if (i >= sh[j]->can_queue)
-            panic("%s: ihdlr, invalid mscp address.\n", BN(j));
-
-         if (HD(j)->cp_stat[i] == IGNORE) {
-            HD(j)->cp_stat[i] = FREE;
-            continue;
-            }
-         else if (HD(j)->cp_stat[i] == LOCKED) {
-            HD(j)->cp_stat[i] = FREE;
-            printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
-                   BN(j), i, HD(j)->iocount);
-            continue;
-            }
-         else if (HD(j)->cp_stat[i] == FREE) {
-            printk("%s: ihdlr, mbox %d is free, count %d.\n", 
-                   BN(j), i, HD(j)->iocount);
-            continue;
-            }
-         else if (HD(j)->cp_stat[i] == IN_RESET)
-            printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
-         else if (HD(j)->cp_stat[i] != IN_USE) 
-            panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
-
-         HD(j)->cp_stat[i] = FREE;
-         SCpnt = spp->SCpnt;
-
-         if (SCpnt == NULL) 
-            panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
-
-         if (SCpnt->host_scribble == NULL) 
-            panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
-                  BN(j), i, SCpnt->pid, SCpnt);
-
-         if (*(unsigned int *)SCpnt->host_scribble != i) 
-            panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
-                  " irq %d.\n", BN(j), i, SCpnt->pid, 
-                  *(unsigned int *)SCpnt->host_scribble, irq);
-
-         tstatus = status_byte(spp->target_status);
-
-         switch (spp->adapter_status) {
-            case ASOK:     /* status OK */
-
-               /* Forces a reset if a disk drive keeps returning BUSY */
-               if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) 
-                  status = DID_ERROR << 16;
-
-               /* If there was a bus reset, redo operation on each target */
-               else if (tstatus != GOOD
-                        && SCpnt->device->type == TYPE_DISK
-                        && HD(j)->target_reset[SCpnt->target])
-                  status = DID_BUS_BUSY << 16;
-
-               /* Works around a flaw in scsi.c */
-               else if (tstatus == CHECK_CONDITION
-                        && SCpnt->device->type == TYPE_DISK
-                        && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
-                  status = DID_BUS_BUSY << 16;
-
-               else
-                  status = DID_OK << 16;
-
-               if (tstatus == GOOD)
-                  HD(j)->target_reset[SCpnt->target] = FALSE;
-
-               if (spp->target_status && SCpnt->device->type == TYPE_DISK)
-                  printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
-                         "0x%x, sense key 0x%x.\n", BN(j), 
-                         SCpnt->target, SCpnt->lun, SCpnt->pid,
-                         spp->target_status, SCpnt->sense_buffer[2]);
-
-               HD(j)->target_time_out[SCpnt->target] = 0;
-
-               break;
-            case ASST:     /* Selection Time Out */
-
-               if (HD(j)->target_time_out[SCpnt->target] > 1)
-                  status = DID_ERROR << 16;
-               else {
-                  status = DID_TIME_OUT << 16;
-                  HD(j)->target_time_out[SCpnt->target]++;
-                  }
-
-               break;
-            case 0x92:     /* Data over/under-run */
-            case 0x93:     /* Unexpected bus free */
-            case 0x94:     /* Target bus phase sequence failure */
-            case 0x96:     /* Illegal SCSI command */
-            case 0xa3:     /* SCSI bus reset error */
-
-               if (SCpnt->device->type != TYPE_TAPE)
-                  status = DID_BUS_BUSY << 16;
-               else
-                  status = DID_ERROR << 16;
-
-               for (k = 0; k < MAX_TARGET; k++) 
-                  HD(j)->target_reset[k] = TRUE;
-
-               break;
-            case 0x01:     /* Invalid command */
-            case 0x02:     /* Invalid parameters */
-            case 0x03:     /* Invalid data list */
-            case 0x84:     /* SCSI bus abort error */
-            case 0x9b:     /* Auto request sense error */
-            case 0x9f:     /* Unexpected command complete message error */
-            case 0xff:     /* Invalid parameter in the S/G list */
-            default:
-               status = DID_ERROR << 16;
-               break;
-            }
-
-         SCpnt->result = status | spp->target_status;
-         HD(j)->iocount++;
-
-         if (loops > 1) HD(j)->multicount++;
+        total_loops++;
+        loops++;
+
+        if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
+                             BN(j), HD(j)->iocount);
+
+        spp = (struct mscp *)inl(sh[j]->io_port + REG_ICM);
+
+        /* Clear interrupt pending flag */
+        outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
+
+        i = spp - HD(j)->cp;
+
+        if (i >= sh[j]->can_queue)
+           panic("%s: ihdlr, invalid mscp address.\n", BN(j));
+
+        if (HD(j)->cp_stat[i] == IGNORE) {
+           HD(j)->cp_stat[i] = FREE;
+           continue;
+           }
+        else if (HD(j)->cp_stat[i] == LOCKED) {
+           HD(j)->cp_stat[i] = FREE;
+           printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
+                  BN(j), i, HD(j)->iocount);
+           continue;
+           }
+        else if (HD(j)->cp_stat[i] == FREE) {
+           printk("%s: ihdlr, mbox %d is free, count %d.\n", 
+                  BN(j), i, HD(j)->iocount);
+           continue;
+           }
+        else if (HD(j)->cp_stat[i] == IN_RESET)
+           printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
+        else if (HD(j)->cp_stat[i] != IN_USE) 
+           panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
+
+        HD(j)->cp_stat[i] = FREE;
+        SCpnt = spp->SCpnt;
+
+        if (SCpnt == NULL) 
+           panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+        if (SCpnt->host_scribble == NULL) 
+           panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
+                 BN(j), i, SCpnt->pid, SCpnt);
+
+        if (*(unsigned int *)SCpnt->host_scribble != i) 
+           panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
+                 " irq %d.\n", BN(j), i, SCpnt->pid, 
+                 *(unsigned int *)SCpnt->host_scribble, irq);
+
+        tstatus = status_byte(spp->target_status);
+
+        switch (spp->adapter_status) {
+           case ASOK:     /* status OK */
+
+              /* Forces a reset if a disk drive keeps returning BUSY */
+              if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) 
+                 status = DID_ERROR << 16;
+
+              /* If there was a bus reset, redo operation on each target */
+              else if (tstatus != GOOD
+                       && SCpnt->device->type == TYPE_DISK
+                       && HD(j)->target_reset[SCpnt->target])
+                 status = DID_BUS_BUSY << 16;
+
+              /* Works around a flaw in scsi.c */
+              else if (tstatus == CHECK_CONDITION
+                       && SCpnt->device->type == TYPE_DISK
+                       && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+                 status = DID_BUS_BUSY << 16;
+
+              else
+                 status = DID_OK << 16;
+
+              if (tstatus == GOOD)
+                 HD(j)->target_reset[SCpnt->target] = FALSE;
+
+              if (spp->target_status && SCpnt->device->type == TYPE_DISK)
+                 printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
+                        "0x%x, sense key 0x%x.\n", BN(j), 
+                        SCpnt->target, SCpnt->lun, SCpnt->pid,
+                        spp->target_status, SCpnt->sense_buffer[2]);
+
+              HD(j)->target_time_out[SCpnt->target] = 0;
+
+              break;
+           case ASST:     /* Selection Time Out */
+
+              if (HD(j)->target_time_out[SCpnt->target] > 1)
+                 status = DID_ERROR << 16;
+              else {
+                 status = DID_TIME_OUT << 16;
+                 HD(j)->target_time_out[SCpnt->target]++;
+                 }
+
+              break;
+           case 0x92:     /* Data over/under-run */
+           case 0x93:     /* Unexpected bus free */
+           case 0x94:     /* Target bus phase sequence failure */
+           case 0x96:     /* Illegal SCSI command */
+           case 0xa3:     /* SCSI bus reset error */
+
+              if (SCpnt->device->type != TYPE_TAPE)
+                 status = DID_BUS_BUSY << 16;
+              else
+                 status = DID_ERROR << 16;
+
+              for (k = 0; k < MAX_TARGET; k++) 
+                 HD(j)->target_reset[k] = TRUE;
+
+              break;
+           case 0x01:     /* Invalid command */
+           case 0x02:     /* Invalid parameters */
+           case 0x03:     /* Invalid data list */
+           case 0x84:     /* SCSI bus abort error */
+           case 0x9b:     /* Auto request sense error */
+           case 0x9f:     /* Unexpected command complete message error */
+           case 0xff:     /* Invalid parameter in the S/G list */
+           default:
+              status = DID_ERROR << 16;
+              break;
+           }
+
+        SCpnt->result = status | spp->target_status;
+        HD(j)->iocount++;
+
+        if (loops > 1) HD(j)->multicount++;
 
 #if defined (DEBUG_INTERRUPT)
-         if (SCpnt->result || do_trace) 
+        if (SCpnt->result || do_trace) 
 #else
-         if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
-             (spp->adapter_status != ASOK && 
-              spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
-             do_trace)
+        if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
+            (spp->adapter_status != ASOK && 
+             spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
+            do_trace)
 #endif
-            printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\
-                   " target %d:%d, pid %ld, count %d.\n",
-                   BN(j), i, spp->adapter_status, spp->target_status,
-                   SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount);
+           printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\
+                  " target %d:%d, pid %ld, count %d.\n",
+                  BN(j), i, spp->adapter_status, spp->target_status,
+                  SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount);
 
-         /* Set the command state to inactive */
-         SCpnt->host_scribble = NULL;
+        /* Set the command state to inactive */
+        SCpnt->host_scribble = NULL;
 
-         restore_flags(flags);
-         SCpnt->scsi_done(SCpnt);
-         cli();
+        restore_flags(flags);
+        SCpnt->scsi_done(SCpnt);
+        cli();
 
-         }   /* Multiple command loop */
+        }   /* Multiple command loop */
 
       }   /* Boards loop */
 
@@ -1011,16 +1012,16 @@ static void u14_34f_interrupt_handler(int irq, struct pt_regs * regs) {
 
    if (total_loops == 0) 
      printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
-            driver_name, irq, calls[irq]);
+           driver_name, irq, calls[irq]);
 
    if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n",
-                        driver_name, irq, calls[irq]);
+                       driver_name, irq, calls[irq]);
 
 #if defined (DEBUG_STATISTICS)
    if ((calls[irq] % 100000) == 10000)
       for (j = 0; sh[j] != NULL; j++)
-         printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
-                calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
+        printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
+               calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
 #endif
 
    restore_flags(flags);
index e53170299b02ed76246a537e47f53ee887780e26..ed591edcd8c39eaf538577c3a319b65b2670dbdc 100644 (file)
@@ -10,27 +10,32 @@ int u14_34f_abort(Scsi_Cmnd *);
 int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_biosparam(Disk *, int, int *);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int); 
+
 #define U14_34F_VERSION "2.01.00"
 
 #define ULTRASTOR_14_34F {                                            \
-                NULL, /* Ptr for modules */                           \
-                NULL, /* usage count for modules */                  \
-                "UltraStor 14F/34F rev. " U14_34F_VERSION " ",        \
-                u14_34f_detect,                                       \
-                NULL, /* Release */                                   \
-                NULL,                                                \
-                NULL,                                                 \
-                u14_34f_queuecommand,                                 \
-                u14_34f_abort,                                        \
-                u14_34f_reset,                                        \
-                NULL,                                                 \
-                u14_34f_biosparam,                                    \
+               NULL, /* Ptr for modules */                           \
+               NULL, /* usage count for modules */                   \
+               generic_proc_info,                                    \
+               "u14_34f",                                            \
+               PROC_SCSI_U14_34F,                                    \
+               "UltraStor 14F/34F rev. " U14_34F_VERSION " ",        \
+               u14_34f_detect,                                       \
+               NULL, /* Release */                                   \
+               NULL,                                                 \
+               NULL,                                                 \
+               u14_34f_queuecommand,                                 \
+               u14_34f_abort,                                        \
+               u14_34f_reset,                                        \
+               NULL,                                                 \
+               u14_34f_biosparam,                                    \
                0,   /* can_queue, reset by detect */                 \
-                7,   /* this_id, reset by detect */                   \
-                0,   /* sg_tablesize, reset by detect */              \
-                0,   /* cmd_per_lun, reset by detect */               \
+               7,   /* this_id, reset by detect */                   \
+               0,   /* sg_tablesize, reset by detect */              \
+               0,   /* cmd_per_lun, reset by detect */               \
                0,   /* number of boards present */                   \
-                1,   /* unchecked isa dma, reset by detect */         \
-                ENABLE_CLUSTERING                                     \
-                }
+               1,   /* unchecked isa dma, reset by detect */         \
+               ENABLE_CLUSTERING                                     \
+               }
 #endif
index 5f0b9bee2ba72460d46bf8e4ac9fda70abd5a283..555f4a79e5eeb5b0cf76bade4f4f69888991b70e 100644 (file)
  * Release ICM slot by clearing first byte on 24F.
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 #include <linux/stddef.h>
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
-
+#include <linux/proc_fs.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
 #include <asm/system.h>
@@ -1140,3 +1144,10 @@ static void ultrastor_interrupt(int irq, struct pt_regs *regs)
     printk("USx4F: interrupt: returning\n");
 #endif
 }
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = ULTRASTOR_14F;
+
+#include "scsi_module.c"
+#endif
index cc92225a44d9d45299d42df9b4c620129b1ca1d0..1a4271bb4c93631a8c4547584bc85cf91203ae46 100644 (file)
@@ -20,6 +20,8 @@ int ultrastor_abort(Scsi_Cmnd *);
 int ultrastor_reset(Scsi_Cmnd *);
 int ultrastor_biosparam(Disk *, int, int *);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 #define ULTRASTOR_14F_MAX_SG 16
 #define ULTRASTOR_24F_MAX_SG 33
 
@@ -30,6 +32,9 @@ int ultrastor_biosparam(Disk *, int, int *);
 
 
 #define ULTRASTOR_14F { NULL, NULL, /* Ptr for modules*/ \
+                         generic_proc_info,            \
+                         "ultrastor",                  \
+                         PROC_SCSI_ULTRASTOR,          \
                          "UltraStor 14F/24F/34F",      \
                          ultrastor_detect,             \
                          NULL, /* Release */           \
index 1905014c5e60d52d3857d40aaa7a6b9ab008d225..15f16cd0969707211817c6ea973cc465f07db03b 100644 (file)
  *                                                           J.B. Jan 1994.
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 #include <stdarg.h>
 #include <linux/kernel.h>
 #include <linux/head.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <linux/ioport.h>
-
+#include <linux/proc_fs.h>
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -223,9 +227,9 @@ static const Signature signatures[] = {
 
 /* ASC Status Port
  */
-#define INT_IM         0x80            /* Interrupt Image Flag */
-#define CMD_RDY                0x40            /* Command Port Ready */
-#define CMD_REJ                0x20            /* Command Port Byte Rejected */
+#define INT_IM         0x80            /* Interrupt Image Flag */
+#define CMD_RDY                0x40            /* Command Port Ready */
+#define CMD_REJ                0x20            /* Command Port Byte Rejected */
 #define ASC_INIT        0x10           /* ASC Initialized Flag */
 #define ASC_STATMASK    0xf0           /* The lower 4 Bytes are reserved */
 
@@ -246,7 +250,7 @@ static const Signature signatures[] = {
 #define HARD_RESET_ACK    6     /* SCSI bus hard reset acknowledge */
 #define START_OGMB        0x80  /* start command in OGMB (n) */
 #define SCAN_OGMBS        0xc0  /* start multiple commands, signature (n) */
-                                /*    where (n) = lower 6 bits */
+                               /*    where (n) = lower 6 bits */
 /* For INITIALIZATION:
  */
 typedef struct initCmd {
@@ -284,10 +288,10 @@ typedef struct initCmd {
 
 /* CONTROL port bits
  */
-#define INT_EN         0x08    /* Interrupt Enable     */
-#define DMA_EN         0x04    /* DMA Enable           */
+#define INT_EN         0x08    /* Interrupt Enable     */
+#define DMA_EN         0x04    /* DMA Enable           */
 #define SCSI_RES       0x02    /* SCSI Reset           */
-#define ASC_RES                0x01    /* ASC Reset            */
+#define ASC_RES                0x01    /* ASC Reset            */
 
 /*
    Driver data structures:
@@ -336,7 +340,7 @@ typedef struct scb {                /* Command Control Block 5.4.1 */
   unchar linkptr[3];           /* Next Command Link Pointer */
   unchar direc;                        /* Transfer Direction */
   unchar reserved2[6];         /* SCSI Command Descriptor Block */
-                                /* end of hardware SCB */
+                               /* end of hardware SCB */
   Scsi_Cmnd *SCpnt;             /* Scsi_Cmnd using this SCB */
   Sgb sgb[WD7000_SG];           /* Scatter/gather list for this SCB */
   Adapter *host;                /* host adapter */
@@ -361,7 +365,7 @@ typedef struct scb {                /* Command Control Block 5.4.1 */
 #define ICB_OP_RECV_SDATA       0x83  /* receive data with status from init. */
 #define ICB_OP_SEND_DATA        0x84  /* send data with status to initiator */
 #define ICB_OP_SEND_STAT        0x86  /* send command status to initiator */
-                             /* 0x87 is reserved */
+                            /* 0x87 is reserved */
 #define ICB_OP_READ_INIT        0x88  /* read initialization bytes */
 #define ICB_OP_READ_ID          0x89  /* read adapter's SCSI ID */
 #define ICB_OP_SET_UMASK        0x8A  /* set unsolicited interrupt mask */
@@ -516,7 +520,7 @@ static inline int scsi2int( unchar *scsi )
 */
 #undef any2scsi
 #define any2scsi(up, p)                        \
-(up)[0] = (((unsigned long)(p)) >> 16);                \
+(up)[0] = (((unsigned long)(p)) >> 16);                \
 (up)[1] = ((unsigned long)(p)) >> 8;           \
 (up)[2] = ((unsigned long)(p));
 
@@ -568,7 +572,7 @@ static inline int command_out(Adapter *host, unchar *cmd, int len)
 {
     WAIT(host->iobase+ASC_STAT,ASC_STATMASK,CMD_RDY,0);
     while (len--)  {
-        do  {
+       do  {
            outb(*cmd, host->iobase+ASC_COMMAND);
            WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
        }  while (inb(host->iobase+ASC_STAT) & CMD_REJ);
@@ -606,14 +610,14 @@ static inline Scb *alloc_scbs(int needed)
     save_flags(flags);
     cli();
     while (busy)  { /* someone else is allocating */
-        sti(); /* Yes this is really needed here */
+       sti();  /* Yes this is really needed here */
        now = jiffies;  while (jiffies == now)  /* wait a jiffy */;
        cli();
     }
     busy = 1;          /* not busy now; it's our turn */
 
     while (freescbs < needed)  {
-        timeout = jiffies + WAITnexttimeout;
+       timeout = jiffies + WAITnexttimeout;
        do {
            sti();      /* Yes this is really needed here */
            now = jiffies;   while (jiffies == now) /* wait a jiffy */;
@@ -712,7 +716,7 @@ static int mail_out( Adapter *host, Scb *scbptr )
     printk(", scb is %x",(unsigned int) scbptr);
 #endif
     if (i >= OGMB_CNT) {
-        /*
+       /*
         *  Alternatively, we might issue the "interrupt on free OGMB",
         *  and sleep, but it must be ensured that it isn't the init
         *  task running.  Instead, this version assumes that the caller
@@ -720,8 +724,8 @@ static int mail_out( Adapter *host, Scb *scbptr )
         *  that marks OGMB's free, waiting even with interrupts off
         *  should work, since they are freed very quickly in most cases.
         */
-        #ifdef DEBUG
-        printk(", no free OGMBs.\n");
+       #ifdef DEBUG
+       printk(", no free OGMBs.\n");
 #endif
        return 0;
     }
@@ -763,23 +767,23 @@ int make_code(unsigned hosterr, unsigned scsierr)
                hosterr = DID_BAD_TARGET;
                break;
        case 80: /* Unexpected Reselection */
-        case 81: /* Unexpected Selection */
+       case 81: /* Unexpected Selection */
                hosterr = DID_BAD_INTR;
                break;
-        case 82: /* Abort Command Message  */
+       case 82: /* Abort Command Message  */
                hosterr = DID_ABORT;
                break;
        case 83: /* SCSI Bus Software Reset */
        case 84: /* SCSI Bus Hardware Reset */
                hosterr = DID_RESET;
                break;
-        default: /* Reserved */
+       default: /* Reserved */
                hosterr = DID_ERROR;
                break;
        }
 #ifdef DEBUG
     if (scsierr||hosterr)
-        printk("\nSCSI command error: SCSI %02x host %04x return %d",
+       printk("\nSCSI command error: SCSI %02x host %04x return %d",
               scsierr,in_error,hosterr);
 #endif
     return scsierr | (hosterr << 16);
@@ -817,7 +821,7 @@ void wd7000_intr_handle(int irq, struct pt_regs * regs)
 #endif
 
     if (!(inb(host->iobase+ASC_STAT) & INT_IM))  {
-        /* NB: these are _very_ possible if IRQ 15 is being used, since
+       /* NB: these are _very_ possible if IRQ 15 is being used, since
           it's the "garbage collector" on the 2nd 8259 PIC.  Specifically,
           any interrupt signal into the 8259 which can't be identified
           comes out as 7 from the 8259, which is 15 to the host.  Thus, it
@@ -833,7 +837,7 @@ void wd7000_intr_handle(int irq, struct pt_regs * regs)
     }
 
     if (flag & MB_INTR)  {
-        /* The interrupt is for a mailbox */
+       /* The interrupt is for a mailbox */
        if (!(flag & IMB_INTR)) {
 #ifdef DEBUG
            printk("wd7000_intr_handle: free outgoing mailbox");
@@ -851,16 +855,16 @@ void wd7000_intr_handle(int irq, struct pt_regs * regs)
            icmb_status = icmbs[icmb].status;
            if (icmb_status & 0x80)  {  /* unsolicited - result in ICMB */
 #ifdef DEBUG
-               printk("wd7000_intr_handle: unsolicited interrupt %02xh\n",
+               printk("wd7000_intr_handle: unsolicited interrupt %02xh\n",
                       icmb_status);
 #endif
-               wd7000_intr_ack(host);
-               return;
+               wd7000_intr_ack(host);
+               return;
            }
            scb = (struct scb *) scsi2int((unchar *)icmbs[icmb].scbptr);
            icmbs[icmb].status = 0;
            if (!(scb->op & ICB_OP_MASK))  {   /* an SCB is done */
-               SCpnt = scb->SCpnt;
+               SCpnt = scb->SCpnt;
                if (--(SCpnt->SCp.phase) <= 0)  {  /* all scbs are done */
                    host_error = scb->vue | (icmb_status << 8);
                    scsi_error = scb->status;
@@ -872,7 +876,7 @@ void wd7000_intr_handle(int irq, struct pt_regs * regs)
                    SCpnt->scsi_done(SCpnt);
                }
            }  else  {    /* an ICB is done */
-               icb = (IcbAny *) scb;
+               icb = (IcbAny *) scb;
                icb->status = icmb_status;
                icb->phase  = 0;
            }
@@ -907,10 +911,10 @@ int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     scb->host = host;
 
     if (SCpnt->use_sg)  {
-        struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
-        unsigned i;
+       struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+       unsigned i;
 
-        if (SCpnt->host->sg_tablesize == SG_NONE)  {
+       if (SCpnt->host->sg_tablesize == SG_NONE)  {
            panic("wd7000_queuecommand: scatter/gather not supported.\n");
        }
 #ifdef DEBUG
@@ -925,7 +929,7 @@ int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
        for (i = 0;  i < SCpnt->use_sg;  i++)  {
            any2scsi(sgb[i].ptr, (int) sg[i].address);
            any2scsi(sgb[i].len, sg[i].length);
-        }
+       }
     }  else  {
        scb->op = 0;
        any2scsi(scb->dataptr, (int) SCpnt->request_buffer);
@@ -968,11 +972,11 @@ int wd7000_diagnostics( Adapter *host, int code )
        barrier(); /* wait for completion */
 
     if (icb.phase)  {
-        printk("wd7000_diagnostics: timed out.\n");
+       printk("wd7000_diagnostics: timed out.\n");
        return 0;
     }
     if (make_code(icb.vue|(icb.status << 8),0))  {
-        printk("wd7000_diagnostics: failed (%02x,%02x)\n",
+       printk("wd7000_diagnostics: failed (%02x,%02x)\n",
               icb.vue, icb.status);
        return 0;
     }
@@ -984,7 +988,7 @@ int wd7000_diagnostics( Adapter *host, int code )
 int wd7000_init( Adapter *host )
 {
     InitCmd init_cmd = {
-        INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, 0,0,0, OGMB_CNT, ICMB_CNT
+       INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, 0,0,0, OGMB_CNT, ICMB_CNT
     };
     int diag;
 
@@ -999,8 +1003,8 @@ int wd7000_init( Adapter *host )
     WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
 
     if ((diag = inb(host->iobase+ASC_INTR_STAT)) != 1)  {
-        printk("wd7000_init: ");
-        switch (diag)  {
+       printk("wd7000_init: ");
+       switch (diag)  {
        case 2:
          printk("RAM failure.\n");
          break;
@@ -1023,7 +1027,7 @@ int wd7000_init( Adapter *host )
          printk("diagnostic code %02Xh received.\n", diag);
          break;
        }
-        return 0;
+       return 0;
     }
     
     /* Clear mailboxes */
@@ -1038,11 +1042,11 @@ int wd7000_init( Adapter *host )
     WAIT(host->iobase+ASC_STAT, ASC_STATMASK, ASC_INIT, 0);
 
     if (request_irq(host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000")) {
-        printk("wd7000_init: can't get IRQ %d.\n", host->irq);
+       printk("wd7000_init: can't get IRQ %d.\n", host->irq);
        return 0;
     }
     if (request_dma(host->dma,"wd7000"))  {
-        printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
+       printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
        free_irq(host->irq);
        return 0;
     }
@@ -1050,9 +1054,9 @@ int wd7000_init( Adapter *host )
     wd7000_enable_intr(host);
 
     if (!wd7000_diagnostics(host,ICB_DIAG_FULL))  {
-        free_dma(host->dma);
-        free_irq(host->irq);
-        return 0;
+       free_dma(host->dma);
+       free_irq(host->irq);
+       return 0;
     }
 
     return 1;
@@ -1105,10 +1109,10 @@ int wd7000_detect(Scsi_Host_Template * tpnt)
 
     cfg = configs;
     for (i = 0; i < NUM_CONFIGS; i++)  {
-        sig = signatures;
+       sig = signatures;
        for (j = 0; j < NUM_SIGNATURES; j++)  {
            if (!memcmp(cfg->bios+sig->ofs, sig->sig, sig->len))  {
-               /* matched this one */
+               /* matched this one */
 #ifdef DEBUG
                printk("WD-7000 SST BIOS detected at %04X: checking...\n",
                       (int) cfg->bios);
@@ -1136,7 +1140,7 @@ int wd7000_detect(Scsi_Host_Template * tpnt)
                       (int)host);
 #endif
                memset( host, 0, sizeof(Adapter) );
-               host->sh = sh;
+               host->sh = sh;
                host->irq = cfg->irq;
                host->iobase = cfg->iobase;
                host->dma = cfg->dma;
@@ -1154,7 +1158,7 @@ int wd7000_detect(Scsi_Host_Template * tpnt)
 
                printk("Western Digital WD-7000 (%d.%d) ",
                       host->rev1, host->rev2);
-                printk("using IO %xh IRQ %d DMA %d.\n",
+               printk("using IO %xh IRQ %d DMA %d.\n",
                       host->iobase, host->irq, host->dma);
 
                request_region(host->iobase, 4,"wd7000"); /* Register our ports */
@@ -1183,7 +1187,7 @@ int wd7000_abort(Scsi_Cmnd * SCpnt)
     Adapter *host = (Adapter *) SCpnt->host->hostdata;
 
     if (inb(host->iobase+ASC_STAT) & INT_IM)  {
-        printk("wd7000_abort: lost interrupt\n");
+       printk("wd7000_abort: lost interrupt\n");
        wd7000_intr_handle(host->irq, NULL);
        return SCSI_ABORT_SUCCESS;
     }
@@ -1215,3 +1219,10 @@ int wd7000_biosparam(Disk * disk, int dev, int* ip)
 /*  if (ip[2] >= 1024) ip[2] = 1024; */
   return 0;
 }
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = WD7000;
+
+#include "scsi_module.c"
+#endif
index d19cabf2144aaa6e774f8ed7cac68ec6768a33aa..11828240e910828253b5b150f501e03334d031e2 100644 (file)
@@ -19,6 +19,8 @@ int wd7000_abort(Scsi_Cmnd *);
 int wd7000_reset(Scsi_Cmnd *);
 int wd7000_biosparam(Disk *, int, int*);
 
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
 #ifndef NULL
 #define NULL 0L
 #endif
@@ -37,13 +39,16 @@ int wd7000_biosparam(Disk *, int, int*);
 #define WD7000_Q    16
 #define WD7000_SG   16
 
-#define WD7000 { NULL, NULL, \
+#define WD7000 { NULL, NULL,            \
+       generic_proc_info,              \
+       "wd7000",                       \
+       PROC_SCSI_7000FASST,            \
        "Western Digital WD-7000",      \
        wd7000_detect,                  \
        NULL,                           \
-       NULL,                           \
-       wd7000_command,                 \
-       wd7000_queuecommand,            \
+       NULL,                           \
+       wd7000_command,                 \
+       wd7000_queuecommand,            \
        wd7000_abort,                   \
        wd7000_reset,                   \
        NULL,                           \
index 9a46fb9e309182396f83e79400d4f979afbd3715..3e9ffb4929c43cf4eaf7d58236f74eac1a46cad7 100644 (file)
@@ -18,6 +18,7 @@
 #endif
 
 #include <linux/fs.h>
+#include <linux/stat.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
@@ -31,6 +32,7 @@
 #include <linux/malloc.h>
 #include <linux/shm.h>
 #include <linux/personality.h>
+#include <linux/elfcore.h>
 
 #include <asm/segment.h>
 #include <asm/pgtable.h>
@@ -48,12 +50,14 @@ extern sysfun_p sys_call_table[];
 
 static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
 static int load_elf_library(int fd);
+static int elf_core_dump(long signr, struct pt_regs * regs);
+extern int dump_fpu (elf_fpregset_t *);
 
 struct linux_binfmt elf_format = {
 #ifndef MODULE
-       NULL, NULL, load_elf_binary, load_elf_library, NULL
+       NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
 #else
-       NULL, &mod_use_count_, load_elf_binary, load_elf_library, NULL
+       NULL, &mod_use_count_, load_elf_binary, load_elf_library, elf_core_dump
 #endif
 };
 
@@ -759,6 +763,411 @@ load_elf_library(int fd){
        return 0;
 }
 
+/*
+ * ELF core dumper
+ *
+ * Modelled on fs/exec.c:aout_core_dump()
+ * Jeremy Fitzhardinge <jeremy@sw.oz.au>
+ */
+/*
+ * These are the only things you should do on a core-file: use only these
+ * functions to write out all the necessary info.
+ */
+static int dump_write(struct file *file, void *addr, int nr)
+{
+       return file->f_op->write(file->f_inode, file, addr, nr) == nr;
+}
+
+static int dump_seek(struct file *file, off_t off)
+{
+       if (file->f_op->lseek) {
+               if (file->f_op->lseek(file->f_inode, file, off, 0) != off)
+                       return 0;
+       } else
+               file->f_pos = off;
+       return 1;
+}
+
+/*
+ * Decide whether a segment is worth dumping; default is yes to be
+ * sure (missing info is worse than too much; etc).
+ * Personally I'd include everything, and use the coredump limit...
+ *
+ * I think we should skip something. But I am not sure how. H.J.
+ */
+static inline int maydump(struct vm_area_struct *vma)
+{
+#if 1
+       if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
+               return 1;
+       if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
+               return 0;
+#endif
+       return 1;
+}
+
+#define roundup(x, y)  ((((x)+((y)-1))/(y))*(y))
+
+/* An ELF note in memory */
+struct memelfnote
+{
+       char *name;
+       int type;
+       unsigned int datasz;
+       void *data;
+};
+
+static int notesize(struct memelfnote *en)
+{
+       int sz;
+       
+       sz = sizeof(struct elf_note);
+       sz += roundup(strlen(en->name), 4);
+       sz += roundup(en->datasz, 4);
+       
+       return sz;
+}
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+static void dump_regs(const char *str, elf_greg_t *r)
+{
+       int i;
+       static const char *regs[] = { "ebx", "ecx", "edx", "esi", "edi", "ebp",
+                                             "eax", "ds", "es", "fs", "gs",
+                                             "orig_eax", "eip", "cs",
+                                             "efl", "uesp", "ss"};
+       printk("Registers: %s\n", str);
+
+       for(i = 0; i < ELF_NGREG; i++)
+       {
+               unsigned long val = r[i];
+               printk("   %-2d %-5s=%08lx %lu\n", i, regs[i], val, val);
+       }
+}
+#endif
+
+#define DUMP_WRITE(addr, nr)   \
+       do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
+#define DUMP_SEEK(off) \
+       do { if (!dump_seek(file, (off))) return 0; } while(0)
+
+static int writenote(struct memelfnote *men, struct file *file)
+{
+       struct elf_note en;
+
+       en.n_namesz = strlen(men->name);
+       en.n_descsz = men->datasz;
+       en.n_type = men->type;
+
+       DUMP_WRITE(&en, sizeof(en));
+       DUMP_WRITE(men->name, en.n_namesz);
+       /* XXX - cast from long long to long to avoid need for libgcc.a */
+       DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));      /* XXX */
+       DUMP_WRITE(men->data, men->datasz);
+       DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));      /* XXX */
+       
+       return 1;
+}
+#undef DUMP_WRITE
+#undef DUMP_SEEK
+
+#define DUMP_WRITE(addr, nr)   \
+       if (!dump_write(&file, (addr), (nr))) \
+               goto close_coredump;
+#define DUMP_SEEK(off) \
+       if (!dump_seek(&file, (off))) \
+               goto close_coredump;
+/*
+ * Actual dumper
+ *
+ * This is a two-pass process; first we find the offsets of the bits,
+ * and then they are actually written out.  If we run out of core limit
+ * we just truncate.
+ */
+static int elf_core_dump(long signr, struct pt_regs * regs)
+{
+       int has_dumped = 0;
+       struct file file;
+       struct inode *inode;
+       unsigned short fs;
+       char corefile[6+sizeof(current->comm)];
+       int segs;
+       int i;
+       size_t size;
+       struct vm_area_struct *vma;
+       struct elfhdr elf;
+       off_t offset = 0, dataoff;
+       int limit = current->rlim[RLIMIT_CORE].rlim_cur;
+       int numnote = 4;
+       struct memelfnote notes[4];
+       struct elf_prstatus prstatus;   /* NT_PRSTATUS */
+       elf_fpregset_t fpu;             /* NT_PRFPREG */
+       struct elf_prpsinfo psinfo;     /* NT_PRPSINFO */
+       
+       if (!current->dumpable || limit < PAGE_SIZE)
+               return 0;
+       current->dumpable = 0;
+
+#ifndef CONFIG_BINFMT_ELF
+       MOD_INC_USE_COUNT;
+#endif
+
+       /* Count what's needed to dump, up to the limit of coredump size */
+       segs = 0;
+       size = 0;
+       for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+               int sz = vma->vm_end-vma->vm_start;
+               
+               if (!maydump(vma))
+                       continue;
+
+               if (size+sz > limit)
+                       break;
+               
+               segs++;
+               size += sz;
+       }
+#ifdef DEBUG
+       printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
+#endif
+
+       /* Set up header */
+       memcpy(elf.e_ident, ELFMAG, SELFMAG);
+       elf.e_ident[EI_CLASS] = ELFCLASS32;
+       elf.e_ident[EI_DATA] = ELFDATA2LSB;
+       elf.e_ident[EI_VERSION] = EV_CURRENT;
+       memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+       
+       elf.e_type = ET_CORE;
+       elf.e_machine = EM_386;
+       elf.e_version = EV_CURRENT;
+       elf.e_entry = 0;
+       elf.e_phoff = sizeof(elf);
+       elf.e_shoff = 0;
+       elf.e_flags = 0;
+       elf.e_ehsize = sizeof(elf);
+       elf.e_phentsize = sizeof(struct elf_phdr);
+       elf.e_phnum = segs+1;           /* Include notes */
+       elf.e_shentsize = 0;
+       elf.e_shnum = 0;
+       elf.e_shstrndx = 0;
+       
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       memcpy(corefile,"core.",5);
+#if 0
+       memcpy(corefile+5,current->comm,sizeof(current->comm));
+#else
+       corefile[4] = '\0';
+#endif
+       if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+               inode = NULL;
+               goto end_coredump;
+       }
+       if (!S_ISREG(inode->i_mode))
+               goto end_coredump;
+       if (!inode->i_op || !inode->i_op->default_file_ops)
+               goto end_coredump;
+       file.f_mode = 3;
+       file.f_flags = 0;
+       file.f_count = 1;
+       file.f_inode = inode;
+       file.f_pos = 0;
+       file.f_reada = 0;
+       file.f_op = inode->i_op->default_file_ops;
+       if (file.f_op->open)
+               if (file.f_op->open(inode,&file))
+                       goto end_coredump;
+       if (!file.f_op->write)
+               goto close_coredump;
+       has_dumped = 1;
+
+       DUMP_WRITE(&elf, sizeof(elf));
+       offset += sizeof(elf);                          /* Elf header */
+       offset += (segs+1) * sizeof(struct elf_phdr);   /* Program headers */
+
+       /*
+        * Set up the notes in similar form to SVR4 core dumps made
+        * with info from their /proc.
+        */
+       memset(&psinfo, 0, sizeof(psinfo));
+       memset(&prstatus, 0, sizeof(prstatus));
+
+       notes[0].name = "CORE";
+       notes[0].type = NT_PRSTATUS;
+       notes[0].datasz = sizeof(prstatus);
+       notes[0].data = &prstatus;
+       prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
+       prstatus.pr_sigpend = current->signal;
+       prstatus.pr_sighold = current->blocked;
+       psinfo.pr_pid = prstatus.pr_pid = current->pid;
+       psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
+       psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
+       psinfo.pr_sid = prstatus.pr_sid = current->session;
+       prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
+       prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
+       prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
+       prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
+       prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
+       prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
+       prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
+       prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
+       if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
+       {
+               printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n",
+                       sizeof(elf_gregset_t), sizeof(struct pt_regs));
+       }
+       else
+               *(struct pt_regs *)&prstatus.pr_reg = *regs;
+       
+#ifdef DEBUG
+       dump_regs("Passed in regs", (elf_greg_t *)regs);
+       dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg);
+#endif
+
+       notes[1].name = "CORE";
+       notes[1].type = NT_PRPSINFO;
+       notes[1].datasz = sizeof(psinfo);
+       notes[1].data = &psinfo;
+       psinfo.pr_state = current->state;
+       psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state];
+       psinfo.pr_zomb = psinfo.pr_sname == 'Z';
+       psinfo.pr_nice = current->priority-15;
+       psinfo.pr_flag = current->flags;
+       psinfo.pr_uid = current->uid;
+       psinfo.pr_gid = current->gid;
+       {
+               int i, len;
+
+               set_fs(fs);
+               
+               len = current->mm->arg_end - current->mm->arg_start;
+               len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
+               memcpy_fromfs(&psinfo.pr_psargs,
+                             (const char *)current->mm->arg_start, len);
+               for(i = 0; i < len; i++)
+                       if (psinfo.pr_psargs[i] == 0)
+                               psinfo.pr_psargs[i] = ' ';
+               psinfo.pr_psargs[len] = 0;
+
+               set_fs(KERNEL_DS);
+       }
+       strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
+
+       notes[2].name = "CORE";
+       notes[2].type = NT_TASKSTRUCT;
+       notes[2].datasz = sizeof(*current);
+       notes[2].data = current;
+       
+       /* Try to dump the fpu. */
+       prstatus.pr_fpvalid = dump_fpu (&fpu);
+       if (!prstatus.pr_fpvalid)
+       {
+               numnote--;
+       }
+       else
+       {
+               notes[3].name = "CORE";
+               notes[3].type = NT_PRFPREG;
+               notes[3].datasz = sizeof(fpu);
+               notes[3].data = &fpu;
+       }
+       
+       /* Write notes phdr entry */
+       {
+               struct elf_phdr phdr;
+               int sz = 0;
+
+               for(i = 0; i < numnote; i++)
+                       sz += notesize(&notes[i]);
+               
+               phdr.p_type = PT_NOTE;
+               phdr.p_offset = offset;
+               phdr.p_vaddr = 0;
+               phdr.p_paddr = 0;
+               phdr.p_filesz = sz;
+               phdr.p_memsz = 0;
+               phdr.p_flags = 0;
+               phdr.p_align = 0;
+
+               offset += phdr.p_filesz;
+               DUMP_WRITE(&phdr, sizeof(phdr));
+       }
+
+       /* Page-align dumped data */
+       dataoff = offset = roundup(offset, PAGE_SIZE);
+       
+       /* Write program headers for segments dump */
+       for(vma = current->mm->mmap, i = 0;
+               i < segs && vma != NULL; vma = vma->vm_next) {
+               struct elf_phdr phdr;
+               size_t sz;
+
+               if (!maydump(vma))
+                       continue;
+               i++;
+
+               sz = vma->vm_end - vma->vm_start;
+               
+               phdr.p_type = PT_LOAD;
+               phdr.p_offset = offset;
+               phdr.p_vaddr = vma->vm_start;
+               phdr.p_paddr = 0;
+               phdr.p_filesz = sz;
+               phdr.p_memsz = sz;
+               offset += sz;
+               phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
+               if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
+               if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
+               phdr.p_align = PAGE_SIZE;
+
+               DUMP_WRITE(&phdr, sizeof(phdr));
+       }
+
+       for(i = 0; i < numnote; i++)
+               if (!writenote(&notes[i], &file))
+                       goto close_coredump;
+       
+       set_fs(fs);
+
+       DUMP_SEEK(dataoff);
+       
+       for(i = 0, vma = current->mm->mmap;
+           i < segs && vma != NULL;
+           vma = vma->vm_next) {
+               unsigned long addr = vma->vm_start;
+               unsigned long len = vma->vm_end - vma->vm_start;
+               
+               if (!maydump(vma))
+                       continue;
+               i++;
+#ifdef DEBUG
+               printk("elf_core_dump: writing %08lx %lx\n", addr, len);
+#endif
+               DUMP_WRITE((void *)addr, len);
+       }
+
+       if ((off_t) file.f_pos != offset) {
+               /* Sanity check */
+               printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
+                      (off_t) file.f_pos, offset);
+       }
+
+ close_coredump:
+       if (file.f_op->release)
+               file.f_op->release(inode,&file);
+
+ end_coredump:
+       set_fs(fs);
+       iput(inode);
+#ifndef CONFIG_BINFMT_ELF
+       MOD_DEC_USE_COUNT;
+#endif
+       return has_dumped;
+}
+
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
 
@@ -771,6 +1180,7 @@ int init_module(void) {
        return 0;
 }
 
+
 void cleanup_module( void) {
        
        if (MOD_IN_USE)
index 3eb269295b335833610e0e233812c5bc7d968d26..b07253ad354198dee0bacd37a4ff23db47426e81 100644 (file)
@@ -152,7 +152,7 @@ int check_disk_change(dev_t dev)
        if (!fops->check_media_change(dev))
                return 0;
 
-       printk("VFS: Disk change detected on device %d/%d\n",
+       printk(KERN_DEBUG "VFS: Disk change detected on device %d/%d\n",
                                        MAJOR(dev), MINOR(dev));
        for (i=0 ; i<NR_SUPER ; i++)
                if (super_blocks[i].s_dev == dev)
index 71c62433c129b42f9df31443b9b4529608c8c264..12b67545ca8f5a55a7af96e86d2472bc53e86e70 100644 (file)
@@ -14,7 +14,7 @@
 .s.o:
        $(AS) -o $*.o $<
 
-OBJS=  inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o
+OBJS=  inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o
 
 proc.o: $(OBJS)
        $(LD) -r -o proc.o $(OBJS)
index 2daae4ab0fc67386e5d9c122891dd82a26c0ee71..db1b1efdd2cbca76ab5da9ee353c3287ab80f22a 100644 (file)
@@ -165,6 +165,26 @@ void proc_read_inode(struct inode * inode)
                return;
        }
 
+       if (ino == PROC_SCSI_SCSI) {
+               inode->i_mode = S_IFREG | S_IWUSR;
+               inode->i_op = &proc_scsi_inode_operations;
+               return;
+       }
+       /* files within /proc/scsi */
+       if ((ino > PROC_SCSI_SCSI) && (ino < PROC_SCSI_FILE)) {
+               inode->i_nlink = 2;
+               inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+               inode->i_op = &proc_scsi_inode_operations;
+               return;
+       }
+
+       /* files within /proc/scsi/<driver>/  */
+       if ((ino >= PROC_SCSI_FILE) && (ino <= PROC_SCSI_LAST)) {
+               inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
+               inode->i_op = &proc_scsi_inode_operations;
+               return;
+       }
+
        if (!pid) {
                switch (ino) {
                        case PROC_KMSG:
@@ -176,6 +196,11 @@ void proc_read_inode(struct inode * inode)
                                inode->i_nlink = 2;
                                inode->i_op = &proc_net_inode_operations;
                                break;
+                       case PROC_SCSI:
+                                inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+                                inode->i_nlink = 2;
+                                inode->i_op = &proc_scsi_inode_operations;
+                                break;
                        case PROC_KCORE:
                                inode->i_mode = S_IFREG | S_IRUSR;
                                inode->i_op = &proc_kcore_inode_operations;
index 26b14816c7100e68ab47bfa824eeb52ff448dd48..a69af1c4cd8ac0a0c9e38008228a22961d856433 100644 (file)
@@ -65,6 +65,7 @@ static struct proc_dir_entry root_dir[] = {
        { PROC_CPUINFO,         7, "cpuinfo" },
        { PROC_SELF,            4, "self" },    /* will change inode # */
        { PROC_NET,             3, "net" },
+       { PROC_SCSI,            4, "scsi" },
 #ifdef CONFIG_DEBUG_MALLOC
        { PROC_MALLOC,          6, "malloc" },
 #endif
diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c
new file mode 100644 (file)
index 0000000..ec7fd77
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ *  linux/fs/proc/scsi.c  
+ *  (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
+ *
+ *  The original version was derived from linux/fs/proc/net.c,
+ *  which is Copyright (C) 1991, 1992 Linus Torvalds. 
+ *  Much has been rewritten, but some of the code still remains.
+ *
+ *  /proc/scsi directory handling functions
+ *
+ *  last change: 95/06/13    
+ *
+ *  Initial version: March '95
+ *  95/15/05 Added subdirectories for each driver and show every
+ *           registered HBA as a single file. 
+ *  95/30/05 Added rudimentary write support for parameter passing
+ *
+ *  TODO: Improve support to write to the driver files
+ *        Optimize directory handling 
+ *        Add some more comments
+ */
+#include <linux/autoconf.h>
+#include <asm/segment.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/config.h>
+#include <linux/mm.h>
+
+/* forward references */
+static int proc_readscsi(struct inode * inode, struct file * file,
+                         char * buf, int count);
+static int proc_writescsi(struct inode * inode, struct file * file,
+                         char * buf, int count);
+static int proc_readscsidir(struct inode *, struct file *, 
+                            void *, filldir_t filldir);
+static int proc_lookupscsi(struct inode *,const char *,int,struct inode **);
+static int proc_scsilseek(struct inode *, struct file *, off_t, int);
+
+extern uint count_templates(void);
+extern void build_proc_dir_hba_entries(uint);
+
+/* the *_get_info() functions are in the respective scsi driver code */
+extern int (* dispatch_scsi_info_ptr)(int, char *, char **, off_t, int, int);
+    
+    
+static struct file_operations proc_scsi_operations = {
+    proc_scsilseek,     /* lseek   */
+    proc_readscsi,      /* read    */
+    proc_writescsi,     /* write   */
+    proc_readscsidir,   /* readdir */
+    NULL,               /* select  */
+    NULL,               /* ioctl   */
+    NULL,               /* mmap    */
+    NULL,               /* no special open code    */
+    NULL,               /* no special release code */
+    NULL                /* can't fsync */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+struct inode_operations proc_scsi_inode_operations = {
+    &proc_scsi_operations,  /* default scsi directory file-ops */
+    NULL,           /* create      */
+    proc_lookupscsi,/* lookup      */
+    NULL,           /* link        */
+    NULL,           /* unlink      */
+    NULL,           /* symlink     */
+    NULL,           /* mkdir       */
+    NULL,           /* rmdir       */
+    NULL,           /* mknod       */
+    NULL,           /* rename      */
+    NULL,           /* readlink    */
+    NULL,           /* follow_link */
+    NULL,           /* bmap        */
+    NULL,           /* truncate    */
+    NULL            /* permission  */
+};
+
+struct proc_dir_entry scsi_dir[PROC_SCSI_FILE - PROC_SCSI_SCSI + 3]; 
+struct proc_dir_entry scsi_hba_dir[(PROC_SCSI_LAST - PROC_SCSI_FILE) * 4]; 
+
+static struct proc_dir_entry scsi_dir2[] = {
+    { PROC_SCSI,                 1, "." },
+    { PROC_ROOT_INO,             2, ".." },
+    { PROC_SCSI_NOT_PRESENT,    11, "not.present" },
+    { 0, 0, NULL }
+};
+
+inline static uint count_dir_entries(uint inode)
+{
+    struct proc_dir_entry *dir;
+    uint i = 0;
+    
+    
+    if(dispatch_scsi_info_ptr)
+        if (inode <= PROC_SCSI_SCSI_DEBUG)
+            dir = scsi_dir;
+        else
+            dir = scsi_hba_dir;
+    else dir = scsi_dir2;
+    
+    while(dir[i].low_ino)
+        i++;
+    
+    return(i);
+}
+
+static int proc_lookupscsi(struct inode * dir, const char * name, int len,
+                           struct inode ** result)
+{
+    struct proc_dir_entry *de = NULL;
+    
+    *result = NULL;
+    if (!dir)
+        return(-ENOENT);
+    if (!S_ISDIR(dir->i_mode)) {
+        iput(dir);
+        return(-ENOENT);
+    }
+    if (dispatch_scsi_info_ptr != NULL)
+        if (dir->i_ino <= PROC_SCSI_SCSI)
+            de = scsi_dir;
+        else {
+            de = &scsi_hba_dir[dispatch_scsi_info_ptr(dir->i_ino, 0, 0, 0, 0, 2)];
+        }
+    else
+        de = scsi_dir2;
+    
+    for (; de->name ; de++) {
+        if (!proc_match(len, name, de))
+            continue;
+        *result = iget(dir->i_sb, de->low_ino);
+        iput(dir);
+        if (!*result)
+            return(-ENOENT);
+        return(0);
+    }
+    iput(dir);
+    return(-ENOENT);
+}
+
+static int proc_readscsidir(struct inode * inode, struct file * filp,
+                            void * dirent, filldir_t filldir)
+{
+    struct proc_dir_entry * de;
+    unsigned int ino;
+    
+    if (!inode || !S_ISDIR(inode->i_mode))
+        return(-EBADF);
+    ino = inode->i_ino;
+       while (((unsigned) filp->f_pos) < count_dir_entries(ino)) {
+        if (dispatch_scsi_info_ptr)
+            if (ino <= PROC_SCSI_SCSI)
+                de = scsi_dir + filp->f_pos;
+            else
+                de = scsi_hba_dir + filp->f_pos;
+        else
+            de = scsi_dir2 + filp->f_pos;
+        if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino)<0)
+            break;
+        filp->f_pos++;
+    }
+    return(0);
+}
+
+int get_not_present_info(char *buffer, char **start, off_t offset, int length)
+{
+    int len, pos, begin;
+    
+    begin = 0;
+    pos = len = sprintf(buffer, 
+                        "The scsi core module is currently not present\n");
+    if(pos < offset) {
+        len = 0;
+        begin = pos;
+    }
+    
+    *start = buffer + (offset - begin);   /* Start of wanted data */
+    len -= (offset - begin);
+    if(len > length)
+        len = length;
+    
+    return(len);
+}
+
+#define PROC_BLOCK_SIZE (3*1024)     /* 4K page size, but our output routines 
+                                      * use some slack for overruns 
+                                      */
+
+static int proc_readscsi(struct inode * inode, struct file * file,
+                         char * buf, int count)
+{
+    uint ino;
+    int length;
+    int bytes = count;
+    int copied = 0;
+    int thistime;
+    char * page;
+    char * start;
+    
+    if (count < -1)               /* Normally I wouldn't do this, */ 
+        return(-EINVAL);          /* but it saves some redundant code.
+                                   * Now it is possible to seek to the 
+                                   * end of the file */
+    if (!(page = (char *) __get_free_page(GFP_KERNEL)))
+        return(-ENOMEM);
+    ino = inode->i_ino;
+    
+    
+    while(bytes > 0 || count == -1)
+    {
+        
+        thistime = bytes;
+        if(bytes > PROC_BLOCK_SIZE || count == -1)
+            thistime = PROC_BLOCK_SIZE;
+        
+        if(dispatch_scsi_info_ptr)
+            length = dispatch_scsi_info_ptr(ino, page, &start, 
+                                            file->f_pos, thistime, 0);
+        else
+            length = get_not_present_info(page, &start, file->f_pos, thistime);
+        if(length < 0) {
+            free_page((ulong) page);
+            return(length);
+        }
+        
+        /*
+         *  We have been given a non page aligned block of
+         *  the data we asked for + a bit. We have been given
+         *  the start pointer and we know the length.. 
+         */
+        if (length <= 0)
+            break;
+        /*
+         *  Copy the bytes, if we're not doing a seek to 
+         *      the end of the file 
+         */
+        if (count != -1)
+            memcpy_tofs(buf + copied, start, length);
+        file->f_pos += length;  /* Move down the file */
+        bytes -= length;
+        copied += length;
+        
+        if(length < thistime)
+            break;  /* End of file */
+        
+    }
+    
+    free_page((ulong) page);
+    return(copied);
+}
+
+
+static int proc_writescsi(struct inode * inode, struct file * file,
+                         char * buf, int count)
+{
+    uint ino;
+    int ret = 0;
+    char * page;
+    
+    if (!(page = (char *) __get_free_page(GFP_KERNEL)))
+        return(-ENOMEM);
+
+    if(count > PROC_BLOCK_SIZE) {
+        return(-EOVERFLOW);
+    }
+
+    ino = inode->i_ino;
+    
+    if(dispatch_scsi_info_ptr != NULL) {
+        memcpy_fromfs(page, buf, count);
+        ret = dispatch_scsi_info_ptr(ino, page, 0, 0, count, 1);
+    } else {
+        free_page((ulong) page);   
+        return(-ENOPKG);          /* Nothing here */
+    }
+    
+    free_page((ulong) page);
+    return(ret);
+}
+
+
+static int proc_scsilseek(struct inode * inode, struct file * file, 
+                          off_t offset, int orig)
+{
+    switch (orig) {
+    case 0:
+        file->f_pos = offset;
+        return(file->f_pos);
+    case 1:
+        file->f_pos += offset;
+        return(file->f_pos);
+    case 2:                  /* This ugly hack allows us to    */
+        if (offset)          /* to determine the length of the */
+            return(-EINVAL); /* file and then later savely to  */ 
+        proc_readscsi(inode, file, 0, -1); /* seek in it       */ 
+        return(file->f_pos);
+    default:
+        return(-EINVAL);
+    }
+}
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
index 5c6f8d1775e4cbd5b6e6b8c147df986b162b7db2..f8e9250ab91dd4b57f1f1f61954f6b1516479840 100644 (file)
@@ -44,7 +44,7 @@ extern inline void set_hae(unsigned long new_hae)
 /*
  * Change virtual addresses to physical addresses and vv.
  */
-extern inline unsigned long virt_to_phys(void * address)
+extern inline unsigned long virt_to_phys(volatile void * address)
 {
        return 0xffffffffUL & (unsigned long) address;
 }
@@ -90,4 +90,21 @@ extern void _outl (unsigned int l,unsigned long port);
 #include <asm/jensen.h>
 #endif
 
+/*
+ * String version of IO memory access ops:
+ */
+extern void memcpy_fromio(void *, unsigned long, unsigned long);
+extern void memcpy_toio(unsigned long, void *, unsigned long);
+extern void memset_io(unsigned long, int, unsigned long);
+
+/*
+ * String versions of in/out ops:
+ */
+extern void insb (unsigned long port, void *src, unsigned long count);
+extern void insw (unsigned long port, void *src, unsigned long count);
+extern void insl (unsigned long port, void *src, unsigned long count);
+extern void outsb (unsigned long port, void *dst, unsigned long count);
+extern void outsw (unsigned long port, void *dst, unsigned long count);
+extern void outsl (unsigned long port, void *dst, unsigned long count);
+
 #endif
index 7d9e38ece15ef432d0efcb3dfe0d613a0683100e..28deb22f97d8d8404accd199be7a66000a9e4dd1 100644 (file)
@@ -289,14 +289,6 @@ extern void outb(unsigned char b, unsigned long addr);
 extern void outw(unsigned short b, unsigned long addr);
 extern void outl(unsigned int b, unsigned long addr);
 
-/*
- * String versions of in/out ops:
- */
-extern void insw (unsigned long port, void *src, unsigned long count);
-extern void insl (unsigned long port, void *src, unsigned long count);
-extern void outsw (unsigned long port, void *dst, unsigned long count);
-extern void outsl (unsigned long port, void *dst, unsigned long count);
-
 extern unsigned long readb(unsigned long addr);
 extern unsigned long readw(unsigned long addr);
 
index f7d2b8380a794cee5abb59903bb7125f6e46058b..2fbbe40941f4bb9219da9bc19c099760c556b3d2 100644 (file)
@@ -43,7 +43,7 @@
  * make the kernel segment mapped at 0, we need to do translation
  * on the i386 as well)
  */
-extern inline unsigned long virt_to_phys(void * address)
+extern inline unsigned long virt_to_phys(volatile void * address)
 {
        return (unsigned long) address;
 }
@@ -65,23 +65,13 @@ extern inline void * phys_to_virt(unsigned long address)
  * differently. On the x86 architecture, we just read/write the
  * memory location directly.
  */
-extern inline unsigned long readb(unsigned long addr)
-{ return *(unsigned char *) addr; }
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
 
-extern inline unsigned long readw(unsigned long addr)
-{ return *(unsigned short *) addr; }
-
-extern inline unsigned long readl(unsigned long addr)
-{ return *(unsigned int *) addr; }
-
-extern inline void writeb(unsigned char b, unsigned long addr)
-{ *(unsigned char *) addr = b; }
-
-extern inline void writew(unsigned short b, unsigned long addr)
-{ *(unsigned short *) addr = b; }
-
-extern inline void writel(unsigned int b, unsigned long addr)
-{ *(unsigned int *) addr = b; }
+#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
 
 #define memset_io(a,b,c)       memset((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
index d9a45530c5bdc1cb1d9e2e7e8d8d145bf2d70a88..a54548ddef4ae7ab72cc95419ae54c60477d20a0 100644 (file)
@@ -79,8 +79,8 @@ extern void enable_irq(unsigned int);
        "inb $0x21,%al\n\t" \
        "jmp 1f\n" \
        "1:\tjmp 1f\n" \
-       "1:\torb $" #mask ",_cache_21\n\t" \
-       "movb _cache_21,%al\n\t" \
+       "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_21)"\n\t" \
+       "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
        "outb %al,$0x21\n\t" \
        "jmp 1f\n" \
        "1:\tjmp 1f\n" \
@@ -91,8 +91,8 @@ extern void enable_irq(unsigned int);
        "inb $0xA1,%al\n\t" \
        "jmp 1f\n" \
        "1:\tjmp 1f\n" \
-       "1:\torb $" #mask ",_cache_A1\n\t" \
-       "movb _cache_A1,%al\n\t" \
+       "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_A1)"\n\t" \
+       "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
        "outb %al,$0xA1\n\t" \
        "jmp 1f\n" \
        "1:\tjmp 1f\n" \
@@ -106,16 +106,16 @@ extern void enable_irq(unsigned int);
        "inb $0x21,%al\n\t" \
        "jmp 1f\n" \
        "1:\tjmp 1f\n" \
-       "1:\tandb $~(" #mask "),_cache_21\n\t" \
-       "movb _cache_21,%al\n\t" \
+       "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_21)"\n\t" \
+       "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
        "outb %al,$0x21\n\t"
 
 #define UNBLK_SECOND(mask) \
        "inb $0xA1,%al\n\t" \
        "jmp 1f\n" \
        "1:\tjmp 1f\n" \
-       "1:\tandb $~(" #mask "),_cache_A1\n\t" \
-       "movb _cache_A1,%al\n\t" \
+       "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_A1)"\n\t" \
+       "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
        "outb %al,$0xA1\n\t"
 
 #define IRQ_NAME2(nr) nr##_interrupt(void)
@@ -128,36 +128,36 @@ asmlinkage void IRQ_NAME(nr); \
 asmlinkage void FAST_IRQ_NAME(nr); \
 asmlinkage void BAD_IRQ_NAME(nr); \
 __asm__( \
-"\n.align 4\n" \
-"_IRQ" #nr "_interrupt:\n\t" \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        "pushl $-"#nr"-2\n\t" \
        SAVE_ALL \
        ACK_##chip(mask) \
-       "incl _intr_count\n\t"\
+       "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
        "sti\n\t" \
        "movl %esp,%ebx\n\t" \
        "pushl %ebx\n\t" \
        "pushl $" #nr "\n\t" \
-       "call _do_IRQ\n\t" \
+       "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
        "addl $8,%esp\n\t" \
        "cli\n\t" \
        UNBLK_##chip(mask) \
-       "decl _intr_count\n\t" \
+       "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
        "jmp ret_from_sys_call\n" \
-"\n.align 4\n" \
-"_fast_IRQ" #nr "_interrupt:\n\t" \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
        SAVE_MOST \
        ACK_##chip(mask) \
-       "incl _intr_count\n\t" \
+       "incl "SYMBOL_NAME_STR(intr_count)"\n\t" \
        "pushl $" #nr "\n\t" \
-       "call _do_fast_IRQ\n\t" \
+       "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
        "addl $4,%esp\n\t" \
        "cli\n\t" \
        UNBLK_##chip(mask) \
-       "decl _intr_count\n\t" \
+       "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
        RESTORE_MOST \
-"\n\n.align 4\n" \
-"_bad_IRQ" #nr "_interrupt:\n\t" \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
        SAVE_MOST \
        ACK_##chip(mask) \
        RESTORE_MOST);
index b4108d5111d424e2bdcb5e1d16deb9702afe4b77..cfef29d9fb2981ac6afe9a702bd3b958e70a4b54 100644 (file)
@@ -49,10 +49,10 @@ __asm__("str %%ax\n\t" \
  */
 #define switch_to(tsk) do { \
 __asm__("cli\n\t" \
-       "xchgl %%ecx,_current\n\t" \
+       "xchgl %%ecx,"SYMBOL_NAME_STR(current)"\n\t" \
        "ljmp %0\n\t" \
        "sti\n\t" \
-       "cmpl %%ecx,_last_task_used_math\n\t" \
+       "cmpl %%ecx,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \
        "jne 1f\n\t" \
        "clts\n" \
        "1:" \
diff --git a/include/asm-sparc/version.h b/include/asm-sparc/version.h
deleted file mode 100644 (file)
index 0c238e9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#define WHO_COMPILED_ME "someone@somewhere.domain"
diff --git a/include/asm-sparc/wim.h b/include/asm-sparc/wim.h
deleted file mode 100644 (file)
index 74b0a65..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* wim.h: Defines the layout of the "Window Invalid Register" on
-          Version 8 of the Sparc Architecture.
-
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
-
-#ifndef __LINUX_SPARC_WIM_H
-#define __LINUX_SPARC_WIM_H
-
-#ifdef __LINUX_SPARC_V8     /* register doesn't exist on the V9 */
-
-/* The Window Invalid Register %wim, holds a set of which register
-   windows are 'valid' at this point in time.
-
-   ------------------------------------------------------------
-   |W31|W30|W29|W28|W27|W26|W25|W24|W23|....|W5|W4|W3|W2|W1|W0|
-   ------------------------------------------------------------
-
-   Each register window on the chip gets one bit. If the bit is
-   set then the window is currently 'invalid' and hardware will
-   trap if that window is entered via a 'save', 'restore', or
-   'rett' instruction. Privileged software is responsible for
-   updating this on trap fills/spills etc. Therefore if a 'save'
-   instruction is executed and it causes the Current Window
-   Pointer to equal a register window which has its bit set in
-   %wim we get a 'overflow' trap, a restore into such a register
-   invokes a window 'spill' trap.
-*/
-
-#define __LINUX_SPARC_HAS_WIM
-
-/* Macro to fine the %wim bit mask for the current window pointer */
-#define CWP_TO_WIM_MASK(cwp)  (1<<(cwp))
-
-/* Assembly version of above macro, 'cwp' and 'wimask' must be registers */
-#define ASM_CWP_TO_WIM_MASK(cwp,wimask) \
-          or  %g0, 0x1, wimask \
-          sll wimask, cwp, wimask
-
-/* Assembly macro to find if the given window is set to invalid in the %wim.
-   Again 'window', 'result', and 'scratch' must be in registers. This leaves 
-   a non-zero value in result if the window is indeed invalid. This routine
-   works because we keep exactly one window invalid at all times to maximize
-   register utilization, which means both kernel and user windows can be in
-   the register file at the same time in certain trap situations.
-*/
-#define ASM_REG_WIN_INVAL(window,result,scratch) \
-         rd  %wim, result \
-         or  %g0, 0x1, scratch \
-         sll scratch, window, scratch \
-         and scratch, result, result
-
-#endif /* !(__LINUX_SPARC_V8) */
-
-#endif  /* !(__LINUX_SPARC_WIM_H) */
-
diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h
new file mode 100644 (file)
index 0000000..9ccf264
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef _LINUX_ELFCORE_H
+#define _LINUX_ELFCORE_H
+
+#include <linux/types.h>
+#include <linux/signal.h>
+#include <linux/time.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+struct elf_siginfo
+{
+       int     si_signo;                       /* signal number */
+       int     si_code;                        /* extra code */
+       int     si_errno;                       /* errno */
+};
+
+typedef unsigned long elf_greg_t;
+#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+typedef struct
+#ifdef __i386__
+       user_i387_struct
+#else
+#error "The FPU in this arch is not supported by ELF core dump.".
+#endif
+elf_fpregset_t;
+
+#ifndef __KERNEL__
+typedef elf_greg_t greg_t;
+typedef elf_gregset_t gregset_t;
+typedef elf_fpregset_t fpregset_t;
+#define NGREG ELF_NGREG
+#endif
+
+/*
+ * Definitons to generate Intel SVR4-like core files.
+ * These mostly have the same names as the SVR4 types with "elf_"
+ * tacked on the front to prevent clashes with linux definitions,
+ * and the typedef forms have been avoided.  This is mostly like
+ * the SVR4 structure, but more Linuxy, with things that Linux does
+ * not support and which gdb doesn't really use excluded.
+ * Fields present but not used are marked with "XXX".
+ */
+struct elf_prstatus
+{
+#if 0
+       long    pr_flags;       /* XXX Process flags */
+       short   pr_why;         /* XXX Reason for process halt */
+       short   pr_what;        /* XXX More detailed reason */
+#endif
+       struct elf_siginfo pr_info;     /* Info associated with signal */
+       short   pr_cursig;      /* Current signal */
+       sigset_t pr_sigpend;    /* Set of pending signals */
+       sigset_t pr_sighold;    /* Set of held signals */
+#if 0
+       struct sigaltstack pr_altstack; /* Alternate stack info */
+       struct sigaction pr_action;     /* Signal action for current sig */
+#endif
+       pid_t   pr_pid;
+       pid_t   pr_ppid;
+       pid_t   pr_pgrp;
+       pid_t   pr_sid;
+       struct timeval pr_utime;        /* User time */
+       struct timeval pr_stime;        /* System time */
+       struct timeval pr_cutime;       /* Cumulative user time */
+       struct timeval pr_cstime;       /* Cumulative system time */
+#if 0
+       long    pr_instr;               /* Current instruction */
+#endif
+       elf_gregset_t pr_reg;   /* GP registers */
+       int pr_fpvalid;         /* True if math co-processor being used.  */
+};
+
+#define ELF_PRARGSZ    (80)    /* Number of chars for args */
+
+struct elf_prpsinfo
+{
+       char    pr_state;       /* numeric process state */
+       char    pr_sname;       /* char for pr_state */
+       char    pr_zomb;        /* zombie */
+       char    pr_nice;        /* nice val */
+       unsigned long pr_flag;  /* flags */
+       uid_t   pr_uid;
+       gid_t   pr_gid;
+       pid_t   pr_pid, pr_ppid, pr_pgrp, pr_sid;
+       /* Lots missing */
+       char    pr_fname[16];   /* filename of executable */
+       char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+#ifndef __KERNEL__
+typedef struct elf_prstatus prstatus_t;
+typedef struct elf_prpsinfo prpsinfo_t;
+#define PRARGSZ ELF_PRARGSZ 
+#endif
+
+#endif /* _LINUX_ELFCORE_H */
index 8f5c4d5f2a04d8e17c7603f02c024cf111755815..c8a7a491a9b765d4c345ec865c2fa53a49785499 100644 (file)
@@ -7,4 +7,53 @@
 #define asmlinkage
 #endif
 
+#ifdef __ELF__
+#define SYMBOL_NAME_STR(X) #X
+#define SYMBOL_NAME(X) X
+#ifdef __STDC__
+#define SYMBOL_NAME_LABEL(X) X##:
+#else
+#define SYMBOL_NAME_LABEL(X) X/**/:
+#endif
+#else
+#define SYMBOL_NAME_STR(X) "_"#X
+#ifdef __STDC__
+#define SYMBOL_NAME(X) _##X
+#define SYMBOL_NAME_LABEL(X) _##X##:
+#else
+#define SYMBOL_NAME(X) _/**/X
+#define SYMBOL_NAME_LABEL(X) _/**/X/**/:
+#endif
+#endif
+
+#if !defined(__i486__) && !defined(__i586__)
+#ifdef __ELF__
+#define __ALIGN .align 4,0x90
+#define __ALIGN_STR ".align 4,0x90"
+#else  /* __ELF__ */
+#define __ALIGN .align 2,0x90
+#define __ALIGN_STR ".align 2,0x90"
+#endif /* __ELF__ */
+#else  /* __i486__/__i586__ */
+#ifdef __ELF__
+#define __ALIGN .align 16,0x90
+#define __ALIGN_STR ".align 16,0x90"
+#else  /* __ELF__ */
+#define __ALIGN .align 4,0x90
+#define __ALIGN_STR ".align 4,0x90"
+#endif /* __ELF__ */
+#endif /* __i486__/__i586__ */
+
+#ifdef __ASSEMBLY__
+
+#define ALIGN __ALIGN
+#define ALIGN_STRING __ALIGN_STRING
+
+#define ENTRY(name) \
+  .globl SYMBOL_NAME(name); \
+  ALIGN; \
+  SYMBOL_NAME_LABEL(name)
+
+#endif
+
 #endif
index fd17ef1704ea545eb3ff75365dfa89e7d8ad62de..39219655d419613bbe58863866d0fbbf1973300e 100644 (file)
@@ -235,6 +235,9 @@ extern unsigned long get_unmapped_area(unsigned long, unsigned long);
 
 #define GFP_DMA                0x80
 
+#define GFP_LEVEL_MASK 0xf
+
+
 /*
  * vm_ops not present page codes for shared memory.
  *
index 0be42eadc165afc30de431ada72de564989ce526..c5e9d95f25120ba4951ab60b2ce9efb9c43dec47 100644 (file)
@@ -47,7 +47,7 @@
 #define PCI_DEVICE_ID          0x02    /* 16 bits */
 #define PCI_COMMAND            0x04    /* 16 bits */
 #define  PCI_COMMAND_IO                0x1     /* Enable response in I/O space */
-#define  PCI_COMMAND_MEMORY    0x2     /* Enable response in I/O space */
+#define  PCI_COMMAND_MEMORY    0x2     /* Enable response in Memory space */
 #define  PCI_COMMAND_MASTER    0x4     /* Enable bus mastering */
 #define  PCI_COMMAND_SPECIAL   0x8     /* Enable response to special cycles */
 #define  PCI_COMMAND_INVALIDATE        0x10    /* Use memory write and invalidate */
 #define PCI_VENDOR_ID_ADAPTEC          0x9004
 #define PCI_DEVICE_ID_ADAPTEC_2940     0x7178
 #define PCI_DEVICE_ID_ADAPTEC_294x     0x7078
+#define PCI_DEVICE_ID_ADAPTEC_7850     0x5078
 
 #define PCI_VENDOR_ID_DPT               0x1044   
 #define PCI_DEVICE_ID_DPT               0xa400  
 #define PCI_DEVICE_ID_UMC_UM8881F      0x8881
 #define PCI_DEVICE_ID_UMC_UM8891A      0x0891
 #define PCI_DEVICE_ID_UMC_UM8886F      0x8886
+#define PCI_DEVICE_ID_UMC_UM8886A      0x886a
 #define PCI_DEVICE_ID_UMC_UM8673F      0x0101
 
 #define PCI_VENDOR_ID_DEC              0x1011
 #define PCI_DEVICE_ID_DEC_TULIP                0x0002
 #define PCI_DEVICE_ID_DEC_TULIP_FAST   0x0009
+#define PCI_DEVICE_ID_DEC_TULIP_PLUS   0x0014
 #define PCI_DEVICE_ID_DEC_FDDI         0x000F
 #define PCI_DEVICE_ID_DEC_BRD          0x0001
 
 #define PCI_DEVICE_ID_CIRRUS_5434_4    0x00A4
 #define PCI_DEVICE_ID_CIRRUS_5434_8    0x00A8
 #define PCI_DEVICE_ID_CIRRUS_6729      0x1100
+#define PCI_DEVICE_ID_CIRRUS_7542      0x1200
 
 #define PCI_VENDOR_ID_BUSLOGIC         0x104B
 #define PCI_DEVICE_ID_BUSLOGIC_946C    0x1040
 #define PCI_VENDOR_ID_X                        0x1061
 #define PCI_DEVICE_ID_X_AGX016         0x0001
 
+#define PCI_VENDOR_ID_ACC              0x10aa
+
+#define PCI_VENDOR_ID_VORTEX           0x1119
+#define PCI_DEVICE_ID_VORTEX_GDT       0x0001
+
+
 /*
  * The PCI interface treats multi-function devices as independent
  * devices.  The slot/function address of each device is encoded
index c70aa162aeac9ba6541fcf9c39fc0dc2c214060b..c082c7a6e3f0560bceda1335758de119094bb029 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_PROC_FS_H
 
 #include <linux/config.h>
+#include <linux/fs.h>
 
 /*
  * The proc filesystem constants/structures
@@ -18,6 +19,7 @@ enum root_directory_inos {
        PROC_PCI,
        PROC_SELF,      /* will change inode # */
        PROC_NET,
+        PROC_SCSI,
 #ifdef CONFIG_DEBUG_MALLOC
        PROC_MALLOC,
 #endif
@@ -104,6 +106,32 @@ enum net_directory_inos {
        PROC_NET_LAST
 };
 
+enum scsi_directory_inos {
+       PROC_SCSI_SCSI = 256,
+       PROC_SCSI_EATA,
+       PROC_SCSI_EATA_PIO,
+       PROC_SCSI_AHA152X,
+       PROC_SCSI_AHA1542,
+       PROC_SCSI_AHA1740,
+       PROC_SCSI_AIC7XXX,
+       PROC_SCSI_BUSLOGIC,
+       PROC_SCSI_U14_34F,
+       PROC_SCSI_FUTURE_DOMAIN,
+       PROC_SCSI_GENERIC_NCR5380,
+       PROC_SCSI_IN2000,
+       PROC_SCSI_PAS16,
+       PROC_SCSI_QLOGIC,
+       PROC_SCSI_SEAGATE,
+       PROC_SCSI_T128,
+       PROC_SCSI_NCR53C7xx,
+       PROC_SCSI_ULTRASTOR,
+       PROC_SCSI_7000FASST,
+       PROC_SCSI_SCSI_DEBUG,   
+       PROC_SCSI_NOT_PRESENT,
+       PROC_SCSI_FILE,                        /* I'm asuming here that we */
+       PROC_SCSI_LAST = (PROC_SCSI_FILE + 16) /* won't ever see more than */
+};                                             /* 16 HBAs in one machine   */
+
 #define PROC_SUPER_MAGIC 0x9fa0
 
 struct proc_dir_entry {
@@ -123,6 +151,7 @@ extern int proc_match(int, const char *, struct proc_dir_entry *);
 extern struct inode_operations proc_root_inode_operations;
 extern struct inode_operations proc_base_inode_operations;
 extern struct inode_operations proc_net_inode_operations;
+extern struct inode_operations proc_scsi_inode_operations;
 extern struct inode_operations proc_mem_inode_operations;
 extern struct inode_operations proc_array_inode_operations;
 extern struct inode_operations proc_arraylong_inode_operations;
index c6f69368704a1f3c7663c5b83d1be180716b7724..bfeb0702608ef972641e2db1b2954698a44acc94 100644 (file)
@@ -1,16 +1,19 @@
+#include <linux/linkage.h>
 #ifdef CONFIG_MODVERSIONS /* CONFIG_MODVERSIONS */
 #undef _set_ver
 #undef X
 #ifndef __GENKSYMS__
 #ifdef MODULE
-#define _set_ver(sym,ver) { (void *) & sym ## _R ## ver, "_" #sym "_R" #ver }
+#define _set_ver(sym,ver) \
+       { (void *) & sym ## _R ## ver, SYMBOL_NAME_STR(sym) "_R" #ver }
 #else /* MODULE */
-#define _set_ver(sym,ver) { (void *) & sym, "_" #sym "_R" #ver }
+#define _set_ver(sym,ver) \
+       { (void *) & sym, SYMBOL_NAME_STR(sym) "_R" #ver }
 #endif /* MODULE */
 #define X(a) a
 #endif /* __GENKSYMS__ */
 #else /* CONFIG_MODVERSIONS */
-#define X(sym) { (void *) & sym, "_" #sym }
+#define X(sym) { (void *) & sym, SYMBOL_NAME_STR(sym)}
 #endif /* CONFIG_MODVERSIONS */
 #define EMPTY {0,0}
        0, 0, 0, {
index 37c4a582ca83101d5bce36adabde16f3e5033ecc..bb33bdbecc996a4bc26596ea2ad2dfcac3d0d954 100644 (file)
  * These are system calls that haven't been implemented yet
  * but have an entry in the table for future expansion..
  */
+#ifdef __ELF__
+#define sys_quotactl   sys_ni_syscall
+#else
 #define _sys_quotactl  _sys_ni_syscall
+#endif
 
 #endif
index ce82e020ff5a8d599e4f607f9f4ba983594ab02d..2078382202aa5a26db143908fe5388a7dcd6a617 100644 (file)
@@ -88,6 +88,19 @@ struct timex {
                                 */
        struct timeval time;    /* (read only) */
        long tick;              /* (modified) usecs between clock ticks */
+
+       long ppsfreq;           /* pps frequency (scaled ppm) (ro) */
+       long jitter;            /* pps jitter (us) (ro) */
+       int shift;              /* interval duration (s) (shift) (ro) */
+       long stabil;            /* pps stability (scaled ppm) (ro) */
+       long jitcnt;            /* jitter limit exceeded (ro) */
+       long calcnt;            /* calibration intervals (ro) */
+       long errcnt;            /* calibration errors (ro) */
+       long stbcnt;            /* stability limit exceeded (ro) */
+
+       int  :32; int  :32; int  :32; int  :32;
+       int  :32; int  :32; int  :32; int  :32;
+       int  :32; int  :32; int  :32; int  :32;
 };
 
 /*
index 9e4870bf54945d902bb0cba5cb74a465169facba..8aa9ce43c19d4d24507c54df871a11d087ad8ac2 100644 (file)
@@ -71,8 +71,14 @@ extern char * ftape_big_buffer;
 #include "../drivers/scsi/scsi.h"
 #include "../drivers/scsi/hosts.h"
 #include "../drivers/scsi/constants.h"
+
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
 #endif
 
+int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start, 
+                               off_t offset, int length, 
+                               int inode, int func) = 0; /* Dirty hack */
+
 extern int sys_tz;
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
@@ -83,7 +89,8 @@ extern void (* iABI_hook)(struct pt_regs * regs);
 struct symbol_table symbol_table = {
 #include <linux/symtab_begin.h>
 #ifdef CONFIG_MODVERSIONS
-       { (void *)1 /* Version version :-) */, "_Using_Versions" },
+       { (void *)1 /* Version version :-) */,
+               SYMBOL_NAME_STR (Using_Versions) },
 #endif
        /* stackable module support */
        X(rename_module_symbol),
@@ -144,6 +151,7 @@ struct symbol_table symbol_table = {
        X(close_fp),
        X(check_disk_change),
        X(invalidate_buffers),
+       X(invalidate_inodes),
        X(fsync_dev),
        X(permission),
        X(inode_setattr),
@@ -325,8 +333,13 @@ struct symbol_table symbol_table = {
        X(kill_fasync),
 #endif
 #ifdef CONFIG_SCSI
-       /* Supports loadable scsi drivers */
-       /* 
+       /* Supports loadable scsi drivers 
+        * technically some of this stuff could be moved to scsi.c, but
+        * scsi.c is initialized before the memory manager is set up.
+        * So we add it here too.  There is a duplicate set in scsi.c
+        * that is used when the entire scsi subsystem is a loadable
+        * module.
+        * 
         * in_scan_scsis is a hack, and should go away once the new 
         * memory allocation code is in the NCR driver 
         */
@@ -338,9 +351,26 @@ struct symbol_table symbol_table = {
        X(scsi_register),
        X(scsi_unregister),
        X(scsicam_bios_param),
-        X(scsi_init_malloc),
-        X(scsi_init_free),
-       X(print_command),
+       X(allocate_device),
+       X(scsi_do_cmd),
+       X(scsi_command_size),
+       X(scsi_init_malloc),
+       X(scsi_init_free),
+       X(scsi_ioctl),
+       X(print_command),
+       X(print_msg),
+       X(print_status),
+       X(print_sense),
+       X(dma_free_sectors),
+       X(kernel_scsi_ioctl),
+       X(need_isa_buffer),
+       X(request_queueable),
+       X(dispatch_scsi_info_ptr),
+       X(generic_proc_info),
+       X(scsi_devices),
+       X(free_pages),
+       X(intr_count),
+       X(mem_map),
        X(print_msg),
        X(print_status),
 #endif
index f0d6589bcb407d190cab45631067ce4d7cb69526..b868ecd5779b2cbe88db11e1dee9bcb7f6a7a100 100644 (file)
@@ -27,7 +27,7 @@ static char buf[1024];
 
 extern void console_print(const char *);
 
-#define DEFAULT_MESSAGE_LOGLEVEL 7 /* KERN_DEBUG */
+#define DEFAULT_MESSAGE_LOGLEVEL 6 /* KERN_INFO */
 #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything more serious than KERN_DEBUG */
 
 unsigned long log_size = 0;
@@ -164,7 +164,7 @@ asmlinkage int printk(const char *fmt, ...)
                        ) {
                                p -= 3;
                                p[0] = '<';
-                               p[1] = DEFAULT_MESSAGE_LOGLEVEL - 1 + '0';
+                               p[1] = DEFAULT_MESSAGE_LOGLEVEL + '0';
                                p[2] = '>';
                        } else
                                msg += 3;
index 244f1ebf808d7ba19ab74a16319a98e34586be77..70ea181efa9bd285982faf75fd6ed9e243345a12 100644 (file)
@@ -17,8 +17,6 @@
 #include <asm/system.h>
 #include <asm/dma.h>
 
-#define GFP_LEVEL_MASK 0xf
-
 /* I want this low enough for a while to catch errors.
    I want this number to be increased in the near future:
         loadable device drivers should use this function to get memory */
index 930ae4623ae67a033e5651acf2f9597898de6f63..97b02d4d127bc8cf892bb469cb64a5b6e1243d08 100644 (file)
@@ -24,7 +24,7 @@ all:          network.a
 
 network.a:     subdirs $(OBJS)
                rm -f $@
-               ar rcs $@ $(OBJS) $(SUBOBJS)
+               $(AR) rcs $@ $(OBJS) $(SUBOBJS)
 
 subdirs:       dummy
                set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done