diff -u --recursive --new-file v2.0.25/linux/CREDITS linux/CREDITS
--- v2.0.25/linux/CREDITS	Wed Nov 13 11:26:21 1996
+++ linux/CREDITS	Tue Nov 19 16:21:06 1996
@@ -68,7 +68,7 @@
 N: Dario Ballabio
 E: dario@milano.europe.dg.com
 D: Author and maintainer of the Ultrastor 14F/34F SCSI driver
-D: Author and maintainer of the EATA ISA/EISA SCSI driver
+D: Author and maintainer of the EATA ISA/EISA/PCI SCSI driver
 S: Data General Corporation
 S: Milano
 S: Italy
@@ -370,6 +370,14 @@
 S: Myrstuguv. 83
 S: S-143 32 VARBY
 S: Sweden
+
+N: Fritz Elfert
+E: fritz@wuemaus.franken.de
+D: ISDN subsystem
+D: ICN ISDN driver
+S: Grombuehlstr. 11r
+S: 97080 Wuerzburg
+S: Germany
 
 N: Paal-Kristian Engstad
 E: engstad@funcom.com
diff -u --recursive --new-file v2.0.25/linux/Documentation/Changes linux/Documentation/Changes
--- v2.0.25/linux/Documentation/Changes	Sat Oct 19 10:06:10 1996
+++ linux/Documentation/Changes	Wed Nov 13 08:23:13 1996
@@ -34,7 +34,10 @@
 bunshou no nihongo ban wa
 http://jf.gee.kyoto-u.ac.jp/JF/v2.0/Changes-2.0.html ni arimasu.
 
-Last updated: October 12, 1996.
+   Voyez le site http://www.linux-kheops.com/traduc/kernels/ pour la
+traduction francais (merci, David Bourgin).  (French translation)
+
+Last updated: November 5, 1996.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Releases
@@ -43,16 +46,16 @@
 - Kernel modules	 2.0.0
 - PPP daemon		 2.2.0f
 - Dynamic linker (ld.so) 1.7.14
-- GNU CC		 2.7.2
+- GNU CC		 2.7.2.1
 - Binutils		 2.7.0.3
-- Linux C Library	 Stable:  5.2.18, Beta:  5.3.12 / 5.4.7
-- Linux C++ Library	 2.7.1.4
+- Linux C Library	 Stable:  5.2.18, Beta:  5.4.10
+- Linux C++ Library	 2.7.2.1
 - Termcap		 2.0.8
 - Procps		 1.01
 - Gpm			 1.10
 - SysVinit		 2.64
 - Util-linux		 2.5
-- Mount                  2.5k
+- Mount                  2.5p
 - Net-tools              1.32-alpha
 - Kbd                    0.91
 
@@ -69,11 +72,11 @@
 127.0.0.1' in your network configuration files and change it to `route
 add -net 127.0.0.0'.
 
-   This error is present in all Red Hat distributions (and derivative
-distributions like Caldera).  If you're running one of these, edit
-/etc/sysconfig/network-scripts/ifup-lo, changing the line `route add
--net $(IPADDR)' to `route add -net 127.0.0.0' and you should be fine.
-The new Red Hat 4.0 (Colgate) distribution does not have this problem.
+   This error is present in all Red Hat distributions through Red Hat
+3.03 (and derivative distributions like Caldera).  If you're running
+one of these, edit /etc/sysconfig/network-scripts/ifup-lo, changing the
+line `route add -net $(IPADDR)' to `route add -net 127.0.0.0' and you
+should be fine.
 
    People have also reported problems due to the naming of the dummy
 network interface driver.  If the dummy driver is compiled into the
@@ -134,9 +137,8 @@
 
    Also, the libc-5.3.x line has a known security hole relating to
 rlogin.  Libc-5.3.12 fixes this, so if you're going to run an
-experimental libc, be sure to upgrade to 5.3.12.  Libc-5.4.7 is
-currently available as well, but it has a few problems of its own (a
-few missing symbols, for example, that will break existing apps).
+experimental libc, be sure to upgrade to 5.3.12.  Libc-5.4.10 is
+currently available as well, but it may have problems, so caveat emptor.
 
    If you're getting an error message that is something to the effect of
 
@@ -271,7 +273,7 @@
 details.  Among the programs this has impacted are older sendmails.  If
 you get a message that sendmail cannot lock aliases.dir (or other
 files), you'll need to upgrade to at least 8.7.x. The latest sendmail
-is at ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/sendmail.8.7.5.tar.gz.
+is at ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/sendmail.8.8.2.tar.gz.
 
 Uugetty
 =======
@@ -293,7 +295,7 @@
 currently at release 2.5.  Some may find, especially when using the
 loop or xiafs file system, NFS, or automounting, that they need to
 upgrade to the latest release of mount, available from
-ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5k.tar.gz.
+ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5p.tar.gz.
 
 Console
 =======
@@ -504,7 +506,7 @@
 
    For a version of Dosemu that works (well, at least as well as DOS
 ever works ;-), get
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.55.tgz
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.64.0.3.tgz
 or check out http://www.ednet.ns.ca/auto/rddc. Be sure to follow the
 instructions in README.newkernels about patching your include files, or
 it will not compile.
@@ -584,7 +586,8 @@
 *************************************************
 
    There are some simple methods useful to know the version of the
-installed programs and libraries.
+installed programs and libraries.  The SysVinit version display
+requires that you be logged in as root.
 
 GNU CC: gcc -v and gcc --version
 PPP: pppd -h (wrong but it show the version)
@@ -595,6 +598,8 @@
 termcap: ls -l /lib/libtermcap.so.*
 modules: insmod -V
 procps: ps --version
+SysVinit: cat /proc/`cat /var/run/syslog.pid`/environ|strings|awk '$1 ~
+/INIT_VERSION/ {print}'
 
 Where to get the files
 **********************
@@ -602,16 +607,16 @@
 Binutils
 ========
 
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.7.0.3.bin.tar.gz
+ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/binutils-2.7.0.3.bin.tar.gz
 Installation notes:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.7.0.3
+ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/release.binutils-2.7.0.3
 
 GNU CC
 ======
 
-ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.1.bin.tar.gz
 Installation notes:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.1
 
 Linux C Library
 ===============
@@ -621,10 +626,10 @@
 Installation notes for 5.2.18:
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.2.18
 
-The latest 5.3.12 release:
-ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.3.12.bin.tar.gz
-Installation notes for 5.3.12:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.3.12
+The latest 5.4.10 release:
+ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.10.bin.tar.gz
+Installation notes for 5.4.10:
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.10
 
 Patched make sources:
 ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74.patched.tar.gz
@@ -634,12 +639,9 @@
 Linux C++ Library
 =================
 
-ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.4.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.3.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.2.1.bin.tar.gz
 Installation notes:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.4
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.3
-Use 2.7.13 with libc 5.2.18 and 2.7.14 with libc 5.3.12.
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.1
 
 Dynamic Linker
 ==============
@@ -712,11 +714,9 @@
    For others, David Bourgin has put together a package of everything
 necessary to quickly and easily upgrade to 2.0.x.  See
 ftp://ftp.wsc.com/pub/freeware/linux/update.linux/ for more information
-and the files.  This package also includes many bug-fixes, including
-one for a recently discovered bug in sendmail-8.7.5 (just look at
-/pub/freeware/linux/update.linux/updat2-0.addon1/sendmail-8.7.5a.tar.gz
-if you only need the bug fix).  There's also an alternate lightweight
-termcap in the same directory that works well for many people.
+and the files.  This package also includes many bug-fixes, such as the
+latest sendmail. There's also an alternate lightweight termcap in the
+same directory that works well for many people.
 
 Please send info about any other packages that 2.0.x "broke" or about
 any new features of 2.0.x that require extra or new packages for use to
diff -u --recursive --new-file v2.0.25/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.0.25/linux/Documentation/Configure.help	Tue Oct  8 21:20:08 1996
+++ linux/Documentation/Configure.help	Tue Nov 19 16:21:06 1996
@@ -1381,14 +1381,14 @@
 
 UltraStor 14F/34F support
 CONFIG_SCSI_U14_34F
-  This is support for the UltraStor 14F, 24F and 34F SCSI-2 host
-  adaptor family. The source at drivers/scsi/u14-34f.c contains some
-  information about this hardware. If the driver doesn't work out of
-  the box, you may have to change some settings in
-  drivers/scsi/u14-34f.h. Read the SCSI-HOWTO, available via ftp
-  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note
-  that there is also another driver for the same hardware: "UltraStor
-  SCSI support", below. You should only enable one of them. This
+  This is support for the UltraStor 14F and 34F SCSI-2 host adapters.
+  The source at drivers/scsi/u14-34f.c contains some information about 
+  this hardware. If the driver doesn't work out of the box, you may have 
+  to change some settings in drivers/scsi/u14-34f.c.
+  Read the SCSI-HOWTO, available via ftp (user: anonymous) at 
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that there is also another
+  driver for the same hardware: "UltraStor SCSI support", below.
+  You should enable both only if you want 24F support as well. This
   driver is also available as a module ( = code which can be inserted
   in and removed from the running kernel whenever you want). If you
   want to compile it as a module, say M here and read
@@ -1626,9 +1626,8 @@
   drivers/scsi/ultrastor.h. If you want to compile this as a module (
   = code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
-  Note that there is also another driver for the same hardware:
-  "UltraStor 14F/34F support", above. You should only enable one of
-  them.
+  Note that there is also another driver for UltraStor hardware:
+  "UltraStor 14F/34F support", above.
  
 7000FASST SCSI support
 CONFIG_SCSI_7000FASST
@@ -1639,12 +1638,16 @@
   want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
-EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support
+EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support
 CONFIG_SCSI_EATA
-  This driver supports all the DPT SCSI host adapters, such as
-  PM2011B/9X, PM2021A/9X, PM2012A, PM1012B, PM2022A/9X, PM2122A/9X and
-  PM2322A/9X. Note that the PM2001 is not supported by this
-  driver. You want to read the start of drivers/scsi/eata.c and the
+  This driver supports all the EATA/DMA-compliant SCSI host adapters
+  and does not need any BIOS32 or PCI BIOS service.
+  Only ISA (0x1F0, 0x170, 0x230, 0x330) and EISA (0x1C88 through 0xFC88)
+  addresses are probed. In order to detect a generic EATA PCI board you
+  can force on it any unused EISA address.
+  Note that there is also another driver for the same hardware:
+  "EATA-DMA support". You should enable only one of them.
+  You want to read the start of drivers/scsi/eata.c and the
   SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
   as a module ( = code which can be inserted in and removed from the
diff -u --recursive --new-file v2.0.25/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE
--- v2.0.25/linux/Documentation/isdn/INTERFACE	Sat Jun 29 20:36:22 1996
+++ linux/Documentation/isdn/INTERFACE	Wed Nov 13 08:36:19 1996
@@ -1,4 +1,4 @@
-$Id: INTERFACE,v 1.3 1996/06/25 17:52:41 fritz Exp $
+$Id: INTERFACE,v 1.5 1996/11/06 17:40:47 keil Exp $
 
 Description of the Interface between Linklevel and Hardwarelevel
   of isdn4linux:
@@ -497,6 +497,12 @@
       num         = ASCII-String in the following format:
                     "%s,%d,%d,%s",CallerNumber,ServiceIndicator,AddInfo,
                     CalledNumber.
+    Return:
+      0           = No device matching this call.
+      1           = At least one device matching this call (RING on ttyI).
+                    HL-driver may send ALERTING on the D-channel in this case.
+      2           = Call will be rejected.
+      -1          = An error happened. (Invalid parameters for example.)
 
   ISDN_STAT_RUN:
 
diff -u --recursive --new-file v2.0.25/linux/Documentation/unicode.txt linux/Documentation/unicode.txt
--- v2.0.25/linux/Documentation/unicode.txt	Sat Mar  2 13:18:47 1996
+++ linux/Documentation/unicode.txt	Tue Nov 12 10:30:48 1996
@@ -20,18 +20,20 @@
 
 In accordance with the Unicode standard/ISO 10646 the range U+F000 to
 U+F8FF has been reserved for OS-wide allocation (the Unicode Standard
-refers to this as a "Corporate Zone").  U+F000 was picked as the
-starting point since it lets the direct-mapping area start on a large
-power of two (in case 1024- or 2048-character fonts ever become
-necessary).  This leaves U+E000 to U+EFFF as End User Zone.
+refers to this as a "Corporate Zone", since this is inaccurate for
+Linux we call it the "Linux Zone").  U+F000 was picked as the starting
+point since it lets the direct-mapping area start on a large power of
+two (in case 1024- or 2048-character fonts ever become necessary).
+This leaves U+E000 to U+EFFF as End User Zone.
 
 The Unicodes in the range U+F000 to U+F1FF have been hard-coded to map
 directly to the loaded font, bypassing the translation table.  The
 user-defined map now defaults to U+F000 to U+F1FF, emulating the
-previous behaviour.
+previous behaviour.  This range may expand in the future should it be
+warranted.
 
-Actual characters assigned in the Corporate Zone
-------------------------------------------------
+Actual characters assigned in the Linux Zone
+--------------------------------------------
 
 In addition, the following characters not present in Unicode 1.1.4 (at
 least, I have not found them!) have been defined; these are used by
@@ -58,7 +60,7 @@
 about the whole 16-bit concept to begin with.)  However, with Linux
 being a hacker-driven OS it seems this is a brilliant linguistic hack
 worth supporting.  Hence I have chosen to add it to the list in the
-Linux "Corporate" Zone.
+Linux Zone.
 
 Several glyph forms for the Klingon alphabet has been proposed.
 However, since the set of symbols appear to be consistent throughout,
@@ -122,5 +124,16 @@
 U+F8F8	KLINGON DIGIT EIGHT
 U+F8F9	KLINGON DIGIT NINE
 
+Other Fictional and Artificial Scripts
+--------------------------------------
 
-	H. Peter Anvin <hpa@storm.net>
+Since the assignment of the Klingon Linux Unicode block, a registry of
+fictional and artificial scripts has been established by John Cowan,
+<cowan@ccil.org>.  The ConScript Unicode Registry is accessible at
+http://locke.ccil.org/~cowan/csur/; the ranges used fall at the bottom
+of the End User Zone and can hence not be normatively assigned, but it
+is recommended that people who wish to encode fictional scripts use
+these codes, in the interest of interoperability.  For Klingon, CSUR
+has adopted the Linux encoding.
+
+	H. Peter Anvin <hpa@zytor.com>
diff -u --recursive --new-file v2.0.25/linux/MAINTAINERS linux/MAINTAINERS
--- v2.0.25/linux/MAINTAINERS	Thu Oct 31 12:08:50 1996
+++ linux/MAINTAINERS	Tue Nov 19 16:21:06 1996
@@ -135,16 +135,16 @@
 W:	http://www.cyclades.com/
 S:	Supported
 
-EATA ISA/EISA SCSI DRIVER
+EATA ISA/EISA/PCI SCSI DRIVER
 P:	Dario Ballabio
 M:	dario@milano.europe.dg.com
-L:	linux-kernel@vger.rutgers.edu
+L:	linux-scsi@vger.rutgers.edu
 S:	Maintained
 
 U14-34F SCSI DRIVER
 P:	Dario Ballabio
 M:	dario@milano.europe.dg.com
-L:	linux-kernel@vger.rutgers.edu
+L:	linux-scsi@vger.rutgers.edu
 S:	Maintained
 
 EATA-DMA SCSI DRIVER
diff -u --recursive --new-file v2.0.25/linux/Makefile linux/Makefile
--- v2.0.25/linux/Makefile	Wed Nov 13 11:26:21 1996
+++ linux/Makefile	Fri Nov 22 12:13:01 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 25
+SUBLEVEL = 26
 
 ARCH = i386
 
diff -u --recursive --new-file v2.0.25/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.0.25/linux/arch/alpha/kernel/bios32.c	Sat Aug 10 10:03:14 1996
+++ linux/arch/alpha/kernel/bios32.c	Mon Nov 18 10:18:23 1996
@@ -37,6 +37,14 @@
 {
         return 0;
 }
+asmlinkage int sys_pciconfig_read()
+{
+        return 0;
+}
+asmlinkage int sys_pciconfig_write()
+{
+        return 0;
+}
 
 #else /* CONFIG_PCI */
 
@@ -48,6 +56,7 @@
 
 #include <asm/hwrpb.h>
 #include <asm/io.h>
+#include <asm/segment.h>
 
 
 #define KB		1024
@@ -1193,4 +1202,81 @@
         }
 }
 
+asmlinkage int sys_pciconfig_read(
+	unsigned long bus,
+	unsigned long dfn,
+	unsigned long off,
+	unsigned long len,
+	unsigned char *buf)
+{
+        unsigned char ubyte;
+        unsigned short ushort;
+        unsigned int uint;
+	long err = 0;
+
+	switch (len) {
+	    case 1:
+	        err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
+		if (err != PCIBIOS_SUCCESSFUL)
+		    ubyte = 0xff;
+		put_user(ubyte, buf);
+		break;
+	    case 2:
+	        err = pcibios_read_config_word(bus, dfn, off, &ushort);
+		if (err != PCIBIOS_SUCCESSFUL)
+		    ushort = 0xffff;
+		put_user(ushort, (unsigned short *)buf);
+		break;
+	    case 4:
+	        err = pcibios_read_config_dword(bus, dfn, off, &uint);
+		if (err != PCIBIOS_SUCCESSFUL)
+		    uint = 0xffffffff;
+		put_user(uint, (unsigned int *)buf);
+		break;
+	    default:
+	        err = -EINVAL;
+	        break;
+	}
+        return err;
+}
+asmlinkage int sys_pciconfig_write(
+	unsigned long bus,
+	unsigned long dfn,
+	unsigned long off,
+	unsigned long len,
+	unsigned char *buf)
+{
+        unsigned char ubyte;
+        unsigned short ushort;
+        unsigned int uint;
+        long err = 0;
+
+	switch (len) {
+	    case 1:
+                ubyte = get_user(buf);
+                err = pcibios_write_config_byte(bus, dfn, off, ubyte);
+                if (err != PCIBIOS_SUCCESSFUL) {
+			err = -EFAULT;
+		}
+		break;
+	    case 2:
+                ushort = get_user((unsigned short *)buf);
+                err = pcibios_write_config_word(bus, dfn, off, ushort);
+                if (err != PCIBIOS_SUCCESSFUL) {
+			err = -EFAULT;
+		}
+		break;
+	    case 4:
+                uint = get_user((unsigned int *)buf);
+                err = pcibios_write_config_dword(bus, dfn, off, uint);
+                if (err != PCIBIOS_SUCCESSFUL) {
+			err = -EFAULT;
+		}
+		break;
+	    default:
+	        err = -EINVAL;
+	        break;
+	}
+        return err;
+}
 #endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.0.25/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.0.25/linux/arch/alpha/kernel/entry.S	Sat Jun  8 11:09:03 1996
+++ linux/arch/alpha/kernel/entry.S	Thu Nov 21 13:41:46 1996
@@ -758,4 +758,4 @@
 	.quad sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler, sys_sched_yield
 	.quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname
 	.quad sys_nanosleep, sys_mremap, do_entSys, do_entSys, do_entSys
-	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+	.quad sys_pciconfig_read, sys_pciconfig_write, do_entSys, do_entSys, do_entSys
diff -u --recursive --new-file v2.0.25/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c
--- v2.0.25/linux/arch/i386/kernel/ksyms.c	Sun Sep 15 10:34:18 1996
+++ linux/arch/i386/kernel/ksyms.c	Thu Nov 14 15:20:09 1996
@@ -19,6 +19,10 @@
 	X(apic_reg),		/* Needed internally for the I386 inlines */
 	X(cpu_data),
 	X(syscall_count),
+	X(kernel_flag),
+	X(kernel_counter),
+	X(active_kernel_processor),
+	X(smp_invalidate_needed),
 #endif
 #include <linux/symtab_end.h>
 };
diff -u --recursive --new-file v2.0.25/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.0.25/linux/arch/i386/kernel/time.c	Wed Nov 13 11:26:21 1996
+++ linux/arch/i386/kernel/time.c	Sun Nov 10 19:40:53 1996
@@ -471,9 +471,9 @@
 				if( x86_model == 0 ) {
 					/* turn on cycle counters during power down */
 					__asm__ __volatile__ (" movl $0x83, %%ecx \n \
-								rdmsr \n \
+								.byte 0x0f,0x32 \n \
 								orl $1,%%eax \n \
-								wrmsr \n " 
+								.byte 0x0f,0x30 \n " 
                                                                 : : : "ax", "cx", "dx" );
 					udelay(500);
 				}
diff -u --recursive --new-file v2.0.25/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.0.25/linux/arch/i386/mm/init.c	Sun Sep  8 19:50:20 1996
+++ linux/arch/i386/mm/init.c	Thu Nov 14 15:20:09 1996
@@ -26,11 +26,13 @@
 #include <asm/pgtable.h>
 #include <asm/dma.h>
 
+#if 0
 /*
  * The SMP kernel can't handle the 4MB page table optimizations yet
  */
 #ifdef __SMP__
 #undef USE_PENTIUM_MM
+#endif
 #endif
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
diff -u --recursive --new-file v2.0.25/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.0.25/linux/drivers/block/ide-tape.c	Wed Nov 13 11:26:21 1996
+++ linux/drivers/block/ide-tape.c	Thu Nov 14 09:34:52 1996
@@ -3717,7 +3717,7 @@
 	ide_drive_t *drive=idetape_chrdev.drive;
 	idetape_tape_t *tape=&(drive->tape);
 	char *buf_ptr=buf;
-	int bytes_read,temp,actually_read=0, original_count = count;
+	int bytes_read,temp,actually_read=0;
 
 #if IDETAPE_DEBUG_LOG
 	printk ("Reached idetape_chrdev_read\n");
@@ -3777,7 +3777,7 @@
 		tape->merge_buffer_size=bytes_read-temp;
 	}
 finish:
-	if (actually_read < original_count && tape->filemark)
+	if (!actually_read && tape->filemark)
 		idetape_space_over_filemarks (drive, MTFSF, 1);
 	return (actually_read);
 }
diff -u --recursive --new-file v2.0.25/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.0.25/linux/drivers/block/ide.c	Wed Nov 13 11:26:22 1996
+++ linux/drivers/block/ide.c	Tue Nov 19 16:21:06 1996
@@ -2279,7 +2279,7 @@
 	ide_input_data(drive, id, SECTOR_WORDS);/* read 512 bytes of id info */
 	sti();
 
-#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO)
+#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
 	/*
 	 * EATA SCSI controllers do a hardware ATA emulation:  
 	 * Ignore them if there is a driver for them available.
diff -u --recursive --new-file v2.0.25/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v2.0.25/linux/drivers/cdrom/mcd.c	Fri Apr 12 09:49:33 1996
+++ linux/drivers/cdrom/mcd.c	Thu Nov 14 09:30:59 1996
@@ -61,6 +61,10 @@
 	07 July 1995 Modifications by Andrew J. Kroll
 
 	Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
+
+	Michael K. Johnson <johnsonm@redhat.com> added retries on open
+	for slow drives which take a while to recognize that they contain
+	a CD.
 */
 
 #include <linux/module.h>
@@ -1095,6 +1099,7 @@
 mcd_open(struct inode *ip, struct file *fp)
 {
 	int st;
+	int count = 0;
 
 	if (mcdPresent == 0)
 		return -ENXIO;			/* no hardware */
@@ -1106,9 +1111,16 @@
 
 	mcd_invalidate_buffers();
 
-	st = statusCmd();			/* check drive status */
-	if (st == -1)
-		return -EIO;			/* drive doesn't respond */
+	do {
+		st = statusCmd();		/* check drive status */
+		if (st == -1)
+			return -EIO;		/* drive doesn't respond */
+		if ((st & MST_READY) == 0) {	/* no disk? wait a sec... */
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + HZ;
+			schedule();
+		}
+	} while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
 
 	if ((st & MST_READY) == 0)		/* no disk in drive */
 	{
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
--- v2.0.25/linux/drivers/isdn/icn/icn.c	Sun Sep  1 09:15:32 1996
+++ linux/drivers/isdn/icn/icn.c	Wed Nov 13 08:36:19 1996
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.29 1996/08/29 20:34:54 fritz Exp $
+/* $Id: icn.c,v 1.31 1996/11/13 02:36:25 fritz Exp $
  *
  * ISDN low-level module for the ICN active ISDN-Card.
  *
@@ -19,6 +19,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: icn.c,v $
+ * Revision 1.31  1996/11/13 02:36:25  fritz
+ * Fixed a race condition in writecmd.
+ * Some optimizations and cleanup.
+ *
+ * Revision 1.30  1996/10/22 23:14:09  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
  * Revision 1.29  1996/08/29 20:34:54  fritz
  * Bugfix in send queue management:
  * sndcount was not updated correctly.
@@ -141,7 +148,7 @@
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.29 $";
+*revision = "$Revision: 1.31 $";
 
 static int icn_addcard(int, char *, char *);
 
@@ -153,13 +160,9 @@
 static void icn_free_queue(struct sk_buff_head *queue)
 {
         struct sk_buff *skb;
-        unsigned long flags;
-        
-        save_flags(flags);
-        cli();
+
         while ((skb = skb_dequeue(queue)))
                 dev_kfree_skb(skb, FREE_WRITE);
-        restore_flags(flags);
 }
 
 /* Put a value into a shift-register, highest bit first.
@@ -262,7 +265,7 @@
 #endif
         save_flags(flags);
         cli();
-        if (dev.chanlock)
+        if (dev.chanlock > 0)
                 dev.chanlock--;
         restore_flags(flags);
 }
@@ -275,12 +278,12 @@
 {
         ulong flags;
 
-        save_flags(flags);
-        cli();
 #ifdef MAP_DEBUG
         printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
                dev.chanlock);
 #endif
+        save_flags(flags);
+        cli();
         if ((!dev.chanlock) ||
             ((dev.channel == channel) && (dev.mcard == card))) {
                 dev.chanlock++;
@@ -306,12 +309,12 @@
 {
         ulong flags;
 
-        save_flags(flags);
-        cli();
 #ifdef MAP_DEBUG
         printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
 #endif
-        if (dev.chanlock)
+        save_flags(flags);
+        cli();
+        if (dev.chanlock > 0)
                 dev.chanlock--;
         if (!dev.chanlock)
                 icn_map_channel(card,channel);
@@ -381,10 +384,12 @@
         struct sk_buff *skb;
         isdn_ctrl cmd;
 
-        if (!card->sndcount[channel])
+        if (!(card->sndcount[channel] ||
+             skb_queue_len(&card->spqueue[channel])))
                 return;
         if (icn_trymaplock_channel(card,mch)) {
-                while (sbfree && card->sndcount[channel]) {
+                while (sbfree && (card->sndcount[channel] ||
+                                  skb_queue_len(&card->spqueue[channel]))) {
                         save_flags(flags);
                         cli();
                         if (card->xmit_lock[channel]) {
@@ -567,6 +572,22 @@
         return dflag;
 }
 
+static void icn_putmsg(icn_card *card, unsigned char c)
+{
+        ulong flags;
+
+        save_flags(flags);
+        cli();
+        *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
+        if (card->msg_buf_write == card->msg_buf_read) {
+                if (++card->msg_buf_read > card->msg_buf_end)
+                card->msg_buf_read = card->msg_buf;
+        }
+        if (card->msg_buf_write > card->msg_buf_end)
+                card->msg_buf_write = card->msg_buf;
+        restore_flags(flags);
+}
+
 static void icn_polldchan(unsigned long data)
 {
         icn_card *card = (icn_card *)data;
@@ -585,16 +606,7 @@
                 avail = msg_avail;
                 for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
                         c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
-                        save_flags(flags);
-                        cli();
-                        *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
-                        if (card->msg_buf_write == card->msg_buf_read) {
-                                if (++card->msg_buf_read > card->msg_buf_end)
-                                        card->msg_buf_read = card->msg_buf;
-                        }
-                        if (card->msg_buf_write > card->msg_buf_end)
-                                card->msg_buf_write = card->msg_buf;
-                        restore_flags(flags);
+                        icn_putmsg(card, c);
                         if (c == 0xff) {
                                 card->imsg[card->iptr] = 0;
                                 card->iptr = 0;
@@ -833,28 +845,28 @@
         printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
 #endif
         SLEEP(1);
-        save_flags(flags);
-        cli();
 #ifdef BOOT_DEBUG
         printk(KERN_DEBUG "Map Bank 0\n");
 #endif
+        save_flags(flags);
+        cli();
         icn_map_channel(card,0);                                   /* Select Bank 0    */
         icn_lock_channel(card,0);                                  /* Lock Bank 0      */
         restore_flags(flags);
         SLEEP(1);
-        memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1);
+        copy_from_user(codebuf, buffer, ICN_CODE_STAGE1);
         memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);           /* Copy code        */
 #ifdef BOOT_DEBUG
         printk(KERN_DEBUG "Bootloader transfered\n");
 #endif
         if (card->doubleS0) {
                 SLEEP(1);
-                save_flags(flags);
-                cli();
-                icn_release_channel();
 #ifdef BOOT_DEBUG
                 printk(KERN_DEBUG "Map Bank 8\n");
 #endif
+                save_flags(flags);
+                cli();
+                icn_release_channel();
                 icn_map_channel(card,2);                           /* Select Bank 8   */
                 icn_lock_channel(card,2);                          /* Lock Bank 8     */
                 restore_flags(flags);
@@ -872,11 +884,11 @@
         if (!card->doubleS0)
                 return 0;
         /* reached only, if we have a Double-S0-Card */
-        save_flags(flags);
-        cli();
 #ifdef BOOT_DEBUG
         printk(KERN_DEBUG "Map Bank 0\n");
 #endif
+        save_flags(flags);
+        cli();
         icn_map_channel(card,0);                                   /* Select Bank 0   */
         icn_lock_channel(card,0);                                  /* Lock Bank 0     */
         restore_flags(flags);
@@ -913,7 +925,7 @@
         while (left) {
                 if (sbfree) {                           /* If there is a free buffer...  */
                         cnt = MIN(256, left);
-                        memcpy_fromfs(codebuf, p, cnt);
+                        copy_from_user(codebuf, p, cnt);
                         memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data                     */ 
                         sbnext;                         /* switch to next buffer         */
                         p += cnt;
@@ -957,12 +969,12 @@
                         schedule();
                 } else {
                         if ((card->secondhalf) || (!card->doubleS0)) {
-                                save_flags(flags);
-                                cli();
 #ifdef BOOT_DEBUG
                                 printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
                                        card->secondhalf);
 #endif
+                                save_flags(flags);
+                                cli();
                                 init_timer(&card->st_timer);
                                 card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
                                 card->st_timer.function = icn_polldchan;
@@ -995,7 +1007,7 @@
                 if (card->msg_buf_read == card->msg_buf_write)
                         return count;
                 if (user)
-                        put_fs_byte(*card->msg_buf_read++, p);
+                        put_user(*card->msg_buf_read++, p);
                 else
                         *p = *card->msg_buf_read++;
                 if (card->msg_buf_read > card->msg_buf_end)
@@ -1005,64 +1017,70 @@
 }
 
 /* Put command-strings into the command-queue of the Interface */
-static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card, int waitflg)
+static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card)
 {
-        int mch = card->secondhalf ? 2 : 0;
+	int mch = card->secondhalf ? 2 : 0;
         int avail;
         int pp;
         int i;
         int count;
+        int xcount;
         int ocount;
+        int loop;
         unsigned long flags;
+        int lastmap_channel;
+        struct icn_card *lastmap_card;
         u_char *p;
         isdn_ctrl cmd;
         u_char msg[0x100];
 
-        while (1) {
-                if (icn_trymaplock_channel(card, mch)) {
-                        avail = cmd_free;
-                        count = MIN(avail, len);
-                        if (user)
-                                memcpy_fromfs(msg, buf, count);
-                        else
-                                memcpy(msg, buf, count);
-                        save_flags(flags);
-                        cli();
-                        ocount = 1;
-                        *card->msg_buf_write++ = '>';
-                        if (card->msg_buf_write > card->msg_buf_end)
-                                card->msg_buf_write = card->msg_buf;
-                        for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp++) {
-                                writeb((*p == '\n') ? 0xff : *p,
-                                       &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
-                                *card->msg_buf_write++ = *p;
-                                if ((*p == '\n') && (i > 1)) {
-                                        *card->msg_buf_write++ = '>';
-                                        if (card->msg_buf_write > card->msg_buf_end)
-                                                card->msg_buf_write = card->msg_buf;
-                                        ocount++;
-                                }
-                                /* No checks for buffer overflow of raw-status-device */
-                                if (card->msg_buf_write > card->msg_buf_end)
-                                        card->msg_buf_write = card->msg_buf;
+        ocount = 1;
+        xcount = loop = 0;
+        while (len) {
+                save_flags(flags);
+                cli();
+                lastmap_card = dev.mcard;
+                lastmap_channel = dev.channel;
+                icn_map_channel(card, mch);
+		
+                avail = cmd_free;
+                count = MIN(avail, len);
+                if (user)
+                        copy_from_user(msg, buf, count);
+                else
+                        memcpy(msg, buf, count);
+                icn_putmsg(card, '>');
+                for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
+			     ++) {
+                        writeb((*p == '\n') ? 0xff : *p,
+                               &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
+                        len--;
+                        xcount++;
+                        icn_putmsg(card, *p);
+                        if ((*p == '\n') && (i > 1)) {
+                                icn_putmsg(card, '>');
                                 ocount++;
                         }
-                        restore_flags(flags);
-                        cmd.command = ISDN_STAT_STAVAIL;
-                        cmd.driver = card->myid;
-                        cmd.arg = ocount;
-                        card->interface.statcallb(&cmd);
-                        writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
-                        icn_release_channel();
-                        waitflg = 0;
+                        ocount++;
+                }
+                writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
+                if (lastmap_card)
+                        icn_map_channel(lastmap_card, lastmap_channel);
+                restore_flags(flags);
+                if (len) {
+                        udelay(1000);
+                        if (loop++ > 20)
+                                break;
                 } else
-                        count = 0;
-                if (!waitflg)
                         break;
-                current->timeout = jiffies + 10;
-                schedule();
         }
-        return count;
+        if (len && (!user))
+                printk(KERN_WARNING "icn: writemsg incomplete!\n");
+        cmd.command = ISDN_STAT_STAVAIL;
+        cmd.driver = card->myid;
+        cmd.arg = ocount;
+        card->interface.statcallb(&cmd);
+        return xcount;
 }
 
 /*
@@ -1175,12 +1193,12 @@
                                                     (void *) a,
                                                     sizeof(ulong) * 2)))
                                         return i;
-                                memcpy_tofs((char *)a,
+                                copy_from_user((char *)a,
                                             (char *)&card, sizeof(ulong));
 				a += sizeof(ulong);
 				{
                                         ulong l = (ulong)&dev;
-                                        memcpy_tofs((char *)a,
+                                        copy_from_user((char *)a,
                                                     (char *)&l, sizeof(ulong));
                                 }
                                 return 0;
@@ -1198,7 +1216,7 @@
                         case ICN_IOCTL_ADDCARD:
                                 if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef))))
                                         return i;
-                                memcpy_fromfs((char *)&cdef, (char *)a, sizeof(cdef));
+                                copy_from_user((char *)&cdef, (char *)a, sizeof(cdef));
                                 return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
                                 break;
                         case ICN_IOCTL_LEASEDCFG:
@@ -1212,7 +1230,7 @@
                                                 current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
                                                 schedule();
                                                 sprintf(cbuf, "00;FV2ON\n01;EAZ1\n");
-                                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                                                 printk(KERN_INFO
                                                        "icn: (%s) Leased-line mode enabled\n",
                                                        CID);
@@ -1225,7 +1243,7 @@
                                         if (card->leased) {
                                                 card->leased = 0;
                                                 sprintf(cbuf, "00;FV2OFF\n");
-                                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                                                 printk(KERN_INFO
                                                        "icn: (%s) Leased-line mode disabled\n",
                                                        CID);
@@ -1275,7 +1293,7 @@
                                 *p2 = '\0';
                                 sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1,
                                         si2, p);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                         }
                         break;
                 case ISDN_CMD_ACCEPTD:
@@ -1292,10 +1310,10 @@
                                                         sprintf(cbuf, "%02d;BTRA\n", (int) a);
                                                         break;
                                         }
-                                        i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                        i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                                 }
                                 sprintf(cbuf, "%02d;DCON_R\n", (int) a);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                         }
                         break;
                 case ISDN_CMD_ACCEPTB:
@@ -1314,7 +1332,7 @@
                                         }
                                 else
                                         sprintf(cbuf, "%02d;BCON_R\n", (int) a);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                         }
                         break;
                 case ISDN_CMD_HANGUP:
@@ -1323,7 +1341,7 @@
                         if (c->arg < ICN_BCH) {
                                 a = c->arg + 1;
                                 sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                         }
                         break;
                 case ISDN_CMD_SETEAZ:
@@ -1339,7 +1357,7 @@
                                 } else
                                         sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
                                                 c->num[0] ? c->num : "0123456789");
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                         }
                         break;
                 case ISDN_CMD_CLREAZ:
@@ -1353,7 +1371,7 @@
                                         sprintf(cbuf, "%02d;MSNC\n", (int) a);
                                 else
                                         sprintf(cbuf, "%02d;EAZC\n", (int) a);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                         }
                         break;
                 case ISDN_CMD_SETL2:
@@ -1371,7 +1389,7 @@
                                         default:
                                                 return -EINVAL;
                                 }
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1);
+                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                                 card->l2_proto[a & 255] = (a >> 8);
                         }
                         break;
@@ -1455,7 +1473,7 @@
         if (card) {
                 if (!card->flags & ICN_FLAGS_RUNNING)
                         return -ENODEV;
-                return (icn_writecmd(buf, len, user, card, 0));
+                return (icn_writecmd(buf, len, user, card));
         }
         printk(KERN_ERR
                "icn: if_writecmd called with invalid driverId!\n");
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h
--- v2.0.25/linux/drivers/isdn/icn/icn.h	Sun Sep  1 09:15:32 1996
+++ linux/drivers/isdn/icn/icn.h	Wed Nov 13 08:36:19 1996
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.21 1996/08/29 20:35:57 fritz Exp $
+/* $Id: icn.h,v 1.22 1996/11/13 02:37:33 fritz Exp $
  *
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: icn.h,v $
+ * Revision 1.22  1996/11/13 02:37:33  fritz
+ * Added delay include.
+ *
  * Revision 1.21  1996/08/29 20:35:57  fritz
  * Speed up B-Channel polling interval.
  *
@@ -135,6 +138,7 @@
 #include <linux/ioport.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
+#include <linux/delay.h>
 #include <linux/isdnif.h>
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c
--- v2.0.25/linux/drivers/isdn/isdn_cards.c	Thu Oct 31 12:08:51 1996
+++ linux/drivers/isdn/isdn_cards.c	Wed Nov 13 08:36:19 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_cards.c,v 1.1 1996/04/20 16:04:36 fritz Exp $
+/* $Id: isdn_cards.c,v 1.2 1996/10/13 19:52:17 keil Exp $
  *
  * Linux ISDN subsystem, initialization for non-modularized drivers.
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_cards.c,v $
+ * Revision 1.2  1996/10/13 19:52:17  keil
+ * HiSax support
+ *
  * Revision 1.1  1996/04/20 16:04:36  fritz
  * Initial revision
  *
@@ -27,15 +30,19 @@
 #include <linux/config.h>
 
 #ifdef CONFIG_ISDN_DRV_ICN
-extern int icn_init(void);
+extern void icn_init(void);
 #endif
 
 #ifdef CONFIG_ISDN_DRV_TELES
-extern int teles_init(void);
+extern void teles_init(void);
+#endif
+
+#ifdef CONFIG_ISDN_DRV_HISAX
+extern void HiSax_init(void);
 #endif
 
 #ifdef CONFIG_ISDN_DRV_PCBIT
-extern int pcbit_init(void);
+extern void pcbit_init(void);
 #endif
 
 void isdn_cards_init(void)
@@ -45,6 +52,9 @@
 #endif
 #if CONFIG_ISDN_DRV_TELES
         teles_init();
+#endif
+#ifdef CONFIG_ISDN_DRV_HISAX
+	HiSax_init();
 #endif
 #if CONFIG_ISDN_DRV_PCBIT
         pcbit_init();
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.0.25/linux/drivers/isdn/isdn_common.c	Sat Jun 29 20:36:22 1996
+++ linux/drivers/isdn/isdn_common.c	Wed Nov 13 08:36:19 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.23 1996/06/25 18:35:38 fritz Exp $
+/* $Id: isdn_common.c,v 1.28 1996/11/13 02:33:19 fritz Exp $
  *
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -21,6 +21,22 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_common.c,v $
+ * Revision 1.28  1996/11/13 02:33:19  fritz
+ * Fixed a race condition.
+ *
+ * Revision 1.27  1996/10/27 22:02:41  keil
+ * return codes for ISDN_STAT_ICALL
+ *
+ * Revision 1.26  1996/10/23 11:59:40  fritz
+ * More compatibility changes.
+ *
+ * Revision 1.25  1996/10/22 23:13:54  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
+ * Revision 1.24  1996/10/11 14:02:03  fritz
+ * Bugfix: call to isdn_ppp_timer_timeout() never compiled, because of
+ *         typo in #ifdef.
+ *
  * Revision 1.23  1996/06/25 18:35:38  fritz
  * Fixed bogus memory access in isdn_set_allcfg().
  *
@@ -139,7 +155,7 @@
 isdn_dev *dev = (isdn_dev *) 0;
 
 static int  has_exported = 0;
-static char *isdn_revision      = "$Revision: 1.23 $";
+static char *isdn_revision      = "$Revision: 1.28 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -231,7 +247,7 @@
                                 isdn_net_autohup();
                         if (tf & ISDN_TIMER_MODEMRING)
                                 isdn_tty_modem_ring();
-#if (defined CONFIG_ISDN_PPP ) && (defined ISDN_CONFIG_MPP)
+#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
                         if (tf & ISDN_TIMER_IPPP)
                                 isdn_ppp_timer_timeout();
 #endif
@@ -407,6 +423,7 @@
 	ulong flags;
 	int i;
 	int r;
+	int retval=0;
         modem_info *info;
 	isdn_ctrl cmd;
 
@@ -469,12 +486,13 @@
                                                 info->msr |= UART_MSR_RI;
                                                 isdn_tty_modem_result(2, info);
                                                 isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
-                                                return 0;
+                                                return 1;
                                         } else if (dev->drv[di]->reject_bus) {
                                                 cmd.driver = di;
                                                 cmd.arg = c->arg;
                                                 cmd.command = ISDN_CMD_HANGUP;
                                                 dev->drv[di]->interface->command(&cmd);
+                                                retval=2;
                                         }
                                         break;
                                 case 1:
@@ -484,10 +502,11 @@
                                         cmd.arg = c->arg;
                                         cmd.command = ISDN_CMD_ACCEPTD;
                                         dev->drv[di]->interface->command(&cmd);
-                                        return 0;
+                                        return 1;
                                         break;
                                 case 2:	/* For calling back, first reject incoming call ... */
                                 case 3:	/* Interface found, but down, reject call actively  */
+                                	retval=2;
                                         printk(KERN_INFO "isdn: Rejecting Call\n");
                                         cmd.driver = di;
                                         cmd.arg = c->arg;
@@ -499,13 +518,13 @@
                                 case 4:
                                         /* ... then start callback. */
                                         isdn_net_dial();
-                                        return 0;
+                                        return 2;
 			}
                         cmd.driver = di;
                         cmd.arg = c->arg;
                         cmd.command = ISDN_CMD_UNLOCK;
                         dev->drv[di]->interface->command(&cmd);
-                        return 0;
+                        return retval;
                         break;
                 case ISDN_STAT_CINF:
 			if (i<0)
@@ -766,13 +785,13 @@
                         while ((count_pull < skb->len) && (left-- > 0)) {
                                 if (dev->drv[di]->DLEflag & DLEmask) {
                                         if (user)
-                                                put_fs_byte(DLE,cp++);
+                                                put_user(DLE,cp++);
                                         else
                                                 *cp++ = DLE;
                                         dev->drv[di]->DLEflag &= ~DLEmask;
                                 } else {
                                         if (user)
-                                                put_fs_byte(*p,cp++);
+                                                put_user(*p,cp++);
                                         else
                                                 *cp++ = *p;
                                         if (*p == DLE) {
@@ -795,7 +814,7 @@
                         }
                         count_put = count_pull;
                         if (user)
-                                memcpy_tofs(cp, skb->data, count_put);
+                                copy_to_user(cp, skb->data, count_put);
                         else
                                 memcpy(cp, skb->data, count_put);
                         cp += count_put;
@@ -905,7 +924,7 @@
 	wake_up_interruptible(&(dev->info_waitq));
 }
 
-static int isdn_read(struct inode *inode, struct file *file, char *buf, int count)
+static RWTYPE isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
 {
 	uint minor = MINOR(inode->i_rdev);
 	int len = 0;
@@ -923,7 +942,7 @@
 		p = isdn_statstr();
 		file->private_data = 0;
 		if ((len = strlen(p)) <= count) {
-			memcpy_tofs(buf, p, len);
+			copy_to_user(buf, p, len);
 			file->f_pos += len;
 			return len;
 		}
@@ -977,12 +996,12 @@
 	return -ENODEV;
 }
 
-static int isdn_lseek(struct inode *inode, struct file *file, off_t offset, int orig)
+static LSTYPE isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig)
 {
 	return -ESPIPE;
 }
 
-static int isdn_write(struct inode *inode, struct file *file, const char *buf, int count)
+static RWTYPE isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
 {
 	uint minor = MINOR(inode->i_rdev);
 	int drvidx;
@@ -1076,7 +1095,7 @@
 		restore_flags(flags);
 		return ret;
 	}
-	memcpy_fromfs((char *) &i, src, sizeof(int));
+	copy_from_user((char *) &i, src, sizeof(int));
         src += sizeof(int);
 	while (i) {
 		char *c;
@@ -1086,7 +1105,7 @@
 			restore_flags(flags);
 			return ret;
 		}
-		memcpy_fromfs((char *) &cfg, src, sizeof(cfg));
+		copy_from_user((char *) &cfg, src, sizeof(cfg));
 		src += sizeof(cfg);
 		if (!isdn_net_new(cfg.name, NULL)) {
 			restore_flags(flags);
@@ -1100,7 +1119,7 @@
 			restore_flags(flags);
 			return ret;
 		}
-		memcpy_fromfs(buf, src, sizeof(buf));
+		copy_from_user(buf, src, sizeof(buf));
 		src += sizeof(buf);
 		c = buf;
 		while (*c) {
@@ -1122,7 +1141,7 @@
 			restore_flags(flags);
 			return ret;
 		}
-		memcpy_fromfs(buf, src, sizeof(buf));
+		copy_from_user(buf, src, sizeof(buf));
 		src += sizeof(buf);
 		c = buf;
 		while (*c) {
@@ -1179,9 +1198,9 @@
 		cfg.callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0;
 		cfg.chargehup = (p->local.hupflags & 4) ? 1 : 0;
 		cfg.ihup = (p->local.hupflags & 8) ? 1 : 0;
-		memcpy_tofs(dest, p->local.name, 10);
+		copy_to_user(dest, p->local.name, 10);
 		dest += 10;
-		memcpy_tofs(dest, (char *) &cfg, sizeof(cfg));
+		copy_to_user(dest, (char *) &cfg, sizeof(cfg));
 		dest += sizeof(cfg);
 		strcpy(phone.name, p->local.name);
 		phone.outgoing = 0;
@@ -1231,8 +1250,8 @@
                                                                sizeof(ulong)*ISDN_MAX_CHANNELS*2)))
                                                 return ret;
                                         for (i = 0;i<ISDN_MAX_CHANNELS;i++) {
-                                                put_fs_long(dev->ibytes[i],p++);
-                                                put_fs_long(dev->obytes[i],p++);
+                                                put_user(dev->ibytes[i],p++);
+                                                put_user(dev->obytes[i],p++);
                                         }
                                         return 0;
                                 } else
@@ -1261,14 +1280,14 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
                                                 return ret;
-                                        memcpy_fromfs(name, (char *) arg, sizeof(name));
+                                        copy_from_user(name, (char *) arg, sizeof(name));
                                         s = name;
                                 } else
                                         s = NULL;
                                 if ((s = isdn_net_new(s, NULL))) {
                                         if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
                                                 return ret;
-                                        memcpy_tofs((char *) arg, s, strlen(s) + 1);
+                                        copy_to_user((char *) arg, s, strlen(s) + 1);
                                         return 0;
                                 } else
                                         return -ENODEV;
@@ -1277,13 +1296,13 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(bname))))
                                                 return ret;
-                                        memcpy_fromfs(bname, (char *) arg, sizeof(bname));
+                                        copy_from_user(bname, (char *) arg, sizeof(bname));
                                 } else
                                         return -EINVAL;
                                 if ((s = isdn_net_newslave(bname))) {
                                         if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
                                                 return ret;
-                                        memcpy_tofs((char *) arg, s, strlen(s) + 1);
+                                        copy_to_user((char *) arg, s, strlen(s) + 1);
                                         return 0;
                                 } else
                                         return -ENODEV;
@@ -1292,7 +1311,7 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
                                                 return ret;
-                                        memcpy_fromfs(name, (char *) arg, sizeof(name));
+                                        copy_from_user(name, (char *) arg, sizeof(name));
                                         return isdn_net_rm(name);
                                 } else
                                         return -EINVAL;
@@ -1301,7 +1320,7 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
                                                 return ret;
-                                        memcpy_fromfs((char *) &cfg, (char *) arg, sizeof(cfg));
+                                        copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
                                         return isdn_net_setcfg(&cfg);
                                 } else
                                         return -EINVAL;
@@ -1310,11 +1329,11 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
                                                 return ret;
-                                        memcpy_fromfs((char *) &cfg, (char *) arg, sizeof(cfg));
+                                        copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
                                         if (!(ret = isdn_net_getcfg(&cfg))) {
                                                 if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(cfg))))
                                                         return ret;
-                                                memcpy_tofs((char *) arg, (char *) &cfg, sizeof(cfg));
+                                                copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg));
                                         }
                                         return ret;
                                 } else
@@ -1324,7 +1343,7 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
                                                 return ret;
-                                        memcpy_fromfs((char *) &phone, (char *) arg, sizeof(phone));
+                                        copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
                                         return isdn_net_addphone(&phone);
                                 } else
                                         return -EINVAL;
@@ -1333,7 +1352,7 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
                                                 return ret;
-                                        memcpy_fromfs((char *) &phone, (char *) arg, sizeof(phone));
+                                        copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
                                         return isdn_net_getphones(&phone, (char *) arg);
                                 } else
                                         return -EINVAL;
@@ -1342,7 +1361,7 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
                                                 return ret;
-                                        memcpy_fromfs((char *) &phone, (char *) arg, sizeof(phone));
+                                        copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
                                         return isdn_net_delphone(&phone);
                                 } else
                                         return -EINVAL;
@@ -1351,7 +1370,7 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
                                                 return ret;
-                                        memcpy_fromfs(name, (char *) arg, sizeof(name));
+                                        copy_from_user(name, (char *) arg, sizeof(name));
                                         return isdn_net_force_dial(name);
                                 } else
                                         return -EINVAL;
@@ -1364,7 +1383,7 @@
                                                 return ret;
                                 } else
                                         return -EINVAL;
-                                memcpy_fromfs(name,(char*)arg,sizeof(name));
+                                copy_from_user(name,(char*)arg,sizeof(name));
                                 return isdn_ppp_dial_slave(name);
                         case IIOCNETDLN:
                                 if(arg) {
@@ -1374,7 +1393,7 @@
                                                 return ret;
                                 } else
                                         return -EINVAL;
-                                memcpy_fromfs(name,(char*)arg,sizeof(name));
+                                copy_from_user(name,(char*)arg,sizeof(name));
                                 return isdn_ppp_hangup_slave(name);
 #endif
                         case IIOCNETHUP:
@@ -1382,7 +1401,7 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
                                                 return ret;
-                                        memcpy_fromfs(name, (char *) arg, sizeof(name));
+                                        copy_from_user(name, (char *) arg, sizeof(name));
                                         return isdn_net_force_hangup(name);
                                 } else
                                         return -EINVAL;
@@ -1408,7 +1427,7 @@
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg,
                                                                sizeof(isdn_ioctl_struct))))
                                                 return ret;
-                                        memcpy_fromfs((char *) &iocts, (char *) arg,
+                                        copy_from_user((char *) &iocts, (char *) arg,
                                                       sizeof(isdn_ioctl_struct));
                                         if (strlen(iocts.drvid)) {
                                                 if ((p = strchr(iocts.drvid, ',')))
@@ -1457,10 +1476,10 @@
                                                 return ret;
                                         
                                         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                                memcpy_tofs(p, dev->mdm.info[i].emu.profile,
+                                                copy_to_user(p, dev->mdm.info[i].emu.profile,
                                                             ISDN_MODEM_ANZREG);
                                                 p += ISDN_MODEM_ANZREG;
-                                                memcpy_tofs(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN);
+                                                copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN);
                                                 p += ISDN_MSNLEN;
                                         }
                                         return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
@@ -1479,10 +1498,10 @@
                                                 return ret;
                                         
                                         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                                memcpy_fromfs(dev->mdm.info[i].emu.profile, p,
+                                                copy_from_user(dev->mdm.info[i].emu.profile, p,
                                                               ISDN_MODEM_ANZREG);
                                                 p += ISDN_MODEM_ANZREG;
-                                                memcpy_fromfs(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN);
+                                                copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN);
                                                 p += ISDN_MSNLEN;
                                         }
                                         return 0;
@@ -1500,7 +1519,7 @@
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg,
                                                                sizeof(isdn_ioctl_struct))))
                                                 return ret;
-                                        memcpy_fromfs((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
+                                        copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
                                         if (strlen(iocts.drvid)) {
                                                 drvidx = -1;
                                                 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
@@ -1515,7 +1534,7 @@
                                         if (cmd == IIOCSETMAP) {
                                                 if ((ret = verify_area(VERIFY_READ, (void *) iocts.arg, 255)))
                                                         return ret;
-                                                memcpy_fromfs(nstring, (char *) iocts.arg, 255);
+                                                copy_from_user(nstring, (char *) iocts.arg, 255);
                                                 memset(dev->drv[drvidx]->msn2eaz, 0,
                                                        sizeof(dev->drv[drvidx]->msn2eaz));
                                                 p = strtok(nstring, ",");
@@ -1534,7 +1553,7 @@
                                                 if ((ret = verify_area(VERIFY_WRITE, (void *) iocts.arg,
                                                                        strlen(nstring) + 1)))
                                                         return ret;
-                                                memcpy_tofs((char *) iocts.arg, nstring, strlen(nstring) + 1);
+                                                copy_to_user((char *) iocts.arg, nstring, strlen(nstring) + 1);
                                         }
                                         return 0;
                                 } else
@@ -1543,7 +1562,7 @@
                                 if (arg) {
                                         if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(ulong))))
                                                 return ret;
-                                        memcpy_tofs((char *) arg, (char *) &dev, sizeof(ulong));
+                                        copy_to_user((char *) arg, (char *) &dev, sizeof(ulong));
                                         return 0;
                                 } else
                                         return -EINVAL;
@@ -1559,7 +1578,7 @@
                                         if ((ret = verify_area(VERIFY_READ, (void *) arg,
                                                                sizeof(isdn_ioctl_struct))))
                                                 return ret;
-                                        memcpy_fromfs((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
+                                        copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
                                         if (strlen(iocts.drvid)) {
                                                 if ((p = strchr(iocts.drvid, ',')))
                                                         *p = 0;
@@ -1582,7 +1601,7 @@
                                         memcpy(c.num, (char *) &iocts.arg, sizeof(ulong));
                                         ret = dev->drv[drvidx]->interface->command(&c);
                                         memcpy((char *) &iocts.arg, c.num, sizeof(ulong));
-                                        memcpy_tofs((char *) arg, &iocts, sizeof(isdn_ioctl_struct));
+                                        copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct));
                                         return ret;
                                 } else
                                         return -EINVAL;
@@ -1816,8 +1835,8 @@
                         cmd.driver = di;
                         cmd.arg = ch;
                         cmd.command = ISDN_CMD_UNLOCK;
-                        (void) dev->drv[di]->interface->command(&cmd);
                         restore_flags(flags);
+                        (void) dev->drv[di]->interface->command(&cmd);
 			return;
 		}
 	restore_flags(flags);
@@ -1891,7 +1910,7 @@
                 skb->free = 1;
 
                 if (user)
-                        memcpy_fromfs(skb_put(skb, len), buf, len);
+                        copy_from_user(skb_put(skb, len), buf, len);
                 else
                         memcpy(skb_put(skb, len), buf, len);
 
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.0.25/linux/drivers/isdn/isdn_net.c	Sun Sep  1 09:15:32 1996
+++ linux/drivers/isdn/isdn_net.c	Wed Nov 13 08:36:19 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.20 1996/08/29 20:06:03 fritz Exp $
+/* $Id: isdn_net.c,v 1.29 1996/11/13 02:31:38 fritz Exp $
  *
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -21,6 +21,35 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.29  1996/11/13 02:31:38  fritz
+ * Minor cleanup.
+ *
+ * Revision 1.28  1996/10/27 20:49:06  keil
+ * bugfix to compile without MPP
+ *
+ * Revision 1.27  1996/10/25 18:46:01  fritz
+ * Another bugfix in isdn_net_autohup()
+ *
+ * Revision 1.26  1996/10/23 23:05:36  fritz
+ * Bugfix: Divide by zero in isdn_net_autohup()
+ *
+ * Revision 1.25  1996/10/22 23:13:58  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
+ * Revision 1.24  1996/10/11 13:57:40  fritz
+ * Bugfix: Error in BogoCPS calculation.
+ *
+ * Revision 1.23  1996/09/23 01:58:08  fritz
+ * Fix: With syncPPP encapsulation, discard LCP packets
+ *      when calculating hangup timeout.
+ *
+ * Revision 1.22  1996/09/23 00:03:37  fritz
+ * Fix: did not compile without CONFIG_ISDN_PPP
+ *
+ * Revision 1.21  1996/09/07 12:44:50  hipp
+ * (hopefully) fixed callback problem with syncPPP
+ * syncPPP network devices now show PPP link encap
+ *
  * Revision 1.20  1996/08/29 20:06:03  fritz
  * Bugfix: Transmission timeout had been much to low.
  *
@@ -130,7 +159,7 @@
  
 extern void dev_purge_queues(struct device *dev);	/* move this to net/core/dev.c */
 
-char *isdn_net_revision = "$Revision: 1.20 $";
+char *isdn_net_revision = "$Revision: 1.29 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -237,19 +266,21 @@
  * Since this function is called every second, simply reset the
  * byte-counter of the interface after copying it to the cps-variable.
  */
+unsigned long last_jiffies = -HZ;
+
 void
 isdn_net_autohup()
 {
 	isdn_net_dev *p = dev->netdev;
         int anymore;
-	ulong flags;
 
-	save_flags(flags);
-	cli();
         anymore = 0;
 	while (p) {
 		isdn_net_local *l = (isdn_net_local *) & (p->local);
-		l->cps = l->transcount;
+		if ((jiffies - last_jiffies) == 0)
+			l->cps = 0;
+		else
+			l->cps = l->transcount / (jiffies - last_jiffies);
 		l->transcount = 0;
 		if (dev->net_verbose > 3)
 			printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps);
@@ -270,8 +301,8 @@
 		}
 		p = (isdn_net_dev *) p->next;
 	}
+	last_jiffies = jiffies;
         isdn_timer_ctrl(ISDN_TIMER_NETHANGUP,anymore);
-	restore_flags(flags);
 }
 
 /*
@@ -902,8 +933,8 @@
                                                 restore_flags(flags);
 						return 0;	/* STN (skb to nirvana) ;) */
 					}
-	                                isdn_net_dial();	/* Initiate dialing */
 					restore_flags(flags);
+	                                isdn_net_dial();	/* Initiate dialing */
 					return 1;	/* let upper layer requeue skb packet */
 				}
 #endif
@@ -917,9 +948,9 @@
                                 }
                                 lp->first_skb = skb;
 				/* Initiate dialing */
-				isdn_net_dial();
                                 ndev->tbusy = 0;
 				restore_flags(flags);
+				isdn_net_dial();
                                 return 0;
 			} else {
                                 /*
@@ -1053,11 +1084,20 @@
 	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
 #ifdef CONFIG_ISDN_PPP
         isdn_net_local *olp = lp;  /* original 'lp' */
+        int proto = PPP_PROTOCOL(skb->data);
 #endif
 
 	lp->transcount += skb->len;
 	lp->stats.rx_packets++;
-	lp->huptimer = 0;
+#ifdef CONFIG_ISDN_PPP
+        /*
+         * If encapsulation is syncppp, don't reset
+         * huptimer on LCP packets.
+         */
+        if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
+            (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
+#endif
+	        lp->huptimer = 0;
 
 	if (lp->master) {
 		/* Bundling: If device is a slave-device, deliver to master, also
@@ -1066,7 +1106,15 @@
 		ndev = lp->master;
 		lp = (isdn_net_local *) ndev->priv;
 		lp->stats.rx_packets++;
-		lp->huptimer = 0;
+#ifdef CONFIG_ISDN_PPP
+                /*
+                 * If encapsulation is syncppp, don't reset
+                 * huptimer on LCP packets.
+                 */
+                if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
+                    (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
+#endif
+                        lp->huptimer = 0;
 	}
 
 	skb->dev = ndev;
@@ -1716,9 +1764,14 @@
 					       eaz);
 					/* if this interface is dialing, it does it probably on a different
 					   device, so free this device */
-					if ((p->local.dialstate == 4) || (p->local.dialstate == 12))
+					if ((p->local.dialstate == 4) || (p->local.dialstate == 12)) {
+#ifdef CONFIG_ISDN_PPP
+                                                if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+                                                        isdn_ppp_free(lp);
+#endif
 						isdn_free_channel(p->local.isdn_device, p->local.isdn_channel,
 							 ISDN_USAGE_NET);
+                                        }
 					dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
 					dev->usage[idx] |= ISDN_USAGE_NET;
 					strcpy(dev->num[idx], nr);
@@ -1808,8 +1861,8 @@
 				}
 #endif
 			/* Initiate dialing */
-			isdn_net_dial();
 			restore_flags(flags);
+			isdn_net_dial();
 			return 0;
 		} else
 			return -EINVAL;
@@ -1899,6 +1952,8 @@
 	netdev->local.exclusive = -1;
 	netdev->local.ppp_slot = -1;
 	netdev->local.pppbind = -1;
+        netdev->local.sav_skb = NULL;
+        netdev->local.first_skb = NULL;
 	netdev->local.l2_proto = ISDN_PROTO_L2_X75I;
 	netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
 	netdev->local.slavedelay = 10 * HZ;
@@ -1972,13 +2027,16 @@
                                        p->local.name);
                                 return -EBUSY;
                         }
-#ifndef CONFIG_ISDN_PPP
                 if (cfg->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
-                        printk(KERN_WARNING "%s: SyncPPP not configured\n",
+#ifndef CONFIG_ISDN_PPP
+                        printk(KERN_WARNING "%s: SyncPPP support not configured\n",
                                p->local.name);
                         return -EINVAL;
-                }
+#else
+                        p->dev.type = ARPHRD_PPP; /* change ARP type */
+                        p->dev.addr_len = 0;
 #endif
+                }
 		if (strlen(cfg->drvid)) {
 			/* A bind has been requested ... */
 			char *c,*e;
@@ -2188,19 +2246,19 @@
 	inout &= 1;
         for (n = p->local.phone[inout]; n; n = n->next) {
 		if (more) {
-			put_fs_byte(' ', phones++);
+			put_user(' ', phones++);
 			count++;
 		}
 		if ((ret = verify_area(VERIFY_WRITE, (void *) phones, strlen(n->num) + 1))) {
 			restore_flags(flags);
 			return ret;
 		}
-		memcpy_tofs(phones, n->num, strlen(n->num) + 1);
+		copy_to_user(phones, n->num, strlen(n->num) + 1);
 		phones += strlen(n->num);
 		count += strlen(n->num);
 		more = 1;
 	}
-        put_fs_byte(0,phones);
+        put_user(0,phones);
         count++;
 	restore_flags(flags);
 	return count;
@@ -2268,16 +2326,11 @@
 int isdn_net_force_hangup(char *name)
 {
 	isdn_net_dev *p = isdn_net_findif(name);
-	int flags;
 	struct device *q;
 
 	if (p) {
-		save_flags(flags);
-		cli();
-		if (p->local.isdn_device < 0) {
-			restore_flags(flags);
+		if (p->local.isdn_device < 0)
 			return 1;
-		}
 		isdn_net_hangup(&p->dev);
 		q = p->local.slave;
 		/* If this interface has slaves, do a hangup for them also. */
@@ -2285,7 +2338,6 @@
 			isdn_net_hangup(q);
 			q = (((isdn_net_local *) q->priv)->slave);
 		}
-		restore_flags(flags);
 		return 0;
 	}
 	return -ENODEV;
@@ -2347,7 +2399,7 @@
 		isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
 	restore_flags(flags);
 
-#ifdef CONFIG_ISDN_PPP
+#ifdef CONFIG_ISDN_MPP
 	isdn_ppp_free_mpqueue(p);	/* still necessary? */
 #endif
 	kfree(p);
@@ -2417,14 +2469,3 @@
         }
 	
 }
-
-
-
-
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- v2.0.25/linux/drivers/isdn/isdn_ppp.c	Sun Sep  1 09:15:32 1996
+++ linux/drivers/isdn/isdn_ppp.c	Wed Nov 13 08:36:19 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.14 1996/08/12 16:26:47 hipp Exp $
+/* $Id: isdn_ppp.c,v 1.20 1996/10/30 12:21:58 fritz Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,25 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.20  1996/10/30 12:21:58  fritz
+ * Cosmetic fix: Compiler warning when compiling without MPP.
+ *
+ * Revision 1.19  1996/10/25 19:03:21  hipp
+ * changed/added some defines to (re)allow compilation without MP/VJ
+ *
+ * Revision 1.18  1996/10/22 23:14:00  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
+ * Revision 1.17  1996/10/22 09:39:49  hipp
+ * a few MP changes and bugfixes
+ *
+ * Revision 1.16  1996/09/23 01:58:10  fritz
+ * Fix: With syncPPP encapsulation, discard LCP packets
+ *      when calculating hangup timeout.
+ *
+ * Revision 1.15  1996/09/07 12:50:12  hipp
+ * bugfixes (unknown device after failed dial attempt, minor bugs)
+ *
  * Revision 1.14  1996/08/12 16:26:47  hipp
  * code cleanup
  * changed connection management from minors to slots
@@ -73,6 +92,8 @@
 
 /* TODO: right tbusy handling when using MP */
 
+#undef ISDN_SYNCPPP_READDRESS
+
 #include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
@@ -84,6 +105,8 @@
 #ifndef PPP_IPX
 #define PPP_IPX 0x002b 
 #endif
+
+/* set this if you use dynamic addressing */
  
 /* Prototypes */
 static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot);
@@ -95,23 +118,45 @@
 #ifdef CONFIG_ISDN_MPP
 static int isdn_ppp_bundle(struct ippp_struct *, int unit);
 static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask);
-static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min);
+static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min);
+static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev,isdn_net_local *, long min);
 static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
-		int BEbyte, int *sqno, int min_sqno);
+		int BEbyte, long *sqno, int min_sqno);
 #endif
 
-char *isdn_ppp_revision              = "$Revision: 1.14 $";
+char *isdn_ppp_revision              = "$Revision: 1.20 $";
+
 struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
 extern int isdn_net_force_dial_lp(isdn_net_local *);
 
 /*
+ * frame log (debug)
+ */
+static void isdn_ppp_frame_log(char *info,char *data,int len,int maxlen)
+{
+	int cnt,j,i;
+	char buf[80];
+
+	if(len < maxlen)
+		maxlen = len;
+	
+	for(i=0,cnt=0;cnt<maxlen;i++) {
+		for(j=0;j<16 && cnt<maxlen;j++,cnt++)
+			sprintf(buf+j*3,"%02x ",(unsigned char) data[cnt]);
+		printk(KERN_DEBUG "%s[%d]: %s\n",info,i,buf);
+	}
+}
+
+/*
  * unbind isdn_net_local <=> ippp-device 
  * note: it can happen, that we hangup/free the master before the slaves
  */
 int isdn_ppp_free(isdn_net_local *lp)
 {
+#ifdef CONFIG_ISDN_MPP
 	isdn_net_local *master_lp=lp;
+#endif
 	unsigned long flags;
 	struct ippp_struct *is;
 
@@ -131,7 +176,7 @@
 	if(master_lp->netdev->queue == lp) {
 		master_lp->netdev->queue = lp->next;
 		if(lp->next == lp) {	/* last link in queue? */
-               		master_lp->netdev->ib.bundled = 0;
+			master_lp->netdev->ib.bundled = 0;
 			isdn_ppp_free_mpqueue(master_lp->netdev);
 			isdn_ppp_free_sqqueue(master_lp->netdev);
 		}
@@ -139,12 +184,20 @@
 	lp->next = lp->last = lp;	/* (re)set own pointers */
 #endif
 
-	isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
+	if( (is->state & IPPP_CONNECT) )
+		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
+	else if(is->state & IPPP_ASSIGNED)
+		is->state = IPPP_OPEN;	/* fallback to 'OPEN but not ASSIGEND' staet */
+		
 
 	if(is->debug & 0x1)
 		printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp,(long) is->lp);
 
 	is->lp = NULL;	/* link is down .. set lp to NULL */
+#ifdef ISDN_SYNCPPP_READDRESS
+	is->old_pa_addr = 0x0;
+	is->old_pa_dstaddr = 0x0;
+#endif
 	lp->ppp_slot = -1;			/* is this OK ?? */
 	restore_flags(flags);
 
@@ -209,7 +262,7 @@
 	is = ippp_table[i];
 	is->lp = lp;
 	is->unit = unit;
-	is->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
+	is->state = IPPP_OPEN | IPPP_ASSIGNED;	/* assigned to a netdevice but not connected */
 
 	restore_flags(flags);
 
@@ -223,6 +276,11 @@
 
 void isdn_ppp_wakeup_daemon(isdn_net_local *lp)
 {
+	if(lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
+		return;
+
+	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
+
 	if (ippp_table[lp->ppp_slot]->wq)
 		wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
 }
@@ -270,6 +328,9 @@
 	int slot;
 	struct ippp_struct *is;
 
+	if(min < 0 || min > ISDN_MAX_CHANNELS)
+		return -ENODEV;
+
 	slot = isdn_ppp_get_slot();
 	if(slot < 0) {
 		return -EBUSY;
@@ -322,11 +383,15 @@
 		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
 
 	if (is->lp) {	/* a lp address says: this link is still up */
-		isdn_net_dev *p = dev->netdev;
-		p = is->lp->netdev;
-		is->lp->ppp_slot = -1;
-		isdn_net_hangup(&p->dev); /* lp->ppp_slot==-1 => no calling of isdn_ppp_closewait() */
-		is->lp = NULL;
+		isdn_net_dev *p = is->lp->netdev;
+		
+		is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
+		/* 
+		 * isdn_net_hangup() calls isdn_ppp_free()
+		 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
+		 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
+		 */
+		isdn_net_hangup(&p->dev);
 	}
 	for (i = 0; i < NUM_RCV_BUFFS; i++) {
 		if (is->rq[i].buf) {
@@ -348,24 +413,33 @@
 /*
  * get_arg .. ioctl helper
  */
-static int get_arg(void *b, unsigned long *val)
+static int get_arg(void *b,void *val,int len)
 {
 	int r;
-	if ((r = verify_area(VERIFY_READ, (void *) b, sizeof(unsigned long))))
+	if(len <= 0)
+		len = sizeof(unsigned long); 
+	if ((r = verify_area(VERIFY_READ, (void *) b, len )))
 		 return r;
-	memcpy_fromfs((void *) val, b, sizeof(unsigned long));
+	copy_from_user((void *) val, b, len );
 	return 0;
 }
 
 /*
  * set arg .. ioctl helper
  */
-static int set_arg(void *b, unsigned long val)
+static int set_arg(void *b, unsigned long val,void *str)
 {
 	int r;
-	if ((r = verify_area(VERIFY_WRITE, b, sizeof(unsigned long))))
-		 return r;
-	memcpy_tofs(b, (void *) &val, sizeof(unsigned long));
+	if(!str) {
+		if ((r = verify_area(VERIFY_WRITE, b, 4 )))
+			 return r;
+		copy_to_user(b, (void *) &val, 4 );
+	}
+	else {
+		if ((r = verify_area(VERIFY_WRITE, b,val)))
+			return r;
+		copy_to_user(b,str,val);
+	}
 	return 0;
 }
 
@@ -389,7 +463,9 @@
 	switch (cmd) {
 	case PPPIOCBUNDLE:
 #ifdef CONFIG_ISDN_MPP
-		if ((r = get_arg((void *) arg, &val)))
+		if( !(is->state & IPPP_CONNECT) )
+			return -EINVAL;
+		if ((r = get_arg((void *) arg, &val,0)))
 			return r;
 		printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
                         (int) min, (int) is->unit, (int) val);
@@ -399,41 +475,50 @@
 #endif
 		break;
 	case PPPIOCGUNIT:	/* get ppp/isdn unit number */
-		if ((r = set_arg((void *) arg, is->unit)))
+		if ((r = set_arg((void *) arg, is->unit,NULL)))
 			return r;
 		break;
 	case PPPIOCGMPFLAGS:	/* get configuration flags */
-		if ((r = set_arg((void *) arg, is->mpppcfg)))
+		if ((r = set_arg((void *) arg, is->mpppcfg,NULL)))
 			return r;
 		break;
 	case PPPIOCSMPFLAGS:	/* set configuration flags */
-		if ((r = get_arg((void *) arg, &val)))
+		if ((r = get_arg((void *) arg, &val,0)))
 			return r;
 		is->mpppcfg = val;
 		break;
 	case PPPIOCGFLAGS:	/* get configuration flags */
-		if ((r = set_arg((void *) arg, is->pppcfg)))
+		if ((r = set_arg((void *) arg, is->pppcfg,NULL)))
 			return r;
 		break;
 	case PPPIOCSFLAGS:	/* set configuration flags */
-		if ((r = get_arg((void *) arg, &val))) {
+		if ((r = get_arg((void *) arg, &val,0))) {
 			return r;
 		}
-		if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP)) {
+		if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT) ) {
 			isdn_net_local *lp = is->lp;
-			lp->netdev->dev.tbusy = 0;
-			mark_bh(NET_BH); /* OK .. we are ready to send buffers */
+			if(lp) {
+				lp->netdev->dev.tbusy = 0;
+				mark_bh(NET_BH); /* OK .. we are ready to send buffers */
+			}
 		}
 		is->pppcfg = val;
 		break;
 #if 0
 	case PPPIOCGSTAT:	/* read PPP statistic information */
 		break;
-	case PPPIOCGTIME:	/* read time delta information */
-		break;
 #endif
+	case PPPIOCGIDLE:	/* get idle time information */
+		if(is->lp)
+		{
+			struct ppp_idle pidle;
+			pidle.xmit_idle = pidle.recv_idle = is->lp->huptimer;
+			if((r = set_arg((void *) arg,sizeof(struct ppp_idle),&pidle)))
+				return r;	
+		}
+		break;
 	case PPPIOCSMRU:	/* set receive unit size for PPP */
-		if ((r = get_arg((void *) arg, &val)))
+		if ((r = get_arg((void *) arg, &val,0)))
 			return r;
 		is->mru = val;
 		break;
@@ -442,7 +527,7 @@
 	case PPPIOCSMPMTU:
 		break;
 	case PPPIOCSMAXCID:	/* set the maximum compression slot id */
-		if ((r = get_arg((void *) arg, &val)))
+		if ((r = get_arg((void *) arg, &val,0)))
 			return r;
 		val++;
 		if(is->maxcid != val) {
@@ -465,14 +550,25 @@
 		}
 		break;
 	case PPPIOCGDEBUG:
-		if ((r = set_arg((void *) arg, is->debug)))
+		if ((r = set_arg((void *) arg, is->debug,0)))
 			return r;
 		break;
 	case PPPIOCSDEBUG:
-		if ((r = get_arg((void *) arg, &val)))
+		if ((r = get_arg((void *) arg, &val,0)))
 			return r;
 		is->debug = val;
 		break;
+	case PPPIOCSCOMPRESS:
+#if 0
+		{
+			struct ppp_option_data pod;
+			r = get_arg((void *) arg,&pod,sizeof(struct ppp_option_data));
+			if(r)
+				return r;
+			ippp_set_compression(is,&pod);
+		}
+#endif
+		break;
 	default:
 		break;
 	}
@@ -607,7 +703,7 @@
 	}
 	if (b->len < count)
 		count = b->len;
-	memcpy_tofs(buf, b->buf, count);
+	copy_to_user(buf, b->buf, count);
 	kfree(b->buf);
 	b->buf = NULL;
 	is->first = b;
@@ -624,6 +720,8 @@
 {
 	isdn_net_local *lp;
 	struct ippp_struct *is;
+	int proto;
+	unsigned char protobuf[4];
 
 	is = file->private_data;
 
@@ -637,12 +735,21 @@
 	if (!lp)
 		printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
 	else {
-		lp->huptimer = 0;
+                /*
+                 * Don't reset huptimer for
+                 * LCP packets. (Echo requests).
+                 */
+                copy_from_user(protobuf, buf, 4);
+                proto = PPP_PROTOCOL(protobuf);
+                if (proto != PPP_LCP)
+			lp->huptimer = 0;
+		
 		if (lp->isdn_device < 0 || lp->isdn_channel < 0)
 			return 0;
 
 		if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 &&
 		    (lp->flags & ISDN_NET_CONNECTED)) {
+			int cnt;
 			struct sk_buff *skb;
 			skb = dev_alloc_skb(count);
 			if(!skb) {
@@ -650,17 +757,22 @@
 				return count;
 			}
 			skb->free = 1;
-			memcpy_fromfs(skb_put(skb, count), buf, count);
-			if(isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb) != count) {
+			copy_from_user(skb_put(skb, count), buf, count);
+			if(is->debug & 0x40) {
+				printk(KERN_DEBUG "ppp xmit: len %ld\n",skb->len);
+				isdn_ppp_frame_log("xmit",skb->data,skb->len,32);
+			}
+			if( (cnt=isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb)) != count) {
 				if(lp->sav_skb) {
 					dev_kfree_skb(lp->sav_skb,FREE_WRITE);
-					printk(KERN_INFO "isdn_ppp_write: freeing sav_skb!\n");
+					printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n",cnt,count);
 				}
+				else
+					printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n",cnt,count);
 				lp->sav_skb = skb;
 			}
 		}
 	}
-
 	return count;
 }
 
@@ -706,14 +818,15 @@
 /*
  * handler for incoming packets on a syncPPP interface
  */
-
 void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
 {
 	struct ippp_struct *is;
 	is = ippp_table[lp->ppp_slot];
 
-	if(is->debug & 0x4)
-		printk(KERN_DEBUG "recv skb, len: %ld\n",skb->len);
+	if(is->debug & 0x4) {
+		printk(KERN_DEBUG "ippp_receive: len: %ld\n",skb->len);
+		isdn_ppp_frame_log("receive",skb->data,skb->len,32);
+	}
 
 	if(net_dev->local.master) {
 		printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n");
@@ -741,7 +854,7 @@
 		}
 		if (proto == PPP_MP) {
 			isdn_net_local *lpq;
-			int sqno, min_sqno, tseq;
+			long sqno, min_sqno, tseq;
 			u_char BEbyte = skb->data[0];
 			if(is->debug & 0x8)
 	 			printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto ,
@@ -758,7 +871,7 @@
 			if ((tseq = is->last_link_seqno) >= sqno) {
 				int range = is->range;
 				if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
-					printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %d, last: %d !!!\n", sqno, tseq);
+					printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %ld, last: %ld !!!\n", sqno, tseq);
 				else {
 					sqno += range;
 					is->last_link_seqno = sqno;
@@ -766,16 +879,19 @@
 			} else
 				is->last_link_seqno = sqno;
 
-			for (min_sqno = 0, lpq = net_dev->queue;;) {
-				if (ippp_table[lpq->ppp_slot]->last_link_seqno > min_sqno)
-					min_sqno = ippp_table[lpq->ppp_slot]->last_link_seqno;
+			for (min_sqno = LONG_MAX, lpq = net_dev->queue;;) {
+				long lls = ippp_table[lpq->ppp_slot]->last_link_seqno;
+				if (lls >= 0 && lls < min_sqno)
+					min_sqno = lls;
 				lpq = lpq->next;
 				if (lpq == net_dev->queue)
 					break;
 			}
 			if (min_sqno >= ippp_table[lpq->ppp_slot]->range) {	/* OK, every link overflowed */
 				int mask = ippp_table[lpq->ppp_slot]->range - 1;	/* range is a power of 2 */
+#if 0
 				isdn_ppp_cleanup_queue(net_dev, min_sqno);
+#endif
 				isdn_ppp_mask_queue(net_dev, mask);
 				net_dev->ib.next_num &= mask;
 				{
@@ -795,11 +911,18 @@
 			}
 			if ((BEbyte & (MP_BEGIN_FRAG | MP_END_FRAG)) != (MP_BEGIN_FRAG | MP_END_FRAG)) {
 				printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot);
-				if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb , BEbyte, &sqno, min_sqno)) < 0)
+				if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb , BEbyte, &sqno, min_sqno)) < 0) {
+					net_dev->ib.modify = 1;	/* block timeout-timer */
+					isdn_ppp_cleanup_sqqueue(net_dev,lp,min_sqno); 
+					net_dev->ib.modify = 0;
 					return;		/* no packet complete */
+				}
 			} else
 				sqno_end = sqno;
 
+			if(is->debug & 0x40)
+				printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n",min_sqno,sqno_end,net_dev->ib.next_num );
+
 			/*
 			 * MP buffer management .. reorders incoming packets ..
 			 * lotsa mem-copies and not heavily tested.
@@ -842,27 +965,14 @@
 						ql->next = q;
 					}
 				}
-				net_dev->ib.modify = 0;
-				return;
 			} else {
 				/* 
 			 	 * packet was 'in order' .. push it higher
 				 */
-				struct sqqueue *q;
-
 				net_dev->ib.next_num = sqno_end + 1;
 				isdn_ppp_push_higher(net_dev, lp, skb, -1);
-
-                                /*
-                                 * check queue, whether we have still buffered the next packet(s)
-                                 */
-				while ((q = net_dev->ib.sq) && q->sqno_start == net_dev->ib.next_num) {
-					isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
-					net_dev->ib.sq = q->next;
-					net_dev->ib.next_num = q->sqno_end + 1;
-					kfree(q);
-				}
 			}
+			isdn_ppp_cleanup_sqqueue(net_dev,lp,min_sqno);
 			net_dev->ib.modify = 0;
 
 		} else
@@ -872,7 +982,6 @@
 		isdn_ppp_push_higher(net_dev, lp, skb , -1);
 }
 
-
 /*
  * push frame to higher layers
  * note: net_dev has to be master net_dev
@@ -892,13 +1001,15 @@
 		}
 	}
 
-	if(is->debug & 0x10)
+	if(is->debug & 0x10) {
 		printk(KERN_DEBUG "push, skb %ld %04x\n",skb->len,proto);
+		isdn_ppp_frame_log("rpush",skb->data,skb->len,32);
+	}
 
 	switch (proto) {
 	case PPP_IPX: /* untested */
 		if(is->debug & 0x20)
-			printk(KERN_DEBUG "isdn_ppp: _IPX\n");
+			printk(KERN_DEBUG "isdn_ppp: IPX\n");
 		skb->dev = dev;
 		skb->mac.raw = skb->data;
 		skb->protocol = htons(ETH_P_IPX);
@@ -971,7 +1082,7 @@
 	}
 
 	netif_rx(skb);
-	net_dev->local.stats.rx_packets++;
+/* net_dev->local.stats.rx_packets++; */ /* done in isdn_net.c */
 	/* Reset hangup-timer */
 	lp->huptimer = 0;
 
@@ -986,7 +1097,7 @@
  * skb isn't allowed!! 
  */
 
-static void isdn_ppp_skb_destructor(struct sk_buff *skb)
+static void isdn_ppp_skb_destructor(struct sk_buff *skb)	/* debug function */
 {
 	char outstr[80],*outpnt=outstr;
 	int i;
@@ -1009,22 +1120,55 @@
 
 	if(mdev)
 		mlp = (isdn_net_local *) (mdev->priv); 
-	else
+	else {
+		mdev = dev;
 		mlp = (isdn_net_local *) (dev->priv);
+	}
 	nd = mlp->netdev;	/* get master lp */
 	ipts = ippp_table[mlp->ppp_slot];
 
 	if (!(ipts->pppcfg & SC_ENABLE_IP)) {    /* PPP connected ? */
+#ifdef ISDN_SYNCPPP_READDRESS
+		if(!ipts->old_pa_addr)
+			ipts->old_pa_addr = mdev->pa_addr;
+		if(!ipts->old_pa_dstaddr)
+			ipts->old_pa_dstaddr = mdev->pa_dstaddr;
+#endif
 		if(ipts->debug & 0x1) {
 			printk(KERN_INFO "%s: IP frame delayed.\n",dev->name);
 			skb->destructor = isdn_ppp_skb_destructor;
 		}
  		return 1;
-        }
+	}
 
 	skb->destructor = NULL;
 
+	switch(ntohs(skb->protocol)) {
+		case ETH_P_IP:
+			proto = PPP_IP;
+#ifdef ISDN_SYNCPPP_READDRESS
+			if(ipts->old_pa_addr != mdev->pa_addr)
+			{
+				struct iphdr *ipfr;
+				ipfr = (struct iphdr *) skb->data;
+printk(KERN_DEBUG "IF-address changed from %lx to %lx\n",ipts->old_pa_addr,mdev->pa_addr);
+				if(ipfr->version == 4) {
+					if(ipfr->saddr == ipts->old_pa_addr) {
+printk(KERN_DEBUG "readdressing %lx to %lx\n",ipfr->saddr,mdev->pa_addr);
+						ipfr->saddr = mdev->pa_addr;
+					}
+				}
+			}
+			/* dstaddr change not so improtant */
+#endif
+			break;
+		case ETH_P_IPX:
+			proto = PPP_IPX;	/* untested */
+			break;
+	}
+
 	lp = nd->queue;		/* get lp on top of queue */
+
 	if(lp->sav_skb) {	/* find a non-busy device */
 		isdn_net_local *nlp = lp->next;
 		while(lp->sav_skb) {
@@ -1046,7 +1190,7 @@
 		printk(KERN_DEBUG  "xmit skb, len %ld\n",skb->len);
 
 #ifdef CONFIG_ISDN_PPP_VJ
-	if (ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes .. but this check again */
+	if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes .. but this check again */
 		struct sk_buff *new_skb;
 
 		new_skb = dev_alloc_skb(skb->len);
@@ -1118,6 +1262,12 @@
 	skb->data[3] = proto & 0xff;
 
         /* tx-stats are now updated via BSENT-callback */
+
+	if(ipts->debug & 0x40) {
+		printk(KERN_DEBUG "skb xmit: len: %ld\n",skb->len);
+		isdn_ppp_frame_log("xmit",skb->data,skb->len,32);
+	}
+
 	if(isdn_net_send_skb(dev , lp , skb)) {	
 		if(lp->sav_skb) {	/* whole sav_skb processing with disabled IRQs ?? */
 			printk(KERN_ERR "%s: whoops .. there is another stored skb!\n",dev->name);
@@ -1129,6 +1279,8 @@
 	return 0;
 }
 
+#ifdef CONFIG_ISDN_MPP
+
 void isdn_ppp_free_sqqueue(isdn_net_dev * p) 
 {
 	struct sqqueue *q = p->ib.sq;
@@ -1158,8 +1310,6 @@
 	}
 }
 
-#ifdef CONFIG_ISDN_MPP
-
 static int isdn_ppp_bundle(struct ippp_struct *is, int unit)
 {
 	char ifn[IFNAMSIZ + 1];
@@ -1215,8 +1365,7 @@
 	}
 }
 
-
-static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int BEbyte, int *sqnop, int min_sqno)
+static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int BEbyte, long *sqnop, int min_sqno)
 {
 	struct mpqueue *qe, *q1, *q;
 	long cnt, flags;
@@ -1228,7 +1377,7 @@
 		printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n");
 		save_flags(flags);
 		cli();
-		isdn_ppp_cleanup_queue(dev, min_sqno);
+		isdn_ppp_cleanup_mpqueue(dev, min_sqno);
 		restore_flags(flags);
 		return -1;
 	}
@@ -1244,7 +1393,7 @@
 		dev->mp_last = q1;
 		q1->next = NULL;
 		q1->last = NULL;
-		isdn_ppp_cleanup_queue(dev, min_sqno);	/* not necessary */
+		isdn_ppp_cleanup_mpqueue(dev, min_sqno);	/* not necessary */
 		restore_flags(flags);
 		return -1;
 	}
@@ -1278,7 +1427,7 @@
 	while (!(q->BEbyte & MP_END_FRAG)) {
 		cnt++;
 		if (!(q->next) || q->next->sqno != cnt) {
-			isdn_ppp_cleanup_queue(dev, min_sqno);
+			isdn_ppp_cleanup_mpqueue(dev, min_sqno);
 			restore_flags(flags);
 			return -1;
 		}
@@ -1293,7 +1442,7 @@
 	while (!(q->BEbyte & MP_BEGIN_FRAG)) {
 		cnt--;
 		if (!(q->last) || q->last->sqno != cnt) {
-			isdn_ppp_cleanup_queue(dev, min_sqno);
+			isdn_ppp_cleanup_mpqueue(dev, min_sqno);
 			restore_flags(flags);
 			return -1;
 		}
@@ -1313,7 +1462,7 @@
 	sqno_end = qe->sqno;
 	*sqnop = q->sqno;
 
-	isdn_ppp_cleanup_queue(dev, min_sqno);
+	isdn_ppp_cleanup_mpqueue(dev, min_sqno);
 	restore_flags(flags);
 
 	*skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
@@ -1344,10 +1493,32 @@
 }
 
 /*
- * remove stale packets from list
+ * check sq-queue, whether we have still buffered the next packet(s)
+ * or packets with a sqno less or equal to min_sqno
+ * net_dev: master netdevice , lp: 'real' local connection
  */
+static void isdn_ppp_cleanup_sqqueue(isdn_net_dev *net_dev, isdn_net_local *lp,long min_sqno)
+{
+	struct sqqueue *q;
+
+	while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno) ) {
+		if(q->sqno_start != net_dev->ib.next_num) {
+			printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n",net_dev->ib.next_num);
+#ifdef CONFIG_ISDN_PPP_VJ
+			slhc_toss(ippp_table[net_dev->local.ppp_slot]->slcomp);
+#endif
+		}
+		isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
+		net_dev->ib.sq = q->next;
+		net_dev->ib.next_num = q->sqno_end + 1;
+		kfree(q);
+    }
+}
 
-static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min_sqno)
+/*
+ * remove stale packets from list
+ */
+static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
 {
 #ifdef CONFIG_ISDN_PPP_VJ
 	int toss = 0;
@@ -1404,9 +1575,9 @@
 	while (net_dev) {
 		isdn_net_local *lp = &net_dev->local;
 		if (net_dev->ib.modify || lp->master)	{	/* interface locked or slave?*/
-                        net_dev = net_dev->next;
+			net_dev = net_dev->next;
 			continue;
-                }
+		}
 
 		q = net_dev->ib.sq;
 		while (q) {
@@ -1475,7 +1646,7 @@
 		}
 #endif
 	}
-	memcpy_tofs (res, &t, sizeof (struct ppp_stats));
+	copy_to_user (res, &t, sizeof (struct ppp_stats));
 	return 0;
 
 }
@@ -1500,7 +1671,7 @@
 			len = strlen(PPP_VERSION) + 1;
 			error = verify_area(VERIFY_WRITE, r, len);
 			if (!error)
-				memcpy_tofs(r, PPP_VERSION, len);
+				copy_to_user(r, PPP_VERSION, len);
 			break;
 		case SIOCGPPPSTATS:
 			error = isdn_ppp_dev_ioctl_stats (lp->ppp_slot, ifr, dev);
@@ -1596,4 +1767,14 @@
 	return -1;
 #endif
 }
+
+#if 0
+static struct symbol_table isdn_ppp_syms = {
+#include <linux/symtab_begin.h>
+    X(isdn_ppp_register_compressor),
+    X(isdn_ppp_unregister_compressor),
+#include <linux/symtab_end.h>
+};
+#endif
+
 
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h
--- v2.0.25/linux/drivers/isdn/isdn_ppp.h	Sun Sep  1 09:15:32 1996
+++ linux/drivers/isdn/isdn_ppp.h	Wed Nov 13 08:36:20 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.h,v 1.4 1996/05/06 11:34:56 hipp Exp $
+/* $Id: isdn_ppp.h,v 1.6 1996/09/23 01:58:11 fritz Exp $
  *
  * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_ppp.h,v $
+ * Revision 1.6  1996/09/23 01:58:11  fritz
+ * Fix: With syncPPP encapsulation, discard LCP packets
+ *      when calculating hangup timeout.
+ *
+ * Revision 1.5  1996/09/07 12:51:34  hipp
+ * *** empty log message ***
+ *
  * Revision 1.4  1996/05/06 11:34:56  hipp
  * fixed a few bugs
  *
@@ -34,6 +41,7 @@
  *
  */
 
+#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
 extern void isdn_ppp_timer_timeout(void);
 extern int  isdn_ppp_read(int , struct file *, char *, int);
 extern int  isdn_ppp_write(int , struct file *, const char *, int);
@@ -54,3 +62,10 @@
 extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
 
 extern struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+
+#define IPPP_OPEN	0x01
+#define IPPP_CONNECT	0x02
+#define IPPP_CLOSEWAIT	0x04
+#define IPPP_NOBLOCK	0x08
+#define IPPP_ASSIGNED	0x10
+
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- v2.0.25/linux/drivers/isdn/isdn_tty.c	Sat Jun 29 20:36:22 1996
+++ linux/drivers/isdn/isdn_tty.c	Wed Nov 13 08:36:20 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.21 1996/06/24 17:40:28 fritz Exp $
+/* $Id: isdn_tty.c,v 1.23 1996/10/22 23:14:02 fritz Exp $
  *
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -20,6 +20,12 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_tty.c,v $
+ * Revision 1.23  1996/10/22 23:14:02  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
+ * Revision 1.22  1996/10/19 18:56:43  fritz
+ * ATZ did not change the xmitbuf size.
+ *
  * Revision 1.21  1996/06/24 17:40:28  fritz
  * Bugfix: Did not compile without CONFIG_ISDN_AUDIO
  *
@@ -125,7 +131,7 @@
 
 static int  isdn_tty_edit_at(const char *, int, modem_info *, int);
 static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int);
-static void isdn_tty_modem_reset_regs(atemu *, int);
+static void isdn_tty_modem_reset_regs(modem_info *, int);
 static void isdn_tty_cmd_ATA(modem_info *);
 static void isdn_tty_at_cout(char *, modem_info *);
 static void isdn_tty_flush_buffer(struct tty_struct *);
@@ -139,7 +145,7 @@
 static int bit2si[8] = {1,5,7,7,7,7,7,7};
 static int si2bit[8] = {4,1,4,4,4,4,4,4};
                                 
-char *isdn_tty_revision        = "$Revision: 1.21 $";
+char *isdn_tty_revision        = "$Revision: 1.23 $";
 
 #define DLE 0x10
 #define ETX 0x03
@@ -375,7 +381,7 @@
                 return 1;
         }
 	if (from_user) {
-		memcpy_fromfs(tmpbuf, buf, c);
+		copy_from_user(tmpbuf, buf, c);
                 p = tmpbuf;
         } else
                 p = (char *)buf;
@@ -710,7 +716,7 @@
 #endif
                         if (info->online)
                                 info->ncarrier = 1;
-                        isdn_tty_modem_reset_regs(&info->emu, 0);
+                        isdn_tty_modem_reset_regs(info, 0);
                         isdn_tty_modem_hup(info);
                 }
                 return;
@@ -785,7 +791,7 @@
 	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
 		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
                 if (info->emu.mdmreg[13] & 4) {
-                        isdn_tty_modem_reset_regs(&info->emu, 0);
+                        isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
                         printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
 #endif
@@ -836,7 +842,7 @@
                                                    &(m->lastplus),
                                                    from_user);
                         if (from_user)
-                                memcpy_fromfs(&(info->xmit_buf[info->xmit_count]), buf, c);
+                                copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c);
                         else
                                 memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
 #ifdef CONFIG_ISDN_AUDIO
@@ -1041,9 +1047,10 @@
 
 static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
 {
-	uint arg = get_user((uint *) value);
+	uint arg;
         int pre_dtr;
 
+    GET_USER(arg, (uint *)value);
 	switch (cmd) {
                 case TIOCMBIS:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
@@ -1067,7 +1074,7 @@
                         if (arg & TIOCM_DTR) {
                                 info->mcr &= ~UART_MCR_DTR;
                                 if (info->emu.mdmreg[13] & 4) {
-                                        isdn_tty_modem_reset_regs(&info->emu, 0);
+                                        isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
                                         printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
 #endif
@@ -1088,7 +1095,7 @@
                         if (pre_dtr |= (info->mcr & UART_MCR_DTR)) {
                                 if (!(info->mcr & UART_MCR_DTR)) {
                                         if (info->emu.mdmreg[13] & 4) {
-                                                isdn_tty_modem_reset_regs(&info->emu, 0);
+                                                isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
                                                 printk(KERN_DEBUG "Mhup in TIOCMSET\n");
 #endif
@@ -1152,7 +1159,7 @@
                         error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
                         if (error)
                                 return error;
-                        arg = get_user((ulong *) arg);
+                        GET_USER(arg, (ulong *) arg);
                         tty->termios->c_cflag =
                                 ((tty->termios->c_cflag & ~CLOCAL) |
                                  (arg ? CLOCAL : 0));
@@ -1546,11 +1553,13 @@
         m->vpar[3] = 2;  /* Compression type        (1 = ADPCM-2   ) */
 }
 
-static void isdn_tty_modem_reset_regs(atemu * m, int force)
+static void isdn_tty_modem_reset_regs(modem_info *info, int force)
 {
+        atemu *m = &info->emu;
 	if ((m->mdmreg[12] & 32) || force) {
 		memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
 		memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
+                info->xmit_size = m->mdmreg[16] * 16;
 	}
         isdn_tty_modem_reset_vpar(m);
 	m->mdmcmdl = 0;
@@ -1622,7 +1631,7 @@
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		info = &m->info[i];
 		isdn_tty_reset_profile(&info->emu);
-		isdn_tty_modem_reset_regs(&info->emu, 1);
+		isdn_tty_modem_reset_regs(info, 1);
 		info->magic = ISDN_ASYNC_MAGIC;
 		info->line = i;
 		info->tty = 0;
@@ -1840,7 +1849,7 @@
 		*pluscount = 0;
 	}
 	if (from_user) {
-		memcpy_fromfs(cbuf, p, count);
+		copy_from_user(cbuf, p, count);
 		p = cbuf;
 	}
 	while (count > 0) {
@@ -2054,7 +2063,7 @@
                         /* &F -Set Factory-Defaults */
                         p[0]++;
                         isdn_tty_reset_profile(m);
-                        isdn_tty_modem_reset_regs(m, 1);
+                        isdn_tty_modem_reset_regs(info, 1);
                         break;
                 case 'S':
                         /* &S - Set Windowsize */
@@ -2612,7 +2621,7 @@
                         case 'Z':
                                 /* Z - Load Registers from Profile */
                                 p++;
-                                isdn_tty_modem_reset_regs(m, 1);
+                                isdn_tty_modem_reset_regs(info, 1);
                                 break;
 #ifdef CONFIG_ISDN_AUDIO
                         case '+':
@@ -2670,7 +2679,7 @@
 
 	for (cnt = count; cnt > 0; p++, cnt--) {
 		if (user)
-			c = get_user(p);
+			GET_USER(c, p);
 		else
 			c = *p;
 		total++;
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c
--- v2.0.25/linux/drivers/isdn/pcbit/drv.c	Sat Jun 29 20:36:22 1996
+++ linux/drivers/isdn/pcbit/drv.c	Wed Nov 13 08:36:20 1996
@@ -428,7 +428,7 @@
 		{
 			u_char cbuf[1024];
 
-			memcpy_fromfs(cbuf, buf, len);
+			copy_from_user(cbuf, buf, len);
 			for (i=0; i<len; i++)
 				writeb(cbuf[i], dev->sh_mem + i);
 		}
@@ -446,7 +446,7 @@
 			/* get it into kernel space */
 			if ((ptr = kmalloc(len, GFP_KERNEL))==NULL)
 				return -ENOMEM;
-			memcpy_fromfs(ptr, buf, len);
+			copy_from_user(ptr, buf, len);
 			loadbuf = ptr;
 		}
 		else
@@ -761,8 +761,13 @@
 static int stat_end = 0;
 
 
-#define memcpy_to_COND(flag, d, s, len) \
-(flag ? memcpy_tofs(d, s, len) : memcpy(d, s, len))
+static __inline void
+memcpy_to_COND(int flag, char *d, const char *s, int len) {
+	if (flag)
+		copy_to_user(d, s, len);
+	else
+		memcpy(d, s, len);
+}
 
 
 int pcbit_stat(u_char* buf, int len, int user, int driver, int channel)
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/teles/callc.c linux/drivers/isdn/teles/callc.c
--- v2.0.25/linux/drivers/isdn/teles/callc.c	Sat Jun 29 20:36:23 1996
+++ linux/drivers/isdn/teles/callc.c	Wed Nov 13 08:36:20 1996
@@ -1,6 +1,9 @@
-/* $Id: callc.c,v 1.13 1996/06/24 17:15:55 fritz Exp $
+/* $Id: callc.c,v 1.14 1996/10/22 23:14:14 fritz Exp $
  *
  * $Log: callc.c,v $
+ * Revision 1.14  1996/10/22 23:14:14  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
  * Revision 1.13  1996/06/24 17:15:55  fritz
  * corrected return code of teles_writebuf()
  *
@@ -1451,7 +1454,7 @@
         ptr += i;
 
         if (user)
-                memcpy_fromfs(ptr, buf, count);
+                copy_from_user(ptr, buf, count);
         else
                 memcpy(ptr, buf, count);
         ibh->datasize = count + i;
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c
--- v2.0.25/linux/drivers/isdn/teles/card.c	Sun Sep  1 09:15:32 1996
+++ linux/drivers/isdn/teles/card.c	Wed Nov 13 08:36:20 1996
@@ -1,4 +1,4 @@
-/* $Id: card.c,v 1.13 1996/07/18 11:21:24 jdenoud Exp $
+/* $Id: card.c,v 1.16 1996/10/22 23:14:16 fritz Exp $
  *
  * card.c     low level stuff for the Teles S0 isdn card
  * 
@@ -7,6 +7,15 @@
  * Beat Doebeli         log all D channel traffic
  * 
  * $Log: card.c,v $
+ * Revision 1.16  1996/10/22 23:14:16  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
+ * Revision 1.15  1996/09/29 19:41:56  fritz
+ * Bugfix: ignore unknown frames.
+ *
+ * Revision 1.14  1996/09/23 01:53:49  fritz
+ * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
+ *
  * Revision 1.13  1996/07/18 11:21:24  jdenoud
  * Use small buffers for incoming audio data
  *
@@ -59,6 +68,7 @@
 
 #define __NO_VERSION__
 #include "teles.h"
+#include "proto.h"
 
 #define INCLUDE_INLINE_FUNCS
 #include <linux/tqueue.h>
@@ -77,7 +87,7 @@
 static inline   byte
 readisac_0(byte * cardm, byte offset)
 {
-	return *(byte *) (cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
+	return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
 }
 
 static inline   byte
@@ -92,7 +102,7 @@
 static inline void
 writeisac_0(byte * cardm, byte offset, byte value)
 {
-	*(byte *) (cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset) = value;
+	writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
 }
 
 static inline void
@@ -119,7 +129,7 @@
 static inline   byte
 readhscx_0(byte * base, byte hscx, byte offset)
 {
-	return *(byte *) (base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
+	return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
 			  ((hscx & 1) ? 0x40 : 0) + offset);
 }
 
@@ -135,8 +145,8 @@
 static inline void
 writehscx_0(byte * base, byte hscx, byte offset, byte data)
 {
-	*(byte *) (base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
-		   ((hscx & 1) ? 0x40 : 0) + offset) = data;
+	writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
+		   ((hscx & 1) ? 0x40 : 0) + offset);
 }
 
 static inline void
@@ -1253,12 +1263,12 @@
         if (card->membase) {
                 cli();
                 timout = jiffies + (HZ / 5) + 1;
-                *(byte *) (card->membase + 0x80) = 0;
+                writeb(0, card->membase + 0x80);
                 sti();
                 while (jiffies <= timout);
                 
                 cli();
-                *(byte *) (card->membase + 0x80) = 1;
+                writeb(1, card->membase + 0x80);
                 timout = jiffies + (HZ / 5) + 1;
                 sti();
                 while (jiffies <= timout);
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/teles/isdnl3.c linux/drivers/isdn/teles/isdnl3.c
--- v2.0.25/linux/drivers/isdn/teles/isdnl3.c	Fri Jun  7 16:02:42 1996
+++ linux/drivers/isdn/teles/isdnl3.c	Wed Nov 13 08:36:20 1996
@@ -1,6 +1,12 @@
-/* $Id: isdnl3.c,v 1.9 1996/06/06 14:22:27 fritz Exp $
+/* $Id: isdnl3.c,v 1.11 1996/09/29 19:41:58 fritz Exp $
  *
  * $Log: isdnl3.c,v $
+ * Revision 1.11  1996/09/29 19:41:58  fritz
+ * Bugfix: ignore unknown frames.
+ *
+ * Revision 1.10  1996/09/25 18:32:43  keil
+ * response for STATUS_ENQ message added
+ *
  * Revision 1.9  1996/06/06 14:22:27  fritz
  * Changed level of "non-digital call..." message, since
  * with audio support, this is quite normal.
@@ -391,6 +397,42 @@
 	newl3state(st, 7);
 }
 
+static void
+l3s21(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *dibh=arg;
+	byte           *p;
+	int             size;
+
+	BufPoolRelease(dibh);
+	
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+	size = st->l2.ihsize;
+
+	*p++ = 0x8;
+	*p++ = 0x1;
+	*p++ = st->l3.callref;
+	*p++ = MT_STATUS;
+	size += 4;
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = 0x9E; /* answer status enquire */
+	size += 4;
+
+	*p++ = 0x14; /* CallState */
+	*p++ = 0x1;
+	*p++ = st->l3.state & 0x3f; /* ISO L3 CallState */
+	size += 3;
+
+	dibh->datasize = size;
+	i_down(st, dibh);
+
+}
+
 struct stateentry {
 	int             state;
 	byte            primitive;
@@ -432,34 +474,44 @@
 
 static struct stateentry datastatelist[] =
 {
+        {0,MT_STATUS_ENQUIRY,l3s21},
         {0,MT_SETUP,l3s12},
+        {1,MT_STATUS_ENQUIRY,l3s21},
         {1,MT_CALL_PROCEEDING,l3s6},
         {1,MT_SETUP_ACKNOWLEDGE,l3s6},
         {1,MT_RELEASE_COMPLETE,l3s4},
         {1,MT_RELEASE,l3s19},
         {1,MT_DISCONNECT,l3s7},
+        {3,MT_STATUS_ENQUIRY,l3s21},
         {3,MT_DISCONNECT,l3s7},
         {3,MT_CONNECT,l3s8},
         {3,MT_ALERTING,l3s11},
         {3,MT_RELEASE,l3s19},
         {3,MT_RELEASE_COMPLETE,l3s4},
+        {4,MT_STATUS_ENQUIRY,l3s21},
         {4,MT_CONNECT,l3s8},
         {4,MT_DISCONNECT,l3s7},
         {4,MT_RELEASE,l3s19},
         {4,MT_RELEASE_COMPLETE,l3s4},
+        {8,MT_STATUS_ENQUIRY,l3s21},
         {6,MT_SETUP,l3s12},
+        {8,MT_STATUS_ENQUIRY,l3s21},
         {7,MT_RELEASE,l3s19},
         {7,MT_RELEASE_COMPLETE,l3s4_1},
         {7,MT_DISCONNECT,l3s7},
+        {8,MT_STATUS_ENQUIRY,l3s21},
         {8,MT_RELEASE,l3s19},
         {8,MT_CONNECT_ACKNOWLEDGE,l3s17},
         {8,MT_DISCONNECT,l3s7},
         {8,MT_RELEASE_COMPLETE,l3s4_1},
+        {10,MT_STATUS_ENQUIRY,l3s21},
         {10,MT_DISCONNECT,l3s7},
         {10,MT_RELEASE,l3s19},
         {10,MT_RELEASE_COMPLETE,l3s4_1},
+        {11,MT_STATUS_ENQUIRY,l3s21},
         {11,MT_RELEASE,l3s19},
         {11,MT_RELEASE_COMPLETE,l3s4},
+        {19,MT_STATUS_ENQUIRY,l3s21},
         {19,MT_RELEASE_COMPLETE,l3s4},
 };
 
@@ -502,7 +554,7 @@
 				  datastatelist_1tr6t[i].rout(st, pr, ibh);
 			  break;
 #endif
-		  default:	/* E-DSS1 */
+		  case PROTO_EURO:	/* E-DSS1 */
 			  for (i = 0; i < datasllen; i++)
 				  if ((st->l3.state == datastatelist[i].state) &&
 				      (mt == datastatelist[i].primitive))
@@ -514,6 +566,10 @@
 				 		st->l3.state, mt);
 			  } else
 				  datastatelist[i].rout(st, pr, ibh);
+			  break;
+		  default:
+		          BufPoolRelease(ibh);
+			  break;
 		}
 	} else if (pr == DL_UNIT_DATA) {
 		ptr = DATAPTR(ibh);
@@ -540,7 +596,7 @@
 				  datastatelist_1tr6t[i].rout(st, pr, ibh);
 			  break;
 #endif
-		  default:	/* E-DSS1 */
+		  case PROTO_EURO:	/* E-DSS1 */
 			  for (i = 0; i < datasllen; i++)
 				  if ((st->l3.state == datastatelist[i].state) &&
 				      (mt == datastatelist[i].primitive))
@@ -552,6 +608,10 @@
 				 		st->l3.state, mt);
 			  } else
 				  datastatelist[i].rout(st, pr, ibh);
+			  break;
+		  default:
+		          BufPoolRelease(ibh);
+			  break;
 		}
 	}
 }
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/teles/l3_1TR6.c linux/drivers/isdn/teles/l3_1TR6.c
--- v2.0.25/linux/drivers/isdn/teles/l3_1TR6.c	Fri Jun  7 16:02:42 1996
+++ linux/drivers/isdn/teles/l3_1TR6.c	Wed Nov 13 08:36:20 1996
@@ -1,6 +1,12 @@
-/* $Id: l3_1TR6.c,v 1.4 1996/06/06 14:22:28 fritz Exp $
+/* $Id: l3_1TR6.c,v 1.6 1996/09/25 18:34:57 keil Exp $
  *
  * $Log: l3_1TR6.c,v $
+ * Revision 1.6  1996/09/25 18:34:57  keil
+ * missing states in 1TR6 Statemachine added
+ *
+ * Revision 1.5  1996/09/23 01:53:51  fritz
+ * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
+ *
  * Revision 1.4  1996/06/06 14:22:28  fritz
  * Changed level of "non-digital call..." message, since
  * with audio support, this is quite normal.
@@ -19,6 +25,8 @@
  *
  */
 
+#include	"proto.h"
+
 static void
 l3_1TR6_message(struct PStack *st, int mt, int pd)
 {
@@ -404,7 +412,7 @@
 }
 
 static void
-l3_1tr6_ignore(struct PStack *st, byte pr, void *arg)
+l3_1tr6_reset(struct PStack *st, byte pr, void *arg)
 {
 	newl3state(st, 0);
 }
@@ -453,16 +461,36 @@
 static struct stateentry downstatelist_1tr6t[] =
 {
 	{0, CC_SETUP_REQ, l3_1tr6_setup},
+	{1, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
+	{1, CC_RELEASE_REQ, l3_1tr6_rel_req},
+        {1, CC_DLRL, l3_1tr6_reset},
+	{2, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
+	{2, CC_RELEASE_REQ, l3_1tr6_rel_req},
+        {2, CC_DLRL, l3_1tr6_reset},
+	{3, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
+	{3, CC_RELEASE_REQ, l3_1tr6_rel_req},
+        {3, CC_DLRL, l3_1tr6_reset},
 	{4, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{6, CC_REJECT_REQ, l3_1tr6_ignore},
+	{4, CC_RELEASE_REQ, l3_1tr6_rel_req},
+        {4, CC_DLRL, l3_1tr6_reset},
+	{6, CC_REJECT_REQ, l3_1tr6_reset},
+	{6, CC_RELEASE_REQ, l3_1tr6_rel_req},
 	{6, CC_SETUP_RSP, l3_1tr6_conn},
 	{6, CC_ALERTING_REQ, l3_1tr6_alert},
+        {6, CC_DLRL, l3_1tr6_reset},
 	{7, CC_SETUP_RSP, l3_1tr6_conn},
+	{7, CC_RELEASE_REQ, l3_1tr6_rel_req},
 	{7, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-        {7, CC_DLRL, l3_1tr6_disconn_req},
+        {7, CC_DLRL, l3_1tr6_reset},
 	{8, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
+	{8, CC_RELEASE_REQ, l3_1tr6_rel_req},
+        {8, CC_DLRL, l3_1tr6_reset},
 	{10, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{12, CC_RELEASE_REQ, l3_1tr6_rel_req}
+	{10, CC_RELEASE_REQ, l3_1tr6_rel_req},
+        {10, CC_DLRL, l3_1tr6_reset},
+	{12, CC_RELEASE_REQ, l3_1tr6_rel_req},
+        {12, CC_DLRL, l3_1tr6_reset},
+        {19, CC_DLRL, l3_1tr6_reset},
 };
 
 static int      downsl_1tr6t_len = sizeof(downstatelist_1tr6t) /
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/teles/l3_1TR6.h linux/drivers/isdn/teles/l3_1TR6.h
--- v2.0.25/linux/drivers/isdn/teles/l3_1TR6.h	Sun May 19 15:29:31 1996
+++ linux/drivers/isdn/teles/l3_1TR6.h	Wed Nov 13 08:36:20 1996
@@ -1,6 +1,9 @@
-/* $Id: l3_1TR6.h,v 1.3 1996/04/30 21:53:48 isdn4dev Exp $
+/* $Id: l3_1TR6.h,v 1.4 1996/09/23 01:53:52 fritz Exp $
  *
  * $Log: l3_1TR6.h,v $
+ * Revision 1.4  1996/09/23 01:53:52  fritz
+ * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
+ *
  * Revision 1.3  1996/04/30 21:53:48  isdn4dev
  * Bugs, SPV, Logging in q931.c  Karsten Keil
  *
@@ -11,9 +14,6 @@
  */
 #ifndef l3_1TR6
 #define l3_1TR6
-
-#define PROTO_DIS_N0 0x40
-#define PROTO_DIS_N1 0x41
 
 /*
  * MsgType N0
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/teles/llglue.c linux/drivers/isdn/teles/llglue.c
--- v2.0.25/linux/drivers/isdn/teles/llglue.c	Fri Jun  7 16:02:42 1996
+++ linux/drivers/isdn/teles/llglue.c	Wed Nov 13 08:36:20 1996
@@ -1,6 +1,9 @@
-/* $Id: llglue.c,v 1.6 1996/06/03 20:03:39 fritz Exp $
+/* $Id: llglue.c,v 1.7 1996/10/22 23:14:17 fritz Exp $
  *
  * $Log: llglue.c,v $
+ * Revision 1.7  1996/10/22 23:14:17  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
  * Revision 1.6  1996/06/03 20:03:39  fritz
  * Fixed typos.
  *
@@ -47,7 +50,7 @@
 
 	for (p = buf, count = 0; count < len; p++, count++) {
 		if (user)
-			put_fs_byte(*teles_status_read++, p);
+			put_user(*teles_status_read++, p);
 		else
 			*p++ = *teles_status_read++;
 		if (teles_status_read > teles_status_end)
diff -u --recursive --new-file v2.0.25/linux/drivers/isdn/teles/q931.c linux/drivers/isdn/teles/q931.c
--- v2.0.25/linux/drivers/isdn/teles/q931.c	Fri Jun  7 16:02:42 1996
+++ linux/drivers/isdn/teles/q931.c	Wed Nov 13 08:36:20 1996
@@ -1,4 +1,4 @@
-/* $Id: q931.c,v 1.5 1996/06/03 20:03:40 fritz Exp $
+/* $Id: q931.c,v 1.6 1996/09/23 01:53:53 fritz Exp $
  *
  * q931.c               code to decode ITU Q.931 call control messages
  * 
@@ -14,6 +14,9 @@
  *
  * 
  * $Log: q931.c,v $
+ * Revision 1.6  1996/09/23 01:53:53  fritz
+ * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
+ *
  * Revision 1.5  1996/06/03 20:03:40  fritz
  * Fixed typos.
  *
@@ -35,6 +38,7 @@
 
 #define __NO_VERSION__
 #include "teles.h"
+#include "proto.h"
 #include "l3_1TR6.h"
 
 byte           *
@@ -1083,7 +1087,7 @@
 			}
 			buf += buf[1] + 2;
 		}
-	} else {	/* EURO */
+	} else if (buf[0]==PROTO_EURO) {	/* EURO */
 		/* locate message type */
 		for (i = 0; i < MTSIZE; i++)
 			if (mtlist[i].nr == buf[3])
@@ -1144,6 +1148,8 @@
 			buf += buf[1] + 2;
 		}
 	}
+	else dp += sprintf(dp,"Unnown frame type %.2x, ignored\n",buf[0]);
+
 	dp += sprintf(dp, "\n");
 	teles_putstatus(sp->dlogspace);
 }
diff -u --recursive --new-file v2.0.25/linux/drivers/net/README.multicast linux/drivers/net/README.multicast
--- v2.0.25/linux/drivers/net/README.multicast	Fri Nov 24 16:39:53 1995
+++ linux/drivers/net/README.multicast	Thu Nov 14 15:20:09 1996
@@ -19,6 +19,7 @@
 3c505		YES		NO		YES		Hardware
 3c507		NO		NO		NO		N/A
 3c509		YES		YES		YES		Software
+3c59x		YES		YES		YES		Software
 ac3200		YES		YES		YES		Software(#)
 apricot		YES		PROMISC		YES		Hardware
 arcnet		NO		NO		NO		N/A
diff -u --recursive --new-file v2.0.25/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.0.25/linux/drivers/net/de4x5.c	Wed Sep 11 17:57:14 1996
+++ linux/drivers/net/de4x5.c	Sat Nov  9 19:31:38 1996
@@ -29,8 +29,7 @@
     measurement. Their error is +/-20k on a quiet (private) network and also
     depend on what load the CPU has.
 
-    The author may    be reached  at  davies@wanton.lkg.dec.com  or  Digital
-    Equipment Corporation, 550 King Street, Littleton MA 01460.
+    The author may be reached at davies@maniac.ultranet.com.
 
     =========================================================================
     This driver has been written  substantially  from scratch, although  its
@@ -212,11 +211,13 @@
 			  and <michael@compurex.com>
       0.441   9-Sep-96    Change dc21041_autoconf() to probe quiet BNC media
                            with a loopback packet.
+      0.442   9-Sep-96    Include AUI in dc21041 media printout. Bug reported
+                           by <bhat@mundook.cs.mu.OZ.AU>
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:v0.441 96/9/9 davies@wanton.lkg.dec.com\n";
+static const char *version = "de4x5.c:v0.442 96/11/7 davies@maniac.ultranet.com\n";
 
 #include <linux/module.h>
 
@@ -915,7 +916,7 @@
 
     }
     
-    if (de4x5_debug > 0) {
+    if (de4x5_debug > 1) {
 	printk(version);
     }
     
@@ -3760,10 +3761,11 @@
 			(lp->media == TP  ? "TP." :
 			 (lp->media == ANS ? "TP/Nway." :
 			  (lp->media == BNC ? "BNC." : 
-			   (lp->media == BNC_AUI ? "BNC/AUI." : 
-			    (lp->media == EXT_SIA ? "EXT SIA." : 
-			     "???."
-			     )))))));
+			   (lp->media == AUI ? "AUI." : 
+			    (lp->media == BNC_AUI ? "BNC/AUI." : 
+			     (lp->media == EXT_SIA ? "EXT SIA." : 
+			      "???."
+			      ))))))));
 	    } else {
 		printk("%s: mode is %s\n", dev->name,
 		    (lp->media == NC ? "link down or incompatible connection.":
diff -u --recursive --new-file v2.0.25/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.0.25/linux/drivers/net/depca.c	Wed Aug 21 09:18:08 1996
+++ linux/drivers/net/depca.c	Sat Nov  9 19:31:38 1996
@@ -37,9 +37,7 @@
     I have benchmarked the driver with a  DE100 at 595kB/s to (542kB/s from)
     a DECstation 5000/200.
 
-    The   author   may    be   reached  at    davies@wanton.lkg.dec.com   or
-    davies@maniac.ultranet.com  or Digital  Equipment Corporation, 550  King
-    Street, Littleton MA 01460.
+    The author may be reached at davies@maniac.ultranet.com
 
     =========================================================================
 
@@ -208,7 +206,7 @@
     =========================================================================
 */
 
-static const char *version = "depca.c:v0.43 96/8/16 davies@wanton.lkg.dec.com\n";
+static const char *version = "depca.c:v0.43 96/8/16 davies@maniac.ultranet.com\n";
 
 #include <linux/module.h>
 
@@ -650,7 +648,7 @@
       status = -ENXIO;
     }
     if (!status) {
-      if (depca_debug > 0) {
+      if (depca_debug > 1) {
 	printk(version);
       }
 
diff -u --recursive --new-file v2.0.25/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.0.25/linux/drivers/net/ewrk3.c	Wed Aug 21 09:18:08 1996
+++ linux/drivers/net/ewrk3.c	Sat Nov  9 19:31:38 1996
@@ -18,9 +18,7 @@
     card and benchmarked with 'ttcp': it transferred 16M  of data at 975kB/s
     (7.8Mb/s) to a DECstation 5000/200.
 
-    The     author  may  be    reached    at  davies@wanton.lkg.dec.com   or
-    davies@maniac.ultranet.com or  Digital  Equipment Corporation,  550 King
-    Street, Littleton MA 01460.
+    The author may be reached at davies@maniac.ultranet.com.
 
     =========================================================================
     This driver has been written  substantially  from scratch, although  its
@@ -138,7 +136,7 @@
     =========================================================================
 */
 
-static const char *version = "ewrk3.c:v0.43 96/8/16 davies@wanton.lkg.dec.com\n";
+static const char *version = "ewrk3.c:v0.43 96/8/16 davies@maniac.ultranet.com\n";
 
 #include <linux/module.h>
 
@@ -590,7 +588,7 @@
     }
 
     if (!status) {
-      if (ewrk3_debug > 0) {
+      if (ewrk3_debug > 1) {
 	printk(version);
       }
       
diff -u --recursive --new-file v2.0.25/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- v2.0.25/linux/drivers/net/loopback.c	Mon May 27 13:12:19 1996
+++ linux/drivers/net/loopback.c	Thu Nov 14 15:20:10 1996
@@ -20,6 +20,8 @@
  *              Michael Griffith:       Don't bother computing the checksums
  *                                      on packets received on the loopback
  *                                      interface.
+ *		Alexey Kuznetsov:	Potential hang under some extreme
+ *					cases removed.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -73,9 +75,9 @@
 	{
 	  	struct sk_buff *skb2=skb;
 	  	skb=skb_clone(skb, GFP_ATOMIC);		/* Clone the buffer */
-	  	if(skb==NULL)
-	  		return 1;
 	  	dev_kfree_skb(skb2, FREE_WRITE);
+	  	if(skb==NULL)
+	  		return 0;
   		unlock=0;
 	}
 	else if(skb->sk)
diff -u --recursive --new-file v2.0.25/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.0.25/linux/drivers/net/tulip.c	Wed Nov 13 11:26:22 1996
+++ linux/drivers/net/tulip.c	Thu Nov 21 10:58:06 1996
@@ -17,7 +17,8 @@
 static char *version =
 "tulip.c:v0.10 8/11/95 becker@cesdis.gsfc.nasa.gov\n"
 "        +0.72 4/17/96 "
-"http://www.dsl.tutics.tut.ac.jp/~linux/tulip\n";
+"http://www.dsl.tutics.tut.ac.jp/~linux/tulip\n"
+"        +0.01 10/24/96 mjacob@feral.com (2.1.7)\n";
 
 /* A few user-configurable values. */
 
@@ -334,6 +335,7 @@
 	int setup_frame[48];	/* Pseudo-Tx frame to init address table. */
 	void (*port_select)(struct device *dev);
 	int (*port_fail)(struct device *dev);
+	struct device *next_module;
 	char *signature;
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
@@ -367,7 +369,6 @@
 static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int tulip_close(struct device *dev);
 static struct enet_statistics *tulip_get_stats(struct device *dev);
-static struct device *tulip_alloc(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 #define	generic21140_fail	NULL
@@ -379,6 +380,11 @@
 static int generic21040_fail(struct device *dev);
 static int generic21041_fail(struct device *dev);
 
+#ifdef MODULE
+/* A list of all installed Tulip devices, for removing the driver module. */
+static struct device *root_tulip_dev = NULL;
+#endif
+
 static struct {
 	void (*port_select)(struct device *dev);
 	int (*port_fail)(struct device *dev);
@@ -436,7 +442,6 @@
 
 #ifdef MODULE
 static int if_port=TULIP_AUTO_PORT;
-static size_t alloc_size;
 #ifdef TULIP_FULL_DUPLEX
 static int full_duplex=1;
 #else
@@ -997,7 +1002,8 @@
 			if (status & TRING_RxFIFO) lp->stats.rx_fifo_errors++;
 		} else {
 			/* Malloc up new buffer, compatible with net-2e. */
-			short pkt_len = lp->rx_ring[entry].status >> 16;
+			/* Omit the four octet CRC from the length. */
+			short pkt_len = (lp->rx_ring[entry].status >> 16) - 4;
 			struct sk_buff *skb;
 
 			skb = dev_alloc_skb(pkt_len + 2);
@@ -1132,6 +1138,7 @@
 			*setup_frm++ = eaddrs[2];
 		} while (++i < 15);
 
+#ifndef	__alpha__
 		/* Now add this frame to the Tx list. */
 		{
 			unsigned long flags;
@@ -1152,46 +1159,8 @@
 			/* Trigger an immediate transmit demand. */
 			tio_write(TPOLL_TRIGGER, CSR1);
 		}
-	}
-}
-
-static struct device *tulip_alloc(struct device *dev)
-{
-	struct tulip_private *tp;
-	char *buff;
-#ifndef	MODULE
-	size_t alloc_size;
 #endif
-	if (!dev || dev->priv) {
-		struct device *olddev = dev;
-
-		alloc_size = sizeof(struct device)
-			+ sizeof(struct tulip_private)
-			+ ETHNAMSIZ;
-		alloc_size = ROUND_UP(alloc_size, 8);
-
-		buff = (char *)kmalloc(alloc_size, GFP_KERNEL);
-		dev = (struct device *)buff;
-		if (dev == NULL) {
-			printk("tulip_alloc: kmalloc failed.\n");
-			return(NULL);
-		}
-		tp = (struct tulip_private *)(buff + sizeof(struct device));
-		memset(buff, 0, alloc_size);
-		dev->priv = (void *)tp;
-		dev->name = (char *)(buff + sizeof(struct device)
-							 + sizeof(struct tulip_private));
-		if (olddev) {
-			dev->next = olddev->next;
-			olddev->next = dev;
-		}
-	} else {
-		alloc_size = ROUND_UP(sizeof(struct tulip_private), 8);
-		tp = (struct tulip_private *)kmalloc(alloc_size, GFP_KERNEL);
-		memset((void *)tp, 0, alloc_size);
-		dev->priv = (void *)tp;
 	}
-	return(dev);
 }
 
 int
@@ -1200,6 +1169,7 @@
 {
 	/* See note below on the Znyx 315 etherarray. */
 	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+	static int last_irq;
 	char detect_mesg[80], *mesgp=detect_mesg;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int i;
@@ -1269,11 +1239,13 @@
 		for (i = 0; i < ETH_ALEN - 1; i++)
 			dev->dev_addr[i] = last_phys_addr[i];
 		dev->dev_addr[i] = last_phys_addr[i] + 1;
+		irq = last_irq;
 	}
 	for (i = 0; i < ETH_ALEN - 1; i++)
 		mesgp += sprintf(mesgp, "%2.2x:", dev->dev_addr[i]);
 	mesgp += sprintf(mesgp, "%2.2x, IRQ %d\n",
 					 last_phys_addr[i] = dev->dev_addr[i], irq);
+	last_irq = irq;
 
 	/* copy ethernet address */
 	if (card_type(tp, device_id,
@@ -1295,21 +1267,20 @@
 	dev->set_multicast_list = &set_multicast_list;
 
 #ifdef	MODULE
-    ether_setup(dev);
 	if (if_port == TULIP_AUTO_PORT)
 		if_port = TULIP_PORT;
 	else
 		tp->port_fix = 1;
 	dev->if_port = if_port;
 	tp->full_duplex = full_duplex;
+	tp->next_module = root_tulip_dev;
+	root_tulip_dev = dev;
 #else
 #ifdef TULIP_FULL_DUPLEX
 	tp->full_duplex = 1;
 #endif
-    init_etherdev(dev, 0);
 	dev->if_port = TULIP_PORT;
 #endif
-
 #ifdef	TULIP_FIX_PORT
 	tp->port_fix = 1;
 #endif
@@ -1340,14 +1311,13 @@
 
     if (!pcibios_present()) return(-ENODEV);
 
-	for (pci_index = 0; pci_index < 8; pci_index++) {
+	for (pci_index = 0; pci_index < 0xff; pci_index++) {
 		/* Search for the PCI_DEVICE_ID_DEV_TULIP* chips */
-		for (cno = 0; pci_chips[cno] != PCI_DEVICE_ID_NONE; cno ++)
+		for (cno = 0; pci_chips[cno] != PCI_DEVICE_ID_NONE; cno++) {
 			if (pcibios_find_device(PCI_VENDOR_ID_DEC,
 									pci_chips[cno],
 									pci_index, &pci_bus,
 									&pci_device_fn) == 0) {
-				struct device *dp;
 
 				/* get IO address */
 				pcibios_read_config_dword(pci_bus, pci_device_fn,
@@ -1355,19 +1325,14 @@
 										  &pci_ioaddr);
 				/* Remove I/O space marker in bit 0. */
 				pci_ioaddr &= ~3;
-				for (dp = tulip_head; dp != NULL; dp = dp->next)
-					if (dp->base_addr == pci_ioaddr) break;
-				if (dp) continue;
 				/* get IRQ */
-				pcibios_read_config_byte(pci_bus, pci_device_fn,
-										 PCI_INTERRUPT_LINE, &pci_irq);
-#ifdef	MODULE
-				/* compare requested IRQ/IO address */
-				if (dev && dev->base_addr &&
-					dev->base_addr != pci_ioaddr) continue;
-#else
-				if ((dev = tulip_alloc(dev)) == NULL) break;
-#endif
+				pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq);
+				dev = init_etherdev(NULL, 
+					ROUND_UP(sizeof(struct device) +
+						sizeof (struct tulip_private) +
+						ETHNAMSIZ, 8));
+
+				if (dev == NULL) break;
 				if (!tulip_head) {
 					printk(version);
 					tulip_head = dev;
@@ -1394,56 +1359,48 @@
 											  PCI_LATENCY_TIMER, 100);
 				}
 				if (tulip_hwinit(dev, pci_ioaddr, pci_irq,
-								 pci_chips[cno]) < 0) continue;
-				num ++;
-#ifdef	MODULE
-				return(0);
-#endif
+								 pci_chips[cno]) < 0) {
+					continue;
+				}
+				num++;
 #ifdef	TULIP_MAX_CARDS
 				if (num >= TULIP_MAX_CARDS) return(0);
 #endif
 		}
 	}
+	}
 	return(num > 0 ? 0: -ENODEV);
 }
 
 #ifdef MODULE
-#ifdef __alpha__
-#if 1
-static int io = 0xb000;
-#else
-static int io = 0x10400;
-#endif
-#else
-static int io = 0xfc80;
-#endif
 
-static struct device *mod_dev;
+/* The parameters that may be passed in... */
+/* This driver does nothing with options yet.  It will later be used to
+   pass the full-duplex flag, etc. */
+int debug = -1;
 
-int init_module(void)
+int
+init_module(void)
 {
-	if ((mod_dev = tulip_alloc(0)) == NULL) return(-EIO);
-
-	mod_dev->base_addr = io;
-	mod_dev->irq = 0;
-	mod_dev->init = &tulip_probe;
-
-	if (register_netdev(mod_dev)) {
-		printk("tulip: register_netdev() returned non-zero.\n");
-		kfree_s(mod_dev, alloc_size);
-		return -EIO;
-	}
-	return(0);
+	root_tulip_dev = NULL;
+	return tulip_probe(NULL);
 }
 
 void
 cleanup_module(void)
 {
-	release_region(mod_dev->base_addr, TULIP_TOTAL_SIZE);
-	unregister_netdev(mod_dev);
-	kfree_s(mod_dev, alloc_size);
-}
+	struct device *next_dev;
 
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_tulip_dev) {
+		next_dev =
+		   ((struct tulip_private *) root_tulip_dev->priv)->next_module;
+		unregister_netdev(root_tulip_dev);
+		release_region(root_tulip_dev->base_addr, TULIP_TOTAL_SIZE);
+		kfree(root_tulip_dev);
+		root_tulip_dev = next_dev;
+	}
+}
 #endif /* MODULE */
 
 
diff -u --recursive --new-file v2.0.25/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.0.25/linux/drivers/pci/pci.c	Wed Nov 13 11:26:22 1996
+++ linux/drivers/pci/pci.c	Tue Nov 19 15:50:07 1996
@@ -69,8 +69,8 @@
 	DEVICE( DEC,		DEC_TULIP_FAST,	"DC21140"),
 	DEVICE( DEC,		DEC_FDDI,	"DEFPA"),
 	DEVICE( DEC,		DEC_TULIP_PLUS,	"DC21041"),
-	DEVICE( DEC,		DEC_21052_AB,	"DC21052-AB"),
-	DEVICE( DEC,		DEC_21152_AA,	"DC21152-AA"),
+	DEVICE( DEC,		DEC_21052,	"DC21052"),
+	DEVICE( DEC,		DEC_21152,	"DC21152"),
 	DEVICE( CIRRUS,		CIRRUS_5430,	"GD 5430"),
 	DEVICE( CIRRUS,		CIRRUS_5434_4,	"GD 5434"),
 	DEVICE( CIRRUS,		CIRRUS_5434_8,	"GD 5434"),
@@ -87,7 +87,7 @@
 	DEVICE( TRIDENT,	TRIDENT_9660,	"TG 9660"),
 	DEVICE( AI,		AI_M1435,	"M1435"),
 	DEVICE( MATROX,		MATROX_MGA_2,	"Atlas PX2085"),
-	DEVICE( MATROX,		MATROX_MIL     ,"Millenium"),
+	DEVICE( MATROX,		MATROX_MIL     ,"Millennium"),
 	DEVICE( MATROX,		MATROX_MGA_IMP,	"MGA Impression"),
 	DEVICE( CT,		CT_65545,	"65545"),
 	DEVICE( CT,		CT_65548,	"65548"),
@@ -210,7 +210,10 @@
 	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX"),
 	DEVICE( AVANCE,		AVANCE_2302,	"ALG-2302"),
 	DEVICE( S3,		S3_ViRGE,	"ViRGE"),
-	DEVICE( S3,		S3_811,		"Trio32/Trio64"),
+	DEVICE( S3,		S3_TRIO,	"Trio32/Trio64"),
+	DEVICE( S3,		S3_AURORA64VP,	"Aurora64V+"),
+	DEVICE( S3,		S3_TRIO64UVP,	"Trio64UV+"),
+	DEVICE( S3,		S3_ViRGE_VX,	"ViRGE/VX"),
 	DEVICE( S3,		S3_868,	"Vision 868"),
 	DEVICE( S3,		S3_928,		"Vision 928-P"),
 	DEVICE( S3,		S3_864_1,	"Vision 864-P"),
diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.0.25/linux/drivers/scsi/Config.in	Thu Oct 31 12:08:52 1996
+++ linux/drivers/scsi/Config.in	Tue Nov 19 16:21:06 1996
@@ -26,7 +26,7 @@
 dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
 dep_tristate 'EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
 dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
-dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
+dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support' CONFIG_SCSI_EATA $CONFIG_SCSI
 dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
 dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
 if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.0.25/linux/drivers/scsi/advansys.c	Tue Oct  8 21:20:12 1996
+++ linux/drivers/scsi/advansys.c	Fri Nov 15 02:45:57 1996
@@ -1,4 +1,4 @@
-/* $Id: advansys.c,v 1.20 1996/09/26 00:47:54 bobf Exp bobf $ */
+/* $Id: advansys.c,v 1.29 1996/11/15 00:45:07 bobf Exp bobf $ */
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  * 
@@ -18,9 +18,10 @@
  */
 
 /*
- * The driver has been run with the v1.2.13, v1.3.57, and v2.0.21 kernels.
+ * The driver has been used in the following kernels:
+ *  v1.2.13, v1.3.57, v2.0.25, v2.1.9
  */
-#define ASC_VERSION "1.7"    /* AdvanSys Driver Version */
+#define ASC_VERSION "2.0"    /* AdvanSys Driver Version */
 
 /*
 
@@ -53,10 +54,10 @@
 
      Connectivity Products:
         ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1)
-        ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1)
-        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
+        ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1, 3)
+        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) (Footnote 4)
         ABP920 - Bus-Master PCI (16 CDB)
-        ABP930 - Bus-Master PCI (16 CDB)
+        ABP930 - Bus-Master PCI (16 CDB) (Footnote 5)
         ABP930U - Bus-Master PCI Ultra (16 CDB)
         ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
         ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
@@ -79,9 +80,11 @@
        1. This board has been shipped by HP with the 4020i CD-R drive.
           The board has no BIOS so it cannot control a boot device, but
           it can control any secondary SCSI device.
-   
        2. This board has been sold by Iomega as a Jaz Jet PCI adapter.
-  
+       3. This board has been sold by SIIG as the i540 SpeedMaster.
+       4. This board has been sold by SIIG as the i542 SpeedMaster.
+       5. This board has been sold by SIIG as the Fast SCSI Pro PCI.
+
   B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.2.13. For versions that follow v1.2.13.
@@ -441,9 +444,46 @@
          5. Remove the request timeout issue form the driver issues list.
          6. Miscellaneous documentation additions and changes.
 
+     1.8 (10/4/96):
+         1. Make changes to handle the new v2.1.0 kernel memory mapping
+            in which a kernel virtual address may not be equivalent to its
+            bus or DMA memory address.
+         2. Change abort and reset request handling to make it yet even
+            more robust.
+         3. Try to mitigate request starvation by sending ordered requests
+            to heavily loaded, tag queuing enabled devices.
+         4. Maintain statistics on request response time.
+         5. Add request response time statistics and other information to
+            the adapter /proc file: /proc/scsi/advansys[0...].
+
+     1.9 (10/21/96):
+         1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
+            make use of mid-level SCSI driver device queue depth flow
+            control mechanism. This will eliminate aborts caused by a
+            device being unable to keep up with requests and eliminate
+            repeat busy or QUEUE FULL status returned by a device.
+         2. Incorporate miscellaneous Asc Library bug fixes.
+         3. To allow the driver to work in kernels with broken module
+            support set 'cmd_per_lun' if the driver is compile as a
+            module. This change affects kernels v1.3.89 to present.
+         4. Remove PCI BIOS address from the driver banner. The PCI BIOS
+            is relocated by the motherboard BIOS and its new address can
+            not be determined by the driver.
+         5. Add mid-level SCSI queue depth information to the adapter
+            /proc file: /proc/scsi/advansys[0...].
+
+     2.0 (11/14/96):
+         1. Change allocation of global structures used for device
+            initialization to guarantee they are in DMA-able memory.
+            Previously when the driver was loaded as a module these
+            structures might not have been in DMA-able memory, causing
+            device initialization to fail.
+
   I. Known Problems or Issues
 
-         None
+         1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around
+            the queue depth flow control code when mid-level SCSI changes
+            are included in Linux.
 
   J. Credits
 
@@ -540,7 +580,7 @@
 
 #define ASC_LIB_VERSION_MAJOR  1
 #define ASC_LIB_VERSION_MINOR  22
-#define ASC_LIB_SERIAL_NUMBER  89
+#define ASC_LIB_SERIAL_NUMBER  91
 
 typedef unsigned char uchar;
 
@@ -615,7 +655,6 @@
 #define ASC_PCI_ID2FUNC( id )   (((id) >> 8) & 0x7)
 #define ASC_PCI_MKID( bus, dev, func ) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
 
-#define  Asc_DvcLib_Status   int
 #define  ASC_DVCLIB_CALL_DONE     (1)
 #define  ASC_DVCLIB_CALL_FAILED   (0)
 #define  ASC_DVCLIB_CALL_ERROR    (-1)
@@ -823,7 +862,7 @@
 #define SCSI_SENKEY_MEDIUM_ERR    0x03
 #define SCSI_SENKEY_HW_ERR        0x04
 #define SCSI_SENKEY_ILLEGAL       0x05
-#define SCSI_SENKEY_ATTENSION     0x06
+#define SCSI_SENKEY_ATTENTION     0x06
 #define SCSI_SENKEY_PROTECTED     0x07
 #define SCSI_SENKEY_BLANK         0x08
 #define SCSI_SENKEY_V_UNIQUE      0x09
@@ -1349,7 +1388,6 @@
 #define ASC_IERR_SCAM                 0x0800
 #define ASC_IERR_SET_SDTR             0x1000
 #define ASC_IERR_RW_LRAM              0x8000
-#define ASC_DVCLIB_STATUS             0x00
 #define ASC_DEF_IRQ_NO  10
 #define ASC_MAX_IRQ_NO  15
 #define ASC_MIN_IRQ_NO  10
@@ -2108,7 +2146,7 @@
 #define ASC_INFO_SIZE			128			/* advansys_info() line size */
 
 /* /proc/scsi/advansys/[0...] related definitions */
-#define ASC_PRTBUF_SIZE			1024
+#define ASC_PRTBUF_SIZE			2048
 #define ASC_PRTLINE_SIZE		160
 
 #define ASC_PRT_NEXT() \
@@ -2137,15 +2175,52 @@
 #define DRIVER_BYTE(byte)	((byte) << 24)
 
 /*
- * REQ and REQP are the generic name for a SCSI request block and pointer.
- * REQPTID(reqp) returns reqp's target id.
- * REQPNEXT(reqp) returns reqp's next pointer.
- * REQPNEXTP(reqp) returns a pointer to reqp's next pointer.
+ * The following definitions and macros are OS independent interfaces to
+ * the queue functions:
+ *  REQ - SCSI request structure
+ *  REQP - pointer to SCSI request structure
+ *  REQPTID(reqp) - reqp's target id
+ *  REQPNEXT(reqp) - reqp's next pointer
+ *  REQPNEXTP(reqp) - pointer to reqp's next pointer
+ *  REQPTIME(reqp) - reqp's time stamp value
+ *  REQTIMESTAMP() - system time stamp value
  */
 typedef Scsi_Cmnd			REQ, *REQP;
 #define REQPNEXT(reqp)		((REQP) ((reqp)->host_scribble))
 #define REQPNEXTP(reqp)		((REQP *) &((reqp)->host_scribble))
 #define REQPTID(reqp)		((reqp)->target)
+#define REQPTIME(reqp)		((reqp)->SCp.this_residual)
+#define REQTIMESTAMP()		(jiffies)
+
+#define REQTIMESTAT(function, ascq, reqp, tid) \
+{ \
+	/*
+	 * If the request time stamp is less than the system time stamp, then \
+	 * maybe the system time stamp wrapped. Set the request time to zero.\
+	 */ \
+	if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
+		REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
+	} else { \
+		/* Indicate an error occurred with the assertion. */ \
+		ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
+		REQPTIME(reqp) = 0; \
+	} \
+	/* Handle first minimum time case without external initialization. */ \
+	if (((ascq)->q_tot_cnt[tid] == 1) ||  \
+		(REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
+			(ascq)->q_min_tim[tid] = REQPTIME(reqp); \
+			ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
+				(function), (tid), (ascq)->q_min_tim[tid]); \
+		} \
+	if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
+		(ascq)->q_max_tim[tid] = REQPTIME(reqp); \
+		ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
+			(function), tid, (ascq)->q_max_tim[tid]); \
+	} \
+	(ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
+	/* Reset the time stamp field. */ \
+	REQPTIME(reqp) = 0; \
+}
 
 /* asc_enqueue() flags */
 #define ASC_FRONT		1
@@ -2243,7 +2318,11 @@
 #endif /* ADVANSYS_STATS */
 
 #define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
-#define ASC_TENTHS(num, den) ((((num) * 10)/(den)) - (10 * ((num)/(den))))
+
+/* If the result wraps when calculating tenths, return 0. */
+#define ASC_TENTHS(num, den) \
+	(((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
+	0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
 
 /*
  * Display a message to the console.
@@ -2287,8 +2366,7 @@
 #define	ASC_DBG3(lvl, s, a1, a2, a3)
 #define	ASC_DBG4(lvl, s, a1, a2, a3, a4)
 #define	ASC_DBG_PRT_SCSI_HOST(lvl, s)
-#define	ASC_DBG_PRT_DVC_VAR(lvl, v)
-#define	ASC_DBG_PRT_DVC_CFG(lvl, c)
+#define	ASC_DBG_PRT_SCSI_CMND(lvl, s)
 #define	ASC_DBG_PRT_SCSI_Q(lvl, scsiqp)
 #define	ASC_DBG_PRT_QDONE_INFO(lvl, qdone)
 #define	ASC_DBG_PRT_HEX(lvl, name, start, length)
@@ -2348,17 +2426,10 @@
 		} \
 	}
 
-#define	ASC_DBG_PRT_DVC_VAR(lvl, v) \
+#define	ASC_DBG_PRT_SCSI_CMND(lvl, s) \
 	{ \
 		if (asc_dbglvl >= (lvl)) { \
-			asc_prt_dvc_var(v); \
-		} \
-	}
-
-#define	ASC_DBG_PRT_DVC_CFG(lvl, c) \
-	{ \
-		if (asc_dbglvl >= (lvl)) { \
-			asc_prt_dvc_cfg(c); \
+			asc_prt_scsi_cmnd(s); \
 		} \
 	}
 
@@ -2431,9 +2502,6 @@
 	ulong 	sg_cnt;			/* # scatter-gather I/O requests received */
 	ulong 	sg_elem;		/* # scatter-gather elements */
 	ulong 	sg_xfer;		/* # scatter-gather transfer 512-bytes */
-	/* Device SCSI Command Queuing Statistics */
-	ASC_SCSI_BIT_ID_TYPE queue_full;
-	ushort	queue_full_cnt[ASC_MAX_TID+1];
 };
 #endif /* ADVANSYS_STATS */
 
@@ -2447,6 +2515,10 @@
 #ifdef ADVANSYS_STATS
 	short					q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */
 	short					q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */
+	ulong					q_tot_cnt[ASC_MAX_TID+1]; /* total enqueue count */
+	ulong					q_tot_tim[ASC_MAX_TID+1]; /* total time queued */
+	ushort					q_max_tim[ASC_MAX_TID+1]; /* maximum time queued */
+	ushort					q_min_tim[ASC_MAX_TID+1]; /* minimum time queued */
 #endif /* ADVANSYS_STATS */
 } asc_queue_t;
 
@@ -2464,10 +2536,21 @@
 	ASC_DVC_CFG			 asc_dvc_cfg;		/* Device configuration */
 	asc_queue_t			 active;			/* Active command queue */
 	asc_queue_t			 waiting;		  	/* Waiting command queue */
+	asc_queue_t			 done;				/* Done command queue */
 	ASC_SCSI_BIT_ID_TYPE init_tidmask;		/* Target initialized mask */
+	/* The following three structures must be in DMA-able memory. */
+	ASC_SCSI_REQ_Q		 scsireqq;
+	ASC_CAP_INFO		 cap_info;
+	ASC_SCSI_INQUIRY	 inquiry;
+	Scsi_Device			 *device[ASC_MAX_TID+1]; /* Mid-Level Scsi Device */
+	ushort				 reqcnt[ASC_MAX_TID+1]; /* Starvation request count */
+#if ASC_QUEUE_FLOW_CONTROL
+	ushort				 nerrcnt[ASC_MAX_TID+1]; /* No error request count */
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+	ASC_SCSI_BIT_ID_TYPE queue_full;		/* Queue full mask */
+	ushort	queue_full_cnt[ASC_MAX_TID+1];	/* Queue full count */
 	ASCEEP_CONFIG		 eep_config;		/* EEPROM configuration */
-	asc_queue_t			 scsi_done_q;		/* Completion command queue */
-	ulong				 reset_jiffies;		/* Saved time of last reset */
+	ulong				 last_reset;		/* Saved time of last reset */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 	/* /proc/scsi/advansys/[0...] */
 	char				 *prtbuf;			/* Statistics Print Buffer */
@@ -2552,13 +2635,6 @@
 STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
 
 /*
- * Global structures used for device initialization.
- */
-STATIC ASC_SCSI_REQ_Q	 asc_scsireqq = { { 0 } };
-STATIC ASC_CAP_INFO		 asc_cap_info = { 0 };
-STATIC ASC_SCSI_INQUIRY	 asc_inquiry = { { 0 } };
-
-/*
  * Global structures required to issue a command.
  */
 STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } };
@@ -2646,6 +2722,7 @@
 #endif /* ADVANSYS_STATS */
 #ifdef ADVANSYS_DEBUG
 STATIC void 		asc_prt_scsi_host(struct Scsi_Host *);
+STATIC void 		asc_prt_scsi_cmnd(Scsi_Cmnd *);
 STATIC void 		asc_prt_dvc_cfg(ASC_DVC_CFG *);
 STATIC void 		asc_prt_dvc_var(ASC_DVC_VAR *);
 STATIC void 		asc_prt_scsi_q(ASC_SCSI_Q *);
@@ -3059,6 +3136,7 @@
 			memset(boardp, 0, sizeof(asc_board_t));
 			boardp->id = asc_board_count - 1;
 			asc_dvc_varp = &boardp->asc_dvc_var;
+			asc_dvc_varp->drv_ptr = (ulong) boardp;
 			asc_dvc_varp->cfg = &boardp->asc_dvc_cfg;
 			asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
 			asc_dvc_varp->iop_base = iop;
@@ -3114,9 +3192,9 @@
 			/*
 			 * Get the board configuration.
 			 *
-			 * AscInitGetConfig() may change the board's bus_type value.
-			 * The asc_bus[bus] value should no longer be used. If the
-			 * bus_type field must be referenced only use the bit-wise
+			 * NOTE: AscInitGetConfig() may change the board's bus_type
+			 * value. The asc_bus[bus] value should no longer be used. If
+			 * the bus_type field must be referenced only use the bit-wise
 			 * AND operator "&".
 			 */
 			ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
@@ -3247,7 +3325,7 @@
 			 */
 
 			/* AscInitSetConfig() will set the IRQ for non-PCI boards. */
-			if (asc_dvc_varp->bus_type != ASC_IS_PCI) {
+			if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
 				shp->irq = asc_dvc_varp->irq_no;
 			}
 
@@ -3286,16 +3364,33 @@
 			 */
 			shp->select_queue_depths = advansys_select_queue_depths;
 
-			shp->cmd_per_lun = 0; /* 'cmd_per_lun' is no longer used. */
+#ifdef MODULE
+			/*
+			 * Following v1.3.89, 'cmd_per_lun' is no longer needed
+			 * and should be set to zero. But because of a bug introduced
+			 * in v1.3.89 if the driver is compiled as a module and
+			 * 'cmd_per_lun' is zero, the Mid-Level SCSI function
+			 * 'allocate_device' will panic. To allow the driver to
+			 * work as a module in these kernels set 'cmd_per_lun' to 1.
+			 */
+			shp->cmd_per_lun = 1;
+#else /* MODULE */
+			shp->cmd_per_lun = 0;
+#endif /* MODULE */
 #endif /* version >= v1.3.89 */
 
 			/*
-			 * Maximum number of scatter-gather elements adapter can handle.
-			 *
-			 * Set a conservative 'sg_tablesize' value to prevent memory
-			 * allocation failures.
+			 * Set the maximum number of scatter-gather elements adapter
+			 * can handle.
 			 */
+
 #ifdef MODULE
+			/*
+			 * If the driver is compiled as a module, set a conservative
+			 * 'sg_tablesize' value to prevent memory allocation failures.
+			 * Memory allocation errors are more likely to occur at module
+			 * load time, then at driver initialization time.
+			 */
 			shp->sg_tablesize = 8;
 #else /* MODULE */
 			/*
@@ -3474,25 +3569,28 @@
 			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
 			(unsigned) shp->base, shp->io_port,
 			shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel);
+	} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+		if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+			== ASC_IS_PCI_ULTRA) {
+			busname = "PCI Ultra";
+		} else {
+			busname = "PCI";
+		}
+		sprintf(info,
+			"AdvanSys SCSI %s: %s %u CDB: IO %X-%X, IRQ %u",
+			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
+			shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq);
 	} else {
 		if (asc_dvc_varp->bus_type & ASC_IS_VL) {
 			busname = "VL";
 		} else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
 			busname = "EISA";
-		} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-			if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
-				== ASC_IS_PCI_ULTRA) {
-				busname = "PCI Ultra";
-			} else {
-				busname = "PCI";
-			}
 		} else {
 			busname = "?";
 			ASC_PRINT2(
 "advansys_info: board %d: unknown bus type %d\n",
 				boardp->id, asc_dvc_varp->bus_type);
 		}
-		/* No DMA channel for non-ISA busses. */
 		sprintf(info,
 			"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u",
 			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
@@ -3512,7 +3610,9 @@
  * Polled-I/O. Apparently host drivers shouldn't return until
  * command is finished.
  *
- * XXX - Can host drivers block here instead of spinning on command status?
+ * Note: This is an old interface that is no longer used by the SCSI
+ * mid-level driver. The new interface, advansys_queuecommand(),
+ * currently handles all requests.
  */
 int
 advansys_command(Scsi_Cmnd *scp)
@@ -3521,6 +3621,10 @@
 	ASC_STATS(scp->host, command);
 	scp->SCp.Status = 0; /* Set to a known state */
 	advansys_queuecommand(scp, advansys_command_done);
+	/*
+	 * XXX - Can host drivers block here instead of spinning on
+	 * command status?
+	 */
 	while (scp->SCp.Status == 0) {
 		continue;
 	}
@@ -3571,11 +3675,11 @@
 		}
 
 		/*
-		 * Add blocked requests to the board's 'scsi_done_q'. The queued
+		 * Add blocked requests to the board's 'done' queue. The queued
 		 * requests will be completed at the end of the abort or reset
 		 * handling.
 		 */
-		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+		asc_enqueue(&boardp->done, scp, ASC_BACK);
 		restore_flags(flags);
 		return 0;
 	}
@@ -3601,7 +3705,7 @@
 	 * target waiting list.
 	 * 
 	 * If an error occurred, the request will have been placed on the
-	 * board's 'scsi_done_q' and must be completed before returning.
+	 * board's 'done' queue and must be completed before returning.
 	 */
 	scp->scsi_done = done;
 	switch (asc_execute_scsi_cmnd(scp)) {
@@ -3612,7 +3716,7 @@
 		break;
 	case ASC_ERROR:
 	default:
-		done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL);
+		done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
 		/* Interrupts could be enabled here. */
 		asc_scsi_done_list(done_scp);
 		break;
@@ -3634,42 +3738,63 @@
 	asc_board_t			*boardp;
 	ASC_DVC_VAR			*asc_dvc_varp;
 	int					flags;
-	int					status = ASC_FALSE;
-	int					abort_do_done = ASC_FALSE;
-	Scsi_Cmnd			*done_scp;
-	int					ret = ASC_ERROR;
-
-	ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
+	int					do_scsi_done;
+	int					scp_found;
+	Scsi_Cmnd			*done_scp = NULL;
+	int					ret;
 
 	/* Save current flags and disable interrupts. */
 	save_flags(flags);
 	cli();
 
+	ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
+
 #ifdef ADVANSYS_STATS
 	if (scp->host != NULL) {
 		ASC_STATS(scp->host, abort);
 	}	
 #endif /* ADVANSYS_STATS */
 
+#ifdef ADVVANSYS_DEBUG
+	do_scsi_done = ASC_ERROR;
+	scp_found = ASC_ERROR;
+	ret = ASC_ERROR;
+#endif /* ADVANSYS_DEBUG */
+
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 	if (scp->serial_number != scp->serial_number_at_timeout) {
+		ASC_PRINT1(
+"advansys_abort: timeout serial number changed for request %x\n",
+			(unsigned) scp);
+		do_scsi_done = ASC_FALSE;
+		scp_found = ASC_FALSE;
 		ret = SCSI_ABORT_NOT_RUNNING;
 	} else
 #endif /* version >= v1.3.89 */
 	if ((shp = scp->host) == NULL) {
 		scp->result = HOST_BYTE(DID_ERROR);
+		do_scsi_done = ASC_TRUE;
+		scp_found = ASC_FALSE;
 		ret = SCSI_ABORT_ERROR;
 	} else if ((boardp = ASC_BOARDP(shp))->flags & 
 				(ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
 		ASC_PRINT2(
 "advansys_abort: board %d: Nested host reset or abort, flags 0x%x\n",
 			boardp->id, boardp->flags);
+		do_scsi_done = ASC_TRUE;
+		if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
+		    (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
+			scp_found = ASC_TRUE;
+		} else {
+			scp_found = ASC_FALSE;
+		}
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_ABORT_ERROR;
 	} else {
 		/* Set abort flag to avoid nested reset or abort requests. */
 		boardp->flags |= ASC_HOST_IN_ABORT;
 
+		do_scsi_done = ASC_TRUE;
 		if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
 			/*
 		 	 * If asc_rmqueue() found the command on the waiting
@@ -3678,6 +3803,7 @@
 		 	 */
 			ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n",
 				(unsigned) scp);
+			scp_found = ASC_TRUE;
 			scp->result = HOST_BYTE(DID_ABORT);
 			ret = SCSI_ABORT_SUCCESS;
 		} else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) {
@@ -3693,7 +3819,7 @@
 			sti(); /* Enable interrupts for AscAbortSRB(). */
 			ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
 				(unsigned) scp);
-			switch (status = AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
+			switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
 			case ASC_TRUE:
 				/* asc_isr_callback() will be called */
 				ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
@@ -3713,20 +3839,23 @@
 			cli();
 
 			/*
-			 * If the abort failed, remove the request from the
-			 * active list and complete it.
+			 * The request will either still be on the active queue
+			 * or have been added to the board's done queue.
 			 */
-			if (status != ASC_TRUE) {
-				if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
-					scp->result = HOST_BYTE(DID_ABORT);
-					abort_do_done = ASC_TRUE;
-				}
+			if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
+				scp->result = HOST_BYTE(DID_ABORT);
+				scp_found = ASC_TRUE;
+			} else {
+				scp_found = asc_rmqueue(&boardp->done, scp);
+				ASC_ASSERT(scp_found == ASC_TRUE);
 			}
 
 		} else {
 			/*
 			 * The command was not found on the active or waiting queues.
 			 */
+			do_scsi_done = ASC_TRUE;
+			scp_found = ASC_FALSE;
 			ret = SCSI_ABORT_NOT_RUNNING;
 		}
 
@@ -3736,11 +3865,11 @@
 		/*
 		 * Because the ASC_HOST_IN_ABORT flag causes both
 		 * 'advansys_interrupt' and 'asc_isr_callback' to
-		 * queue requests to the board's 'scsi_done_q' and
+		 * queue requests to the board's 'done' queue and
 		 * prevents waiting commands from being executed,
 		 * these queued requests must be handled here.
 		 */
-		done_scp = asc_dequeue_list(&boardp->scsi_done_q, NULL, ASC_TID_ALL);
+		done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
 
 		/*
 		 * Start any waiting commands for the board.
@@ -3749,22 +3878,39 @@
 			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
 			asc_execute_queue(&boardp->waiting);
 		}
+	}
 
-		/* Interrupts could be enabled here. */
+	/* Interrupts could be enabled here. */
 
-		/*
-		 * If needed, complete the aborted request.
-		 */
-		if (abort_do_done == ASC_TRUE) {
+	/*
+	 * Complete the request to be aborted, unless it has been
+	 * restarted as detected above, even if it was not found on
+	 * the device active or waiting queues.
+	 */
+	ASC_ASSERT(do_scsi_done != ASC_ERROR);
+	ASC_ASSERT(scp_found != ASC_ERROR);
+	if (do_scsi_done == ASC_TRUE) {
+		if (scp->scsi_done == NULL) {
+			ASC_PRINT1(
+"advansys_abort: aborted request scsi_done() is NULL, %x\n",
+				(unsigned) scp);
+		} else {
+			if (scp_found == ASC_FALSE) {
+				ASC_PRINT1(
+"advansys_abort: abort request not active or waiting, completing anyway %x\n",
+					(unsigned) scp);
+			}
 			ASC_STATS(scp->host, done);
 			scp->scsi_done(scp);
 		}
+	}
 
-		/*
-		 * It is possible for the request done function to re-enable
-		 * interrupts without confusing the driver. But here interrupts
-		 * aren't enabled until all requests have been completed.
-		 */
+	/*
+	 * It is possible for the request done function to re-enable
+	 * interrupts without confusing the driver. But here interrupts
+	 * aren't enabled until all requests have been completed.
+	 */
+	if (done_scp != NULL) {
 		asc_scsi_done_list(done_scp);
 	}
 
@@ -3795,18 +3941,18 @@
 	int					flags;
 	Scsi_Cmnd			*done_scp = NULL, *last_scp = NULL;
 	Scsi_Cmnd			*tscp, *new_last_scp;
-	int					scp_found = ASC_FALSE;
-	int 				device_reset = ASC_FALSE;
+	int					do_scsi_done;
+	int					scp_found;
 	int					status;
 	int					target;
-	int					ret = ASC_ERROR;
-
-	ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
+	int					ret;
 
 	/* Save current flags and disable interrupts. */
 	save_flags(flags);
 	cli();
 
+	ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
+
 #ifdef ADVANSYS_STATS
 	if (scp->host != NULL) {
 		ASC_STATS(scp->host, reset);
@@ -3815,21 +3961,35 @@
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 	if (scp->serial_number != scp->serial_number_at_timeout) {
+		ASC_PRINT1(
+"advansys_reset: timeout serial number changed for request %x\n",
+			(unsigned) scp);
+		do_scsi_done = ASC_FALSE;
+		scp_found = ASC_FALSE;
 		ret = SCSI_RESET_NOT_RUNNING;
 	} else
 #endif /* version >= v1.3.89 */
 	if ((shp = scp->host) == NULL) {
 		scp->result = HOST_BYTE(DID_ERROR);
+		do_scsi_done = ASC_TRUE;
+		scp_found = ASC_FALSE;
 		ret = SCSI_RESET_ERROR;
 	} else if ((boardp = ASC_BOARDP(shp))->flags & 
 				(ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
 		ASC_PRINT2(
 "advansys_reset: board %d: Nested host reset or abort, flags 0x%x\n",
 			boardp->id, boardp->flags);
+		do_scsi_done = ASC_TRUE;
+		if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
+		    (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
+			scp_found = ASC_TRUE;
+		} else {
+			scp_found = ASC_FALSE;
+		}
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_RESET_ERROR;
-	} else if (jiffies >= boardp->reset_jiffies &&
-			   jiffies < (boardp->reset_jiffies + (10 * HZ))) {
+	} else if (jiffies >= boardp->last_reset &&
+			   jiffies < (boardp->last_reset + (10 * HZ))) {
 		/*
 		 * Don't allow a reset to be attempted within 10 seconds
 		 * of the last reset.
@@ -3840,15 +4000,27 @@
 		 */
 		ASC_DBG(1,
 			"advansys_reset: reset within 10 sec of last reset ignored\n");
+		do_scsi_done = ASC_TRUE;
+		if ((asc_rmqueue(&boardp->active, scp) == ASC_TRUE) ||
+		    (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE)) {
+			scp_found = ASC_TRUE;
+		} else {
+			scp_found = ASC_FALSE;
+		}
 		scp->result = HOST_BYTE(DID_ERROR);
 		ret = SCSI_RESET_ERROR;
 	} else {
+		int device_reset = ASC_FALSE;
+
+		do_scsi_done = ASC_TRUE;
+
 		/* Set reset flag to avoid nested reset or abort requests. */
 		boardp->flags |= ASC_HOST_IN_RESET;
 
 		/*
-	 	 * If the request is on the target waiting or active queue,
-		 * note that it was found and remove it from its queue.
+	 	 * If the request is on the target waiting or active queue
+		 * or the board done queue, then remove it and note that it
+		 * was found.
 		 */
 		if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) {
 			ASC_DBG(1, "advansys_reset: active scp_found = TRUE\n");
@@ -3856,6 +4028,10 @@
 		} else if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
 			ASC_DBG(1, "advansys_reset: waiting scp_found = TRUE\n");
 			scp_found = ASC_TRUE;
+		} else if (asc_rmqueue(&boardp->done, scp) == ASC_TRUE) {
+			scp_found = ASC_TRUE;
+		} else {
+			scp_found = ASC_FALSE;
 		}
 
 		/*
@@ -3939,11 +4115,11 @@
 		/*
 		 * Because the ASC_HOST_IN_RESET flag causes both
 		 * 'advansys_interrupt' and 'asc_isr_callback' to
-		 * queue requests to the board's 'scsi_done_q' and
+		 * queue requests to the board's 'done' queue and
 		 * prevents waiting commands from being executed,
 		 * these queued requests must be handled here.
 		 */
-		done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp,
+		done_scp = asc_dequeue_list(&boardp->done, &last_scp,
 									ASC_TID_ALL);
 
 		/*
@@ -4006,7 +4182,7 @@
 		}
 
 		/* Save the time of the most recently completed reset. */
-		boardp->reset_jiffies = jiffies;
+		boardp->last_reset = jiffies;
 
 		/* Clear reset flag. */
 		boardp->flags &= ~ASC_HOST_IN_RESET;
@@ -4018,34 +4194,35 @@
 			ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
 			asc_execute_queue(&boardp->waiting);
 		}
+		ret = SCSI_RESET_SUCCESS;
+	}
 
-		/* Interrupts could be enabled here. */
+	/* Interrupts could be enabled here. */
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-		/*
-		 * If the command was found on the active or waiting request
-		 * queues or if the the SCSI_RESET_SYNCHRONOUS flag is set,
-		 * then done the command now.
-		 */
-		if (scp_found == ASC_TRUE || (reset_flags & SCSI_RESET_SYNCHRONOUS)) {
-			scp->result = HOST_BYTE(DID_RESET);
-			ASC_STATS(scp->host, done);
-			scp->scsi_done(scp);
-		}
-#else /* version >= v1.3.89 */
-		if (scp_found == ASC_TRUE) {
-			scp->result = HOST_BYTE(DID_RESET);
+	ASC_ASSERT(do_scsi_done != ASC_ERROR);
+	ASC_ASSERT(scp_found != ASC_ERROR);
+	if (do_scsi_done == ASC_TRUE) {
+		if (scp->scsi_done == NULL) {
+			ASC_PRINT1(
+"advansys_reset: reset request scsi_done() is NULL, %x\n",
+				(unsigned) scp);
+		} else {
+			if (scp_found == ASC_FALSE) {
+				ASC_PRINT1(
+"advansys_reset: reset request not active or waiting, completing anyway %x\n",
+					(unsigned) scp);
+			}
 			ASC_STATS(scp->host, done);
 			scp->scsi_done(scp);
 		}
-#endif /* version >= v1.3.89 */
-		ret = SCSI_RESET_SUCCESS;
+	}
 
-		/*
-		 * It is possible for the request done function to re-enable
-		 * interrupts without confusing the driver. But here interrupts
-		 * aren't enabled until requests have been completed.
-		 */
+	/*
+	 * It is possible for the request done function to re-enable
+	 * interrupts without confusing the driver. But here interrupts
+	 * aren't enabled until requests have been completed.
+	 */
+	if (done_scp != NULL) {
 		asc_scsi_done_list(done_scp);
 	}
 
@@ -4239,11 +4416,11 @@
 			 * Add to the list of requests that must be completed.
 			 */
 			if (done_scp == NULL) {
-				done_scp = asc_dequeue_list(&boardp->scsi_done_q, &last_scp,
+				done_scp = asc_dequeue_list(&boardp->done, &last_scp,
 					ASC_TID_ALL);
 			} else {
 				ASC_ASSERT(last_scp != NULL);
-				REQPNEXT(last_scp) = asc_dequeue_list(&boardp->scsi_done_q,
+				REQPNEXT(last_scp) = asc_dequeue_list(&boardp->done,
 					&new_last_scp, ASC_TID_ALL);
 				if (new_last_scp != NULL) {
 					ASC_ASSERT(REQPNEXT(last_scp) != NULL);
@@ -4285,6 +4462,11 @@
 		if (device->host != shp) {
 			continue;
 		}
+		/*
+		 * Save a pointer to the device and set its initial/maximum
+		 * queue depth.
+		 */
+		boardp->device[device->id] = device;
 		device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id];
 		ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n",
 			(unsigned) shp, device->id, device->queue_depth);
@@ -4318,6 +4500,7 @@
 		tscp = REQPNEXT(scp);
 		REQPNEXT(scp) = NULL;
 		ASC_STATS(scp->host, done);
+		ASC_ASSERT(scp->scsi_done != NULL);
 		scp->scsi_done(scp);
 		scp = tscp;
 	}
@@ -4360,7 +4543,7 @@
  * 	host_scribble - used for pointer to another Scsi_Cmnd
  *
  * If this function returns ASC_NOERROR or ASC_ERROR the request
- * has been enqueued on the board's 'scsi_done_q' and must be
+ * has been enqueued on the board's 'done' queue and must be
  * completed by the caller.
  *
  * If ASC_BUSY is returned the request must be enqueued by the
@@ -4371,6 +4554,7 @@
 {
 	asc_board_t		*boardp;
 	ASC_DVC_VAR		*asc_dvc_varp;
+	Scsi_Device		*device;
 	int				ret;
 
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
@@ -4379,6 +4563,7 @@
 
 	boardp = ASC_BOARDP(scp->host);
 	asc_dvc_varp = &boardp->asc_dvc_var;
+	device = boardp->device[scp->target];
 
 	/*
 	 * If this is the first command, then initialize the device. If
@@ -4387,7 +4572,7 @@
 	if ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(scp->target)) == 0) {
 		if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) {
 			scp->result = HOST_BYTE(DID_BAD_TARGET);
-			asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
 			return ASC_ERROR;
 		}
 		boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target);
@@ -4412,9 +4597,30 @@
 	asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
 	asc_scsi_q.q1.target_lun = scp->lun;
 	asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 	asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0];
+#else /* version >= v2.0.0 */
+	asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]);
+#endif /* version >= v2.0.0 */
 	asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
-	asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+
+	/*
+	 * If there are any outstanding requests for the current target,
+	 * then every 255th request send an ORDERED request. This heuristic
+	 * tries to retain the benefit of request sorting while preventing
+	 * request starvation. 255 is the max number of tags or pending commands
+	 * a device may have outstanding.
+	 *
+	 * The request count is incremented below for every successfully
+	 * started request.
+	 * 
+	 */
+	if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 0) &&
+	    (boardp->reqcnt[scp->target] % 255) == 0) {
+		asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED;
+	} else {
+		asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+	}
 
 	/*
 	 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
@@ -4425,8 +4631,11 @@
 		 * CDB request of single contiguous buffer.
 		 */
 		ASC_STATS(scp->host, cont_cnt);
- 		/* request_buffer is already a real address. */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 		asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer;
+#else /* version >= v2.0.0 */
+		asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer);
+#endif /* version >= v2.0.0 */
 		asc_scsi_q.q1.data_cnt = scp->request_bufflen;
 		ASC_STATS_ADD(scp->host, cont_xfer,
 					  ASC_CEILING(scp->request_bufflen, 512));
@@ -4444,7 +4653,7 @@
 "asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n",
 				boardp->id, scp->use_sg, scp->host->sg_tablesize);
 			scp->result = HOST_BYTE(DID_ERROR);
-			asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
 			return ASC_ERROR;
 		}
 
@@ -4468,7 +4677,11 @@
 		 */
 		slp = (struct scatterlist *) scp->request_buffer;
 		for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 			asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address;
+#else /* version >= v2.0.0 */
+			asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address);
+#endif /* version >= v2.0.0 */
 			asc_sg_head.sg_list[sgcnt].bytes = slp->length;
 			ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 		}
@@ -4484,28 +4697,71 @@
 	switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
 	case ASC_NOERROR:
 		ASC_STATS(scp->host, asc_noerror);
+		/*
+		 * Increment monotonically increasing per device successful
+		 * request counter. Wrapping doesn't matter.
+		 */
+		boardp->reqcnt[scp->target]++;
+
+#if ASC_QUEUE_FLOW_CONTROL
+		/*
+		 * Conditionally increment the device queue depth.
+		 *
+	 	 * If no error occurred and there have been 100 consecutive
+		 * successfull requests and the current queue depth is less
+		 * than the maximum queue depth, then increment the current
+		 * queue depth.
+		 */
+		if (boardp->nerrcnt[scp->target]++ > 100) {
+			boardp->nerrcnt[scp->target] = 0;
+			if ((device->queue_curr_depth < device->queue_depth) &&
+			    (!(boardp->queue_full & ASC_TIX_TO_TARGET_ID(scp->target)) ||
+				 (boardp->queue_full_cnt[scp->target] >
+				  device->queue_curr_depth))) {
+				device->queue_curr_depth++;
+			}
+		}
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		asc_enqueue(&boardp->active, scp, ASC_BACK);
 		ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
 		break;
 	case ASC_BUSY:
 		/* Caller must enqueue request and retry later. */
 		ASC_STATS(scp->host, asc_busy);
+#if ASC_QUEUE_FLOW_CONTROL
+		/*
+		 * Clear consecutive no error counter and if possbile decrement
+		 * queue depth.
+		 */
+		boardp->nerrcnt[scp->target] = 0;
+		if (device->queue_curr_depth > 1) {
+			device->queue_curr_depth--;
+		}
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		break;
 	case ASC_ERROR:
 		ASC_PRINT2(
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
 			boardp->id, asc_dvc_varp->err_code);
 		ASC_STATS(scp->host, asc_error);
+#if ASC_QUEUE_FLOW_CONTROL
+		/* Clear consecutive no error counter. */
+		boardp->nerrcnt[scp->target] = 0;
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		scp->result = HOST_BYTE(DID_ERROR);
-		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+		asc_enqueue(&boardp->done, scp, ASC_BACK);
 		break;
 	default:
 		ASC_PRINT2(
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
 			boardp->id, asc_dvc_varp->err_code);
 		ASC_STATS(scp->host, asc_unknown);
+#if ASC_QUEUE_FLOW_CONTROL
+		/* Clear consecutive no error counter. */
+		boardp->nerrcnt[scp->target] = 0;
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		scp->result = HOST_BYTE(DID_ERROR);
-		asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+		asc_enqueue(&boardp->done, scp, ASC_BACK);
 		break;
 	}
 
@@ -4645,7 +4901,7 @@
 	 * The done function for the command will be called from
 	 * advansys_interrupt().
 	 */
-	asc_enqueue(&boardp->scsi_done_q, scp, ASC_BACK);
+	asc_enqueue(&boardp->done, scp, ASC_BACK);
 
 	return;
 }
@@ -4659,6 +4915,9 @@
 asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 {
 	asc_board_t				*boardp;
+	ASC_SCSI_REQ_Q			*scsireqq;
+	ASC_CAP_INFO			*cap_info;
+	ASC_SCSI_INQUIRY		*inquiry;
 	int						found;
 	ASC_SCSI_BIT_ID_TYPE	save_use_tagged_qng;
 	ASC_SCSI_BIT_ID_TYPE	save_can_tagged_qng;
@@ -4675,9 +4934,11 @@
 	boardp = ASC_BOARDP(scp->host);
 
 	/* Set-up AscInitPollTarget() arguments. */
-	memset(&asc_scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
-	memset(&asc_cap_info, 0, sizeof(ASC_CAP_INFO));
-	memset(&asc_inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
+	scsireqq = &boardp->scsireqq;
+	memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
+	cap_info = &boardp->cap_info;
+	memset(cap_info, 0, sizeof(ASC_CAP_INFO));
+	inquiry = &boardp->inquiry;
 
 	/*
 	 * XXX - AscInitPollBegin() re-initializes these fields to
@@ -4695,24 +4956,24 @@
 		return ASC_FALSE;
 	}
 
-	asc_scsireqq.sense_ptr = &asc_scsireqq.sense[0];
-	asc_scsireqq.r1.sense_len = ASC_MIN_SENSE_LEN;
-	asc_scsireqq.r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-	asc_scsireqq.r1.target_lun = 0;
-	asc_scsireqq.r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
+	scsireqq->sense_ptr = &scsireqq->sense[0];
+	scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN;
+	scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+	scsireqq->r1.target_lun = 0;
+	scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
 
 	found = ASC_FALSE;
 	ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n");
-	switch (ret = AscInitPollTarget(asc_dvc_varp, &asc_scsireqq,
-		&asc_inquiry, &asc_cap_info)) {
+	switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry,
+		cap_info)) {
 	case ASC_TRUE:
 		found = ASC_TRUE;
 #ifdef ADVANSYS_DEBUG
 		tidmask = ASC_TIX_TO_TARGET_ID(scp->target);
 		ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n",
-			asc_cap_info.lba, asc_cap_info.blk_size);
+			cap_info->lba, cap_info->blk_size);
 		ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
-			asc_inquiry.byte0.peri_dvc_type);
+			inquiry->byte0.peri_dvc_type);
 		if (asc_dvc_varp->use_tagged_qng & tidmask) {
 			ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n",
 				asc_dvc_varp->max_dvc_qng[scp->target]);
@@ -5188,12 +5449,14 @@
 	ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid);
 #ifdef ADVANSYS_STATS
 	/* Maintain request queue statistics. */
+	ascq->q_tot_cnt[tid]++;
 	ascq->q_cur_cnt[tid]++;
 	if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
 		ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
 		ASC_DBG2(1, "asc_enqueue: new q_max_cnt[%d] %d\n",
 			tid, ascq->q_max_cnt[tid]);
 	}
+	REQPTIME(reqp) = REQTIMESTAMP();
 #endif /* ADVANSYS_STATS */
 	ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp);
 	return;
@@ -5227,6 +5490,7 @@
 		/* Maintain request queue statistics. */
 		ascq->q_cur_cnt[tid]--;
 		ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+		REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
 #endif /* ADVANSYS_STATS */
 	}
 	ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp);
@@ -5249,6 +5513,9 @@
  * (or the function return value) is not NULL, i.e. use a temporary
  * variable for 'lastpp' and check its value after the function return
  * before assigning it to the list last pointer.
+ *
+ * Unfortunately collecting queuing time statistics adds overhead to
+ * the function that isn't inherent to the function's algorithm.
  */
 REQP
 asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
@@ -5268,7 +5535,7 @@
 	if (tid != ASC_TID_ALL) {
 		/* Return all requests for the specified 'tid'. */
 		if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) {
-			/* List is empty set first and last return pointers to NULL. */
+			/* List is empty; Set first and last return pointers to NULL. */
 			firstp = lastp = NULL;
 		} else {
 			firstp = ascq->q_first[tid];
@@ -5276,7 +5543,13 @@
 			ascq->q_first[tid] = ascq->q_last[tid] = NULL;
 			ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
 #ifdef ADVANSYS_STATS
-			ascq->q_cur_cnt[tid] = 0;
+			{
+				REQP reqp;
+				ascq->q_cur_cnt[tid] = 0;
+				for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+					REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid);
+				}
+			}
 #endif /* ADVANSYS_STATS */
 		}
 	} else {
@@ -5299,6 +5572,14 @@
 #endif /* ADVANSYS_STATS */
 			}
 		}
+#ifdef ADVANSYS_STATS
+		{
+			REQP reqp;
+			for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+				REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->target);
+			}
+		}
+#endif /* ADVANSYS_STATS */
 	}
 	if (lastpp) {
 		*lastpp = lastp;
@@ -5324,7 +5605,7 @@
 	int			tid;
 	int			ret = ASC_FALSE;
 
-	ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %d\n",
+	ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %x\n",
 		(unsigned) ascq, (unsigned) reqp);
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
 	ASC_ASSERT(reqp != NULL);
@@ -5373,6 +5654,7 @@
 	/* Maintain request queue statistics. */
 	if (ret == ASC_TRUE) {
 		ascq->q_cur_cnt[tid]--;
+		REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
 	}
 	ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
@@ -5406,6 +5688,7 @@
 			break;
 		}
 	}
+	ASC_DBG1(1, "asc_isqueued: ret %x\n", ret);
 	return ret;
 }
 
@@ -5478,7 +5761,7 @@
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if (boardp->asc_dvc_cfg.chip_scsi_id == i) {
 			continue;
-		} else if (boardp->init_tidmask & (1 << i)) {
+		} else if (boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
 			len = asc_prt_line(cp, leftlen, " %d,", i);
 			ASC_PRT_NEXT();
 		}
@@ -5534,7 +5817,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->disc_enable & (1 << i)) ? 'Y' : 'N');
+			i, (ep->disc_enable & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5545,7 +5828,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->use_cmd_qng & (1 << i)) ? 'Y' : 'N');
+			i, (ep->use_cmd_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5556,7 +5839,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->start_motor & (1 << i)) ? 'Y' : 'N');
+			i, (ep->start_motor & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5567,7 +5850,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->init_sdtr & (1 << i)) ? 'Y' : 'N');
+			i, (ep->init_sdtr & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5595,9 +5878,15 @@
 STATIC int
 asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
 {
+	asc_board_t			*boardp;
 	int					leftlen;
 	int					totlen;
 	int					len;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+	int					i;
+#endif /* version >= v1.3.89 */
+
+	boardp = ASC_BOARDP(shp);
 
 	leftlen = cplen;
 	totlen = len = 0;
@@ -5608,42 +5897,91 @@
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
+" host_busy %u, last_reset %u, max_id %u, max_lun %u\n",
+		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun);
+#else /* version >= v1.3.89 */
 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
 		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
 		shp->max_channel);
-#else /* version >= v1.3.89 */
-" host_busy %u, last_reset %u, max_id %u, max_lun %u\n",
-		shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun);
 #endif /* version >= v1.3.89 */
 	ASC_PRT_NEXT();
 	
 	len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
+" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+		shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun);
+#else /* version >= v1.3.57 */
 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
 		shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
 		shp->cmd_per_lun);
-#else /* version >= v1.3.57 */
-" can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
-		shp->can_queue, shp->this_id, shp->sg_tablesize, shp->cmd_per_lun);
 #endif /* version >= v1.3.57 */
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,57)
-" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
-		shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
-#else /* version >= v1.3.57 */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,57)
 " unchecked_isa_dma %d, loaded_as_module %d\n",
 		shp->unchecked_isa_dma, shp->loaded_as_module);
+#else /* version >= v1.3.57 */
+" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
+		shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
 #endif /* version >= v1.3.57 */
 	ASC_PRT_NEXT();
 
 	len = asc_prt_line(cp, leftlen,
-" flags %x, reset_jiffies %x, jiffies %x\n",
-		ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->reset_jiffies, jiffies);
+" flags %x, last_reset %x, jiffies %x\n",
+		ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies);
+	ASC_PRT_NEXT();
+
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+	len = asc_prt_line(cp, leftlen,
+" queue_depth:     ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %d:%d",
+			i, boardp->device[i]->queue_depth);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
+#endif /* version >= v1.3.89 */
+
+#if ASC_QUEUE_FLOW_CONTROL
+	len = asc_prt_line(cp, leftlen,
+" queue_curr_depth:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %d:%d",
+			i, boardp->device[i]->queue_curr_depth);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
 
+	len = asc_prt_line(cp, leftlen,
+" queue_count:     ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %d:%d",
+			i, boardp->device[i]->queue_count);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+
  	return totlen;
 }
 
@@ -5668,9 +6006,6 @@
 	ASC_DVC_VAR			*v;
 	ASC_DVC_CFG			*c;
 	int					i;
-#ifdef ADVANSYS_STATS
-	struct asc_stats	*s;
-#endif /* ADVANSYS_STATS */
 
 	boardp = ASC_BOARDP(shp);
 	v = &boardp->asc_dvc_var;
@@ -5704,11 +6039,11 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (v->sdtr_done & (1 << i)) ? 'Y' : 'N');
+			i, (v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5719,11 +6054,11 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (v->use_tagged_qng & (1 << i)) ? 'Y' : 'N');
+			i, (v->use_tagged_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5735,7 +6070,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]);
@@ -5750,7 +6085,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]);
@@ -5759,21 +6094,18 @@
 	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
 
-#ifdef ADVANSYS_STATS
-	s = &boardp->asc_stats;
-
 	/* Indicate whether the device has returned queue full status. */
 	len = asc_prt_line(cp, leftlen,
 " Command Queue Full:      ");
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
-		if (s->queue_full & (1 << i)) {
+		if (boardp->queue_full & ASC_TIX_TO_TARGET_ID(i)) {
 			len = asc_prt_line(cp, leftlen, " %d:Y-%d",
-				i, s->queue_full_cnt[i]);
+				i, boardp->queue_full_cnt[i]);
 		} else {
 			len = asc_prt_line(cp, leftlen, " %d:N", i);
 		}
@@ -5781,7 +6113,6 @@
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
-#endif /* ADVANSYS_STATS */
 
  	return totlen;
 }
@@ -5897,18 +6228,19 @@
 }
 
 /*
- * Convert a virtual address to a virtual address.
- *
- * Apparently Linux is loaded V=R (virtual equals real). Just return
- * the virtual address.
+ * Convert a virtual address to a bus address.
  */
 ulong
 DvcGetPhyAddr(uchar *buf_addr, ulong buf_len)
 {
-	ulong phys_addr;
+	ulong bus_addr;
 
-	phys_addr = (ulong) buf_addr;
-	return phys_addr;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+	bus_addr = (ulong) buf_addr;
+#else /* version >= v2.0.0 */
+	bus_addr = virt_to_bus(buf_addr);
+#endif /* version >= v2.0.0 */
+	return bus_addr;
 }
 
 ulong
@@ -5919,7 +6251,11 @@
 
 	buf_size = buf_len;
 	asc_sg_head_ptr->entry_cnt = 1;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 	asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr;
+#else /* version >= v2.0.0 */
+	asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr);
+#endif /* version >= v2.0.0 */
 	asc_sg_head_ptr->sg_list[0].bytes = buf_size;
 	return buf_size;
 }
@@ -6076,8 +6412,6 @@
 /*
  * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
- *
- * This function was formerly supplied by the library.
  */
 ushort
 AscGetChipBiosAddress(
@@ -6088,13 +6422,15 @@
     ushort  cfg_lsw ;
     ushort  bios_addr ;
 
-    /*
-     *   We can't get the BIOS address for PCI
-     */
-    if ( bus_type & ASC_IS_PCI )
-    {
-        return( 0 );
-    }
+	/*
+	 * The PCI BIOS is re-located by the motherboard BIOS. Because
+	 * of this the driver can not determine where a PCI BIOS is
+	 * loaded and executes.
+	 */
+	if ( bus_type & ASC_IS_PCI )
+	{
+		return( 0 );
+	}
 
     if( ( bus_type & ASC_IS_EISA ) != 0 )
     {
@@ -6170,25 +6506,6 @@
 	ASC_PRT_NEXT();
 
 	/*
-	 * Display request queuing statistics.
-	 */
-	len = asc_prt_line(cp, leftlen,
-" Active and Pending Request Queues:\n");
-	ASC_PRT_NEXT();
-
-	active = &ASC_BOARDP(shp)->active;
-	waiting = &ASC_BOARDP(shp)->waiting;
-	for (i = 0; i < ASC_MAX_TID + 1; i++) {
-		if (active->q_max_cnt[i] > 0 || waiting->q_max_cnt[i] > 0) {
-			len = asc_prt_line(cp, leftlen,
-"  target %d: active [cur %d, max %d], waiting [cur %d, max %d]\n",
-				i, active->q_cur_cnt[i], active->q_max_cnt[i],
-				waiting->q_cur_cnt[i], waiting->q_max_cnt[i]);
-			ASC_PRT_NEXT();
-		}
-	}
-
-	/*
 	 * Display data transfer statistics.
 	 */
 	if (s->cont_cnt > 0) {
@@ -6235,6 +6552,44 @@
 		ASC_PRT_NEXT();
 	}
 
+	/*
+	 * Display request queuing statistics.
+	 */
+	len = asc_prt_line(cp, leftlen,
+" Active and Waiting Request Queues (time unit: %d HZ):\n", HZ);
+	ASC_PRT_NEXT();
+
+	active = &ASC_BOARDP(shp)->active;
+	waiting = &ASC_BOARDP(shp)->waiting;
+	for (i = 0; i < ASC_MAX_TID + 1; i++) {
+		if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) {
+			len = asc_prt_line(cp, leftlen, " target %d\n", i);
+			ASC_PRT_NEXT();
+
+			len = asc_prt_line(cp, leftlen,
+"   active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
+				active->q_cur_cnt[i], active->q_max_cnt[i],
+				active->q_tot_cnt[i],
+				active->q_min_tim[i], active->q_max_tim[i],
+				(active->q_tot_cnt[i] == 0) ? 0 :
+				(active->q_tot_tim[i]/active->q_tot_cnt[i]),
+				(active->q_tot_cnt[i] == 0) ? 0 :
+				ASC_TENTHS(active->q_tot_tim[i], active->q_tot_cnt[i]));
+			ASC_PRT_NEXT();
+
+			len = asc_prt_line(cp, leftlen,
+"   waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
+				waiting->q_cur_cnt[i], waiting->q_max_cnt[i],
+				waiting->q_tot_cnt[i],
+				waiting->q_min_tim[i], waiting->q_max_tim[i],
+				(waiting->q_tot_cnt[i] == 0) ? 0 :
+				(waiting->q_tot_tim[i]/waiting->q_tot_cnt[i]),
+				(waiting->q_tot_cnt[i] == 0) ? 0 :
+				ASC_TENTHS(waiting->q_tot_tim[i], waiting->q_tot_cnt[i]));
+			ASC_PRT_NEXT();
+		}
+	}
+
  	return totlen;
 }
 #endif /* ADVANSYS_STATS */
@@ -6275,6 +6630,60 @@
 }
 
 /*
+ * asc_prt_scsi_cmnd()
+ */
+STATIC void 
+asc_prt_scsi_cmnd(Scsi_Cmnd *s)
+{
+	printk("Scsi_Cmnd at addr %x\n", (unsigned) s);
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+	printk(
+" host %x, device %x, target %u, lun %u\n",
+		(unsigned) s->host, (unsigned) s->device, s->target, s->lun);
+#else /* version >= v1.3.0 */
+	printk(
+" host %x, device %x, target %u, lun %u, channel %u,\n",
+		(unsigned) s->host, (unsigned) s->device, s->target, s->lun,
+		s->channel);
+#endif /* version >= v1.3.0 */
+
+	asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
+
+	printk(
+" use_sg %u, sglist_len %u, abort_reason %x\n",
+		s->use_sg, s->sglist_len, s->abort_reason);
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
+	printk(
+" retries %d, allowed %d\n",
+		 s->retries, s->allowed);
+#else /* version >= v1.3.89 */
+	printk(
+" serial_number %x, serial_number_at_timeout %x, retries %d, allowed %d\n",
+		(unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout,
+		 s->retries, s->allowed);
+#endif /* version >= v1.3.89 */
+
+	printk(
+" timeout_per_command %d, timeout_total %d, timeout %d\n",
+		s->timeout_per_command, s->timeout_total, s->timeout);
+
+	printk(
+" internal_timeout %u, flags %u, this_count %d\n",
+		s->internal_timeout, s->flags, s->this_count);
+
+	printk(
+" scsi_done %x, done %x, host_scribble %x, result %x\n",
+		(unsigned) s->scsi_done, (unsigned) s->done,
+		(unsigned) s->host_scribble, s->result);
+
+	printk(
+" tag %u, pid %u\n",
+		(unsigned) s->tag, (unsigned) s->pid);
+}
+
+/*
  * asc_prt_dvc_var()
  */
 STATIC void 
@@ -6896,6 +7305,8 @@
 						asc_dvc->sdtr_done |= target_id;
 						asc_dvc->init_sdtr |= target_id;
 						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+						sdtr_data = AscCalSDTRData(asc_dvc,
+							sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset);
 						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
 					} else {
 						q_cntl |= QC_MSG_OUT;
@@ -6903,6 +7314,8 @@
 									  sdtr_xmsg.xfer_period,
 									  sdtr_xmsg.req_ack_offset);
 						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+						sdtr_data = AscCalSDTRData(asc_dvc,
+							sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset);
 						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
 						asc_dvc->sdtr_done |= target_id;
 						asc_dvc->init_sdtr |= target_id;
@@ -6996,24 +7409,23 @@
 									 (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) tid_no),
 									 cur_dvc_qng);
 				}
-#ifdef ADVANSYS_STATS
 				{
-					asc_board_t		*boardp;
-					int				i;
-					for (i = 0; i < ASC_NUM_BOARD_SUPPORTED; i++) {
-						if (asc_host[i] == NULL) {
-							continue;
-						}
-						boardp = ASC_BOARDP(asc_host[i]);
-						if (&boardp->asc_dvc_var == asc_dvc) {
-							boardp->asc_stats.queue_full |= target_id;
-							boardp->asc_stats.queue_full_cnt[tid_no] =
-							  cur_dvc_qng;
-							break;
-						}
-					}
+				asc_board_t		*boardp;
+				boardp = (asc_board_t *) asc_dvc->drv_ptr;
+
+				/*
+				 * Set the device queue depth to the number of
+				 * active requests when the QUEUE FULL condition
+				 * was encountered.
+				 */
+				boardp->queue_full |= target_id;
+				boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
+#if ASC_QUEUE_FLOW_CONTROL
+				if (boardp->device[tid_no]->queue_curr_depth > cur_dvc_qng) {
+					boardp->device[tid_no]->queue_curr_depth = cur_dvc_qng;
+				}
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 				}
-#endif
 			}
 		}
 		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
@@ -7331,8 +7743,10 @@
 	scsiq->r3.host_stat = 0;
 	scsiq->r3.done_stat = 0;
 	scsiq->r2.vm_id = 0;
-	scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
 	scsiq->r1.data_cnt = buf_len;
+	scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
+	scsiq->sense_ptr = (uchar dosfar *) scsiq->sense ;
+	scsiq->r1.sense_len = ASC_MIN_SENSE_LEN ;
 	scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE;
 	scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ;
 	scsiq->r2.srb_ptr = (ulong) scsiq;
@@ -7345,6 +7759,12 @@
 		}
 		scsiq->r1.data_addr = phy_addr;
 	}
+	if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
+                       (uchar dosfar *) scsiq->sense_ptr,
+                       (ulong) scsiq->r1.sense_len )) == 0L) {
+		return (ERR);
+	}
+	scsiq->r1.sense_addr = phy_addr ;
 	return (0);
 }
 
@@ -8441,21 +8861,22 @@
 {
 	ruchar             *period_table;
 	int                 max_index;
+	int                 min_index;
 	int                 i;
 	period_table = asc_dvc->sdtr_period_tbl;
 	max_index = (int) asc_dvc->max_sdtr_index;
+	min_index = ( int )asc_dvc->host_init_sdtr_index ;
 	if (
-		   (syn_time >= period_table[0])
-		   && (syn_time <= period_table[max_index])
+		   (syn_time <= period_table[max_index])
 	  ) {
-		for (i = 0; i < (max_index - 1); i++) {
+		for (i = min_index; i < (max_index - 1); i++) {
 			if (syn_time <= period_table[i]) {
-				return (i);
+				return ((uchar) i);
 			}
 		}
-		return (max_index);
+		return ((uchar) max_index);
 	} else {
-		return (max_index + 1);
+		return ((uchar) (max_index + 1));
 	}
 }
 
@@ -9260,20 +9681,20 @@
 	asc_dvc->no_scam = 0;
 	asc_dvc->unit_not_ready = 0;
 	asc_dvc->queue_full_or_busy = 0;
+	asc_dvc->redo_scam = 0 ;
+	asc_dvc->res2 = 0 ;
+	asc_dvc->host_init_sdtr_index = 0 ;
+	asc_dvc->res7 = 0 ;
+	asc_dvc->res8 = 0 ;
+	asc_dvc->cfg->can_tagged_qng = 0 ;
+	asc_dvc->cfg->cmd_qng_enabled = 0;
 	asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
 	asc_dvc->init_sdtr = ASC_SCSI_WIDTH_BIT_SET;
 	asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
 	asc_dvc->scsi_reset_wait = 3;
 	asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
 	asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
-	asc_dvc->redo_scam = 0;
-	asc_dvc->res2 = 0;
-	asc_dvc->host_init_sdtr_index = 0;
-	asc_dvc->res7 = 0;
-	asc_dvc->res8 = 0;
 	asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
-	asc_dvc->cfg->can_tagged_qng = 0;
-	asc_dvc->cfg->cmd_qng_enabled = 0;
 	asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
 	asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
 	asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
@@ -9562,6 +9983,9 @@
 		scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat;
 		scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat;
 		scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg;
+		ASC_DBG4(1, "AscInitPollIsrCallBack: done_stat %x, host_stat %x, scsi_stat %x, scsi_msg %x\n",
+			scsi_done_q->d3.done_stat, scsi_done_q->d3.host_stat,
+			scsi_done_q->d3.scsi_stat, scsi_done_q->d3.scsi_msg);
 		if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) &&
 			(scsi_done_q->d3.host_stat == 0)) {
 			cp_sen_len = (uchar) ASC_MIN_SENSE_LEN;
@@ -9893,21 +10317,12 @@
 	int                 support_read_cap;
 	int                 tmp_disable_init_sdtr;
 	int                 sta;
-	ulong               phy_addr;
 	dvc_found = 0;
 	tmp_disable_init_sdtr = FALSE;
 	tid_bits = scsiq->r1.target_id;
 	lun = scsiq->r1.target_lun;
 	tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix);
 	if (
-		   (phy_addr = AscGetOnePhyAddr(asc_dvc,
-										(uchar dosfar *) scsiq->sense_ptr,
-										(ulong) scsiq->r1.sense_len)) == 0L
-	  ) {
-		return (ERR);
-	}
-	scsiq->r1.sense_addr = phy_addr;
-	if (
 		   ((asc_dvc->init_sdtr & tid_bits) != 0)
 		   && ((asc_dvc->sdtr_done & tid_bits) == 0)
 	  ) {
@@ -10024,7 +10439,7 @@
 	int                 status;
 	int                 retry = 0;
 
-	ASC_DBG1(1, "PollQueueDone: timeout_sec %d", timeout_sec);
+	ASC_DBG1(1, "PollQueueDone: timeout_sec %d\n", timeout_sec);
 	do {
 		ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n");
 		if ((status = AscExeScsiQueue(asc_dvc,
@@ -10032,6 +10447,7 @@
 			ASC_DBG(1, "PollQueueDone: before AscPollQDone\n");
 			if ((status = AscPollQDone(asc_dvc, scsiq,
 									   timeout_sec)) != 1) {
+				ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 				if (status == 0x80) {
 					if (retry++ > ASC_MAX_INIT_BUSY_RETRY) {
 						break;
@@ -10047,14 +10463,18 @@
 				scsiq->r3.host_stat = 0;
 				scsiq->r3.scsi_stat = 0;
 				scsiq->r3.scsi_msg = 0;
+				ASC_DBG(1, "PollQueueDone: before AscAbortSRB()\n");
 				AscAbortSRB(asc_dvc, (ulong) scsiq);
 			}
+			ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 			ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat);
 			return (scsiq->r3.done_stat);
 		}
+		ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 		DvcSleepMilliSecond(5);
 	} while (((status == 0) || (status == 0x80)) &&
 			  retry++ < ASC_MAX_INIT_BUSY_RETRY);
+	ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 	ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n");
 	return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
@@ -10153,12 +10573,12 @@
 	ASC_REQ_SENSE dosfar *sen;
 	retry = 0;
 	tid_bits = scsiq->r1.target_id;
-	while (retry++ < 2) {
+	while (retry++ < 4) {
 		PollScsiTestUnitReady(asc_dvc, scsiq);
 		if (scsiq->r3.done_stat == 0x01) {
 			return (1);
 		} else if (scsiq->r3.done_stat == QD_WITH_ERROR) {
-			DvcSleepMilliSecond(100);
+			DvcSleepMilliSecond(200);
 			sen = (ASC_REQ_SENSE dosfar *) scsiq->sense_ptr;
 			if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) &&
 				((sen->err_code & 0x70) != 0)) {
@@ -10174,9 +10594,10 @@
 					} else {
 						DvcSleepMilliSecond(5000);
 					}
-				} else if (sen->sense_key == SCSI_SENKEY_ATTENSION) {
-					DvcSleepMilliSecond(500);
+				} else if (sen->sense_key == SCSI_SENKEY_ATTENTION) {
+					DvcSleepMilliSecond( ( ulong )( 500L*retry ) ) ;
 				} else {
+					DvcSleepMilliSecond( 500 ) ;
 					break;
 				}
 			} else {
@@ -10208,6 +10629,7 @@
 	while (TRUE) {
 		if (asc_dvc->err_code != 0) {
 			scsiq->r3.done_stat = QD_WITH_ERROR;
+			ASC_DBG1(1, "AscPollQDone: err_code %x\n", asc_dvc->err_code);
 			sta = ERR;
 			break;
 		}
@@ -10220,10 +10642,12 @@
 		}
 		DvcSleepMilliSecond(10);
 		if (loop++ > loop_end) {
+			ASC_DBG(1, "AscPollQDone: loop finished\n");
 			sta = 0;
 			break;
 		}
 		if (AscIsChipHalted(iop_base)) {
+			ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n");
 #if !CC_ASCISR_CHECK_INT_PENDING
 			AscAckInterrupt(iop_base);
 #endif
@@ -10231,6 +10655,7 @@
 			loop = 0;
 		} else {
 			if (AscIsIntPending(iop_base)) {
+				ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n");
 #if !CC_ASCISR_CHECK_INT_PENDING
 				AscAckInterrupt(iop_base);
 #endif
diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.0.25/linux/drivers/scsi/eata.c	Wed Jul 10 08:05:27 1996
+++ linux/drivers/scsi/eata.c	Tue Nov 19 16:21:07 1996
@@ -1,6 +1,13 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
+ *          Added support for EATA 2.0C, PCI, multichannel and wide SCSI.
+ *
+ *      27 Sep 1996 rev. 2.12 for linux 2.1.0
+ *          Portability cleanups (virtual/bus addressing, little/big endian
+ *          support).
+ *
  *      09 Jul 1996 rev. 2.11 for linux 2.0.4
  *          Number of internal retries is now limited.
  *
@@ -78,7 +85,8 @@
  *
  *  Here is a brief description of the DPT SCSI host adapters.
  *  All these boards provide an EATA/DMA compatible programming interface
- *  and are fully supported by this driver:
+ *  and are fully supported by this driver in any configuration, including
+ *  multiple SCSI channels:
  *
  *  PM2011B/9X -  Entry Level ISA
  *  PM2021A/9X -  High Performance ISA
@@ -87,30 +95,39 @@
  *  PM2022A/9X -  Entry Level EISA
  *  PM2122A/9X -  High Performance EISA
  *  PM2322A/9X -  Extra High Performance EISA
+ *  PM3021     -  SmartRAID Adapter for ISA
+ *  PM3222     -  SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI)
+ *  PM3224     -  SmartRAID Adapter for PCI  (PM3224W is 16-bit wide SCSI)
  *
  *  The DPT PM2001 provides only the EATA/PIO interface and hence is not
  *  supported by this driver.
  *
  *  This code has been tested with up to 3 Distributed Processing Technology 
  *  PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) eisa controllers,
- *  no on board cache and no RAID option. 
- *  BIOS must be enabled on the first board and must be disabled for all other 
- *  boards. 
- *  Support is provided for any number of DPT PM2122 eisa boards.
- *  All boards should be configured at the same IRQ level.
- *  Multiple IRQ configurations are supported too.
- *  Boards can be located in any eisa slot (1-15) and are named EATA0, 
- *  EATA1,... in increasing eisa slot number. ISA boards are detected
- *  after the eisa slot probes.
- *
- *  The IRQ for EISA boards should be _level_ triggered (not _edge_ triggered).
- *  This is a requirement in order to support multiple boards on the same IRQ.
- *
- *  Other eisa configuration parameters are:
- *
- *  COMMAND QUEUING   : ENABLED
- *  COMMAND TIMEOUT   : ENABLED
- *  CACHE             : DISABLED
+ *  in any combination of private and shared IRQ.
+ *  PCI support has been tested using a DPT PM3224W (firmware v07G.0).
+ *
+ *  Multiple ISA, EISA and PCI boards can be configured in the same system.
+ *  It is suggested to put all the EISA boards on the same IRQ level, all
+ *  the PCI  boards on another IRQ level, while ISA boards cannot share 
+ *  interrupts.
+ *
+ *  If you configure multiple boards on the same IRQ, the interrupt must
+ *  be _level_ triggered (not _edge_ triggered).
+ *
+ *  This driver detects EATA boards by probes at fixed port addresses,
+ *  so no BIOS32 or PCI BIOS support is used or required.
+ *  The suggested way to detect a generic EATA PCI board is to force on it
+ *  any unused EISA address, even if there are other controllers on the EISA
+ *  bus, or even if you system has no EISA bus at all.
+ *  Do not force any ISA address on EATA PCI boards.
+ *
+ *  The sequence of detection probes is:
+ *  - ISA 0x1F0; 
+ *  - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15);
+ *  - ISA  0x170, 0x230, 0x330.
+ *
+ *  The boards are named EATA0, EATA1,... according to the detection order.
  *
  *  In order to support multiple ISA boards in a reliable way,
  *  the driver sets host->wish_block = TRUE for all ISA boards.
@@ -127,6 +144,7 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/byteorder.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -154,11 +172,14 @@
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
 
-#define MAX_TARGET 8
+#define MAX_CHANNEL 4
+#define MAX_LUN 32
+#define MAX_TARGET 32
 #define MAX_IRQ 16
 #define MAX_BOARDS 18
 #define MAX_MAILBOXES 64
 #define MAX_SGLIST 64
+#define MAX_LARGE_SGLIST 252
 #define MAX_INTERNAL_RETRIES 64
 #define MAX_CMD_PER_LUN 2
 
@@ -184,7 +205,7 @@
 #define REG_MID         4
 #define REG_MSB         5
 #define REGION_SIZE     9
-#define EISA_RANGE      0xf000
+#define EISA_RANGE      0x1000
 #define BSY_ASSERTED      0x80
 #define DRQ_ASSERTED      0x08
 #define ABSY_ASSERTED     0x01
@@ -209,6 +230,7 @@
 /* Number of valid bytes in the board config structure for EATA 2.0x */
 #define EATA_2_0A_SIZE 28
 #define EATA_2_0B_SIZE 30
+#define EATA_2_0C_SIZE 34
 
 /* Board info structure */
 struct eata_info {
@@ -224,8 +246,7 @@
 	      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;
+   unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */
    ulong  cp_len;       /* Number of valid bytes in cp */
    ulong  sp_len;       /* Number of valid bytes in sp */
    ushort queue_size;   /* Max number of cp that can be queued */
@@ -241,10 +262,14 @@
    unchar  isaena:1,    /* ISA i/o addressing is disabled/enabled */
 	 forcaddr:1,    /* Port address has been forced */
 		 :6;
-   unchar  max_id:5,    /* Max number of SCSI target IDs */
+   unchar  max_id:5,    /* Max SCSI target ID number */
 	 max_chan:3;    /* Max SCSI channel number on this board */
 
-   ushort ipad[249];
+   /* Structure extension defined in EATA 2.0C */
+   unchar   max_lun;    /* Max SCSI LUN number */
+   unchar   notused[3];
+
+   ushort ipad[247];
    };
 
 /* Board config structure */
@@ -283,9 +308,9 @@
    unchar unused[4];
    unchar phsunit:1,     /* Send to Target Physical Unit (bypass RAID) */
 	  notused:7;
-   unchar target;        /* SCSI Target ID */
-   unchar     lun:3,     /* LUN */
-		 :2,
+   unchar  target:5,     /* SCSI target ID */
+          channel:3;     /* SCSI channel number */
+   unchar     lun:5,     /* SCSI logical unit number */
 	   luntar:1,     /* This cp is for Target (not LUN) */
 	   dispri:1,     /* Disconnect Privilege granted */
 	      one:1;     /* 1 */
@@ -315,26 +340,31 @@
    char board_name[16];                 /* Name of this board */
    char board_id[256];                  /* data from INQUIRY on this board */
    int in_reset;                        /* True if board is doing a reset */
-   int target_time_out[MAX_TARGET];     /* N. of timeout errors on target */
-   int target_reset[MAX_TARGET];        /* If TRUE redo operation on target */
+   int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */
+   int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */
    unsigned int retries;                /* Number of internal retries */
    unsigned long last_retried_pid;      /* Pid of last retried command */
-   unsigned char subversion;            /* Bus type, either ISA or ESA */
+   unsigned char subversion;            /* Bus type, either ISA or EISA/PCI */
    unsigned char protocol_rev;          /* EATA 2.0 rev., 'A' or 'B' or 'C' */
    struct mssp sp[MAX_MAILBOXES];       /* Returned status for this board */
    };
 
-static struct Scsi_Host * sh[MAX_BOARDS + 1];
-static const char* driver_name = "EATA";
+static struct Scsi_Host *sh[MAX_BOARDS + 1];
+static const char *driver_name = "EATA";
 static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
+#define H2DEV(x) htonl(x)
+#define DEV2H(x) H2DEV(x)
+#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
+#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
+
 static void eata2x_interrupt_handler(int, void *, struct pt_regs *);
 static int do_trace = FALSE;
 
-static inline unchar wait_on_busy(ushort iobase) {
+static inline int wait_on_busy(unsigned int iobase) {
    unsigned int loop = MAXLOOP;
 
    while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED)
@@ -343,22 +373,22 @@
    return FALSE;
 }
 
-static inline unchar do_dma (ushort iobase, unsigned int addr, unchar cmd) {
+static inline int do_dma(unsigned int iobase, unsigned int addr, unchar cmd) {
 
    if (wait_on_busy(iobase)) return TRUE;
 
-   if (addr) {
-      outb((char)  addr,        iobase + REG_LOW);
-      outb((char) (addr >> 8),  iobase + REG_LM);
-      outb((char) (addr >> 16), iobase + REG_MID);
-      outb((char) (addr >> 24), iobase + REG_MSB);
+   if ((addr = V2DEV(addr))) {
+      outb((char) (addr >> 24), iobase + REG_LOW);
+      outb((char) (addr >> 16), iobase + REG_LM);
+      outb((char) (addr >> 8),  iobase + REG_MID);
+      outb((char)  addr,        iobase + REG_MSB);
       }
 
    outb(cmd, iobase + REG_CMD);
    return FALSE;
 }
 
-static inline unchar read_pio (ushort iobase, ushort *start, ushort *end) {
+static inline int read_pio(unsigned int iobase, ushort *start, ushort *end) {
    unsigned int loop = MAXLOOP;
    ushort *p;
 
@@ -374,12 +404,11 @@
    return FALSE;
 }
 
-static inline int port_detect(ushort *port_base, unsigned int j, 
-			      Scsi_Host_Template * tpnt) {
-   unsigned char irq, dma_channel, subversion;
+static inline int port_detect(unsigned int *port_base, unsigned int j, 
+			      Scsi_Host_Template *tpnt) {
+   unsigned char irq, dma_channel, subversion, c;
    unsigned char protocol_rev;
    struct eata_info info;
-   const char *board_status;
 
    /* Allowed DMA channels for ISA (0 indicates reserved) */
    unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
@@ -403,27 +432,24 @@
    /* Check the controller "EATA" signature */
    if (info.sign != EATA_SIGNATURE) return FALSE;
 
-   if (ntohl(info.data_len) < EATA_2_0A_SIZE) {
+   if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
       printk("%s: config structure size (%ld bytes) too short, detaching.\n", 
-	     name, ntohl(info.data_len));
+	     name, DEV2H(info.data_len));
       return FALSE;
       }
-   else if (ntohl(info.data_len) == EATA_2_0A_SIZE)
+   else if (DEV2H(info.data_len) == EATA_2_0A_SIZE)
       protocol_rev = 'A';
-   else if (ntohl(info.data_len) == EATA_2_0B_SIZE)
+   else if (DEV2H(info.data_len) == EATA_2_0B_SIZE)
       protocol_rev = 'B';
    else
       protocol_rev = 'C';
 
-   if (protocol_rev != 'A' && info.max_chan > 0)
-      printk("%s: warning, only scsi channel 0 is supported.\n", name);
-
    irq = info.irq;
 
-   if (*port_base & EISA_RANGE) {
+   if (*port_base >= EISA_RANGE) {
 
       if (!info.haaval || info.ata || info.drqvld) {
-	 printk("%s: unusable EISA board found (%d%d%d), detaching.\n", 
+	 printk("%s: unusable EISA/PCI board found (%d%d%d), detaching.\n", 
 		name, info.haaval, info.ata, info.drqvld);
 	 return FALSE;
 	 }
@@ -450,11 +476,6 @@
       printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
 	     name, irq);
 
-   if (info.second)
-      board_status = "Sec.";
-   else
-      board_status = "Prim.";
-
    /* Board detected, allocate its IRQ if not already done */
    if ((irq >= MAX_IRQ) || ((irqlist[irq] == NO_IRQ) && request_irq
        (irq, eata2x_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
@@ -498,6 +519,7 @@
       }
 
    sh[j]->io_port = *port_base;
+   sh[j]->unique_id = *port_base;
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->dma_channel = dma_channel;
    sh[j]->irq = irq;
@@ -526,11 +548,20 @@
       enable_dma(dma_channel);
       }
 
+   if (protocol_rev != 'A' && info.max_chan > 0 && info.max_chan < MAX_CHANNEL)
+      sh[j]->max_channel = info.max_chan;
+
+   if (protocol_rev != 'A' && info.max_id > 7 && info.max_id < MAX_TARGET)
+      sh[j]->max_id = info.max_id + 1;
+
+   if (protocol_rev == 'C' && info.max_lun > 7 && info.max_lun < MAX_LUN)
+      sh[j]->max_lun = info.max_lun + 1;
+
    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,
+   printk("%s: rev. 2.0%c, PORT 0x%03x, IRQ %u, DMA %u, SG %d, "\
+	  "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev,
+	   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 */
@@ -545,30 +576,38 @@
       sh[j]->can_queue = MAX_MAILBOXES;
       }
 
+   if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
+      printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
+             BN(j), sh[j]->max_id, sh[j]->max_lun);
+
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      printk("%s: SCSI channel %u enabled, host target ID %u.\n",
+             BN(j), c, info.host_addr[3 - c]);
+
 #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, max_lun %u.\n", name, protocol_rev, info.isaena, 
+	     info.forcaddr, info.max_id, info.max_chan, info.max_lun);
 
-   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));
+   printk("%s: Vers. 0x%x, SYNC 0x%x, sec. %u, infol %ld, cpl %ld spl %ld.\n", 
+	  name, info.version, info.sync, info.second, DEV2H(info.data_len), 
+	  DEV2H(info.cp_len), DEV2H(info.sp_len));
 #endif
 
    return TRUE;
 }
 
-int eata2x_detect (Scsi_Host_Template * tpnt) {
+int eata2x_detect(Scsi_Host_Template *tpnt) {
    unsigned int j = 0, k, flags;
 
-   ushort io_port[] = { 
-      0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88,
-      0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, 
-      0x1f0,  0x170,  0x330,  0x230,  0x0
+   unsigned int io_port[] = { 
+      0x1f0,  0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88,
+      0x8c88, 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, 
+      0x170,  0x230,  0x330,  0x0
       };
 
-   ushort *port_base = io_port;
+   unsigned int *port_base = io_port;
 
    tpnt->proc_dir = &proc_scsi_eata2x;
 
@@ -598,20 +637,20 @@
 
 static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
    unsigned int k;
-   struct scatterlist * sgpnt;
+   struct scatterlist *sgpnt;
 
    sgpnt = (struct scatterlist *) SCpnt->request_buffer;
 
    for (k = 0; k < SCpnt->use_sg; k++) {
-      cpp->sglist[k].address = htonl((unsigned int) sgpnt[k].address);
-      cpp->sglist[k].num_bytes = htonl((unsigned int) sgpnt[k].length);
+      cpp->sglist[k].address = V2DEV(sgpnt[k].address);
+      cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length);
       }
 
-   cpp->data_address = htonl((unsigned int) cpp->sglist);
-   cpp->data_len = htonl((SCpnt->use_sg * sizeof(struct sg_list)));
+   cpp->data_address = V2DEV(cpp->sglist);
+   cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
 }
 
-int eata2x_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    unsigned int i, j, k, flags;
    struct mscp *cpp;
    struct mssp *spp;
@@ -670,15 +709,16 @@
 
    memset(spp, 0, sizeof(struct mssp));
 
-   /* The EATA protocol uses Big Endian format, while Intel is Little Endian */
-   cpp->sp_addr = htonl((unsigned int) spp);
+   /* The EATA protocol uses Big Endian format */
+   cpp->sp_addr = V2DEV(spp);
 
    SCpnt->scsi_done = done;
    cpp->index = i;
    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);
+   if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
+			BN(j), i, SCpnt->channel, SCpnt->target,
+                        SCpnt->lun, SCpnt->pid);
 
    for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
      if (SCpnt->cmnd[0] == data_out_cmds[k]) {
@@ -690,10 +730,11 @@
    cpp->reqsen = TRUE;
    cpp->dispri = TRUE;
    cpp->one = TRUE;
+   cpp->channel = SCpnt->channel;
    cpp->target = SCpnt->target;
    cpp->lun = SCpnt->lun;  
    cpp->SCpnt = SCpnt;
-   cpp->sense_addr = htonl((unsigned int) SCpnt->sense_buffer); 
+   cpp->sense_addr = V2DEV(SCpnt->sense_buffer); 
    cpp->sense_len = sizeof SCpnt->sense_buffer;
 
    if (SCpnt->use_sg) {
@@ -701,8 +742,8 @@
       build_sg_list(cpp, SCpnt);
       }
    else {
-      cpp->data_address = htonl((unsigned int) SCpnt->request_buffer);
-      cpp->data_len = htonl(SCpnt->request_bufflen);
+      cpp->data_address = V2DEV(SCpnt->request_buffer);
+      cpp->data_len = H2DEV(SCpnt->request_bufflen);
       }
 
    memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
@@ -711,8 +752,9 @@
    if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) {
       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);
+      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
+             " done.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
+             SCpnt->pid);
       restore_flags(flags);
       done(SCpnt);    
       return 0;
@@ -723,7 +765,7 @@
    return 0;
 }
 
-int eata2x_abort (Scsi_Cmnd *SCarg) {
+int eata2x_abort(Scsi_Cmnd *SCarg) {
    unsigned int i, j, flags;
 
    save_flags(flags);
@@ -731,15 +773,15 @@
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
 
    if (SCarg->host_scribble == NULL) {
-      printk("%s: abort, target %d, pid %ld inactive.\n",
-	     BN(j), SCarg->target, SCarg->pid);
+      printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
+	     BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
       restore_flags(flags);
       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);
+   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n", 
+	  BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
 
    if (i >= sh[j]->can_queue)
       panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -782,16 +824,17 @@
    panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
 }
 
-int eata2x_reset (Scsi_Cmnd *SCarg, unsigned int reset_flags) {
-   unsigned int i, j, flags, time, k, limit = 0;
+int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
+   unsigned int i, j, flags, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
    save_flags(flags);
    cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
-   printk("%s: reset, enter, target %d, pid %ld, reset_flags %u.\n", 
-	  BN(j), SCarg->target, SCarg->pid, reset_flags);
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n", 
+	  BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
+          reset_flags);
 
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
@@ -810,9 +853,11 @@
 
    HD(j)->retries = 0;
 
-   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE;
-
-   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0;
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      for (k = 0; k < sh[j]->max_id; k++) {
+         HD(j)->target_redo[k][c] = TRUE;
+         HD(j)->target_to[k][c] = 0;
+         }
 
    for (i = 0; i < sh[j]->can_queue; i++) {
 
@@ -896,9 +941,10 @@
       }
 }
 
-static void eata2x_interrupt_handler(int irq, void *dev_id, struct pt_regs * regs) {
+static void eata2x_interrupt_handler(int irq, void *dev_id,
+                                     struct pt_regs *regs) {
    Scsi_Cmnd *SCpnt;
-   unsigned int i, j, k, flags, status, tstatus, loops, total_loops = 0;
+   unsigned int i, j, k, c, flags, status, tstatus, loops, total_loops = 0;
    struct mssp *spp;
    struct mscp *cpp;
 
@@ -991,9 +1037,8 @@
 		     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])
+		  else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
+     		           && HD(j)->target_redo[SCpnt->target][SCpnt->channel])
 		     status = DID_BUS_BUSY << 16;
    
 		  /* Works around a flaw in scsi.c */
@@ -1006,15 +1051,16 @@
 		     status = DID_OK << 16;
    
 		  if (tstatus == GOOD)
-		     HD(j)->target_reset[SCpnt->target] = FALSE;
+		     HD(j)->target_redo[SCpnt->target][SCpnt->channel] = 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]);
+		     printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
+                            "target_status 0x%x, sense key 0x%x.\n", BN(j), 
+			    SCpnt->channel, SCpnt->target, SCpnt->lun, 
+                            SCpnt->pid, spp->target_status, 
+                            SCpnt->sense_buffer[2]);
    
-		  HD(j)->target_time_out[SCpnt->target] = 0;
+		  HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
    
                   if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
 
@@ -1022,11 +1068,11 @@
 	       case ASST:     /* Selection Time Out */
 	       case 0x02:     /* Command Time Out   */
    
-		  if (HD(j)->target_time_out[SCpnt->target] > 1)
+		  if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
 		     status = DID_ERROR << 16;
 		  else {
 		     status = DID_TIME_OUT << 16;
-		     HD(j)->target_time_out[SCpnt->target]++;
+		     HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
 		     }
    
 		  break;
@@ -1035,8 +1081,9 @@
 	       case 0x03:     /* SCSI Bus Reset Received */
 	       case 0x04:     /* Initial Controller Power-up */
    
-		  for (k = 0; k < MAX_TARGET; k++) 
-		     HD(j)->target_reset[k] = TRUE;
+		  for (c = 0; c <= sh[j]->max_channel; c++) 
+		     for (k = 0; k < sh[j]->max_id; k++) 
+		        HD(j)->target_redo[k][c] = TRUE;
    
 	          if (SCpnt->device->type != TYPE_TAPE
                       && HD(j)->retries < MAX_INTERNAL_RETRIES) {
@@ -1075,9 +1122,10 @@
 		do_trace)
 #endif
 	       printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
-		      " target %d:%d, pid %ld, count %d.\n",
+		      " target %d.%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);
+		      SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
+                      HD(j)->iocount);
    
 	    /* Set the command state to inactive */
 	    SCpnt->host_scribble = NULL;
diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- v2.0.25/linux/drivers/scsi/eata.h	Wed Jul 10 08:05:27 1996
+++ linux/drivers/scsi/eata.h	Tue Nov 19 16:21:07 1996
@@ -11,7 +11,7 @@
 int eata2x_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *, unsigned int);
 
-#define EATA_VERSION "2.11.00"
+#define EATA_VERSION "2.20.00"
 
 
 #define EATA {                                                 \
diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- v2.0.25/linux/drivers/scsi/g_NCR5380.c	Wed Apr 17 09:01:18 1996
+++ linux/drivers/scsi/g_NCR5380.c	Fri Nov 22 12:06:30 1996
@@ -386,14 +386,15 @@
 	blocks--;
     }
 
+    if (blocks) {
 #if (NDEBUG & NDEBUG_C400_PREAD)
-    printk("53C400r: EXTRA: Waiting for buffer\n");
+	printk("53C400r: EXTRA: Waiting for buffer\n");
 #endif
-    while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
-	;
+	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+	    ;
 
 #if (NDEBUG & NDEBUG_C400_PREAD)
-    printk("53C400r: Transferring EXTRA 128 bytes\n");
+	printk("53C400r: Transferring EXTRA 128 bytes\n");
 #endif
 #ifdef CONFIG_SCSI_G_NCR5380_PORT
 	for (i=0; i<128; i++)
@@ -402,8 +403,13 @@
 	/* implies CONFIG_SCSI_G_NCR5380_MEM */
 	memmove(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
 #endif
-    start+=128;
-    blocks--;
+	start+=128;
+	blocks--;
+    }
+#if (NDEBUG & NDEBUG_C400_PREAD)
+    else
+	printk("53C400r: No EXTRA required\n");
+#endif
 
 #if (NDEBUG & NDEBUG_C400_PREAD)
     printk("53C400r: Final values: blocks=%d   start=%d\n", blocks, start);
diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.0.25/linux/drivers/scsi/ppa.c	Tue Apr 16 16:08:21 1996
+++ linux/drivers/scsi/ppa.c	Thu Nov 14 15:20:10 1996
@@ -46,7 +46,7 @@
 #define   PPA_SPIN_TMO          5000000 /* ppa_wait loop limiter */
 #define   PPA_SECTOR_SIZE       512     /* for a performance hack only */
 
-#include  <unistd.h>
+#include  <linux/stddef.h>
 #include  <linux/module.h>
 #include  <linux/kernel.h>
 #include  <linux/tqueue.h>
diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.0.25/linux/drivers/scsi/scsi.c	Thu Oct 31 12:08:53 1996
+++ linux/drivers/scsi/scsi.c	Thu Nov 14 15:20:10 1996
@@ -311,7 +311,7 @@
 
 void scsi_make_blocked_list(void)  {
     int block_count = 0, index;
-    unsigned int flags;
+    unsigned long flags;
     struct Scsi_Host * sh[128], * shpnt;
     
     /*
@@ -1025,7 +1025,7 @@
     kdev_t dev;
     struct request * req = NULL;
     int tablesize;
-    unsigned int flags;
+    unsigned long flags;
     struct buffer_head * bh, *bhp;
     struct Scsi_Host * host;
     Scsi_Cmnd * SCpnt = NULL;
@@ -1293,7 +1293,7 @@
 
 static void scsi_request_sense (Scsi_Cmnd * SCpnt)
 {
-    unsigned int flags;
+    unsigned long flags;
     
     save_flags(flags);
     cli();
diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.0.25/linux/drivers/scsi/u14-34f.c	Wed Jul 10 08:05:27 1996
+++ linux/drivers/scsi/u14-34f.c	Tue Nov 19 16:21:07 1996
@@ -1,6 +1,13 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
+ *          Added multichannel support.
+ *
+ *      27 Sep 1996 rev. 2.12 for linux 2.1.0
+ *          Portability cleanups (virtual/bus addressing, little/big endian
+ *          support).
+ *
  *      09 Jul 1996 rev. 2.11 for linux 2.0.4
  *          "Data over/under-run" no longer implies a redo on all targets.
  *          Number of internal retries is now limited.
@@ -157,6 +164,7 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/byteorder.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -197,6 +205,8 @@
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
 
+#define MAX_CHANNEL 1
+#define MAX_LUN 8
 #define MAX_TARGET 8
 #define MAX_IRQ 16
 #define MAX_BOARDS 4
@@ -248,9 +258,9 @@
    unsigned char dcn: 1;                /* disable disconnect */
    unsigned char ca: 1;                 /* use cache (if available) */
    unsigned char sg: 1;                 /* scatter/gather operation */
-   unsigned char target: 3;             /* target SCSI id */
-   unsigned char ch_no: 2;              /* SCSI channel (always 0 for 14f) */
-   unsigned char lun: 3;                /* logical unit number */
+   unsigned char target: 3;             /* SCSI target id */
+   unsigned char channel: 2;            /* SCSI channel number */
+   unsigned char lun: 3;                /* SCSI logical unit number */
    unsigned int data_address PACKED;    /* transfer data pointer */
    unsigned int data_len PACKED;        /* length in bytes */
    unsigned int command_link PACKED;    /* for linking command chains */
@@ -266,8 +276,8 @@
    Scsi_Cmnd *SCpnt;
 
    struct sg_list {
-      unsigned int address;     /* Segment Address */
-      unsigned int num_bytes;   /* Segment Length */
+      unsigned int address;             /* Segment Address */
+      unsigned int num_bytes;           /* Segment Length */
       } sglist[MAX_SGLIST];
 
    unsigned int index;   /* cp index */
@@ -283,8 +293,8 @@
    char board_name[16];                 /* Name of this board */
    char board_id[256];                  /* data from INQUIRY on this board */
    int in_reset;                        /* True if board is doing a reset */
-   int target_time_out[MAX_TARGET];     /* N. of timeout errors on target */
-   int target_reset[MAX_TARGET];        /* If TRUE redo operation on target */
+   int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */
+   int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */
    unsigned int retries;                /* Number of internal retries */
    unsigned long last_retried_pid;      /* Pid of last retried command */
    unsigned char subversion;            /* Bus type, either ISA or ESA */
@@ -295,17 +305,31 @@
    unsigned char slot;
    };
 
-static struct Scsi_Host * sh[MAX_BOARDS + 1];
-static const char* driver_name = "Ux4F";
+static struct Scsi_Host *sh[MAX_BOARDS + 1];
+static const char *driver_name = "Ux4F";
 static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
+#if defined(__BIG_ENDIAN)
+#define H2DEV(x) ((unsigned long)( \
+	(((unsigned long)(x) & 0x000000ffU) << 24) | \
+	(((unsigned long)(x) & 0x0000ff00U) <<  8) | \
+	(((unsigned long)(x) & 0x00ff0000U) >>  8) | \
+	(((unsigned long)(x) & 0xff000000U) >> 24)))
+#else
+#define H2DEV(x) (x)
+#endif
+
+#define DEV2H(x) H2DEV(x)
+#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
+#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
+
 static void u14_34f_interrupt_handler(int, void *, struct pt_regs *);
 static int do_trace = FALSE;
 
-static inline unchar wait_on_busy(ushort iobase) {
+static inline int wait_on_busy(unsigned int iobase) {
    unsigned int loop = MAXLOOP;
 
    while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED)
@@ -322,8 +346,8 @@
    memset(cpp, 0, sizeof(struct mscp));
    cpp->opcode = OP_HOST_ADAPTER;
    cpp->xdir = DTD_IN;
-   cpp->data_address = (unsigned int) HD(j)->board_id;
-   cpp->data_len = sizeof(HD(j)->board_id);
+   cpp->data_address = V2DEV(HD(j)->board_id);
+   cpp->data_len = H2DEV(sizeof(HD(j)->board_id));
    cpp->scsi_cdbs_len = 6;
    cpp->scsi_cdbs[0] = HA_CMD_INQUIRY;
 
@@ -338,7 +362,7 @@
    outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
 
    /* Store pointer in OGM address bytes */
-   outl((unsigned int)cpp, sh[j]->io_port + REG_OGM);
+   outl(V2DEV(cpp), sh[j]->io_port + REG_OGM);
 
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
@@ -357,9 +381,9 @@
    return FALSE;
 }
 
-static inline int port_detect(ushort *port_base, unsigned int j, 
-			      Scsi_Host_Template * tpnt) {
-   unsigned char irq, dma_channel, subversion;
+static inline int port_detect(unsigned int *port_base, unsigned int j, 
+			      Scsi_Host_Template *tpnt) {
+   unsigned char irq, dma_channel, subversion, c;
    unsigned char in_byte;
 
    /* Allowed BIOS base addresses (NULL indicates reserved) */
@@ -447,6 +471,7 @@
       }
 
    sh[j]->io_port = *port_base;
+   sh[j]->unique_id = *port_base;
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->base = bios_segment_table[config_1.bios_segment];
    sh[j]->irq = irq;
@@ -505,6 +530,10 @@
       enable_dma(dma_channel);
       }
 
+   sh[j]->max_channel = MAX_CHANNEL - 1;
+   sh[j]->max_id = MAX_TARGET;
+   sh[j]->max_lun = MAX_LUN;
+
    if (HD(j)->subversion == ISA && !board_inquiry(j)) {
       HD(j)->board_id[40] = 0;
 
@@ -519,21 +548,29 @@
 
    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,
+	  (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);
+
+   if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
+      printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
+             BN(j), sh[j]->max_id, sh[j]->max_lun);
+
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      printk("%s: SCSI channel %u enabled, host target ID %u.\n",
+             BN(j), c, sh[j]->this_id);
+
    return TRUE;
 }
 
-int u14_34f_detect (Scsi_Host_Template * tpnt) {
+int u14_34f_detect(Scsi_Host_Template *tpnt) {
    unsigned int j = 0, k, flags;
 
-   ushort io_port[] = {
+   unsigned int io_port[] = {
       0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140, 0x0
       };
 
-   ushort *port_base = io_port;
+   unsigned int *port_base = io_port;
 
    tpnt->proc_dir = &proc_scsi_u14_34f;
 
@@ -563,19 +600,19 @@
 
 static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
    unsigned int k, data_len = 0;
-   struct scatterlist * sgpnt;
+   struct scatterlist *sgpnt;
 
    sgpnt = (struct scatterlist *) SCpnt->request_buffer;
 
    for (k = 0; k < SCpnt->use_sg; k++) {
-      cpp->sglist[k].address = (unsigned int) sgpnt[k].address;
-      cpp->sglist[k].num_bytes = sgpnt[k].length;
+      cpp->sglist[k].address = V2DEV(sgpnt[k].address);
+      cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length);
       data_len += sgpnt[k].length;
       }
 
    cpp->use_sg = SCpnt->use_sg;
-   cpp->data_address = (unsigned int) cpp->sglist;
-   cpp->data_len = data_len;
+   cpp->data_address = V2DEV(cpp->sglist);
+   cpp->data_len = H2DEV(data_len);
 }
 
 int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
@@ -634,8 +671,9 @@
    cpp->index = i;
    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);
+   if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
+			BN(j), i, SCpnt->channel, SCpnt->target, 
+                        SCpnt->lun, SCpnt->pid);
 
    cpp->xdir = DTD_IN;
 
@@ -646,10 +684,11 @@
 	}
 
    cpp->opcode = OP_SCSI;
+   cpp->channel = SCpnt->channel;
    cpp->target = SCpnt->target;
    cpp->lun = SCpnt->lun;
    cpp->SCpnt = SCpnt;
-   cpp->sense_addr = (unsigned int) SCpnt->sense_buffer;
+   cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
    cpp->sense_len = sizeof SCpnt->sense_buffer;
 
    if (SCpnt->use_sg) {
@@ -657,8 +696,8 @@
       build_sg_list(cpp, SCpnt);
       }
    else {
-      cpp->data_address = (unsigned int)SCpnt->request_buffer;
-      cpp->data_len = SCpnt->request_bufflen;
+      cpp->data_address = V2DEV(SCpnt->request_buffer);
+      cpp->data_len = H2DEV(SCpnt->request_bufflen);
       }
 
    cpp->scsi_cdbs_len = SCpnt->cmd_len;
@@ -667,15 +706,16 @@
    if (wait_on_busy(sh[j]->io_port)) {
       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);
+      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
+             " done.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
+             SCpnt->pid);
       restore_flags(flags);
       done(SCpnt);
       return 0;
       }
 
    /* Store pointer in OGM address bytes */
-   outl((unsigned int)cpp, sh[j]->io_port + REG_OGM);
+   outl(V2DEV(cpp), sh[j]->io_port + REG_OGM);
 
    /* Issue OGM interrupt */
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
@@ -693,15 +733,15 @@
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
 
    if (SCarg->host_scribble == NULL) {
-      printk("%s: abort, target %d, pid %ld inactive.\n",
-	     BN(j), SCarg->target, SCarg->pid);
+      printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
+	     BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
       restore_flags(flags);
       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);
+   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+	  BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
 
    if (i >= sh[j]->can_queue)
       panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -744,16 +784,17 @@
    panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
 }
 
-int u14_34f_reset(Scsi_Cmnd * SCarg, unsigned int reset_flags) {
-   unsigned int i, j, flags, time, k, limit = 0;
+int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
+   unsigned int i, j, flags, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
    save_flags(flags);
    cli();
    j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
-   printk("%s: reset, enter, target %d, pid %ld, reset_flags %u.\n", 
-	  BN(j), SCarg->target, SCarg->pid, reset_flags);
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n", 
+	  BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
+          reset_flags);
 
    if (SCarg->host_scribble == NULL)
       printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
@@ -772,9 +813,11 @@
 
    HD(j)->retries = 0;
 
-   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE;
-
-   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0;
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      for (k = 0; k < sh[j]->max_id; k++) {
+         HD(j)->target_redo[k][c] = TRUE;
+         HD(j)->target_to[k][c] = 0;
+         }
 
    for (i = 0; i < sh[j]->can_queue; i++) {
 
@@ -859,7 +902,7 @@
       }
 }
 
-int u14_34f_biosparam(Disk * disk, kdev_t dev, int * dkinfo) {
+int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
    unsigned int j = 0;
    int size = disk->capacity;
 
@@ -869,9 +912,10 @@
    return 0;
 }
 
-static void u14_34f_interrupt_handler(int irq, void *dev_id, struct pt_regs * regs) {
+static void u14_34f_interrupt_handler(int irq, void *dev_id,
+                                      struct pt_regs *regs) {
    Scsi_Cmnd *SCpnt;
-   unsigned int i, j, k, flags, status, tstatus, loops, total_loops = 0;
+   unsigned int i, j, k, c, flags, status, tstatus, loops, total_loops = 0;
    struct mscp *spp;
 
    save_flags(flags);
@@ -901,7 +945,7 @@
 	 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);
+	 spp = (struct mscp *)DEV2V(inl(sh[j]->io_port + REG_ICM));
 
 	 /* Clear interrupt pending flag */
 	 outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
@@ -956,9 +1000,8 @@
 		  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])
+	       else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
+		        && HD(j)->target_redo[SCpnt->target][SCpnt->channel])
 		  status = DID_BUS_BUSY << 16;
 
 	       /* Works around a flaw in scsi.c */
@@ -971,26 +1014,27 @@
 		  status = DID_OK << 16;
 
 	       if (tstatus == GOOD)
-		  HD(j)->target_reset[SCpnt->target] = FALSE;
+		  HD(j)->target_redo[SCpnt->target][SCpnt->channel] = 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]);
+		  printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
+                         "target_status 0x%x, sense key 0x%x.\n", BN(j), 
+			 SCpnt->channel, SCpnt->target, SCpnt->lun,
+                         SCpnt->pid, spp->target_status,
+                         SCpnt->sense_buffer[2]);
 
-	       HD(j)->target_time_out[SCpnt->target] = 0;
+	       HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
 
                if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
 
 	       break;
 	    case ASST:     /* Selection Time Out */
 
-	       if (HD(j)->target_time_out[SCpnt->target] > 1)
+	       if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
 		  status = DID_ERROR << 16;
 	       else {
 		  status = DID_TIME_OUT << 16;
-		  HD(j)->target_time_out[SCpnt->target]++;
+		  HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
 		  }
 
 	       break;
@@ -1001,8 +1045,10 @@
 	    case 0x96:     /* Illegal SCSI command */
 	    case 0xa3:     /* SCSI bus reset error */
 
-	       for (k = 0; k < MAX_TARGET; k++) 
-		  HD(j)->target_reset[k] = TRUE;
+	       for (c = 0; c <= sh[j]->max_channel; c++) 
+	          for (k = 0; k < sh[j]->max_id; k++) 
+	             HD(j)->target_redo[k][c] = TRUE;
+   
 
 	    case 0x92:     /* Data over/under-run */
 
@@ -1042,9 +1088,10 @@
 	     do_trace)
 #endif
 	    printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
-		   " target %d:%d, pid %ld, count %d.\n",
+		   " target %d.%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);
+		   SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
+                   HD(j)->iocount);
 
 	 /* Set the command state to inactive */
 	 SCpnt->host_scribble = NULL;
diff -u --recursive --new-file v2.0.25/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v2.0.25/linux/drivers/scsi/u14-34f.h	Wed Jul 10 08:05:27 1996
+++ linux/drivers/scsi/u14-34f.h	Tue Nov 19 16:21:07 1996
@@ -10,7 +10,7 @@
 int u14_34f_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "2.11.00"
+#define U14_34F_VERSION "2.20.00"
 
 #define ULTRASTOR_14_34F {                                            \
 		NULL, /* Ptr for modules */                           \
diff -u --recursive --new-file v2.0.25/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v2.0.25/linux/include/asm-alpha/unistd.h	Mon Aug  5 10:13:54 1996
+++ linux/include/asm-alpha/unistd.h	Mon Nov 18 10:25:38 1996
@@ -166,6 +166,10 @@
 #define __NR_nanosleep			340
 #define __NR_mremap			341
 #define __NR_nfsctl			342
+#define __NR_setresuid			343
+#define __NR_getresuid			344
+#define __NR_pciconfig_read		345
+#define __NR_pciconfig_write		346
 
 #if defined(__LIBRARY__) && defined(__GNUC__)
 
diff -u --recursive --new-file v2.0.25/linux/include/linux/igmp.h linux/include/linux/igmp.h
--- v2.0.25/linux/include/linux/igmp.h	Wed Aug 21 09:18:10 1996
+++ linux/include/linux/igmp.h	Thu Nov 14 15:20:10 1996
@@ -36,6 +36,7 @@
 #define IGMP_HOST_MEMBERSHIP_REPORT	0x12	/* Ditto */
 #define IGMP_DVMRP			0x13	/* DVMRP routing */
 #define IGMP_PIM			0x14	/* PIM routing */
+#define IGMP_TRACE			0x15	/* CISCO trace */
 #define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16	/* New version of 0x11 */
 #define IGMP_HOST_LEAVE_MESSAGE 	0x17	/* An extra BSD seems to send */
 
@@ -90,7 +91,8 @@
 	unsigned long multiaddr;
 	struct ip_mc_list *next;
 	struct timer_list timer;
-	int tm_running;
+	short tm_running;
+	short reporter;
 	int users;
 };
 
diff -u --recursive --new-file v2.0.25/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- v2.0.25/linux/include/linux/isdn.h	Sun Sep  1 09:15:33 1996
+++ linux/include/linux/isdn.h	Wed Nov 13 08:36:20 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.16 1996/08/12 16:20:56 hipp Exp $
+/* $Id: isdn.h,v 1.18 1996/11/06 17:37:50 keil Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -21,6 +21,12 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn.h,v $
+ * Revision 1.18  1996/11/06 17:37:50  keil
+ * more changes for 2.1.X
+ *
+ * Revision 1.17  1996/09/07 12:53:57  hipp
+ * moved a few isdn_ppp.c specific defines to drives/isdn/isdn_ppp.h
+ *
  * Revision 1.16  1996/08/12 16:20:56  hipp
  * renamed ppp_minor to ppp_slot
  *
@@ -212,7 +218,6 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/malloc.h>
-#include <linux/mm.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/tty.h>
@@ -503,11 +508,6 @@
 
 #define NUM_RCV_BUFFS     64
 #define PPP_HARD_HDR_LEN 4
-
-#define IPPP_OPEN        0x1
-#define IPPP_CONNECT     0x2
-#define IPPP_CLOSEWAIT   0x4
-#define IPPP_NOBLOCK     0x8
 
 #ifdef CONFIG_ISDN_PPP
 
diff -u --recursive --new-file v2.0.25/linux/include/linux/isdnif.h linux/include/linux/isdnif.h
--- v2.0.25/linux/include/linux/isdnif.h	Fri Jun  7 16:02:43 1996
+++ linux/include/linux/isdnif.h	Wed Nov 13 08:36:20 1996
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.9 1996/06/06 21:24:24 fritz Exp $
+/* $Id: isdnif.h,v 1.13 1996/11/13 02:39:59 fritz Exp $
  *
  * Linux ISDN subsystem
  *
@@ -22,6 +22,18 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdnif.h,v $
+ * Revision 1.13  1996/11/13 02:39:59  fritz
+ * More compatibility changes.
+ *
+ * Revision 1.12  1996/11/06 17:38:48  keil
+ * more changes for 2.1.X
+ *
+ * Revision 1.11  1996/10/23 11:59:42  fritz
+ * More compatibility changes.
+ *
+ * Revision 1.10  1996/10/22 23:14:19  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
  * Revision 1.9  1996/06/06 21:24:24  fritz
  * Started adding support for suspend/resume.
  *
@@ -301,6 +313,30 @@
  *
  */
 extern int register_isdn(isdn_if*);
+
+/* Compatibility Linux-2.0.X <-> Linux-2.1.X */
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+#if (LINUX_VERSION_CODE < 0x020100)
+#include <linux/mm.h>
+#define copy_from_user memcpy_fromfs
+#define copy_to_user memcpy_tofs
+#define GET_USER(x, addr) ( x = get_user(addr) )
+#define RWTYPE int
+#define LSTYPE int
+#define RWARG int
+#define LSARG off_t
+#else
+#include <asm/uaccess.h>
+#define GET_USER get_user
+#define PUT_USER put_user
+#define RWTYPE long
+#define LSTYPE long long
+#define RWARG unsigned long
+#define LSARG long long
+#endif
 
 #endif /* __KERNEL__ */
 #endif /* isdnif_h */
diff -u --recursive --new-file v2.0.25/linux/include/linux/major.h linux/include/linux/major.h
--- v2.0.25/linux/include/linux/major.h	Sun Sep  8 19:50:21 1996
+++ linux/include/linux/major.h	Sat Nov 16 13:00:47 1996
@@ -8,8 +8,8 @@
 
 /* limits */
 
-#define MAX_CHRDEV 64
-#define MAX_BLKDEV 64
+#define MAX_CHRDEV 128
+#define MAX_BLKDEV 128
 
 #define UNNAMED_MAJOR	0
 #define MEM_MAJOR	1
diff -u --recursive --new-file v2.0.25/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.0.25/linux/include/linux/pci.h	Wed Nov 13 11:26:23 1996
+++ linux/include/linux/pci.h	Tue Nov 19 15:50:06 1996
@@ -264,8 +264,8 @@
 #define PCI_DEVICE_ID_DEC_TULIP_FAST	0x0009
 #define PCI_DEVICE_ID_DEC_FDDI		0x000F
 #define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014
-#define PCI_DEVICE_ID_DEC_21052_AB	0x0021
-#define PCI_DEVICE_ID_DEC_21152_AA	0x0024
+#define PCI_DEVICE_ID_DEC_21052		0x0021
+#define PCI_DEVICE_ID_DEC_21152		0x0024
 
 #define PCI_VENDOR_ID_CIRRUS		0x1013
 #define PCI_DEVICE_ID_CIRRUS_5430	0x00a0
@@ -531,7 +531,10 @@
 
 #define PCI_VENDOR_ID_S3		0x5333
 #define PCI_DEVICE_ID_S3_ViRGE		0x5631
-#define PCI_DEVICE_ID_S3_811		0x8811
+#define PCI_DEVICE_ID_S3_TRIO		0x8811
+#define PCI_DEVICE_ID_S3_AURORA64VP	0x8812
+#define PCI_DEVICE_ID_S3_TRIO64UVP	0x8814
+#define PCI_DEVICE_ID_S3_ViRGE_VX	0x883d
 #define PCI_DEVICE_ID_S3_868		0x8880
 #define PCI_DEVICE_ID_S3_928		0x88b0
 #define PCI_DEVICE_ID_S3_864_1		0x88c0
diff -u --recursive --new-file v2.0.25/linux/include/net/protocol.h linux/include/net/protocol.h
--- v2.0.25/linux/include/net/protocol.h	Sun Feb 11 13:28:37 1996
+++ linux/include/net/protocol.h	Thu Nov 14 15:20:10 1996
@@ -35,7 +35,7 @@
   void			(*err_handler)(int type, int code, unsigned char *buff,
 				       __u32 daddr,
 				       __u32 saddr,
-				       struct inet_protocol *protocol);
+				       struct inet_protocol *protocol, int len);
   struct inet_protocol *next;
   unsigned char		protocol;
   unsigned char		copy:1;
diff -u --recursive --new-file v2.0.25/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.0.25/linux/include/net/tcp.h	Mon Sep  2 15:18:26 1996
+++ linux/include/net/tcp.h	Thu Nov 14 15:20:10 1996
@@ -129,7 +129,7 @@
 extern struct tcp_mib tcp_statistics;
 
 extern void	tcp_err(int type, int code, unsigned char *header, __u32 daddr,
-			__u32, struct inet_protocol *protocol);
+			__u32, struct inet_protocol *protocol, int len);
 extern void	tcp_shutdown (struct sock *sk, int how);
 extern int	tcp_rcv(struct sk_buff *skb, struct device *dev,
 			struct options *opt, __u32 daddr,
diff -u --recursive --new-file v2.0.25/linux/include/net/udp.h linux/include/net/udp.h
--- v2.0.25/linux/include/net/udp.h	Mon May 20 08:32:19 1996
+++ linux/include/net/udp.h	Thu Nov 14 15:20:10 1996
@@ -32,7 +32,7 @@
 
 
 extern void	udp_err(int type, int code, unsigned char *header, __u32 daddr,
-			__u32 saddr, struct inet_protocol *protocol);
+			__u32 saddr, struct inet_protocol *protocol, int len);
 extern void	udp_send_check(struct udphdr *uh, __u32 saddr, 
 			__u32 daddr, int len, struct sock *sk);
 extern int	udp_recvfrom(struct sock *sk, unsigned char *to,
diff -u --recursive --new-file v2.0.25/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.0.25/linux/net/appletalk/ddp.c	Fri May 31 13:46:27 1996
+++ linux/net/appletalk/ddp.c	Thu Nov 14 15:20:10 1996
@@ -1085,7 +1085,7 @@
 	err=verify_area(VERIFY_WRITE,optval,sizeof(int));
 	if (err) 
 		return err;
-	put_user(val,optval);
+	put_user(val,(int *)optval);
 	return(0);
 }
 
diff -u --recursive --new-file v2.0.25/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.0.25/linux/net/ax25/af_ax25.c	Sat Aug 10 10:03:16 1996
+++ linux/net/ax25/af_ax25.c	Thu Nov 14 15:20:10 1996
@@ -1034,7 +1034,7 @@
 	if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0)
 		return err;
 
-	put_user(val, optval);
+	put_user(val, (int *)optval);
 
 	return 0;
 }
diff -u --recursive --new-file v2.0.25/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.0.25/linux/net/ipv4/icmp.c	Wed Nov 13 11:26:23 1996
+++ linux/net/ipv4/icmp.c	Thu Nov 14 15:20:10 1996
@@ -642,8 +642,15 @@
 	unsigned char *dp;	
 	int match_addr=0;
 	
+	if(len<sizeof(struct iphdr))
+		goto flush_it;
+		
 	iph = (struct iphdr *) (icmph + 1);
 	
+	len-=iph->ihl<<2;
+	if(len<0)
+		goto flush_it;
+	
 	dp= ((unsigned char *)iph)+(iph->ihl<<2);
 	
 	if(icmph->type==ICMP_DEST_UNREACH)
@@ -784,12 +791,13 @@
 			if (iph->protocol == ipprot->protocol && ipprot->err_handler) 
 			{
 				ipprot->err_handler(icmph->type, icmph->code, dp,
-					    iph->daddr, iph->saddr, ipprot);
+					    iph->daddr, iph->saddr, ipprot, len);
 			}
 
 			ipprot = nextip;
 		}
 	}
+flush_it:
 	kfree_skb(skb, FREE_READ);
 }
 
@@ -806,6 +814,9 @@
 	/*
 	 *	Get the copied header of the packet that caused the redirect
 	 */
+	
+	if(len<=sizeof(struct iphdr))
+		goto flush_it;
 	 
 	iph = (struct iphdr *) (icmph + 1);
 	ip = iph->daddr;
@@ -861,7 +872,7 @@
   	/*
   	 *	Discard the original packet
   	 */
-  	 
+flush_it:
   	kfree_skb(skb, FREE_READ);
 }
 
diff -u --recursive --new-file v2.0.25/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v2.0.25/linux/net/ipv4/igmp.c	Thu Oct 31 12:08:55 1996
+++ linux/net/ipv4/igmp.c	Thu Nov 14 15:20:10 1996
@@ -61,6 +61,9 @@
  *					miscalculation fixed in igmp_heard_query
  *					and random() made to return unsigned to
  *					prevent negative expiry times.
+ *		Alexey Kuznetsov:	Wrong group leaving behaviour, backport
+ *					fix from pending 2.1.x patches.
+ *		Alan Cox:		Forget to enable FDDI support earlier.
  */
 
 
@@ -278,6 +281,7 @@
 		igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
 	else
 		igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
+	im->reporter=1;
 }
 
 static void igmp_init_timer(struct ip_mc_list *im)
@@ -289,17 +293,24 @@
 }
 
 
-static void igmp_heard_report(struct device *dev, unsigned long address)
+static void igmp_heard_report(struct device *dev, __u32 address, __u32 src)
 {
 	struct ip_mc_list *im;
 
-	if ((address & IGMP_LOCAL_GROUP_MASK) != IGMP_LOCAL_GROUP) {
-	  /* Timers are only set for non-local groups */
-	  for(im=dev->ip_mc_list;im!=NULL;im=im->next) {
-	    if(im->multiaddr==address && im->tm_running) {
-	      igmp_stop_timer(im);
-	    }
-	  }
+	if ((address & IGMP_LOCAL_GROUP_MASK) != IGMP_LOCAL_GROUP) 
+	{
+		/* Timers are only set for non-local groups */
+		for(im=dev->ip_mc_list;im!=NULL;im=im->next) 
+		{
+			if(im->multiaddr==address)
+			{
+				if(im->tm_running) 
+					igmp_stop_timer(im);
+				if(src!=dev->pa_addr)
+					im->reporter=0;
+				return;
+			}
+		}
 	}
 }
 
@@ -391,8 +402,8 @@
 void ip_mc_filter_add(struct device *dev, unsigned long addr)
 {
 	char buf[6];
-	if(dev->type!=ARPHRD_ETHER)
-		return; /* Only do ethernet now */
+	if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_FDDI)
+		return; /* Only do ethernet or FDDI for now */
 	ip_mc_map(addr,buf);
 	dev_mc_add(dev,buf,ETH_ALEN,0);
 }
@@ -404,8 +415,8 @@
 void ip_mc_filter_del(struct device *dev, unsigned long addr)
 {
 	char buf[6];
-	if(dev->type!=ARPHRD_ETHER)
-		return; /* Only do ethernet now */
+	if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_FDDI)
+		return; /* Only do ethernet or FDDI for now */
 	ip_mc_map(addr,buf);
 	dev_mc_delete(dev,buf,ETH_ALEN,0);
 }
@@ -473,9 +484,9 @@
 	if(ih->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS)
 		igmp_heard_query(dev,ih->code);
 	if(ih->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==ih->group)
-		igmp_heard_report(dev,ih->group);
+		igmp_heard_report(dev,ih->group, saddr);
 	if(ih->type==IGMP_HOST_NEW_MEMBERSHIP_REPORT && daddr==ih->group)
-		igmp_heard_report(dev,ih->group);
+		igmp_heard_report(dev,ih->group, saddr);
 	kfree_skb(skb, FREE_READ);
 	return 0;
 }
diff -u --recursive --new-file v2.0.25/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.0.25/linux/net/ipv4/ip_fragment.c	Thu Oct 31 12:08:55 1996
+++ linux/net/ipv4/ip_fragment.c	Fri Nov 22 11:58:34 1996
@@ -10,6 +10,8 @@
  *
  * Fixes:
  *		Alan Cox	:	Split from ip.c , see ip_input.c for history.
+ *		Alan Cox	:	Handling oversized frames
+ *		Uriel Maimon	:	Accounting errors in two fringe cases.
  */
 
 #include <linux/types.h>
@@ -486,7 +488,7 @@
 	{
 		skb->sk = NULL;
 		printk("Oversized packet received from %s\n",in_ntoa(iph->saddr));
-		frag_kfree_skb(skb, FREE_READ);
+		kfree_skb(skb, FREE_READ);
 		ip_statistics.IpReasmFails++;
 		return NULL;
 	}	
@@ -554,6 +556,9 @@
 		/*
 		 *	If we get a frag size of <= 0, remove it and the packet
 		 *	that it goes with.
+		 *
+		 *	We never throw the new frag away, so the frag being
+		 *	dumped has always been charged for.
 		 */
 		if (tmp->len <= 0)
 		{
@@ -580,15 +585,21 @@
 	tfp = ip_frag_create(offset, end, skb, ptr);
 
 	/*
-	 *	No memory to save the fragment - so throw the lot
+	 *	No memory to save the fragment - so throw the lot. If we
+	 *	failed the frag_create we haven't charged the queue.
 	 */
 
 	if (!tfp)
 	{
 		skb->sk = NULL;
-		frag_kfree_skb(skb, FREE_READ);
+		kfree_skb(skb, FREE_READ);
 		return NULL;
 	}
+	
+	/*
+	 *	From now on our buffer is charged to the queues.
+	 */
+	 
 	tfp->prev = prev;
 	tfp->next = next;
 	if (prev != NULL)
diff -u --recursive --new-file v2.0.25/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.0.25/linux/net/ipv4/ipmr.c	Thu Oct 31 12:08:55 1996
+++ linux/net/ipv4/ipmr.c	Thu Nov 14 15:20:10 1996
@@ -542,7 +542,7 @@
 				return -EINVAL;
 			if((err=verify_area(VERIFY_READ, optval,sizeof(int)))<0)
 				return err;
-			mroute_do_pim= (optval)?1:0;
+			mroute_do_pim= get_user((int *)optval)?1:0;
 			return 0;
 		/*
 		 *	Spurious command, or MRT_VERSION which you cannot
diff -u --recursive --new-file v2.0.25/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.0.25/linux/net/ipv4/tcp.c	Wed Nov 13 11:26:24 1996
+++ linux/net/ipv4/tcp.c	Thu Nov 14 20:56:46 1996
@@ -502,7 +502,7 @@
  */
 
 void tcp_err(int type, int code, unsigned char *header, __u32 daddr,
-	__u32 saddr, struct inet_protocol *protocol)
+	__u32 saddr, struct inet_protocol *protocol, int len)
 {
 	struct tcphdr *th = (struct tcphdr *)header;
 	struct sock *sk;
@@ -514,6 +514,10 @@
 	struct iphdr *iph=(struct iphdr *)(header-sizeof(struct iphdr));
 #endif
 	th =(struct tcphdr *)header;
+	
+	if(len<sizeof(struct tcphdr))
+		return;
+		
 	sk = get_sock(&tcp_prot, th->source, daddr, th->dest, saddr, 0, 0);
 
 	if (sk == NULL)
@@ -1420,6 +1424,8 @@
 			if (copied)
 				break;
 			copied = -ERESTARTSYS;
+			if (nonblock)
+				copied = -EAGAIN;
 			break;
 		}
 
diff -u --recursive --new-file v2.0.25/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.0.25/linux/net/ipv4/tcp_input.c	Thu Oct 31 12:08:56 1996
+++ linux/net/ipv4/tcp_input.c	Fri Nov 22 11:58:34 1996
@@ -202,7 +202,7 @@
   	 
 	if (sk->state==TCP_SYN_SENT || sk->state==TCP_SYN_RECV) 
 	{
-		tcp_send_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl);
+		tcp_send_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev,0,255);
 		return;
 	}
 
@@ -248,11 +248,18 @@
 	/*
 	 *	We want the right error as BSD sees it (and indeed as we do).
 	 */
-	sk->err = ECONNRESET;
-	if (sk->state == TCP_SYN_SENT)
+	switch (sk->state) {
+	case TCP_TIME_WAIT:
+		break;
+	case TCP_SYN_SENT:
 		sk->err = ECONNREFUSED;
-	if (sk->state == TCP_CLOSE_WAIT)
+		break;
+	case TCP_CLOSE_WAIT:
 		sk->err = EPIPE;
+		break;
+	default:
+		sk->err = ECONNRESET;
+	}
 #ifdef CONFIG_TCP_RFC1337
 	/*
 	 *	Time wait assassination protection [RFC1337]
@@ -368,7 +375,7 @@
 	{
 		if(sk->debug)
 			printk("Reset on %p: Connect on dead socket.\n",sk);
-		tcp_send_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl);
+		tcp_send_reset(daddr, saddr, th, sk->prot, opt, dev, 0,255);
 		tcp_statistics.TcpAttemptFails++;
 		kfree_skb(skb, FREE_READ);
 		return;
@@ -1558,7 +1565,7 @@
 				{
 					sk->acked_seq = new_seq + th->fin;
 					tcp_send_reset(sk->saddr, sk->daddr, skb->h.th,
-						sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl);
+						sk->prot, NULL, skb->dev, 0, 255);
 					tcp_statistics.TcpEstabResets++;
 					sk->err = EPIPE;
 					sk->error_report(sk);
@@ -1863,7 +1870,7 @@
 		if(sk->state==TCP_LISTEN)
 		{
 			if(th->ack)	/* These use the socket TOS.. might want to be the received TOS */
-				tcp_send_reset(daddr,saddr,th,sk->prot,opt,dev,sk->ip_tos, sk->ip_ttl);
+				tcp_send_reset(daddr,saddr,th,sk->prot,opt,dev,0, 255);
 
 			/*
 			 *	We don't care for RST, and non SYN are absorbed (old segments)
@@ -1944,7 +1951,7 @@
 					   different connection  [ th->rst is checked in tcp_send_reset()] */
 					tcp_statistics.TcpAttemptFails++;
 					tcp_send_reset(daddr, saddr, th,
-						sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
+						sk->prot, opt,dev,0,255);
 					kfree_skb(skb, FREE_READ);
 					return(0);
 				}
@@ -1956,7 +1963,7 @@
 					   start. Shouldn't happen but cover it */
 	         			tcp_statistics.TcpAttemptFails++;
 	                                tcp_send_reset(daddr, saddr, th,
-	                                        sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
+	                                        sk->prot, opt,dev,0,255);
 					kfree_skb(skb, FREE_READ);
 					return 0;
 				}
@@ -2103,7 +2110,7 @@
 	 
 	if(th->syn && skb->seq!=sk->syn_seq)
 	{
-		tcp_send_reset(daddr,saddr,th, &tcp_prot, opt, dev, skb->ip_hdr->tos, 255);
+		tcp_send_reset(daddr,saddr,th, &tcp_prot, opt, dev,0, 255);
 		return tcp_reset(sk,skb);	
 	}
 
@@ -2120,7 +2127,7 @@
 		 
 		if(sk->state==TCP_SYN_RECV)
 		{
-			tcp_send_reset(daddr, saddr, th,sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl);
+			tcp_send_reset(daddr, saddr, th,sk->prot, opt, dev,0,255);
 		}
 		kfree_skb(skb, FREE_READ);
 		return 0;
@@ -2164,7 +2171,7 @@
 	/*
 	 *	No such TCB. If th->rst is 0 send a reset (checked in tcp_send_reset)
 	 */
-	tcp_send_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);
+	tcp_send_reset(daddr, saddr, th, &tcp_prot, opt,dev,0,255);
 
 discard_it:
 	/*
diff -u --recursive --new-file v2.0.25/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.0.25/linux/net/ipv4/udp.c	Tue Oct  8 21:20:15 1996
+++ linux/net/ipv4/udp.c	Thu Nov 14 15:20:11 1996
@@ -151,7 +151,7 @@
  */
 
 void udp_err(int type, int code, unsigned char *header, __u32 daddr,
-	__u32 saddr, struct inet_protocol *protocol)
+	__u32 saddr, struct inet_protocol *protocol, int len)
 {
 	struct udphdr *uh;
 	struct sock *sk;
@@ -159,6 +159,9 @@
 	/*
 	 *	Find the 8 bytes of post IP header ICMP included for us
 	 */  
+	 
+	if(len<sizeof(struct udphdr))
+		return;
 	
 	uh = (struct udphdr *)header;  
    
diff -u --recursive --new-file v2.0.25/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.0.25/linux/net/unix/af_unix.c	Tue Oct  8 21:20:15 1996
+++ linux/net/unix/af_unix.c	Sat Nov  9 10:53:54 1996
@@ -679,7 +679,7 @@
  *	Support routines for struct cmsghdr handling
  */
  
-static struct cmsghdr *unix_copyrights(void *userp, int len)
+static struct cmsghdr *unix_copyrights(void *userp, int len) /* AT&T ? */
 {
 	struct cmsghdr *cm;
 
@@ -724,9 +724,6 @@
 		int fd;
 		
 		fd = fdp[i];	
-#if 0
-		printk("testing  fd %d\n", fd);
-#endif
 		if (fd < 0 || fd >= NR_OPEN)
 			return -EBADF;
 		if (current->files->fd[fd]==NULL)
@@ -1106,9 +1103,9 @@
 					return copied;
 				if(noblock)
 					return -EAGAIN;
+				unix_data_wait(sk);
 				if(current->signal & ~current->blocked)
 					return -ERESTARTSYS;
-				unix_data_wait(sk);
 				down(&sk->protinfo.af_unix.readsem);
 				continue;
 			}
@@ -1297,7 +1294,7 @@
 
 void unix_proto_init(struct net_proto *pro)
 {
-	printk(KERN_INFO "NET3: Unix domain sockets 0.12 for Linux NET3.035.\n");
+	printk(KERN_INFO "NET3: Unix domain sockets 0.13 for Linux NET3.035.\n");
 	sock_register(unix_proto_ops.family, &unix_proto_ops);
 #ifdef CONFIG_PROC_FS
 	proc_net_register(&(struct proc_dir_entry) {
