diff -u --recursive --new-file v2.1.126/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.126/linux/Documentation/Configure.help	Fri Oct 23 22:01:18 1998
+++ linux/Documentation/Configure.help	Thu Nov  5 09:56:15 1998
@@ -4058,24 +4058,46 @@
   say M here and read Documentation/modules.txt. The module will be
   called NCR53c406.o.
 
-Tekram DC390(T) (AMD PCscsi) SCSI support
+Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support
 CONFIG_SCSI_DC390T
-  This driver supports the Tekram DC390(T) PCI SCSI host adapter with
-  the Am53C974A chip, and perhaps other cards using the same chip.
-  This driver does _not_ support the DC390W/U/F adaptor with the
-  NCR/Symbios chips; use "NCR53C8XX SCSI support" for that one.
+  This driver supports  PCI SCSI host adapters  based on the Am53C974A
+  chip,  e.g.  Tekram DC390(T),  DawiControl 2974  and  some   onboard
+  PCscsi/PCnet (Am53/79C974) solutions.
+  Documentation can be found in linux/drivers/scsi/README.tmscsim.
+  
+  Note that this driver  does NOT support Tekram DC390W/U/F, which are
+  based on NCR/Symbios chips. Use the NCR53C8XX driver for those.
+  Also note, that there is another generic Am53C974 driver.
 
   If you want to compile this driver 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. The module will be
+  inserted in and removed from the running kernel  whenever you want),
+  say M here  and read Documentation/modules.txt.  The module  will be
   called tmscsim.o.
 
+Skip support for other Am53/79C974 based SCSI adapters
+CONFIG_SCSI_DC390T_NOGENSUPP
+  Normally, the DC390(T) SCSI driver relies on the DC390 EEPROM to get
+  initial values  for its settings,  such as speed,  termination, etc.
+  If  it can't find  this EEPROM, it  will use  defaults  or  the user
+  supplied boot/module parameters. For details on driver configuration
+  see linux/drivers/scsi/README.tmscsim.
+
+  With this option set, if no EEPROM is found, the driver gives up and
+  thus only supports  Tekram DC390(T) adapters.  This can be useful if
+  you have a DC390(T)  and another Am53C974 based adapter,  which, for
+  some reason, you want to drive with the other AM53C974 driver.
+
+  If unsure, say N.
+
 AM53/79C974 PCI SCSI support
 CONFIG_SCSI_AM53C974
   This is support for the AM53/79C974 SCSI host adapters. Please read
   drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO,
   available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you. 
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you.
+
+  Note that there is another driver for AM53C974 based adapters: The
+  Tekram DC390(T) driver.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -7224,10 +7246,10 @@
 
 Specialix IO8+ card support
 CONFIG_SPECIALIX
-  This is a driver for the Specialix IO8+ multiport card which gives
-  you many serial ports. You would need something like this to 
-  connect more than two modems to your Linux box, for instance in
-  order to become a BBS. 
+  This is a driver for the Specialix IO8+ multiport card (both the
+  ISA and the PCI version) which gives you many serial ports. You 
+  would need something like this to connect more than two modems to 
+  your Linux box, for instance in order to become a BBS. 
 
   If you have a card like that, say Y here and read the file
   Documentation/specialix.txt. Also it's possible to say M here and
diff -u --recursive --new-file v2.1.126/linux/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd
--- v2.1.126/linux/Documentation/cdrom/ide-cd	Mon Aug  3 12:45:43 1998
+++ linux/Documentation/cdrom/ide-cd	Sat Oct 24 10:43:47 1998
@@ -1,6 +1,8 @@
 IDE-CD driver documentation
 Originally by scott snyder  <snyder@fnald0.fnal.gov> (19 May 1996)
 Carrying on the torch is: Erik Andersen <andersee@debian.org>
+New maintainers (19 Oct 1998): Jens Axboe <axboe@image.dk>
+                               Chris Zwilling <chris@cloudnet.com>
 
 1. Introduction
 ---------------
diff -u --recursive --new-file v2.1.126/linux/Documentation/specialix.txt linux/Documentation/specialix.txt
--- v2.1.126/linux/Documentation/specialix.txt	Sat May  2 14:19:52 1998
+++ linux/Documentation/specialix.txt	Wed Oct 28 22:04:05 1998
@@ -17,7 +17,10 @@
       written by Dmitry Gorodchanin. The specialix IO8+ card
       programming information was obtained from the CL-CD1865 Data
       Book, and Specialix document number 6200059: IO8+ Hardware
-      Functional Specification.
+      Functional Specification, augmented by document number 6200088:
+      Merak Hardware Functional Specification. (IO8+/PCI is also 
+      called Merak)
+
 
       This program is free software; you can redistribute it and/or
       modify it under the terms of the GNU General Public License as
@@ -67,6 +70,9 @@
 other computer runs just fine with the Specialix card at 0x100....
 The card occupies 4 addresses, but actually only two are really used.
 
+The PCI version doesn't have any dip switches. The BIOS assigns
+an IO address. 
+
 The driver now still autoprobes at 0x100, 0x180, 0x250 and 0x260.  If
 that causes trouble for you, please report that. I'll remove
 autoprobing then.
@@ -75,6 +81,9 @@
 change any jumpers to change the IRQ. Just use a command line
 argument (irq=xx) to the insmod program to set the interrupt.
 
+The BIOS assigns the IRQ on the PCI version. You have no say in what
+IRQ to use in that case. 
+
 If your specialix cards are not at the default locations, you can use
 the kernel command line argument "specialix=io0,irq0,io1,irq1...".
 Here "io0" is the io address for the first card, and "irq0" is the
@@ -99,6 +108,32 @@
 
 in your /etc/lilo.conf file if you use lilo. 
 
+The Specialix driver is slightly odd: It allows you to have the second
+or third card detected without having a first card. This has
+advantages and disadvantages. A slot that isn't filled by an ISA card,
+might be filled if a PCI card is detected. Thus if you have an ISA
+card at 0x250 and a PCI card, you would get:
+
+sx0: specialix IO8+ Board at 0x100 not found.
+sx1: specialix IO8+ Board at 0x180 not found.
+sx2: specialix IO8+ board detected at 0x250, IRQ 12, CD1865 Rev. B.
+sx3: specialix IO8+ Board at 0x260 not found.
+sx0: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
+
+This would happen if you don't give any probe hints to the driver. 
+If you would specify:
+
+   specialix=0x250,11
+
+you'd get the following messages:
+
+sx0: specialix IO8+ board detected at 0x250, IRQ 11, CD1865 Rev. B.
+sx1: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
+
+ISA probing is aborted after the IO address you gave is exhausted, and
+the PCI card is now detected as the second card. The ISA card is now
+also forced to IRQ11....
+
 
 Baud rates
 ==========
@@ -118,20 +153,26 @@
 If you near the "limit" you will first start to see a graceful
 degradation in that the chip cannot keep the transmitter busy at all
 times. However with a central clock this slow, you can also get it to
-miss incoming characters.
+miss incoming characters. The driver will print a warning message when
+you are outside the official specs. The messages usually show up in
+the file /var/log/messages .
 
 The specialix card cannot reliably do 115k2. If you use it, you have
 to do "extensive testing" (*) to verify if it actually works.
 
 When "mgetty" communicates with my modem at 115k2 it reports:
 got: +++[0d]ATQ0V1H0[0d][0d][8a]O[cb][0d][8a]
-                            ^^^^ ^^^^ ^^^^ 
+                            ^^^^ ^^^^    ^^^^ 
 
 The three characters that have the "^^^" under them have suffered a
 bit error in the highest bit. In conclusion: I've tested it, and found
 that it simply DOESN'T work for me. I also suspect that this is also
 caused by the baud rate being just a little bit out of tune. 
 
+I upgraded the crystal to 66Mhz on one of my Specialix cards. Works
+great! Contact me for details. (Voids warranty, requires a steady hand
+and more such restrictions....)
+
 
 (*) Cirrus logic CD1864 databook, page 40.
 
@@ -248,7 +289,7 @@
 Ports and devices
 =================
 
-Port 0 is the one furthest from the ISA connector.
+Port 0 is the one furthest from the card-edge connector.
 
 Devices:
 
@@ -265,10 +306,20 @@
 done
 echo ""
 
+If your system doesn't come with these devices preinstalled, bug your
+linux-vendor about this. They have had ample time to get this
+implemented by now.
 
 You cannot have more than 4 boards in one computer. The card only
 supports 4 different interrupts. If you really want this, contact me
 about this and I'll give you a few tips (requires soldering iron)....
+
+If you have enough PCI slots, you can probably use more than 4 PCI
+versions of the card though.... 
+
+The PCI version of the card cannot adhere to the mechanical part of
+the PCI spec because the 8 serial connectors are simply too large. If
+it doesn't fit in your computer, bring back the card.
 
 
 ------------------------------------------------------------------------
diff -u --recursive --new-file v2.1.126/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.126/linux/MAINTAINERS	Fri Oct 23 22:01:19 1998
+++ linux/MAINTAINERS	Tue Oct 27 10:10:08 1998
@@ -186,6 +186,12 @@
 L:	linux-hams@vger.rutgers.edu
 S:	Maintained
 
+DC390/AM53C974 SCSI driver
+P:	Kurt Garloff
+M:	K.Garloff@ping.de
+W:	ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+S:	Maintained
+
 DECnet NETWORK LAYER
 P:	Steven Whitehouse
 M:	SteveW@ACM.org
@@ -328,8 +334,10 @@
 S:	Odd Fixes
 
 IDE/ATAPI CDROM DRIVER 
-P:	Erik Andersen
-M:	andersee@debian.org
+P:	Jens Axboe
+M:	axboe@image.dk
+P:	Chris Zwilling
+M:	chris@cloudnet.com
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
@@ -671,8 +679,10 @@
 S:	Maintained
 
 UNIFORM CDROM DRIVER 
-P:	Erik Andersen
-M:	andersee@debian.org
+P:	Jens Axboe
+M:	axboe@image.dk
+P:	Chris Zwilling
+M:	chris@cloudnet.com
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
diff -u --recursive --new-file v2.1.126/linux/Makefile linux/Makefile
--- v2.1.126/linux/Makefile	Fri Oct 23 22:01:19 1998
+++ linux/Makefile	Fri Oct 23 22:03:09 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 126
+SUBLEVEL = 127
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -u --recursive --new-file v2.1.126/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.126/linux/arch/alpha/defconfig	Wed Sep  9 14:51:03 1998
+++ linux/arch/alpha/defconfig	Wed Oct 28 22:10:04 1998
@@ -241,7 +241,6 @@
 # CONFIG_PC110_PAD is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
diff -u --recursive --new-file v2.1.126/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.1.126/linux/arch/alpha/kernel/osf_sys.c	Thu Sep 17 17:53:34 1998
+++ linux/arch/alpha/kernel/osf_sys.c	Thu Nov  5 09:58:29 1998
@@ -1306,6 +1306,7 @@
 {
 	struct timeval tmp;
 	unsigned long ticks;
+	unsigned long tmp_timeout;
 
 	if (get_tv32(&tmp, sleep))
 		goto fault;
@@ -1313,18 +1314,11 @@
 	ticks = tmp.tv_usec;
 	ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
 	ticks += tmp.tv_sec * HZ;
-	current->timeout = ticks + jiffies;
-	current->state = TASK_INTERRUPTIBLE;
 
-	schedule();
+	current->state = TASK_INTERRUPTIBLE;
+	ticks = schedule_timeout(ticks);
 
 	if (remain) {
-		ticks = jiffies;
-		if (ticks < current->timeout)
-			ticks = current->timeout - ticks;
-		else
-			ticks = 0;
-		current->timeout = 0;
 		tmp.tv_sec = ticks / HZ;
 		tmp.tv_usec = ticks % HZ;
 		if (put_tv32(remain, &tmp))
diff -u --recursive --new-file v2.1.126/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c
--- v2.1.126/linux/arch/alpha/kernel/sys_sio.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_sio.c	Tue Oct 27 23:02:57 1998
@@ -110,6 +110,9 @@
  *
  * This probably ought to be configurable via MILO.  For
  * example, sound boards seem to like using IRQ 9.
+ *
+ * This is NOT how we should do it. PIRQ0-X should have
+ * their own IRQ's, the way intel uses the IO-APIC irq's.
  */
 static unsigned long sio_route_tab __initdata = 0;
 
@@ -238,7 +241,7 @@
 avanti_pci_fixup(void)
 {
 	layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE);
-	sio_pci_fixup(noname_map_irq, 0x0b0a090f);
+	sio_pci_fixup(noname_map_irq, 0x0b0a0e0f);
 	sio_fixup_irq_levels(sio_collect_irq_levels());
         enable_ide(0x26e);
 }
diff -u --recursive --new-file v2.1.126/linux/arch/i386/boot/tools/build.c linux/arch/i386/boot/tools/build.c
--- v2.1.126/linux/arch/i386/boot/tools/build.c	Wed Jun 24 22:54:03 1998
+++ linux/arch/i386/boot/tools/build.c	Sun Oct 25 14:16:21 1998
@@ -151,7 +151,7 @@
 	if (setup_sectors < SETUP_SECTS)
 		setup_sectors = SETUP_SECTS;
 	fprintf(stderr, "Setup is %d bytes.\n", i);
-	memset(buf, sizeof(buf), 0);
+	memset(buf, 0, sizeof(buf));
 	while (i < setup_sectors * 512) {
 		c = setup_sectors * 512 - i;
 		if (c > sizeof(buf))
diff -u --recursive --new-file v2.1.126/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.126/linux/arch/i386/defconfig	Fri Oct 23 22:01:19 1998
+++ linux/arch/i386/defconfig	Wed Nov  4 11:27:42 1998
@@ -146,8 +146,7 @@
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
-CONFIG_SCSI_BUSLOGIC=y
-CONFIG_SCSI_OMIT_FLASHPOINT=y
+# CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA_DMA is not set
 # CONFIG_SCSI_EATA_PIO is not set
@@ -157,7 +156,12 @@
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
diff -u --recursive --new-file v2.1.126/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.1.126/linux/arch/i386/kernel/entry.S	Thu Sep 17 17:53:34 1998
+++ linux/arch/i386/kernel/entry.S	Tue Oct 27 10:20:47 1998
@@ -107,7 +107,7 @@
 2:	popl %es;	\
 	addl $4,%esp;	\
 3:	iret;		\
-.section fixup,"ax";	\
+.section .fixup,"ax";	\
 4:	movl $0,(%esp);	\
 	jmp 1b;		\
 5:	movl $0,(%esp);	\
diff -u --recursive --new-file v2.1.126/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.1.126/linux/arch/i386/kernel/setup.c	Fri Oct 23 22:01:19 1998
+++ linux/arch/i386/kernel/setup.c	Sat Oct 31 14:23:34 1998
@@ -81,6 +81,7 @@
 
 extern int root_mountflags;
 extern int _etext, _edata, _end;
+extern unsigned long cpu_hz;
 
 /*
  * This is set up by the setup-routine at boot-time
@@ -617,6 +618,11 @@
 				p += sprintf(p, "stepping\t: %d\n", c->x86_mask);
 		} else
 			p += sprintf(p, "stepping\t: unknown\n");
+
+		if (c->x86_capability & X86_FEATURE_TSC) {
+			p += sprintf(p, "cpu MHz\t\t: %lu.%06lu\n",
+				cpu_hz / 1000000, (cpu_hz % 1000000));
+		}
 
 		/* Cache size */
 		if (c->x86_cache_size >= 0)
diff -u --recursive --new-file v2.1.126/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.1.126/linux/arch/i386/mm/fault.c	Fri Oct  9 13:27:05 1998
+++ linux/arch/i386/mm/fault.c	Tue Oct 27 10:18:35 1998
@@ -156,7 +156,14 @@
 			if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 				goto bad_area;
 	}
-	handle_mm_fault(tsk, vma, address, write);
+
+	/*
+	 * If for any reason at all we couldn't handle the fault,
+	 * make sure we exit gracefully rather than endlessly redo
+	 * the fault.
+	 */
+	if (!handle_mm_fault(tsk, vma, address, write))
+		goto do_sigbus;
 
 	/*
 	 * Did it hit the DOS screen memory VA from vm86 mode?
@@ -243,4 +250,24 @@
 	}
 	die("Oops", regs, error_code);
 	do_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+do_sigbus:
+	up(&mm->mmap_sem);
+
+	/*
+	 * Send a sigbus, regardless of whether we were in kernel
+	 * or user mode.
+	 */
+	tsk->tss.cr2 = address;
+	tsk->tss.error_code = error_code;
+	tsk->tss.trap_no = 14;
+	force_sig(SIGBUS, tsk);
+
+	/* Kernel mode? Handle exceptions or die */
+	if (!(error_code & 4))
+		goto no_context;
 }
diff -u --recursive --new-file v2.1.126/linux/arch/m68k/atari/time.c linux/arch/m68k/atari/time.c
--- v2.1.126/linux/arch/m68k/atari/time.c	Tue Jun 23 10:01:20 1998
+++ linux/arch/m68k/atari/time.c	Thu Nov  5 09:58:29 1998
@@ -279,8 +279,7 @@
 
     while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
         current->state = TASK_INTERRUPTIBLE;
-        current->timeout = jiffies + HWCLK_POLL_INTERVAL;
-        schedule();
+        schedule_timeout(HWCLK_POLL_INTERVAL);
     }
 
     save_flags(flags);
diff -u --recursive --new-file v2.1.126/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c
--- v2.1.126/linux/arch/mips/kernel/irixsig.c	Fri Oct 23 22:01:19 1998
+++ linux/arch/mips/kernel/irixsig.c	Thu Nov  5 09:58:29 1998
@@ -568,7 +568,7 @@
 asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info,
 				struct timespec *tp)
 {
-	unsigned long expire = 0;
+	long expire = MAX_SCHEDULE_TIMEOUT;
 	sigset_t kset;
 	int i, sig, error, timeo = 0;
 
@@ -603,21 +603,21 @@
 			error = -EINVAL;
 			goto out;
 		}
-		expire = timespectojiffies(tp)+(tp->tv_sec||tp->tv_nsec)+jiffies;
-		current->timeout = expire;
+		expire = timespectojiffies(tp)+(tp->tv_sec||tp->tv_nsec);
 	}
 
 	while(1) {
 		long tmp = 0;
 
-		current->state = TASK_INTERRUPTIBLE; schedule();
+		current->state = TASK_INTERRUPTIBLE;
+		expire = schedule_timeout(expire);
 
 		for (i=0; i<=4; i++)
 			tmp |= (current->signal.sig[i] & kset.sig[i]);
 
 		if (tmp)
 			break;
-		if (tp && expire <= jiffies) {
+		if (!expire) {
 			timeo = 1;
 			break;
 		}
diff -u --recursive --new-file v2.1.126/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.1.126/linux/arch/mips/kernel/sysirix.c	Fri Oct 23 22:01:19 1998
+++ linux/arch/mips/kernel/sysirix.c	Thu Nov  5 09:58:29 1998
@@ -1081,13 +1081,8 @@
 
 asmlinkage int irix_sginap(int ticks)
 {
-	lock_kernel();
-	if(ticks) {
-		current->timeout = ticks + jiffies;
-		current->state = TASK_INTERRUPTIBLE;
-	}
-	schedule();
-	unlock_kernel();
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(ticks);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.126/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c
--- v2.1.126/linux/arch/mips/sgi/kernel/indy_sc.c	Fri Oct 23 22:01:20 1998
+++ linux/arch/mips/sgi/kernel/indy_sc.c	Mon Oct 26 09:57:55 1998
@@ -5,7 +5,6 @@
  * Copyright (C) 1997 Ralf Baechle (ralf@gnu.org),
  * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com).
  */
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.1.126/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c
--- v2.1.126/linux/arch/mips/sgi/kernel/setup.c	Fri Oct 23 22:01:20 1998
+++ linux/arch/mips/sgi/kernel/setup.c	Mon Oct 26 09:57:55 1998
@@ -5,6 +5,7 @@
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
  */
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/kbd_ll.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.126/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- v2.1.126/linux/arch/ppc/8xx_io/uart.c	Mon Oct  5 13:13:35 1998
+++ linux/arch/ppc/8xx_io/uart.c	Thu Nov  5 09:58:29 1998
@@ -1314,12 +1314,11 @@
 static void send_break(ser_info_t *info, int duration)
 {
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + duration;
 #ifdef SERIAL_DEBUG_SEND_BREAK
 	printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
 #endif
 	begin_break(info);
-	schedule();
+	schedule_timeout(duration);
 	end_break(info);
 #ifdef SERIAL_DEBUG_SEND_BREAK
 	printk("done jiffies=%lu\n", jiffies);
@@ -1633,8 +1632,7 @@
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
+			schedule_timeout(info->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
@@ -1691,8 +1689,7 @@
 #endif
 		current->state = TASK_INTERRUPTIBLE;
 /*		current->counter = 0;	 make us low-priority */
-		current->timeout = jiffies + char_time;
-		schedule();
+		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
 		if (timeout && ((orig_jiffies + timeout) < jiffies))
diff -u --recursive --new-file v2.1.126/linux/arch/ppc/apus_defconfig linux/arch/ppc/apus_defconfig
--- v2.1.126/linux/arch/ppc/apus_defconfig	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/apus_defconfig	Wed Oct 28 22:10:05 1998
@@ -297,7 +297,6 @@
 # CONFIG_UNIX98_PTYS is not set
 # CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
diff -u --recursive --new-file v2.1.126/linux/arch/ppc/chrp_defconfig linux/arch/ppc/chrp_defconfig
--- v2.1.126/linux/arch/ppc/chrp_defconfig	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/chrp_defconfig	Wed Oct 28 22:10:05 1998
@@ -265,7 +265,6 @@
 # CONFIG_MOUSE is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
diff -u --recursive --new-file v2.1.126/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- v2.1.126/linux/arch/ppc/common_defconfig	Thu Aug  6 14:06:29 1998
+++ linux/arch/ppc/common_defconfig	Wed Oct 28 22:10:05 1998
@@ -287,7 +287,6 @@
 # CONFIG_PC110_PAD is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
diff -u --recursive --new-file v2.1.126/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.1.126/linux/arch/ppc/defconfig	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/defconfig	Wed Oct 28 22:10:05 1998
@@ -296,7 +296,6 @@
 # CONFIG_MOUSE is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
diff -u --recursive --new-file v2.1.126/linux/arch/ppc/mbx_defconfig linux/arch/ppc/mbx_defconfig
--- v2.1.126/linux/arch/ppc/mbx_defconfig	Thu Aug  6 14:06:29 1998
+++ linux/arch/ppc/mbx_defconfig	Wed Oct 28 22:10:05 1998
@@ -171,7 +171,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
diff -u --recursive --new-file v2.1.126/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig
--- v2.1.126/linux/arch/ppc/pmac_defconfig	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/pmac_defconfig	Wed Oct 28 22:10:05 1998
@@ -296,7 +296,6 @@
 # CONFIG_MOUSE is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
diff -u --recursive --new-file v2.1.126/linux/arch/ppc/prep_defconfig linux/arch/ppc/prep_defconfig
--- v2.1.126/linux/arch/ppc/prep_defconfig	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/prep_defconfig	Wed Oct 28 22:10:05 1998
@@ -246,7 +246,6 @@
 # CONFIG_PC110_PAD is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile
--- v2.1.126/linux/arch/sparc/boot/Makefile	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/boot/Makefile	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.8 1998/09/16 12:24:51 jj Exp $
+# $Id: Makefile,v 1.9 1998/10/26 20:01:03 davem Exp $
 # Makefile for the Sparc boot stuff.
 #
 # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,10 @@
 	$(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
 	$(NETWORKS) $(DRIVERS)
 
+# I wanted to make this depend upon BTOBJS so that a parallel
+# build would work, but this fails because $(HEAD) cannot work
+# properly as it will cause head.o to be built with the implicit
+# rules not the ones in kernel/Makefile.  Someone please fix. --DaveM
 vmlinux.o: dummy
 	$(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o
 
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.1.126/linux/arch/sparc/defconfig	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/defconfig	Tue Oct 27 09:52:20 1998
@@ -21,6 +21,7 @@
 CONFIG_VT_CONSOLE=y
 # CONFIG_AP1000 is not set
 # CONFIG_SUN4 is not set
+# CONFIG_PCI is not set
 
 #
 # Console drivers
@@ -67,6 +68,7 @@
 # CONFIG_SPARCAUDIO is not set
 # CONFIG_SPARCAUDIO_AMD7930 is not set
 # CONFIG_SPARCAUDIO_CS4231 is not set
+# CONFIG_SPARCAUDIO_DBRI is not set
 CONFIG_SUN_OPENPROMFS=m
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
@@ -74,7 +76,7 @@
 CONFIG_SYSCTL=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
+CONFIG_BINFMT_MISC=m
 CONFIG_BINFMT_JAVA=m
 
 #
@@ -82,51 +84,32 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_STRIPED=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
 CONFIG_MD_MIRRORING=m
 CONFIG_MD_RAID5=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_NBD=m
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-# CONFIG_NETLINK_DEV is not set
-CONFIG_FIREWALL=y
-CONFIG_NET_ALIAS=y
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
+# CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
-CONFIG_IP_FIREWALL=y
-# CONFIG_IP_FIREWALL_NETLINK is not set
-# CONFIG_IP_TRANSPARENT_PROXY is not set
-# CONFIG_IP_ALWAYS_DEFRAG is not set
-CONFIG_IP_MASQUERADE=y
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_ICMP is not set
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_MOD is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
-# CONFIG_ARPD is not set
+# CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
 
 #
@@ -135,7 +118,7 @@
 CONFIG_INET_RARP=m
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
-CONFIG_IPV6=y
+CONFIG_IPV6=m
 # CONFIG_IPV6_EUI64 is not set
 
 #
@@ -145,7 +128,7 @@
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
 CONFIG_ATALK=m
-CONFIG_X25=m
+# CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
@@ -154,18 +137,7 @@
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
-CONFIG_NET_SCHED=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_CSZ=m
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-# CONFIG_NET_SCH_TEQL is not set
-CONFIG_NET_SCH_TBF=y
-# CONFIG_NET_QOS is not set
-# CONFIG_NET_CLS is not set
+# CONFIG_NET_SCHED is not set
 
 #
 # ISDN subsystem
@@ -184,7 +156,7 @@
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SG=m
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -235,21 +207,22 @@
 #
 # Filesystems
 #
-CONFIG_QUOTA=y
+# CONFIG_QUOTA is not set
 CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
+CONFIG_CODA_FS=m
 CONFIG_SMB_FS=m
 CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
@@ -267,13 +240,12 @@
 CONFIG_ROMFS_FS=m
 CONFIG_AUTOFS_FS=m
 CONFIG_AMIGA_PARTITION=y
-CONFIG_UFS_FS=y
+CONFIG_UFS_FS=m
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
-# CONFIG_SOLARIS_X86_PARTITION is not set
+CONFIG_SOLARIS_X86_PARTITION=y
 # CONFIG_ADFS_FS is not set
-CONFIG_QNX4FS_FS=m
-# CONFIG_QNX4FS_RW is not set
+# CONFIG_QNX4FS_FS is not set
 # CONFIG_MAC_PARTITION is not set
 CONFIG_NLS=y
 
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c
--- v2.1.126/linux/arch/sparc/kernel/devices.c	Thu Apr 23 20:21:30 1998
+++ linux/arch/sparc/kernel/devices.c	Tue Oct 27 09:52:20 1998
@@ -1,5 +1,5 @@
 /* devices.c: Initial scan of the prom device tree for important
- *            Sparc device nodes which we need to find.
+ *	      Sparc device nodes which we need to find.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
@@ -14,8 +14,8 @@
 #include <asm/smp.h>
 #include <asm/system.h>
 
-struct prom_cpuinfo linux_cpus[NR_CPUS];
-int linux_num_cpus;
+struct prom_cpuinfo linux_cpus[32];
+int linux_num_cpus = 0;
 
 extern void cpu_probe(void);
 extern void clock_stop_probe(void); /* tadpole.c */
@@ -25,64 +25,55 @@
 device_scan(unsigned long mem_start))
 {
 	char node_str[128];
-	int nd, prom_node_cpu, thismid;
-	int cpu_nds[NR_CPUS];  /* One node for each cpu */
-	int cpu_ctr = 0;
+	int thismid;
 
 	prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
 
 	if(strcmp(node_str, "cpu") == 0) {
-		cpu_nds[0] = prom_root_node;
-		cpu_ctr++;
+		linux_num_cpus++;
 	} else {
 		int scan;
 		scan = prom_getchild(prom_root_node);
 		prom_printf("root child is %08lx\n", (unsigned long) scan);
-		nd = 0;
 		while((scan = prom_getsibling(scan)) != 0) {
 			prom_getstring(scan, "device_type", node_str, sizeof(node_str));
 			if(strcmp(node_str, "cpu") == 0) {
-				cpu_nds[cpu_ctr] = scan;
-				linux_cpus[cpu_ctr].prom_node = scan;
+				linux_cpus[linux_num_cpus].prom_node = scan;
 				prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
-				linux_cpus[cpu_ctr].mid = thismid;
+				linux_cpus[linux_num_cpus].mid = thismid;
 				prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
-					    cpu_ctr, (unsigned long) scan,
+					    linux_num_cpus, (unsigned long) scan,
 					    thismid);
-				cpu_ctr++;
+				linux_num_cpus++;
 			}
 		};
-		if(cpu_ctr == 0) {
+		if(linux_num_cpus == 0) {
 			if (sparc_cpu_model == sun4d) {
 				scan = prom_getchild(prom_root_node);
 				for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
 				     scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
 					int node = prom_getchild(scan);
-					
+
 					prom_getstring(node, "device_type", node_str, sizeof(node_str));
 					if (strcmp(node_str, "cpu") == 0) {
 						prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
-						cpu_nds[cpu_ctr] = node;
-						linux_cpus[cpu_ctr].prom_node = node;
-						linux_cpus[cpu_ctr].mid = thismid;
+						linux_cpus[linux_num_cpus].prom_node = node;
+						linux_cpus[linux_num_cpus].mid = thismid;
 						prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
-							    cpu_ctr, (unsigned long) node,
+							    linux_num_cpus, (unsigned long) node,
 							    thismid);
-						cpu_ctr++;
+						linux_num_cpus++;
 					}
 				}
 			}
 		}
-		if(cpu_ctr == 0) {
+		if(linux_num_cpus == 0) {
 			printk("No CPU nodes found, cannot continue.\n");
 			/* Probably a sun4e, Sun is trying to trick us ;-) */
 			halt();
 		}
-		printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
+		printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
 	};
-	prom_node_cpu = cpu_nds[0];
-
-	linux_num_cpus = cpu_ctr;
 
 	cpu_probe();
 #ifdef CONFIG_SUN_AUXIO
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/ebus.c linux/arch/sparc/kernel/ebus.c
--- v2.1.126/linux/arch/sparc/kernel/ebus.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/ebus.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.1 1998/09/18 10:43:43 jj Exp $
+/* $Id: ebus.c,v 1.2 1998/10/07 11:35:16 jj Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -141,6 +141,9 @@
 		       (unsigned long)sparc_alloc_io (dev->base_address[i], 0,
 						      regs[i].reg_size,
 						      dev->prom_name, 0, 0);
+		    /* Some drivers call 'check_region', so we release it */
+                    release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE);
+
 		    if (dev->base_address[i] == 0 ) {
 			panic("ebus: unable sparc_alloc_io for dev %s",
 			      dev->prom_name);
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/init_task.c linux/arch/sparc/kernel/init_task.c
--- v2.1.126/linux/arch/sparc/kernel/init_task.c	Thu Apr 23 20:21:30 1998
+++ linux/arch/sparc/kernel/init_task.c	Tue Oct 27 09:52:20 1998
@@ -6,7 +6,7 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct files * init_fd_array[NR_OPEN] = { NULL, };
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM;
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v2.1.126/linux/arch/sparc/kernel/irq.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/irq.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.89 1998/09/21 05:05:12 jj Exp $
+/*  $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -8,6 +8,7 @@
  *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
  *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com)
  *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ *  Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
  */
 
 #include <linux/config.h>
@@ -191,13 +192,9 @@
         restore_flags(flags);
 }
 
-/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
+/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */
+unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
-#ifdef __SMP__
-atomic_t __sparc_bh_counter = ATOMIC_INIT(0);
-#else
-int __sparc_bh_counter = 0;
-#endif
 
 #ifdef __SMP__
 /* SMP interrupt locking on Sparc. */
@@ -208,14 +205,33 @@
 /* This protects IRQ's. */
 spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
 
-/* This protects BH software state (masks, things like that). */
-spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
-
 /* Global IRQ locking depth. */
 atomic_t global_irq_count = ATOMIC_INIT(0);
 
+atomic_t global_bh_count = ATOMIC_INIT(0);
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED;
+
 #ifdef DEBUG_IRQLOCK
 
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_bh CPU#%d stuck at %08lx\n", cpu, where); stuck = INIT_STUCK; }
+
+static inline void wait_on_bh(int cpu, unsigned long where)
+{
+	int stuck = INIT_STUCK;
+	do {
+		STUCK;
+		/* nothing .. wait for the other bh's to go away */
+	} while (atomic_read(&global_bh_count) != 0);
+}
+
 static unsigned long previous_irqholder;
 
 #undef INIT_STUCK
@@ -225,36 +241,83 @@
 #define STUCK \
 if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
 
+/*
+ * We have to allow irqs to arrive between __sti and __cli
+ */
+#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+
 static inline void wait_on_irq(int cpu, unsigned long where)
 {
 	int stuck = INIT_STUCK;
 	int local_count = local_irq_count[cpu];
 
-	/* Are we the only one in an interrupt context? */
-	while (local_count != atomic_read(&global_irq_count)) {
+	for (;;) {
+
 		/*
-		 * No such luck. Now we need to release the lock,
-		 * _and_ release our interrupt context, because
-		 * otherwise we'd have dead-locks and live-locks
-		 * and other fun things.
+		 * Wait until all interrupts are gone. Wait
+		 * for bottom half handlers unless we're
+		 * already executing in one..
 		 */
-		atomic_sub(local_count, &global_irq_count);
+		if (!atomic_read(&global_irq_count)) {
+			if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+				break;
+		}
+
+		/* Duh, we have to loop. Release the lock to avoid deadlocks */
 		spin_unlock(&global_irq_lock);
 
-		/*
-		 * Wait for everybody else to go away and release
-		 * their things before trying to get the lock again.
-		 */
 		for (;;) {
 			STUCK;
+
+			__sti();
+			SYNC_OTHER_CORES(cpu);
+			__cli();
+
 			if (atomic_read(&global_irq_count))
 				continue;
 			if (*((unsigned char *)&global_irq_lock))
 				continue;
+			if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+				continue;
 			if (spin_trylock(&global_irq_lock))
 				break;
 		}
-		atomic_add(local_count, &global_irq_count);
+	}
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler. 
+ */
+void synchronize_bh(void)
+{
+	unsigned long where;
+
+	__asm__("mov %%i7, %0" : "=r" (where));
+
+	if (atomic_read(&global_bh_count) && !in_interrupt()) {
+		int cpu = smp_processor_id();
+		wait_on_bh(cpu, where);
+	}
+}
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+void synchronize_irq(void)
+{
+	if (atomic_read(&global_irq_count)) {
+		/* Stupid approach */
+		cli();
+		sti();
 	}
 }
 
@@ -281,54 +344,106 @@
 			} while (*((volatile unsigned char *)&global_irq_lock));
 		} while (!spin_trylock(&global_irq_lock));
 	}
-	/*
-	 * Ok, we got the lock bit.
-	 * But that's actually just the easy part.. Now
-	 * we need to make sure that nobody else is running
+	/* 
+	 * We also to make sure that nobody else is running
 	 * in an interrupt context. 
 	 */
 	wait_on_irq(cpu, where);
 
 	/*
-	 * Finally.
+	 * Ok, finally..
 	 */
 	global_irq_holder = cpu;
 	previous_irqholder = where;
 }
 
+/*
+ * A global "cli()" while in an interrupt context
+ * turns into just a local cli(). Interrupts
+ * should use spinlocks for the (very unlikely)
+ * case that they ever want to protect against
+ * each other.
+ *
+ * If we already have local interrupts disabled,
+ * this will not turn a local disable into a
+ * global one (problems with spinlocks: this makes
+ * save_flags+cli+sti usable inside a spinlock).
+ */
 void __global_cli(void)
 {
-	int cpu = smp_processor_id();
+	unsigned int flags;
 	unsigned long where;
 
 	__asm__("mov %%i7, %0" : "=r" (where));
-	__cli();
-	get_irqlock(cpu, where);
+
+	__save_flags(flags);
+
+	if ((flags & PSR_PIL) != PSR_PIL) {
+		int cpu = smp_processor_id();
+		__cli();
+		if (!local_irq_count[cpu])
+			get_irqlock(cpu, where);
+	}
 }
 
 void __global_sti(void)
 {
-	release_irqlock(smp_processor_id());
+	int cpu = smp_processor_id();
+
+	if (!local_irq_count[cpu])
+		release_irqlock(cpu);
 	__sti();
 }
 
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
 unsigned long __global_save_flags(void)
 {
-	return global_irq_holder == (unsigned char) smp_processor_id();
+	int retval;
+	int local_enabled = 0;
+	unsigned long flags;
+
+	__save_flags(flags);
+
+	if ((flags & PSR_PIL) != PSR_PIL)
+		local_enabled = 1;
+
+	/* default to local */
+	retval = 2 + local_enabled;
+
+	/* check for global flags if we're not in an interrupt */
+	if (!local_irq_count[smp_processor_id()]) {
+		if (local_enabled)
+			retval = 1;
+		if (global_irq_holder == (unsigned char) smp_processor_id())
+			retval = 0;
+	}
+	return retval;
 }
 
 void __global_restore_flags(unsigned long flags)
 {
-	if(flags & 1) {
+	switch (flags) {
+	case 0:
 		__global_cli();
-	} else {
-		/* release_irqlock() */
-		if(global_irq_holder == smp_processor_id()) {
-			global_irq_holder = NO_PROC_ID;
-			spin_unlock(&global_irq_lock);
-		}
-		if(!(flags & 2))
-			__sti();
+		break;
+	case 1:
+		__global_sti();
+		break;
+	case 2:
+		__cli();
+		break;
+	case 3:
+		__sti();
+		break;
+	default:
+		printk("global_restore_flags: %08lx (%08lx)\n",
+			flags, (&flags)[-1]);
 	}
 }
 
@@ -353,7 +468,7 @@
 	while (*((volatile unsigned char *)&global_irq_lock)) {
 		if ((unsigned char) cpu == global_irq_holder) {
 			struct pt_regs *regs = _opaque;
-			int sbh_cnt = atomic_read(&__sparc_bh_counter);
+			int sbh_cnt = atomic_read(&global_bh_count);
 			int globl_locked = *((unsigned char *)&global_irq_lock);
 			int globl_icount = atomic_read(&global_irq_count);
 			int local_count = local_irq_count[cpu];
@@ -386,24 +501,6 @@
 }
 
 #endif /* DEBUG_IRQLOCK */
-
-/* There has to be a better way. */
-void synchronize_irq(void)
-{
-	int cpu = smp_processor_id();
-	int local_count = local_irq_count[cpu];
-
-	if(local_count != atomic_read(&global_irq_count)) {
-		unsigned long flags;
-
-		/* See comment below at __global_save_flags to understand
-		 * why we must do it this way on Sparc.
-		 */
-		save_and_cli(flags);
-		restore_flags(flags);
-	}
-}
-
 #endif /* __SMP__ */
 
 void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
@@ -511,12 +608,13 @@
 	/* If this is flagged as statically allocated then we use our
 	 * private struct which is never freed.
 	 */
-	if (irqflags & SA_STATIC_ALLOC)
+	if (irqflags & SA_STATIC_ALLOC) {
 	    if (static_irq_count < MAX_STATIC_ALLOC)
 		action = &static_irqaction[static_irq_count++];
 	    else
 		printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
 		       irq, devname);
+	}
 	
 	if (action == NULL)
 	    action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
@@ -604,11 +702,12 @@
 	/* If this is flagged as statically allocated then we use our
 	 * private struct which is never freed.
 	 */
-	if (irqflags & SA_STATIC_ALLOC)
+	if (irqflags & SA_STATIC_ALLOC) {
 	    if (static_irq_count < MAX_STATIC_ALLOC)
 		action = &static_irqaction[static_irq_count++];
 	    else
 		printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname);
+	}
 	
 	if (action == NULL)
 	    action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c
--- v2.1.126/linux/arch/sparc/kernel/pcic.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/pcic.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.2 1998/09/29 03:21:56 jj Exp $
+/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -83,7 +83,7 @@
 	int node;
 	int err;
 
-	if (pci_present()) {
+	if (pcibios_present()) {
 		prom_printf("PCIC: called twice!\n");
 		prom_halt();
 	}
@@ -426,7 +426,7 @@
 	/* A hack until do_gettimeofday prototype is moved to arch specific headers
 	   and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
 	((unsigned int *)do_gettimeofday)[0] = 
-		0x10800000 | (((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) & 0x003fffff);
+		0x10800000 | ((((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) >> 2) & 0x003fffff);
 	((unsigned int *)do_gettimeofday)[1] =
 		0x01000000;
 	BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM);
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v2.1.126/linux/arch/sparc/kernel/signal.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/signal.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.86 1998/09/29 09:46:04 davem Exp $
+/*  $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -75,6 +75,7 @@
 	__siginfo_fpu_t		*fpu_save;
 	unsigned long		insns [2] __attribute__ ((aligned (8)));
 	unsigned int		extramask[_NSIG_WORDS - 1];
+	unsigned int		extra_size; /* Should be 0 */
 	__siginfo_fpu_t		fpu_state;
 };
 
@@ -86,6 +87,7 @@
 	__siginfo_fpu_t		*fpu_save;
 	unsigned int		insns [2];
 	stack_t			stack;
+	unsigned int		extra_size; /* Should be 0 */
 	__siginfo_fpu_t		fpu_state;
 };
 
@@ -203,16 +205,19 @@
 #endif
 	current->used_math = 1;
 	current->flags &= ~PF_USEDFPU;
+	
+	if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
+		return -EFAULT;
 
-	err = copy_from_user(&current->tss.float_regs[0], &fpu->si_float_regs[0],
-		       (sizeof(unsigned long) * 32));
+	err = __copy_from_user(&current->tss.float_regs[0], &fpu->si_float_regs[0],
+			       (sizeof(unsigned long) * 32));
 	err |= __get_user(current->tss.fsr, &fpu->si_fsr);
 	err |= __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
 	if (current->tss.fpqdepth != 0)
-		err |= copy_from_user(&current->tss.fpqueue[0],
-			       &fpu->si_fpqueue[0],
-			       ((sizeof(unsigned long) +
-			       (sizeof(unsigned long *)))*16));
+		err |= __copy_from_user(&current->tss.fpqueue[0],
+					&fpu->si_fpqueue[0],
+					((sizeof(unsigned long) +
+					(sizeof(unsigned long *)))*16));
 	return err;
 }
 
@@ -241,7 +246,7 @@
 
 	/* 2. Restore the state */
 	up_psr = regs->psr;
-	err |= copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
+	err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
 
 	/* User can only change condition codes and FPU enabling in %psr. */
 	regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
@@ -250,14 +255,14 @@
 	err |= __get_user(fpu_save, &sf->fpu_save);
 
 	if (fpu_save)
-		err |= restore_fpu_state(regs, sf->fpu_save);
+		err |= restore_fpu_state(regs, fpu_save);
 
 	/* This is pretty much atomic, no amount locking would prevent
 	 * the races which exist anyways.
 	 */
 	err |= __get_user(set.sig[0], &sf->info.si_mask);
-	err |= copy_from_user(&set.sig[1], &sf->extramask,
-			   (_NSIG_WORDS-1) * sizeof(unsigned int));
+	err |= __copy_from_user(&set.sig[1], &sf->extramask,
+			        (_NSIG_WORDS-1) * sizeof(unsigned int));
 			   
 	if (err)
 		goto segv_and_exit;
@@ -270,8 +275,6 @@
 	return;
 
 segv_and_exit:
-	/* Ugh, we need to grab master lock in these rare cases ;-( */
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -305,8 +308,8 @@
 	 */
 	err |= __get_user(set.sig[0], &scptr->sigc_mask);
 	/* Note that scptr + 1 points to extramask */
-	err |= copy_from_user(&set.sig[1], scptr + 1,
-			   (_NSIG_WORDS - 1) * sizeof(unsigned int));
+	err |= __copy_from_user(&set.sig[1], scptr + 1,
+				(_NSIG_WORDS - 1) * sizeof(unsigned int));
 	
 	if (err)
 		goto segv_and_exit;
@@ -352,7 +355,7 @@
 	   (((unsigned long) sf) & 0x03))
 		goto segv;
 
-	err = get_user(pc, &sf->regs.pc);
+	err = __get_user(pc, &sf->regs.pc);
 	err |= __get_user(npc, &sf->regs.npc);
 	err |= ((pc | npc) & 0x03);
 
@@ -366,8 +369,8 @@
 	err |= __get_user(fpu_save, &sf->fpu_save);
 
 	if(fpu_save)
-		err |= restore_fpu_state(regs, &sf->fpu_state);
-	err |= copy_from_user(&set, &sf->mask, sizeof(sigset_t));
+		err |= restore_fpu_state(regs, fpu_save);
+	err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
 	
 	err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
 	
@@ -459,13 +462,13 @@
 		for(window = 0; window < current->tss.w_saved; window++) {
 			sc->sigc_spbuf[window] =
 				(char *)current->tss.rwbuf_stkptrs[window];
-			err |= copy_to_user(&sc->sigc_wbuf[window],
-					    &current->tss.reg_window[window],
-					    sizeof(struct reg_window));
+			err |= __copy_to_user(&sc->sigc_wbuf[window],
+					      &current->tss.reg_window[window],
+					      sizeof(struct reg_window));
 		}
 	else
-		err |= copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
-				    sizeof(struct reg_window));
+		err |= __copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
+				      sizeof(struct reg_window));
 
 	current->tss.w_saved = 0; /* So process is allowed to execute. */
 	err |= __put_user(signr, &sframep->sig_num);
@@ -490,11 +493,8 @@
 	return;
 
 sigill_and_return:
-	/* Ugh, we need to grab master lock in these rare cases ;-( */
-	lock_kernel();
 	do_exit(SIGILL);
 sigsegv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -520,13 +520,13 @@
 		regs->psr &= ~(PSR_EF);
 	}
 #endif
-	err |= copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
-			    (sizeof(unsigned long) * 32));
+	err |= __copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+			      (sizeof(unsigned long) * 32));
 	err |= __put_user(current->tss.fsr, &fpu->si_fsr);
 	err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
 	if (current->tss.fpqdepth != 0)
-		err |= copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
-				    ((sizeof(unsigned long) +
+		err |= __copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
+				      ((sizeof(unsigned long) +
 				      (sizeof(unsigned long *)))*16));
 	current->used_math = 0;
 	return err;
@@ -560,7 +560,9 @@
 	}
 
 	/* 2. Save the current process state */
-	err = copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+	err = __copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+	
+	err |= __put_user(0, &sf->extra_size);
 
 	if (current->used_math) {
 		err |= save_fpu_state(regs, &sf->fpu_state);
@@ -572,8 +574,8 @@
 	err |= __put_user(oldset->sig[0], &sf->info.si_mask);
 	err |= __copy_to_user(sf->extramask, &oldset->sig[1],
 			      (_NSIG_WORDS - 1) * sizeof(unsigned int));
-	err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
-			    sizeof (struct reg_window));
+	err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+			      sizeof (struct reg_window));
 	if (err)
 		goto sigsegv;
 	
@@ -606,10 +608,8 @@
 	return;
 
 sigill_and_return:
-	lock_kernel();
 	do_exit(SIGILL);
 sigsegv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -620,7 +620,7 @@
 	struct rt_signal_frame *sf;
 	int sigframe_size;
 	unsigned int psr;
-	int i, err;
+	int err;
 
 	synchronize_user_stack();
 	sigframe_size = RT_ALIGNEDSZ;
@@ -632,15 +632,16 @@
 	if(current->tss.w_saved != 0)
 		goto sigill;
 
-	err  = put_user(regs->pc, &sf->regs.pc);
+	err  = __put_user(regs->pc, &sf->regs.pc);
 	err |= __put_user(regs->npc, &sf->regs.npc);
 	err |= __put_user(regs->y, &sf->regs.y);
 	psr = regs->psr;
 	if(current->used_math)
 		psr |= PSR_EF;
 	err |= __put_user(psr, &sf->regs.psr);
-	for(i = 0; i < 16; i++)
-		err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+	err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
+	err |= __put_user(0, &sf->extra_size);
+
 	if(psr & PSR_EF) {
 		err |= save_fpu_state(regs, &sf->fpu_state);
 		err |= __put_user(&sf->fpu_state, &sf->fpu_save);
@@ -654,8 +655,8 @@
 	err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
 	
-	err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
-			    sizeof (struct reg_window));	
+	err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+			      sizeof (struct reg_window));	
 	if (err)
 		goto sigsegv;
 
@@ -685,10 +686,8 @@
 	return;
 
 sigill:
-	lock_kernel();
 	do_exit(SIGILL);
 sigsegv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -717,7 +716,7 @@
 	}
 
 	/* Start with a clean frame pointer and fill it */
-	err = clear_user(sfp, sizeof (*sfp));
+	err = __clear_user(sfp, sizeof (*sfp));
 
 	/* Setup convenience variables */
 	si = &sfp->si;
@@ -746,8 +745,8 @@
 	err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
 	
 	/* Copy g [1..7] and o [0..7] registers */
-	err |= copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
-	err |= copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
+	err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
+	err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
 
 	/* Setup sigaltstack */
 	err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
@@ -775,9 +774,9 @@
 	 */
 	for(window = 0; window < current->tss.w_saved; window++) {
 		err |= __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
-		err |= copy_to_user(&gw->win [window],
-				    &current->tss.reg_window [window],
-				    sizeof (svr4_rwindow_t));
+		err |= __copy_to_user(&gw->win [window],
+				      &current->tss.reg_window [window],
+				      sizeof (svr4_rwindow_t));
 		err |= __put_user(0, gw->winptr [window]);
 	}
 
@@ -819,10 +818,8 @@
 	return;
 
 sigill_and_return:
-	lock_kernel();
 	do_exit(SIGILL);
 sigsegv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -839,6 +836,8 @@
 		goto sigsegv_and_return;
 
 	err = clear_user(uc, sizeof (*uc));
+	if (err)
+		return -EFAULT;
 
 	/* Setup convenience variables */
 	mc = &uc->mcontext;
@@ -860,8 +859,8 @@
 	err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
 	
 	/* Copy g [1..7] and o [0..7] registers */
-	err |= copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
-	err |= copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
+	err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
+	err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
 
 	/* Setup sigaltstack */
 	err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
@@ -874,7 +873,6 @@
 	return (err ? -EFAULT : 0);
 
 sigsegv_and_return:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -950,14 +948,13 @@
 	regs->psr |= (psr & PSR_ICC);
 
 	/* Restore g[1..7] and o[0..7] registers */
-	err |= copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1],
+	err |= __copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1],
 			      sizeof (long) * 7);
-	err |= copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0],
+	err |= __copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0],
 			      sizeof (long) * 8);
 	return (err ? -EFAULT : 0);
 
 sigsegv_and_return:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -1110,7 +1107,9 @@
 			case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
 				if(current->binfmt && current->binfmt->core_dump) {
 					lock_kernel();
-					if(current->binfmt->core_dump(signr, regs))
+					if(current->binfmt &&
+					   current->binfmt->core_dump &&
+					   current->binfmt->core_dump(signr, regs))
 						exit_code |= 0x80;
 					unlock_kernel();
 				}
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.1.126/linux/arch/sparc/kernel/smp.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/smp.c	Tue Oct 27 09:52:20 1998
@@ -64,6 +64,9 @@
 /* Kernel spinlock */
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 
+/* Used to make bitops atomic */
+unsigned char bitops_spinlock = 0;
+
 volatile unsigned long ipi_count;
 
 volatile int smp_process_available=0;
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.1.126/linux/arch/sparc/kernel/sparc_ksyms.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.70 1998/09/17 11:04:55 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.72 1998/10/22 15:15:08 ecd Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6 +68,10 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 
+#ifdef __SMP__
+extern spinlock_t kernel_flag;
+#endif
+
 /* One thing to note is that the way the symbols of the mul/div
  * support routines are named is a mess, they all start with
  * a '.' which makes it a bitch to export, here is the trick:
@@ -87,33 +91,21 @@
 EXPORT_SYMBOL(sparc_cpu_model);
 EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
 #ifdef SPIN_LOCK_DEBUG
-EXPORT_SYMBOL(_spin_lock);
-EXPORT_SYMBOL(_spin_unlock);
+EXPORT_SYMBOL(_do_spin_lock);
+EXPORT_SYMBOL(_do_spin_unlock);
 EXPORT_SYMBOL(_spin_trylock);
-EXPORT_SYMBOL(_spin_lock_irq);
-EXPORT_SYMBOL(_spin_unlock_irq);
-EXPORT_SYMBOL(_spin_lock_irqsave);
-EXPORT_SYMBOL(_spin_unlock_irqrestore);
-EXPORT_SYMBOL(_read_lock);
-EXPORT_SYMBOL(_read_unlock);
-EXPORT_SYMBOL(_read_lock_irq);
-EXPORT_SYMBOL(_read_unlock_irq);
-EXPORT_SYMBOL(_read_lock_irqsave);
-EXPORT_SYMBOL(_read_unlock_irqrestore);
-EXPORT_SYMBOL(_write_lock);
-EXPORT_SYMBOL(_write_unlock);
-EXPORT_SYMBOL(_write_lock_irq);
-EXPORT_SYMBOL(_write_unlock_irq);
-EXPORT_SYMBOL(_write_lock_irqsave);
-EXPORT_SYMBOL(_write_unlock_irqrestore);
+EXPORT_SYMBOL(_do_read_lock);
+EXPORT_SYMBOL(_do_read_unlock);
+EXPORT_SYMBOL(_do_write_lock);
+EXPORT_SYMBOL(_do_write_unlock);
 #else
 EXPORT_SYMBOL_PRIVATE(_rw_read_enter);
 EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
 EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
 #endif
-EXPORT_SYMBOL(__sparc_bh_counter);
 #ifdef __SMP__
 #ifdef DEBUG_IRQLOCK
+EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_cli);
@@ -142,14 +134,19 @@
 EXPORT_SYMBOL_PRIVATE(_clear_le_bit);
 
 /* IRQ implementation. */
-EXPORT_SYMBOL(local_irq_count);
 #ifdef __SMP__
+EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(global_irq_lock);
 EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_bh_count);
+EXPORT_SYMBOL(sparc_bh_lock);
 EXPORT_SYMBOL(global_irq_count);
 EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(synchronize_bh);
 #endif
+EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(local_bh_count);
 
 EXPORT_SYMBOL(udelay);
 EXPORT_SYMBOL(mstk48t02_regs);
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c
--- v2.1.126/linux/arch/sparc/kernel/sun4d_irq.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/sun4d_irq.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/*  $Id: sun4d_irq.c,v 1.15 1998/09/29 09:46:12 davem Exp $
+/*  $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $
  *  arch/sparc/kernel/sun4d_irq.c:
  *			SS1000/SC2000 interrupt handling.
  *
@@ -438,8 +438,13 @@
 	int cpu;
 
 	/* Map the User Timer registers. */
-	sun4d_timers = sparc_alloc_io(BW_LOCAL_BASE+BW_TIMER_LIMIT, 0,
+#ifdef __SMP__
+	sun4d_timers = sparc_alloc_io(CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT, 0,
+				      PAGE_SIZE, "user timer", 0xf, 0x0);
+#else
+	sun4d_timers = sparc_alloc_io(CSR_BASE(0)+BW_TIMER_LIMIT, 0,
 				      PAGE_SIZE, "user timer", 0xf, 0x0);
+#endif
     
 	sun4d_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
 	master_l10_counter = &sun4d_timers->l10_cur_count;
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c
--- v2.1.126/linux/arch/sparc/kernel/sunos_ioctl.c	Thu Apr 23 20:21:30 1998
+++ linux/arch/sparc/kernel/sunos_ioctl.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.30 1998/01/21 06:17:32 ecd Exp $
+/* $Id: sunos_ioctl.c,v 1.31 1998/10/25 19:31:04 davem Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -218,7 +218,7 @@
 	}
 
 #if 0
-	if (cmd & 0xff00 == ('k' << 8)){
+	if ((cmd & 0xff00) == ('k' << 8)) {
 		printk ("[[KBIO: %8.8x\n", (unsigned int) cmd);
 	}
 #endif
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v2.1.126/linux/arch/sparc/kernel/sys_sparc.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/sys_sparc.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.48 1998/09/07 09:19:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -181,6 +181,7 @@
 	struct file * file = NULL;
 	unsigned long retval = -EBADF;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
@@ -214,6 +215,7 @@
 		fput(file);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return retval;
 }
 
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.1.126/linux/arch/sparc/kernel/sys_sunos.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/kernel/sys_sunos.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.92 1998/08/31 03:40:53 davem Exp $
+/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6 +68,7 @@
 	struct file * file = NULL;
 	unsigned long retval, ret_type;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	current->personality |= PER_BSD;
 	if(flags & MAP_NORESERVE) {
@@ -128,6 +129,7 @@
 		fput(file);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return retval;
 }
 
@@ -147,6 +149,7 @@
 	unsigned long rlim;
 	unsigned long newbrk, oldbrk;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if(ARCH_SUN4C_SUN4) {
 		if(brk >= 0x20000000 && brk < 0xe0000000) {
@@ -213,6 +216,7 @@
 	retval = 0;
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return retval;
 }
 
@@ -579,20 +583,16 @@
 
 asmlinkage int sunos_uname(struct sunos_utsname *name)
 {
-	int ret = -EFAULT;
-
+	int ret;
 	down(&uts_sem);
-	if(!name)
-		goto out;
-	if(copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1))
-		goto out;
-	copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
-	put_user('\0', &name->nname[8]);
-	copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
-	copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
-	copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
-	ret = 0;
-out:
+	ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
+	if (!ret) {
+		ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
+		ret |= __put_user('\0', &name->nname[8]);
+		ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
+		ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
+		ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
+	}
 	up(&uts_sem);
 	return ret;
 }
@@ -843,7 +843,7 @@
 	strncpy (linux_nfs_mount.hostname, the_name, 254);
 	linux_nfs_mount.hostname [255] = 0;
 	putname (the_name);
-
+	
 	dev = get_unnamed_dev ();
 	
 	ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
@@ -860,6 +860,9 @@
 	int ret = -EINVAL;
 	char *dev_fname = 0;
 
+	if (!capable (CAP_SYS_ADMIN))
+		return -EPERM;
+		
 	lock_kernel();
 	/* We don't handle the integer fs type */
 	if ((flags & SMNT_NEWTYPE) == 0)
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/lib/bitops.S linux/arch/sparc/lib/bitops.S
--- v2.1.126/linux/arch/sparc/lib/bitops.S	Sun Jan 26 02:07:09 1997
+++ linux/arch/sparc/lib/bitops.S	Tue Oct 27 09:52:20 1998
@@ -26,12 +26,26 @@
 	wr	%g3, PSR_PIL, %psr
 	nop; nop; nop
 1:
-	ld	[%g1], %g7
+#ifdef __SMP__
+	set	C_LABEL(bitops_spinlock), %g5
+2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
+	orcc	%g7, 0x0, %g0		! Did we get it?
+	bne	2b			! Nope...
+#endif
+	 ld	[%g1], %g7
 	or	%g7, %g2, %g5
-	andcc	%g3, PSR_PIL, %g0
 	and	%g7, %g2, %g2
+#ifdef __SMP__
+	st	%g5, [%g1]
+	set	C_LABEL(bitops_spinlock), %g5
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 stb	%g0, [%g5]
+#else
+	andcc	%g3, PSR_PIL, %g0
 	bne	1f
 	 st	%g5, [%g1]
+#endif
 	wr	%g3, 0x0, %psr
 	nop; nop; nop
 1:
@@ -48,12 +62,26 @@
 	wr	%g3, PSR_PIL, %psr
 	nop; nop; nop
 1:
-	ld	[%g1], %g7
+#ifdef __SMP__
+	set	C_LABEL(bitops_spinlock), %g5
+2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
+	orcc	%g7, 0x0, %g0		! Did we get it?
+	bne	2b			! Nope...
+#endif
+	 ld	[%g1], %g7
 	andn	%g7, %g2, %g5
-	andcc	%g3, PSR_PIL, %g0
 	and	%g7, %g2, %g2
+#ifdef __SMP__
+	st	%g5, [%g1]
+	set	C_LABEL(bitops_spinlock), %g5
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 stb	%g0, [%g5]
+#else
+	andcc	%g3, PSR_PIL, %g0
 	bne	1f
 	 st	%g5, [%g1]
+#endif
 	wr	%g3, 0x0, %psr
 	nop; nop; nop
 1:
@@ -70,12 +98,26 @@
 	wr	%g3, PSR_PIL, %psr
 	nop; nop; nop
 1:
-	ld	[%g1], %g7
+#ifdef __SMP__
+	set	C_LABEL(bitops_spinlock), %g5
+2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
+	orcc	%g7, 0x0, %g0		! Did we get it?
+	bne	2b			! Nope...
+#endif
+	 ld	[%g1], %g7
 	xor	%g7, %g2, %g5
-	andcc	%g3, PSR_PIL, %g0
 	and	%g7, %g2, %g2
+#ifdef __SMP__
+	st	%g5, [%g1]
+	set	C_LABEL(bitops_spinlock), %g5
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 stb	%g0, [%g5]
+#else
+	andcc	%g3, PSR_PIL, %g0
 	bne	1f
 	 st	%g5, [%g1]
+#endif
 	wr	%g3, 0x0, %psr
 	nop; nop; nop
 1:
@@ -92,12 +134,26 @@
 	wr	%g3, PSR_PIL, %psr
 	nop; nop; nop
 1:
-	ldub	[%g1], %g7
+#ifdef __SMP__
+	set	C_LABEL(bitops_spinlock), %g5
+2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
+	orcc	%g7, 0x0, %g0		! Did we get it?
+	bne	2b			! Nope...
+#endif
+	 ldub	[%g1], %g7
 	or	%g7, %g2, %g5
-	andcc	%g3, PSR_PIL, %g0
 	and	%g7, %g2, %g2
+#ifdef __SMP__
+	stb	%g5, [%g1]
+	set	C_LABEL(bitops_spinlock), %g5
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 stb	%g0, [%g5]
+#else
+	andcc	%g3, PSR_PIL, %g0
 	bne	1f
 	 stb	%g5, [%g1]
+#endif
 	wr	%g3, 0x0, %psr
 	nop; nop; nop
 1:
@@ -113,12 +169,26 @@
 	wr	%g3, PSR_PIL, %psr
 	nop; nop; nop
 1:
-	ldub	[%g1], %g7
+#ifdef __SMP__
+	set	C_LABEL(bitops_spinlock), %g5
+2:	ldstub	[%g5], %g7		! Spin on the byte lock for SMP.
+	orcc	%g7, 0x0, %g0		! Did we get it?
+	bne	2b			! Nope...
+#endif
+	 ldub	[%g1], %g7
 	andn	%g7, %g2, %g5
-	andcc	%g3, PSR_PIL, %g0
 	and	%g7, %g2, %g2
+#ifdef __SMP__
+	stb	%g5, [%g1]
+	set	C_LABEL(bitops_spinlock), %g5
+	andcc	%g3, PSR_PIL, %g0
+	bne	1f
+	 stb	%g0, [%g5]
+#else
+	andcc	%g3, PSR_PIL, %g0
 	bne	1f
 	 stb	%g5, [%g1]
+#endif
 	wr	%g3, 0x0, %psr
 	nop; nop; nop
 1:
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/lib/debuglocks.c linux/arch/sparc/lib/debuglocks.c
--- v2.1.126/linux/arch/sparc/lib/debuglocks.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc/lib/debuglocks.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: debuglocks.c,v 1.3 1998/09/29 09:46:22 davem Exp $
+/* $Id: debuglocks.c,v 1.5 1998/10/14 09:19:04 jj Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -120,29 +120,17 @@
 	if(val) {
 		while(rw->lock & 0xff) {
 			if (!--stuck) {
-				show(str, (spinlock_t *)rw, caller);
-				stuck = INIT_STUCK;
-			}
-			barrier();
-		}
-		goto wlock_again;
-	}
-clock_again:
-	__asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
-	if(val) {
-		while(rw->lock & 0xff00) {
-			if (!--stuck) {
 				show_read(str, rw, caller);
 				stuck = INIT_STUCK;
 			}
 			barrier();
 		}
-		goto clock_again;
+		goto wlock_again;
 	}
-	(*((unsigned short *)&rw->lock))++;
+
 	rw->reader_pc[cpu] = caller;
 	barrier();
-	(*(((unsigned short *)&rw->lock)+1)) = 0;
+	rw->lock++;
 }
 
 #undef INIT_STUCK
@@ -157,22 +145,22 @@
 
 	STORE_CALLER(caller);
 
-clock_again:
-	__asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+wlock_again:
+	__asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
 	if(val) {
-		while(rw->lock & 0xff00) {
+		while(rw->lock & 0xff) {
 			if (!--stuck) {
 				show_read(str, rw, caller);
 				stuck = INIT_STUCK;
 			}
 			barrier();
 		}
-		goto clock_again;
+		goto wlock_again;
 	}
-	(*((unsigned short *)&rw->lock))--;
+
 	rw->reader_pc[cpu] = 0;
 	barrier();
-	(*(((unsigned char *)&rw->lock)+2))=0;
+	rw->lock -= 0x1ff;
 }
 
 #undef INIT_STUCK
@@ -190,7 +178,8 @@
 wlock_again:
 	__asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
 	if(val) {
-		while(rw->lock & 0xff) {
+wlock_wait:
+		while(rw->lock) {
 			if (!--stuck) {
 				show_write(str, rw, caller);
 				stuck = INIT_STUCK;
@@ -199,14 +188,15 @@
 		}
 		goto wlock_again;
 	}
-	rw->owner_pc = (cpu & 3) | (caller & ~3);
-	while(rw->lock & ~0xff) {
-		if (!--stuck) {
-			show_write(str, rw, caller);
-			stuck = INIT_STUCK;
-		}
+
+	if (rw->lock & ~0xff) {
+		*(((unsigned char *)&rw->lock)+3) = 0;
 		barrier();
+		goto wlock_wait;
 	}
+
+	barrier();
+	rw->owner_pc = (cpu & 3) | (caller & ~3);
 }
 
 void _do_write_unlock(rwlock_t *rw)
diff -u --recursive --new-file v2.1.126/linux/arch/sparc/lib/locks.S linux/arch/sparc/lib/locks.S
--- v2.1.126/linux/arch/sparc/lib/locks.S	Thu Aug  6 14:06:30 1998
+++ linux/arch/sparc/lib/locks.S	Tue Oct 27 09:52:20 1998
@@ -1,7 +1,9 @@
-/* $Id: locks.S,v 1.13 1998/07/30 11:29:28 davem Exp $
+/* $Id: locks.S,v 1.15 1998/10/14 09:18:55 jj Exp $
  * locks.S: SMP low-level lock primitives on Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
 #include <asm/cprefix.h>
@@ -43,52 +45,48 @@
 	 ldstub	[%g1 + 3], %g2
 	b	___rw_read_enter_spin_on_wlock
 	 ldub	[%g1 + 3], %g2
+___rw_read_exit_spin_on_wlock:
+	orcc	%g2, 0x0, %g0
+	be,a	___rw_read_exit
+	 ldstub	[%g1 + 3], %g2
+	b	___rw_read_exit_spin_on_wlock
+	 ldub	[%g1 + 3], %g2
 ___rw_write_enter_spin_on_wlock:
 	orcc	%g2, 0x0, %g0
 	be,a	___rw_write_enter
 	 ldstub	[%g1 + 3], %g2
 	b	___rw_write_enter_spin_on_wlock
-	 ldub	[%g1 + 3], %g2
+	 ld	[%g1], %g2
 
 	.globl	___rw_read_enter
 ___rw_read_enter:
 	orcc	%g2, 0x0, %g0
 	bne,a	___rw_read_enter_spin_on_wlock
 	 ldub	[%g1 + 3], %g2
-1:
-	ldstub	[%g1 + 2], %g7
-	orcc	%g7, 0x0, %g0
-	bne	1b
-	 ldsh	[%g1], %g2
+	ld	[%g1], %g2
 	add	%g2, 1, %g2
-	sth	%g2, [%g1]
-	sth	%g0, [%g1 + 2]
+	st	%g2, [%g1]
 	retl
 	 mov	%g4, %o7
 
-	/* We must be careful here to not blow away wlock. */
 	.globl	___rw_read_exit
-___rw_read_exit_spin:
-	ldstub	[%g1 + 2], %g2
 ___rw_read_exit:
 	orcc	%g2, 0x0, %g0
-	bne	___rw_read_exit_spin
-	 ldsh	[%g1], %g7
-	sub	%g7, 1, %g7
-	sth	%g7, [%g1]
-	stb	%g0, [%g1 + 2]
+	bne,a	___rw_read_exit_spin_on_wlock
+	 ldub	[%g1 + 3], %g2
+	ld	[%g1], %g2
+	sub	%g2, 0x1ff, %g2
+	st	%g2, [%g1]
 	retl
 	 mov	%g4, %o7
 
 	.globl	___rw_write_enter
 ___rw_write_enter:
 	orcc	%g2, 0x0, %g0
-	bne,a	___rw_write_enter_spin_on_wlock
-	 ldub	[%g1 + 3], %g2
-	ld	[%g1], %g2
-1:
-	andncc	%g2, 0xff, %g0
-	bne,a	1b
+	bne	___rw_write_enter_spin_on_wlock
 	 ld	[%g1], %g2
+	andncc	%g2, 0xff, %g0
+	bne,a	___rw_write_enter_spin_on_wlock
+	 stb	%g0, [%g1 + 3]
 	retl
 	 mov	%g4, %o7
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- v2.1.126/linux/arch/sparc64/Makefile	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc64/Makefile	Tue Oct 27 09:52:20 1998
@@ -1,21 +1,28 @@
-# $Id: Makefile,v 1.29 1998/09/16 12:25:20 jj Exp $
+# $Id: Makefile,v 1.33 1998/10/19 07:04:02 jj Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
 # 64-bit Sparc.
 #
-# Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
 #
 
 # If the solaris /bin/sh wasn't so broken, I wouldn't need the following
 # line...
 SHELL  =/bin/bash
 
-CC		= sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
+CC		:= sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
 
+CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| 	\)' > /dev/null; then echo y; else echo n; fi)
 IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
 NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
 
+ifneq ($(CC_HAS_ARGS),y)
+MAKEOVERRIDES	:= $(shell echo "$(MAKEOVERRIDES)" | sed 's CC=$(CC) CC=$(CC)\\\ -D__KERNEL__\\\ -I$(TOPDIR)/include ')
+override CC	:= $(CC) -D__KERNEL__ -I$(TOPDIR)/include
+endif
+
 ifneq ($(NEW_GAS),y)
 AS		= sparc64-linux-as
 LD		= sparc64-linux-ld
@@ -28,7 +35,6 @@
 endif
 ELFTOAOUT	= elftoaout
 
-
 #
 # Uncomment the first CFLAGS if you are doing kgdb source level
 # debugging of the kernel to get the proper debugging information.
@@ -40,6 +46,16 @@
 else
   CFLAGS := $(CFLAGS) -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \
 	    -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
+endif
+
+# Uncomment this to get spinlock/rwlock debugging on SMP.
+# DEBUG_SPINLOCK = 1
+
+ifdef SMP
+  ifdef DEBUG_SPINLOCK
+    CFLAGS += -DSPIN_LOCK_DEBUG
+    AFLAGS += -DSPIN_LOCK_DEBUG
+  endif
 endif
 
 LINKFLAGS = -T arch/sparc64/vmlinux.lds
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.1.126/linux/arch/sparc64/defconfig	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc64/defconfig	Tue Oct 27 09:52:20 1998
@@ -27,6 +27,7 @@
 CONFIG_PROM_CONSOLE=y
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_MATROX is not set
 CONFIG_FB_SBUS=y
 CONFIG_FB_CREATOR=y
 CONFIG_FB_CGSIX=y
@@ -86,10 +87,11 @@
 CONFIG_BINFMT_MISC=m
 CONFIG_BINFMT_JAVA=m
 CONFIG_SOLARIS_EMUL=m
-CONFIG_PARPORT=y
-CONFIG_PARPORT_AX=y
+CONFIG_PARPORT=m
+CONFIG_PARPORT_AX=m
+CONFIG_PARPORT_LOWLEVEL_MODULE=y
 # CONFIG_PARPORT_OTHER is not set
-CONFIG_PRINTER=y
+CONFIG_PRINTER=m
 CONFIG_PRINTER_READBACK=y
 CONFIG_ENVCTRL=m
 
@@ -122,11 +124,9 @@
 # Networking options
 #
 CONFIG_PACKET=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
+# CONFIG_NET_ALIAS is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -136,8 +136,7 @@
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-CONFIG_IP_ALIAS=y
-# CONFIG_ARPD is not set
+# CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
 
 #
@@ -165,18 +164,7 @@
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
-CONFIG_NET_SCHED=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_CSZ=m
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-# CONFIG_NET_QOS is not set
-# CONFIG_NET_CLS is not set
+# CONFIG_NET_SCHED is not set
 
 #
 # SCSI support
@@ -249,7 +237,7 @@
 CONFIG_HAPPYMEAL=y
 CONFIG_SUNQE=m
 CONFIG_MYRI_SBUS=m
-CONFIG_DE4X5=y
+CONFIG_DE4X5=m
 CONFIG_VORTEX=m
 
 #
@@ -258,18 +246,19 @@
 # CONFIG_QUOTA is not set
 CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
+CONFIG_CODA_FS=m
 CONFIG_SMB_FS=m
 CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
@@ -292,8 +281,7 @@
 CONFIG_SMD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
 # CONFIG_ADFS_FS is not set
-CONFIG_QNX4FS_FS=m
-# CONFIG_QNX4FS_RW is not set
+# CONFIG_QNX4FS_FS is not set
 # CONFIG_MAC_PARTITION is not set
 CONFIG_NLS=y
 
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.1.126/linux/arch/sparc64/kernel/Makefile	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc64/kernel/Makefile	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.40 1998/09/17 11:05:03 jj Exp $
+# $Id: Makefile,v 1.41 1998/10/11 06:58:14 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -89,6 +89,8 @@
 	@echo "" >> asm_offsets.h
 	@echo "#else /* __SMP__ */" >> asm_offsets.h
 	@echo "" >> asm_offsets.h
+	@echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h
+	@echo "" >> asm_offsets.h
 	@echo "#include <linux/sched.h>" > tmp.c
 	$(CC) -D__SMP__ -E tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@@ -110,6 +112,31 @@
 	# </hack>
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
+	@echo "" >> asm_offsets.h
+	@echo "#else /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
+	@echo "" >> asm_offsets.h
+	@echo "#include <linux/sched.h>" > tmp.c
+	$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
+	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
+	@echo "#include <linux/sched.h>" >> check_asm.c
+	@echo 'struct task_struct _task;' >> check_asm.c
+	@echo 'struct mm_struct _mm;' >> check_asm.c
+	@echo 'struct thread_struct _thread;' >> check_asm.c
+	@echo 'int main(void) {' >> check_asm.c
+	$(SH) ./check_asm.sh task tmp.i check_asm.c
+	$(SH) ./check_asm.sh mm tmp.i check_asm.c
+	$(SH) ./check_asm.sh thread tmp.i check_asm.c
+	@echo 'return 0; }' >> check_asm.c
+	@rm -f tmp.[ci]
+	#$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -o check_asm check_asm.c
+	# <hack> Until we can do this natively, a hack has to take place
+	$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
+	$(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
+	@rm -f check_asm.s
+	# </hack>
+	./check_asm >> asm_offsets.h
+	@rm -f check_asm check_asm.c
+	@echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
 	@echo "" >> asm_offsets.h
 	@echo "#endif /* __SMP__ */" >> asm_offsets.h
 	@echo "" >> asm_offsets.h
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.1.126/linux/arch/sparc64/kernel/entry.S	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc64/kernel/entry.S	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.90 1998/09/25 01:09:05 davem Exp $
+/* $Id: entry.S,v 1.91 1998/10/07 01:27:08 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -730,7 +730,7 @@
 		 mov		%l5, %o7
 ret_from_syscall:
 		/* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in
-		 * %o7 for us.
+		 * %o7 for us.  Check performance counter stuff too.
 		 */
 		andn		%o7, 0x100, %o7
 		sth		%o7, [%g6 + AOFF_task_tss + AOFF_thread_flags]
@@ -739,7 +739,13 @@
 		membar		#StoreStore | #LoadStore
 		stb		%g0, [%o4 + %lo(scheduler_lock)]
 #endif
-		b,pt		%xcc, ret_sys_call
+		andcc		%o7, 0x200, %g0
+		be,pt		%icc, 1f
+		 nop
+		ldx		[%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7
+		wr		%g0, %o7, %pcr
+		wr		%g0, %g0, %pic
+1:		b,pt		%xcc, ret_sys_call
 		 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
 sparc_exit:	rdpr		%otherwin, %g1
 		rdpr		%pstate, %g2
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.1.126/linux/arch/sparc64/kernel/head.S	Thu Aug  6 14:06:30 1998
+++ linux/arch/sparc64/kernel/head.S	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.53 1998/06/15 16:59:35 jj Exp $
+/* $Id: head.S,v 1.54 1998/10/06 20:48:30 ecd Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -379,6 +379,9 @@
 	sethi	%hi(ivector_to_mask), %g5
 	or	%g5, %lo(ivector_to_mask), %g1  /* IVECTOR table */
 	mov	0x40, %g2			/* INTR data 0 register */
+
+	/* Kill PROM timer */
+	wr	%g0, 0, %tick_cmpr
 
 	/* Ok, we're done setting up all the state our trap mechanims needs,
 	 * now get back into normal globals and let the PROM know what is up.
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.1.126/linux/arch/sparc64/kernel/ioctl32.c	Mon Oct  5 13:13:37 1998
+++ linux/arch/sparc64/kernel/ioctl32.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.52 1998/09/25 17:09:22 jj Exp $
+/* $Id: ioctl32.c,v 1.53 1998/10/26 08:01:01 jj Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -1532,8 +1532,9 @@
 		error = loop_status(fd, cmd, arg);
 		goto out;
 
-	case AUTOFS_IOC_SETTIMEOUT:
-		error = rw_long(fd, cmd, arg);
+#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+	case AUTOFS_IOC_SETTIMEOUT32:
+		error = rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
 		goto out;
 		
 	case PIO_FONTX:
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- v2.1.126/linux/arch/sparc64/kernel/irq.c	Thu Aug  6 14:06:30 1998
+++ linux/arch/sparc64/kernel/irq.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.61 1998/08/02 14:51:38 ecd Exp $
+/* $Id: irq.c,v 1.66 1998/10/21 15:02:25 ecd Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
@@ -15,6 +15,7 @@
 #include <linux/malloc.h>
 #include <linux/random.h> /* XXX ADD add_foo_randomness() calls... -DaveM */
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -208,7 +209,7 @@
 	13, /* Audio Record */
 	14, /* Audio Playback */
 	15, /* PowerFail */
-	9,  /* Keyboard/Mouse/Serial */
+	3,  /* second SCSI */
 	11, /* Floppy */
 	2,  /* Spare Hardware */
 	9,  /* Keyboard */
@@ -573,22 +574,18 @@
 	restore_flags(flags);
 }
 
-/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu
- * structure for cache reasons.
+/* Only uniprocessor needs this IRQ/BH locking depth, on SMP it
+ * lives in the per-cpu structure for cache reasons.
  */
 #ifndef __SMP__
 unsigned int local_irq_count;
-#endif
-
-#ifndef __SMP__
-int __sparc64_bh_counter = 0;
+unsigned int local_bh_count;
 
 #define irq_enter(cpu, irq)	(local_irq_count++)
 #define irq_exit(cpu, irq)	(local_irq_count--)
-
 #else
-
-atomic_t __sparc64_bh_counter = ATOMIC_INIT(0);
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED;
 
 /* Who has global_irq_lock. */
 unsigned char global_irq_holder = NO_PROC_ID;
@@ -596,136 +593,163 @@
 /* This protects IRQ's. */
 spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
 
-/* This protects BH software state (masks, things like that). */
-spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
-
 /* Global IRQ locking depth. */
 atomic_t global_irq_count = ATOMIC_INIT(0);
 
-static unsigned long previous_irqholder;
+#define irq_enter(cpu, irq)			\
+do {	hardirq_enter(cpu);			\
+	spin_unlock_wait(&global_irq_lock);	\
+} while(0)
+#define irq_exit(cpu, irq)	hardirq_exit(cpu)
 
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+static void show(char * str)
+{
+	int cpu = smp_processor_id();
 
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+	printk("\n%s, CPU %d:\n", str, cpu);
+	printk("irq:  %d [%d %d]\n",
+	       atomic_read(&global_irq_count),
+	       cpu_data[0].irq_count, cpu_data[1].irq_count);
+	printk("bh:   %d [%d %d]\n",
+	       (spin_is_locked(&global_bh_count) ? 1 : 0),
+	       cpu_data[0].bh_count, cpu_data[1].bh_count);
+}
+
+#define MAXCOUNT 100000000
+
+static inline void wait_on_bh(void)
+{
+	int count = MAXCOUNT;
+	do {
+		if(!--count) {
+			show("wait_on_bh");
+			count = 0;
+		}
+		membar("#LoadLoad");
+	} while(spin_is_locked(&global_bh_count));
+}
 
-static inline void wait_on_irq(int cpu, unsigned long where)
-{
-	int stuck = INIT_STUCK;
-	int local_count = local_irq_count;
+#define SYNC_OTHER_ULTRAS(x)	udelay(x+1)
 
-	while(local_count != atomic_read(&global_irq_count)) {
-		atomic_sub(local_count, &global_irq_count);
-		spin_unlock(&global_irq_lock);
+static inline void wait_on_irq(int cpu)
+{
+	int count = MAXCOUNT;
+	for(;;) {
+		membar("#LoadLoad");
+		if (!atomic_read (&global_irq_count)) {
+			if (local_bh_count || ! spin_is_locked(&global_bh_count))
+				break;
+		}
+		spin_unlock (&global_irq_lock);
+		membar("#StoreLoad | #StoreStore");
 		for(;;) {
-			STUCK;
-			membar("#StoreLoad | #LoadLoad");
+			if (!--count) {
+				show("wait_on_irq");
+				count = ~0;
+			}
+			__sti();
+			SYNC_OTHER_ULTRAS(cpu);
+			__cli();
 			if (atomic_read(&global_irq_count))
 				continue;
-			if (*((volatile unsigned char *)&global_irq_lock))
+			if (spin_is_locked (&global_irq_lock))
+				continue;
+			if (!local_bh_count && spin_is_locked (&global_bh_count))
 				continue;
-			membar("#LoadLoad | #LoadStore");
 			if (spin_trylock(&global_irq_lock))
 				break;
 		}
-		atomic_add(local_count, &global_irq_count);
 	}
 }
 
-#undef INIT_STUCK
-#define INIT_STUCK 10000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+void synchronize_bh(void)
+{
+	if (spin_is_locked (&global_bh_count) && !in_interrupt())
+		wait_on_bh();
+}
 
-static inline void get_irqlock(int cpu, unsigned long where)
+void synchronize_irq(void)
 {
-	int stuck = INIT_STUCK;
+	if (atomic_read(&global_irq_count)) {
+		cli();
+		sti();
+	}
+}
 
-	if (!spin_trylock(&global_irq_lock)) {
-		membar("#StoreLoad | #LoadLoad");
+static inline void get_irqlock(int cpu)
+{
+	if (! spin_trylock(&global_irq_lock)) {
 		if ((unsigned char) cpu == global_irq_holder)
 			return;
 		do {
-			do {
-				STUCK;
+			while (spin_is_locked (&global_irq_lock))
 				membar("#LoadLoad");
-			} while(*((volatile unsigned char *)&global_irq_lock));
-		} while (!spin_trylock(&global_irq_lock));
+		} while(! spin_trylock(&global_irq_lock));
 	}
-	wait_on_irq(cpu, where);
+	wait_on_irq(cpu);
 	global_irq_holder = cpu;
-	previous_irqholder = where;
 }
 
 void __global_cli(void)
 {
-	int cpu = smp_processor_id();
-	unsigned long where;
+	unsigned long flags;
 
-	__asm__ __volatile__("mov %%i7, %0" : "=r" (where));
-	__cli();
-	get_irqlock(cpu, where);
+	__save_flags(flags);
+	if(flags == 0) {
+		int cpu = smp_processor_id();
+		__cli();
+		if (! local_irq_count)
+			get_irqlock(cpu);
+	}
 }
 
 void __global_sti(void)
 {
-	release_irqlock(smp_processor_id());
-	__sti();
-}
+	int cpu = smp_processor_id();
 
-void __global_restore_flags(unsigned long flags)
-{
-	if (flags & 1) {
-		__global_cli();
-	} else {
-		if (global_irq_holder == (unsigned char) smp_processor_id()) {
-			global_irq_holder = NO_PROC_ID;
-			spin_unlock(&global_irq_lock);
-		}
-		if (!(flags & 2))
-			__sti();
-	}
+	if (! local_irq_count)
+		release_irqlock(cpu);
+	__sti();
 }
 
-#undef INIT_STUCK
-#define INIT_STUCK 200000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
-
-void irq_enter(int cpu, int irq)
+unsigned long __global_save_flags(void)
 {
-	int stuck = INIT_STUCK;
+	unsigned long flags, local_enabled, retval;
 
-	hardirq_enter(cpu);
-	while (*((volatile unsigned char *)&global_irq_lock)) {
-		if ((unsigned char) cpu == global_irq_holder)
-			printk("irq_enter: Frosted Lucky Charms, "
-			       "they're magically delicious!\n");
-		STUCK;
-		membar("#LoadLoad");
+	__save_flags(flags);
+	local_enabled = ((flags == 0) ? 1 : 0);
+	retval = 2 + local_enabled;
+	if (! local_irq_count) {
+		if (local_enabled)
+			retval = 1;
+		if (global_irq_holder == (unsigned char) smp_processor_id())
+			retval = 0;
 	}
+	return retval;
 }
 
-void irq_exit(int cpu, int irq)
-{
-	hardirq_exit(cpu);
-	release_irqlock(cpu);
-}
-
-void synchronize_irq(void)
+void __global_restore_flags(unsigned long flags)
 {
-	int local_count = local_irq_count;
-	unsigned long flags;
-
-	if (local_count != atomic_read(&global_irq_count)) {
-		save_and_cli(flags);
-		restore_flags(flags);
+	switch (flags) {
+	case 0:
+		__global_cli();
+		break;
+	case 1:
+		__global_sti();
+		break;
+	case 2:
+		__cli();
+		break;
+	case 3:
+		__sti();
+		break;
+	default:
+	{
+		unsigned long pc;
+		__asm__ __volatile__("mov %%i7, %0" : "=r" (pc));
+		printk("global_restore_flags: Bogon flags(%016lx) caller %016lx\n",
+		       flags, pc);
+	}
 	}
 }
 
@@ -787,7 +811,7 @@
 	/*
 	 * Check for TICK_INT on level 14 softint.
 	 */
-	if ((irq == 14) && get_softint() & (1UL << 0))
+	if ((irq == 14) && (get_softint() & (1UL << 0)))
 		irq = 0;
 #endif
 	clear_softint(1 << irq);
@@ -1004,12 +1028,15 @@
 /* Called from smp_commence, when we know how many cpus are in the system
  * and can have device IRQ's directed at them.
  */
+/* #define SMP_IRQ_VERBOSE */
 void distribute_irqs(void)
 {
 	unsigned long flags;
 	int cpu, level;
 
+#ifdef SMP_IRQ_VERBOSE
 	printk("SMP: redistributing interrupts...\n");
+#endif
 	save_and_cli(flags);
 	cpu = 0;
 	for(level = 0; level < NR_IRQS; level++) {
@@ -1020,16 +1047,18 @@
 				struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
 				unsigned int *imap = __imap(bucket);
 				unsigned int val;
-				unsigned long tid = __cpu_logical_map[cpu] << 9;
+				unsigned long tid = __cpu_logical_map[cpu] << 26;
 
 				val = *imap;
 				*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
 
+#ifdef SMP_IRQ_VERBOSE
 				printk("SMP: Redirecting IGN[%x] INO[%x] "
 				       "to cpu %d [%s]\n",
 				       (val & SYSIO_IMAP_IGN) >> 6,
 				       (val & SYSIO_IMAP_INO), cpu,
 				       p->name);
+#endif
 
 				cpu++;
 				if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1)
@@ -1114,12 +1143,17 @@
 
 __initfunc(void init_IRQ(void))
 {
-	int i;
+	static int called = 0;
+
+	if (called == 0) {
+		int i;
 
-	map_prom_timers();
-	kill_prom_timer();
-	for(i = 0; i < NUM_IVECS; i++)
-		ivector_to_mask[i] = 0;
+		called = 1;
+		map_prom_timers();
+		kill_prom_timer();
+		for(i = 0; i < NUM_IVECS; i++)
+			ivector_to_mask[i] = 0;
+	}
 
 	/* We need to clear any IRQ's pending in the soft interrupt
 	 * registers, a spurious one could be left around from the
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.1.126/linux/arch/sparc64/kernel/process.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/process.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.75 1998/09/23 02:05:15 davem Exp $
+/*  $Id: process.c,v 1.82 1998/10/19 21:52:23 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -71,13 +71,16 @@
 {
 	current->priority = 0;
 	while(1) {
+		struct task_struct *p;
+
 		check_pgt_cache();
 		run_task_queue(&tq_scheduler);
-		barrier();
 		current->counter = 0;
-		if(current->need_resched)
+		if (current->need_resched != 0 ||
+		    ((p = init_task.next_run) != NULL &&
+		     (p->processor == smp_processor_id() ||
+		      (p->tss.flags & SPARC_FLAG_NEWCHILD) != 0)))
 			schedule();
-		barrier();
 	}
 }
 
@@ -386,12 +389,32 @@
 		else
 			current->tss.utraps[0]--;
 	}
+
+	/* Turn off performance counters if on. */
+	if (current->tss.flags & SPARC_FLAG_PERFCTR) {
+		current->tss.user_cntd0 =
+			current->tss.user_cntd1 = NULL;
+		current->tss.pcr_reg = 0;
+		current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+		write_pcr(0);
+	}
 }
 
 void flush_thread(void)
 {
+	if (!(current->tss.flags & SPARC_FLAG_KTHREAD))
+		flush_user_windows();
 	current->tss.w_saved = 0;
 
+	/* Turn off performance counters if on. */
+	if (current->tss.flags & SPARC_FLAG_PERFCTR) {
+		current->tss.user_cntd0 =
+			current->tss.user_cntd1 = NULL;
+		current->tss.pcr_reg = 0;
+		current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+		write_pcr(0);
+	}
+
 	/* No new signal delivery by default. */
 	current->tss.new_signal = 0;
 	current->tss.fpsaved[0] = 0;
@@ -399,18 +422,14 @@
 	/* Now, this task is no longer a kernel thread. */
 	current->tss.current_ds = USER_DS;
 	if(current->tss.flags & SPARC_FLAG_KTHREAD) {
-		extern spinlock_t scheduler_lock;
-
 		current->tss.flags &= ~SPARC_FLAG_KTHREAD;
 
 		/* exec_mmap() set context to NO_CONTEXT, here is
 		 * where we grab a new one.
 		 */
-		spin_lock(&scheduler_lock);
 		current->mm->cpu_vm_mask = 0;
 		activate_context(current);
 		current->mm->cpu_vm_mask = (1UL<<smp_processor_id());
-		spin_unlock(&scheduler_lock);
 	}
 	if (current->tss.flags & SPARC_FLAG_32BIT)
 		__asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -524,7 +543,6 @@
 	current->tss.w_saved = 0;
 	return;
 barf:
-	lock_kernel();
 	do_exit(SIGILL);
 }
 
@@ -552,7 +570,19 @@
 	p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
 	p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
 	p->tss.fpsaved[0] = 0;
+	p->mm->segments = (void *) 0;
 	if(regs->tstate & TSTATE_PRIV) {
+		/* Special case, if we are spawning a kernel thread from
+		 * a userspace task (via KMOD, NFS, or similar) we must
+		 * disable performance counters in the child because the
+		 * address space and protection realm are changing.
+		 */
+		if (current->tss.flags & SPARC_FLAG_PERFCTR) {
+			p->tss.user_cntd0 =
+				p->tss.user_cntd1 = NULL;
+			p->tss.pcr_reg = 0;
+			p->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+		}
 		p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
 		p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD);
 		p->tss.current_ds = KERNEL_DS;
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c
--- v2.1.126/linux/arch/sparc64/kernel/psycho.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/psycho.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.64 1998/09/01 07:24:24 jj Exp $
+/* $Id: psycho.c,v 1.65 1998/10/20 14:41:28 ecd Exp $
  * psycho.c: Ultra/AX U2P PCI controller support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1639,17 +1639,8 @@
 		return;
 	}
 
-	/* See if we find a matching interrupt-map entry. */
-	if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
-		pdev->irq = psycho_irq_build(pbm, pdev,
-					     (pbm->parent->upa_portid << 6)
-					     | prom_irq);
-#ifdef FIXUP_IRQ_DEBUG
-		dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
-			prom_irq, pdev->irq);
-#endif
 	/* See if fully specified already (ie. for onboard devices like hme) */
-	} else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
+	if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
 		pdev->irq = psycho_irq_build(pbm, pdev, prom_irq);
 #ifdef FIXUP_IRQ_DEBUG
 		dprintf("fully specified prom_irq[%x] pdev->irq[%x]",
@@ -1663,6 +1654,15 @@
 #ifdef FIXUP_IRQ_DEBUG
 		dprintf("partially specified prom_irq[%x] pdev->irq[%x]",
 		        prom_irq, pdev->irq);
+#endif
+	/* See if we find a matching interrupt-map entry. */
+	} else if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
+		pdev->irq = psycho_irq_build(pbm, pdev,
+					     (pbm->parent->upa_portid << 6)
+					     | prom_irq);
+#ifdef FIXUP_IRQ_DEBUG
+		dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
+			prom_irq, pdev->irq);
 #endif
 	} else {
 		unsigned int bus, slot, line;
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- v2.1.126/linux/arch/sparc64/kernel/ptrace.c	Thu Aug  6 14:06:30 1998
+++ linux/arch/sparc64/kernel/ptrace.c	Tue Oct 27 09:52:20 1998
@@ -43,6 +43,12 @@
 
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
+
+	/* Seems non-intuitive but the page copy/clear routines always
+	 * check current's value.
+	 */
+	current->mm->segments = (void *) (addr & PAGE_SIZE);
+
 	if (pgd_none(*pgdir)) {
 		handle_mm_fault(tsk, vma, addr, write);
 		goto repeat;
@@ -574,7 +580,11 @@
 		goto out;
 	}
 #endif
-	if(!(child = find_task_by_pid(pid))) {
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	read_unlock(&tasklist_lock);
+
+	if(!child) {
 		pt_error_return(regs, ESRCH);
 		goto out;
 	}
@@ -604,9 +614,13 @@
 		}
 		child->flags |= PF_PTRACED;
 		if(child->p_pptr != current) {
+			unsigned long flags;
+
+			write_lock_irqsave(&tasklist_lock, flags);
 			REMOVE_LINKS(child);
 			child->p_pptr = current;
 			SET_LINKS(child);
+			write_unlock_irqrestore(&tasklist_lock, flags);
 		}
 		send_sig(SIGSTOP, child, 1);
 		pt_succ_return(regs, 0);
@@ -781,11 +795,12 @@
 			cregs->tnpc = npc;
 		}
 		cregs->y = y;
-		for(i = 1; i < 16; i++)
+		for(i = 1; i < 16; i++) {
 			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
 				pt_error_return(regs, EFAULT);
 				goto out;
 			}
+		}
 		pt_succ_return(regs, 0);
 		goto out;
 	}
@@ -814,11 +829,12 @@
 			cregs->tnpc = tnpc;
 		}
 		cregs->y = y;
-		for(i = 1; i < 16; i++)
+		for(i = 1; i < 16; i++) {
 			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
 				pt_error_return(regs, EFAULT);
 				goto out;
 			}
+		}
 		pt_succ_return(regs, 0);
 		goto out;
 	}
@@ -1055,23 +1071,29 @@
 			pt_succ_return(regs, 0);
 			goto out;
 		}
-		wake_up_process(child);
 		child->exit_code = SIGKILL;
+		wake_up_process(child);
 		pt_succ_return(regs, 0);
 		goto out;
 	}
 
 	case PTRACE_SUNDETACH: { /* detach a process that was attached. */
+		unsigned long flags;
+
 		if ((unsigned long) data > _NSIG) {
 			pt_error_return(regs, EIO);
 			goto out;
 		}
 		child->flags &= ~(PF_PTRACED|PF_TRACESYS);
-		wake_up_process(child);
 		child->exit_code = data;
+
+		write_lock_irqsave(&tasklist_lock, flags);
 		REMOVE_LINKS(child);
 		child->p_pptr = child->p_opptr;
 		SET_LINKS(child);
+		write_unlock_irqrestore(&tasklist_lock, flags);
+
+		wake_up_process(child);
 		pt_succ_return(regs, 0);
 		goto out;
 	}
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.1.126/linux/arch/sparc64/kernel/rtrap.S	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/rtrap.S	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.40 1998/09/23 02:05:18 davem Exp $
+/* $Id: rtrap.S,v 1.44 1998/10/21 22:27:22 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -46,13 +46,15 @@
 		ldub			[%l6 + %o0], %l2
 		sub			%l5, 2, %l5
 		add			%g6, AOFF_task_tss + AOFF_thread_gsr, %o1
-		andcc			%l2, FPRS_FEF, %g0
+		andcc			%l2, (FPRS_FEF|FPRS_DU), %g0
 		be,pt			%icc, 2f
 		 and			%l2, FPRS_DL, %l6
+		andcc			%l2, FPRS_FEF, %g0
+		be,pn			%icc, 5f
+		 sll			%o0, 3, %o5
 		rd			%fprs, %g5
 		wr			%g5, FPRS_FEF, %fprs
 		ldub			[%o1 + %o0], %g5
-		sll			%o0, 3, %o5
 		add			%g6, AOFF_task_tss + AOFF_thread_xfsr, %o1
 		membar			#StoreLoad | #LoadLoad
 		sll			%o0, 8, %o2
@@ -130,25 +132,49 @@
 		 nop
 		lduw			[%g6 + AOFF_task_sigpending], %l0
 check_signal:	brz,a,pt		%l0, check_user_wins
-		 lduh			[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+		 nop
 		clr			%o0
 		mov			%l5, %o2  
 		mov			%l6, %o3
 		call			do_signal
 		 add			%sp, STACK_BIAS + REGWIN_SZ, %o1
-		lduh			[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
 		clr			%l6
-check_user_wins:brz,pt			%o2, 1f
+
+		/* We must not take any traps between here and the actual
+		 * return to user-space.  If we do we risk having windows
+		 * saved to the thread struct between the test and the
+		 * actual return from trap.  --DaveM
+		 */
+check_user_wins:
+		wrpr			%l7, 0x0, %pstate
+		lduh			[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+		brz,pt			%o2, 1f
 		 sethi			%hi(TSTATE_PEF), %l6
 
+		wrpr			%l7, PSTATE_IE, %pstate
 		call			fault_in_user_windows
 		 add			%sp, STACK_BIAS + REGWIN_SZ, %o0
-
+		/* It is OK to leave interrupts on now because if
+		 * fault_in_user_windows has returned it has left us
+		 * with a clean user stack state.
+		 */
 1:
 #if 0
 		call			rtrap_check
 		 add			%sp, STACK_BIAS + REGWIN_SZ, %o0
 #endif
+		lduh			[%g6 + AOFF_task_tss + AOFF_thread_flags], %l5
+		andcc			%l5, 0x200, %g0
+		be,pt			%xcc, 1f
+		 nop
+
+		/* Don't forget to preserve user window invariants. */
+		wrpr			%l7, PSTATE_IE, %pstate
+		call			update_perfctrs
+		 nop
+		ba,a,pt			%xcc, check_user_wins
+
+1:
 		andcc			%l1, %l6, %g0
 		be,pt			%xcc, rt_continue
 		 stb			%g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
@@ -159,5 +185,17 @@
 		 andn			%l1, %l6, %l1
 		ba,pt			%xcc, rt_continue+4
 		 lduh			[%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
+
+5:		wr			%g0, FPRS_FEF, %fprs
+		membar			#StoreLoad | #LoadLoad
+		sll			%o0, 8, %o2
+		add			%g6, AOFF_task_fpregs+0x80, %o3
+		add			%g6, AOFF_task_fpregs+0xc0, %o4
+		ldda			[%o3 + %o2] ASI_BLK_P, %f32
+		ldda			[%o4 + %o2] ASI_BLK_P, %f48
+1:		membar			#Sync
+		wr			%g0, FPRS_DU, %fprs
+		ba,pt			%xcc, rt_continue
+		 stb			%l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth]
 
 #undef PTREGS_OFF
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.1.126/linux/arch/sparc64/kernel/setup.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/setup.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.32 1998/09/24 03:21:37 davem Exp $
+/*  $Id: setup.c,v 1.37 1998/10/14 15:49:09 ecd Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -62,38 +62,207 @@
  * prints out pretty messages and returns.
  */
 
-extern unsigned long sparc64_ttable_tl0;
 #if CONFIG_SUN_CONSOLE
 void (*prom_palette)(int);
 #endif
 asmlinkage void sys_sync(void);	/* it's really int */
 
+static void
+prom_console_write(struct console *con, const char *s, unsigned n)
+{
+	prom_printf("%s", s);
+}
+
+static struct console prom_console = {
+	"prom",
+	prom_console_write,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	CON_CONSDEV | CON_ENABLED,
+	-1,
+	0,
+	NULL
+};
+
+#define PROM_TRUE	-1
+#define PROM_FALSE	0
+
 /* Pretty sick eh? */
-void prom_sync_me(long *args)
+int prom_callback(long *args)
 {
-	unsigned long prom_tba, flags;
+	struct console *cons, *saved_console = NULL;
+	unsigned long flags;
+	char *cmd;
+
+	if (!args)
+		return -1;
+	if (!(cmd = (char *)args[0]))
+		return -1;
 
 	save_and_cli(flags);
-	__asm__ __volatile__("flushw; rdpr %%tba, %0\n\t" : "=r" (prom_tba));
-	__asm__ __volatile__("wrpr %0, 0x0, %%tba\n\t" : : "r" (&sparc64_ttable_tl0));
-
-#ifdef CONFIG_SUN_CONSOLE
-	if (prom_palette)
-        	prom_palette (1);
-#endif
-	prom_printf("PROM SYNC COMMAND...\n");
-	show_free_areas();
-	if(current->pid != 0) {
-		sti();
-		sys_sync();
-		cli();
+	cons = console_drivers;
+	while (cons) {
+		unregister_console(cons);
+		cons->flags &= ~(CON_PRINTBUFFER);
+		cons->next = saved_console;
+		saved_console = cons;
+		cons = console_drivers;
 	}
-	prom_printf("Returning to prom\n");
+	register_console(&prom_console);
+	if (!strcmp(cmd, "sync")) {
+		prom_printf("PROM `%s' command...\n", cmd);
+		show_free_areas();
+		if(current->pid != 0) {
+			sti();
+			sys_sync();
+			cli();
+		}
+		args[2] = 0;
+		args[args[1] + 3] = -1;
+		prom_printf("Returning to PROM\n");
+	} else if (!strcmp(cmd, "va>tte-data")) {
+		unsigned long ctx, va;
+		unsigned long tte = 0;
+		long res = PROM_FALSE;
+
+		ctx = args[3];
+		va = args[4];
+		if (ctx) {
+			/*
+			 * Find process owning ctx, lookup mapping.
+			 */
+			struct task_struct *p;
+			pgd_t *pgdp;
+			pmd_t *pmdp;
+			pte_t *ptep;
+
+			for_each_task(p)
+				if (p->tss.ctx == ctx)
+					break;
+			if (p->tss.ctx != ctx)
+				goto done;
+
+			pgdp = pgd_offset(p->mm, va);
+			if (pgd_none(*pgdp))
+				goto done;
+			pmdp = pmd_offset(pgdp, va);
+			if (pmd_none(*pmdp))
+				goto done;
+			ptep = pte_offset(pmdp, va);
+			if (!pte_present(*ptep))
+				goto done;
+			tte = pte_val(*ptep);
+			res = PROM_TRUE;
+			goto done;
+		}
 
-	__asm__ __volatile__("flushw; wrpr %0, 0x0, %%tba\n\t" : : "r" (prom_tba));
-	restore_flags(flags);
+		if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
+			/*
+			 * Locked down tlb entry 63.
+			 */
+			tte = spitfire_get_dtlb_data(63);
+			res = PROM_TRUE;
+			goto done;
+		}
+
+		if (va < PGDIR_SIZE) {
+			/*
+			 * vmalloc or prom_inherited mapping.
+			 */
+			pgd_t *pgdp;
+			pmd_t *pmdp;
+			pte_t *ptep;
+
+			pgdp = pgd_offset_k(va);
+			if (pgd_none(*pgdp))
+				goto done;
+			pmdp = pmd_offset(pgdp, va);
+			if (pmd_none(*pmdp))
+				goto done;
+			ptep = pte_offset(pmdp, va);
+			if (!pte_present(*ptep))
+				goto done;
+			tte = pte_val(*ptep);
+			res = PROM_TRUE;
+			goto done;
+		}
+
+		if (va < PAGE_OFFSET) {
+			/*
+			 * No mappings here.
+			 */
+			goto done;
+		}
 
-	return;
+		if (va & (1UL << 40)) {
+			/*
+			 * I/O page.
+			 */
+
+			tte = (__pa(va) & _PAGE_PADDR) |
+			      _PAGE_VALID | _PAGE_SZ4MB |
+			      _PAGE_E | _PAGE_P | _PAGE_W;
+			res = PROM_TRUE;
+			goto done;
+		}
+
+		/*
+		 * Normal page.
+		 */
+		tte = (__pa(va) & _PAGE_PADDR) |
+		      _PAGE_VALID | _PAGE_SZ4MB |
+		      _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W;
+		res = PROM_TRUE;
+
+	done:
+		if (res == PROM_TRUE) {
+			args[2] = 3;
+			args[args[1] + 3] = 0;
+			args[args[1] + 4] = res;
+			args[args[1] + 5] = tte;
+		} else {
+			args[2] = 2;
+			args[args[1] + 3] = 0;
+			args[args[1] + 4] = res;
+		}
+	} else if (!strcmp(cmd, ".soft1")) {
+		unsigned long tte;
+
+		tte = args[3];
+		prom_printf("%lx:\"%s%s%s%s%s\" ",
+			    (tte & _PAGE_SOFT) >> 7,
+			    tte & _PAGE_MODIFIED ? "M" : "-",
+			    tte & _PAGE_ACCESSED ? "A" : "-",
+			    tte & _PAGE_READ     ? "W" : "-",
+			    tte & _PAGE_WRITE    ? "R" : "-",
+			    tte & _PAGE_PRESENT  ? "P" : "-");
+
+		args[2] = 2;
+		args[args[1] + 3] = 0;
+		args[args[1] + 4] = PROM_TRUE;
+	} else if (!strcmp(cmd, ".soft2")) {
+		unsigned long tte;
+
+		tte = args[3];
+		prom_printf("%lx ", (tte & _PAGE_SOFT2) >> 50);
+
+		args[2] = 2;
+		args[args[1] + 3] = 0;
+		args[args[1] + 4] = PROM_TRUE;
+	} else {
+		prom_printf("unknown PROM `%s' command...\n", cmd);
+	}
+	unregister_console(&prom_console);
+	while (saved_console) {
+		cons = saved_console;
+		saved_console = cons->next;
+		register_console(cons);
+	}
+	restore_flags(flags);
+	return 0;
 }
 
 extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
@@ -250,28 +419,6 @@
 
 extern struct consw sun_serial_con;
 
-#ifdef PROM_DEBUG_CONSOLE
-static void
-prom_console_write(struct console *con, const char *s, unsigned n)
-{
-	prom_printf("%s", s);
-}
-
-static struct console prom_console = {
-	"prom",
-	prom_console_write,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	CON_PRINTBUFFER,
-	-1,
-	0,
-	NULL
-};
-#endif
-
 __initfunc(void setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
@@ -279,10 +426,6 @@
 	unsigned long lowest_paddr, end_of_phys_memory = 0;
 	int total, i;
 
-#ifdef PROM_DEBUG_CONSOLE
-	register_console(&prom_console);
-#endif
-
 	/* Initialize PROM console and command line. */
 	*cmdline_p = prom_getbootargs();
 	strcpy(saved_command_line, *cmdline_p);
@@ -316,7 +459,13 @@
 			}
 		}
 	}
-	prom_setsync(prom_sync_me);
+	prom_setcallback(prom_callback);
+	prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
+		   "' linux-va>tte-data to va>tte-data");
+	prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
+		   "' linux-.soft1 to .soft1");
+	prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
+		   "' linux-.soft2 to .soft2");
 
 	/* In paging_init() we tip off this value to see if we need
 	 * to change init_mm.pgd to point to the real alias mapping.
@@ -439,8 +588,6 @@
 extern int smp_bogo(char *);
 extern int mmu_info(char *);
 
-unsigned long dcache_aliases_found = 0;
-
 int get_cpuinfo(char *buffer)
 {
 	int cpuid=smp_processor_id();
@@ -454,7 +601,6 @@
             "type\t\t: sun4u\n"
 	    "ncpus probed\t: %d\n"
 	    "ncpus active\t: %d\n"
-	    "d-aliases\t: %lu\n"
 #ifndef __SMP__
             "BogoMips\t: %lu.%02lu\n"
 #endif
@@ -462,7 +608,7 @@
             sparc_cpu_type[cpuid],
             sparc_fpu_type[cpuid],
             prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff,
-	    linux_num_cpus, smp_num_cpus, dcache_aliases_found
+	    linux_num_cpus, smp_num_cpus
 #ifndef __SMP__
             , loops_per_sec/500000, (loops_per_sec/5000) % 100
 #endif
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.1.126/linux/arch/sparc64/kernel/signal.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/signal.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.37 1998/09/25 01:09:22 davem Exp $
+/*  $Id: signal.c,v 1.38 1998/10/16 03:19:04 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -53,7 +53,7 @@
 	unsigned char fenab;
 	int err;
 
-	__asm__ __volatile__("flushw");
+	flush_user_windows();
 	if(tp->w_saved						||
 	   (((unsigned long)ucp) & (sizeof(unsigned long)-1))	||
 	   (!__access_ok((unsigned long)ucp, sizeof(*ucp))))
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.1.126/linux/arch/sparc64/kernel/signal32.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/signal32.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.44 1998/09/25 01:09:17 davem Exp $
+/*  $Id: signal32.c,v 1.47 1998/10/13 09:07:40 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -76,6 +76,9 @@
 	/* __siginfo_fpu32_t * */ u32 fpu_save;
 	unsigned int		insns [2];
 	unsigned		extramask[_NSIG_WORDS32 - 1];
+	unsigned		extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
+	/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
+	siginfo_extra_v8plus_t	v8plus;
 	__siginfo_fpu_t		fpu_state;
 };
 
@@ -87,6 +90,9 @@
 	/* __siginfo_fpu32_t * */ u32 fpu_save;
 	unsigned int		insns [2];
 	stack_t32		stack;
+	unsigned		extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
+	/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
+	siginfo_extra_v8plus_t	v8plus;
 	__siginfo_fpu_t		fpu_state;
 };
 
@@ -209,7 +215,7 @@
 	unsigned pc, npc, fpu_save;
 	sigset_t set;
 	unsigned seta[_NSIG_WORDS32];
-	int err;
+	int err, i;
 	
 	regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
 	sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
@@ -232,24 +238,18 @@
 	err = __get_user(regs->y, &sf->info.si_regs.y);
 	err |= __get_user(psr, &sf->info.si_regs.psr);
 
-	err |= __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]);
-	err |= __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]);
-	err |= __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]);
-	err |= __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]);
-	err |= __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]);
-	err |= __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]);
-	err |= __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]);
-	err |= __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]);
-	err |= __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]);
-	err |= __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]);
-	err |= __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]);
-	err |= __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]);
-	err |= __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]);
-	err |= __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]);
-	err |= __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]);
+	for (i = UREG_G1; i <= UREG_I7; i++)
+		err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+	if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
+		err |= __get_user(i, &sf->v8plus.g_upper[0]);
+		if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
+			for (i = UREG_G1; i <= UREG_I7; i++)
+				err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
+		}
+	}
 
 	/* User can only change condition codes in %tstate. */
-	regs->tstate &= ~(TSTATE_ICC);
+	regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
 	regs->tstate |= psr_to_tstate_icc(psr);
 
 	err |= __get_user(fpu_save, &sf->fpu_save);
@@ -273,7 +273,6 @@
 	return;
 
 segv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -329,12 +328,11 @@
 	err |= __get_user(psr, &scptr->sigc_psr);
 	if (err)
 		goto segv;
-	regs->tstate &= ~(TSTATE_ICC);
+	regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
 	regs->tstate |= psr_to_tstate_icc(psr);
 	return;
 
 segv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -346,7 +344,7 @@
 	sigset_t set;
 	sigset_t32 seta;
 	stack_t st;
-	int err;
+	int err, i;
 	
 	synchronize_user_stack();
 	regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
@@ -369,25 +367,19 @@
 	/* 2. Restore the state */
 	err = __get_user(regs->y, &sf->regs.y);
 	err |= __get_user(psr, &sf->regs.psr);
-
-	err |= __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]);
-	err |= __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]);
-	err |= __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]);
-	err |= __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]);
-	err |= __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]);
-	err |= __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]);
-	err |= __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]);
-	err |= __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]);
-	err |= __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]);
-	err |= __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]);
-	err |= __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]);
-	err |= __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]);
-	err |= __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]);
-	err |= __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]);
-	err |= __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]);
+	
+	for (i = UREG_G1; i <= UREG_I7; i++)
+		err |= __get_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+	if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
+		err |= __get_user(i, &sf->v8plus.g_upper[0]);
+		if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
+			for (i = UREG_G1; i <= UREG_I7; i++)
+				err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
+		}
+	}
 
 	/* User can only change condition codes in %tstate. */
-	regs->tstate &= ~(TSTATE_ICC);
+	regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
 	regs->tstate |= psr_to_tstate_icc(psr);
 
 	err |= __get_user(fpu_save, &sf->fpu_save);
@@ -417,7 +409,6 @@
 	spin_unlock_irq(&current->sigmask_lock);
 	return;
 segv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -472,7 +463,6 @@
 		/* Don't change signal code and address, so that
 		 * post mortem debuggers can have a look.
 		 */
-		lock_kernel ();
 		do_exit(SIGILL);
 	}
 
@@ -544,7 +534,6 @@
 	return;
 
 sigsegv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -614,6 +603,10 @@
 	err |= __put_user(psr, &sf->info.si_regs.psr);
 	for (i = 0; i < 16; i++)
 		err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+	err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
+	err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
+	for (i = 1; i < 16; i++)
+		err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
 
 	if (psr & PSR_EF) {
 		err |= save_fpu_state32(regs, &sf->fpu_state);
@@ -682,10 +675,8 @@
 	return;
 
 sigill:
-	lock_kernel();
 	do_exit(SIGILL);
 sigsegv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -717,7 +708,6 @@
 #ifdef DEBUG_SIGNALS
 		printk ("Invalid stack frame\n");
 #endif
-		lock_kernel ();
 		do_exit(SIGILL);
 	}
 
@@ -833,7 +823,6 @@
 	return;
 
 sigsegv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -850,7 +839,6 @@
 	
 	if (current->tss.w_saved){
 		printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved);
-		lock_kernel();
 		do_exit (SIGSEGV);
 	}
 	err = clear_user(uc, sizeof (*uc));
@@ -968,7 +956,7 @@
 	regs->tnpc = npc | 1;
 	err |= __get_user(regs->y, &((*gr) [SVR4_Y]));
 	err |= __get_user(psr, &((*gr) [SVR4_PSR]));
-	regs->tstate &= ~(TSTATE_ICC);
+	regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
 	regs->tstate |= psr_to_tstate_icc(psr);
 #if 0	
 	if(psr & PSR_EF)
@@ -984,7 +972,6 @@
 
 	return -EINTR;
 sigsegv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -1034,6 +1021,10 @@
 	err |= __put_user(psr, &sf->regs.psr);
 	for (i = 0; i < 16; i++)
 		err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+	err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
+	err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
+	for (i = 1; i < 16; i++)
+		err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
 
 	if (psr & PSR_EF) {
 		err |= save_fpu_state32(regs, &sf->fpu_state);
@@ -1107,10 +1098,8 @@
 	return;
 
 sigill:
-	lock_kernel();
 	do_exit(SIGILL);
 sigsegv:
-	lock_kernel();
 	do_exit(SIGSEGV);
 }
 
@@ -1304,14 +1293,19 @@
 			case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
 				if(current->binfmt && current->binfmt->core_dump) {
 					lock_kernel();
-					if(current->binfmt->core_dump(signr, regs))
+					if(current->binfmt &&
+					   current->binfmt->core_dump &&
+					   current->binfmt->core_dump(signr, regs))
 						exit_code |= 0x80;
 					unlock_kernel();
 				}
 #ifdef DEBUG_SIGNALS
 				/* Very useful to debug dynamic linker problems */
 				printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
-				show_regs (regs);
+				/* On SMP we are only interested in the current
+				 * CPU's registers.
+				 */
+				__show_regs (regs);
 #ifdef DEBUG_SIGNALS_TLB
 				do {
 					extern void sparc_ultra_dump_itlb(void);
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.1.126/linux/arch/sparc64/kernel/smp.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/smp.c	Tue Oct 27 09:52:20 1998
@@ -41,7 +41,9 @@
 
 struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
 
-static unsigned char boot_cpu_id __initdata = 0;
+/* Please don't make this initdata!!!  --DaveM */
+static unsigned char boot_cpu_id = 0;
+
 static int smp_activated = 0;
 
 volatile int cpu_number_map[NR_CPUS];
@@ -82,12 +84,16 @@
 
 __initfunc(void smp_store_cpu_info(int id))
 {
-	cpu_data[id].udelay_val			= loops_per_sec;
 	cpu_data[id].irq_count			= 0;
+	cpu_data[id].bh_count			= 0;
+	/* multiplier and counter set by
+	   smp_setup_percpu_timer()  */
+	cpu_data[id].udelay_val			= loops_per_sec;
+
 	cpu_data[id].pgcache_size		= 0;
+	cpu_data[id].pte_cache			= NULL;
 	cpu_data[id].pgdcache_size		= 0;
 	cpu_data[id].pgd_cache			= NULL;
-	cpu_data[id].pte_cache			= NULL;
 }
 
 extern void distribute_irqs(void);
@@ -137,6 +143,11 @@
 	__asm__ __volatile__("membar #Sync\n\t"
 			     "flush  %%g6" : : : "memory");
 
+	/* Clear this or we will die instantly when we
+	 * schedule back to this idler...
+	 */
+	current->tss.flags &= ~(SPARC_FLAG_NEWCHILD);
+
 	while(!smp_processors_ready)
 		membar("#LoadLoad");
 }
@@ -396,6 +407,8 @@
 {
 	u32 ctx = mm->context & 0x3ff;
 
+	start &= PAGE_MASK;
+	end   &= PAGE_MASK;
 	if(mm == current->mm && atomic_read(&mm->count) == 1) {
 		if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
 			goto local_flush_and_out;
@@ -404,8 +417,6 @@
 	smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
 
 local_flush_and_out:
-	start &= PAGE_MASK;
-	end &= PAGE_MASK;
 	__flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start));
 }
 
@@ -413,6 +424,7 @@
 {
 	u32 ctx = mm->context & 0x3ff;
 
+	page &= PAGE_MASK;
 	if(mm == current->mm && atomic_read(&mm->count) == 1) {
 		if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
 			goto local_flush_and_out;
@@ -433,11 +445,11 @@
 	smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
 
 local_flush_and_out:
-	__flush_tlb_page(ctx, (page & PAGE_MASK), SECONDARY_CONTEXT);
+	__flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
 }
 
 /* CPU capture. */
-#define CAPTURE_DEBUG
+/* #define CAPTURE_DEBUG */
 extern unsigned long xcall_capture;
 
 static atomic_t smp_capture_depth = ATOMIC_INIT(0);
@@ -446,37 +458,42 @@
 
 void smp_capture(void)
 {
-	int result = atomic_add_return(1, &smp_capture_depth);
+	if (smp_processors_ready) {
+		int result = atomic_add_return(1, &smp_capture_depth);
 
-	membar("#StoreStore | #LoadStore");
-	if(result == 1) {
-		int ncpus = smp_num_cpus;
+		membar("#StoreStore | #LoadStore");
+		if(result == 1) {
+			int ncpus = smp_num_cpus;
 
 #ifdef CAPTURE_DEBUG
-		printk("CPU[%d]: Sending penguins to jail...", smp_processor_id());
+			printk("CPU[%d]: Sending penguins to jail...",
+			       smp_processor_id());
 #endif
-		penguins_are_doing_time = 1;
-		membar("#StoreStore | #LoadStore");
-		atomic_inc(&smp_capture_registry);
-		smp_cross_call(&xcall_capture, 0, 0, 0);
-		while(atomic_read(&smp_capture_registry) != ncpus)
-			membar("#LoadLoad");
+			penguins_are_doing_time = 1;
+			membar("#StoreStore | #LoadStore");
+			atomic_inc(&smp_capture_registry);
+			smp_cross_call(&xcall_capture, 0, 0, 0);
+			while(atomic_read(&smp_capture_registry) != ncpus)
+				membar("#LoadLoad");
 #ifdef CAPTURE_DEBUG
-		printk("done\n");
+			printk("done\n");
 #endif
+		}
 	}
 }
 
 void smp_release(void)
 {
-	if(atomic_dec_and_test(&smp_capture_depth)) {
+	if(smp_processors_ready) {
+		if(atomic_dec_and_test(&smp_capture_depth)) {
 #ifdef CAPTURE_DEBUG
-		printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
-		       smp_processor_id());
+			printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
+			       smp_processor_id());
 #endif
-		penguins_are_doing_time = 0;
-		membar("#StoreStore | #StoreLoad");
-		atomic_dec(&smp_capture_registry);
+			penguins_are_doing_time = 0;
+			membar("#StoreStore | #StoreLoad");
+			atomic_dec(&smp_capture_registry);
+		}
 	}
 }
 
@@ -539,8 +556,12 @@
 		if(!--prof_counter(cpu))
 		{
 			if (cpu == boot_cpu_id) {
-				extern void irq_enter(int, int);
-				extern void irq_exit(int, int);
+/* XXX Keep this in sync with irq.c --DaveM */
+#define irq_enter(cpu, irq)			\
+do {	hardirq_enter(cpu);			\
+	spin_unlock_wait(&global_irq_lock);	\
+} while(0)
+#define irq_exit(cpu, irq)	hardirq_exit(cpu)
 
 				irq_enter(cpu, 0);
 				kstat.irqs[cpu][0]++;
@@ -548,6 +569,9 @@
 				timer_tick_interrupt(regs);
 
 				irq_exit(cpu, 0);
+
+#undef irq_enter
+#undef irq_exit
 			}
 
 			if(current->pid) {
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.1.126/linux/arch/sparc64/kernel/sparc64_ksyms.c	Fri Oct  9 13:27:06 1998
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.42 1998/10/05 03:18:50 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.48 1998/10/20 03:09:08 jj Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -13,8 +13,10 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/sched.h>
 #include <linux/in6.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
 
 #include <asm/oplib.h>
 #include <asm/delay.h>
@@ -55,7 +57,6 @@
 extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
 				unsigned long, unsigned long, unsigned long);
 void _sigpause_common (unsigned int set, struct pt_regs *);
-extern void *__bzero_1page(void *);
 extern void *__bzero(void *, size_t);
 extern void *__bzero_noasi(void *, size_t);
 extern void *__memscan_zero(void *, size_t);
@@ -63,6 +64,7 @@
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 extern __kernel_size_t __strlen(const char *);
+extern __kernel_size_t strlen(const char *);
 extern char saved_command_line[];
 extern char *getname32(u32 name);
 extern void linux_sparc_syscall(void);
@@ -87,6 +89,17 @@
 
 #ifdef __SMP__
 extern spinlock_t scheduler_lock;
+extern spinlock_t kernel_flag;
+extern int smp_num_cpus;
+#ifdef SPIN_LOCK_DEBUG
+extern void _do_spin_lock (spinlock_t *lock, char *str);
+extern void _do_spin_unlock (spinlock_t *lock);
+extern int _spin_trylock (spinlock_t *lock);
+extern void _do_read_lock(rwlock_t *rw, char *str);
+extern void _do_read_unlock(rwlock_t *rw, char *str);
+extern void _do_write_lock(rwlock_t *rw, char *str);
+extern void _do_write_unlock(rwlock_t *rw);
+#endif
 #endif
 
 /* One thing to note is that the way the symbols of the mul/div
@@ -102,19 +115,46 @@
 
 /* used by various drivers */
 #ifdef __SMP__
+/* Kernel wide locking */
 EXPORT_SYMBOL(scheduler_lock);
+EXPORT_SYMBOL(kernel_flag);
+
+/* Software-IRQ BH locking */
 EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_bh_count);
+EXPORT_SYMBOL(synchronize_bh);
+
+/* Hard IRQ locking */
 EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
 EXPORT_SYMBOL(synchronize_irq);
-EXPORT_SYMBOL(cpu_data);
 EXPORT_SYMBOL_PRIVATE(global_cli);
 EXPORT_SYMBOL_PRIVATE(global_sti);
+EXPORT_SYMBOL_PRIVATE(global_save_flags);
 EXPORT_SYMBOL_PRIVATE(global_restore_flags);
+
+/* Per-CPU information table */
+EXPORT_SYMBOL(cpu_data);
+
+/* Misc SMP information */
+EXPORT_SYMBOL(smp_num_cpus);
+
+/* Spinlock debugging library, optional. */
+#ifdef SPIN_LOCK_DEBUG
+EXPORT_SYMBOL(_do_spin_lock);
+EXPORT_SYMBOL(_do_spin_unlock);
+EXPORT_SYMBOL(_spin_trylock);
+EXPORT_SYMBOL(_do_read_lock);
+EXPORT_SYMBOL(_do_read_unlock);
+EXPORT_SYMBOL(_do_write_lock);
+EXPORT_SYMBOL(_do_write_unlock);
+#endif
+
 #else
 EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(local_bh_count);
 #endif
-EXPORT_SYMBOL_PRIVATE(_lock_kernel);
-EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 
@@ -124,7 +164,6 @@
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
 EXPORT_SYMBOL(sparc_free_io);
-EXPORT_SYMBOL(__sparc64_bh_counter);
 EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
 EXPORT_SYMBOL(mmu_get_scsi_sgl);
 EXPORT_SYMBOL(mmu_get_scsi_one);
@@ -185,6 +224,9 @@
 /* sparc library symbols */
 EXPORT_SYMBOL(bcopy);
 EXPORT_SYMBOL(__strlen);
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
+EXPORT_SYMBOL(strlen);
+#endif
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
@@ -220,7 +262,7 @@
 /* Special internal versions of library functions. */
 EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memset);
-EXPORT_SYMBOL(__bzero_1page);
+EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(__bzero);
 EXPORT_SYMBOL(__memscan_zero);
 EXPORT_SYMBOL(__memscan_generic);
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.1.126/linux/arch/sparc64/kernel/sys_sparc.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/sys_sparc.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.22 1998/09/25 01:09:27 davem Exp $
+/* $Id: sys_sparc.c,v 1.25 1998/10/21 03:21:15 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -25,6 +25,7 @@
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 #include <asm/utrap.h>
+#include <asm/perfctr.h>
 
 /* XXX Make this per-binary type, this way we can detect the type of
  * XXX a binary.  Every Sparc executable calls this very early on.
@@ -151,6 +152,7 @@
 	struct file * file = NULL;
 	unsigned long retval = -EBADF;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
@@ -189,6 +191,7 @@
 		fput(file);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return retval;
 }
 
@@ -377,4 +380,106 @@
 	}
 
 	return ret;
+}
+
+/* Invoked by rtrap code to update performance counters in
+ * user space.
+ */
+asmlinkage void
+update_perfctrs(void)
+{
+	unsigned long pic, tmp;
+
+	read_pic(pic);
+	tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
+	__put_user(tmp, current->tss.user_cntd0);
+	tmp = (current->tss.kernel_cntd1 += (pic >> 32));
+	__put_user(tmp, current->tss.user_cntd1);
+	reset_pic();
+}
+
+asmlinkage int
+sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2)
+{
+	int err = 0;
+
+	switch(opcode) {
+	case PERFCTR_ON:
+		current->tss.pcr_reg = arg2;
+		current->tss.user_cntd0 = (u64 *) arg0;
+		current->tss.user_cntd1 = (u64 *) arg1;
+		current->tss.kernel_cntd0 =
+			current->tss.kernel_cntd1 = 0;
+		write_pcr(arg2);
+		reset_pic();
+		current->tss.flags |= SPARC_FLAG_PERFCTR;
+		break;
+
+	case PERFCTR_OFF:
+		err = -EINVAL;
+		if ((current->tss.flags & SPARC_FLAG_PERFCTR) != 0) {
+			current->tss.user_cntd0 =
+				current->tss.user_cntd1 = NULL;
+			current->tss.pcr_reg = 0;
+			write_pcr(0);
+			current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+			err = 0;
+		}
+		break;
+
+	case PERFCTR_READ: {
+		unsigned long pic, tmp;
+
+		if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+			err = -EINVAL;
+			break;
+		}
+		read_pic(pic);
+		tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
+		err |= __put_user(tmp, current->tss.user_cntd0);
+		tmp = (current->tss.kernel_cntd1 += (pic >> 32));
+		err |= __put_user(tmp, current->tss.user_cntd1);
+		reset_pic();
+		break;
+	}
+
+	case PERFCTR_CLRPIC:
+		if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+			err = -EINVAL;
+			break;
+		}
+		current->tss.kernel_cntd0 =
+			current->tss.kernel_cntd1 = 0;
+		reset_pic();
+		break;
+
+	case PERFCTR_SETPCR: {
+		u64 *user_pcr = (u64 *)arg0;
+		if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+			err = -EINVAL;
+			break;
+		}
+		err |= __get_user(current->tss.pcr_reg, user_pcr);
+		write_pcr(current->tss.pcr_reg);
+		current->tss.kernel_cntd0 =
+			current->tss.kernel_cntd1 = 0;
+		reset_pic();
+		break;
+	}
+
+	case PERFCTR_GETPCR: {
+		u64 *user_pcr = (u64 *)arg0;
+		if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+			err = -EINVAL;
+			break;
+		}
+		err |= __put_user(current->tss.pcr_reg, user_pcr);
+		break;
+	}
+
+	default:
+		err = -EINVAL;
+		break;
+	};
+	return err;
 }
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.1.126/linux/arch/sparc64/kernel/sys_sparc32.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.95 1998/09/07 09:20:50 davem Exp $
+/* $Id: sys_sparc32.c,v 1.98 1998/10/26 20:01:11 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -224,9 +224,6 @@
         __kernel_ipc_pid_t32    shm_cpid; 
         __kernel_ipc_pid_t32    shm_lpid; 
         unsigned short          shm_nattch;
-        unsigned short          shm_npages;
-        u32			shm_pages;
-        u32			attaches; 
 };
                                                         
 /*
@@ -1394,7 +1391,7 @@
 		else if(is_smb)
 			do_smb_super_data_conv((void *)data_page);
 		else
-			panic("Tell DaveM he fucked up...");
+			panic("The problem is here...");
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
 		err = sys_mount((char *)dev_page, (char *)dir_page,
@@ -2707,10 +2704,53 @@
 
 /* Query various bits about modules.  */
 
-extern long get_mod_name(const char *user_name, char **buf);
-extern void put_mod_name(char *buf);
-extern struct module *find_module(const char *name);
-extern struct module kernel_module;
+static inline long
+get_mod_name(const char *user_name, char **buf)
+{
+	unsigned long page;
+	long retval;
+
+	if ((unsigned long)user_name >= TASK_SIZE
+	    && !segment_eq(get_fs (), KERNEL_DS))
+		return -EFAULT;
+
+	page = __get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE);
+	if (retval > 0) {
+		if (retval < PAGE_SIZE) {
+			*buf = (char *)page;
+			return retval;
+		}
+		retval = -ENAMETOOLONG;
+	} else if (!retval)
+		retval = -EINVAL;
+
+	free_page(page);
+	return retval;
+}
+
+static inline void
+put_mod_name(char *buf)
+{
+	free_page((unsigned long)buf);
+}
+
+static __inline__ struct module *find_module(const char *name)
+{
+	struct module *mod;
+
+	for (mod = module_list; mod ; mod = mod->next) {
+		if (mod->flags & MOD_DELETED)
+			continue;
+		if (!strcmp(mod->name, name))
+			break;
+	}
+
+	return mod;
+}
 
 static int
 qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
@@ -2720,7 +2760,7 @@
 
 	nmod = space = 0;
 
-	for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) {
+	for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) {
 		len = strlen(mod->name)+1;
 		if (len > bufsize)
 			goto calc_space_needed;
@@ -2738,7 +2778,7 @@
 
 calc_space_needed:
 	space += len;
-	while ((mod = mod->next) != &kernel_module)
+	while ((mod = mod->next)->next != NULL)
 		space += strlen(mod->name)+1;
 
 	if (put_user(space, ret))
@@ -2752,7 +2792,7 @@
 {
 	size_t i, space, len;
 
-	if (mod == &kernel_module)
+	if (mod->next == NULL)
 		return -EINVAL;
 	if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
 		if (put_user(0, ret))
@@ -2796,7 +2836,7 @@
 	size_t nrefs, space, len;
 	struct module_ref *ref;
 
-	if (mod == &kernel_module)
+	if (mod->next == NULL)
 		return -EINVAL;
 	if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
 		if (put_user(0, ret))
@@ -2898,7 +2938,7 @@
 {
 	int error = 0;
 
-	if (mod == &kernel_module)
+	if (mod->next == NULL)
 		return -EINVAL;
 
 	if (sizeof(struct module_info32) <= bufsize) {
@@ -2926,9 +2966,11 @@
 	int err;
 
 	lock_kernel();
-	if (name_user == 0)
-		mod = &kernel_module;
-	else {
+	if (name_user == 0) {
+		/* This finds "kernel_module" which is not exported. */
+		for(mod = module_list; mod->next != NULL; mod = mod->next)
+			;
+	} else {
 		long namelen;
 		char *name;
 
@@ -2937,9 +2979,11 @@
 			goto out;
 		}
 		err = -ENOENT;
-		if (namelen == 0)
-			mod = &kernel_module;
-		else if ((mod = find_module(name)) == NULL) {
+		if (namelen == 0) {
+			/* This finds "kernel_module" which is not exported. */
+			for(mod = module_list; mod->next != NULL; mod = mod->next)
+				;
+		} else if ((mod = find_module(name)) == NULL) {
 			put_mod_name(name);
 			goto out;
 		}
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.1.126/linux/arch/sparc64/kernel/sys_sunos32.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.18 1998/08/31 03:41:01 davem Exp $
+/* $Id: sys_sunos32.c,v 1.22 1998/10/26 20:01:13 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6 +68,7 @@
 	struct file *file = NULL;
 	unsigned long retval, ret_type;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	current->personality |= PER_BSD;
 	if(flags & MAP_NORESERVE) {
@@ -117,6 +118,7 @@
 		fput(file);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return (u32) retval;
 }
 
@@ -131,6 +133,7 @@
 	unsigned long rlim;
 	unsigned long newbrk, oldbrk, brk = (unsigned long) baddr;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (brk < current->mm->end_code)
 		goto out;
@@ -178,6 +181,7 @@
 	retval = 0;
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return retval;
 }
 
@@ -538,27 +542,17 @@
 	char mach[9];
 };
 
-asmlinkage int sunos_uname(u32 u_name)
+asmlinkage int sunos_uname(struct sunos_utsname *name)
 {
-	struct sunos_utsname *name = (struct sunos_utsname *)A(u_name);
-	int ret = -EFAULT;
+	int ret;
 
 	down(&uts_sem);
-	if(!name)
-		goto out;
-	if(copy_to_user(&name->sname[0],
-			&system_utsname.sysname[0],
-			sizeof(name->sname) - 1))
-		goto out;
-	copy_to_user(&name->nname[0],
-		     &system_utsname.nodename[0],
-		     sizeof(name->nname) - 1);
-	put_user('\0', &name->nname[8]);
-	copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
-	copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
-	copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
-	ret = 0;
-out:
+	ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
+	ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
+	ret |= put_user('\0', &name->nname[8]);
+	ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
+	ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
+	ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
 	up(&uts_sem);
 	return ret;
 }
@@ -837,6 +831,8 @@
 	int ret = -EINVAL;
 	char *dev_fname = 0;
 
+	if (!capable (CAP_SYS_ADMIN))
+		return -EPERM;
 	lock_kernel();
 	/* We don't handle the integer fs type */
 	if ((flags & SMNT_NEWTYPE) == 0)
@@ -1211,9 +1207,6 @@
         __kernel_ipc_pid_t32    shm_cpid; 
         __kernel_ipc_pid_t32    shm_lpid; 
         unsigned short          shm_nattch;
-        unsigned short          shm_npages;
-        u32			shm_pages;
-        u32			attaches; 
 };
                                                         
 static inline int sunos_shmid_get(struct shmid_ds32 *user,
@@ -1230,8 +1223,7 @@
 	   __get_user(kern->shm_ctime, &user->shm_ctime)		||
 	   __get_user(kern->shm_cpid, &user->shm_cpid)			||
 	   __get_user(kern->shm_lpid, &user->shm_lpid)			||
-	   __get_user(kern->shm_nattch, &user->shm_nattch)		||
-	   __get_user(kern->shm_npages, &user->shm_npages))
+	   __get_user(kern->shm_nattch, &user->shm_nattch))
 		return -EFAULT;
 	return 0;
 }
@@ -1250,8 +1242,7 @@
 	   __put_user(kern->shm_ctime, &user->shm_ctime)		||
 	   __put_user(kern->shm_cpid, &user->shm_cpid)			||
 	   __put_user(kern->shm_lpid, &user->shm_lpid)			||
-	   __put_user(kern->shm_nattch, &user->shm_nattch)		||
-	   __put_user(kern->shm_npages, &user->shm_npages))
+	   __put_user(kern->shm_nattch, &user->shm_nattch))
 		return -EFAULT;
 	return 0;
 }
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.1.126/linux/arch/sparc64/kernel/systbls.S	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/systbls.S	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.49 1998/09/13 04:30:32 davem Exp $
+/* $Id: systbls.S,v 1.50 1998/10/07 01:27:27 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -20,7 +20,7 @@
 /*0*/	.word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
 /*5*/	.word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
 /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod
-/*15*/	.word sys32_chmod, sys32_lchown, sparc_brk, sys_nis_syscall, sys32_lseek
+/*15*/	.word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek
 /*20*/	.word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
 /*25*/	.word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
 /*30*/	.word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
@@ -79,7 +79,7 @@
 /*0*/	.word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
 /*5*/	.word sys_open, sys_close, sys_wait4, sys_creat, sys_link
 /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod
-/*15*/	.word sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek
+/*15*/	.word sys_chmod, sys_lchown, sparc_brk, sys_perfctr, sys_lseek
 /*20*/	.word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
 /*25*/	.word sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall
 /*30*/	.word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- v2.1.126/linux/arch/sparc64/kernel/trampoline.S	Thu Aug  6 14:06:31 1998
+++ linux/arch/sparc64/kernel/trampoline.S	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.5 1998/05/25 05:31:45 davem Exp $
+/* $Id: trampoline.S,v 1.6 1998/10/11 06:58:23 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -27,6 +27,7 @@
 	stxa	%g1, [%g0] ASI_LSU_CONTROL
 	membar	#Sync
 	wrpr	%g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+	wr	%g0, 0, %fprs
 	wrpr	%g0, 15, %pil
 
 	sethi	%uhi(PAGE_OFFSET), %g4
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.1.126/linux/arch/sparc64/kernel/traps.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/traps.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.54 1998/09/25 01:09:02 davem Exp $
+/* $Id: traps.c,v 1.55 1998/10/11 06:58:22 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -661,7 +661,7 @@
 #ifndef __SMP__
 	unsigned node = linux_cpus[get_cpuid()].prom_node;
 #else
-#error SMP not supported on sparc64 yet
+#error cache_flush_trap not supported on sparc64/SMP yet
 #endif
 
 #if 0
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/unaligned.c linux/arch/sparc64/kernel/unaligned.c
--- v2.1.126/linux/arch/sparc64/kernel/unaligned.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/kernel/unaligned.c	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.11 1998/09/22 03:24:52 davem Exp $
+/* $Id: unaligned.c,v 1.13 1998/10/07 22:43:13 davem Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -58,9 +58,10 @@
 {
 	unsigned int tmp;
 
-	if (((insn >> 19) & 0xf) == 14)
-		return 8;	/* stx* */
-	tmp = (insn >> 19) & 3;
+	tmp = ((insn >> 19) & 0xf);
+	if (tmp == 11 || tmp == 14) /* ldx/stx */
+		return 8;
+	tmp &= 3;
 	if(!tmp)
 		return 4;
 	else if(tmp == 3)
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile
--- v2.1.126/linux/arch/sparc64/lib/Makefile	Thu Aug  6 14:06:31 1998
+++ linux/arch/sparc64/lib/Makefile	Tue Oct 27 09:52:20 1998
@@ -1,10 +1,10 @@
-# $Id: Makefile,v 1.16 1998/06/12 14:53:53 jj Exp $
+# $Id: Makefile,v 1.18 1998/10/13 09:07:24 davem Exp $
 # Makefile for Sparc library files..
 #
 
 CFLAGS := $(CFLAGS)
 
-OBJS  = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \
+OBJS  = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
 	memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
 	VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o
 
@@ -16,10 +16,10 @@
 VISbzero.o: VISbzero.S VIS.h
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
 
 dep:
 
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/VIScopy.S linux/arch/sparc64/lib/VIScopy.S
--- v2.1.126/linux/arch/sparc64/lib/VIScopy.S	Thu Aug  6 14:06:31 1998
+++ linux/arch/sparc64/lib/VIScopy.S	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.18 1998/06/12 14:53:55 jj Exp $
+/* $Id: VIScopy.S,v 1.19 1998/10/19 21:52:19 davem Exp $
  * VIScopy.S: High speed copy operations utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -480,7 +480,7 @@
 vis01:FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_SYNC(o0, f48) membar #Sync
       FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)  STORE_JUMP(o0, f48, finish_f0) membar #Sync
 vis02:FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)  STORE_SYNC(o0, f48) membar #Sync
-      FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, check_finish_f16) add %o2, %g3, %g7
+      FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, finish_f16) membar #Sync
 vis03:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_SYNC(o0, f48) membar #Sync
       FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_JUMP(o0, f48, finish_f32) membar #Sync
       VISLOOP_PAD
@@ -569,18 +569,7 @@
 finish_f10:	FINISH_VISCHUNK(o0, f10, f12, g3)
 finish_f12:	FINISH_VISCHUNK(o0, f12, f14, g3)
 finish_f14:	UNEVEN_VISCHUNK(o0, f14, f0,  g3)
-/* This is a special hack to speed up 8K page copy */
-check_finish_f16:
-		andcc 		%g1, 7, %g0
-		bne,pn		%icc, finish_f16
-		 cmp		%g7, 0x40
-		bne,pn		%icc, finish_f16
-		 FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
-		membar #Sync
-		EXVIS1(STBLK	%f48, [%o0] ASIBLK)
-		b,pt		%xcc, vis_ret
-finish_f16:	 membar		#Sync
-		FINISH_VISCHUNK(o0, f16, f18, g3)
+finish_f16:	FINISH_VISCHUNK(o0, f16, f18, g3)
 finish_f18:	FINISH_VISCHUNK(o0, f18, f20, g3)
 finish_f20:	FINISH_VISCHUNK(o0, f20, f22, g3)
 finish_f22:	FINISH_VISCHUNK(o0, f22, f24, g3)
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/VISsave.S linux/arch/sparc64/lib/VISsave.S
--- v2.1.126/linux/arch/sparc64/lib/VISsave.S	Thu Aug  6 14:06:31 1998
+++ linux/arch/sparc64/lib/VISsave.S	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: VISsave.S,v 1.2 1998/06/19 12:14:25 jj Exp $
+/* $Id: VISsave.S,v 1.3 1998/10/21 10:36:39 jj Exp $
  * VISsave.S: Code for saving FPU register state for
  *            VIS routines. One should not call this directly,
  *            but use macros provided in <asm/visasm.h>.
@@ -76,11 +76,13 @@
 
 	sll		%g1, 5, %g1
 	add		%g6, AOFF_task_fpregs+0xc0, %g3
+	wr		%g0, FPRS_FEF, %fprs
 	membar		#StoreStore | #LoadStore
 	stda		%f32, [%g2 + %g1] ASI_BLK_P
 	stda		%f48, [%g3 + %g1] ASI_BLK_P
 	membar		#Sync
 	jmpl		%g7 + %g0, %g0
+
 	 nop
 
 	.align		32
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- v2.1.126/linux/arch/sparc64/lib/blockops.S	Thu Aug  6 14:06:31 1998
+++ linux/arch/sparc64/lib/blockops.S	Tue Oct 27 09:52:20 1998
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.14 1998/06/12 14:53:46 jj Exp $
+/* $Id: blockops.S,v 1.16 1998/10/20 03:09:04 jj Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,9 @@
 
 #include "VIS.h"
 #include <asm/visasm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/asm_offsets.h>
 
 #define TOUCH(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7)	\
 	fmovd	%reg0, %f48; 	fmovd	%reg1, %f50;		\
@@ -14,12 +17,47 @@
 	fmovd	%reg4, %f56; 	fmovd	%reg5, %f58;		\
 	fmovd	%reg6, %f60; 	fmovd	%reg7, %f62;
 
+#define	TLBTEMP_BASE	(8 * 1024 * 1024)
+#define	DCACHE_SIZE	(PAGE_SIZE * 2)
+#define TLBTEMP_ENT1	(61 << 3)
+#define TLBTEMP_ENT2	(62 << 3)
+#define TLBTEMP_ENTSZ	(1 << 3)
+
 	.text
 	.align		32
 	.globl		copy_page
 	.type		copy_page,@function
 copy_page: /* %o0=dest, %o1=src */
 	VISEntry
+	ldx		[%g6 + AOFF_task_mm], %o2
+	sub		%o0, %g4, %g1
+	sethi		%uhi(_PAGE_VALID), %g3
+	sub		%o1, %g4, %g2
+	sllx		%g3, 32, %g3
+	ldx		[%o2 + AOFF_mm_segments], %o0
+	or		%g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3
+	or		%g1, %g3, %g1
+	or		%g2, %g3, %g2
+	mov		TLB_TAG_ACCESS, %o2
+	sethi		%hi(TLBTEMP_BASE), %o3
+	sethi		%hi(DCACHE_SIZE), %o1
+	add		%o0, %o3, %o0
+	add		%o0, %o1, %o1
+	sethi		%hi(TLBTEMP_ENT1), %o3
+	rdpr		%pstate, %g3
+	wrpr		%g3, PSTATE_IE, %pstate
+	ldxa		[%o3] ASI_DTLB_TAG_READ, %o4
+	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %o5
+	stxa		%o0, [%o2] ASI_DMMU
+	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
+	membar		#Sync
+	add		%o3, (TLBTEMP_ENTSZ), %o3
+	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
+	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
+	stxa		%o1, [%o2] ASI_DMMU
+	stxa		%g2, [%o3] ASI_DTLB_DATA_ACCESS
+	membar		#Sync
+
 	membar		#LoadStore | #StoreStore | #StoreLoad
 	ldda		[%o1] ASI_BLK_P, %f0
 	add		%o1, 0x40, %o1
@@ -50,15 +88,44 @@
 	stda		%f0, [%o0] ASI_BLK_P
 	add		%o0, 0x40, %o0
 	stda		%f16, [%o0] ASI_BLK_P
-	membar		#StoreStore | #StoreLoad
+	membar		#Sync
+	VISExit
+
+	mov		TLB_TAG_ACCESS, %o2
+	stxa		%g5, [%o2] ASI_DMMU
+	stxa		%g7, [%o3] ASI_DTLB_DATA_ACCESS
+	membar		#Sync
+	sub		%o3, (TLBTEMP_ENTSZ), %o3
+	stxa		%o4, [%o2] ASI_DMMU
+	stxa		%o5, [%o3] ASI_DTLB_DATA_ACCESS
+	membar		#Sync
 	jmpl		%o7 + 0x8, %g0
-	 VISExit
+	 wrpr		%g3, 0x0, %pstate
 
 	.align		32
-	.globl		__bzero_1page
-	.type		__bzero_1page,@function
-__bzero_1page:	/* %o0=dest */
+	.globl		clear_page
+	.type		clear_page,@function
+clear_page:		/* %o0=dest */
 	VISEntryHalf
+	ldx		[%g6 + AOFF_task_mm], %o2
+	sub		%o0, %g4, %g1
+	sethi		%uhi(_PAGE_VALID), %g3
+	sllx		%g3, 32, %g3
+	or		%g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3
+	ldx		[%o2 + AOFF_mm_segments], %o0
+	or		%g1, %g3, %g1
+	mov		TLB_TAG_ACCESS, %o2
+	sethi		%hi(TLBTEMP_BASE), %o3
+	add		%o0, %o3, %o0
+	sethi		%hi(TLBTEMP_ENT2), %o3
+	rdpr		%pstate, %g3
+	wrpr		%g3, PSTATE_IE, %pstate
+	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
+	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
+	stxa		%o0, [%o2] ASI_DMMU
+	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
+	membar		#Sync
+
 	fzero		%f0				! FPA	Group
 	mov		32, %o1				! IEU0
 	fzero		%f2				! FPA	Group
@@ -79,6 +146,11 @@
 	subcc		%o1, 1, %o1			! IEU1
 	bne,pt		%icc, 1b			! CTI
 	 add		%o0, 0x100, %o0			! IEU0	Group
-	membar		#StoreStore | #StoreLoad	! LSU	Group
-	jmpl		%o7 + 0x8, %g0			! CTI	Group brk forced
-	 VISExitHalf
+	membar		#Sync				! LSU	Group
+	VISExitHalf
+
+	stxa		%g5, [%o2] ASI_DMMU
+	stxa		%g7, [%o3] ASI_DTLB_DATA_ACCESS
+	membar		#Sync
+	jmpl		%o7 + 0x8, %g0
+	 wrpr		%g3, 0x0, %pstate
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/debuglocks.c linux/arch/sparc64/lib/debuglocks.c
--- v2.1.126/linux/arch/sparc64/lib/debuglocks.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/lib/debuglocks.c	Tue Oct 27 09:52:20 1998
@@ -0,0 +1,278 @@
+/* $Id: debuglocks.c,v 1.2 1998/10/13 09:07:27 davem Exp $
+ * debuglocks.c: Debugging versions of SMP locking primitives.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+#ifdef __SMP__
+
+/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
+#ifdef SPIN_LOCK_DEBUG
+
+#define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
+
+static inline void show (char *str, spinlock_t *lock, unsigned long caller)
+{
+	int cpu = smp_processor_id();
+
+	printk("%s(%p) CPU#%d stuck at %08x, owner PC(%08x):CPU(%x)\n",
+	       str, lock, cpu, (unsigned int) caller,
+	       lock->owner_pc, lock->owner_cpu);
+}
+
+static inline void show_read (char *str, rwlock_t *lock, unsigned long caller)
+{
+	int cpu = smp_processor_id();
+
+	printk("%s(%p) CPU#%d stuck at %08x, writer PC(%08x):CPU(%x)\n",
+	       str, lock, cpu, (unsigned int) caller,
+	       lock->writer_pc, lock->writer_cpu);
+}
+
+static inline void show_write (char *str, rwlock_t *lock, unsigned long caller)
+{
+	int cpu = smp_processor_id();
+
+	printk("%s(%p) CPU#%d stuck at %08x\n",
+	       str, lock, cpu, (unsigned int) caller);
+	printk("Writer: PC(%08x):CPU(%x)\n",
+	       lock->writer_pc, lock->writer_cpu);
+	printk("Readers: 0[%08x] 1[%08x] 2[%08x] 4[%08x]\n",
+	       lock->reader_pc[0], lock->reader_pc[1],
+	       lock->reader_pc[2], lock->reader_pc[3]);
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+void _do_spin_lock(spinlock_t *lock, char *str)
+{
+	unsigned long caller, val;
+	int stuck = INIT_STUCK;
+	int cpu = smp_processor_id();
+
+	GET_CALLER(caller);
+again:
+	__asm__ __volatile__("ldstub [%1], %0"
+			     : "=r" (val)
+			     : "r" (&(lock->lock))
+			     : "memory");
+	membar("#StoreLoad | #StoreStore");
+	if (val) {
+		while (lock->lock) {
+			if (!--stuck) {
+				show(str, lock, caller);
+				stuck = INIT_STUCK;
+			}
+			membar("#LoadLoad");
+		}
+		goto again;
+	}
+	lock->owner_pc = ((unsigned int)caller);
+	lock->owner_cpu = cpu;
+}
+
+int _spin_trylock(spinlock_t *lock)
+{
+	unsigned long val, caller;
+	int cpu = smp_processor_id();
+
+	GET_CALLER(caller);
+	__asm__ __volatile__("ldstub [%1], %0"
+			     : "=r" (val)
+			     : "r" (&(lock->lock))
+			     : "memory");
+	membar("#StoreLoad | #StoreStore");
+	if (!val) {
+		lock->owner_pc = ((unsigned int)caller);
+		lock->owner_cpu = cpu;
+	}
+	return val == 0;
+}
+
+void _do_spin_unlock(spinlock_t *lock)
+{
+	lock->owner_pc = 0;
+	lock->owner_cpu = NO_PROC_ID;
+	membar("#StoreStore | #LoadStore");
+	lock->lock = 0;
+}
+
+/* Keep INIT_STUCK the same... */
+
+void _do_read_lock (rwlock_t *rw, char *str)
+{
+	unsigned long caller, val;
+	int stuck = INIT_STUCK;
+	int cpu = smp_processor_id();
+
+	GET_CALLER(caller);
+wlock_again:
+	/* Wait for any writer to go away.  */
+	while (((long)(rw->lock)) < 0) {
+		if (!--stuck) {
+			show_read(str, rw, caller);
+			stuck = INIT_STUCK;
+		}
+		membar("#LoadLoad");
+	}
+	/* Try once to increment the counter.  */
+	__asm__ __volatile__("
+	ldx		[%0], %%g5
+	brlz,a,pn	%%g5, 2f
+	 mov		1, %0
+	add		%%g5, 1, %%g7
+	casx		[%0], %%g5, %%g7
+	sub		%%g5, %%g7, %0
+2:"	: "=r" (val)
+	: "0" (&(rw->lock))
+	: "g5", "g7", "memory");
+	membar("#StoreLoad | #StoreStore");
+	if (val)
+		goto wlock_again;
+	rw->reader_pc[cpu] = ((unsigned int)caller);
+}
+
+void _do_read_unlock (rwlock_t *rw, char *str)
+{
+	unsigned long caller, val;
+	int stuck = INIT_STUCK;
+	int cpu = smp_processor_id();
+
+	GET_CALLER(caller);
+
+	/* Drop our identity _first_. */
+	rw->reader_pc[cpu] = 0;
+runlock_again:
+	/* Spin trying to decrement the counter using casx.  */
+	__asm__ __volatile__("
+	ldx	[%0], %%g5
+	sub	%%g5, 1, %%g7
+	casx	[%0], %%g5, %%g7
+	membar	#StoreLoad | #StoreStore
+	sub	%%g5, %%g7, %0
+"	: "=r" (val)
+	: "0" (&(rw->lock))
+	: "g5", "g7", "memory");
+	if (val) {
+		if (!--stuck) {
+			show_read(str, rw, caller);
+			stuck = INIT_STUCK;
+		}
+		goto runlock_again;
+	}
+}
+
+void _do_write_lock (rwlock_t *rw, char *str)
+{
+	unsigned long caller, val;
+	int stuck = INIT_STUCK;
+	int cpu = smp_processor_id();
+
+	GET_CALLER(caller);
+wlock_again:
+	/* Spin while there is another writer. */
+	while (((long)rw->lock) < 0) {
+		if (!--stuck) {
+			show_write(str, rw, caller);
+			stuck = INIT_STUCK;
+		}
+		membar("#LoadLoad");
+	}
+
+	/* Try to acuire the write bit.  */
+	__asm__ __volatile__("
+	mov	1, %%g3
+	sllx	%%g3, 63, %%g3
+	ldx	[%0], %%g5
+	brlz,pn	%%g5, 1f
+	 or	%%g5, %%g3, %%g7
+	casx	[%0], %%g5, %%g7
+	membar	#StoreLoad | #StoreStore
+	ba,pt	%%xcc, 2f
+	 sub	%%g5, %%g7, %0
+1:	mov	1, %0
+2:"	: "=r" (val)
+	: "0" (&(rw->lock))
+	: "g3", "g5", "g7", "memory");
+	if (val) {
+		/* We couldn't get the write bit. */
+		if (!--stuck) {
+			show_write(str, rw, caller);
+			stuck = INIT_STUCK;
+		}
+		goto wlock_again;
+	}
+	if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) {
+		/* Readers still around, drop the write
+		 * lock, spin, and try again.
+		 */
+		if (!--stuck) {
+			show_write(str, rw, caller);
+			stuck = INIT_STUCK;
+		}
+		__asm__ __volatile__("
+		mov	1, %%g3
+		sllx	%%g3, 63, %%g3
+1:		ldx	[%0], %%g5
+		andn	%%g5, %%g3, %%g7
+		casx	[%0], %%g5, %%g7
+		cmp	%%g5, %%g7
+		bne,pn	%%xcc, 1b
+		 membar	#StoreLoad | #StoreStore"
+		: /* no outputs */
+		: "r" (&(rw->lock))
+		: "g3", "g5", "g7", "cc", "memory");
+		while(rw->lock != 0) {
+			if (!--stuck) {
+				show_write(str, rw, caller);
+				stuck = INIT_STUCK;
+			}
+			membar("#LoadLoad");
+		}
+		goto wlock_again;
+	}
+
+	/* We have it, say who we are. */
+	rw->writer_pc = ((unsigned int)caller);
+	rw->writer_cpu = cpu;
+}
+
+void _do_write_unlock(rwlock_t *rw)
+{
+	unsigned long caller, val;
+	int stuck = INIT_STUCK;
+
+	GET_CALLER(caller);
+
+	/* Drop our identity _first_ */
+	rw->writer_pc = 0;
+	rw->writer_cpu = NO_PROC_ID;
+wlock_again:
+	__asm__ __volatile__("
+	mov	1, %%g3
+	sllx	%%g3, 63, %%g3
+	ldx	[%0], %%g5
+	andn	%%g5, %%g3, %%g7
+	casx	[%0], %%g5, %%g7
+	membar	#StoreLoad | #StoreStore
+	sub	%%g5, %%g7, %0
+"	: "=r" (val)
+	: "0" (&(rw->lock))
+	: "g3", "g5", "g7", "memory");
+	if (val) {
+		if (!--stuck) {
+			show_write("write_unlock", rw, caller);
+			stuck = INIT_STUCK;
+		}
+		goto wlock_again;
+	}
+}
+
+#endif /* SPIN_LOCK_DEBUG */
+#endif /* __SMP__ */
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/locks.S linux/arch/sparc64/lib/locks.S
--- v2.1.126/linux/arch/sparc64/lib/locks.S	Sat Aug 16 09:51:09 1997
+++ linux/arch/sparc64/lib/locks.S	Wed Dec 31 16:00:00 1969
@@ -1,76 +0,0 @@
-/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $
- * locks.S: SMP low-level lock primitives on Sparc64.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/asm_offsets.h>
-#include <asm/ptrace.h>
-#include <asm/smp.h>
-
-	.text
-	.align		32
-
-___lk_busy_spin:
-	ldub		[%g1 + 0], %g2
-	brnz,pt		%g2, ___lk_busy_spin
-	 membar		#LoadLoad
-	b,pt		%xcc, 1f
-	 ldstub		[%g1 + 0], %g2
-
-	.globl		___lock_kernel
-___lock_kernel:
-	addcc		%g2, -1, %g2
-	rdpr		%pil, %g3
-	bcs,a,pn	%icc, 9f
-	 stw		%g2, [%g6 + AOFF_task_lock_depth]
-	wrpr		%g0, 15, %pil
-	ldstub		[%g1 + 0], %g2
-1:	brnz,pn		%g2, ___lk_busy_spin
-	 membar		#StoreLoad | #StoreStore
-	lduw		[%g6 + AOFF_task_processor], %g2
-	stb		%g2, [%g1 + 1]
-2:	mov		-1, %g2
-	stw		%g2, [%g6 + AOFF_task_lock_depth]
-	wrpr		%g3, 0, %pil
-9:	jmpl		%o7 + 0x8, %g0
-	 mov		%g5, %o7
-
-	.globl		___lock_reacquire_kernel
-___lock_reacquire_kernel:
-	rdpr		%pil, %g3
-	wrpr		%g0, 15, %pil
-	stw		%g2, [%g6 + AOFF_task_lock_depth]
-	ldstub		[%g1 + 0], %g2
-1:	brz,pt		%g2, 3f
-	 membar		#StoreLoad | #StoreStore
-2:	ldub		[%g1 + 0], %g2
-	brnz,pt		%g2, 2b
-	 membar		#LoadLoad
-	b,pt		%xcc, 1b
-	 ldstub		[%g1 + 0], %g2
-3:	lduw		[%g6 + AOFF_task_processor], %g2
-	stb		%g2, [%g1 + 1]
-	wrpr		%g3, 0, %pil
-	jmpl		%o7 + 0x8, %g0
-	 mov		%g5, %o7
-
-#undef NO_PROC_ID
-#define NO_PROC_ID	0xff
-
-	.globl		___unlock_kernel
-___unlock_kernel:
-	addcc		%g2, 1, %g2
-	rdpr		%pil, %g3
-	bne,a,pn	%icc, 1f
-	 stw		%g2, [%g6 + AOFF_task_lock_depth]
-	wrpr		15, %pil
-	mov		NO_PROC_ID, %g2
-	stb		%g2, [%g1 + 1]
-	membar		#StoreStore | #LoadStore
-	stb		%g0, [%g1 + 0]
-	stw		%g0, [%g6 + AOFF_task_lock_depth]
-	wrpr		%g3, 0, %pil
-1:	jmpl		%o7 + 0x8, %g0
-	 mov		%g5, %o7
-	
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/strlen.S linux/arch/sparc64/lib/strlen.S
--- v2.1.126/linux/arch/sparc64/lib/strlen.S	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/lib/strlen.S	Tue Oct 27 09:52:20 1998
@@ -9,7 +9,8 @@
 #define HI_MAGIC 0x80808080
 
 	.align	32
-	.global __strlen
+	.global strlen, __strlen
+strlen:
 __strlen:
 	mov	%o0, %o1
 	andcc	%o0, 3, %g0
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/math-emu/Makefile linux/arch/sparc64/math-emu/Makefile
--- v2.1.126/linux/arch/sparc64/math-emu/Makefile	Thu Apr 23 20:21:32 1998
+++ linux/arch/sparc64/math-emu/Makefile	Tue Oct 27 09:52:20 1998
@@ -16,10 +16,4 @@
 		fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o		\
 		fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o
 
-.S.s:
-	$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
-
-.S.o:
-	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.1.126/linux/arch/sparc64/mm/fault.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/mm/fault.c	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.24 1998/09/22 03:27:33 davem Exp $
+/* $Id: fault.c,v 1.25 1998/10/19 21:52:26 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -154,6 +154,7 @@
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
+	current->mm->segments = (void *) (address & PAGE_SIZE);
 	handle_mm_fault(current, vma, address, write);
 	up(&mm->mmap_sem);
 	return;
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.1.126/linux/arch/sparc64/mm/init.c	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/mm/init.c	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.98 1998/09/28 06:18:39 davem Exp $
+/*  $Id: init.c,v 1.103 1998/10/20 03:09:12 jj Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -45,7 +45,6 @@
 
 int do_check_pgt_cache(int low, int high)
 {
-        struct page *page, *page2;
         int freed = 0;
 
 	if(pgtable_cache_size > high) {
@@ -60,6 +59,7 @@
 	}
 #ifndef __SMP__ 
         if (pgd_cache_size > high / 4) {
+		struct page *page, *page2;
                 for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) {
                         if ((unsigned long)page->pprev_hash == 3) {
                                 if (page2)
@@ -537,7 +537,7 @@
 				if (pgd_none(*pgdp)) {
 					pmdp = sparc_init_alloc(&mempool,
 							 PMD_TABLE_SIZE);
-					clear_page(pmdp);
+					memset(pmdp, 0, PAGE_SIZE);
 					pgd_set(pgdp, pmdp);
 				}
 				pmdp = pmd_offset(pgdp, vaddr);
@@ -591,12 +591,17 @@
 }
 
 static int prom_ditlb_set = 0;
-int prom_itlb_ent, prom_dtlb_ent;
-unsigned long prom_itlb_tag, prom_itlb_data;
-unsigned long prom_dtlb_tag, prom_dtlb_data;
+struct prom_tlb_entry {
+	int		tlb_ent;
+	unsigned long	tlb_tag;
+	unsigned long	tlb_data;
+};
+struct prom_tlb_entry prom_itlb[8], prom_dtlb[8];
 
 void prom_world(int enter)
 {
+	int i;
+
 	if (!prom_ditlb_set)
 		return;
 	if (enter) {
@@ -604,29 +609,44 @@
 		__flush_nucleus_vptes();
 
 		/* Install PROM world. */
-		__asm__ __volatile__("stxa %0, [%1] %2"
-					: : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS),
+		for (i = 0; i < 8; i++) {
+			if (prom_dtlb[i].tlb_ent != -1) {
+				__asm__ __volatile__("stxa %0, [%1] %2"
+					: : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
 					"i" (ASI_DMMU));
-		membar("#Sync");
-		spitfire_put_dtlb_data(62, prom_dtlb_data);
-		membar("#Sync");
-		__asm__ __volatile__("stxa %0, [%1] %2"
-					: : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS),
+				membar("#Sync");
+				spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
+						       prom_dtlb[i].tlb_data);
+				membar("#Sync");
+			}
+
+			if (prom_itlb[i].tlb_ent != -1) {
+				__asm__ __volatile__("stxa %0, [%1] %2"
+					: : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
 					"i" (ASI_IMMU));
-		membar("#Sync");
-		spitfire_put_itlb_data(62, prom_itlb_data);
-		membar("#Sync");
+				membar("#Sync");
+				spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
+						       prom_itlb[i].tlb_data);
+				membar("#Sync");
+			}
+		}
 	} else {
-		__asm__ __volatile__("stxa %%g0, [%0] %1"
+		for (i = 0; i < 8; i++) {
+			if (prom_dtlb[i].tlb_ent != -1) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
 					: : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-		membar("#Sync");
-		spitfire_put_dtlb_data(62, 0x0UL);
-		membar("#Sync");
-		__asm__ __volatile__("stxa %%g0, [%0] %1"
+				membar("#Sync");
+				spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
+				membar("#Sync");
+			}
+			if (prom_itlb[i].tlb_ent != -1) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
 					: : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
-		membar("#Sync");
-		spitfire_put_itlb_data(62, 0x0UL);
-		membar("#Sync");
+				membar("#Sync");
+				spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL);
+				membar("#Sync");
+			}
+		}
 	}
 }
 
@@ -640,8 +660,8 @@
 	 * it (conveniently) fails to mention any of these in the
 	 * translations property.  The only ones that matter are
 	 * the locked PROM tlb entries, so we impose the following
-	 * irrecovable rule on the PROM, it is allowed 1 locked
-	 * entry in the ITLB and 1 in the DTLB.
+	 * irrecovable rule on the PROM, it is allowed 8 locked
+	 * entries in the ITLB and 8 in the DTLB.
 	 *
 	 * Supposedly the upper 16GB of the address space is
 	 * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED
@@ -650,17 +670,23 @@
 	 * systems to coordinate mmu mappings is also COMPLETELY
 	 * UNDOCUMENTED!!!!!! Thanks S(t)un!
 	 */
+	if (save_p) {
+		for(i = 0; i < 8; i++) {
+			prom_dtlb[i].tlb_ent = -1;
+			prom_itlb[i].tlb_ent = -1;
+		}
+	}
 	for(i = 0; i < 63; i++) {
 		unsigned long data;
 
 		data = spitfire_get_dtlb_data(i);
-		if(!dtlb_seen && (data & _PAGE_L)) {
+		if(data & _PAGE_L) {
 			unsigned long tag = spitfire_get_dtlb_tag(i);
 
 			if(save_p) {
-				prom_dtlb_ent = i;
-				prom_dtlb_tag = tag;
-				prom_dtlb_data = data;
+				prom_dtlb[dtlb_seen].tlb_ent = i;
+				prom_dtlb[dtlb_seen].tlb_tag = tag;
+				prom_dtlb[dtlb_seen].tlb_data = data;
 			}
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
 					     : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
@@ -668,18 +694,22 @@
 			spitfire_put_dtlb_data(i, 0x0UL);
 			membar("#Sync");
 
-			dtlb_seen = 1;
-			if(itlb_seen)
+			dtlb_seen++;
+			if(dtlb_seen > 7)
 				break;
 		}
+	}
+	for(i = 0; i < 63; i++) {
+		unsigned long data;
+
 		data = spitfire_get_itlb_data(i);
-		if(!itlb_seen && (data & _PAGE_L)) {
+		if(data & _PAGE_L) {
 			unsigned long tag = spitfire_get_itlb_tag(i);
 
 			if(save_p) {
-				prom_itlb_ent = i;
-				prom_itlb_tag = tag;
-				prom_itlb_data = data;
+				prom_itlb[itlb_seen].tlb_ent = i;
+				prom_itlb[itlb_seen].tlb_tag = tag;
+				prom_itlb[itlb_seen].tlb_data = data;
 			}
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
 					     : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
@@ -687,15 +717,8 @@
 			spitfire_put_itlb_data(i, 0x0UL);
 			membar("#Sync");
 
-			/* Re-install it. */
-			__asm__ __volatile__("stxa %0, [%1] %2"
-					     : : "r" (tag), "r" (TLB_TAG_ACCESS),
-					         "i" (ASI_IMMU));
-			membar("#Sync");
-			spitfire_put_itlb_data(62, data);
-			membar("#Sync");
-			itlb_seen = 1;
-			if(dtlb_seen)
+			itlb_seen++;
+			if(itlb_seen > 7)
 				break;
 		}
 	}
@@ -706,19 +729,29 @@
 /* Give PROM back his world, done during reboots... */
 void prom_reload_locked(void)
 {
-	__asm__ __volatile__("stxa %0, [%1] %2"
-			     : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS),
-			     "i" (ASI_DMMU));
-	membar("#Sync");
-	spitfire_put_dtlb_data(prom_dtlb_ent, prom_dtlb_data);
-	membar("#Sync");
-
-	__asm__ __volatile__("stxa %0, [%1] %2"
-			     : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS),
-			     "i" (ASI_IMMU));
-	membar("#Sync");
-	spitfire_put_itlb_data(prom_itlb_ent, prom_itlb_data);
-	membar("#Sync");
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		if (prom_dtlb[i].tlb_ent != -1) {
+			__asm__ __volatile__("stxa %0, [%1] %2"
+				: : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
+				"i" (ASI_DMMU));
+			membar("#Sync");
+			spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
+					       prom_dtlb[i].tlb_data);
+			membar("#Sync");
+		}
+
+		if (prom_itlb[i].tlb_ent != -1) {
+			__asm__ __volatile__("stxa %0, [%1] %2"
+				: : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
+				"i" (ASI_IMMU));
+			membar("#Sync");
+			spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
+					       prom_itlb[i].tlb_data);
+			membar("#Sync");
+		}
+	}
 }
 
 void __flush_dcache_range(unsigned long start, unsigned long end)
@@ -844,7 +877,7 @@
 
 	pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
 	if(pmd) {
-		clear_page(pmd);
+		memset(pmd, 0, PAGE_SIZE);
 		pgd_set(pgd, pmd);
 		return pmd + offset;
 	}
@@ -857,7 +890,7 @@
 
 	pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
 	if(pte) {
-		clear_page(pte);
+		memset(pte, 0, PAGE_SIZE);
 		pmd_set(pmd, pte);
 		return pte + offset;
 	}
@@ -875,13 +908,13 @@
 		pgdp = pgd_offset(init_task.mm, start);
 		if (pgd_none(*pgdp)) {
 			pmdp = sparc_init_alloc(&mempool, PAGE_SIZE);
-			clear_page(pmdp);
+			memset(pmdp, 0, PAGE_SIZE);
 			pgd_set(pgdp, pmdp);
 		}
 		pmdp = pmd_offset(pgdp, start);
 		if (pmd_none(*pmdp)) {
 			ptep = sparc_init_alloc(&mempool, PAGE_SIZE);
-			clear_page(ptep);
+			memset(ptep, 0, PAGE_SIZE);
 			pmd_set(pmdp, ptep);
 		}
 		start = (start + PMD_SIZE) & PMD_MASK;
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.1.126/linux/arch/sparc64/mm/ultra.S	Mon Oct  5 13:13:38 1998
+++ linux/arch/sparc64/mm/ultra.S	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.27 1998/09/28 06:18:42 davem Exp $
+/* $Id: ultra.S,v 1.29 1998/10/22 03:05:51 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -125,34 +125,39 @@
 	retl
 	 wrpr		%g1, 0x0, %pstate
 
-	/* Unfortunately, it is necessary. */
-	.globl		flush_page_to_ram
-flush_page_to_ram:	/* %o0 = page */
-	rdpr		%pstate, %g5
-	wrpr		%g5, PSTATE_IE, %pstate
-	sethi		%hi(dcache_aliases_found), %g1
-	ldx		[%g1 + %lo(dcache_aliases_found)], %g2
-	sub		%o0, %g4, %o0		! Get phys_page
-	clr		%o2			! This dcache area begin
-	sethi		%hi(1<<14), %o1		! This dcache area end
-1:	ldxa		[%o2] ASI_DCACHE_TAG, %o3
-	andcc		%o3, 0x3, %g0		! Valid bits set?
-	be,pn		%xcc, 2f		! Nope, skip this one
-	 andn		%o3, 0x3, %o3		! Mask out valid bits
-	sllx		%o3, (13 - 2), %o3	! Shift into physaddr
-	cmp		%o3, %o0		! Match?
-	bne,pt		%xcc, 2f		! Nope, skip to next
+	.align		32
+	.globl		flush_icache_page
+flush_icache_page:	/* %o0 = phys_page */
+	sethi		%hi(1 << 13), %o2	! I-cache valid/set bit
+	srlx		%o0, 5, %o0		! phys-addr comparitor
+	clr		%o1			! I-cache address
+1:	ldda		[%o1] ASI_IC_TAG, %o4
+	andcc		%o5, %o2, %g0
+	be,pn		%xcc, 2f
+	 andn		%o5, %o2, %o5
+	cmp		%o5, %o0
+
+	be,pn		%xcc, iflush1
+2:	 ldda		[%o1 + %o2] ASI_IC_TAG, %o4
+4:	andcc		%o5, %o2, %g0
+	be,pn		%xcc, 3f
+	 andn		%o5, %o2, %o5
+	cmp		%o5, %o0
+	be,pn		%xcc, iflush2
 	 nop
-	stxa		%g0, [%o2] ASI_DCACHE_TAG
-	membar		#Sync
-	add		%g2, 1, %g2		! Increment alias counter
-2:	add		%o2, (1<<5), %o2	! 32-bytes per full line
-	cmp		%o2, %o1
+
+3:	add		%o1, 0x20, %o1
+	cmp		%o1, %o2
 	bne,pt		%xcc, 1b
 	 nop
-	stx		%g2, [%g1 + %lo(dcache_aliases_found)]
 	retl
-	 wrpr		%g5, 0x0, %pstate
+	 nop
+iflush1:stxa		%g0, [%o1] ASI_IC_TAG
+	membar		#Sync
+	ba,a,pt		%xcc, 4b
+iflush2:stxa		%g0, [%o1 + %o2] ASI_IC_TAG
+	membar		#Sync
+	ba,a,pt		%xcc, 3b
 
 #ifdef __SMP__
 	/* These are all called by the slaves of a cross call, at
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c
--- v2.1.126/linux/arch/sparc64/prom/misc.c	Thu Aug  6 14:06:31 1998
+++ linux/arch/sparc64/prom/misc.c	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.10 1998/07/21 10:36:29 jj Exp $
+/* $Id: misc.c,v 1.13 1998/10/13 14:03:49 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -40,25 +40,18 @@
 /* Drop into the prom, with the chance to continue with the 'go'
  * prom command.
  */
-/* XXX Fix the pre and post calls as it locks up my Ultra at the moment -DaveM */
 void
 prom_cmdline(void)
 {
-	extern void kernel_enter_debugger(void);
-	/* extern void install_obp_ticker(void); */
-	/* extern void install_linux_ticker(void); */
 	unsigned long flags;
     
-	/* kernel_enter_debugger(); */
 #ifdef CONFIG_SUN_CONSOLE
 	if(!serial_console && prom_palette)
 		prom_palette (1);
 #endif
-	/* install_obp_ticker(); */
-	save_flags(flags); cli();
+	__save_and_cli(flags);
 	p1275_cmd ("enter", P1275_INOUT(0,0));
-	restore_flags(flags);
-	/* install_linux_ticker(); */
+	__restore_flags(flags);
 #ifdef CONFIG_SUN_CONSOLE
 	if(!serial_console && prom_palette)
 		prom_palette (0);
@@ -78,7 +71,7 @@
 
 /* Set prom sync handler to call function 'funcp'. */
 void
-prom_setsync(sync_func_t funcp)
+prom_setcallback(callback_func_t funcp)
 {
 	if(!funcp) return;
 	p1275_cmd ("set-callback", P1275_ARG(0,P1275_ARG_IN_FUNCTION)|
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c
--- v2.1.126/linux/arch/sparc64/prom/p1275.c	Fri May  8 23:14:46 1998
+++ linux/arch/sparc64/prom/p1275.c	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.13 1998/04/24 15:45:35 jj Exp $
+/* $Id: p1275.c,v 1.15 1998/10/13 14:03:47 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -15,9 +15,10 @@
 #include <asm/system.h>
 #include <asm/spitfire.h>
 #include <asm/pstate.h>
+#include <asm/spinlock.h>
 
 struct {
-	long prom_sync_routine;			/* 0x00 */
+	long prom_callback;			/* 0x00 */
 	void (*prom_cif_handler)(long *);	/* 0x08 */
 	unsigned long prom_cif_stack;		/* 0x10 */
 	unsigned long prom_args [23];		/* 0x18 */
@@ -31,29 +32,262 @@
 	__asm__ __volatile__ ("
 	mov	%0, %%o0
 	ldx	[%%o0 + 0x010], %%o1	! prom_cif_stack
-	save	%%o1, -0xc0, %%sp
+	save	%%o1, -0x190, %%sp
 	ldx	[%%i0 + 0x008], %%l2	! prom_cif_handler
 	rdpr	%%pstate, %%l4
-	mov	%%g4, %%l0
-	mov	%%g6, %%l1
-	wrpr	%%l4, %1, %%pstate	! turn on address masking
+	wrpr	%%g0, 0x15, %%pstate	! save alternate globals
+	stx	%%g1, [%%sp + 2047 + 0x0b0]
+	stx	%%g2, [%%sp + 2047 + 0x0b8]
+	stx	%%g3, [%%sp + 2047 + 0x0c0]
+	stx	%%g4, [%%sp + 2047 + 0x0c8]
+	stx	%%g5, [%%sp + 2047 + 0x0d0]
+	stx	%%g6, [%%sp + 2047 + 0x0d8]
+	stx	%%g7, [%%sp + 2047 + 0x0e0]
+	wrpr	%%g0, 0x814, %%pstate	! save interrupt globals
+	stx	%%g1, [%%sp + 2047 + 0x0e8]
+	stx	%%g2, [%%sp + 2047 + 0x0f0]
+	stx	%%g3, [%%sp + 2047 + 0x0f8]
+	stx	%%g4, [%%sp + 2047 + 0x100]
+	stx	%%g5, [%%sp + 2047 + 0x108]
+	stx	%%g6, [%%sp + 2047 + 0x110]
+	stx	%%g7, [%%sp + 2047 + 0x118]
+	wrpr	%%g0, 0x14, %%pstate	! save normal globals
+	stx	%%g1, [%%sp + 2047 + 0x120]
+	stx	%%g2, [%%sp + 2047 + 0x128]
+	stx	%%g3, [%%sp + 2047 + 0x130]
+	stx	%%g4, [%%sp + 2047 + 0x138]
+	stx	%%g5, [%%sp + 2047 + 0x140]
+	stx	%%g6, [%%sp + 2047 + 0x148]
+	stx	%%g7, [%%sp + 2047 + 0x150]
+	wrpr	%%g0, 0x414, %%pstate	! save mmu globals
+	stx	%%g1, [%%sp + 2047 + 0x158]
+	stx	%%g2, [%%sp + 2047 + 0x160]
+	stx	%%g3, [%%sp + 2047 + 0x168]
+	stx	%%g4, [%%sp + 2047 + 0x170]
+	stx	%%g5, [%%sp + 2047 + 0x178]
+	stx	%%g6, [%%sp + 2047 + 0x180]
+	stx	%%g7, [%%sp + 2047 + 0x188]
+	mov	%%g1, %%l0		! also save to locals, so we can handle
+	mov	%%g2, %%l1		! tlb faults later on, when accessing
+	mov	%%g3, %%l3		! the stack.
+	mov	%%g7, %%l5
+	wrpr	%%l4, %1, %%pstate	! turn off interrupts
 	call	%%l2
 	 add	%%i0, 0x018, %%o0	! prom_args
-	wrpr	%%l4, 0, %%pstate	! put pstate back
-	mov	%%l0, %%g4
+	wrpr	%%g0, 0x414, %%pstate	! restore mmu globals
+	mov	%%l0, %%g1
+	mov	%%l1, %%g2
+	mov	%%l3, %%g3
+	mov	%%l5, %%g7
+	wrpr	%%g0, 0x14, %%pstate	! restore normal globals
+	ldx	[%%sp + 2047 + 0x120], %%g1
+	ldx	[%%sp + 2047 + 0x128], %%g2
+	ldx	[%%sp + 2047 + 0x130], %%g3
+	ldx	[%%sp + 2047 + 0x138], %%g4
+	ldx	[%%sp + 2047 + 0x140], %%g5
+	ldx	[%%sp + 2047 + 0x148], %%g6
+	ldx	[%%sp + 2047 + 0x150], %%g7
+	wrpr	%%g0, 0x814, %%pstate	! restore interrupt globals
+	ldx	[%%sp + 2047 + 0x0e8], %%g1
+	ldx	[%%sp + 2047 + 0x0f0], %%g2
+	ldx	[%%sp + 2047 + 0x0f8], %%g3
+	ldx	[%%sp + 2047 + 0x100], %%g4
+	ldx	[%%sp + 2047 + 0x108], %%g5
+	ldx	[%%sp + 2047 + 0x110], %%g6
+	ldx	[%%sp + 2047 + 0x118], %%g7
+	wrpr	%%g0, 0x15, %%pstate	! restore alternate globals
+	ldx	[%%sp + 2047 + 0x0b0], %%g1
+	ldx	[%%sp + 2047 + 0x0b8], %%g2
+	ldx	[%%sp + 2047 + 0x0c0], %%g3
+	ldx	[%%sp + 2047 + 0x0c8], %%g4
+	ldx	[%%sp + 2047 + 0x0d0], %%g5
+	ldx	[%%sp + 2047 + 0x0d8], %%g6
+	ldx	[%%sp + 2047 + 0x0e0], %%g7
+	wrpr	%%l4, 0, %%pstate	! restore original pstate
 	ret
-	 restore %%l1, 0, %%g6
-	save	%%sp, -0xc0, %%sp	! If you change the offset of the save 
-	rdpr	%%pstate, %%l4		! here, please change the 0x8038 
-	andn	%%l4, %1, %%l3		! constant below as well
-	wrpr	%%l3, %%pstate
-	ldx	[%%o0 + 0x000], %%l2
+	 restore
+	" : : "r" (&p1275buf), "i" (PSTATE_IE));
+}
+
+void prom_cif_callback(void)
+{
+	__asm__ __volatile__ ("
+	mov	%0, %%o1
+	save	%%sp, -0x270, %%sp
+	rdpr	%%pstate, %%l4
+	wrpr	%%g0, 0x15, %%pstate	! save PROM alternate globals
+	stx	%%g1, [%%sp + 2047 + 0x0b0]
+	stx	%%g2, [%%sp + 2047 + 0x0b8]
+	stx	%%g3, [%%sp + 2047 + 0x0c0]
+	stx	%%g4, [%%sp + 2047 + 0x0c8]
+	stx	%%g5, [%%sp + 2047 + 0x0d0]
+	stx	%%g6, [%%sp + 2047 + 0x0d8]
+	stx	%%g7, [%%sp + 2047 + 0x0e0]
+					! restore Linux alternate globals
+	ldx	[%%sp + 2047 + 0x190], %%g1
+	ldx	[%%sp + 2047 + 0x198], %%g2
+	ldx	[%%sp + 2047 + 0x1a0], %%g3
+	ldx	[%%sp + 2047 + 0x1a8], %%g4
+	ldx	[%%sp + 2047 + 0x1b0], %%g5
+	ldx	[%%sp + 2047 + 0x1b8], %%g6
+	ldx	[%%sp + 2047 + 0x1c0], %%g7
+	wrpr	%%g0, 0x814, %%pstate	! save PROM interrupt globals
+	stx	%%g1, [%%sp + 2047 + 0x0e8]
+	stx	%%g2, [%%sp + 2047 + 0x0f0]
+	stx	%%g3, [%%sp + 2047 + 0x0f8]
+	stx	%%g4, [%%sp + 2047 + 0x100]
+	stx	%%g5, [%%sp + 2047 + 0x108]
+	stx	%%g6, [%%sp + 2047 + 0x110]
+	stx	%%g7, [%%sp + 2047 + 0x118]
+					! restore Linux interrupt globals
+	ldx	[%%sp + 2047 + 0x1c8], %%g1
+	ldx	[%%sp + 2047 + 0x1d0], %%g2
+	ldx	[%%sp + 2047 + 0x1d8], %%g3
+	ldx	[%%sp + 2047 + 0x1e0], %%g4
+	ldx	[%%sp + 2047 + 0x1e8], %%g5
+	ldx	[%%sp + 2047 + 0x1f0], %%g6
+	ldx	[%%sp + 2047 + 0x1f8], %%g7
+	wrpr	%%g0, 0x14, %%pstate	! save PROM normal globals
+	stx	%%g1, [%%sp + 2047 + 0x120]
+	stx	%%g2, [%%sp + 2047 + 0x128]
+	stx	%%g3, [%%sp + 2047 + 0x130]
+	stx	%%g4, [%%sp + 2047 + 0x138]
+	stx	%%g5, [%%sp + 2047 + 0x140]
+	stx	%%g6, [%%sp + 2047 + 0x148]
+	stx	%%g7, [%%sp + 2047 + 0x150]
+					! restore Linux normal globals
+	ldx	[%%sp + 2047 + 0x200], %%g1
+	ldx	[%%sp + 2047 + 0x208], %%g2
+	ldx	[%%sp + 2047 + 0x210], %%g3
+	ldx	[%%sp + 2047 + 0x218], %%g4
+	ldx	[%%sp + 2047 + 0x220], %%g5
+	ldx	[%%sp + 2047 + 0x228], %%g6
+	ldx	[%%sp + 2047 + 0x230], %%g7
+	wrpr	%%g0, 0x414, %%pstate	! save PROM mmu globals
+	stx	%%g1, [%%sp + 2047 + 0x158]
+	stx	%%g2, [%%sp + 2047 + 0x160]
+	stx	%%g3, [%%sp + 2047 + 0x168]
+	stx	%%g4, [%%sp + 2047 + 0x170]
+	stx	%%g5, [%%sp + 2047 + 0x178]
+	stx	%%g6, [%%sp + 2047 + 0x180]
+	stx	%%g7, [%%sp + 2047 + 0x188]
+					! restore Linux mmu globals
+	ldx	[%%sp + 2047 + 0x238], %%o0
+	ldx	[%%sp + 2047 + 0x240], %%o1
+	ldx	[%%sp + 2047 + 0x248], %%l2
+	ldx	[%%sp + 2047 + 0x250], %%l3
+	ldx	[%%sp + 2047 + 0x258], %%l5
+	ldx	[%%sp + 2047 + 0x260], %%l6
+	ldx	[%%sp + 2047 + 0x268], %%l7
+					! switch to Linux tba
+	sethi	%%hi(sparc64_ttable_tl0), %%l1
+	rdpr	%%tba, %%l0		! save PROM tba
+	mov	%%o0, %%g1
+	mov	%%o1, %%g2
+	mov	%%l2, %%g3
+	mov	%%l3, %%g4
+	mov	%%l5, %%g5
+	mov	%%l6, %%g6
+	mov	%%l7, %%g7
+	wrpr	%%l1, %%tba		! install Linux tba
+	wrpr	%%l4, 0, %%pstate	! restore PSTATE
+	call	prom_world
+	 mov	%%g0, %%o0
+	ldx	[%%i1 + 0x000], %%l2
 	call	%%l2
-	 nop
+	 mov	%%i0, %%o0
+	mov	%%o0, %%l1
+	call	prom_world
+	 or	%%g0, 1, %%o0
+	wrpr	%%g0, 0x14, %%pstate	! interrupts off
+					! restore PROM mmu globals
+	ldx	[%%sp + 2047 + 0x158], %%o0
+	ldx	[%%sp + 2047 + 0x160], %%o1
+	ldx	[%%sp + 2047 + 0x168], %%l2
+	ldx	[%%sp + 2047 + 0x170], %%l3
+	ldx	[%%sp + 2047 + 0x178], %%l5
+	ldx	[%%sp + 2047 + 0x180], %%l6
+	ldx	[%%sp + 2047 + 0x188], %%l7
+	wrpr	%%g0, 0x414, %%pstate	! restore PROM mmu globals
+	mov	%%o0, %%g1
+	mov	%%o1, %%g2
+	mov	%%l2, %%g3
+	mov	%%l3, %%g4
+	mov	%%l5, %%g5
+	mov	%%l6, %%g6
+	mov	%%l7, %%g7
+	wrpr	%%l0, %%tba		! restore PROM tba
+	wrpr	%%g0, 0x14, %%pstate	! restore PROM normal globals
+	ldx	[%%sp + 2047 + 0x120], %%g1
+	ldx	[%%sp + 2047 + 0x128], %%g2
+	ldx	[%%sp + 2047 + 0x130], %%g3
+	ldx	[%%sp + 2047 + 0x138], %%g4
+	ldx	[%%sp + 2047 + 0x140], %%g5
+	ldx	[%%sp + 2047 + 0x148], %%g6
+	ldx	[%%sp + 2047 + 0x150], %%g7
+	wrpr	%%g0, 0x814, %%pstate	! restore PROM interrupt globals
+	ldx	[%%sp + 2047 + 0x0e8], %%g1
+	ldx	[%%sp + 2047 + 0x0f0], %%g2
+	ldx	[%%sp + 2047 + 0x0f8], %%g3
+	ldx	[%%sp + 2047 + 0x100], %%g4
+	ldx	[%%sp + 2047 + 0x108], %%g5
+	ldx	[%%sp + 2047 + 0x110], %%g6
+	ldx	[%%sp + 2047 + 0x118], %%g7
+	wrpr	%%g0, 0x15, %%pstate	! restore PROM alternate globals
+	ldx	[%%sp + 2047 + 0x0b0], %%g1
+	ldx	[%%sp + 2047 + 0x0b8], %%g2
+	ldx	[%%sp + 2047 + 0x0c0], %%g3
+	ldx	[%%sp + 2047 + 0x0c8], %%g4
+	ldx	[%%sp + 2047 + 0x0d0], %%g5
+	ldx	[%%sp + 2047 + 0x0d8], %%g6
+	ldx	[%%sp + 2047 + 0x0e0], %%g7
 	wrpr	%%l4, 0, %%pstate
 	ret
-	 restore
-	" : : "r" (&p1275buf), "i" (0 /* PSTATE_AM */));
+	 restore %%l1, 0, %%o0
+	" : : "r" (&p1275buf), "i" (PSTATE_PRIV));
+}
+
+/* We need some SMP protection here.  But be careful as
+ * prom callback code can call into here too, this is why
+ * the counter is needed.  -DaveM
+ */
+static int prom_entry_depth = 0;
+#ifdef __SMP__
+static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
+extern void smp_capture(void);
+extern void smp_release(void);
+#endif
+
+static __inline__ unsigned long prom_get_lock(void)
+{
+	unsigned long flags;
+
+	__save_and_cli(flags);
+	if (prom_entry_depth == 0) {
+		spin_lock(&prom_entry_lock);
+
+#if 1 /* DEBUGGING */
+		if (prom_entry_depth != 0)
+			panic("prom_get_lock");
+#endif
+#ifdef __SMP__
+		smp_capture();
+#endif
+	}
+	prom_entry_depth++;
+
+	return flags;
+}
+
+static __inline__ void prom_release_lock(unsigned long flags)
+{
+	if (--prom_entry_depth == 0) {
+#ifdef __SMP__
+		smp_release();
+#endif
+		spin_unlock(&prom_entry_lock);
+	}
+	__restore_flags(flags);
 }
 
 long p1275_cmd (char *service, long fmt, ...)
@@ -66,13 +300,15 @@
 	long ctx = 0;
 	
 	p = p1275buf.prom_buffer;
-	__save_and_cli(flags);
 	ctx = spitfire_get_primary_context ();
 	if (ctx) {
 		flushw_user ();
 		spitfire_set_primary_context (0);
 	}
-	p1275buf.prom_args[0] = (unsigned long)p;			/* service */
+
+	flags = prom_get_lock();
+
+	p1275buf.prom_args[0] = (unsigned long)p;		/* service */
 	strcpy (p, service);
 	p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
 	p1275buf.prom_args[1] = nargs = (fmt & 0x0f);		/* nargs */
@@ -82,7 +318,9 @@
 	for (i = 0; i < nargs; i++, attrs >>= 3) {
 		switch (attrs & 0x7) {
 		case P1275_ARG_NUMBER:
-			p1275buf.prom_args[i + 3] = (unsigned)va_arg(list, long); break;
+			p1275buf.prom_args[i + 3] =
+						(unsigned)va_arg(list, long);
+			break;
 		case P1275_ARG_IN_STRING:
 			strcpy (p, va_arg(list, char *));
 			p1275buf.prom_args[i + 3] = (unsigned long)p;
@@ -111,16 +349,16 @@
 			p += 32;
 			break;
 		case P1275_ARG_IN_FUNCTION:
-			p1275buf.prom_args[i + 3] = (unsigned long)prom_cif_interface + 0x38;
-			p1275buf.prom_sync_routine = va_arg(list, long); break;
+			p1275buf.prom_args[i + 3] =
+					(unsigned long)prom_cif_callback;
+			p1275buf.prom_callback = va_arg(list, long);
+			break;
 		}
 	}
 	va_end(list);
 
 	prom_world(1);
-	
 	prom_cif_interface();
-	
 	prom_world(0);
 
 	attrs = fmt >> 8;
@@ -128,11 +366,14 @@
 	for (i = 0; i < nargs; i++, attrs >>= 3) {
 		switch (attrs & 0x7) {
 		case P1275_ARG_NUMBER:
-			(void) va_arg(list, long); break;
+			(void) va_arg(list, long);
+			break;
 		case P1275_ARG_IN_STRING:
-			(void) va_arg(list, char *); break;
+			(void) va_arg(list, char *);
+			break;
 		case P1275_ARG_IN_FUNCTION:
-			(void) va_arg(list, long); break;
+			(void) va_arg(list, long);
+			break;
 		case P1275_ARG_IN_BUF:
 			(void) va_arg(list, char *);
 			(void) va_arg(list, long);
@@ -152,10 +393,12 @@
 	}
 	va_end(list);
 	x = p1275buf.prom_args [nargs + 3];
-	
+
+	prom_release_lock(flags);
+
 	if (ctx)
 		spitfire_set_primary_context (ctx);
-	__restore_flags(flags);
+
 	return x;
 }
 
diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/solaris/Makefile linux/arch/sparc64/solaris/Makefile
--- v2.1.126/linux/arch/sparc64/solaris/Makefile	Thu Apr 23 20:21:32 1998
+++ linux/arch/sparc64/solaris/Makefile	Tue Oct 27 09:52:21 1998
@@ -15,10 +15,10 @@
 endif
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(CPPFLAGS) -ansi $< -o $*.s
+	$(CPP) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(CPPFLAGS) -ansi -c $< -o $*.o
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o
 
 ifneq ($(CONFIG_SOLARIS_EMUL),y)
 do_it_all:
diff -u --recursive --new-file v2.1.126/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.126/linux/drivers/block/floppy.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/block/floppy.c	Fri Nov  6 12:33:25 1998
@@ -1740,12 +1740,14 @@
 	if(do_print)
 		print_result("unexpected interrupt", inr);
 	if (inr == 0){
+		int max_sensei = 4;
 		do {
 			output_byte(FD_SENSEI);
 			inr = result();
 			if(do_print)
 				print_result("sensei", inr);
-		} while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2);
+			max_sensei--;
+		} while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2 && max_sensei);
 	}
 	if (handler) {
 		int cpu = smp_processor_id();
diff -u --recursive --new-file v2.1.126/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.1.126/linux/drivers/block/ide-cd.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/block/ide-cd.c	Sat Oct 31 10:17:22 1998
@@ -3,6 +3,7 @@
  * linux/drivers/block/ide-cd.c
  * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
  * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1998 Jens Axboe and Chris Zwilling
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
@@ -221,9 +222,13 @@
  * 4.15  Aug 25, 1998  -- Updated ide-cd.h to respect mechine endianess, 
  *                         patch thanks to "Eddie C. Dost" <ecd@skynet.be>
  *
+ * 4.50  Oct 19, 1998  -- New maintainers!
+ *                         Jens Axboe <axboe@image.dk>
+ *                         Chris Zwilling <chris@cloudnet.com>
+ *
  *************************************************************************/
 
-#define IDECD_VERSION "4.15"
+#define IDECD_VERSION "4.50"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -1290,8 +1295,7 @@
 void cdrom_sleep (int time)
 {
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + time;
-	schedule ();
+	schedule_timeout(time);
 }
 
 static
@@ -2632,7 +2636,7 @@
 		if (was_locked)
 			(void) cdrom_lockdoor (drive, 1, NULL);
 
-		return stat;
+		return slot;
 	}
 }
 
diff -u --recursive --new-file v2.1.126/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h
--- v2.1.126/linux/drivers/block/ide-cd.h	Thu Sep 17 17:53:35 1998
+++ linux/drivers/block/ide-cd.h	Sat Nov  7 11:28:46 1998
@@ -4,6 +4,7 @@
  *  linux/drivers/block/ide_modes.h
  *
  *  Copyright (C) 1996  Erik Andersen
+ *  Copyright (C) 1998  Jens Axboe and Chris Zwilling
  */
 
 #include <asm/byteorder.h>
diff -u --recursive --new-file v2.1.126/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.1.126/linux/drivers/block/loop.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/block/loop.c	Mon Oct 26 09:57:55 1998
@@ -27,7 +27,6 @@
 
 #include <linux/module.h>
 
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/file.h>
diff -u --recursive --new-file v2.1.126/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.1.126/linux/drivers/block/md.c	Fri Oct  9 13:27:07 1998
+++ linux/drivers/block/md.c	Sat Oct 31 10:37:14 1998
@@ -1139,8 +1139,7 @@
 		while (blocksize*j/(jiffies-starttime+1)*HZ/1024 > SPEED_LIMIT)
 		{
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies+1;
-			schedule();
+			schedule_timeout(1);
 		}
 
 		/*
diff -u --recursive --new-file v2.1.126/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c
--- v2.1.126/linux/drivers/block/paride/pcd.c	Mon Oct  5 13:13:38 1998
+++ linux/drivers/block/paride/pcd.c	Wed Nov  4 10:03:01 1998
@@ -559,8 +559,7 @@
 static void pcd_sleep( int cs )
 
 {       current->state = TASK_INTERRUPTIBLE;
-        current->timeout = jiffies + cs;
-        schedule();
+        schedule_timeout(cs);
 }
 
 static int pcd_reset( int unit )
diff -u --recursive --new-file v2.1.126/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- v2.1.126/linux/drivers/block/paride/pf.c	Mon Oct  5 13:13:38 1998
+++ linux/drivers/block/paride/pf.c	Wed Nov  4 10:04:43 1998
@@ -660,8 +660,7 @@
 static void pf_sleep( int cs )
 
 {       current->state = TASK_INTERRUPTIBLE;
-        current->timeout = jiffies + cs;
-        schedule();
+        schedule_timeout(cs);
 }
 
 
diff -u --recursive --new-file v2.1.126/linux/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c
--- v2.1.126/linux/drivers/block/paride/pg.c	Mon Oct  5 13:13:38 1998
+++ linux/drivers/block/paride/pg.c	Wed Nov  4 10:04:29 1998
@@ -357,8 +357,7 @@
 static void pg_sleep( int cs )
 
 {       current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + cs;
-	schedule();
+	schedule_timeout(cs);
 }
 
 static int pg_wait( int unit, int go, int stop, int tmo, char * msg )
diff -u --recursive --new-file v2.1.126/linux/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c
--- v2.1.126/linux/drivers/block/paride/pt.c	Mon Oct  5 13:13:38 1998
+++ linux/drivers/block/paride/pt.c	Wed Nov  4 10:05:12 1998
@@ -464,8 +464,7 @@
 static void pt_sleep( int cs )
 
 {       current->state = TASK_INTERRUPTIBLE;
-        current->timeout = jiffies + cs;
-        schedule();
+        schedule_timeout(cs);
 }
 
 static int pt_poll_dsc( int unit, int pause, int tmo, char *msg )
diff -u --recursive --new-file v2.1.126/linux/drivers/block/swim3.c linux/drivers/block/swim3.c
--- v2.1.126/linux/drivers/block/swim3.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/block/swim3.c	Thu Nov  5 09:58:39 1998
@@ -740,8 +740,7 @@
 			break;
 		}
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 1;
-		schedule();
+		schedule_timeout(1);
 	}
 	fs->ejected = 1;
 	release_drive(fs);
@@ -807,8 +806,7 @@
 				break;
 			}
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + 1;
-			schedule();
+			schedule_timeout(1);
 		}
 		if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0
 				 || swim3_readbit(fs, DISK_IN) == 0))
@@ -911,8 +909,7 @@
 		if (signal_pending(current))
 			break;
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 1;
-		schedule();
+		schedule_timeout(1);
 	}
 	ret = swim3_readbit(fs, SEEK_COMPLETE) == 0
 		|| swim3_readbit(fs, DISK_IN) == 0;
diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.1.126/linux/drivers/cdrom/cdrom.c	Thu Sep 17 17:53:35 1998
+++ linux/drivers/cdrom/cdrom.c	Sat Oct 24 10:43:47 1998
@@ -1,6 +1,7 @@
 /* linux/drivers/cdrom/cdrom.c. 
    Copyright (c) 1996, 1997 David A. van Leeuwen.
    Copyright (c) 1997, 1998 Erik Andersen <andersee@debian.org>
+   Copyright (c) 1998 Jens Axboe and Chris Zwilling
 
    May be copied or modified under the terms of the GNU General Public
    License.  See linux/COPYING for more information.
@@ -86,10 +87,15 @@
   Thanks to Grant R. Guenther <grant@torque.net> for spotting this bug.
   -- Made a few things more pedanticly correct.
 
+ 2.50  Oct 19, 1998 - Jens Axboe <axboe@image.dk>
+  -- New maintainers! Erik was too busy to continue the work on the driver,
+  so now Chris Zwilling <chris@cloudnet.com> and Jens Axboe <axboe@image.dk>
+  will do their best to follow in his footsteps
+
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 2.14"
-#define VERSION "Id: cdrom.c 2.14 1998/08/17 erik"
+#define REVISION "Revision: 2.50"
+#define VERSION "Id: cdrom.c 2.50 1998/10/19"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c
--- v2.1.126/linux/drivers/cdrom/cdu31a.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/cdrom/cdu31a.c	Wed Nov  4 12:09:43 1998
@@ -409,8 +409,7 @@
    if (cdu31a_irq <= 0)
    {
       current->state = TASK_INTERRUPTIBLE;
-      current->timeout = jiffies;
-      schedule();
+      schedule_timeout(0);
    }
    else /* Interrupt driven */
    {
@@ -753,8 +752,7 @@
    }
 
    current->state = TASK_INTERRUPTIBLE;
-   current->timeout = jiffies + 2*HZ;
-   schedule();
+   schedule_timeout(2*HZ);
 
    sony_get_toc();
 }
@@ -1012,8 +1010,7 @@
    {
       num_retries++;
       current->state = TASK_INTERRUPTIBLE;
-      current->timeout = jiffies + HZ/10; /* Wait .1 seconds on retries */
-      schedule();
+      schedule_timeout(HZ/10);  /* Wait .1 seconds on retries */
       goto retry_cd_operation;
    }
 
diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c
--- v2.1.126/linux/drivers/cdrom/gscd.c	Wed Aug 26 11:37:36 1998
+++ linux/drivers/cdrom/gscd.c	Sat Oct 31 10:28:25 1998
@@ -66,6 +66,7 @@
 #define gscd_port gscd /* for compatible parameter passing with "insmod" */
 #include "gscd.h"
 
+static int gscd_blocksizes[1] = {512};
 
 static int gscdPresent            = 0;
 
@@ -1060,6 +1061,7 @@
 	}
 
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blksize_size[MAJOR_NR] = gscd_blocksizes;
 	read_ahead[MAJOR_NR] = 4;
         
         disk_state = 0;
diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v2.1.126/linux/drivers/cdrom/mcd.c	Tue Jun 23 10:01:22 1998
+++ linux/drivers/cdrom/mcd.c	Wed Nov  4 12:09:43 1998
@@ -1100,8 +1100,7 @@
                         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();
+                        schedule_timeout(HZ);
                 }
         } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
 
diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- v2.1.126/linux/drivers/cdrom/mcdx.c	Thu Feb 12 20:56:05 1998
+++ linux/drivers/cdrom/mcdx.c	Wed Nov  4 14:52:21 1998
@@ -794,8 +794,7 @@
 	 * allowed! */
     if (current->pid == 0) {
 		while (jiffies < tout) {
-            current->timeout = jiffies;
-            schedule();
+            schedule_timeout(0);
         }
     } else {
         current->timeout = tout;
@@ -1247,6 +1246,7 @@
 {
     int border;
     int done = 0;
+	long timeout;
 
 	if (stuffp->audio) {
 			xwarn("Attempt to read from audio CD.\n");
@@ -1281,13 +1281,12 @@
 
 	do {
 
-	    current->timeout = jiffies + 5 * HZ;
 	    while (stuffp->busy) {
 
-			interruptible_sleep_on(&stuffp->busyq);
+			timeout = interruptible_sleep_on_timeout(&stuffp->busyq, 5*HZ);
 
 			if (!stuffp->introk) { xtrace(XFER, "error via interrupt\n"); }
-			else if (current->timeout == 0) { xtrace(XFER, "timeout\n"); }
+			else if (!timeout) { xtrace(XFER, "timeout\n"); }
 			else if (signal_pending(current)) {
 				xtrace(XFER, "signal\n");
 			} else continue;
diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- v2.1.126/linux/drivers/cdrom/sbpcd.c	Thu Sep 17 17:53:35 1998
+++ linux/drivers/cdrom/sbpcd.c	Wed Nov  4 12:09:43 1998
@@ -843,8 +843,7 @@
 {
 	sti();
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + time;
-	schedule();
+	schedule_timeout(time);
 	sti();
 }
 /*==========================================================================*/
diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c
--- v2.1.126/linux/drivers/cdrom/sonycd535.c	Wed Aug 26 11:37:36 1998
+++ linux/drivers/cdrom/sonycd535.c	Thu Nov  5 21:36:12 1998
@@ -62,26 +62,24 @@
  * This interface is (unfortunately) a polled interface.  This is
  * because most Sony interfaces are set up with DMA and interrupts
  * disables.  Some (like mine) do not even have the capability to
- * handle interrupts or DMA.  For this reason you will see a lot of
+ * handle interrupts or DMA.  For this reason you will see a bit of
  * the following:
  *
- *   retry_count = jiffies+ SONY_JIFFIES_TIMEOUT;
- *   while ((retry_count > jiffies) && (! <some condition to wait for))
+ *   snap = jiffies;
+ *   while (jiffies-snap < SONY_JIFFIES_TIMEOUT)
  *   {
- *      while (handle_sony_cd_attention())
- *         ;
- *
+ *		if (some_condition())
+ *         break;
  *      sony_sleep();
  *   }
- *   if (the condition not met)
+ *   if (some_condition not met)
  *   {
- *      return an error;
+ *      return an_error;
  *   }
  *
  * This ugly hack waits for something to happen, sleeping a little
- * between every try.  it also handles attentions, which are
- * asynchronous events from the drive informing the driver that a disk
- * has been inserted, removed, etc.
+ * between every try.  (The conditional is written so that jiffies
+ * wrap-around is handled properly.)
  *
  * One thing about these drives: They talk in MSF (Minute Second Frame) format.
  * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a
@@ -327,17 +325,14 @@
 
 
 /*
- * Wait a little while (used for polling the drive).  If in initialization,
- * setting a timeout doesn't work, so just loop for a while.  (We trust
- * that the sony_sleep() call is protected by a test for proper jiffies count.)
+ * Wait a little while.
  */
 static inline void
 sony_sleep(void)
 {
 	if (sony535_irq_used <= 0) {	/* poll */
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies;
-		schedule();
+		schedule_timeout(0);
 	} else {	/* Interrupt driven */
 		cli();
 		enable_interrupts();
@@ -370,12 +365,13 @@
 static int
 read_result_reg(Byte *data_ptr)
 {
-	int retry_count;
+	unsigned long snap;
 	int read_status;
 
-	retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-	while (jiffies < retry_count) {
-		if (((read_status = inb(read_status_reg)) & SONY535_RESULT_NOT_READY_BIT) == 0) {
+	snap = jiffies;
+	while (jiffies-snap < SONY_JIFFIES_TIMEOUT) {
+		read_status = inb(read_status_reg);
+		if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) {
 #if DEBUG > 1
 			printk(CDU535_MESSAGE_NAME
 					": read_result_reg(): readStatReg = 0x%x\n", read_status);
@@ -599,7 +595,7 @@
 	Byte cmd_buff[7];
 	int  i;
 	int  read_status;
-	int  retry_count;
+	unsigned long snap;
 	Byte *data_buff;
 	int  sector_count = 0;
 
@@ -618,8 +614,9 @@
 	/* read back the data one block at a time */
 	while (0 < n_blocks--) {
 		/* wait for data to be ready */
-		retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-		while (jiffies < retry_count) {
+		int data_valid = 0;
+		snap = jiffies;
+		while (jiffies-snap < SONY_JIFFIES_TIMEOUT) {
 			read_status = inb(read_status_reg);
 			if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) {
 				read_exec_status(status);
@@ -630,11 +627,12 @@
 				data_buff = buff[sector_count++];
 				for (i = 0; i < block_size; i++)
 					*data_buff++ = inb(data_reg);	/* unrolling this loop does not seem to help */
+				data_valid = 1;
 				break;			/* exit the timeout loop */
 			}
 			sony_sleep();		/* data not ready, sleep a while */
 		}
-		if (retry_count <= jiffies)
+		if (!data_valid)
 			return TIME_OUT;	/* if we reach this stage */
 	}
 
@@ -893,8 +891,7 @@
 						if (readStatus == BAD_STATUS) {
 							/* Sleep for a while, then retry */
 							current->state = TASK_INTERRUPTIBLE;
-							current->timeout = jiffies + RETRY_FOR_BAD_STATUS;
-							schedule();
+							schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10);
 						}
 #if DEBUG > 0
 						printk(CDU535_MESSAGE_NAME
@@ -1493,7 +1490,8 @@
 	Byte cmd_buff[3];
 	Byte ret_buff[2];
 	Byte status[2];
-	int  retry_count;
+	unsigned long snap;
+	int  got_result = 0;
 	int  tmp_irq;
 	int  i;
 
@@ -1525,21 +1523,22 @@
 	}
 	/* look for the CD-ROM, follows the procedure in the DOS driver */
 	inb(select_unit_reg);
-	retry_count = jiffies + 2 * HZ;
-	while (jiffies < retry_count)
-		sony_sleep();			/* wait for 40 18 Hz ticks (from DOS driver) */
+	/* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */
+	schedule_timeout((HZ+17)*40/18);
 	inb(result_reg);
 
 	outb(0, read_status_reg);	/* does a reset? */
-	retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
-	while (jiffies < retry_count) {
+	snap = jiffies;
+	while (jiffies-snap < SONY_JIFFIES_TIMEOUT) {
 		select_unit(0);
-		if (inb(result_reg) != 0xff)
+		if (inb(result_reg) != 0xff) {
+			got_result = 1;
 			break;
+		}
 		sony_sleep();
 	}
 
-	if ((jiffies < retry_count) && (check_drive_status() != TIME_OUT)) {
+	if (got_result && (check_drive_status() != TIME_OUT)) {
 		/* CD-ROM drive responded --  get the drive configuration */
 		cmd_buff[0] = SONY535_INQUIRY;
 		if (do_sony_cmd(cmd_buff, 1, status,
diff -u --recursive --new-file v2.1.126/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.126/linux/drivers/char/Makefile	Fri Oct 23 22:01:20 1998
+++ linux/drivers/char/Makefile	Tue Oct 27 09:52:21 1998
@@ -240,12 +240,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_SUN_OPENPROMIO),y)
-else
-  ifeq ($(CONFIG_SUN_OPENPROMIO),m)
-  endif
-endif
-
 ifeq ($(CONFIG_WDT),y)
 L_OBJS += wdt.o
 else
diff -u --recursive --new-file v2.1.126/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c
--- v2.1.126/linux/drivers/char/bw-qcam.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/char/bw-qcam.c	Sat Oct 31 11:03:24 1998
@@ -214,8 +214,7 @@
 			if(runs++>1000)
 			{
 				current->state=TASK_INTERRUPTIBLE;
-				current->timeout = jiffies+HZ/10;
-				schedule();
+				schedule_timeout(HZ/10);
 			}
 			if(runs>1050)
 				return -1;
@@ -232,8 +231,7 @@
 			if(runs++>1000)
 			{
 				current->state=TASK_INTERRUPTIBLE;
-				current->timeout = jiffies+HZ/10;
-				schedule();
+				schedule_timeout(HZ/10);
 			}
 			if(runs++>1050)	/* 5 seconds */
 				return -1;
@@ -263,8 +261,7 @@
 		if(runs++>1000)
 		{
 			current->state=TASK_INTERRUPTIBLE;
-			current->timeout = jiffies+HZ/10;
-			schedule();
+			schedule_timeout(HZ/10);
 		}
 		if(runs++>1050)	/* 5 seconds */
 			return 0;
diff -u --recursive --new-file v2.1.126/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c
--- v2.1.126/linux/drivers/char/c-qcam.c	Tue Aug 18 22:02:03 1998
+++ linux/drivers/char/c-qcam.c	Sat Oct 31 11:04:24 1998
@@ -58,8 +58,7 @@
 		if (qcam_ready1(qcam) == value)
 			return 0;
 		current->state=TASK_INTERRUPTIBLE;
-		current->timeout = jiffies+HZ/10;
-		schedule();
+		schedule_timeout(HZ/10);
 	}
 
 	/* Probably somebody pulled the plug out.  Not much we can do. */
@@ -85,8 +84,7 @@
 		if (qcam_ready2(qcam) == value)
 			return 0;
 		current->state=TASK_INTERRUPTIBLE;
-		current->timeout = jiffies+HZ/10;
-		schedule();
+		schedule_timeout(HZ/10);
 	}
 
 	/* Probably somebody pulled the plug out.  Not much we can do. */
diff -u --recursive --new-file v2.1.126/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.1.126/linux/drivers/char/console.c	Fri Oct  9 13:27:07 1998
+++ linux/drivers/char/console.c	Mon Nov  2 13:21:42 1998
@@ -2415,7 +2415,7 @@
 	}
 	printk("Console: switching ");
 	if (!deflt)
-		printk("consoles %d-%d ", first, last);
+		printk("consoles %d-%d ", first+1, last+1);
 	if (j >= 0)
 		printk("to %s %s %dx%d\n",
 		       vc_cons[j].d->vc_can_do_color ? "colour" : "mono",
@@ -2564,7 +2564,7 @@
 		return;
 	if (console_blanked) {
 		timer_table[BLANK_TIMER].fn = unblank_screen;
-		timer_table[BLANK_TIMER].expires = 0;
+		timer_table[BLANK_TIMER].expires = jiffies;	/* Now */
 		timer_active |= 1<<BLANK_TIMER;
 	} else if (blankinterval) {
 		timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
diff -u --recursive --new-file v2.1.126/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.1.126/linux/drivers/char/cyclades.c	Wed Sep  9 14:51:07 1998
+++ linux/drivers/char/cyclades.c	Sat Oct 31 11:05:20 1998
@@ -2590,8 +2590,7 @@
 #endif
 	    current->state = TASK_INTERRUPTIBLE;
 	    current->counter = 0;	/* make us low-priority */
-	    current->timeout = jiffies + char_time;
-	    schedule();
+	    schedule_timeout(char_time);
 	    if (signal_pending(current))
 		break;
 	    if (timeout && ((orig_jiffies + timeout) < jiffies))
@@ -2604,8 +2603,7 @@
     /* Run one more char cycle */
     current->state = TASK_INTERRUPTIBLE;
     current->counter = 0;	/* make us low-priority */
-    current->timeout = jiffies + (char_time * 5);
-    schedule();
+    schedule_timeout(char_time * 5);
     current->state = TASK_RUNNING;
 #ifdef CY_DEBUG_WAIT_UNTIL_SENT
     printk("Clean (jiff=%lu)...done\n", jiffies);
@@ -2737,8 +2735,7 @@
     if (info->blocked_open) {
         if (info->close_delay) {
             current->state = TASK_INTERRUPTIBLE;
-            current->timeout = jiffies + info->close_delay;
-            schedule();
+            schedule_timeout(info->close_delay);
         }
         wake_up_interruptible(&info->open_wait);
     }
diff -u --recursive --new-file v2.1.126/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c
--- v2.1.126/linux/drivers/char/dsp56k.c	Wed Aug 26 11:37:36 1998
+++ linux/drivers/char/dsp56k.c	Sat Oct 31 11:05:37 1998
@@ -63,8 +63,7 @@
 #define wait_some(n) \
 { \
 	current->state = TASK_INTERRUPTIBLE; \
-	current->timeout = jiffies + n; \
-	schedule(); \
+	schedule_timeout(n); \
 }
 
 #define handshake(count, maxio, timeout, ENABLE, f) \
diff -u --recursive --new-file v2.1.126/linux/drivers/char/epca.c linux/drivers/char/epca.c
--- v2.1.126/linux/drivers/char/epca.c	Sun Jun  7 11:16:29 1998
+++ linux/drivers/char/epca.c	Sat Oct 31 11:05:53 1998
@@ -647,8 +647,7 @@
 			if (ch->close_delay) 
 			{
 				current->state = TASK_INTERRUPTIBLE;
-				current->timeout = jiffies + ch->close_delay;
-				schedule();
+				schedule_timeout(ch->close_delay);
 			}
 
 			wake_up_interruptible(&ch->open_wait);
diff -u --recursive --new-file v2.1.126/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.1.126/linux/drivers/char/esp.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/char/esp.c	Sat Oct 31 11:06:21 1998
@@ -2147,8 +2147,7 @@
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
+			schedule_timeout(info->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
@@ -2182,8 +2181,7 @@
 		(serial_in(info, UART_ESI_STAT2) != 0xff)) {
 		current->state = TASK_INTERRUPTIBLE;
 		current->counter = 0;
-		current->timeout = jiffies + char_time;
-		schedule();
+		schedule_timeout(char_time);
 
 		if (signal_pending(current))
 			break;
diff -u --recursive --new-file v2.1.126/linux/drivers/char/ftape/lowlevel/fdc-io.c linux/drivers/char/ftape/lowlevel/fdc-io.c
--- v2.1.126/linux/drivers/char/ftape/lowlevel/fdc-io.c	Sun Jun  7 11:16:29 1998
+++ linux/drivers/char/ftape/lowlevel/fdc-io.c	Wed Nov  4 09:56:37 1998
@@ -389,6 +389,7 @@
 	sigset_t old_sigmask;	
 	static int resetting = 0;
 	TRACE_FUN(ft_t_fdc_dma);
+	long timeout;
 
 #if LINUX_VERSION_CODE >= KERNEL_VER(2,0,16)
  	if (waitqueue_active(&ftape_wait_intr)) {
@@ -400,8 +401,7 @@
 	}
 #endif
 	/* timeout time will be up to USPT microseconds too long ! */
-	current->timeout = jiffies + (1000 * time + FT_USPT - 1) / FT_USPT;
-	current->state = TASK_INTERRUPTIBLE;
+	timeout = (1000 * time + FT_USPT - 1) / FT_USPT;
 
 	spin_lock_irq(&current->sigmask_lock);
 	old_sigmask = current->blocked;
@@ -409,9 +409,10 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
+	current->state = TASK_INTERRUPTIBLE;
 	add_wait_queue(&ftape_wait_intr, &wait);
-	while (!ft_interrupt_seen && current->state != TASK_RUNNING) {
-		schedule();	/* sets TASK_RUNNING on timeout */
+	while (!ft_interrupt_seen && (current->state == TASK_INTERRUPTIBLE)) {
+		timeout = schedule_timeout(timeout);
         }
 
 	spin_lock_irq(&current->sigmask_lock);
@@ -433,7 +434,6 @@
 	 */
 	current->state = TASK_RUNNING; 
 	if (ft_interrupt_seen) { /* woken up by interrupt */
-		current->timeout = 0;	  /* interrupt hasn't cleared this */
 		ft_interrupt_seen = 0;
 		TRACE_EXIT 0;
 	}
diff -u --recursive --new-file v2.1.126/linux/drivers/char/ftape/lowlevel/ftape-io.c linux/drivers/char/ftape/lowlevel/ftape-io.c
--- v2.1.126/linux/drivers/char/ftape/lowlevel/ftape-io.c	Tue Dec  2 09:33:16 1997
+++ linux/drivers/char/ftape/lowlevel/ftape-io.c	Wed Nov  4 09:57:43 1998
@@ -89,17 +89,18 @@
 		/*  Time too small for scheduler, do a busy wait ! */
 		ftape_udelay(time);
 	} else {
+		long timeout;
 		unsigned long flags;
 		unsigned int ticks = (time + FT_USPT - 1) / FT_USPT;
 
 		TRACE(ft_t_any, "%d msec, %d ticks", time/1000, ticks);
-		current->timeout = jiffies + ticks;
+		timeout = ticks;
 		current->state = TASK_INTERRUPTIBLE;
 		save_flags(flags);
 		sti();
 		do {
 			while (current->state != TASK_RUNNING) {
-				schedule();
+				timeout = schedule_timeout(timeout);
 			}
 			/*  Mmm. Isn't current->blocked == 0xffffffff ?
 			 */
@@ -108,7 +109,7 @@
 				      "awoken by non-blocked signal :-(");
 				break;	/* exit on signal */
 			}
-		} while (current->timeout > 0);
+		} while (timeout);
 		restore_flags(flags);
 	}
 	TRACE_EXIT;
diff -u --recursive --new-file v2.1.126/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.1.126/linux/drivers/char/istallion.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/char/istallion.c	Sat Oct 31 11:07:22 1998
@@ -1292,8 +1292,7 @@
 #endif
 	if (len > 0) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + len;
-		schedule();
+		schedule_timeout(len);
 		current->state = TASK_RUNNING;
 	}
 }
@@ -2252,7 +2251,8 @@
 {
 	stlibrd_t	*brdp;
 	stliport_t	*portp;
-	long		arg, savestate, savetime;
+	long		arg;
+	/* long savestate, savetime; */
 
 #if DEBUG
 	printk("stli_breakctl(tty=%x,state=%d)\n", (int) tty, state);
@@ -2272,15 +2272,18 @@
 /*
  *	Due to a bug in the tty send_break() code we need to preserve
  *	the current process state and timeout...
- */
 	savetime = current->timeout;
 	savestate = current->state;
+ */
 
 	arg = (state == -1) ? BREAKON : BREAKOFF;
 	stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0);
 
+/*
+ *
 	current->timeout = savetime;
 	current->state = savestate;
+ */
 }
 
 /*****************************************************************************/
diff -u --recursive --new-file v2.1.126/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.126/linux/drivers/char/lp.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/char/lp.c	Sat Nov  7 10:56:05 1998
@@ -162,17 +162,17 @@
 		lp_table[minor].irq_missed = 1;
 }
 
-static __inline__ void lp_schedule(int minor)
+static __inline__ void lp_schedule(int minor, long timeout)
 {
 	struct pardevice *dev = lp_table[minor].dev;
 	register unsigned long int timeslip = (jiffies - dev->time);
 	if ((timeslip > dev->timeslice) && (dev->port->waithead != NULL)) {
 		lp_parport_release(minor);
 		lp_table[minor].irq_missed = 1;
-		schedule ();
+		schedule_timeout(timeout);
 		lp_parport_claim(minor);
 	} else
-		schedule();
+		schedule_timeout(timeout);
 }
 
 static int lp_reset(int minor)
@@ -269,9 +269,8 @@
 {
 	if (LP_POLLED(minor) || LP_PREEMPTED(minor)) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + LP_TIMEOUT_POLLED;
 		lp_parport_release(minor);
-		schedule();
+		schedule_timeout(LP_TIMEOUT_POLLED);
 		lp_parport_claim(minor);
 		lp_table[minor].irq_missed = 1;
 	}
@@ -381,8 +380,7 @@
 					printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor));
 #endif
 					current->state = TASK_INTERRUPTIBLE;
-					current->timeout = jiffies + LP_TIME(minor);
-					lp_schedule (minor);
+					lp_schedule(minor, LP_TIME(minor));
 				} else {
 					cli();
 					if (LP_PREEMPTED(minor))
@@ -399,8 +397,7 @@
 					}
 					if (!lp_table[minor].irq_detected)
 					{
-						current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
-						interruptible_sleep_on(&lp->wait_q);
+						interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT);
 					}
 					sti();
 				}
@@ -535,8 +532,7 @@
 					return -EINTR;
 			}
 			current->state=TASK_INTERRUPTIBLE;
-			current->timeout=jiffies + LP_TIME(minor);
-			schedule ();
+			schedule_timeout(LP_TIME(minor));
 		}
 
 		counter=0;
diff -u --recursive --new-file v2.1.126/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.126/linux/drivers/char/mem.c	Mon Oct  5 13:13:39 1998
+++ linux/drivers/char/mem.c	Tue Oct 27 09:52:21 1998
@@ -35,6 +35,9 @@
 void dmasound_init(void);
 #endif
 #endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
 #ifdef CONFIG_ISDN
 int isdn_init(void);
 #endif
@@ -570,6 +573,9 @@
 #ifdef CONFIG_DMASOUND
 	dmasound_init();
 #endif	
+#endif
+#ifdef CONFIG_SPARCAUDIO
+	sparcaudio_init();
 #endif
 #ifdef CONFIG_JOYSTICK
 	/*
diff -u --recursive --new-file v2.1.126/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c
--- v2.1.126/linux/drivers/char/msp3400.c	Thu Aug 20 17:05:15 1998
+++ linux/drivers/char/msp3400.c	Sat Oct 31 10:17:22 1998
@@ -554,8 +554,7 @@
 			UNLOCK_I2C_BUS(msp->bus);
 
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + HZ/25;
-			schedule();
+			schedule_timeout(HZ/25);
 			if (signal_pending(current))
 				goto done;
 			if (msp->restart) {
@@ -589,8 +588,7 @@
 			UNLOCK_I2C_BUS(msp->bus);
 
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + HZ/25;
-			schedule();
+			schedule_timeout(HZ/25);
 			if (signal_pending(current))
 				goto done;
 			if (msp->restart) {
@@ -715,8 +713,7 @@
 
 		/* wait 1 sec */
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + HZ;
-		schedule();
+		schedule_timeout(HZ);
 		if (signal_pending(current))
 			goto done;
 		if (msp->restart) {
diff -u --recursive --new-file v2.1.126/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.1.126/linux/drivers/char/n_tty.c	Wed Aug 26 11:37:37 1998
+++ linux/drivers/char/n_tty.c	Sat Oct 31 10:17:22 1998
@@ -419,7 +419,7 @@
 	char buf[64];
 
 	tty->num_overrun++;
-	if (tty->overrun_time < (jiffies - HZ)) {
+	if (time_before(tty->overrun_time, jiffies - HZ)) {
 		printk("%s: %d input overrun(s)\n", tty_name(tty, buf),
 		       tty->num_overrun);
 		tty->overrun_time = jiffies;
@@ -872,6 +872,7 @@
 	int minimum, time;
 	ssize_t retval = 0;
 	ssize_t size;
+	long timeout;
 
 do_it_again:
 
@@ -900,7 +901,7 @@
 	}
 
 	minimum = time = 0;
-	current->timeout = (unsigned long) -1;
+	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (!tty->icanon) {
 		time = (HZ / 10) * TIME_CHAR(tty);
 		minimum = MIN_CHAR(tty);
@@ -911,9 +912,9 @@
 				 (tty->minimum_to_wake > minimum))
 				tty->minimum_to_wake = minimum;
 		} else {
-			current->timeout = 0;
+			timeout = 0;
 			if (time) {
-				current->timeout = time + jiffies;
+				timeout = time;
 				time = 0;
 			}
 			tty->minimum_to_wake = minimum = 1;
@@ -949,7 +950,7 @@
 			}
 			if (tty_hung_up_p(file))
 				break;
-			if (!current->timeout)
+			if (!timeout)
 				break;
 			if (file->f_flags & O_NONBLOCK) {
 				retval = -EAGAIN;
@@ -960,7 +961,7 @@
 				break;
 			}
 			enable_bh(TQUEUE_BH);
-			schedule();
+			timeout = schedule_timeout(timeout);
 			disable_bh(TQUEUE_BH);
 			continue;
 		}
@@ -1021,7 +1022,7 @@
 		if (b - buf >= minimum)
 			break;
 		if (time)
-			current->timeout = time + jiffies;
+			timeout = time;
 	}
 	enable_bh(TQUEUE_BH);
 	remove_wait_queue(&tty->read_wait, &wait);
@@ -1030,7 +1031,6 @@
 		tty->minimum_to_wake = minimum;
 
 	current->state = TASK_RUNNING;
-	current->timeout = 0;
 	size = b - buf;
 	if (size) {
 		retval = size;
diff -u --recursive --new-file v2.1.126/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.126/linux/drivers/char/pc_keyb.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/char/pc_keyb.c	Tue Nov  3 23:10:00 1998
@@ -56,7 +56,7 @@
 
 static void kbd_write(int address, int data);
 
-static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
 
 /* used only by send_data - set by keyboard_interrupt */
 static volatile unsigned char reply_expected = 0;
@@ -904,10 +904,18 @@
 
 static int __init psaux_init(void)
 {
+#if 0
+	/*
+	 * Don't bother with the BIOS flag: even if we don't have
+	 * a mouse connected at bootup we may still want to connect
+	 * one later, and we don't want to just let the BIOS tell
+	 * us that it has no mouse..
+	 */
 	if (aux_device_present != 0xaa)
 		return -EIO;
 
 	printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
+#endif
 	misc_register(&psaux_mouse);
 	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
 	memset(queue, 0, sizeof(*queue));
diff -u --recursive --new-file v2.1.126/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- v2.1.126/linux/drivers/char/pcxx.c	Sun Jun  7 11:16:30 1998
+++ linux/drivers/char/pcxx.c	Thu Nov  5 09:58:43 1998
@@ -633,8 +633,7 @@
 		if(info->blocked_open) {
 			if(info->close_delay) {
 				current->state = TASK_INTERRUPTIBLE;
-				current->timeout = jiffies + info->close_delay;
-				schedule();
+				schedule_timeout(info->close_delay);
 			}
 			wake_up_interruptible(&info->open_wait);
 		}
diff -u --recursive --new-file v2.1.126/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c
--- v2.1.126/linux/drivers/char/qpmouse.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/char/qpmouse.c	Sat Oct 31 10:43:36 1998
@@ -245,8 +245,7 @@
 		if (inb_p(qp_status)&(QP_RX_FULL))
 			inb_p(qp_data);
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + (5*HZ + 99) / 100;
-		schedule();
+		schedule_timeout((5*HZ + 99) / 100);
 		retries++;
 	}
 	return !(retries==MAX_RETRIES);
diff -u --recursive --new-file v2.1.126/linux/drivers/char/radio-sf16fmi.c linux/drivers/char/radio-sf16fmi.c
--- v2.1.126/linux/drivers/char/radio-sf16fmi.c	Fri Oct  9 13:27:08 1998
+++ linux/drivers/char/radio-sf16fmi.c	Thu Nov  5 09:58:43 1998
@@ -43,7 +43,7 @@
  * 92.7400017 -> 92.75
  */
 #define RSF16_ENCODE(x)	((x)/800+214)
-#define RSF16_MINFREQ 88*16000
+#define RSF16_MINFREQ 87*16000
 #define RSF16_MAXFREQ 108*16000
 
 static void outbits(int bits, unsigned int data, int port)
@@ -64,27 +64,31 @@
 	}
 }
 
-static void fmi_mute(int port)
+static inline void fmi_mute(int port)
 {
 	outb(0x00, port);
 }
 
-static void fmi_unmute(int port)
+static inline void fmi_unmute(int port)
 {
 	outb(0x08, port);
 }
 
-static int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
+static inline int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
 {
         int myport = dev->port;
 
 	outbits(16, RSF16_ENCODE(freq), myport);
 	outbits(8, 0xC0, myport);
-	/* we should wait here... */
+	/* it is better than udelay(140000), isn't it? */
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(HZ/7);
+	/* ignore signals, we really should restore volume */
+	if (dev->curvol) fmi_unmute(myport);
 	return 0;
 }
 
-static int fmi_getsigstr(struct fmi_device *dev)
+static inline int fmi_getsigstr(struct fmi_device *dev)
 {
 	int val;
 	int res;
@@ -93,10 +97,16 @@
 	val = dev->curvol ? 0x08 : 0x00;	/* unmute/mute */
 	outb(val, myport);
 	outb(val | 0x10, myport);
-	udelay(140000);
+	/* it is better than udelay(140000), isn't it? */
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(HZ/7);
+	/* do not do it..., 140ms is very looong time to get signal in real program 
+	if (signal_pending(current))
+	    return -EINTR;
+	*/
 	res = (int)inb(myport+1);
 	outb(val, myport);
-	return (res & 2) ? 0 : 1;
+	return (res & 2) ? 0 : 0xFFFF;
 }
 
 static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
@@ -136,7 +146,7 @@
 			v.rangehigh = RSF16_MAXFREQ/mult;
 			v.flags=fmi->flags;
 			v.mode=VIDEO_MODE_AUTO;
-			v.signal=0xFFFF*fmi_getsigstr(fmi);
+			v.signal = fmi_getsigstr(fmi);
 			if(copy_to_user(arg,&v, sizeof(v)))
 				return -EFAULT;
 			return 0;
diff -u --recursive --new-file v2.1.126/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- v2.1.126/linux/drivers/char/riscom8.c	Thu May  7 22:51:49 1998
+++ linux/drivers/char/riscom8.c	Thu Nov  5 09:58:43 1998
@@ -1172,8 +1172,7 @@
 		timeout = jiffies+HZ;
 		while(port->IER & IER_TXEMPTY)  {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + port->timeout;
-			schedule();
+			schedule_timeout(port->timeout);
 			if (jiffies > timeout)
 				break;
 		}
@@ -1189,8 +1188,7 @@
 	if (port->blocked_open) {
 		if (port->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + port->close_delay;
-			schedule();
+			schedule_timeout(port->close_delay);
 		}
 		wake_up_interruptible(&port->open_wait);
 	}
diff -u --recursive --new-file v2.1.126/linux/drivers/char/rocket.c linux/drivers/char/rocket.c
--- v2.1.126/linux/drivers/char/rocket.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/char/rocket.c	Thu Nov  5 09:58:43 1998
@@ -1181,8 +1181,7 @@
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
+			schedule_timeout(info->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	} else {
@@ -1269,10 +1268,9 @@
 static void send_break(	struct r_port * info, int duration)
 {
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + duration;
 	cli();
 	sSendBreak(&info->channel);
-	schedule();
+	schedule_timeout(duration);
 	sClrBreak(&info->channel);
 	sti();
 }
@@ -1666,8 +1664,7 @@
 #endif
 		current->state = TASK_INTERRUPTIBLE;
 		current->counter = 0;	/* make us low-priority */
-		current->timeout = jiffies + check_time;
-		schedule();
+		schedule_timeout(check_time);
 		if (signal_pending(current))
 			break;
 	}
diff -u --recursive --new-file v2.1.126/linux/drivers/char/saa5249.c linux/drivers/char/saa5249.c
--- v2.1.126/linux/drivers/char/saa5249.c	Fri Oct  9 13:27:08 1998
+++ linux/drivers/char/saa5249.c	Thu Nov  5 09:58:43 1998
@@ -242,8 +242,7 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + delay;
-	schedule();
+	schedule_timeout(delay);
 
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = oldblocked;
diff -u --recursive --new-file v2.1.126/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.1.126/linux/drivers/char/serial.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/char/serial.c	Tue Nov  3 22:05:25 1998
@@ -1653,6 +1653,8 @@
 			return -EPERM;
 		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
 			       (new_serial.flags & ASYNC_USR_MASK));
+		info->flags = ((state->flags & ~ASYNC_USR_MASK) |
+			       (info->flags & ASYNC_USR_MASK));
 		state->custom_divisor = new_serial.custom_divisor;
 		goto check_and_exit;
 	}
@@ -1660,8 +1662,9 @@
 	new_serial.irq = irq_cannonicalize(new_serial.irq);
 
 	if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
-	    (new_serial.type < PORT_UNKNOWN) ||
-	    (new_serial.type > PORT_MAX)) {
+	    (new_serial.baud_base == 0) || (new_serial.type < PORT_UNKNOWN) ||
+	    (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
+	    (new_serial.type == PORT_STARTECH)) {
 		return -EINVAL;
 	}
 
@@ -2291,8 +2294,7 @@
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
+			schedule_timeout(info->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
@@ -2346,8 +2348,7 @@
 #endif
 		current->state = TASK_INTERRUPTIBLE;
 		current->counter = 0;	/* make us low-priority */
-		current->timeout = jiffies + char_time;
-		schedule();
+		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
 		if (timeout && ((orig_jiffies + timeout) < jiffies))
diff -u --recursive --new-file v2.1.126/linux/drivers/char/serial167.c linux/drivers/char/serial167.c
--- v2.1.126/linux/drivers/char/serial167.c	Fri Oct  9 13:27:08 1998
+++ linux/drivers/char/serial167.c	Thu Nov  5 09:58:43 1998
@@ -1952,8 +1952,7 @@
     if (info->blocked_open) {
 	if (info->close_delay) {
 	    current->state = TASK_INTERRUPTIBLE;
-	    current->timeout = jiffies + info->close_delay;
-	    schedule();
+	    schedule_timeout(info->close_delay);
 	}
 	wake_up_interruptible(&info->open_wait);
     }
diff -u --recursive --new-file v2.1.126/linux/drivers/char/specialix.c linux/drivers/char/specialix.c
--- v2.1.126/linux/drivers/char/specialix.c	Thu May  7 22:51:49 1998
+++ linux/drivers/char/specialix.c	Thu Nov  5 09:58:43 1998
@@ -58,6 +58,8 @@
  *                Made many more debug printk's a compile time option.
  * Revision 1.8:  Jul 1  1997
  *                port to linux-2.1.43 kernel.
+ * Revision 1.9:  Oct 9  1998
+ *                Added stuff for the IO8+/PCI version. . 
  * 
  */
 
@@ -87,6 +89,7 @@
 #include <linux/delay.h>
 #include <linux/tqueue.h>
 #include <linux/version.h>
+#include <linux/pci.h>
 
 
 /* ************************************************************** */
@@ -173,7 +176,6 @@
 #define SPECIALIX_TYPE_NORMAL	1
 #define SPECIALIX_TYPE_CALLOUT	2
 
-static struct specialix_board * IRQ_to_board[16] = { NULL, } ;
 static struct tty_driver specialix_driver, specialix_callout_driver;
 static int    specialix_refcount = 0;
 static struct tty_struct * specialix_table[SX_NBOARD * SX_NPORT] = { NULL, };
@@ -331,17 +333,22 @@
 
 extern inline void sx_request_io_range(struct specialix_board * bp)
 {
-	request_region(bp->base, SX_IO_SPACE, "specialix IO8+" );
+	request_region(bp->base, 
+	               bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE,
+	               "specialix IO8+" );
 }
 
 
 extern inline void sx_release_io_range(struct specialix_board * bp)
 {
-	release_region(bp->base, SX_IO_SPACE);
+	release_region(bp->base, 
+	               bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE);
 }
 
 	
 /* Must be called with enabled interrupts */
+/* Ugly. Very ugly. Don't use this for anything else than initialization 
+   code */
 extern inline void sx_long_delay(unsigned long delay)
 {
 	unsigned long i;
@@ -357,6 +364,8 @@
 	int virq;
 	int i;
 
+	if (bp->flags & SX_BOARD_IS_PCI) 
+		return 1;
 	switch (bp->irq) {
 	/* In the same order as in the docs... */
 	case 15: virq = 0;break;
@@ -484,9 +493,14 @@
 	printk (KERN_DEBUG "sx%d: DSR lines are: %02x, rts lines are: %02x\n", 
 	        board_No(bp),  val1, val2);
 #endif
-	if (val1 != 0xb2) {
-		printk(KERN_INFO "sx%d: specialix IO8+ ID at 0x%03x not found.\n",
-		       board_No(bp), bp->base);
+	/* They managed to switch the bit order between the docs and
+	   the IO8+ card. The new PCI card now conforms to old docs.
+	   They changed the PCI docs to reflect the situation on the
+	   old card. */
+	val2 = (bp->flags & SX_BOARD_IS_PCI)?0x4d : 0xb2;
+	if (val1 != val2) {
+		printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
+		       board_No(bp), val2, bp->base, val1);
 		return 1;
 	}
 
@@ -868,7 +882,7 @@
 	unsigned long loop = 0;
 	int saved_reg;
 
-	bp = IRQ_to_board[irq];
+	bp = dev_id;
 	
 	if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
 #ifdef SPECIALIX_DEBUG 
@@ -924,6 +938,25 @@
  *  Routines for open & close processing.
  */
 
+void turn_ints_off (struct specialix_board *bp)
+{
+	if (bp->flags & SX_BOARD_IS_PCI) {
+		/* This was intended for enabeling the interrupt on the
+		 * PCI card. However it seems that it's already enabled
+		 * and as PCI interrupts can be shared, there is no real
+		 * reason to have to turn it off. */
+	}
+	(void) sx_in_off (bp, 0); /* Turn off interrupts. */
+}
+
+void turn_ints_on (struct specialix_board *bp)
+{
+	if (bp->flags & SX_BOARD_IS_PCI) {
+		/* play with the PCI chip. See comment above. */
+	}
+	(void) sx_in (bp, 0); /* Turn ON interrupts. */
+}
+
 
 /* Called with disabled interrupts */
 extern inline int sx_setup_board(struct specialix_board * bp)
@@ -933,14 +966,12 @@
 	if (bp->flags & SX_BOARD_ACTIVE) 
 		return 0;
 
-	error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", NULL);
+	error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp);
 
 	if (error) 
 		return error;
 
-	IRQ_to_board[bp->irq] = bp;
-	(void) sx_in (bp, 0); /* Turn ON interrupts. */
-
+	turn_ints_on (bp);
 	bp->flags |= SX_BOARD_ACTIVE;
 
 	MOD_INC_USE_COUNT;
@@ -956,11 +987,13 @@
 	
 	bp->flags &= ~SX_BOARD_ACTIVE;
 	
-	free_irq(bp->irq, NULL);
-	(void) sx_in_off (bp, 0); /* Turn off interrupts. */
+#if SPECIALIX_DEBUG > 2
+	printk ("Freeing IRQ%d for board %d.\n", bp->irq, board_No (bp));
+#endif
+	free_irq(bp->irq, bp);
+
+	turn_ints_off (bp);
 
-	IRQ_to_board[bp->irq] = NULL;
-	
 	MOD_DEC_USE_COUNT;
 }
 
@@ -1045,12 +1078,14 @@
 		/* Page 48 of version 2.0 of the CL-CD1865 databook */
 		if (tmp >= 12) {
 			printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
-			        "Performance degradation is possible.\n",
+			        "Performance degradation is possible.\n"
+			        "Read specialix.txt for more info.\n",
 			        port_No (port), tmp);
 		} else {
 			printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
 			        "Warning: overstressing Cirrus chip. "
-                                "This might not work.\n", 
+			        "This might not work.\n"
+			        "Read specialix.txt for more info.\n", 
 			        port_No (port), tmp);
 		}
 	}
@@ -1516,8 +1551,7 @@
 		timeout = jiffies+HZ;
 		while(port->IER & IER_TXEMPTY) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + port->timeout;
-			schedule();
+			schedule_timeout(port->timeout);
 			if (jiffies > timeout) {
 				printk (KERN_INFO "Timeout waiting for close\n");
 				break;
@@ -1536,8 +1570,7 @@
 	if (port->blocked_open) {
 		if (port->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + port->close_delay;
-			schedule();
+			schedule_timeout(port->close_delay);
 		}
 		wake_up_interruptible(&port->open_wait);
 	}
@@ -2153,7 +2186,6 @@
 		return 1;
 	}
 	init_bh(SPECIALIX_BH, do_specialix_bh);
-	memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
 	memset(&specialix_driver, 0, sizeof(specialix_driver));
 	specialix_driver.magic = TTY_DRIVER_MAGIC;
 	specialix_driver.name = "ttyW";
@@ -2265,7 +2297,7 @@
 	int i;
 	int found = 0;
 
-	printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997.\n");
+	printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
 	printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
 #ifdef CONFIG_SPECIALIX_RTSCTS
 	printk (KERN_INFO "sx: DTR/RTS pin is always RTS.\n");
@@ -2280,6 +2312,35 @@
 		if (sx_board[i].base && !sx_probe(&sx_board[i]))
 			found++;
 
+#ifdef CONFIG_PCI
+	if (pci_present()) {
+		struct pci_dev *pdev = NULL;
+		unsigned int tint;
+
+		i=0;
+		while (i <= SX_NBOARD) {
+			if (sx_board[i].flags & SX_BOARD_PRESENT) {
+				i++;
+				continue;
+			}
+			pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
+			                        PCI_DEVICE_ID_SPECIALIX_IO8, 
+			                        pdev);
+			if (!pdev) break;
+
+			sx_board[i].irq = pdev->irq;
+
+			pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);
+			/* Mask out the fact that it's IO-space */
+			sx_board[i].base = tint & PCI_BASE_ADDRESS_IO_MASK; 
+
+			sx_board[i].flags |= SX_BOARD_IS_PCI;
+			if (!sx_probe(&sx_board[i]))
+				found ++;
+		}
+	}
+#endif
+
 	if (!found) {
 		sx_release_drivers();
 		printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
@@ -2296,7 +2357,8 @@
 
 /*
  * You can setup up to 4 boards.
- * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
+ * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter.
+ * You should specify the IRQs too in that case "irq=....,...". 
  * 
  * More than 4 boards in one computer is not possible, as the card can
  * only use 4 different interrupts. 
diff -u --recursive --new-file v2.1.126/linux/drivers/char/specialix_io8.h linux/drivers/char/specialix_io8.h
--- v2.1.126/linux/drivers/char/specialix_io8.h	Tue Mar 10 10:03:31 1998
+++ linux/drivers/char/specialix_io8.h	Wed Oct 28 22:04:05 1998
@@ -43,9 +43,16 @@
 
 #ifdef __KERNEL__
 
-#define SX_NBOARD		4
+/* You can have max 4 ISA cards in one PC, and I recommend not much 
+more than a few  PCI versions of the card. */
+
+#define SX_NBOARD		8
+
 /* NOTE: Specialix decoder recognizes 4 addresses, but only two are used.... */
 #define SX_IO_SPACE             4
+/* The PCI version decodes 8 addresses, but still only 2 are used. */
+#define SX_PCI_IO_SPACE         8
+
 /* eight ports per board. */
 #define SX_NPORT        	8
 #define SX_BOARD(line)		((line) / SX_NPORT)
@@ -93,6 +100,7 @@
 
 #define SX_BOARD_PRESENT	0x00000001
 #define SX_BOARD_ACTIVE		0x00000002
+#define SX_BOARD_IS_PCI		0x00000004
 
 
 struct specialix_port {
diff -u --recursive --new-file v2.1.126/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v2.1.126/linux/drivers/char/stallion.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/char/stallion.c	Thu Nov  5 09:58:43 1998
@@ -1072,8 +1072,7 @@
 #endif
 	if (len > 0) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + len;
-		schedule();
+		schedule_timeout(len);
 		current->state = TASK_RUNNING;
 	}
 }
diff -u --recursive --new-file v2.1.126/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v2.1.126/linux/drivers/char/tpqic02.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/char/tpqic02.c	Thu Nov  5 09:58:43 1998
@@ -588,9 +588,10 @@
 		/* not ready and no exception && timeout not expired yet */
 	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (jiffies<spin_t)) {
 		/* be `nice` to other processes on long operations... */
-		current->timeout = jiffies + 3*HZ/10;	/* nap 0.30 sec between checks, */
 		current->state = TASK_INTERRUPTIBLE;
-		schedule();		 /* but could be woken up earlier by signals... */
+		/* nap 0.30 sec between checks, */
+		/* but could be woken up earlier by signals... */
+		schedule_timeout(3*HZ/10);
 	}
 
 	/* don't use jiffies for this test because it may have changed by now */
diff -u --recursive --new-file v2.1.126/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.1.126/linux/drivers/char/tty_io.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/char/tty_io.c	Sat Oct 31 10:17:22 1998
@@ -1623,11 +1623,10 @@
 static int send_break(struct tty_struct *tty, int duration)
 {
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + duration;
 
 	tty->driver.break_ctl(tty, -1);
 	if (!signal_pending(current))
-		schedule();
+		schedule_timeout(duration);
 	tty->driver.break_ctl(tty, 0);
 	if (signal_pending(current))
 		return -EINTR;
@@ -2046,7 +2045,10 @@
 	return kmem_start;
 }
 
-static struct tty_driver dev_tty_driver, dev_syscons_driver, dev_ptmx_driver;
+static struct tty_driver dev_tty_driver, dev_syscons_driver;
+#ifdef CONFIG_UNIX98_PTYS
+static struct tty_driver dev_ptmx_driver;
+#endif
 #ifdef CONFIG_VT
 static struct tty_driver dev_console_driver;
 #endif
diff -u --recursive --new-file v2.1.126/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c
--- v2.1.126/linux/drivers/char/tty_ioctl.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/char/tty_ioctl.c	Sat Oct 31 10:17:22 1998
@@ -40,7 +40,7 @@
 #define TERMIOS_WAIT	2
 #define TERMIOS_TERMIO	4
 
-void tty_wait_until_sent(struct tty_struct * tty, int timeout)
+void tty_wait_until_sent(struct tty_struct * tty, long timeout)
 {
 	struct wait_queue wait = { current, NULL };
 
@@ -53,10 +53,8 @@
 		return;
 	add_wait_queue(&tty->write_wait, &wait);
 	current->counter = 0;	/* make us low-priority */
-	if (timeout)
-		current->timeout = timeout + jiffies;
-	else
-		current->timeout = (unsigned) -1;
+	if (!timeout)
+		timeout = MAX_SCHEDULE_TIMEOUT;
 	do {
 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
 		printk("waiting %s...(%d)\n", tty_name(tty, buf),
@@ -67,15 +65,10 @@
 			goto stop_waiting;
 		if (!tty->driver.chars_in_buffer(tty))
 			break;
-		schedule();
-	} while (current->timeout);
-	if (tty->driver.wait_until_sent) {
-		if (current->timeout == -1)
-			timeout = 0;
-		else
-			timeout = current->timeout - jiffies;
+		timeout = schedule_timeout(timeout);
+	} while (timeout);
+	if (tty->driver.wait_until_sent)
 		tty->driver.wait_until_sent(tty, timeout);
-	}
 stop_waiting:
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&tty->write_wait, &wait);
diff -u --recursive --new-file v2.1.126/linux/drivers/char/tuner.c linux/drivers/char/tuner.c
--- v2.1.126/linux/drivers/char/tuner.c	Wed Aug 26 11:37:37 1998
+++ linux/drivers/char/tuner.c	Sat Oct 31 10:17:22 1998
@@ -142,8 +142,7 @@
 	if (debug) {
 		UNLOCK_I2C_BUS(t->bus);
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + HZ/10;
-		schedule();
+		schedule_timeout(HZ/10);
 		LOCK_I2C_BUS(t->bus);
 		
 		if (tuner_islocked (t))
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/act2000/act2000_isa.c linux/drivers/isdn/act2000/act2000_isa.c
--- v2.1.126/linux/drivers/isdn/act2000/act2000_isa.c	Sun Jun  7 11:16:30 1998
+++ linux/drivers/isdn/act2000/act2000_isa.c	Thu Nov  5 09:58:43 1998
@@ -61,8 +61,7 @@
 {
         sti();
         current->state = TASK_INTERRUPTIBLE;
-        current->timeout = jiffies + t;
-        schedule();
+        schedule_timeout(t);
         sti();
 }
 
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/avmb1/b1capi.c linux/drivers/isdn/avmb1/b1capi.c
--- v2.1.126/linux/drivers/isdn/avmb1/b1capi.c	Wed Apr  1 20:11:49 1998
+++ linux/drivers/isdn/avmb1/b1capi.c	Thu Nov  5 09:58:43 1998
@@ -965,9 +965,8 @@
 
 		while (card->cardstate != CARD_RUNNING) {
 
-			current->timeout = jiffies + HZ / 10;	/* 0.1 sec */
 			current->state = TASK_INTERRUPTIBLE;
-			schedule();
+			schedule_timeout(HZ/10);	/* 0.1 sec */
 
 			if (signal_pending(current))
 				return -EINTR;
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/arcofi.c linux/drivers/isdn/hisax/arcofi.c
--- v2.1.126/linux/drivers/isdn/hisax/arcofi.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/arcofi.c	Thu Nov  5 09:58:43 1998
@@ -40,8 +40,7 @@
 	while (cnt && !test_bit(HW_MON1_TX_END, &cs->HW_Flags)) {
 		cnt--;
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + (10 * HZ) / 1000;	/* Timeout 10ms */
-		schedule();
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
 	}
 	restore_flags(flags);
 	sprintf(tmp, "arcofi tout %d", cnt);
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c
--- v2.1.126/linux/drivers/isdn/hisax/asuscom.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/asuscom.c	Thu Nov  5 09:58:43 1998
@@ -201,12 +201,10 @@
 	save_flags(flags);
 	sti();
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 1;
-	schedule();
+	schedule_timeout(1);
 	byteout(cs->hw.asus.adr, 0);	/* Reset Off */
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 1;
-	schedule();
+	schedule_timeout(1);
 	restore_flags(flags);
 }
 
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c
--- v2.1.126/linux/drivers/isdn/hisax/diva.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/diva.c	Thu Nov  5 09:58:43 1998
@@ -241,13 +241,11 @@
 	cs->hw.diva.ctrl_reg = 0;        /* Reset On */
 	byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + (10 * HZ) / 1000;	/* Timeout 10ms */
-	schedule();
+	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
 	cs->hw.diva.ctrl_reg |= DIVA_RESET;  /* Reset Off */
 	byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + (10 * HZ) / 1000;	/* Timeout 10ms */
-	schedule();
+	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
 	if (cs->subtyp == DIVA_ISA)
 		cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
 	else
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c
--- v2.1.126/linux/drivers/isdn/hisax/elsa.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/elsa.c	Thu Nov  5 09:58:44 1998
@@ -450,12 +450,10 @@
 		sti();
 		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + (10 * HZ) / 1000;	/* Timeout 10ms */
-		schedule();
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
 		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + (10 * HZ) / 1000;	/* Timeout 10ms */
-		schedule();
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
 		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
 		schedule();
 		restore_flags(flags);
@@ -658,8 +656,7 @@
 			} else
 				return(0);
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + (110 * HZ) / 1000;		/* Timeout 110ms */
-			schedule();
+			schedule_timeout((110*HZ)/1000);		/* Timeout 110ms */
 			restore_flags(flags);
 			cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
 			byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- v2.1.126/linux/drivers/isdn/hisax/isdnl1.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/isdnl1.c	Sat Oct 31 10:37:14 1998
@@ -639,8 +639,7 @@
 		sti();
 		current->state = TASK_INTERRUPTIBLE;
 		/* Timeout 10ms */
-		current->timeout = jiffies + (10 * HZ) / 1000;
-		schedule();
+		schedule_timeout((10 * HZ) / 1000);
 		restore_flags(flags);
 		printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
 			cs->irq, kstat_irqs(cs->irq));
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c
--- v2.1.126/linux/drivers/isdn/hisax/netjet.c	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/hisax/netjet.c	Thu Nov  5 09:58:44 1998
@@ -971,13 +971,11 @@
 	cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
 	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + (10 * HZ) / 1000;	/* Timeout 10ms */
-	schedule();
+	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
 	cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
 	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + (10 * HZ) / 1000;	/* Timeout 10ms */
-	schedule();
+	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
 	restore_flags(flags);
 	cs->hw.njet.auxd = 0;
 	cs->hw.njet.dmactrl = 0;
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c
--- v2.1.126/linux/drivers/isdn/hisax/sedlbauer.c	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/hisax/sedlbauer.c	Thu Nov  5 09:58:44 1998
@@ -242,12 +242,10 @@
 		save_flags(flags);
 		sti();
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 1;
-		schedule();
+		schedule_timeout(1);
 		byteout(cs->hw.sedl.reset_off, 0);	/* Reset Off */
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 1;
-		schedule();
+		schedule_timeout(1);
 		restore_flags(flags);
 	}
 }
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c
--- v2.1.126/linux/drivers/isdn/hisax/sportster.c	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/hisax/sportster.c	Thu Nov  5 09:58:44 1998
@@ -165,13 +165,11 @@
 	save_flags(flags);
 	sti();
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 1;
-	schedule();
+	schedule_timeout(1);
 	cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
 	byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 1;
-	schedule();
+	schedule_timeout(1);
 	restore_flags(flags);
 }
 
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c
--- v2.1.126/linux/drivers/isdn/hisax/teleint.c	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/hisax/teleint.c	Thu Nov  5 09:58:44 1998
@@ -246,13 +246,11 @@
 	save_flags(flags);
 	sti();
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 3;
-	schedule();
+	schedule_timeout(3);
 	cs->hw.hfc.cirm &= ~HFC_RESET;
 	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);	/* Reset Off */
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 1;
-	schedule();
+	schedule_timeout(1);
 	restore_flags(flags);
 }
 
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/teles3c.c linux/drivers/isdn/hisax/teles3c.c
--- v2.1.126/linux/drivers/isdn/hisax/teles3c.c	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/hisax/teles3c.c	Thu Nov  5 09:58:44 1998
@@ -79,13 +79,11 @@
 	save_flags(flags);
 	sti();
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 3;
-	schedule();
+	schedule_timeout(3);
 	cs->hw.hfcD.cirm = HFCD_MEM8K;
 	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);	/* Reset Off */
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 1;
-	schedule();
+	schedule_timeout(1);
 	cs->hw.hfcD.cirm |= HFCD_INTB;
 	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);	/* INT B */
 	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e);
@@ -136,8 +134,7 @@
 			save_flags(flags);
 			sti();
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + (80*HZ)/1000;
-			schedule();
+			schedule_timeout((80*HZ)/1000);
 			cs->hw.hfcD.ctmt |= HFCD_TIM800;
 			cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 
 			cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
--- v2.1.126/linux/drivers/isdn/icn/icn.c	Sun Jun  7 11:16:30 1998
+++ linux/drivers/isdn/icn/icn.c	Thu Nov  5 09:58:44 1998
@@ -914,8 +914,7 @@
 			printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
 #endif
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-			schedule();
+			schedule_timeout(ICN_BOOT_TIMEOUT1);
 		} else {
 #ifdef BOOT_DEBUG
 			printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
@@ -941,8 +940,7 @@
   printk(KERN_DEBUG "SLEEP(%d)\n",slsec); \
   while (slsec) { \
     current->state = TASK_INTERRUPTIBLE; \
-    current->timeout = jiffies + HZ; \
-    schedule(); \
+    schedule_timeout(HZ); \
     slsec--; \
   } \
 }
@@ -1104,8 +1102,7 @@
 				return -EIO;
 			}
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + 10;
-			schedule();
+			schedule_timeout(10);
 		}
 	}
 	writeb(0x20, &sbuf_n);
@@ -1129,8 +1126,7 @@
 			printk(KERN_DEBUG "Proto TO?\n");
 #endif
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-			schedule();
+			schedule_timeout(ICN_BOOT_TIMEOUT1);
 		} else {
 			if ((card->secondhalf) || (!card->doubleS0)) {
 #ifdef BOOT_DEBUG
@@ -1425,11 +1421,9 @@
 						if (!card->leased) {
 							card->leased = 1;
 							while (card->ptype == ISDN_PTYPE_UNKNOWN) {
-								current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-								schedule();
+								schedule_timeout(ICN_BOOT_TIMEOUT1);
 							}
-							current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-							schedule();
+							schedule_timeout(ICN_BOOT_TIMEOUT1);
 							sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",
 								(a & 1)?'1':'C', (a & 2)?'2':'C');
 							i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- v2.1.126/linux/drivers/isdn/isdn_tty.c	Wed Apr  1 20:11:51 1998
+++ linux/drivers/isdn/isdn_tty.c	Sat Oct 31 10:37:14 1998
@@ -1820,9 +1820,8 @@
 		timeout = jiffies + HZ;
 		while (!(info->lsr & UART_LSR_TEMT)) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + 20;
-			schedule();
-			if (jiffies > timeout)
+			schedule_timeout(20);
+			if (time_after(jiffies,timeout))
 				break;
 		}
 	}
@@ -1837,8 +1836,7 @@
 	tty->closing = 0;
 	if (info->blocked_open) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 50;
-		schedule();
+		schedule_timeout(50);
 		wake_up_interruptible(&info->open_wait);
 	}
 	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE |
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c
--- v2.1.126/linux/drivers/isdn/isdnloop/isdnloop.c	Sun Jun  7 11:16:30 1998
+++ linux/drivers/isdn/isdnloop/isdnloop.c	Sat Oct 31 10:37:14 1998
@@ -1179,11 +1179,9 @@
 						if (!card->leased) {
 							card->leased = 1;
 							while (card->ptype == ISDN_PTYPE_UNKNOWN) {
-								current->timeout = jiffies + 10;
-								schedule();
+								schedule_timeout(10);
 							}
-							current->timeout = jiffies + 10;
-							schedule();
+							schedule_timeout(10);
 							sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n");
 							i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
 							printk(KERN_INFO
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/sc/init.c linux/drivers/isdn/sc/init.c
--- v2.1.126/linux/drivers/isdn/sc/init.c	Wed Apr  1 20:11:52 1998
+++ linux/drivers/isdn/sc/init.c	Thu Nov  5 09:58:44 1998
@@ -165,8 +165,7 @@
 			pr_debug("Doing a SAFE probe reset\n");
 			outb(0xFF, io[b] + RESET_OFFSET);
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + milliseconds(10000);
-			schedule();
+			schedule_timeout(milliseconds(10000));
 		}
 		pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b],
 			ram[b] == 0 ? "will" : "won't");
@@ -514,8 +513,7 @@
 	 */
 	outb(PRI_BASEPG_VAL, pgport);
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + HZ;
-	schedule();
+	schedule_timeout(HZ);
 	sig = readl(rambase + SIG_OFFSET);
 	pr_debug("Looking for a signature, got 0x%x\n", sig);
 #if 0
@@ -535,8 +533,7 @@
 	 */
 	outb(BRI_BASEPG_VAL, pgport);
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + HZ;
-	schedule();
+	schedule_timeout(HZ);
 	sig = readl(rambase + SIG_OFFSET);
 	pr_debug("Looking for a signature, got 0x%x\n", sig);
 #if 0
@@ -571,8 +568,7 @@
 	x = 0;
 	while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 1;
-		schedule();
+		schedule_timeout(1);
 		x++;
 	}
 	if(x == 100) {
diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/sc/message.c linux/drivers/isdn/sc/message.c
--- v2.1.126/linux/drivers/isdn/sc/message.c	Wed Apr  1 20:11:52 1998
+++ linux/drivers/isdn/sc/message.c	Thu Nov  5 09:58:44 1998
@@ -267,8 +267,7 @@
 	/* wait for the response */
 	while (tries < timeout) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 1; 
-		schedule();
+		schedule_timeout(1);
 		
 		pr_debug("SAR waiting..\n");
 
diff -u --recursive --new-file v2.1.126/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.1.126/linux/drivers/macintosh/macserial.c	Thu Aug  6 14:06:32 1998
+++ linux/drivers/macintosh/macserial.c	Thu Nov  5 09:58:44 1998
@@ -1264,8 +1264,7 @@
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
+			schedule_timeout(info->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
@@ -1301,8 +1300,7 @@
 	while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
 		current->state = TASK_INTERRUPTIBLE;
 		current->counter = 0;	/* make us low-priority */
-		current->timeout = jiffies + char_time;
-		schedule();
+		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
 		if (timeout && ((orig_jiffies + timeout) < jiffies))
diff -u --recursive --new-file v2.1.126/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
--- v2.1.126/linux/drivers/macintosh/mediabay.c	Fri May  8 23:14:47 1998
+++ linux/drivers/macintosh/mediabay.c	Thu Nov  5 09:58:44 1998
@@ -184,8 +184,7 @@
 
 		prev = media_bay_id;
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 1;
-		schedule();
+		schedule_timeout(1);
 		if (signal_pending(current))
 			return 0;
 	}
diff -u --recursive --new-file v2.1.126/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c
--- v2.1.126/linux/drivers/misc/parport_ieee1284.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/misc/parport_ieee1284.c	Sat Oct 31 10:17:22 1998
@@ -34,8 +34,7 @@
 			schedule();
 	}
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies+4;
-	schedule();				/* wait for 40ms */
+	schedule_timeout(HZ/25);				/* wait for 40ms */
 	status = parport_read_status(port);
 	return ((status & mask) == result)?0:1;
 }		
diff -u --recursive --new-file v2.1.126/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.1.126/linux/drivers/misc/parport_pc.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/misc/parport_pc.c	Mon Oct 26 13:42:53 1998
@@ -7,6 +7,8 @@
  *          Andrea Arcangeli
  *
  * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
+ *
+ * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
  */
 
 /* This driver should work with any hardware that is broadly compatible
@@ -557,12 +559,12 @@
 static int irq_probe_ECP(struct parport *pb)
 {
 	int irqs, i;
-		
+
 	sti();
 	irqs = probe_irq_on();
 		
-	parport_pc_write_econtrol(pb, 0x00);    /* Reset FIFO */
-	parport_pc_write_econtrol(pb, 0xd0);    /* TEST FIFO + nErrIntrEn */
+	parport_pc_write_econtrol(pb, 0x00);	/* Reset FIFO */
+	parport_pc_write_econtrol(pb, 0xd0);	/* TEST FIFO + nErrIntrEn */
 
 	/* If Full FIFO sure that WriteIntrThresold is generated */
 	for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++) 
diff -u --recursive --new-file v2.1.126/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
--- v2.1.126/linux/drivers/misc/parport_procfs.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/misc/parport_procfs.c	Mon Oct 26 13:42:53 1998
@@ -8,16 +8,11 @@
  *
  * based on work by Grant Guenther <grant@torque.net>
  *              and Philip Blundell
+ *
+ * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
  */
 
-#include <linux/stddef.h>
-#include <linux/tasks.h>
-#include <linux/ctype.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-
+#include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
@@ -26,6 +21,11 @@
 #include <linux/malloc.h>
 #include <linux/proc_fs.h>
 #include <linux/parport.h>
+#include <linux/ctype.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
 
 struct proc_dir_entry *base = NULL;
 
diff -u --recursive --new-file v2.1.126/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- v2.1.126/linux/drivers/misc/parport_share.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/misc/parport_share.c	Tue Oct 27 10:32:29 1998
@@ -105,7 +105,7 @@
 	tmp->ops = ops;
 	tmp->number = portnum;
 	memset (&tmp->probe_info, 0, sizeof (struct parport_device_info));
-	spin_lock_init(&tmp->cad_lock);
+	tmp->cad_lock = RW_LOCK_UNLOCKED;
 	spin_lock_init(&tmp->waitlist_lock);
 	spin_lock_init(&tmp->pardevice_lock);
 
diff -u --recursive --new-file v2.1.126/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.1.126/linux/drivers/net/3c509.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/3c509.c	Mon Oct 26 13:45:22 1998
@@ -34,6 +34,7 @@
 		v1.10 4/21/97 Fixed module code so that multiple cards may be detected,
 				other cleanups.  -djb
 		Andrea Arcangeli:	Upgraded to Donald Becker's version 1.12.
+		Rick Payne:	Fixed SMP race condition
 */
 
 static char *version = "3c509.c:1.12 6/4/97 becker@cesdis.gsfc.nasa.gov\n";
@@ -59,6 +60,7 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>	/* for udelay() */
 
+#include <asm/spinlock.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 
@@ -122,6 +124,7 @@
 struct el3_private {
 	struct enet_statistics stats;
 	struct device *next_dev;
+	spinlock_t lock;
 	/* skb send-queue */
 	int head, size;
 	struct sk_buff *queue[SKB_QUEUE_SIZE];
@@ -401,6 +404,9 @@
 	outw(RxReset, ioaddr + EL3_CMD);
 	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
+	/* Set the spinlock before grabbing IRQ! */
+	((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+
 	if (request_irq(dev->irq, &el3_interrupt, 0, "3c509", dev)) {
 		return -EAGAIN;
 	}
@@ -520,6 +526,11 @@
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		printk("%s: Transmitter access conflict.\n", dev->name);
 	else {
+		unsigned long flags;
+
+	    	/* Spin on the lock, until we're clear of an IRQ */
+	    	spin_lock_irqsave(&lp->lock, flags);
+	    
 		/* Put out the doubleword header... */
 		outw(skb->len, ioaddr + TX_FIFO);
 		outw(0x00, ioaddr + TX_FIFO);
@@ -536,6 +547,8 @@
 		} else
 			/* Interrupt us when the FIFO has room for max-sized packet. */
 			outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+
+		spin_unlock_irqrestore(&lp->lock, flags);
 	}
 
 	dev_kfree_skb (skb);
@@ -560,6 +573,7 @@
 el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct device *dev = (struct device *)dev_id;
+	struct el3_private *lp;
 	int ioaddr, status;
 	int i = INTR_WORK;
 
@@ -568,6 +582,9 @@
 		return;
 	}
 
+	lp = (struct el3_private *)dev->priv;
+	spin_lock(&lp->lock);
+
 	if (dev->interrupt)
 		printk("%s: Re-entering the interrupt handler.\n", dev->name);
 	dev->interrupt = 1;
@@ -629,7 +646,7 @@
 		printk("%s: exiting interrupt, status %4.4x.\n", dev->name,
 			   inw(ioaddr + EL3_STATUS));
 	}
-
+	spin_unlock(&lp->lock);
 	dev->interrupt = 0;
 	return;
 }
diff -u --recursive --new-file v2.1.126/linux/drivers/net/bmac.c linux/drivers/net/bmac.c
--- v2.1.126/linux/drivers/net/bmac.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/net/bmac.c	Tue Oct 27 09:57:19 1998
@@ -17,6 +17,7 @@
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/feature.h>
 #include "bmac.h"
 
 #define trunc_page(x)	((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
@@ -30,15 +31,6 @@
 /* switch to use multicast code lifted from sunhme driver */
 #define SUNHME_MULTICAST
 
-/* a bunch of constants for the "Heathrow" interrupt controller.
-   These really should be in an include file somewhere */
-#define IoBaseHeathrow ((unsigned *)0xf3000000)
-#define HeathrowFCR 0x0038	/* FCR offset from Heathrow Base Address */
-#define fcrEnetEnabledBits	0x60000000 /* mask to enable Enet Xcvr/Controller */
-#define fcrResetEnetCell	0x80000000 /* mask used to reset Enet cell */
-#define fcrClearResetEnetCell	0x7fffffff /* mask used to clear reset Enet cell */
-#define fcrDisableEnet		0x1fffffff /* mask to disable Enet Xcvr/Controller */
-
 #define N_RX_RING	64
 #define N_TX_RING	32
 #define MAX_TX_ACTIVE	1
@@ -122,6 +114,7 @@
 };
 
 struct device *bmac_devs = NULL;
+static int is_bmac_plus;
 
 #if 0
 /*
@@ -157,8 +150,6 @@
 static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
 static void bmac_set_timeout(struct device *dev);
 static void bmac_tx_timeout(unsigned long data);
-static void bmac_reset_chip(struct device *dev);
-static void bmac_init_registers(struct device *dev);
 static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy);
 static int bmac_output(struct sk_buff *skb, struct device *dev);
 static void bmac_start(struct device *dev);
@@ -240,34 +231,86 @@
 	struct bmac_data *bp = (struct bmac_data *) dev->priv;
 	volatile struct dbdma_regs *rd = bp->rx_dma;
 	volatile struct dbdma_regs *td = bp->tx_dma;
-	volatile unsigned *heathrowFCR;
-	unsigned int fcrValue;
 	 
 	dbdma_reset(rd);
 	dbdma_reset(td);
 
-	heathrowFCR = (unsigned *)((unsigned char *)IoBaseHeathrow + HeathrowFCR);
+	feature_set(FEATURE_BMac_IO_enable);
+	udelay(10000);
+	feature_set(FEATURE_BMac_reset);
+	udelay(10000);
+	feature_clear(FEATURE_BMac_reset);
+	udelay(10000);
+}
 
-	fcrValue = in_le32(heathrowFCR);
+#define MIFDELAY	udelay(500)
 
-	fcrValue &= fcrDisableEnet;	/* clear out Xvr and Controller Bit */
-	out_le32(heathrowFCR, fcrValue);
-	udelay(50000);
+static unsigned int
+bmac_mif_readbits(struct device *dev, int nb)
+{
+	unsigned int val = 0;
 
-	fcrValue |= fcrResetEnetCell;	/* set bit to reset them */
-	out_le32(heathrowFCR, fcrValue);
-	udelay(50000);
-	
-	fcrValue &= fcrDisableEnet;
-	out_le32(heathrowFCR, fcrValue);
-	udelay(50000);
-
-	fcrValue |= fcrEnetEnabledBits;
-	out_le32(heathrowFCR, fcrValue);
-	udelay(50000);
-	
-	out_le32(heathrowFCR, fcrValue);
-	udelay(50000);
+	while (--nb >= 0) {
+		bmwrite(dev, MIFCSR, 0);
+		MIFDELAY;
+		if (bmread(dev, MIFCSR) & 8)
+			val |= 1 << nb;
+		bmwrite(dev, MIFCSR, 1);
+		MIFDELAY;
+	}
+	bmwrite(dev, MIFCSR, 0);
+	MIFDELAY;
+	bmwrite(dev, MIFCSR, 1);
+	MIFDELAY;
+	return val;
+}
+
+static void
+bmac_mif_writebits(struct device *dev, unsigned int val, int nb)
+{
+	int b;
+
+	while (--nb >= 0) {
+		b = (val & (1 << nb))? 6: 4;
+		bmwrite(dev, MIFCSR, b);
+		MIFDELAY;
+		bmwrite(dev, MIFCSR, b|1);
+		MIFDELAY;
+	}
+}
+
+static unsigned int
+bmac_mif_read(struct device *dev, unsigned int addr)
+{
+	unsigned int val;
+
+	bmwrite(dev, MIFCSR, 4);
+	MIFDELAY;
+	bmac_mif_writebits(dev, ~0U, 32);
+	bmac_mif_writebits(dev, 6, 4);
+	bmac_mif_writebits(dev, addr, 10);
+	bmwrite(dev, MIFCSR, 2);
+	MIFDELAY;
+	bmwrite(dev, MIFCSR, 1);
+	MIFDELAY;
+	val = bmac_mif_readbits(dev, 17);
+	bmwrite(dev, MIFCSR, 4);
+	MIFDELAY;
+	printk(KERN_DEBUG "bmac_mif_read(%x) -> %x\n", addr, val);
+	return val;
+}
+
+static void
+bmac_mif_write(struct device *dev, unsigned int addr, unsigned int val)
+{
+	bmwrite(dev, MIFCSR, 4);
+	MIFDELAY;
+	bmac_mif_writebits(dev, ~0U, 32);
+	bmac_mif_writebits(dev, 5, 4);
+	bmac_mif_writebits(dev, addr, 10);
+	bmac_mif_writebits(dev, 2, 2);
+	bmac_mif_writebits(dev, val, 16);
+	bmac_mif_writebits(dev, 3, 2);
 }
 
 static void
@@ -280,14 +323,23 @@
 
 	/* XXDEBUG(("bmac: enter init_registers\n")); */
 
+	bmwrite(dev, RXRST, RxResetValue);
 	bmwrite(dev, TXRST, TxResetBit);
 
+	i = 100;
 	do {
+		--i;
+		udelay(10000);
 		regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
-	} while (regValue & TxResetBit);
+	} while ((regValue & TxResetBit) && i > 0);
+
+	if (!is_bmac_plus) {
+		regValue = bmread(dev, XCVRIF);
+		regValue |= ClkBit | SerialMode | COLActiveLow;
+		bmwrite(dev, XCVRIF, regValue);
+		udelay(10000);
+	}
 
-	bmwrite(dev, RXRST, RxResetValue);
-	bmwrite(dev, XCVRIF, ClkBit | SerialMode | COLActiveLow);	
 	bmwrite(dev, RSEED, (unsigned short)0x1968);		
 
 	regValue = bmread(dev, XIFC);
@@ -366,18 +418,30 @@
 
 	/* enable rx dma channel */
 	dbdma_continue(rd);
+ 
+	oldConfig = bmread(dev, TXCFG);		
+	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
   
 	/* turn on rx plus any other bits already on (promiscuous possibly) */
 	oldConfig = bmread(dev, RXCFG);		
 	bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 
- 
-	oldConfig = bmread(dev, TXCFG);		
-	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
+	udelay(20000);
 }
 
 static int
 bmac_init_chip(struct device *dev)
 {
+	if (is_bmac_plus && bmac_mif_read(dev, 2) == 0x7810) {
+		if (bmac_mif_read(dev, 4) == 0xa1) {
+			bmac_mif_write(dev, 0, 0x1000);
+		} else {
+			bmac_mif_write(dev, 4, 0xa1);
+			bmac_mif_write(dev, 0, 0x1200);
+		}
+		/* XXX debugging */
+		bmac_mif_read(dev, 0);
+		bmac_mif_read(dev, 4);
+	}
 	bmac_init_registers(dev);
 	return 1;
 }
@@ -1144,8 +1208,16 @@
 	unsigned char *addr;
 	static struct device_node *all_bmacs = NULL, *next_bmac;
 
-	if (all_bmacs == NULL)
-		all_bmacs = next_bmac = find_devices("bmac");
+	if (all_bmacs == NULL) {
+		all_bmacs = find_devices("bmac");
+		is_bmac_plus = 0;
+		if (all_bmacs == NULL) {
+			all_bmacs = find_compatible_devices("network", "bmac+");
+			if (all_bmacs)
+				is_bmac_plus = 1;
+		}
+		next_bmac = all_bmacs;
+	}
 	bmacs = next_bmac;
 	if (bmacs == NULL) return -ENODEV;
 	next_bmac = bmacs->next;
@@ -1157,7 +1229,7 @@
 		       bmacs->full_name);
 		return -EINVAL;
 	}
-    
+
 	if (dev == NULL) {
 		dev = init_etherdev(NULL, PRIV_BYTES);
 		bmac_devs = dev;  /*KLUDGE!!*/
diff -u --recursive --new-file v2.1.126/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.1.126/linux/drivers/net/cs89x0.c	Mon Feb 23 18:12:05 1998
+++ linux/drivers/net/cs89x0.c	Thu Nov  5 09:58:44 1998
@@ -403,8 +403,7 @@
 
 	/* wait 30 ms */
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 3;
-	schedule();
+	schedule_timeout(30*HZ/1000);
 
 	if (lp->chip_type != CS8900) {
 		/* Hardware problem requires PNP registers to be reconfigured after a reset */
diff -u --recursive --new-file v2.1.126/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.1.126/linux/drivers/net/de4x5.c	Fri Oct  9 13:27:09 1998
+++ linux/drivers/net/de4x5.c	Sat Oct 24 09:23:14 1998
@@ -972,7 +972,7 @@
 static void    srom_repair(struct device *dev, int card);
 static int     test_bad_enet(struct device *dev, int status);
 static int     an_exception(struct bus_type *lp);
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
 static void    eisa_probe(struct device *dev, u_long iobase);
 #endif
 static void    pci_probe(struct device *dev, u_long iobase);
@@ -1021,7 +1021,7 @@
 #endif /* MODULE */
 
 static char name[DE4X5_NAME_LENGTH + 1];
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
 static int lastEISA = 0;
 #else
@@ -1095,7 +1095,7 @@
 {
     u_long iobase = dev->base_addr;
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
     eisa_probe(dev, iobase);
 #endif
     if (lastEISA == MAX_EISA_SLOTS) {
@@ -2028,7 +2028,7 @@
     return;
 }
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
 /*
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
@@ -2096,7 +2096,7 @@
 
     return;
 }
-#endif                         /* !(__sparc_v9__) && !(__powerpc__) */
+#endif          /* !(__sparc_v9__) && !(__powerpc__) && !defined(__alpha__) */
 
 /*
 ** PCI bus I/O device probe
@@ -5826,7 +5826,7 @@
     u_int class = DE4X5_CLASS_CODE;
     u_int device;
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
     char name[DE4X5_STRLEN];
     u_long iobase = 0x1000;
 
diff -u --recursive --new-file v2.1.126/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.1.126/linux/drivers/net/eepro100.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/eepro100.c	Sat Oct 24 08:53:15 1998
@@ -1384,7 +1384,7 @@
 		data[3] = mdio_read(ioaddr, data[0], data[1]);
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!suser())
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		mdio_write(ioaddr, data[0], data[1], data[2]);
 		return 0;
diff -u --recursive --new-file v2.1.126/linux/drivers/net/ne2.c linux/drivers/net/ne2.c
--- v2.1.126/linux/drivers/net/ne2.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/ne2.c	Mon Oct 26 09:57:56 1998
@@ -55,7 +55,6 @@
 "ne2.c:v0.90 Oct 14 1998 David Weinehall <tao@acc.umu.se>\n";
 
 #include <linux/module.h>
-#include <linux/config.h>
 #include <linux/version.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.126/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.1.126/linux/drivers/net/ppp.c	Fri Oct  9 13:27:09 1998
+++ linux/drivers/net/ppp.c	Sat Oct 31 10:17:23 1998
@@ -507,7 +507,6 @@
 		if (file->f_flags & O_NONBLOCK)
 			break;
 
-		current->timeout = 0;
 		interruptible_sleep_on(&ppp->read_wait);
 		err = -EINTR;
 		if (signal_pending(current))
diff -u --recursive --new-file v2.1.126/linux/drivers/net/sktr.c linux/drivers/net/sktr.c
--- v2.1.126/linux/drivers/net/sktr.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/sktr.c	Thu Nov  5 09:58:44 1998
@@ -1526,12 +1526,11 @@
 {
 	long tmp;
 
-	tmp = jiffies + time/(1000000/HZ);
+	tmp = time/(1000000/HZ);
 	do {
-		current->timeout	= tmp;
 		current->state 		= TASK_INTERRUPTIBLE;
-		schedule();
-	} while(tmp > jiffies);
+		tmp = schedule_timeout(tmp);
+	} while(tmp);
 
 	return;
 }
diff -u --recursive --new-file v2.1.126/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.1.126/linux/drivers/net/tlan.c	Tue Aug 18 22:02:04 1998
+++ linux/drivers/net/tlan.c	Mon Nov  2 09:11:58 1998
@@ -25,6 +25,11 @@
  *		Microchip Technology, 24C01A/02A/04A Data Sheet
  *			available in PDF format from www.microchip.com
  *
+ * Change History
+ *
+ *	Tigran Aivazian <tigran@sco.com>:	TLan_PciProbe() now uses
+ *						new PCI BIOS interface.
+ *
  ********************************************************************/
 
 
@@ -32,7 +37,6 @@
 
 #include "tlan.h"
 
-#include <linux/bios32.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
@@ -152,7 +156,7 @@
 };
 
 
-static int	TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * );
+static int	TLan_PciProbe( u8 *, u8 *, u8 *, u32 *, u32 * );
 static int	TLan_Init( struct device * );
 static int	TLan_Open(struct device *dev);
 static int	TLan_StartTx(struct sk_buff *, struct device *);
@@ -269,7 +273,6 @@
 extern int init_module(void)
 {
 	TLanPrivateInfo	*priv;
-	u8		bus;
 	struct device	*dev;
 	size_t		dev_size;
 	u8		dfn;
@@ -296,7 +299,7 @@
 
 	dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo);
 
-	while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index ) ) ) {
+	while ( ( found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index ) ) ) {
 		dev = (struct device *) kmalloc( dev_size, GFP_KERNEL );
 		if ( dev == NULL ) {
 			printk( "TLAN:  Could not allocate memory for device.\n" );
@@ -417,10 +420,10 @@
 	TLanPrivateInfo	*priv;
 	static int	pad_allocated = 0;
 	int		found;
-	u8		bus, dfn, irq, rev;
+	u8		dfn, irq, rev;
 	u32		io_base, index;
 
-	found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index );
+	found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index );
 
 	if ( ! found ) {
 		return -ENODEV;
@@ -502,8 +505,6 @@
 	 *	Returns:
 	 *		1 if another TLAN card was found, 0 if not.
 	 *	Parms:
-	 *		pci_bus		The PCI bus the card was found
-	 *				on.
 	 *		pci_dfn		The PCI whatever the card was
 	 *				found at.
 	 *		pci_irq		The IRQ of the found adapter.
@@ -522,33 +523,26 @@
 	 *
 	 **************************************************************/
 
-int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
+int TLan_PciProbe(u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
 {
 	static int dl_index = 0;
-	static int pci_index = 0;
-
-	int	not_found;
-	u8	pci_latency;
+	static struct pci_dev * pdev = NULL;
 	u16	pci_command;
 	int	reg;
 
 
-	if ( ! pcibios_present() ) {
+	if ( ! pci_present() ) {
 		printk( "TLAN:   PCI Bios not present.\n" );
 		return 0;
 	}
 
 	for (; TLanAdapterList[dl_index].vendorId != 0; dl_index++) {
 
-		not_found = pcibios_find_device(
+		pdev = pci_find_device(
 			TLanAdapterList[dl_index].vendorId,
-			TLanAdapterList[dl_index].deviceId,
-			pci_index,
-			pci_bus,
-			pci_dfn
-		);
+			TLanAdapterList[dl_index].deviceId, pdev);
 
-		if ( ! not_found ) {
+		if ( pdev ) {
 
 			TLAN_DBG(
 				TLAN_DEBUG_GNRL,
@@ -557,19 +551,14 @@
 				TLanAdapterList[dl_index].deviceId
 			);
 
-			pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_REVISION_ID, pci_rev);
-			pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_INTERRUPT_LINE, pci_irq);
-			pcibios_read_config_word ( *pci_bus,  *pci_dfn, PCI_COMMAND, &pci_command);
-			pcibios_read_config_dword( *pci_bus,  *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_base);
-			pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_LATENCY_TIMER, &pci_latency);
-
-			if (pci_latency < 0x10) {
-				pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff);
-				TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    Setting latency timer to max.\n");
-			}
+			*pci_irq = pdev->irq;
+			*pci_io_base = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+			*pci_dfn = pdev->devfn;
+			pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev);
+			pci_read_config_word ( pdev,  PCI_COMMAND, &pci_command);
 
 			for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg +=4 ) {
-				pcibios_read_config_dword( *pci_bus, *pci_dfn, reg, pci_io_base);
+				pci_read_config_dword( pdev, reg, pci_io_base);
 				if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) {
 					*pci_io_base &= PCI_BASE_ADDRESS_IO_MASK;
 					TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    IO mapping is available at %x.\n", *pci_io_base);
@@ -582,12 +571,7 @@
 			if ( *pci_io_base == 0 )
 				printk("TLAN:    IO mapping not available, ignoring device.\n");
 
-			if ( ! ( pci_command & PCI_COMMAND_MASTER ) ) {
-				pcibios_write_config_word ( *pci_bus,  *pci_dfn, PCI_COMMAND, pci_command | PCI_COMMAND_MASTER );
-				printk( "TLAN:  Activating PCI bus mastering for this device.\n" );
-			}
-
-			pci_index++;
+			pci_set_master(pdev);
 
 			if ( *pci_io_base ) {
 				*dl_ix = dl_index;
@@ -595,7 +579,7 @@
 			}
 
 		} else {
-			pci_index = 0;
+			pdev = NULL;
 		}
 	}
 
diff -u --recursive --new-file v2.1.126/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.1.126/linux/drivers/pci/oldproc.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/pci/oldproc.c	Wed Oct 28 22:04:05 1998
@@ -400,6 +400,7 @@
 	DEVICE( LITEON,		LITEON_LNE100TX,"LNE100TX"),
 	DEVICE( NP,		NP_PCI_FDDI,	"NP-PCI"),       
 	DEVICE( ATT,		ATT_L56XMF,	"L56xMF"),
+	DEVICE( SPECIALIX,	SPECIALIX_IO8,	"IO8+/PCI"),
 	DEVICE( SPECIALIX,	SPECIALIX_XIO,	"XIO/SIO host"),
 	DEVICE( SPECIALIX,	SPECIALIX_RIO,	"RIO host"),
 	DEVICE( AURAVISION,	AURAVISION_VXP524,"VXP524"),
diff -u --recursive --new-file v2.1.126/linux/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c
--- v2.1.126/linux/drivers/pnp/parport_probe.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/pnp/parport_probe.c	Thu Nov  5 21:25:24 1998
@@ -76,7 +76,7 @@
 			Byte |= (z<<4);
 			if (temp) 
 				*(temp++) = Byte; 
-			if (count++ == length)
+			if (++count == length)
 				temp = NULL;
 			/* Does the error line indicate end of data? */
 			if ((parport_read_status(port) & LP_PERRORP) == 
@@ -105,9 +105,8 @@
 	switch (parport_ieee1284_nibble_mode_ok(port, 4)) {
 	case 1:
 		current->state=TASK_INTERRUPTIBLE;
-		current->timeout=jiffies+1;
-		schedule();	/* HACK: wait 10ms because printer seems to
-				 * ack wrong */
+		/* HACK: wait 10ms because printer seems to ack wrong */
+		schedule_timeout((HZ+99)/100);	
 		result = read_polled(port, buffer, len);
 		break;
 	case 0:
diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.1.126/linux/drivers/sbus/char/pcikbd.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/pcikbd.c	Thu Nov  5 09:58:44 1998
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.22 1998/09/21 05:06:45 jj Exp $
+/* $Id: pcikbd.c,v 1.23 1998/10/07 11:35:24 jj Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -36,13 +36,6 @@
 #else
 #define PCI_KB_NAME	"keyboard"
 #define PCI_MS_NAME	"mouse"
-/*
- * XXX.
- * Gleb defines check_region and request_region here.
- * This looks suspicios because he neglects to call
- * sparc_alloc_io, but the conflict with sparc_alloc_io is what
- * causes problems.
- */
 #endif
 
 #include "pcikbd.h"
@@ -517,7 +510,7 @@
 			for_each_ebusdev(edev, ebus) {
 				if(!strcmp(edev->prom_name, "8042")) {
 					for_each_edevchild(edev, child) {
-						if (!strcmp(child->prom_name, "kb_ps2"))
+                                                if (!strcmp(child->prom_name, PCI_KB_NAME))
 							goto found;
 					}
 				}
@@ -698,8 +691,7 @@
 		    == AUX_STAT_OBF)
 			pcimouse_inb(pcimouse_iobase + KBD_DATA_REG);
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + (5*HZ + 99) / 100;
-		schedule();
+		schedule_timeout((5*HZ + 99)/100);
 		retries++;
 	}
 	return (retries < MAX_RETRIES);
diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.1.126/linux/drivers/sbus/char/sab82532.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/sab82532.c	Thu Nov  5 09:58:44 1998
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.23 1998/09/16 03:20:25 ecd Exp $
+/* $Id: sab82532.c,v 1.26 1998/10/25 06:46:41 ecd Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -88,6 +88,7 @@
 	"V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)",
 	"V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)"
 };
+static char serial_version[16];
 
 /*
  * tmp_buf is used as a temporary buffer by sab82532_write.  We need to
@@ -505,7 +506,7 @@
 #endif
 	}
 	if ((info->regs->r.pvr & info->pvr_dsr_bit) ^ info->dsr) {
-		info->dsr = info->regs->r.pvr & info->pvr_dsr_bit;
+		info->dsr = (info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : 1;
 		info->icount.dsr++;
 		modem_change++;
 #if 0
@@ -786,6 +787,12 @@
 	 */
 	sab82532_init_line(info);
 
+	if (info->tty->termios->c_cflag & CBAUD) {
+		info->regs->rw.mode &= ~(SAB82532_MODE_FRTS);
+		info->regs->rw.mode |= SAB82532_MODE_RTS;
+		info->regs->rw.pvr &= ~(info->pvr_dtr_bit);
+	}
+
 	/*
 	 * Finally, enable interrupts
 	 */
@@ -951,8 +958,9 @@
 	ebrg = ebrg_table[i].n;
 	ebrg |= (ebrg_table[i].m << 6);
 
-	if (ebrg_table[i].baud)
-		info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud;
+	info->baud = ebrg_table[i].baud;
+	if (info->baud)
+		info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
 	else
 		info->timeout = 0;
 	info->timeout += HZ / 50;		/* Add .02 seconds of slop */
@@ -1278,7 +1286,9 @@
 {
 	unsigned int result;
 
-	result =  ((info->regs->r.mode & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS)
+	result =  ((info->regs->r.mode & SAB82532_MODE_RTS) ? 
+		    ((info->regs->r.mode & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS)
+							    : TIOCM_RTS)
 		| ((info->regs->r.pvr & info->pvr_dtr_bit) ? 0 : TIOCM_DTR)
 		| ((info->regs->r.vstr & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR)
 		| ((info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : TIOCM_DSR)
@@ -1619,8 +1629,7 @@
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
+			schedule_timeout(info->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
@@ -1664,8 +1673,7 @@
 	while (info->xmit_cnt || !info->all_sent) {
 		current->state = TASK_INTERRUPTIBLE;
 		current->counter = 0;
-		current->timeout = jiffies + char_time;
-		schedule();
+		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
 		if (timeout && (orig_jiffies + timeout) < jiffies)
@@ -1952,9 +1960,11 @@
  * /proc fs routines....
  */
 
-static int inline line_info(char *buf, struct tty_struct *tty)
+static __inline__ int
+line_info(char *buf, struct sab82532 *info)
 {
-	struct sab82532 *info = (struct sab82532 *)tty->driver_data;
+	unsigned long flags;
+	char stat_buf[30];
 	int ret;
 
 	ret = sprintf(buf, "%d: uart:SAB82532 ", info->line);
@@ -1972,8 +1982,8 @@
 			ret += sprintf(buf+ret, "V?.? ");
 			break;
 	}
-	ret += sprintf(buf+ret, "port:%lX irq:%d",
-		       (unsigned long)info->regs, info->irq);
+	ret += sprintf(buf+ret, "port:%lX irq:%s",
+		       (unsigned long)info->regs, __irq_itoa(info->irq));
 
 	if (!info->regs) {
 		ret += sprintf(buf+ret, "\n");
@@ -1983,20 +1993,57 @@
 	/*
 	 * Figure out the current RS-232 lines
 	 */
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	save_flags(flags); cli();
+	if (info->regs->r.mode & SAB82532_MODE_RTS) {
+		if (!(info->regs->r.mode & SAB82532_MODE_FRTS))
+			strcat(stat_buf, "|RTS");
+	} else {
+		strcat(stat_buf, "|RTS");
+	}
+	if (info->regs->r.star & SAB82532_STAR_CTS)
+		strcat(stat_buf, "|CTS");
+	if (!(info->regs->r.pvr & info->pvr_dtr_bit))
+		strcat(stat_buf, "|DTR");
+	if (!(info->regs->r.pvr & info->pvr_dsr_bit))
+		strcat(stat_buf, "|DSR");
+	if (!(info->regs->r.vstr & SAB82532_VSTR_CD))
+		strcat(stat_buf, "|CD");
+	restore_flags(flags);
+
+	if (info->baud)
+		ret += sprintf(buf+ret, " baud:%d", info->baud);
+
+	if (info->icount.frame)
+		ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+
+	if (info->icount.parity)
+		ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+
+	if (info->icount.brk)
+		ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
 
-	ret += sprintf(buf+ret, "\n");
+	if (info->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+
+	/*
+	 * Last thing is the RS-232 status lines.
+	 */
+	ret += sprintf(buf+ret, " %s\n", stat_buf + 1);
 	return ret;
 }
 
 int sab82532_read_proc(char *page, char **start, off_t off, int count,
 		       int *eof, void *data)
 {
-	int i, len = 0;
-	off_t	begin = 0;
-
-	len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.23 $");
-	for (i = 0; i < NR_PORTS && len < 4000; i++) {
-		len += line_info(page + len, sab82532_table[i]);
+	struct sab82532 *info = sab82532_chain;
+	off_t begin = 0;
+	int len = 0;
+
+	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+	for (info = sab82532_chain; info && len < 4000; info = info->next) {
+		len += line_info(page + len, info);
 		if (len+begin > off+count)
 			goto done;
 		if (len+begin < off) {
@@ -2089,13 +2136,14 @@
 
 __initfunc(static inline void show_serial_version(void))
 {
-	char *revision = "$Revision: 1.23 $";
+	char *revision = "$Revision: 1.26 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
-	p = strchr(++version, ' ');
+	strcpy(serial_version, ++version);
+	p = strchr(serial_version, ' ');
 	*p = '\0';
-	printk("SAB82532 serial driver version %s\n", version);
+	printk("SAB82532 serial driver version %s\n", serial_version);
 }
 
 /*
@@ -2456,8 +2504,9 @@
 	ebrg = ebrg_table[i].n;
 	ebrg |= (ebrg_table[i].m << 6);
 
-	if (ebrg_table[i].baud)
-		info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud;
+	info->baud = ebrg_table[i].baud;
+	if (info->baud)
+		info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
 	else
 		info->timeout = 0;
 	info->timeout += HZ / 50;		/* Add .02 seconds of slop */
@@ -2490,6 +2539,7 @@
 		info->regs->rw.mode &= ~(SAB82532_MODE_FRTS);
 		info->regs->rw.mode |= SAB82532_MODE_FCTS;
 	}
+	info->regs->rw.pvr &= ~(info->pvr_dtr_bit);
 	info->regs->rw.mode |= SAB82532_MODE_RAC;
 	restore_flags(flags);
 
diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.1.126/linux/drivers/sbus/char/su.c	Thu Aug  6 14:06:32 1998
+++ linux/drivers/sbus/char/su.c	Thu Nov  5 09:58:44 1998
@@ -1,69 +1,164 @@
-/* $Id: su.c,v 1.10 1998/05/29 06:00:26 ecd Exp $
- * su.c: Small serial driver for keyboard/mouse interface on Ultra/AX
+/* $Id: su.c,v 1.12 1998/10/25 04:24:52 ecd Exp $
+ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ * Coypright (C) 1998  Pete Zaitcev   (zaitcev@metabyte.com)
  *
- * This is mainly a very stripped down version of drivers/char/serial.c,
+ * This is mainly a variation of drivers/char/serial.c,
  * credits go to authors mentioned therein.
  */
 
+/*
+ * Configuration section.
+ */
+#define SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO	/* Unused on sparc */
+#define SERIAL_DO_RESTART
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+#undef SERIAL_DEBUG_THROTTLE
+
+#define RS_ISR_PASS_LIMIT 256
+
+/*
+ * 0x20 is sun4m thing, Dave Redman heritage.
+ * See arch/sparc/kernel/irq.c.
+ */
+#define IRQ_4M(n)	((n)|0x20)
+
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s)							\
+do {									\
+	printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n",		\
+	       kdevname(tty->device), (info->flags), serial_refcount,	\
+	       info->count,tty->count,s);				\
+} while (0);
+#else
+#define DBG_CNT(s)
+#endif
+
+/*
+ * End of serial driver configuration section.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 #include <linux/string.h>
+#include <linux/fcntl.h>
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
+#include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
+#include <linux/delay.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#include <linux/major.h>
+#endif
+#include <linux/sysrq.h>
 
+#include <asm/system.h>
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/ebus.h>
 #include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
 
 #include "sunserial.h"
 #include "sunkbd.h"
 #include "sunmouse.h"
 
-static char *serial_name = "kbd/mouse serial driver";
-static char *serial_version = "1.0";
-
-/* Set of debugging defines */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-
 /* We are on a NS PC87303 clocked with 24.0 MHz, which results
  * in a UART clock of 1.8462 MHz.
  */
 #define BAUD_BASE	(1846200 / 16)
 
+#ifdef CONFIG_SERIAL_CONSOLE
+extern int serial_console;
+static struct console sercons;
+int su_serial_console_init(void);
+#endif
+
+/*
+ * serial.c saves memory when it allocates async_info upon first open.
+ * We have parts of state structure together because we do call startup
+ * for keyboard and mouse.
+ */
 struct su_struct {
 	int		 magic;
 	unsigned long	 port;
 	int		 baud_base;
-	int		 type;
+	int		 type;		/* Hardware type: e.g. 16550 */
 	int		 irq;
 	int		 flags;
-	unsigned char	 IER;
-	unsigned char	 MCR;
 	int		 line;
 	int		 cflag;
+
 	int		 kbd_node;
 	int		 ms_node;
+	int		 port_node;
+
 	char		 name[16];
-};
 
-static struct su_struct su_table[] = {
-	{ 0, 0, BAUD_BASE, PORT_UNKNOWN },
-	{ 0, 0, BAUD_BASE, PORT_UNKNOWN }
+	int		 xmit_fifo_size;
+	int		 custom_divisor;
+	unsigned short	 close_delay;
+	unsigned short	 closing_wait;	/* time to wait before closing */
+
+	struct tty_struct 	*tty;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			timeout;
+	int			quot;
+	int			x_char;	/* xon/xoff character */
+	int			IER; 	/* Interrupt Enable Register */
+	int			MCR; 	/* Modem control register */
+	unsigned long		event;
+	int			blocked_open; /* # of blocked opens */
+	long			session; /* Session of opening process */
+	long			pgrp; /* pgrp of opening process */
+	unsigned char 		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct tq_struct	tqueue;
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+	struct wait_queue	*delta_msr_wait;
+
+	int			count;
+	struct async_icount	icount;
+	struct termios		normal_termios, callout_termios;
+	unsigned long		last_active;	/* For async_struct, to be */
 };
 
-#define NR_PORTS (sizeof(su_table) / sizeof(struct su_struct))
+static char *serial_name = "PCIO serial driver";
+static char *serial_version = "1.1";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
 
-static void autoconfig(struct su_struct * info);
+static void autoconfig(struct su_struct *info);
 static void change_speed(struct su_struct *info);
+static void su_wait_until_sent(struct tty_struct *tty, int timeout);
 
 /*
  * Here we define the default xmit fifo size used for each type of
@@ -83,12 +178,52 @@
 	{ 0, 0}
 };
 
+
+#define NR_PORTS	4
+
+static struct su_struct su_table[NR_PORTS];
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
 /*
- * This is used to figure out the divisor speeds and the timeouts
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
  */
-static int baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+static unsigned char *tmp_buf;
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct su_struct *info,
+					kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null su_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+#ifdef __sparc_v9__
 
 static inline
 unsigned int su_inb(struct su_struct *info, unsigned long offset)
@@ -102,19 +237,117 @@
 	outb(value, info->port + offset);
 }
 
+#else
+
+static inline
+unsigned int su_inb(struct su_struct *info, unsigned long offset)
+{
+	return (unsigned int)(*(volatile unsigned char *)(info->port + offset));
+}
+
 static inline void
-receive_chars(struct su_struct *info, struct pt_regs *regs)
+su_outb(struct su_struct *info, unsigned long offset, int value)
+{
+	/*
+	 * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
+	 * connected with a gate then go to SlavIO. When IRQ4 goes tristated
+	 * gate gives logical one. Since we use level triggered interrupts
+	 * we have lockup and watchdog reset. We cannot mask IRQ because
+	 * keyboard shares IRQ with us (Bob Smelik: I would not hire you).
+	 * P3: Assure that OUT2 never goes down.
+	 */
+	if (offset == UART_MCR) value |= UART_MCR_OUT2;
+	*(volatile unsigned char *)(info->port + offset) = value;
+}
+
+#endif
+
+#define serial_in(info, off)		su_inb(info, off)
+#define serial_inp(info, off)		su_inb(info, off)
+#define serial_out(info, off, val)	su_outb(info, off, val)
+#define serial_outp(info, off, val)	su_outb(info, off, val)
+
+/*
+ * ------------------------------------------------------------
+ * su_stop() and su_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void su_stop(struct tty_struct *tty)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "su_stop"))
+		return;
+
+	save_flags(flags); cli();
+	if (info->IER & UART_IER_THRI) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+	restore_flags(flags);
+}
+
+static void su_start(struct tty_struct *tty)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "su_start"))
+		return;
+
+	save_flags(flags); cli();
+	if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+	restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * su_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static __inline__ void
+su_sched_event(struct su_struct *info, int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_serial);
+	mark_bh(SERIAL_BH);
+}
+
+static __inline__ void
+receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs)
 {
 	unsigned char status = 0;
 	unsigned char ch;
 
 	do {
-		ch = su_inb(info, UART_RX);
-
-#ifdef SERIAL_DEBUG_INTR
-		printk("DR%02x:%02x...", ch, status);
-#endif
-
+		ch = serial_inp(info, UART_RX);
 		if (info->kbd_node) {
 			if(ch == SUNKBD_RESET) {
                         	l1a_state.kbd_id = 1;
@@ -142,11 +375,206 @@
 	} while (status & UART_LSR_DR);
 }
 
+static __inline__ void
+receive_serial_chars(struct su_struct *info, int *status, struct pt_regs *regs)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch;
+	int ignored = 0;
+	struct	async_icount *icount;
+
+	icount = &info->icount;
+	do {
+		ch = serial_inp(info, UART_RX);
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			break;
+		*tty->flip.char_buf_ptr = ch;
+		icount->rx++;
+
+#ifdef SERIAL_DEBUG_INTR
+		printk("DR%02x:%02x...", ch, *status);
+#endif
+		*tty->flip.flag_buf_ptr = 0;
+		if (*status & (UART_LSR_BI | UART_LSR_PE |
+			       UART_LSR_FE | UART_LSR_OE)) {
+			/*
+			 * For statistics only
+			 */
+			if (*status & UART_LSR_BI) {
+				*status &= ~(UART_LSR_FE | UART_LSR_PE);
+				icount->brk++;
+			} else if (*status & UART_LSR_PE)
+				icount->parity++;
+			else if (*status & UART_LSR_FE)
+				icount->frame++;
+			if (*status & UART_LSR_OE)
+				icount->overrun++;
+
+			/*
+			 * Now check to see if character should be
+			 * ignored, and mask off conditions which
+			 * should be ignored.
+			 */
+			if (*status & info->ignore_status_mask) {
+				if (++ignored > 100)
+					break;
+				goto ignore_char;
+			}
+			*status &= info->read_status_mask;
+
+			if (*status & (UART_LSR_BI)) {
+#ifdef SERIAL_DEBUG_INTR
+				printk("handling break....");
+#endif
+				*tty->flip.flag_buf_ptr = TTY_BREAK;
+				if (info->flags & ASYNC_SAK)
+					do_SAK(tty);
+			} else if (*status & UART_LSR_PE)
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+			else if (*status & UART_LSR_FE)
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+			if (*status & UART_LSR_OE) {
+				/*
+				 * Overrun is special, since it's
+				 * reported immediately, and doesn't
+				 * affect the current character
+				 */
+				if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+					tty->flip.count++;
+					tty->flip.flag_buf_ptr++;
+					tty->flip.char_buf_ptr++;
+					*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+				}
+			}
+		}
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+	ignore_char:
+		*status = serial_inp(info, UART_LSR);
+	} while (*status & UART_LSR_DR);
+	tty_flip_buffer_push(tty);
+}
+
+static __inline__ void
+transmit_chars(struct su_struct *info, int *intr_done)
+{
+	int count;
+
+	if (info->x_char) {
+		serial_outp(info, UART_TX, info->x_char);
+		info->icount.tx++;
+		info->x_char = 0;
+		if (intr_done)
+			*intr_done = 0;
+		return;
+	}
+	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+	    info->tty->hw_stopped) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+		return;
+	}
+
+	count = info->xmit_fifo_size;
+	do {
+		serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
+		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		info->icount.tx++;
+		if (--info->xmit_cnt <= 0)
+			break;
+	} while (--count > 0);
+	
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		su_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("THRE...");
+#endif
+	if (intr_done)
+		*intr_done = 0;
+
+	if (info->xmit_cnt <= 0) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+}
+
+static __inline__ void
+check_modem_status(struct su_struct *info)
+{
+	int	status;
+	struct	async_icount *icount;
+
+	status = serial_in(info, UART_MSR);
+
+	if (status & UART_MSR_ANY_DELTA) {
+		icount = &info->icount;
+		/* update input line counters */
+		if (status & UART_MSR_TERI)
+			icount->rng++;
+		if (status & UART_MSR_DDSR)
+			icount->dsr++;
+		if (status & UART_MSR_DDCD) {
+			icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+			if ((info->flags & ASYNC_HARDPPS_CD) &&
+			    (status & UART_MSR_DCD))
+				hardpps();
+#endif
+	}
+		if (status & UART_MSR_DCTS)
+			icount->cts++;
+		wake_up_interruptible(&info->delta_msr_wait);
+	}
+
+	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+		printk("ttys%d CD now %s...", info->line,
+		       (status & UART_MSR_DCD) ? "on" : "off");
+#endif		
+		if (status & UART_MSR_DCD)
+			wake_up_interruptible(&info->open_wait);
+		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+			printk("doing serial hangup...");
+#endif
+			if (info->tty)
+				tty_hangup(info->tty);
+	}
+	}
+	if (info->flags & ASYNC_CTS_FLOW) {
+		if (info->tty->hw_stopped) {
+			if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx start...");
+#endif
+				info->tty->hw_stopped = 0;
+				info->IER |= UART_IER_THRI;
+				serial_out(info, UART_IER, info->IER);
+				su_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+				return;
+			}
+		} else {
+			if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx stop...");
+#endif
+				info->tty->hw_stopped = 1;
+				info->IER &= ~UART_IER_THRI;
+				serial_out(info, UART_IER, info->IER);
+			}
+		}
+	}
+}
+
 /*
- * This is the serial driver's generic interrupt routine
+ * This is the kbd/mouse serial driver's interrupt routine
  */
 static void
-su_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+su_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct su_struct *info = (struct su_struct *)dev_id;
 	unsigned char status;
@@ -154,52 +582,171 @@
 #ifdef SERIAL_DEBUG_INTR
 	printk("su_interrupt(%s)...", __irq_itoa(irq));
 #endif
+	if (!info)
+		return;
 
-	if (su_inb(info, UART_IIR) & UART_IIR_NO_INT)
+	if (serial_in(info, UART_IIR) & UART_IIR_NO_INT)
 		return;
 
-	status = su_inb(info, UART_LSR);
+	status = serial_inp(info, UART_LSR);
 #ifdef SERIAL_DEBUG_INTR
 	printk("status = %x...", status);
 #endif
 	if (status & UART_LSR_DR)
-		receive_chars(info, regs);
+		receive_kbd_ms_chars(info, regs);
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("end.\n");
+#endif
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static void
+su_serial_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	int status;
+	struct su_struct *info;
+	int pass_counter = 0;
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("su_interrupt(%s)...", __irq_itoa(irq));
+#endif
+	info = (struct su_struct *)dev_id;
+	if (!info || !info->tty)
+		return;
+	
+	do {
+		status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+		printk("status = %x...", status);
+#endif
+		if (status & UART_LSR_DR)
+			receive_serial_chars(info, &status, regs);
+		check_modem_status(info);
+		if (status & UART_LSR_THRE)
+			transmit_chars(info, 0);
+
+		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+#if 0
+			printk("rs loop break\n");
+#endif
+			break; 	/* Prevent infinite loops */
+		}
+	} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
+
+	info->last_active = jiffies;
 
 #ifdef SERIAL_DEBUG_INTR
 	printk("end.\n");
 #endif
 }
 
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * su_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using su_sched_event(), and they get done here.
+ */
+static void
+do_serial_bh(void)
+{
+	run_task_queue(&tq_serial);
+}
+
+static void
+do_softint(void *private_)
+{
+	struct su_struct	*info = (struct su_struct *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+/*
+ * ---------------------------------------------------------------
+ * Low level utility subroutines for the serial driver:  routines to
+ * figure out the appropriate timeout for an interrupt chain, routines
+ * to initialize and startup a serial port, and routines to shutdown a
+ * serial port.  Useful stuff like that.
+ * ---------------------------------------------------------------
+ */
+
 static int
-startup(struct su_struct * info)
+startup(struct su_struct *info)
 {
 	unsigned long flags;
 	int	retval=0;
+	unsigned long page;
 
-	save_flags(flags); cli();
-
-	if (info->flags & ASYNC_INITIALIZED) {
-		goto errout;
-	}
+	save_flags(flags);
+	if (info->tty) {
+		page = get_free_page(GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+
+		cli();
+
+		if (info->flags & ASYNC_INITIALIZED) {
+			free_page(page);
+			goto errout;
+		}
 
-	if (!info->port || !info->type) {
-		goto errout;
+		if (info->port == 0 || info->type == PORT_UNKNOWN) {
+			set_bit(TTY_IO_ERROR, &info->tty->flags);
+			free_page(page);
+			goto errout;
+		}
+		if (info->xmit_buf)
+			free_page(page);
+		else
+			info->xmit_buf = (unsigned char *) page;
 	}
+	cli();
 
 #ifdef SERIAL_DEBUG_OPEN
-	printk("starting up su%d (irq %s)...", info->line,
-	       __irq_itoa(info->irq));
+	printk("starting up ttys%d (irq %d)...", info->line, state->irq);
 #endif
 
-	if (info->type == PORT_16750)
-		su_outb(info, UART_IER, 0);
+	if (uart_config[info->type].flags & UART_STARTECH) {
+		/* Wake up UART */
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		serial_outp(info, UART_IER, 0);
+		serial_outp(info, UART_EFR, 0);
+		serial_outp(info, UART_LCR, 0);
+	}
+
+	if (info->type == PORT_16750) {
+		/* Wake up UART */
+		serial_outp(info, UART_IER, 0);
+	}
 
 	/*
 	 * Clear the FIFO buffers and disable them
 	 * (they will be reenabled in change_speed())
 	 */
 	if (uart_config[info->type].flags & UART_CLEAR_FIFO)
-		su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
 					     UART_FCR_CLEAR_XMIT));
 
 	/*
@@ -207,47 +754,84 @@
 	 * if it is, then bail out, because there's likely no UART
 	 * here.
 	 */
-	if (su_inb(info, UART_LSR) == 0xff) {
-		retval = -ENODEV;
+	if (serial_inp(info, UART_LSR) == 0xff) {
+		if (capable(CAP_SYS_ADMIN)) {
+			if (info->tty)
+				set_bit(TTY_IO_ERROR, &info->tty->flags);
+		} else
+			retval = -ENODEV;
 		goto errout;
 	}
-	
+
 	/*
 	 * Allocate the IRQ if necessary
 	 */
-	retval = request_irq(info->irq, su_interrupt, SA_SHIRQ,
-			     info->name, info);
-	if (retval)
+	if (info->kbd_node || info->ms_node) {
+		retval = request_irq(info->irq, su_kbd_ms_interrupt,
+				     SA_SHIRQ, info->name, info);
+	} else {
+		retval = request_irq(info->irq, su_serial_interrupt,
+				     SA_SHIRQ, info->name, info);
+	}
+	if (retval) {
+		if (capable(CAP_SYS_ADMIN)) {
+			if (info->tty)
+				set_bit(TTY_IO_ERROR, &info->tty->flags);
+			retval = 0;
+		}
 		goto errout;
+	}
 
 	/*
 	 * Clear the interrupt registers.
 	 */
-	su_inb(info, UART_RX);
-	su_inb(info, UART_IIR);
-	su_inb(info, UART_MSR);
+	(void) serial_inp(info, UART_RX);
+	(void) serial_inp(info, UART_IIR);
+	(void) serial_inp(info, UART_MSR);
 
 	/*
 	 * Now, initialize the UART 
 	 */
-	su_outb(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	serial_outp(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
 
-	info->MCR = UART_MCR_OUT2;
-	su_outb(info, UART_MCR, info->MCR);
+	info->MCR = 0;
+	if (info->tty && info->tty->termios->c_cflag & CBAUD)
+		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+	if (info->irq != 0)
+		info->MCR |= UART_MCR_OUT2;
+	serial_outp(info, UART_MCR, info->MCR);
 
 	/*
 	 * Finally, enable interrupts
 	 */
-	info->IER = UART_IER_RLSI | UART_IER_RDI;
-	su_outb(info, UART_IER, info->IER);	/* enable interrupts */
-	
+	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+	serial_outp(info, UART_IER, info->IER);	/* enable interrupts */
+
 	/*
 	 * And clear the interrupt registers again for luck.
 	 */
-	su_inb(info, UART_LSR);
-	su_inb(info, UART_RX);
-	su_inb(info, UART_IIR);
-	su_inb(info, UART_MSR);
+	(void)serial_inp(info, UART_LSR);
+	(void)serial_inp(info, UART_RX);
+	(void)serial_inp(info, UART_IIR);
+	(void)serial_inp(info, UART_MSR);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * Set up the tty->alt_speed kludge
+	 */
+	if (info->tty) {
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			info->tty->alt_speed = 57600;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			info->tty->alt_speed = 115200;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			info->tty->alt_speed = 230400;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			info->tty->alt_speed = 460800;
+	}
 
 	/*
 	 * and set the speed of the serial port
@@ -257,38 +841,135 @@
 	info->flags |= ASYNC_INITIALIZED;
 	restore_flags(flags);
 	return 0;
-	
+
 errout:
 	restore_flags(flags);
 	return retval;
 }
 
 /*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
  */
 static void
-change_speed(struct su_struct *info)
+shutdown(struct su_struct *info)
 {
-	unsigned char cval, fcr = 0;
-	int quot = 0;
-	unsigned long flags;
-	int i;
+	unsigned long	flags;
 
-	/* byte size and parity */
-	switch (info->cflag & CSIZE) {
-		case CS5: cval = 0x00; break;
-		case CS6: cval = 0x01; break;
-		case CS7: cval = 0x02; break;
-		case CS8: cval = 0x03; break;
-		/* Never happens, but GCC is too dumb to figure it out */
-		default:  cval = 0x00; break;
-	}
-	if (info->cflag & CSTOPB) {
-		cval |= 0x04;
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	save_flags(flags); cli(); /* Disable interrupts */
+
+	/*
+	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+	 * here so the queue might never be waken up
+	 */
+	wake_up_interruptible(&info->delta_msr_wait);
+	
+	/*
+	 * Free the IRQ, if necessary
+	 */
+	free_irq(info->irq, info);
+
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
 	}
-	if (info->cflag & PARENB) {
+
+	info->IER = 0;
+	serial_outp(info, UART_IER, 0x00);	/* disable all intrs */
+	info->MCR &= ~UART_MCR_OUT2;
+
+	/* disable break condition */
+	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+	serial_outp(info, UART_MCR, info->MCR);
+
+	/* disable FIFO's */	
+	serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+				     UART_FCR_CLEAR_XMIT));
+	(void)serial_in(info, UART_RX);    /* read data port to reset things */
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	if (uart_config[info->type].flags & UART_STARTECH) {
+		/* Arrange to enter sleep mode */
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		serial_outp(info, UART_IER, UART_IERX_SLEEP);
+		serial_outp(info, UART_LCR, 0);
+	}
+	if (info->type == PORT_16750) {
+		/* Arrange to enter sleep mode */
+		serial_outp(info, UART_IER, UART_IERX_SLEEP);
+	}
+	info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+}
+
+static __inline__ int
+su_get_baud_rate(struct su_struct *info)
+{
+	static int baud_table[] = {
+		0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+		4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
+	};
+	int i;
+
+	if (info->tty)
+		return tty_get_baud_rate(info->tty);
+
+	i = info->cflag & CBAUD;
+	if (i & CBAUDEX) {
+		i &= ~(CBAUDEX);
+		if (i < 1 || i > 4)
+			info->cflag &= ~(CBAUDEX);
+		else
+			i += 15;
+	}
+	return baud_table[i];
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void
+change_speed(struct su_struct *info)
+{
+	int		quot = 0, baud;
+	unsigned int	cval, fcr = 0;
+	int		bits;
+	unsigned long	flags;
+
+	if (!info->kbd_node && !info->ms_node) {
+		if (!info->tty || !info->tty->termios)
+			return;
+		if (!info->port)
+			return;
+		info->cflag = info->tty->termios->c_cflag;
+	}
+
+	/* byte size and parity */
+	switch (info->cflag & CSIZE) {
+	      case CS5: cval = 0x00; bits = 7; break;
+	      case CS6: cval = 0x01; bits = 8; break;
+	      case CS7: cval = 0x02; bits = 9; break;
+	      case CS8: cval = 0x03; bits = 10; break;
+		/* Never happens, but GCC is too dumb to figure it out */
+	      default:  cval = 0x00; bits = 7; break;
+	}
+	if (info->cflag & CSTOPB) {
+		cval |= 0x04;
+		bits++;
+	}
+	if (info->cflag & PARENB) {
 		cval |= UART_LCR_PARITY;
+		bits++;
 	}
 	if (!(info->cflag & PARODD))
 		cval |= UART_LCR_EPAR;
@@ -297,101 +978,1195 @@
 		cval |= UART_LCR_SPAR;
 #endif
 
-	/* Determine divisor based on baud rate */
-	i = info->cflag & CBAUD;
-	if (i & CBAUDEX) {
-		i &= ~CBAUDEX;
-		if (i < 1 || i > 4) 
-			info->cflag &= ~CBAUDEX;
+	/* Determine divisor based on baud rate */
+	baud = su_get_baud_rate(info);
+	if (baud == 38400 &&
+	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+		quot = info->custom_divisor;
+	else {
+		if (baud == 134)
+			/* Special case since 134 is really 134.5 */
+			quot = (2 * info->baud_base / 269);
+		else if (baud)
+			quot = info->baud_base / baud;
+	}
+	/* If the quotient is ever zero, default to 9600 bps */
+	if (!quot)
+		quot = info->baud_base / 9600;
+	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / info->baud_base);
+	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+
+	/* Set up FIFO's */
+	if (uart_config[info->type].flags & UART_USE_FIFO) {
+		if ((info->baud_base / quot) < 9600)
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+		else
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+	}
+	if (info->type == PORT_16750)
+		fcr |= UART_FCR7_64BYTE;
+
+	/* CTS flow control flag and modem status interrupts */
+	info->IER &= ~UART_IER_MSI;
+	if (info->flags & ASYNC_HARDPPS_CD)
+		info->IER |= UART_IER_MSI;
+	if (info->cflag & CRTSCTS) {
+		info->flags |= ASYNC_CTS_FLOW;
+		info->IER |= UART_IER_MSI;
+	} else
+		info->flags &= ~ASYNC_CTS_FLOW;
+	if (info->cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else {
+		info->flags |= ASYNC_CHECK_CD;
+		info->IER |= UART_IER_MSI;
+	}
+	serial_out(info, UART_IER, info->IER);
+
+	/*
+	 * Set up parity check flag
+	 */
+	if (info->tty) {
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+		info->read_status_mask = UART_LSR_OE | UART_LSR_THRE |
+					 UART_LSR_DR;
+		if (I_INPCK(info->tty))
+			info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+		if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+			info->read_status_mask |= UART_LSR_BI;
+
+		/*
+		 * Characters to ignore
+		 */
+		info->ignore_status_mask = 0;
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+		if (I_IGNBRK(info->tty)) {
+			info->ignore_status_mask |= UART_LSR_BI;
+			/*
+			 * If we're ignore parity and break indicators, ignore 
+			 * overruns too.  (For real raw support).
+			 */
+			if (I_IGNPAR(info->tty))
+				info->ignore_status_mask |= UART_LSR_OE;
+		}
+		/*
+		 * !!! ignore all characters if CREAD is not set
+		 */
+		if ((info->cflag & CREAD) == 0)
+			info->ignore_status_mask |= UART_LSR_DR;
+	}
+
+	save_flags(flags); cli();
+	if (uart_config[info->type].flags & UART_STARTECH) {
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR,
+			    (info->cflag & CRTSCTS) ? UART_EFR_CTS : 0);
+	}
+	serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
+	serial_outp(info, UART_DLL, quot & 0xff);	/* LS of divisor */
+	serial_outp(info, UART_DLM, quot >> 8);		/* MS of divisor */
+	if (info->type == PORT_16750)
+		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
+	serial_outp(info, UART_LCR, cval);		/* reset DLAB */
+	if (info->type != PORT_16750)
+		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
+	restore_flags(flags);
+	info->quot = quot;
+}
+
+static void
+su_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "su_put_char"))
+		return;
+
+	if (!tty || !info->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+		restore_flags(flags);
+		return;
+	}
+
+	info->xmit_buf[info->xmit_head++] = ch;
+	info->xmit_head &= SERIAL_XMIT_SIZE-1;
+	info->xmit_cnt++;
+	restore_flags(flags);
+}
+
+static void su_put_char_kbd(unsigned char c)
+{
+	struct su_struct *info = su_table;
+	int lsr;
+
+	if (!info->kbd_node)
+		++info;
+	if (!info)
+		return;
+
+	do {
+		lsr = serial_in(info, UART_LSR);
+	} while (!(lsr & UART_LSR_THRE));
+
+	/* Send the character out. */
+	su_outb(info, UART_TX, c);
+}
+
+static void
+su_change_mouse_baud(int baud)
+{
+	struct su_struct *info = su_table;
+
+	if (!info->ms_node)
+		++info;
+	if (!info)
+		return;
+
+	info->cflag &= ~(CBAUDEX | CBAUD);
+	switch(baud) {
+		case 1200:
+			info->cflag |= B1200;
+			break;
+		case 2400:
+			info->cflag |= B2400;
+			break;
+		case 4800:
+			info->cflag |= B4800;
+			break;
+		case 9600:
+			info->cflag |= B9600;
+			break;
+		default:
+			printk("su_change_mouse_baud: unknown baud rate %d, "
+			       "defaulting to 1200\n", baud);
+			info->cflag |= 1200;
+			break;
+	}
+	change_speed(info);
+}
+
+static void
+su_flush_chars(struct tty_struct *tty)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
+				
+	if (serial_paranoia_check(info, tty->device, "su_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+	info->IER |= UART_IER_THRI;
+	serial_out(info, UART_IER, info->IER);
+	restore_flags(flags);
+}
+
+static int
+su_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, ret = 0;
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "su_write"))
+		return 0;
+
+	if (!tty || !info->xmit_buf || !tmp_buf)
+		return 0;
+
+	save_flags(flags);
+	if (from_user) {
+		down(&tmp_buf_sem);
+		while (1) {
+			c = MIN(count,
+				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				    SERIAL_XMIT_SIZE - info->xmit_head));
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(tmp_buf, buf, c);
+			if (!c) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+			cli();
+			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - info->xmit_head));
+			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+			info->xmit_head = ((info->xmit_head + c) &
+					   (SERIAL_XMIT_SIZE-1));
+			info->xmit_cnt += c;
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		up(&tmp_buf_sem);
+	} else {
+		while (1) {
+			cli();		
+			c = MIN(count,
+				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				    SERIAL_XMIT_SIZE - info->xmit_head));
+			if (c <= 0) {
+				restore_flags(flags);
+				break;
+			}
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
+			info->xmit_head = ((info->xmit_head + c) &
+					   (SERIAL_XMIT_SIZE-1));
+			info->xmit_cnt += c;
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+	}
+	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+	    !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+	return ret;
+}
+
+static int
+su_write_room(struct tty_struct *tty)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	int	ret;
+
+	if (serial_paranoia_check(info, tty->device, "su_write_room"))
+		return 0;
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int
+su_chars_in_buffer(struct tty_struct *tty)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "su_chars_in_buffer"))
+		return 0;
+	return info->xmit_cnt;
+}
+
+static void
+su_flush_buffer(struct tty_struct *tty)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "su_flush_buffer"))
+		return;
+	cli();
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	sti();
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void
+su_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "su_send_char"))
+		return;
+
+	info->x_char = ch;
+	if (ch) {
+		/* Make sure transmit interrupts are on */
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * su_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void
+su_throttle(struct tty_struct * tty)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "su_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		su_send_xchar(tty, STOP_CHAR(tty));
+
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR &= ~UART_MCR_RTS;
+
+	cli();
+	serial_out(info, UART_MCR, info->MCR);
+	sti();
+}
+
+static void
+su_unthrottle(struct tty_struct * tty)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "su_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			su_send_xchar(tty, START_CHAR(tty));
+	}
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR |= UART_MCR_RTS;
+	cli();
+	serial_out(info, UART_MCR, info->MCR);
+	sti();
+}
+
+/*
+ * ------------------------------------------------------------
+ * su_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int
+get_lsr_info(struct su_struct * info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+
+	cli();
+	status = serial_in(info, UART_LSR);
+	sti();
+	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+	return put_user(result,value);
+}
+
+
+static int
+get_modem_info(struct su_struct * info, unsigned int *value)
+{
+	unsigned char control, status;
+	unsigned int result;
+
+	control = info->MCR;
+	cli();
+	status = serial_in(info, UART_MSR);
+	sti();
+	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+		| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+		| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+	return put_user(result,value);
+}
+
+static int
+set_modem_info(struct su_struct * info, unsigned int cmd, unsigned int *value)
+{
+	int error;
+	unsigned int arg;
+
+	error = get_user(arg, value);
+	if (error)
+		return error;
+	switch (cmd) {
+	case TIOCMBIS: 
+		if (arg & TIOCM_RTS)
+			info->MCR |= UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR |= UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR |= UART_MCR_OUT2;
+#endif
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			info->MCR &= ~UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR &= ~UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR &= ~UART_MCR_OUT2;
+#endif
+		break;
+	case TIOCMSET:
+		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+					    UART_MCR_OUT1 |
+					    UART_MCR_OUT2 |
+#endif
+					    UART_MCR_DTR))
+			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+			     | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+			     | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+		break;
+	default:
+		return -EINVAL;
+	}
+	cli();
+	serial_out(info, UART_MCR, info->MCR);
+	sti();
+	return 0;
+}
+
+/*
+ * su_break() --- routine which turns the break handling on or off
+ */
+static void
+su_break(struct tty_struct *tty, int break_state)
+{
+	struct su_struct * info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "su_break"))
+		return;
+
+	if (!info->port)
+		return;
+	save_flags(flags); cli();
+	if (break_state == -1)
+		serial_out(info, UART_LCR,
+			   serial_inp(info, UART_LCR) | UART_LCR_SBC);
+	else
+		serial_out(info, UART_LCR,
+			   serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+	restore_flags(flags);
+}
+
+static int
+su_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error;
+	struct su_struct * info = (struct su_struct *)tty->driver_data;
+	struct async_icount cprev, cnow;	/* kernel counter temps */
+	struct serial_icounter_struct *p_cuser;	/* user space */
+
+	if (serial_paranoia_check(info, tty->device, "su_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+
+	switch (cmd) {
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+
+		case TIOCSERGETLSR: /* Get line status register */
+			return get_lsr_info(info, (unsigned int *) arg);
+
+#if 0
+		case TIOCSERGSTRUCT:
+			if (copy_to_user((struct async_struct *) arg,
+					 info, sizeof(struct async_struct)))
+				return -EFAULT;
+			return 0;
+#endif
+				
+		/*
+		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+		 * - mask passed in arg for lines of interest
+ 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 * Caller should use TIOCGICOUNT to see which one it was
+		 */
+		case TIOCMIWAIT:
+			cli();
+			/* note the counters on entry */
+			cprev = info->icount;
+			sti();
+			while (1) {
+				interruptible_sleep_on(&info->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+				cli();
+				cnow = info->icount; /* atomic copy */
+				sti();
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
+				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+					return -EIO; /* no change => error */
+				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+					return 0;
+				}
+				cprev = cnow;
+			}
+			/* NOTREACHED */
+
+		/* 
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+		case TIOCGICOUNT:
+			cli();
+			cnow = info->icount;
+			sti();
+			p_cuser = (struct serial_icounter_struct *) arg;
+			error = put_user(cnow.cts, &p_cuser->cts);
+			if (error) return error;
+			error = put_user(cnow.dsr, &p_cuser->dsr);
+			if (error) return error;
+			error = put_user(cnow.rng, &p_cuser->rng);
+			if (error) return error;
+			error = put_user(cnow.dcd, &p_cuser->dcd);
+			if (error) return error;
+			return 0;
+
+		default:
+			return -ENOIOCTLCMD;
+		}
+	/* return 0; */ /* Trigger warnings is fall through by a chance. */
+}
+
+static void
+su_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+
+	if (   (tty->termios->c_cflag == old_termios->c_cflag)
+	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_speed(info);
+
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) &&
+	    !(tty->termios->c_cflag & CBAUD)) {
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+		cli();
+		serial_out(info, UART_MCR, info->MCR);
+		sti();
+	}
+	
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+	    (tty->termios->c_cflag & CBAUD)) {
+		info->MCR |= UART_MCR_DTR;
+		if (!(tty->termios->c_cflag & CRTSCTS) || 
+		    !test_bit(TTY_THROTTLED, &tty->flags)) {
+			info->MCR |= UART_MCR_RTS;
+		}
+		cli();
+		serial_out(info, UART_MCR, info->MCR);
+		sti();
+	}
+	
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		su_start(tty);
+	}
+
+#if 0
+	/*
+	 * No need to wake up processes in open wait, since they
+	 * sample the CLOCAL flag once, and don't recheck it.
+	 * XXX  It's not clear whether the current behavior is correct
+	 * or not.  Hence, this may change.....
+	 */
+	if (!(old_termios->c_cflag & CLOCAL) &&
+	    (tty->termios->c_cflag & CLOCAL))
+		wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * su_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void
+su_close(struct tty_struct *tty, struct file * filp)
+{
+	struct su_struct *info = (struct su_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "su_close"))
+		return;
+
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		DBG_CNT("before DEC-hung");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("su_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("su_close: bad serial port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk("su_close: bad serial port count for ttys%d: %d\n",
+		       info->line, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		DBG_CNT("before DEC-2");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->IER &= ~UART_IER_RLSI;
+	info->read_status_mask &= ~UART_LSR_DR;
+	if (info->flags & ASYNC_INITIALIZED) {
+		serial_out(info, UART_IER, info->IER);
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		su_wait_until_sent(tty, info->timeout);
+	}
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+	restore_flags(flags);
+}
+
+/*
+ * su_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void
+su_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct su_struct * info = (struct su_struct *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+	int lsr;
+
+	if (serial_paranoia_check(info, tty->device, "su_wait_until_sent"))
+		return;
+
+	if (info->type == PORT_UNKNOWN)
+		return;
+
+	orig_jiffies = jiffies;
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 * 
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	if (timeout)
+	  char_time = MIN(char_time, timeout);
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("In su_wait_until_sent(%d) check=%lu...", timeout, char_time);
+	printk("jiff=%lu...", jiffies);
+#endif
+	while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+		current->state = TASK_INTERRUPTIBLE;
+		current->counter = 0;	/* make us low-priority */
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && ((orig_jiffies + timeout) < jiffies))
+			break;
+	}
+	current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * su_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void
+su_hangup(struct tty_struct *tty)
+{
+	struct su_struct * info = (struct su_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "su_hangup"))
+		return;
+
+	su_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	info->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * su_open() and friends
+ * ------------------------------------------------------------
+ */
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+		struct su_struct *info)
+{
+	struct wait_queue wait = { current, NULL };
+	int		retval;
+	int		do_clocal = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * su_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	cli();
+	if (!tty_hung_up_p(filp)) 
+		info->count--;
+	sti();
+	info->blocked_open++;
+	while (1) {
+		cli();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (tty->termios->c_cflag & CBAUD))
+			serial_out(info, UART_MCR,
+				   serial_inp(info, UART_MCR) |
+				   (UART_MCR_DTR | UART_MCR_RTS));
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(info->flags & ASYNC_CLOSING) &&
+		    (do_clocal || (serial_in(info, UART_MSR) &
+				   UART_MSR_DCD)))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, info->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		info->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int
+su_open(struct tty_struct *tty, struct file * filp)
+{
+	struct su_struct	*info;
+	int 			retval, line;
+	unsigned long		page;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS))
+		return -ENODEV;
+	info = su_table + line;
+	if (serial_paranoia_check(info, tty->device, "su_open"))
+		return -ENODEV;
+	info->count++;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("su_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->count);
+#endif
+	tty->driver_data = info;
+	info->tty = tty;
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	if (!tmp_buf) {
+		page = get_free_page(GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+		if (tmp_buf)
+			free_page(page);
 		else
-			i += 15;
+			tmp_buf = (unsigned char *) page;
 	}
-	if (!quot) {
-		if (baud_table[i] == 134)
-			/* Special case since 134 is really 134.5 */
-			quot = (2 * info->baud_base / 269);
-		else if (baud_table[i])
-			quot = info->baud_base / baud_table[i];
-		/* If the quotient is ever zero, default to 1200 bps */
-		if (!quot)
-			quot = info->baud_base / 1200;
+
+	/*
+	 * If the port is the middle of closing, bail out now
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
 	}
+	
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
 
-	/* Set up FIFO's */
-	if (uart_config[info->type].flags & UART_USE_FIFO)
-		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+	MOD_INC_USE_COUNT;
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("su_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
 
-	su_outb(info, UART_IER, info->IER);
+	if ((info->count == 1) &&
+	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else 
+			*tty->termios = info->callout_termios;
+		change_speed(info);
+	}
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (sercons.cflag && sercons.index == line) {
+		tty->termios->c_cflag = sercons.cflag;
+		sercons.cflag = 0;
+		change_speed(info);
+	}
+#endif
+	info->session = current->session;
+	info->pgrp = current->pgrp;
 
-	save_flags(flags); cli();
-	su_outb(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
-	su_outb(info, UART_DLL, quot & 0xff);	/* LS of divisor */
-	su_outb(info, UART_DLM, quot >> 8);		/* MS of divisor */
-	if (info->type == PORT_16750)
-		su_outb(info, UART_FCR, fcr); 	/* set fcr */
-	su_outb(info, UART_LCR, cval);		/* reset DLAB */
-	if (info->type != PORT_16750)
-		su_outb(info, UART_FCR, fcr); 	/* set fcr */
-	restore_flags(flags);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("su_open ttys%d successful...", info->line);
+#endif
+	return 0;
 }
 
-static void
-su_put_char(unsigned char c)
+/*
+ * /proc fs routines....
+ */
+static __inline__ int
+line_info(char *buf, struct su_struct *info)
 {
-	struct su_struct *info = su_table;
-	int lsr;
+	char	stat_buf[30], control, status;
+	int	ret;
 
-	if (!info->kbd_node)
-		++info;
+	ret = sprintf(buf, "%d: uart:%s port:%X irq:%s",
+		      info->line, uart_config[info->type].name, 
+		      (int)info->port, __irq_itoa(info->irq));
+
+	if (info->port == 0 || info->type == PORT_UNKNOWN) {
+		ret += sprintf(buf+ret, "\n");
+		return ret;
+	}
 
-	do {
-		lsr = inb(info->port + UART_LSR);
-	} while (!(lsr & UART_LSR_THRE));
+	/*
+	 * Figure out the current RS-232 lines
+	 */
+	cli();
+	status = serial_in(info, UART_MSR);
+	control = info ? info->MCR : serial_in(info, UART_MCR);
+	sti();
+
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (control & UART_MCR_RTS)
+		strcat(stat_buf, "|RTS");
+	if (status & UART_MSR_CTS)
+		strcat(stat_buf, "|CTS");
+	if (control & UART_MCR_DTR)
+		strcat(stat_buf, "|DTR");
+	if (status & UART_MSR_DSR)
+		strcat(stat_buf, "|DSR");
+	if (status & UART_MSR_DCD)
+		strcat(stat_buf, "|CD");
+	if (status & UART_MSR_RI)
+		strcat(stat_buf, "|RI");
+
+	if (info->quot) {
+		ret += sprintf(buf+ret, " baud:%d",
+			       info->baud_base / info->quot);
+	}
+
+	ret += sprintf(buf+ret, " tx:%d rx:%d",
+		      info->icount.tx, info->icount.rx);
+
+	if (info->icount.frame)
+		ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
 
-	/* Send the character out. */
-	su_outb(info, UART_TX, c);
+	if (info->icount.parity)
+		ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+
+	if (info->icount.brk)
+		ret += sprintf(buf+ret, " brk:%d", info->icount.brk);	
+
+	if (info->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+
+	/*
+	 * Last thing is the RS-232 status lines
+	 */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+	return ret;
 }
 
-static void
-su_change_mouse_baud(int baud)
+int su_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
 {
-	struct su_struct *info = su_table;
-
-	if (!info->ms_node)
-		++info;
-	if (!info)
-		return;
+	int i, len = 0;
+	off_t	begin = 0;
 
-	info->cflag &= ~(CBAUDEX | CBAUD);
-	switch(baud) {
-		case 1200:
-			info->cflag |= B1200;
-			break;
-		case 2400:
-			info->cflag |= B2400;
-			break;
-		case 4800:
-			info->cflag |= B4800;
-			break;
-		case 9600:
-			info->cflag |= B9600;
-			break;
-		default:
-			printk("su_change_mouse_baud: unknown baud rate %d, "
-			       "defaulting to 1200\n", baud);
-			info->cflag |= 1200;
-			break;
+	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+	for (i = 0; i < NR_PORTS && len < 4000; i++) {
+		len += line_info(page + len, &su_table[i]);
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
 	}
-	change_speed(info);
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (begin-off);
+	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
 /*
+ * ---------------------------------------------------------------------
+ * su_init() and friends
+ *
+ * su_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
  * This routine prints out the appropriate serial driver version
  * number, and identifies which options were configured into this
  * driver.
  */
-static inline void
-show_su_version(void)
+static __inline__
+void show_su_version(void)
 {
  	printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
 }
@@ -407,10 +2182,15 @@
 autoconfig(struct su_struct *info)
 {
 	unsigned char status1, status2, scratch, scratch2;
+#ifdef __sparc_v9__
 	struct linux_ebus_device *dev = 0;
 	struct linux_ebus *ebus;
+#else
+	struct linux_prom_registers reg0;
+#endif
 	unsigned long flags;
 
+#ifdef __sparc_v9__
 	for_each_ebus(ebus) {
 		for_each_ebusdev(dev, ebus) {
 			if (!strncmp(dev->prom_name, "su", 2)) {
@@ -430,9 +2210,29 @@
 		return;
 
 	info->irq = dev->irqs[0];
+#else
+	if (!info->port_node)
+		return;
+
+	if (prom_getproperty(info->port_node, "reg",
+	    (char *)&reg0, sizeof(reg0)) == -1) {
+		prom_printf("su: no \"reg\" property\n");
+		return;
+	}
+	prom_apply_obio_ranges(&reg0, 1);
+	if ((info->port = (unsigned long) sparc_alloc_io(reg0.phys_addr,
+	    0, reg0.reg_size, "su-regs", reg0.which_io, 0)) == 0) {
+		prom_printf("su: cannot map\n");
+		return;
+	}
+	/*
+	 * There is no intr property on MrCoffee, so hardwire it. Krups?
+	 */
+	info->irq = IRQ_4M(13);
+#endif
 
 #ifdef DEBUG_SERIAL_OPEN
-	printk("Found 'su' at %016lx IRQ %d,%x\n", dev->base_address[0],
+	printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
 	       __irq_itoa(dev->irqs[0]));
 #endif
 
@@ -449,33 +2249,35 @@
 	 * 0x80 is a non-existent port; which should be safe since
 	 * include/asm/io.h also makes this assumption.
 	 */
-	scratch = su_inb(info, UART_IER);
+	scratch = serial_in(info, UART_IER);
 	su_outb(info, UART_IER, 0);
-	scratch2 = su_inb(info, UART_IER);
+	scratch2 = serial_in(info, UART_IER);
 	su_outb(info, UART_IER, scratch);
 	if (scratch2) {
 		restore_flags(flags);
 		return;		/* We failed; there's nothing here */
 	}
 
-	scratch = su_inb(info, UART_MCR);
+#if 0 /* P3 You will never beleive but SuperIO fails this test in MrCoffee. */
+	scratch = serial_in(info, UART_MCR);
 	su_outb(info, UART_MCR, UART_MCR_LOOP | scratch);
-	scratch2 = su_inb(info, UART_MSR);
+	scratch2 = serial_in(info, UART_MSR);
 	su_outb(info, UART_MCR, UART_MCR_LOOP | 0x0A);
-	status1 = su_inb(info, UART_MSR) & 0xF0;
+	status1 = serial_in(info, UART_MSR) & 0xF0;
 	su_outb(info, UART_MCR, scratch);
 	su_outb(info, UART_MSR, scratch2);
 	if (status1 != 0x90) {
 		restore_flags(flags);
 		return;
 	} 
+#endif
 
-	scratch2 = su_inb(info, UART_LCR);
+	scratch2 = serial_in(info, UART_LCR);
 	su_outb(info, UART_LCR, 0xBF);	/* set up for StarTech test */
 	su_outb(info, UART_EFR, 0);	/* EFR is the same as FCR */
 	su_outb(info, UART_LCR, 0);
 	su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
-	scratch = su_inb(info, UART_IIR) >> 6;
+	scratch = serial_in(info, UART_IIR) >> 6;
 	switch (scratch) {
 		case 0:
 			info->type = PORT_16450;
@@ -528,21 +2330,27 @@
 		if ((status1 != 0xa5) || (status2 != 0x5a))
 			info->type = PORT_8250;
 	}
+	info->xmit_fifo_size = uart_config[info->type].dfl_xmit_fifo_size;
 
 	if (info->type == PORT_UNKNOWN) {
 		restore_flags(flags);
 		return;
 	}
 
-	sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
+	if (info->kbd_node || info->ms_node)
+		sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
+	else
+		strcpy(info->name, "su(serial)");
+
+#ifdef __sparc_v9__
 	request_region(info->port, 8, info->name);
+#endif
 
 	/*
 	 * Reset the UART.
 	 */
 	su_outb(info, UART_MCR, 0x00);
-	su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
-				     UART_FCR_CLEAR_XMIT));
+	su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
 	su_inb(info, UART_RX);
 
 	restore_flags(flags);
@@ -551,19 +2359,117 @@
 /*
  * The serial driver boot-time initialization code!
  */
-__initfunc(int su_init(void))
+__initfunc(int su_serial_init(void))
 {
 	int i;
 	struct su_struct *info;
-	
+
+	init_bh(SERIAL_BH, do_serial_bh);
 	show_su_version();
 
+	/* Initialize the tty_driver structure */
+
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.driver_name = "su";
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = NR_PORTS;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = su_open;
+	serial_driver.close = su_close;
+	serial_driver.write = su_write;
+	serial_driver.put_char = su_put_char;
+	serial_driver.flush_chars = su_flush_chars;
+	serial_driver.write_room = su_write_room;
+	serial_driver.chars_in_buffer = su_chars_in_buffer;
+	serial_driver.flush_buffer = su_flush_buffer;
+	serial_driver.ioctl = su_ioctl;
+	serial_driver.throttle = su_throttle;
+	serial_driver.unthrottle = su_unthrottle;
+	serial_driver.send_xchar = su_send_xchar;
+	serial_driver.set_termios = su_set_termios;
+	serial_driver.stop = su_stop;
+	serial_driver.start = su_start;
+	serial_driver.hangup = su_hangup;
+	serial_driver.break_ctl = su_break;
+	serial_driver.wait_until_sent = su_wait_until_sent;
+	serial_driver.read_proc = su_read_proc;
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register regular su\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout su\n");
+
 	for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
 		info->line = i;
+		info->type = PORT_UNKNOWN;
+		info->baud_base = BAUD_BASE;
+		/* info->flags = 0; */
+		info->custom_divisor = 0;
+		info->close_delay = 5*HZ/10;
+		info->closing_wait = 30*HZ;
+		info->callout_termios = callout_driver.init_termios;
+		info->normal_termios = serial_driver.init_termios;
+		info->icount.cts = info->icount.dsr = 
+			info->icount.rng = info->icount.dcd = 0;
+		info->icount.rx = info->icount.tx = 0;
+		info->icount.frame = info->icount.parity = 0;
+		info->icount.overrun = info->icount.brk = 0;
+		info->tqueue.routine = do_softint;
+		info->tqueue.data = info;
+		info->cflag = serial_driver.init_termios.c_cflag;
+
+		autoconfig(info);
+		if (info->type == PORT_UNKNOWN)
+			continue;
+
+		printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
+		       info->name, info->port, __irq_itoa(info->irq),
+		       uart_config[info->type].name);
+	}
+
+	return 0;
+}
+
+__initfunc(int su_kbd_ms_init(void))
+{
+	int i;
+	struct su_struct *info;
+
+	show_su_version();
+
+	for (i = 0, info = su_table; i < 2; i++, info++) {
+		info->line = i;
+		info->type = PORT_UNKNOWN;
+		info->baud_base = BAUD_BASE;
+
 		if (info->kbd_node)
-			info->cflag = B1200 | CS8 | CREAD;
+			info->cflag = B1200 | CS8 | CLOCAL | CREAD;
 		else
-			info->cflag = B4800 | CS8 | CREAD;
+			info->cflag = B4800 | CS8 | CLOCAL | CREAD;
 
 		autoconfig(info);
 		if (info->type == PORT_UNKNOWN)
@@ -575,7 +2481,7 @@
 
 		startup(info);
 		if (info->kbd_node)
-			keyboard_zsinit(su_put_char);
+			keyboard_zsinit(su_put_char_kbd);
 		else
 			sun_mouse_zsinit();
 	}
@@ -592,6 +2498,33 @@
 	int len;
 
 	/*
+	 * Find su on MrCoffee. We return OK code if find any.
+	 * Then su_init finds every one and initializes them.
+	 * We do this early because MrCoffee got no aliases.
+	 */
+	node = prom_getchild(prom_root_node);
+	if ((node = prom_searchsiblings(node, "obio")) != 0) {
+		if ((sunode = prom_getchild(node)) != 0) {
+			if ((sunode = prom_searchsiblings(sunode, "su")) != 0) {
+				info->port_node = sunode;
+#ifdef CONFIG_SERIAL_CONSOLE
+				/*
+				 * Console must be initiated after the generic
+				 * initialization.
+				 * sunserial_setinitfunc inverts order, so
+				 * call this before next one.
+				 */
+				sunserial_setinitfunc(memory_start,
+						      su_serial_console_init);
+#endif
+        			sunserial_setinitfunc(memory_start,
+						      su_serial_init);
+				return 0;
+			}
+		}
+	}
+
+	/*
 	 * Get the nodes for keyboard and mouse from 'aliases'...
 	 */
         node = prom_getchild(prom_root_node);
@@ -619,7 +2552,9 @@
 	 * Find matching EBus nodes...
 	 */
         node = prom_getchild(prom_root_node);
-	node = prom_searchsiblings(node, "pci");
+	if ((node = prom_searchsiblings(node, "pci")) == 0) {
+		return -ENODEV;		/* Plain sparc */
+	}
 
 	/*
 	 * Check for SUNW,sabre on Ultra 5/10/AXi.
@@ -668,7 +2603,7 @@
 				/*
 				 * Found everything we need?
 				 */
-				if (devices == NR_PORTS)
+				if (devices == 2)
 					goto found;
 
 				sunode = prom_getsibling(sunode);
@@ -687,7 +2622,7 @@
 	return -ENODEV;
 
 found:
-        sunserial_setinitfunc(memory_start, su_init);
+        sunserial_setinitfunc(memory_start, su_kbd_ms_init);
         rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
 	sunkbd_setinitfunc(memory_start, sun_kbd_init);
 	kbd_ops.compute_shiftstate = sun_compute_shiftstate;
@@ -695,9 +2630,266 @@
 	kbd_ops.getledstate = sun_getledstate;
 	kbd_ops.setkeycode = sun_setkeycode;
 	kbd_ops.getkeycode = sun_getkeycode;
+#ifdef CONFIG_PCI
 	sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
 			       sun_func_buf, sun_func_table,
 			       sun_funcbufsize, sun_funcbufleft,
 			       sun_accent_table, sun_accent_table_size);
+#endif
+	return 0;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ *	Wait for transmitter & holding register to empty
+ */
+static __inline__ void
+wait_for_xmitr(struct su_struct *info)
+{
+	int lsr;
+	unsigned int tmout = 1000000;
+
+	do {
+		lsr = su_inb(info, UART_LSR);
+		if (--tmout == 0)
+			break;
+	} while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
+}
+
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ */
+static void
+serial_console_write(struct console *co, const char *s,
+				unsigned count)
+{
+	struct su_struct *info;
+	int ier;
+	unsigned i;
+
+	info = su_table + co->index;
+	/*
+	 *	First save the IER then disable the interrupts
+	 */
+	ier = su_inb(info, UART_IER);
+	su_outb(info, UART_IER, 0x00);
+
+	/*
+	 *	Now, do each character
+	 */
+	for (i = 0; i < count; i++, s++) {
+		wait_for_xmitr(info);
+
+		/*
+		 *	Send the character out.
+		 *	If a LF, also do CR...
+		 */
+		su_outb(info, UART_TX, *s);
+		if (*s == 10) {
+			wait_for_xmitr(info);
+			su_outb(info, UART_TX, 13);
+		}
+	}
+
+	/*
+	 *	Finally, Wait for transmitter & holding register to empty
+	 * 	and restore the IER
+	 */
+	wait_for_xmitr(info);
+	su_outb(info, UART_IER, ier);
+}
+
+/*
+ *	Receive character from the serial port
+ */
+static int
+serial_console_wait_key(struct console *co)
+{
+	struct su_struct *info;
+	int ier;
+	int lsr;
+	int c;
+
+	info = su_table + co->index;
+
+	/*
+	 *	First save the IER then disable the interrupts so
+	 *	that the real driver for the port does not get the
+	 *	character.
+	 */
+	ier = su_inb(info, UART_IER);
+	su_outb(info, UART_IER, 0x00);
+
+	do {
+		lsr = su_inb(info, UART_LSR);
+	} while (!(lsr & UART_LSR_DR));
+	c = su_inb(info, UART_RX);
+
+	/*
+	 *	Restore the interrupts
+	 */
+	su_outb(info, UART_IER, ier);
+
+	return c;
+}
+
+static kdev_t
+serial_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ *	Setup initial baud/bits/parity. We do two things here:
+ *	- construct a cflag setting for the first su_open()
+ *	- initialize the serial port
+ *	Return non-zero if we didn't find a serial port.
+ */
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+	struct su_struct *info;
+	unsigned cval;
+	int	baud = 9600;
+	int	bits = 8;
+	int	parity = 'n';
+	int	cflag = CREAD | HUPCL | CLOCAL;
+	int	quot = 0;
+	char	*s;
+
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) parity = *s++;
+		if (*s) bits   = *s - '0';
+	}
+
+	/*
+	 *	Now construct a cflag setting.
+	 */
+	switch(baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 2400:
+			cflag |= B2400;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 57600:
+			cflag |= B57600;
+			break;
+		case 115200:
+			cflag |= B115200;
+			break;
+		case 9600:
+		default:
+			cflag |= B9600;
+			break;
+	}
+	switch(bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch(parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+	co->cflag = cflag;
+
+	/*
+	 *	Divisor, bytesize and parity
+	 */
+	info = su_table + co->index;
+	quot = BAUD_BASE / baud;
+	cval = cflag & (CSIZE | CSTOPB);
+#if defined(__powerpc__) || defined(__alpha__)
+	cval >>= 8;
+#else /* !__powerpc__ && !__alpha__ */
+	cval >>= 4;
+#endif /* !__powerpc__ && !__alpha__ */
+	if (cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+
+	/*
+	 *	Disable UART interrupts, set DTR and RTS high
+	 *	and set speed.
+	 */
+	su_outb(info, UART_IER, 0);
+	su_outb(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+	su_outb(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
+	su_outb(info, UART_DLL, quot & 0xff);		/* LS of divisor */
+	su_outb(info, UART_DLM, quot >> 8);		/* MS of divisor */
+	su_outb(info, UART_LCR, cval);			/* reset DLAB */
+	info->quot = quot;
+
+	/*
+	 *	If we read 0xff from the LSR, there is no UART here.
+	 */
+	if (su_inb(info, UART_LSR) == 0xff)
+		return -1;
+
+	return 0;
+}
+
+static struct console sercons = {
+	"ttyS",
+	serial_console_write,
+	NULL,
+	serial_console_device,
+	serial_console_wait_key,
+	NULL,
+	serial_console_setup,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+/*
+ *	Register console.
+ */
+__initfunc(int su_serial_console_init(void))
+{
+	extern int con_is_present(void);
+
+	if (con_is_present())
+		return 0;
+	if (serial_console == 0)
+		return 0;
+	if (su_table[0].port == 0 || su_table[0].port_node == 0)
+		return 0;
+	sercons.index = 0;
+	register_console(&sercons);
 	return 0;
 }
+
+#endif /* CONFIG_SERIAL_CONSOLE */
diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/su32.c linux/drivers/sbus/char/su32.c
--- v2.1.126/linux/drivers/sbus/char/su32.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/su32.c	Wed Dec 31 16:00:00 1969
@@ -1,3565 +0,0 @@
-/* $Id: su32.c,v 1.1 1998/09/18 10:45:32 jj Exp $
- * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- * Coypright (C) 1998  Pete Zaitcev   (zaitcev@metabyte.com)
- *
- * This is mainly a variation of drivers/char/serial.c,
- * credits go to authors mentioned therein.
- */
-
-/*
- * Configuration section.
- */
-#define SERIAL_PARANOIA_CHECK
-#define CONFIG_SERIAL_NOPAUSE_IO	/* Unused on sparc */
-#define SERIAL_DO_RESTART
-
-#if 1
-/* Normally these defines are controlled by the autoconf.h */
-
-#undef CONFIG_SERIAL_MANY_PORTS
-#define CONFIG_SERIAL_SHARE_IRQ		/* Must be enabled for MrCoffee. */
-#undef CONFIG_SERIAL_DETECT_IRQ		/* code is removed from su.c */
-#undef CONFIG_SERIAL_MULTIPORT
-#endif
-
-/* Sanity checks */
-
-#ifdef CONFIG_SERIAL_MULTIPORT
-#ifndef CONFIG_SERIAL_SHARE_IRQ
-#define CONFIG_SERIAL_SHARE_IRQ
-#endif
-#endif
-
-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-#undef SERIAL_DEBUG_THROTTLE
-
-/* */
-
-#define RS_STROBE_TIME (10*HZ)
-#define RS_ISR_PASS_LIMIT 256
-
-#ifdef __sparc_v9__
-#define IRQ_4M(n)	(n)
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
-#else
-/* 0x20 is sun4m thing, Dave Redman heritage. See arch/sparc/kernel/irq.c. */
-#define IRQ_4M(n)	((n)|0x20)
-/* Interrupts must be shared on MrCoffee. */
-#define IRQ_T(info)	SA_SHIRQ
-#endif
-
-#define SERIAL_INLINE
-  
-#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
-#else
-#define DBG_CNT(s)
-#endif
-
-/*
- * End of serial driver configuration section.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#ifdef CONFIG_SERIAL_CONSOLE
-#include <linux/console.h>
-#include <linux/major.h>
-#endif
-#include <linux/sysrq.h>
-
-#include <asm/system.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/ebus.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#if 0 /* P3: Needed if we to support /sbin/setserial. */
-#include <asm/serial.h>
-#endif
-
-#include "sunserial.h"
-#include "sunkbd.h"
-#include "sunmouse.h"
-
-/* We are on a NS PC87303 clocked with 24.0 MHz, which results
- * in a UART clock of 1.8462 MHz.
- */
-#define BAUD_BASE	(1846200 / 16)
-
-#ifdef CONFIG_SERIAL_CONSOLE
-extern int serial_console;
-static struct console sercons;
-int su_serial_console_init(void);
-#endif
-
-/*
- * serial.c saves memory when it allocates async_info upon first open.
- * We have parts of state structure together because we do call startup
- * for keyboard and mouse.
- */
-struct su_struct {
-	int		 magic;
-	unsigned long	 port;
-	int		 baud_base;
-	int		type;			/* Hardware type: e.g. 16550 */
-	int		 irq;
-	int		 flags;
-	int		 line;
-	int		 cflag;
-
-	/* XXX Unify. */
-	int		 kbd_node;
-	int		 ms_node;
-	int		 port_node;
-
-	char		 name[16];
-
-	int		xmit_fifo_size;
-	int		custom_divisor;
-	unsigned short	close_delay;
-	unsigned short	closing_wait; /* time to wait before closing */
-	unsigned short	closing_wait2; /* no longer used... */
-
-	struct tty_struct 	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			timeout;
-	int			quot;
-	int			x_char;	/* xon/xoff character */
-	int			IER; 	/* Interrupt Enable Register */
-	int			MCR; 	/* Modem control register */
-	unsigned long		event;
-	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
-	struct tq_struct	tqueue;
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
-	struct wait_queue	*delta_msr_wait;
-
-	struct su_struct	*next_port;
-	struct su_struct	*prev_port;
-
-	int			count;
-	struct async_icount	icount;
-	struct termios		normal_termios, callout_termios;
-	unsigned long		last_active;	/* For async_struct, to be */
-};
-
-#if 0 /* P3: became unused after surgery. */
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-#endif
-
-#ifdef SERIAL_INLINE
-#define _INLINE_ inline
-#endif
-
-static char *serial_name = "Serial driver";
-static char *serial_version = "4.25.s1";
-
-static DECLARE_TASK_QUEUE(tq_serial);
-
-static struct tty_driver serial_driver, callout_driver;
-static int serial_refcount;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/*
- * IRQ_timeout		- How long the timeout should be for each IRQ
- * 				should be after the IRQ has been active.
- */
-static struct su_struct *IRQ_ports[NR_IRQS];
-#ifdef CONFIG_SERIAL_MULTIPORT
-static struct rs_multiport_struct rs_multiport[NR_IRQS];
-#endif
-static int IRQ_timeout[NR_IRQS];
-
-static void autoconfig(struct su_struct *info);
-static void change_speed(struct su_struct *info);
-static void su_wait_until_sent(struct tty_struct *tty, int timeout);
-
-/*
- * Here we define the default xmit fifo size used for each type of
- * UART
- */
-static struct serial_uart_config uart_config[] = {
-	{ "unknown", 1, 0 }, 
-	{ "8250", 1, 0 }, 
-	{ "16450", 1, 0 }, 
-	{ "16550", 1, 0 }, 
-	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, 
-	{ "cirrus", 1, 0 }, 
-	{ "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH }, 
-	{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
-		  UART_STARTECH }, 
-	{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
-	{ 0, 0}
-};
-
-
-#define NR_PORTS	4
-
-static struct su_struct su_table[NR_PORTS];
-static struct tty_struct *serial_table[NR_PORTS];
-static struct termios *serial_termios[NR_PORTS];
-static struct termios *serial_termios_locked[NR_PORTS];
-
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static struct semaphore tmp_buf_sem = MUTEX;
-
-static inline int serial_paranoia_check(struct su_struct *info,
-					kdev_t device, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-	static const char *badmagic =
-		"Warning: bad magic number for serial struct (%s) in %s\n";
-	static const char *badinfo =
-		"Warning: null su_struct for (%s) in %s\n";
-
-	if (!info) {
-		printk(badinfo, kdevname(device), routine);
-		return 1;
-	}
-	if (info->magic != SERIAL_MAGIC) {
-		printk(badmagic, kdevname(device), routine);
-		return 1;
-	}
-#endif
-	return 0;
-}
-
-#ifdef __sparc_v9__
-
-static inline
-unsigned int su_inb(struct su_struct *info, unsigned long offset)
-{
-	return inb(info->port + offset);
-}
-
-static inline void
-su_outb(struct su_struct *info, unsigned long offset, int value)
-{
-	outb(value, info->port + offset);
-}
-
-#else
-
-static inline
-unsigned int su_inb(struct su_struct *info, unsigned long offset)
-{
-	return (unsigned int)(*(volatile unsigned char *)(info->port + offset));
-}
-
-static inline void
-su_outb(struct su_struct *info, unsigned long offset, int value)
-{
-	/*
-	 * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
-	 * connected with a gate then go to SlavIO. When IRQ4 goes tristated
-	 * gate gives logical one. Since we use level triggered interrupts
-	 * we have lockup and watchdog reset. We cannot mask IRQ because
-	 * keyboard shares IRQ with us (Bob Smelik: I would not hire you).
-	 * P3: Assure that OUT2 never goes down.
-	 */
-	if (offset == UART_MCR) value |= UART_MCR_OUT2;
-	*(volatile unsigned char *)(info->port + offset) = value;
-}
-
-#endif
-
-#define serial_in(info, off)	su_inb(info, off)
-#define serial_inp(info, off)	su_inb(info, off)
-#define serial_out(info, off, val)	su_outb(info, off, val)
-#define serial_outp(info, off, val)	su_outb(info, off, val)
-
-/*
- * ------------------------------------------------------------
- * su_stop() and su_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void su_stop(struct tty_struct *tty)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->device, "su_stop"))
-		return;
-
-	save_flags(flags); cli();
-	if (info->IER & UART_IER_THRI) {
-		info->IER &= ~UART_IER_THRI;
-		serial_out(info, UART_IER, info->IER);
-	}
-	restore_flags(flags);
-}
-
-static void su_start(struct tty_struct *tty)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-	unsigned long flags;
-	
-	if (serial_paranoia_check(info, tty->device, "su_start"))
-		return;
-
-	save_flags(flags); cli();
-	if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
-		info->IER |= UART_IER_THRI;
-		serial_out(info, UART_IER, info->IER);
-	}
-	restore_flags(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * su_interrupt().  They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off.  People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible.  After you are done making modifications, it is not a bad
- * idea to do:
- * 
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static _INLINE_ void su_sched_event(struct su_struct *info, int event)
-{
-	info->event |= 1 << event;
-	queue_task(&info->tqueue, &tq_serial);
-	mark_bh(SERIAL_BH);
-}
-
-static _INLINE_ void receive_chars(struct su_struct *info, int *status,
-		struct pt_regs *regs)
-{
-	struct tty_struct *tty = info->tty;
-	unsigned char ch;
-	int ignored = 0;
-	struct	async_icount *icount;
-
-	icount = &info->icount;
-	do {
-		ch = serial_inp(info, UART_RX);
-		if (info->kbd_node) {
-			if(ch == SUNKBD_RESET) {
-                        	l1a_state.kbd_id = 1;
-                        	l1a_state.l1_down = 0;
-                	} else if(l1a_state.kbd_id) {
-                        	l1a_state.kbd_id = 0;
-                	} else if(ch == SUNKBD_L1) {
-                        	l1a_state.l1_down = 1;
-                	} else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
-                        	l1a_state.l1_down = 0;
-                	} else if(ch == SUNKBD_A && l1a_state.l1_down) {
-                        	/* whee... */
-                        	batten_down_hatches();
-                        	/* Continue execution... */
-                        	l1a_state.l1_down = 0;
-                        	l1a_state.kbd_id = 0;
-                        	return;
-                	}
-                	sunkbd_inchar(ch, regs);
-		} else {
-			sun_mouse_inbyte(ch);
-		}
-		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-			break;
-		*tty->flip.char_buf_ptr = ch;
-		icount->rx++;
-
-#ifdef SERIAL_DEBUG_INTR
-		printk("DR%02x:%02x...", ch, *status);
-#endif
-		*tty->flip.flag_buf_ptr = 0;
-		if (*status & (UART_LSR_BI | UART_LSR_PE |
-			       UART_LSR_FE | UART_LSR_OE)) {
-			/*
-			 * For statistics only
-			 */
-			if (*status & UART_LSR_BI) {
-				*status &= ~(UART_LSR_FE | UART_LSR_PE);
-				icount->brk++;
-			} else if (*status & UART_LSR_PE)
-				icount->parity++;
-			else if (*status & UART_LSR_FE)
-				icount->frame++;
-			if (*status & UART_LSR_OE)
-				icount->overrun++;
-
-			/*
-			 * Now check to see if character should be
-			 * ignored, and mask off conditions which
-			 * should be ignored.
- */
-			if (*status & info->ignore_status_mask) {
-				if (++ignored > 100)
-					break;
-				goto ignore_char;
-			}
-			*status &= info->read_status_mask;
-
-			if (*status & (UART_LSR_BI)) {
-#ifdef SERIAL_DEBUG_INTR
-				printk("handling break....");
-#endif
-				*tty->flip.flag_buf_ptr = TTY_BREAK;
-				if (info->flags & ASYNC_SAK)
-					do_SAK(tty);
-			} else if (*status & UART_LSR_PE)
-				*tty->flip.flag_buf_ptr = TTY_PARITY;
-			else if (*status & UART_LSR_FE)
-				*tty->flip.flag_buf_ptr = TTY_FRAME;
-			if (*status & UART_LSR_OE) {
-				/*
-				 * Overrun is special, since it's
-				 * reported immediately, and doesn't
-				 * affect the current character
-				 */
-				if (tty->flip.count < TTY_FLIPBUF_SIZE) {
-					tty->flip.count++;
-					tty->flip.flag_buf_ptr++;
-					tty->flip.char_buf_ptr++;
-					*tty->flip.flag_buf_ptr = TTY_OVERRUN;
-				}
-			}
-		}
-		tty->flip.flag_buf_ptr++;
-		tty->flip.char_buf_ptr++;
-		tty->flip.count++;
-	ignore_char:
-		*status = serial_inp(info, UART_LSR);
-	} while (*status & UART_LSR_DR);
-	tty_flip_buffer_push(tty);
-}
-
-static _INLINE_ void transmit_chars(struct su_struct *info, int *intr_done)
-{
-	int count;
-
-	if (info->x_char) {
-		serial_outp(info, UART_TX, info->x_char);
-		info->icount.tx++;
-		info->x_char = 0;
-		if (intr_done)
-			*intr_done = 0;
-		return;
-	}
-	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
-	    info->tty->hw_stopped) {
-		info->IER &= ~UART_IER_THRI;
-		serial_out(info, UART_IER, info->IER);
-		return;
-	}
-
-	count = info->xmit_fifo_size;
-	do {
-		serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
-		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-		info->icount.tx++;
-		if (--info->xmit_cnt <= 0)
-			break;
-	} while (--count > 0);
-	
-	if (info->xmit_cnt < WAKEUP_CHARS)
-		su_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-
-#ifdef SERIAL_DEBUG_INTR
-	printk("THRE...");
-#endif
-	if (intr_done)
-		*intr_done = 0;
-
-	if (info->xmit_cnt <= 0) {
-		info->IER &= ~UART_IER_THRI;
-		serial_out(info, UART_IER, info->IER);
-	}
-}
-
-static _INLINE_ void check_modem_status(struct su_struct *info)
-{
-	int	status;
-	struct	async_icount *icount;
-
-	status = serial_in(info, UART_MSR);
-
-	if (status & UART_MSR_ANY_DELTA) {
-		icount = &info->icount;
-		/* update input line counters */
-		if (status & UART_MSR_TERI)
-			icount->rng++;
-		if (status & UART_MSR_DDSR)
-			icount->dsr++;
-		if (status & UART_MSR_DDCD) {
-			icount->dcd++;
-#ifdef CONFIG_HARD_PPS
-			if ((info->flags & ASYNC_HARDPPS_CD) &&
-			    (status & UART_MSR_DCD))
-				hardpps();
-#endif
-	}
-		if (status & UART_MSR_DCTS)
-			icount->cts++;
-		wake_up_interruptible(&info->delta_msr_wait);
-	}
-
-	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
-		printk("ttys%d CD now %s...", info->line,
-		       (status & UART_MSR_DCD) ? "on" : "off");
-#endif		
-		if (status & UART_MSR_DCD)
-			wake_up_interruptible(&info->open_wait);
-		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
-#ifdef SERIAL_DEBUG_OPEN
-			printk("doing serial hangup...");
-#endif
-			if (info->tty)
-				tty_hangup(info->tty);
-	}
-	}
-	if (info->flags & ASYNC_CTS_FLOW) {
-		if (info->tty->hw_stopped) {
-			if (status & UART_MSR_CTS) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-				printk("CTS tx start...");
-#endif
-				info->tty->hw_stopped = 0;
-				info->IER |= UART_IER_THRI;
-				serial_out(info, UART_IER, info->IER);
-				su_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-				return;
-			}
-		} else {
-			if (!(status & UART_MSR_CTS)) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-				printk("CTS tx stop...");
-#endif
-				info->tty->hw_stopped = 1;
-				info->IER &= ~UART_IER_THRI;
-				serial_out(info, UART_IER, info->IER);
-			}
-		}
-	}
-}
-	
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-/*
- * This is the serial driver's generic interrupt routine
-	 */
-static void su_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	int status;
-	struct su_struct *info;
-	int pass_counter = 0;
-	struct su_struct *end_mark = 0;
-#ifdef CONFIG_SERIAL_MULTIPORT
-	int first_multi = 0;
-	struct su_multiport_struct *multi;
-#endif
-
-#ifdef SERIAL_DEBUG_INTR
-	printk("su_interrupt(%s)...", __irq_itoa(irq));
-#endif
-
-	info = IRQ_ports[irq];
-	if (!info)
-		return;
-	
-#ifdef CONFIG_SERIAL_MULTIPORT	
-	multi = &rs_multiport[irq];
-	if (multi->port_monitor)
-		first_multi = inb(multi->port_monitor);
-#endif
-
-	do {
-		if (!info->tty ||
-		    (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
-			if (!end_mark)
-				end_mark = info;
-			goto next;
-		}
-		end_mark = 0;
-
-		info->last_active = jiffies;
-	
-		status = serial_inp(info, UART_LSR);
-#ifdef SERIAL_DEBUG_INTR
-		printk("status = %x...", status);
-#endif
-		if (status & UART_LSR_DR)
-			receive_chars(info, &status, regs);
-		check_modem_status(info);
-		if (status & UART_LSR_THRE)
-			transmit_chars(info, 0);
-
-	next:
-		info = info->next_port;
-		if (!info) {
-			info = IRQ_ports[irq];
-			if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
-				printk("rs loop break\n");
-#endif
-				break; 	/* Prevent infinite loops */
-			}
-			continue;
-		}
-	} while (end_mark != info);
-#ifdef CONFIG_SERIAL_MULTIPORT	
-	if (multi->port_monitor)
-		printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
-		       info->irq, first_multi,
-		       inb(multi->port_monitor));
-#endif
-#ifdef SERIAL_DEBUG_INTR
-	printk("end.\n");
-#endif
-}
-#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
-	
-
-/*
- * This is the serial driver's interrupt routine for a single port
- */
-static void su_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
-{
-	int status;
-	int pass_counter = 0;
-	struct su_struct * info;
-#ifdef CONFIG_SERIAL_MULTIPORT	
-	int first_multi = 0;
-	struct rs_multiport_struct *multi;
-#endif
-
-#ifdef SERIAL_DEBUG_INTR
-	printk("su_interrupt_single(%d) int=%x ...", irq,
-			serial_inp(&su_table[0], UART_IIR));
-#endif
-	
-	info = IRQ_ports[irq];
-	if (!info || !info->tty)
-		return;
-
-#ifdef CONFIG_SERIAL_MULTIPORT	
-	multi = &rs_multiport[irq];
-	if (multi->port_monitor)
-		first_multi = inb(multi->port_monitor);
-#endif
-
-	do {
-		status = serial_inp(info, UART_LSR);
-#ifdef SERIAL_DEBUG_INTR
-		printk("status = %x...", status);
-#endif
-		if (status & UART_LSR_DR)
-			receive_chars(info, &status, regs);
-		check_modem_status(info);
-		if (status & UART_LSR_THRE)
-			transmit_chars(info, 0);
-		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
-			printk("su_single loop break.\n");
-#endif
-			break;
-		}
-	} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
-	info->last_active = jiffies;
-#ifdef CONFIG_SERIAL_MULTIPORT	
-	if (multi->port_monitor)
-		printk("rs port monitor (single) irq %s: 0x%x, 0x%x\n",
-		       __irq_itoa(info->irq), first_multi,
-		       inb(multi->port_monitor));
-#endif
-#ifdef SERIAL_DEBUG_INTR
-	printk("end.\n");
-#endif
-}
-
-#ifdef CONFIG_SERIAL_MULTIPORT	
-/*
- * This is the serial driver's for multiport boards
- */
-static void su_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
-{
-	int status;
-	struct su_struct * info;
-	int pass_counter = 0;
-	int first_multi= 0;
-	struct rs_multiport_struct *multi;
-
-#ifdef SERIAL_DEBUG_INTR
-	printk("rs_interrupt_multi(%d)...", irq);
-#endif
-
-	info = IRQ_ports[irq];
-	if (!info)
-		return;
-	multi = &rs_multiport[irq];
-	if (!multi->port1) {
-		/* Should never happen */
-		printk("rs_interrupt_multi: NULL port1!\n");
-		return;
-	}
-	if (multi->port_monitor)
-		first_multi = inb(multi->port_monitor);
-
-	while (1) {
-		if (!info->tty ||
-		    (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
-			goto next;
-
-		info->last_active = jiffies;
-
-		status = serial_inp(info, UART_LSR);
-#ifdef SERIAL_DEBUG_INTR
-		printk("status = %x...", status);
-#endif
-		if (status & UART_LSR_DR)
-			receive_chars(info, &status, regs);
-		check_modem_status(info);
-		if (status & UART_LSR_THRE)
-			transmit_chars(info, 0);
-
-	next:
-		info = info->next_port;
-		if (info)
-			continue;
-
-		info = IRQ_ports[irq];
-		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 1
-			printk("rs_multi loop break\n");
-#endif
-			break; 	/* Prevent infinite loops */
-		}
-		if (multi->port_monitor)
-			printk("rs port monitor irq %d: 0x%x, 0x%x\n",
-			       info->irq, first_multi,
-			       inb(multi->port_monitor));
-		if ((inb(multi->port1) & multi->mask1) != multi->match1)
-			continue;
-		if (!multi->port2)
-			break;
-		if ((inb(multi->port2) & multi->mask2) != multi->match2)
-			continue;
-		if (!multi->port3)
-			break;
-		if ((inb(multi->port3) & multi->mask3) != multi->match3)
-			continue;
-		if (!multi->port4)
-			break;
-		if ((inb(multi->port4) & multi->mask4) == multi->match4)
-			continue;
-		break;
-	} 
-#ifdef SERIAL_DEBUG_INTR
-	printk("end.\n");
-#endif
-}
-#endif
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * su_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using su_sched_event(), and they get done here.
- */
-static void do_serial_bh(void)
-{
-	run_task_queue(&tq_serial);
-}
-
-static void do_softint(void *private_)
-{
-	struct su_struct	*info = (struct su_struct *) private_;
-	struct tty_struct	*tty;
-	
-	tty = info->tty;
-	if (!tty)
-		return;
-
-	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
-	}
-}
-
-/*
- * This subroutine is called when the RS_TIMER goes off.  It is used
- * by the serial driver to handle ports that do not have an interrupt
- * (irq=0).  This doesn't work very well for 16450's, but gives barely
- * passable results for a 16550A.  (Although at the expense of much
- * CPU overhead).
- */
-static void su_timer(void)
-{
-	static unsigned long last_strobe = 0;
-	struct su_struct *info;
-	unsigned int	i;
-
-	if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
-		for (i=1; i < NR_IRQS; i++) {
-			info = IRQ_ports[i];
-			if (!info)
-				continue;
-			cli();
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-			if (info->next_port) {
-				do {
-					serial_out(info, UART_IER, 0);
-					info->IER |= UART_IER_THRI;
-					serial_out(info, UART_IER, info->IER);
-					info = info->next_port;
-				} while (info);
-#ifdef CONFIG_SERIAL_MULTIPORT
-				if (rs_multiport[i].port1)
-					rs_interrupt_multi(i, NULL, NULL);
-				else
-#endif
-					su_interrupt(i, NULL, NULL);
-			} else
-#endif /* CONFIG_SERIAL_SHARE_IRQ */
-				su_interrupt_single(i, NULL, NULL);
-			sti();
-		}
-	}
-	last_strobe = jiffies;
-	timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME;
-	timer_active |= 1 << RS_TIMER;
-
-	if (IRQ_ports[0]) {
-		cli();
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-		su_interrupt(0, NULL, NULL);
-#else
-		su_interrupt_single(0, NULL, NULL);
-#endif
-		sti();
-
-		timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
-	}
-}
-
-/*
- * ---------------------------------------------------------------
- * Low level utility subroutines for the serial driver:  routines to
- * figure out the appropriate timeout for an interrupt chain, routines
- * to initialize and startup a serial port, and routines to shutdown a
- * serial port.  Useful stuff like that.
- * ---------------------------------------------------------------
- */
-
-/*
- * This routine figures out the correct timeout for a particular IRQ.
- * It uses the smallest timeout of all of the serial ports in a
- * particular interrupt chain.  Now only used for IRQ 0....
- */
-static void figure_IRQ_timeout(int irq)
-{
-	struct su_struct	*info;
-	int	timeout = 60*HZ;	/* 60 seconds === a long time :-) */
-
-	info = IRQ_ports[irq];
-	if (!info) {
-		IRQ_timeout[irq] = 60*HZ;
-		return;
-	}
-	while (info) {
-		if (info->timeout < timeout)
-			timeout = info->timeout;
-		info = info->next_port;
-	}
-	if (!irq)
-		timeout = timeout / 2;
-	IRQ_timeout[irq] = timeout ? timeout : 1;
-}
-
-static int startup(struct su_struct *info)
-{
-	unsigned long flags;
-	int	retval=0;
-	void (*handler)(int, void *, struct pt_regs *);
-	unsigned long page;
-#ifdef CONFIG_SERIAL_MANY_PORTS
-	unsigned short ICP;
-#endif
-
-	page = get_free_page(GFP_KERNEL);
-	if (!page)
-		return -ENOMEM;
-
-	save_flags(flags); cli();
-
-	if (info->flags & ASYNC_INITIALIZED) {
-		free_page(page);
-		goto errout;
-	}
-
-	if (info->port == 0 || info->type == PORT_UNKNOWN) {
-		if (info->tty)
-			set_bit(TTY_IO_ERROR, &info->tty->flags);
-		free_page(page);
-		goto errout;
-	}
-	if (info->xmit_buf)
-		free_page(page);
-	else
-		info->xmit_buf = (unsigned char *) page;
-
-	if (uart_config[info->type].flags & UART_STARTECH) {
-		/* Wake up UART */
-		serial_outp(info, UART_LCR, 0xBF);
-		serial_outp(info, UART_EFR, UART_EFR_ECB);
-		serial_outp(info, UART_IER, 0);
-		serial_outp(info, UART_EFR, 0);
-		serial_outp(info, UART_LCR, 0);
-	}
-
-	if (info->type == PORT_16750) {
-		/* Wake up UART */
-		serial_outp(info, UART_IER, 0);
-	}
-
-	/*
-	 * Clear the FIFO buffers and disable them
-	 * (they will be reenabled in change_speed())
-	 */
-	if (uart_config[info->type].flags & UART_CLEAR_FIFO)
-		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
-					     UART_FCR_CLEAR_XMIT));
-
-	/*
-	 * At this point there's no way the LSR could still be 0xFF;
-	 * if it is, then bail out, because there's likely no UART
-	 * here.
-	 */
-	if (serial_inp(info, UART_LSR) == 0xff) {
-		if (capable(CAP_SYS_ADMIN)) {
-			if (info->tty)
-				set_bit(TTY_IO_ERROR, &info->tty->flags);
-		} else
-			retval = -ENODEV;
-		goto errout;
-	}
-
-	/*
-	 * Allocate the IRQ if necessary
-	 */
-	if (info->irq && (!IRQ_ports[info->irq] ||
-			  !IRQ_ports[info->irq]->next_port)) {
-		if (IRQ_ports[info->irq]) {
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-			free_irq(IRQ_4M(info->irq), info);
-#ifdef CONFIG_SERIAL_MULTIPORT				
-			if (rs_multiport[info->irq].port1)
-				handler = rs_interrupt_multi;
-			else
-#endif
-				handler = su_interrupt;
-#else
-			retval = -EBUSY;
-			goto errout;
-#endif /* CONFIG_SERIAL_SHARE_IRQ */
-		} else 
-			handler = su_interrupt_single;
-
-		retval = request_irq(IRQ_4M(info->irq), handler, IRQ_T(info),
-				     "serial", info);
-		if (retval) {
-			if (capable(CAP_SYS_ADMIN)) {
-				if (info->tty)
-					set_bit(TTY_IO_ERROR,
-						&info->tty->flags);
-				retval = 0;
-			}
-			goto errout;
-		}
-	}
-
-	/*
-	 * Insert serial port into IRQ chain.
-	 */
-	info->prev_port = 0;
-	info->next_port = IRQ_ports[info->irq];
-	if (info->next_port)
-		info->next_port->prev_port = info;
-	IRQ_ports[info->irq] = info;
-	figure_IRQ_timeout(info->irq);
-
-	/*
-	 * Clear the interrupt registers.
-	 */
-     /* (void) serial_inp(info, UART_LSR); */   /* (see above) */
-	(void) serial_inp(info, UART_RX);
-	(void) serial_inp(info, UART_IIR);
-	(void) serial_inp(info, UART_MSR);
-
-	/*
-	 * Now, initialize the UART 
-	 */
-	serial_outp(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
-
-	info->MCR = 0;
-	if (info->tty->termios->c_cflag & CBAUD)
-		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#ifdef CONFIG_SERIAL_MANY_PORTS
-	if (info->flags & ASYNC_FOURPORT) {
-		if (info->irq == 0)
-			info->MCR |= UART_MCR_OUT1;
-	} else
-#endif
-	{
-		if (info->irq != 0)
-			info->MCR |= UART_MCR_OUT2;
-	}
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-	/*
-	 * DEC did something gratutiously wrong....
-	 */
-	info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
-	serial_outp(info, UART_MCR, info->MCR);
-
-	/*
-	 * Finally, enable interrupts
-	 */
-	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-	serial_outp(info, UART_IER, info->IER);	/* enable interrupts */
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-	if (info->flags & ASYNC_FOURPORT) {
-		/* Enable interrupts on the AST Fourport board */
-		ICP = (info->port & 0xFE0) | 0x01F;
-		outb_p(0x80, ICP);
-		(void) inb_p(ICP);
-	}
-#endif
-
-	/*
-	 * And clear the interrupt registers again for luck.
-	 */
-	(void)serial_inp(info, UART_LSR);
-	(void)serial_inp(info, UART_RX);
-	(void)serial_inp(info, UART_IIR);
-	(void)serial_inp(info, UART_MSR);
-
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-	/*
-	 * Set up serial timers...
-	 */
-	timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
-	timer_active |= 1 << RS_TIMER;
-
-	/*
-	 * Set up the tty->alt_speed kludge
-	 */
-	if (info->tty) {
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-			info->tty->alt_speed = 57600;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-			info->tty->alt_speed = 115200;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-			info->tty->alt_speed = 230400;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-			info->tty->alt_speed = 460800;
-	}
-
-	/*
-	 * and set the speed of the serial port
-	 */
-	change_speed(info);
-
-	info->flags |= ASYNC_INITIALIZED;
-	restore_flags(flags);
-	return 0;
-
-errout:
-	restore_flags(flags);
-	return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct su_struct *info)
-{
-	unsigned long	flags;
-	int		retval;
-
-	if (!(info->flags & ASYNC_INITIALIZED))
-		return;
-
-	save_flags(flags); cli(); /* Disable interrupts */
-
-	/*
-	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
-	 * here so the queue might never be waken up
-	 */
-	wake_up_interruptible(&info->delta_msr_wait);
-	
-	/*
-	 * First unlink the serial port from the IRQ chain...
-	 */
-	if (info->next_port)
-		info->next_port->prev_port = info->prev_port;
-	if (info->prev_port)
-		info->prev_port->next_port = info->next_port;
-	else
-		IRQ_ports[info->irq] = info->next_port;
-	figure_IRQ_timeout(info->irq);
-
-	/*
-	 * Free the IRQ, if necessary
-	 */
-	if (info->irq && (!IRQ_ports[info->irq] ||
-			  !IRQ_ports[info->irq]->next_port)) {
-		if (IRQ_ports[info->irq]) {
-			free_irq(IRQ_4M(info->irq), info);
-			retval = request_irq(IRQ_4M(info->irq),
-			    su_interrupt_single, IRQ_T(info), "serial", info);
-			
-			if (retval)
-				printk("serial shutdown: request_irq: error %d"
-				       "  Couldn't reacquire IRQ.\n", retval);
-		} else
-			free_irq(IRQ_4M(info->irq), info);
-	}
-
-	if (info->xmit_buf) {
-		free_page((unsigned long) info->xmit_buf);
-		info->xmit_buf = 0;
-	}
-
-	info->IER = 0;
-	serial_outp(info, UART_IER, 0x00);	/* disable all intrs */
-#ifdef CONFIG_SERIAL_MANY_PORTS
-	if (info->flags & ASYNC_FOURPORT) {
-		/* reset interrupts on the AST Fourport board */
-		(void) inb((info->port & 0xFE0) | 0x01F);
-		info->MCR |= UART_MCR_OUT1;
-	} else
-#endif
-		info->MCR &= ~UART_MCR_OUT2;
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-	/*
-	 * DEC did something gratutiously wrong....
-	 */
-	info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
-
-	/* disable break condition */
-	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
-
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
-		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-	serial_outp(info, UART_MCR, info->MCR);
-
-	/* disable FIFO's */	
-	serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
-				     UART_FCR_CLEAR_XMIT));
-	(void)serial_in(info, UART_RX);    /* read data port to reset things */
-
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-	if (uart_config[info->type].flags & UART_STARTECH) {
-		/* Arrange to enter sleep mode */
-		serial_outp(info, UART_LCR, 0xBF);
-		serial_outp(info, UART_EFR, UART_EFR_ECB);
-		serial_outp(info, UART_IER, UART_IERX_SLEEP);
-		serial_outp(info, UART_LCR, 0);
-	}
-	if (info->type == PORT_16750) {
-		/* Arrange to enter sleep mode */
-		serial_outp(info, UART_IER, UART_IERX_SLEEP);
-	}
-	info->flags &= ~ASYNC_INITIALIZED;
-	restore_flags(flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct su_struct *info)
-{
-	unsigned short port;
-	int	quot = 0, baud_base, baud;
-	unsigned cflag, cval, fcr = 0;
-	int	bits;
-	unsigned long flags;
-
-	if (!info->tty || !info->tty->termios)
-		return;
-	cflag = info->tty->termios->c_cflag;
-	if (!(port = info->port))
-		return;
-
-	/* byte size and parity */
-	switch (cflag & CSIZE) {
-	      case CS5: cval = 0x00; bits = 7; break;
-	      case CS6: cval = 0x01; bits = 8; break;
-	      case CS7: cval = 0x02; bits = 9; break;
-	      case CS8: cval = 0x03; bits = 10; break;
-		/* Never happens, but GCC is too dumb to figure it out */
-	      default:  cval = 0x00; bits = 7; break;
-	}
-	if (cflag & CSTOPB) {
-		cval |= 0x04;
-		bits++;
-	}
-	if (cflag & PARENB) {
-		cval |= UART_LCR_PARITY;
-		bits++;
-	}
-	if (!(cflag & PARODD))
-		cval |= UART_LCR_EPAR;
-#ifdef CMSPAR
-	if (cflag & CMSPAR)
-		cval |= UART_LCR_SPAR;
-#endif
-
-	/* Determine divisor based on baud rate */
-	baud = tty_get_baud_rate(info->tty);
-	baud_base = info->baud_base;
-	if (baud == 38400 &&
-	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
-		quot = info->custom_divisor;
-	else {
-		if (baud == 134)
-			/* Special case since 134 is really 134.5 */
-			quot = (2*baud_base / 269);
-		else if (baud)
-			quot = baud_base / baud;
-	}
-	/* If the quotient is ever zero, default to 9600 bps */
-	if (!quot)
-		quot = baud_base / 9600;
-	info->quot = quot;
-	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
-	info->timeout += HZ/50;		/* Add .02 seconds of slop */
-
-	/* Set up FIFO's */
-	if (uart_config[info->type].flags & UART_USE_FIFO) {
-		if ((info->baud_base / quot) < 2400)
-		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
-		else
-			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
-	}
-	if (info->type == PORT_16750)
-		fcr |= UART_FCR7_64BYTE;
-
-	/* CTS flow control flag and modem status interrupts */
-	info->IER &= ~UART_IER_MSI;
-	if (info->flags & ASYNC_HARDPPS_CD)
-		info->IER |= UART_IER_MSI;
-	if (cflag & CRTSCTS) {
-		info->flags |= ASYNC_CTS_FLOW;
-		info->IER |= UART_IER_MSI;
-	} else
-		info->flags &= ~ASYNC_CTS_FLOW;
-	if (cflag & CLOCAL)
-		info->flags &= ~ASYNC_CHECK_CD;
-	else {
-		info->flags |= ASYNC_CHECK_CD;
-		info->IER |= UART_IER_MSI;
-	}
-	serial_out(info, UART_IER, info->IER);
-
-	/*
-	 * Set up parity check flag
-	 */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-	if (I_INPCK(info->tty))
-		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
-		info->read_status_mask |= UART_LSR_BI;
-
-	/*
-	 * Characters to ignore
-	 */
-	info->ignore_status_mask = 0;
-	if (I_IGNPAR(info->tty))
-		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
-	if (I_IGNBRK(info->tty)) {
-		info->ignore_status_mask |= UART_LSR_BI;
-		/*
-		 * If we're ignore parity and break indicators, ignore 
-		 * overruns too.  (For real raw support).
-		 */
-		if (I_IGNPAR(info->tty))
-			info->ignore_status_mask |= UART_LSR_OE;
-	}
-	/*
-	 * !!! ignore all characters if CREAD is not set
-	 */
-	if ((cflag & CREAD) == 0)
-		info->ignore_status_mask |= UART_LSR_DR;
-	save_flags(flags); cli();
-	if (uart_config[info->type].flags & UART_STARTECH) {
-		serial_outp(info, UART_LCR, 0xBF);
-		serial_outp(info, UART_EFR,
-			    (cflag & CRTSCTS) ? UART_EFR_CTS : 0);
-	}
-	serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
-	serial_outp(info, UART_DLL, quot & 0xff);	/* LS of divisor */
-	serial_outp(info, UART_DLM, quot >> 8);		/* MS of divisor */
-	if (info->type == PORT_16750)
-		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
-	serial_outp(info, UART_LCR, cval);		/* reset DLAB */
-	if (info->type != PORT_16750)
-		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
-	restore_flags(flags);
-	info->quot = quot;
-}
-
-static void su_put_char(struct tty_struct *tty, unsigned char ch)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->device, "su_put_char"))
-		return;
-
-	if (!tty || !info->xmit_buf)
-		return;
-
-	save_flags(flags); cli();
-	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
-		restore_flags(flags);
-		return;
-	}
-
-	info->xmit_buf[info->xmit_head++] = ch;
-	info->xmit_head &= SERIAL_XMIT_SIZE-1;
-	info->xmit_cnt++;
-	restore_flags(flags);
-}
-
-static void su_put_char_kbd(unsigned char c)
-{
-	struct su_struct *info;
-	int i;
-	int lsr;
-
-	for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
-		if (info->kbd_node != 0)
-			break;
-	}
-	if (i >= NR_PORTS) {
-		/* XXX P3: I would put a printk here but it may flood. */
-		return;
-	}
-
-	do {
-		lsr = serial_in(info, UART_LSR);
-	} while (!(lsr & UART_LSR_THRE));
-
-	/* Send the character out. */
-	su_outb(info, UART_TX, c);
-}
-
-static void su_change_mouse_baud(int baud)
-{
-	struct su_struct *info = su_table;
-	int i;
-
-	for (i = 0, info = su_table; i < NR_PORTS; i++, info++)
-		if (info->kbd_node != 0) break;
-	if (i >= NR_PORTS) return;
-
-	info->cflag &= ~(CBAUDEX | CBAUD);
-	switch(baud) {
-		case 1200:
-			info->cflag |= B1200;
-			break;
-		case 2400:
-			info->cflag |= B2400;
-			break;
-		case 4800:
-			info->cflag |= B4800;
-			break;
-		case 9600:
-			info->cflag |= B9600;
-			break;
-		default:
-			printk("su_change_mouse_baud: unknown baud rate %d, "
-			       "defaulting to 1200\n", baud);
-			info->cflag |= 1200;
-			break;
-	}
-	change_speed(info);
-}
-
-static void su_flush_chars(struct tty_struct *tty)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-	unsigned long flags;
-				
-	if (serial_paranoia_check(info, tty->device, "su_flush_chars"))
-		return;
-
-	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-	    !info->xmit_buf)
-		return;
-
-	save_flags(flags); cli();
-	info->IER |= UART_IER_THRI;
-	serial_out(info, UART_IER, info->IER);
-	restore_flags(flags);
-}
-
-static int su_write(struct tty_struct * tty, int from_user,
-		    const unsigned char *buf, int count)
-{
-	int	c, ret = 0;
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->device, "su_write"))
-		return 0;
-
-	if (!tty || !info->xmit_buf || !tmp_buf)
-		return 0;
-
-	save_flags(flags);
-	if (from_user) {
-		down(&tmp_buf_sem);
-		while (1) {
-			c = MIN(count,
-				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				    SERIAL_XMIT_SIZE - info->xmit_head));
-			if (c <= 0)
-				break;
-
-			c -= copy_from_user(tmp_buf, buf, c);
-			if (!c) {
-				if (!ret)
-					ret = -EFAULT;
-				break;
-			}
-			cli();
-			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				       SERIAL_XMIT_SIZE - info->xmit_head));
-			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-			info->xmit_head = ((info->xmit_head + c) &
-					   (SERIAL_XMIT_SIZE-1));
-			info->xmit_cnt += c;
-			restore_flags(flags);
-			buf += c;
-			count -= c;
-			ret += c;
-		}
-		up(&tmp_buf_sem);
-	} else {
-		while (1) {
-			cli();		
-			c = MIN(count,
-				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				    SERIAL_XMIT_SIZE - info->xmit_head));
-			if (c <= 0) {
-				restore_flags(flags);
-				break;
-			}
-			memcpy(info->xmit_buf + info->xmit_head, buf, c);
-			info->xmit_head = ((info->xmit_head + c) &
-					   (SERIAL_XMIT_SIZE-1));
-			info->xmit_cnt += c;
-			restore_flags(flags);
-			buf += c;
-			count -= c;
-			ret += c;
-		}
-	}
-	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
-	    !(info->IER & UART_IER_THRI)) {
-		info->IER |= UART_IER_THRI;
-		serial_out(info, UART_IER, info->IER);
-	}
-	return ret;
-}
-
-static int su_write_room(struct tty_struct *tty)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-	int	ret;
-
-	if (serial_paranoia_check(info, tty->device, "su_write_room"))
-		return 0;
-	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-	if (ret < 0)
-		ret = 0;
-	return ret;
-}
-
-static int su_chars_in_buffer(struct tty_struct *tty)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-				
-	if (serial_paranoia_check(info, tty->device, "su_chars_in_buffer"))
-		return 0;
-	return info->xmit_cnt;
-}
-
-static void su_flush_buffer(struct tty_struct *tty)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-
-	if (serial_paranoia_check(info, tty->device, "su_flush_buffer"))
-		return;
-	cli();
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	sti();
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void su_send_xchar(struct tty_struct *tty, char ch)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-
-	if (serial_paranoia_check(info, tty->device, "su_send_char"))
-		return;
-
-	info->x_char = ch;
-	if (ch) {
-		/* Make sure transmit interrupts are on */
-		info->IER |= UART_IER_THRI;
-		serial_out(info, UART_IER, info->IER);
-	}
-}
-
-/*
- * ------------------------------------------------------------
- * su_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void su_throttle(struct tty_struct * tty)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-	
-	printk("throttle %s: %d....\n", tty_name(tty, buf),
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->device, "su_throttle"))
-		return;
-	
-	if (I_IXOFF(tty))
-		su_send_xchar(tty, STOP_CHAR(tty));
-
-	if (tty->termios->c_cflag & CRTSCTS)
-		info->MCR &= ~UART_MCR_RTS;
-
-	cli();
-	serial_out(info, UART_MCR, info->MCR);
-	sti();
-}
-
-static void su_unthrottle(struct tty_struct * tty)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-	
-	printk("unthrottle %s: %d....\n", tty_name(tty, buf),
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->device, "su_unthrottle"))
-		return;
-	
-	if (I_IXOFF(tty)) {
-		if (info->x_char)
-			info->x_char = 0;
-		else
-			su_send_xchar(tty, START_CHAR(tty));
-	}
-	if (tty->termios->c_cflag & CRTSCTS)
-		info->MCR |= UART_MCR_RTS;
-	cli();
-	serial_out(info, UART_MCR, info->MCR);
-	sti();
-}
-
-/*
- * ------------------------------------------------------------
- * su_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-#if 0
-static int get_serial_info(struct su_struct * info,
-			   struct serial_struct * retinfo)
-{
-	struct serial_struct tmp;
-
-	if (!retinfo)
-		return -EFAULT;
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.type = info->type;
-	tmp.line = info->line;
-	tmp.port = info->port;
-	tmp.irq = info->irq;
-	tmp.flags = info->flags;
-	tmp.xmit_fifo_size = info->xmit_fifo_size;
-	tmp.baud_base = info->baud_base;
-	tmp.close_delay = info->close_delay;
-	tmp.closing_wait = info->closing_wait;
-	tmp.custom_divisor = info->custom_divisor;
-	tmp.hub6 = 0;
-	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
-		return -EFAULT;
-	return 0;
-}
-
-static int set_serial_info(struct su_struct * info,
-			   struct serial_struct * new_info)
-{
-	struct serial_struct new_serial;
- 	struct serial_state old_state, *state;
-	unsigned int		i,change_irq,change_port;
-	int 			retval = 0;
-
-	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
-		return -EFAULT;
-	old_state = *state;
-  
-	change_irq = new_serial.irq != state->irq;
-	change_port = (new_serial.port != state->port);
-  
-	if (!capable(CAP_SYS_ADMIN)) {
-		if (change_irq || change_port ||
-		    (new_serial.baud_base != state->baud_base) ||
-		    (new_serial.type != state->type) ||
-		    (new_serial.close_delay != state->close_delay) ||
-		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
-		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
-		     (state->flags & ~ASYNC_USR_MASK)))
-			return -EPERM;
-		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
-			       (new_serial.flags & ASYNC_USR_MASK));
-		state->custom_divisor = new_serial.custom_divisor;
-		goto check_and_exit;
-	}
-
-	new_serial.irq = irq_cannonicalize(new_serial.irq);
-
-	if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
-	    (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
-		return -EINVAL;
-	}
-
-	/* Make sure address is not already in use */
-	if (new_serial.type) {
-		for (i = 0 ; i < NR_PORTS; i++)
-			if ((state != &su_table[i]) &&
-			    (su_table[i].port == new_serial.port) &&
-			    su_table[i].type)
-				return -EADDRINUSE;
-	}
-
-	if ((change_port || change_irq) && (state->count > 1))
-		return -EBUSY;
-
-	/*
-	 * OK, past this point, all the error checking has been done.
-	 * At this point, we start making changes.....
-	 */
-
-	state->baud_base = new_serial.baud_base;
-	state->flags = ((state->flags & ~ASYNC_FLAGS) |
-			(new_serial.flags & ASYNC_FLAGS));
-	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
-		       (info->flags & ASYNC_INTERNAL_FLAGS));
-	state->custom_divisor = new_serial.custom_divisor;
-	state->type = new_serial.type;
-	state->close_delay = new_serial.close_delay * HZ/100;
-	state->closing_wait = new_serial.closing_wait * HZ/100;
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-	info->xmit_fifo_size = state->xmit_fifo_size =
-		new_serial.xmit_fifo_size;
-
-	release_region(state->port,8);
-	if (change_port || change_irq) {
-		/*
-		 * We need to shutdown the serial port at the old
-		 * port/irq combination.
-		 */
-		shutdown(info);
-		state->irq = new_serial.irq;
-		info->port = state->port = new_serial.port;
-		info->hub6 = state->hub6 = new_serial.hub6;
-	}
-	if (state->type != PORT_UNKNOWN)
-		request_region(state->port,8,"serial(set)");
-
-check_and_exit:
-	if (!state->port || !state->type)
-		return 0;
-	if (state->type != old_state.type)
-		info->xmit_fifo_size = state->xmit_fifo_size =
-			uart_config[state->type].dfl_xmit_fifo_size;
-	if (state->flags & ASYNC_INITIALIZED) {
-		if (((old_state.flags & ASYNC_SPD_MASK) !=
-		     (state->flags & ASYNC_SPD_MASK)) ||
-		    (old_state.custom_divisor != state->custom_divisor)) {
-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-				info->tty->alt_speed = 57600;
-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-				info->tty->alt_speed = 115200;
-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-				info->tty->alt_speed = 230400;
-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-				info->tty->alt_speed = 460800;
-			change_speed(info);
-		}
-	} else
-		retval = startup(info);
-	return retval;
-}
-#endif
-
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * 	    is emptied.  On bus types like RS485, the transmitter must
- * 	    release the bus after transmitting. This must be done when
- * 	    the transmit shift register is empty, not be done when the
- * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
- */
-static int get_lsr_info(struct su_struct * info, unsigned int *value)
-{
-	unsigned char status;
-	unsigned int result;
-
-	cli();
-	status = serial_in(info, UART_LSR);
-	sti();
-	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-	return put_user(result,value);
-}
-
-
-static int get_modem_info(struct su_struct * info, unsigned int *value)
-{
-	unsigned char control, status;
-	unsigned int result;
-
-	control = info->MCR;
-	cli();
-	status = serial_in(info, UART_MSR);
-	sti();
-	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
-		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
-#ifdef TIOCM_OUT1
-		| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
-		| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
-#endif
-		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
-		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
-		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
-		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	return put_user(result,value);
-}
-
-static int set_modem_info(struct su_struct * info, unsigned int cmd,
-			  unsigned int *value)
-{
-	int error;
-	unsigned int arg;
-
-	error = get_user(arg, value);
-	if (error)
-		return error;
-	switch (cmd) {
-	case TIOCMBIS: 
-		if (arg & TIOCM_RTS)
-			info->MCR |= UART_MCR_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR |= UART_MCR_DTR;
-#ifdef TIOCM_OUT1
-		if (arg & TIOCM_OUT1)
-			info->MCR |= UART_MCR_OUT1;
-		if (arg & TIOCM_OUT2)
-			info->MCR |= UART_MCR_OUT2;
-#endif
-		break;
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS)
-			info->MCR &= ~UART_MCR_RTS;
-		if (arg & TIOCM_DTR)
-			info->MCR &= ~UART_MCR_DTR;
-#ifdef TIOCM_OUT1
-		if (arg & TIOCM_OUT1)
-			info->MCR &= ~UART_MCR_OUT1;
-		if (arg & TIOCM_OUT2)
-			info->MCR &= ~UART_MCR_OUT2;
-#endif
-		break;
-	case TIOCMSET:
-		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
-#ifdef TIOCM_OUT1
-					    UART_MCR_OUT1 |
-					    UART_MCR_OUT2 |
-#endif
-					    UART_MCR_DTR))
-			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
-#ifdef TIOCM_OUT1
-			     | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
-			     | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
-#endif
-			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
-		break;
-	default:
-		return -EINVAL;
-	}
-	cli();
-	serial_out(info, UART_MCR, info->MCR);
-	sti();
-	return 0;
-}
-
-#if 0
-static int do_autoconfig(struct su_struct * info)
-{
-	int			retval;
-	
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-
-	if (info->state->count > 1)
-		return -EBUSY;
-	
-	shutdown(info);
-
-	autoconfig(info->state);
-	if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0))
-		info->state->irq = detect_uart_irq(info->state);
-
-	retval = startup(info);
-	if (retval)
-		return retval;
-	return 0;
-}
-#endif
-
-/*
- * su_break() --- routine which turns the break handling on or off
- */
-static void su_break(struct tty_struct *tty, int break_state)
-{
-	struct su_struct * info = (struct su_struct *)tty->driver_data;
-	unsigned long flags;
-	
-	if (serial_paranoia_check(info, tty->device, "su_break"))
-		return;
-
-	if (!info->port)
-		return;
-	save_flags(flags); cli();
-	if (break_state == -1)
-		serial_out(info, UART_LCR,
-			   serial_inp(info, UART_LCR) | UART_LCR_SBC);
-	else
-		serial_out(info, UART_LCR,
-			   serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
-	restore_flags(flags);
-}
-
-#ifdef CONFIG_SERIAL_MULTIPORT
-static int get_multiport_struct(struct su_struct * info,
-				struct serial_multiport_struct *retinfo)
-{
-	struct serial_multiport_struct ret;
-	struct rs_multiport_struct *multi;
-	
-	multi = &rs_multiport[info->state->irq];
-
-	ret.port_monitor = multi->port_monitor;
-	
-	ret.port1 = multi->port1;
-	ret.mask1 = multi->mask1;
-	ret.match1 = multi->match1;
-	
-	ret.port2 = multi->port2;
-	ret.mask2 = multi->mask2;
-	ret.match2 = multi->match2;
-	
-	ret.port3 = multi->port3;
-	ret.mask3 = multi->mask3;
-	ret.match3 = multi->match3;
-	
-	ret.port4 = multi->port4;
-	ret.mask4 = multi->mask4;
-	ret.match4 = multi->match4;
-
-	ret.irq = info->state->irq;
-
-	if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
-		return -EFAULT;
-	return 0;
-}
-
-static int set_multiport_struct(struct su_struct * info,
-				struct serial_multiport_struct *in_multi)
-{
-	struct serial_multiport_struct new_multi;
-	struct rs_multiport_struct *multi;
-	struct serial_state *state;
-	int	was_multi, now_multi;
-	int	retval;
-	void (*handler)(int, void *, struct pt_regs *);
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	state = info->state;
-	
-	if (copy_from_user(&new_multi, in_multi,
-			   sizeof(struct serial_multiport_struct)))
-		return -EFAULT;
-	
-	if (new_multi.irq != state->irq || state->irq == 0 ||
-	    !IRQ_ports[state->irq])
-		return -EINVAL;
-
-	multi = &rs_multiport[state->irq];
-	was_multi = (multi->port1 != 0);
-	
-	multi->port_monitor = new_multi.port_monitor;
-	
-	if (multi->port1)
-		release_region(multi->port1,1);
-	multi->port1 = new_multi.port1;
-	multi->mask1 = new_multi.mask1;
-	multi->match1 = new_multi.match1;
-	if (multi->port1)
-		request_region(multi->port1,1,"serial(multiport1)");
-
-	if (multi->port2)
-		release_region(multi->port2,1);
-	multi->port2 = new_multi.port2;
-	multi->mask2 = new_multi.mask2;
-	multi->match2 = new_multi.match2;
-	if (multi->port2)
-		request_region(multi->port2,1,"serial(multiport2)");
-
-	if (multi->port3)
-		release_region(multi->port3,1);
-	multi->port3 = new_multi.port3;
-	multi->mask3 = new_multi.mask3;
-	multi->match3 = new_multi.match3;
-	if (multi->port3)
-		request_region(multi->port3,1,"serial(multiport3)");
-
-	if (multi->port4)
-		release_region(multi->port4,1);
-	multi->port4 = new_multi.port4;
-	multi->mask4 = new_multi.mask4;
-	multi->match4 = new_multi.match4;
-	if (multi->port4)
-		request_region(multi->port4,1,"serial(multiport4)");
-
-	now_multi = (multi->port1 != 0);
-	
-	if (IRQ_ports[state->irq]->next_port &&
-	    (was_multi != now_multi)) {
-		free_irq(IRQ_4M(state->irq), info);
-		if (now_multi)
-			handler = rs_interrupt_multi;
-		else
-			handler = su_interrupt;
-
-		retval = request_irq(IRQ_4M(state->irq), handler, IRQ_T(info),
-				     "serial", info);
-		if (retval) {
-			printk("Couldn't reallocate serial interrupt "
-			       "driver!!\n");
-		}
-	}
-
-	return 0;
-}
-#endif
-
-static int su_ioctl(struct tty_struct *tty, struct file * file,
-		    unsigned int cmd, unsigned long arg)
-{
-	int error;
-	struct su_struct * info = (struct su_struct *)tty->driver_data;
-	struct async_icount cprev, cnow;	/* kernel counter temps */
-	struct serial_icounter_struct *p_cuser;	/* user space */
-
-	if (serial_paranoia_check(info, tty->device, "su_ioctl"))
-		return -ENODEV;
-
-	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
-	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
-		    return -EIO;
-	}
-
-	switch (cmd) {
-		case TIOCMGET:
-			return get_modem_info(info, (unsigned int *) arg);
-		case TIOCMBIS:
-		case TIOCMBIC:
-		case TIOCMSET:
-			return set_modem_info(info, cmd, (unsigned int *) arg);
-#if 0
-		case TIOCGSERIAL:
-			return get_serial_info(info,
-					       (struct serial_struct *) arg);
-		case TIOCSSERIAL:
-			return set_serial_info(info,
-					       (struct serial_struct *) arg);
-		case TIOCSERCONFIG:
-			return do_autoconfig(info);
-#endif
-
-		case TIOCSERGETLSR: /* Get line status register */
-			return get_lsr_info(info, (unsigned int *) arg);
-
-#if 0
-		case TIOCSERGSTRUCT:
-			if (copy_to_user((struct async_struct *) arg,
-					 info, sizeof(struct async_struct)))
-				return -EFAULT;
-			return 0;
-#endif
-				
-#ifdef CONFIG_SERIAL_MULTIPORT
-		case TIOCSERGETMULTI:
-			return get_multiport_struct(info,
-				       (struct serial_multiport_struct *) arg);
-		case TIOCSERSETMULTI:
-			return set_multiport_struct(info,
-				       (struct serial_multiport_struct *) arg);
-#endif
-			
-		/*
-		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-		 * - mask passed in arg for lines of interest
- 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-		 * Caller should use TIOCGICOUNT to see which one it was
-		 */
-		case TIOCMIWAIT:
-			cli();
-			/* note the counters on entry */
-			cprev = info->icount;
-			sti();
-			while (1) {
-				interruptible_sleep_on(&info->delta_msr_wait);
-				/* see if a signal did it */
-				if (signal_pending(current))
-					return -ERESTARTSYS;
-				cli();
-				cnow = info->icount; /* atomic copy */
-				sti();
-				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
-				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-					return -EIO; /* no change => error */
-				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
-					return 0;
-				}
-				cprev = cnow;
-			}
-			/* NOTREACHED */
-
-		/* 
-		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-		 * Return: write counters to the user passed counter struct
-		 * NB: both 1->0 and 0->1 transitions are counted except for
-		 *     RI where only 0->1 is counted.
-		 */
-		case TIOCGICOUNT:
-			cli();
-			cnow = info->icount;
-			sti();
-			p_cuser = (struct serial_icounter_struct *) arg;
-			error = put_user(cnow.cts, &p_cuser->cts);
-			if (error) return error;
-			error = put_user(cnow.dsr, &p_cuser->dsr);
-			if (error) return error;
-			error = put_user(cnow.rng, &p_cuser->rng);
-			if (error) return error;
-			error = put_user(cnow.dcd, &p_cuser->dcd);
-			if (error) return error;
-			return 0;
-
-		default:
-			return -ENOIOCTLCMD;
-		}
-	/* return 0; */ /* Trigger warnings is fall through by a chance. */
-}
-
-static void su_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-
-	if (   (tty->termios->c_cflag == old_termios->c_cflag)
-	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
-		== RELEVANT_IFLAG(old_termios->c_iflag)))
-	  return;
-
-	change_speed(info);
-
-	/* Handle transition to B0 status */
-	if ((old_termios->c_cflag & CBAUD) &&
-	    !(tty->termios->c_cflag & CBAUD)) {
-		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-		cli();
-		serial_out(info, UART_MCR, info->MCR);
-		sti();
-	}
-	
-	/* Handle transition away from B0 status */
-	if (!(old_termios->c_cflag & CBAUD) &&
-	    (tty->termios->c_cflag & CBAUD)) {
-		info->MCR |= UART_MCR_DTR;
-		if (!(tty->termios->c_cflag & CRTSCTS) || 
-		    !test_bit(TTY_THROTTLED, &tty->flags)) {
-			info->MCR |= UART_MCR_RTS;
-		}
-		cli();
-		serial_out(info, UART_MCR, info->MCR);
-		sti();
-	}
-	
-	/* Handle turning off CRTSCTS */
-	if ((old_termios->c_cflag & CRTSCTS) &&
-	    !(tty->termios->c_cflag & CRTSCTS)) {
-		tty->hw_stopped = 0;
-		su_start(tty);
-	}
-
-#if 0
-	/*
-	 * No need to wake up processes in open wait, since they
-	 * sample the CLOCAL flag once, and don't recheck it.
-	 * XXX  It's not clear whether the current behavior is correct
-	 * or not.  Hence, this may change.....
-	 */
-	if (!(old_termios->c_cflag & CLOCAL) &&
-	    (tty->termios->c_cflag & CLOCAL))
-		wake_up_interruptible(&info->open_wait);
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * su_close()
- * 
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void su_close(struct tty_struct *tty, struct file * filp)
-{
-	struct su_struct *info = (struct su_struct *)tty->driver_data;
-	unsigned long flags;
-
-	if (!info || serial_paranoia_check(info, tty->device, "su_close"))
-		return;
-
-	save_flags(flags); cli();
-	
-	if (tty_hung_up_p(filp)) {
-		DBG_CNT("before DEC-hung");
-		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
-		return;
-	}
-	
-#ifdef SERIAL_DEBUG_OPEN
-	printk("su_close ttys%d, count = %d\n", info->line, info->count);
-#endif
-	if ((tty->count == 1) && (info->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  info->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * serial port won't be shutdown.
-		 */
-		printk("su_close: bad serial port count; tty->count is 1, "
-		       "info->count is %d\n", info->count);
-		info->count = 1;
-	}
-	if (--info->count < 0) {
-		printk("su_close: bad serial port count for ttys%d: %d\n",
-		       info->line, info->count);
-		info->count = 0;
-	}
-	if (info->count) {
-		DBG_CNT("before DEC-2");
-		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
-		return;
-	}
-	info->flags |= ASYNC_CLOSING;
-	/*
-	 * Save the termios structure, since this port may have
-	 * separate termios for callout and dialin.
-	 */
-	if (info->flags & ASYNC_NORMAL_ACTIVE)
-		info->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
-	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
-	 * the line discipline to only process XON/XOFF characters.
-	 */
-	tty->closing = 1;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
-	/*
-	 * At this point we stop accepting input.  To do this, we
-	 * disable the receive line status interrupts, and tell the
-	 * interrupt driver to stop checking the data ready bit in the
-	 * line status register.
-	 */
-	info->IER &= ~UART_IER_RLSI;
-	info->read_status_mask &= ~UART_LSR_DR;
-	if (info->flags & ASYNC_INITIALIZED) {
-		serial_out(info, UART_IER, info->IER);
-		/*
-		 * Before we drop DTR, make sure the UART transmitter
-		 * has completely drained; this is especially
-		 * important if there is a transmit FIFO!
-		 */
-		su_wait_until_sent(tty, info->timeout);
-	}
-	shutdown(info);
-	if (tty->driver.flush_buffer)
-		tty->driver.flush_buffer(tty);
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
-	tty->closing = 0;
-	info->event = 0;
-	info->tty = 0;
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
-		}
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
-	MOD_DEC_USE_COUNT;
-	restore_flags(flags);
-}
-
-/*
- * su_wait_until_sent() --- wait until the transmitter is empty
- */
-static void su_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-	struct su_struct * info = (struct su_struct *)tty->driver_data;
-	unsigned long orig_jiffies, char_time;
-	int lsr;
-
-	if (serial_paranoia_check(info, tty->device, "su_wait_until_sent"))
-		return;
-
-	if (info->type == PORT_UNKNOWN)
-		return;
-
-	orig_jiffies = jiffies;
-	/*
-	 * Set the check interval to be 1/5 of the estimated time to
-	 * send a single character, and make it at least 1.  The check
-	 * interval should also be less than the timeout.
-	 * 
-	 * Note: we have to use pretty tight timings here to satisfy
-	 * the NIST-PCTS.
-	 */
-	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
-	char_time = char_time / 5;
-	if (char_time == 0)
-		char_time = 1;
-	if (timeout)
-	  char_time = MIN(char_time, timeout);
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-	printk("In su_wait_until_sent(%d) check=%lu...", timeout, char_time);
-	printk("jiff=%lu...", jiffies);
-#endif
-	while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
-		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
-		current->timeout = jiffies + char_time;
-		schedule();
-		if (signal_pending(current))
-			break;
-		if (timeout && ((orig_jiffies + timeout) < jiffies))
-			break;
-	}
-	current->state = TASK_RUNNING;
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-
-/*
- * su_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void su_hangup(struct tty_struct *tty)
-{
-	struct su_struct * info = (struct su_struct *)tty->driver_data;
-
-	if (serial_paranoia_check(info, tty->device, "su_hangup"))
-		return;
-
-	su_flush_buffer(tty);
-	shutdown(info);
-	info->event = 0;
-	info->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
-	info->tty = 0;
-	wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * su_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-			   struct su_struct *info)
-{
-	struct wait_queue wait = { current, NULL };
-	int		retval;
-	int		do_clocal = 0;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		return ((info->flags & ASYNC_HUP_NOTIFY) ?
-			-EAGAIN : -ERESTARTSYS);
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-
-	/*
-	 * If non-blocking mode is set, or the port is not enabled,
-	 * then make the check up front and then exit.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
-		info->flags |= ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
-	 * su_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready before block: ttys%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	cli();
-	if (!tty_hung_up_p(filp)) 
-		info->count--;
-	sti();
-	info->blocked_open++;
-	while (1) {
-		cli();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD))
-			serial_out(info, UART_MCR,
-				   serial_inp(info, UART_MCR) |
-				   (UART_MCR_DTR | UART_MCR_RTS));
-		sti();
-		current->state = TASK_INTERRUPTIBLE;
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-			if (info->flags & ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;	
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) &&
-		    (do_clocal || (serial_in(info, UART_MSR) &
-				   UART_MSR_DCD)))
-			break;
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-#ifdef SERIAL_DEBUG_OPEN
-		printk("block_til_ready blocking: ttys%d, count = %d\n",
-		       info->line, info->count);
-#endif
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready after blocking: ttys%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	if (retval)
-		return retval;
-	info->flags |= ASYNC_NORMAL_ACTIVE;
-	return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain.   It also performs the serial-specific
- * initialization for the tty structure.
-	 */
-static int su_open(struct tty_struct *tty, struct file * filp)
-{
-	struct su_struct	*info;
-	int 			retval, line;
-	unsigned long		page;
-
-	line = MINOR(tty->device) - tty->driver.minor_start;
-	if ((line < 0) || (line >= NR_PORTS))
-		return -ENODEV;
-	info = su_table + line;
-	if (serial_paranoia_check(info, tty->device, "su_open"))
-		return -ENODEV;
-	info->count++;
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("su_open %s%d, count = %d\n", tty->driver.name, info->line,
-	       info->count);
-#endif
-	tty->driver_data = info;
-	info->tty = tty;
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
-	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
-		if (!page)
-			return -ENOMEM;
-		if (tmp_buf)
-			free_page(page);
-		else
-			tmp_buf = (unsigned char *) page;
-	}
-
-	/*
-	 * If the port is the middle of closing, bail out now
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		return ((info->flags & ASYNC_HUP_NOTIFY) ?
-			-EAGAIN : -ERESTARTSYS);
-#else
-		return -EAGAIN;
-#endif
-	}
-	
-	/*
-	 * Start up serial port
-	 */
-	retval = startup(info);
-	if (retval)
-		return retval;
-
-	MOD_INC_USE_COUNT;
-	retval = block_til_ready(tty, filp, info);
-	if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-		printk("su_open returning after block_til_ready with %d\n",
-		       retval);
-#endif
-		return retval;
-	}
-
-	if ((info->count == 1) &&
-	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
-		change_speed(info);
-	}
-#ifdef CONFIG_SERIAL_CONSOLE
-	if (sercons.cflag && sercons.index == line) {
-		tty->termios->c_cflag = sercons.cflag;
-		sercons.cflag = 0;
-	change_speed(info);
-	}
-#endif
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("su_open ttys%d successful...", info->line);
-#endif
-	return 0;
-}
-
-/*
- * /proc fs routines....
- */
-
-static inline int line_info(char *buf, struct su_struct *info)
-{
-	char	stat_buf[30], control, status;
-	int	ret;
-
-	ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
-		      info->line, uart_config[info->type].name, 
-		      (int)info->port, info->irq);
-
-	if (info->port == 0 || info->type == PORT_UNKNOWN) {
-		ret += sprintf(buf+ret, "\n");
-		return ret;
-	}
-
-	/*
-	 * Figure out the current RS-232 lines
-	 */
-	cli();
-	status = serial_in(info, UART_MSR);
-	control = info ? info->MCR : serial_in(info, UART_MCR);
-	sti();
-
-	stat_buf[0] = 0;
-	stat_buf[1] = 0;
-	if (control & UART_MCR_RTS)
-		strcat(stat_buf, "|RTS");
-	if (status & UART_MSR_CTS)
-		strcat(stat_buf, "|CTS");
-	if (control & UART_MCR_DTR)
-		strcat(stat_buf, "|DTR");
-	if (status & UART_MSR_DSR)
-		strcat(stat_buf, "|DSR");
-	if (status & UART_MSR_DCD)
-		strcat(stat_buf, "|CD");
-	if (status & UART_MSR_RI)
-		strcat(stat_buf, "|RI");
-
-	if (info->quot) {
-		ret += sprintf(buf+ret, " baud:%d",
-			       info->baud_base / info->quot);
-	}
-
-	ret += sprintf(buf+ret, " tx:%d rx:%d",
-		      info->icount.tx, info->icount.rx);
-
-	if (info->icount.frame)
-		ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
-
-	if (info->icount.parity)
-		ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
-
-	if (info->icount.brk)
-		ret += sprintf(buf+ret, " brk:%d", info->icount.brk);	
-
-	if (info->icount.overrun)
-		ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
-
-	/*
-	 * Last thing is the RS-232 status lines
-	 */
-	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-	return ret;
-}
-
-int su_read_proc(char *page, char **start, off_t off, int count,
-		 int *eof, void *data)
-{
-	int i, len = 0;
-	off_t	begin = 0;
-
-	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
-	for (i = 0; i < NR_PORTS && len < 4000; i++) {
-		len += line_info(page + len, &su_table[i]);
-		if (len+begin > off+count)
-			goto done;
-		if (len+begin < off) {
-			begin += len;
-			len = 0;
-		}
-	}
-	*eof = 1;
-done:
-	if (off >= len+begin)
-		return 0;
-	*start = page + (begin-off);
-	return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/*
- * ---------------------------------------------------------------------
- * su_init() and friends
- *
- * su_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static _INLINE_ void show_su_version(void)
-{
- 	printk(KERN_INFO "%s version %s with", serial_name, serial_version);
-#ifdef CONFIG_SERIAL_MANY_PORTS
-	printk(" MANY_PORTS");
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_MULTIPORT
-	printk(" MULTIPORT");
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_SHARE_IRQ
-	printk(" SHARE_IRQ");
-#endif
-#define SERIAL_OPT
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-	printk(" DETECT_IRQ");
-#endif
-#ifdef SERIAL_OPT
-	printk(" enabled\n");
-#else
-	printk(" no serial options enabled\n");
-#endif
-#undef SERIAL_OPT
-}
-
-/*
- * This routine is called by su_init() to initialize a specific serial
- * port.  It determines what type of UART chip this serial port is
- * using: 8250, 16450, 16550, 16550A.  The important question is
- * whether or not this UART is a 16550A or not, since this will
- * determine whether or not we can use its FIFO features or not.
- */
-static void
-autoconfig(struct su_struct *info)
-{
-	unsigned char status1, status2, scratch, scratch2;
-#ifdef __sparc_v9__
-	struct linux_ebus_device *dev = 0;
-	struct linux_ebus *ebus;
-#else
-	struct linux_prom_registers reg0;
-#endif
-	unsigned long flags;
-
-#ifdef __sparc_v9__
-	for_each_ebus(ebus) {
-		for_each_ebusdev(dev, ebus) {
-			if (!strncmp(dev->prom_name, "su", 2)) {
-				if (dev->prom_node == info->kbd_node)
-					goto ebus_done;
-				if (dev->prom_node == info->ms_node)
-					goto ebus_done;
-			}
-		}
-	}
-ebus_done:
-	if (!dev)
-		return;
-
-	info->port = dev->base_address[0];
-	if (check_region(info->port, 8))
-		return;
-
-	info->irq = dev->irqs[0];
-
-#ifdef DEBUG_SERIAL_OPEN
-	printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
-	       __irq_itoa(dev->irqs[0]));
-#endif
-
-#else
-	if (info->port_node == 0) {
-		return;
-	}
-	if (prom_getproperty(info->port_node, "reg",
-	    (char *)&reg0, sizeof(reg0)) == -1) {
-		prom_printf("su: no \"reg\" property\n");
-		return;
-	}
-	prom_apply_obio_ranges(&reg0, 1);
-	if ((info->port = (unsigned long) sparc_alloc_io(reg0.phys_addr,
-	    0, reg0.reg_size, "su-regs", reg0.which_io, 0)) == 0) {
-		prom_printf("su: cannot map\n");
-		return;
-	}
-	/*
-	 * There is no intr property on MrCoffee, so hardwire it. Krups?
-	 */
-	info->irq = 13;
-#endif
-
-	info->magic = SERIAL_MAGIC;
-
-	save_flags(flags); cli();
-	
-	/*
-	 * Do a simple existence test first; if we fail this, there's
-	 * no point trying anything else.
-	 *
-	 * 0x80 is used as a nonsense port to prevent against false
-	 * positives due to ISA bus float.  The assumption is that
-	 * 0x80 is a non-existent port; which should be safe since
-	 * include/asm/io.h also makes this assumption.
-	 */
-	scratch = serial_in(info, UART_IER);
-	su_outb(info, UART_IER, 0);
-	scratch2 = serial_in(info, UART_IER);
-	su_outb(info, UART_IER, scratch);
-	if (scratch2) {
-		restore_flags(flags);
-		return;		/* We failed; there's nothing here */
-	}
-
-#if 0 /* P3 You will never beleive but SuperIO fails this test in MrCoffee. */
-	scratch = serial_in(info, UART_MCR);
-	su_outb(info, UART_MCR, UART_MCR_LOOP | scratch);
-	scratch2 = serial_in(info, UART_MSR);
-	su_outb(info, UART_MCR, UART_MCR_LOOP | 0x0A);
-	status1 = serial_in(info, UART_MSR) & 0xF0;
-	su_outb(info, UART_MCR, scratch);
-	su_outb(info, UART_MSR, scratch2);
-	if (status1 != 0x90) {
-		restore_flags(flags);
-		return;
-	} 
-#endif
-
-	scratch2 = serial_in(info, UART_LCR);
-	su_outb(info, UART_LCR, 0xBF);	/* set up for StarTech test */
-	su_outb(info, UART_EFR, 0);	/* EFR is the same as FCR */
-	su_outb(info, UART_LCR, 0);
-	su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
-	scratch = serial_in(info, UART_IIR) >> 6;
-	switch (scratch) {
-		case 0:
-			info->type = PORT_16450;
-			break;
-		case 1:
-			info->type = PORT_UNKNOWN;
-			break;
-		case 2:
-			info->type = PORT_16550;
-			break;
-		case 3:
-			info->type = PORT_16550A;
-			break;
-	}
-	if (info->type == PORT_16550A) {
-		/* Check for Startech UART's */
-		su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-		if (su_inb(info, UART_EFR) == 0) {
-			info->type = PORT_16650;
-		} else {
-			su_outb(info, UART_LCR, 0xBF);
-			if (su_inb(info, UART_EFR) == 0)
-				info->type = PORT_16650V2;
-		}
-	}
-	if (info->type == PORT_16550A) {
-		/* Check for TI 16750 */
-		su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-		su_outb(info, UART_FCR,
-			    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
-		scratch = su_inb(info, UART_IIR) >> 5;
-		if (scratch == 7) {
-			su_outb(info, UART_LCR, 0);
-			su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
-			scratch = su_inb(info, UART_IIR) >> 5;
-			if (scratch == 6)
-				info->type = PORT_16750;
-		}
-		su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
-	}
-	su_outb(info, UART_LCR, scratch2);
-	if (info->type == PORT_16450) {
-		scratch = su_inb(info, UART_SCR);
-		su_outb(info, UART_SCR, 0xa5);
-		status1 = su_inb(info, UART_SCR);
-		su_outb(info, UART_SCR, 0x5a);
-		status2 = su_inb(info, UART_SCR);
-		su_outb(info, UART_SCR, scratch);
-
-		if ((status1 != 0xa5) || (status2 != 0x5a))
-			info->type = PORT_8250;
-	}
-	info->xmit_fifo_size = uart_config[info->type].dfl_xmit_fifo_size;
-
-	if (info->type == PORT_UNKNOWN) {
-		restore_flags(flags);
-		return;
-	}
-
-#ifdef __sparc_v9__
-	sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
-	request_region(info->port, 8, info->name);
-#else
-	strcpy(info->name, "su(serial)");
-#endif
-
-	/*
-	 * Reset the UART.
-	 */
-	su_outb(info, UART_MCR, 0x00);
-	su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
-				     UART_FCR_CLEAR_XMIT));
-	su_inb(info, UART_RX);
-
-	restore_flags(flags);
-}
-
-/*
- * The serial driver boot-time initialization code!
- */
-__initfunc(int su_init(void))
-{
-	int i;
-	struct su_struct *info;
-	extern void atomwide_serial_init (void);
-	extern void dualsp_serial_init (void);
-	
-#ifdef CONFIG_ATOMWIDE_SERIAL
-	atomwide_serial_init ();
-#endif
-#ifdef CONFIG_DUALSP_SERIAL
-	dualsp_serial_init ();
-#endif
-	
-	init_bh(SERIAL_BH, do_serial_bh);
-	timer_table[RS_TIMER].fn = su_timer;
-	timer_table[RS_TIMER].expires = 0;
-
-	for (i = 0; i < NR_IRQS; i++) {
-		IRQ_ports[i] = 0;
-		IRQ_timeout[i] = 0;
-#ifdef CONFIG_SERIAL_MULTIPORT
-		memset(&rs_multiport[i], 0,
-		       sizeof(struct rs_multiport_struct));
-#endif
-	}
-#if 0	/* Must be shared with keyboard on MrCoffee. */
-#ifdef CONFIG_SERIAL_CONSOLE
-	/*
-	 *	The interrupt of the serial console port
-	 *	can't be shared.
-	 */
-	if (sercons.flags & CON_CONSDEV) {
-		for(i = 0; i < NR_PORTS; i++)
-			if (i != sercons.index &&
-			    su_table[i].irq == su_table[sercons.index].irq)
-				su_table[i].irq = 0;
-	}
-#endif
-#endif
-	show_su_version();
-
-	/* Initialize the tty_driver structure */
-
-	memset(&serial_driver, 0, sizeof(struct tty_driver));
-	serial_driver.magic = TTY_DRIVER_MAGIC;
-	serial_driver.driver_name = "su";
-	serial_driver.name = "ttyS";
-	serial_driver.major = TTY_MAJOR;
-	serial_driver.minor_start = 64;
-	serial_driver.num = NR_PORTS;
-	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
-	serial_driver.subtype = SERIAL_TYPE_NORMAL;
-	serial_driver.init_termios = tty_std_termios;
-	serial_driver.init_termios.c_cflag =
-		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	serial_driver.flags = TTY_DRIVER_REAL_RAW;
-	serial_driver.refcount = &serial_refcount;
-	serial_driver.table = serial_table;
-	serial_driver.termios = serial_termios;
-	serial_driver.termios_locked = serial_termios_locked;
-
-	serial_driver.open = su_open;
-	serial_driver.close = su_close;
-	serial_driver.write = su_write;
-	serial_driver.put_char = su_put_char;
-	serial_driver.flush_chars = su_flush_chars;
-	serial_driver.write_room = su_write_room;
-	serial_driver.chars_in_buffer = su_chars_in_buffer;
-	serial_driver.flush_buffer = su_flush_buffer;
-	serial_driver.ioctl = su_ioctl;
-	serial_driver.throttle = su_throttle;
-	serial_driver.unthrottle = su_unthrottle;
-	serial_driver.send_xchar = su_send_xchar;
-	serial_driver.set_termios = su_set_termios;
-	serial_driver.stop = su_stop;
-	serial_driver.start = su_start;
-	serial_driver.hangup = su_hangup;
-	serial_driver.break_ctl = su_break;
-	serial_driver.wait_until_sent = su_wait_until_sent;
-	serial_driver.read_proc = su_read_proc;
-
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-	callout_driver.name = "cua";
-	callout_driver.major = TTYAUX_MAJOR;
-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-	callout_driver.read_proc = 0;
-	callout_driver.proc_entry = 0;
-
-	if (tty_register_driver(&serial_driver))
-		panic("Couldn't register regular su\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout su\n");
-
-	for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
-		info->magic = SSTATE_MAGIC;
-		info->line = i;
-		info->type = PORT_UNKNOWN;
-		info->baud_base = BAUD_BASE;
-		/* info->flags = 0; */
-		info->custom_divisor = 0;
-		info->close_delay = 5*HZ/10;
-		info->closing_wait = 30*HZ;
-		info->callout_termios = callout_driver.init_termios;
-		info->normal_termios = serial_driver.init_termios;
-		info->icount.cts = info->icount.dsr = 
-			info->icount.rng = info->icount.dcd = 0;
-		info->icount.rx = info->icount.tx = 0;
-		info->icount.frame = info->icount.parity = 0;
-		info->icount.overrun = info->icount.brk = 0;
-		info->tqueue.routine = do_softint;
-		info->tqueue.data = info;
-
-		if (info->kbd_node)
-			info->cflag = B1200 | CS8 | CREAD;
-		else if (info->ms_node)
-			info->cflag = B4800 | CS8 | CREAD;
-		else
-			info->cflag = B9600 | CS8 | CREAD;
-
-		autoconfig(info);
-		if (info->type == PORT_UNKNOWN)
-			continue;
-
-		printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
-		       info->name, info->port, __irq_itoa(info->irq),
-		       uart_config[info->type].name);
-
-		/*
-		 * We want startup here because we want mouse and keyboard
-		 * working without opening. On SPARC console will work
-		 * without startup.
-		 */
-		if (info->kbd_node) {
-			startup(info);
-			keyboard_zsinit(su_put_char_kbd);
-		} else if (info->ms_node) {
-		startup(info);
-			sun_mouse_zsinit();
-	}
-	}
-
-	return 0;
-}
-
-__initfunc(int su_probe (unsigned long *memory_start))
-{
-	struct su_struct *info = su_table;
-        int node, enode, tnode, sunode;
-	int kbnode = 0, msnode = 0;
-	int devices = 0;
-	char prop[128];
-	int len;
-
-	/*
-	 * Find su on MrCoffee. We return OK code if find any.
-	 * Then su_init finds every one and initializes them.
-	 * We do this early because MrCoffee got no aliases.
-	 */
-	node = prom_getchild(prom_root_node);
-	if ((node = prom_searchsiblings(node, "obio")) != 0) {
-		if ((sunode = prom_getchild(node)) != 0) {
-			if ((sunode = prom_searchsiblings(sunode, "su")) != 0) {
-				info->port_node = sunode;
-#ifdef CONFIG_SERIAL_CONSOLE
-				/*
-				 * Console must be initiated after the generic initialization.
-				 * sunserial_setinitfunc inverts order, so call this before next one.
-				 */
-				sunserial_setinitfunc(memory_start, su_serial_console_init);
-#endif
-        			sunserial_setinitfunc(memory_start, su_init);
-				return 0;
-			}
-		}
-	}
-
-	/*
-	 * Get the nodes for keyboard and mouse from 'aliases'...
-	 */
-        node = prom_getchild(prom_root_node);
-	node = prom_searchsiblings(node, "aliases");
-	if (!node)
-		return -ENODEV;
-
-	len = prom_getproperty(node, "keyboard", prop, sizeof(prop));
-	if (len > 0) {
-		prop[len] = 0;
-		kbnode = prom_finddevice(prop);
-	}
-	if (!kbnode)
-		return -ENODEV;
-
-	len = prom_getproperty(node, "mouse", prop, sizeof(prop));
-	if (len > 0) {
-		prop[len] = 0;
-		msnode = prom_finddevice(prop);
-	}
-	if (!msnode)
-		return -ENODEV;
-
-	/*
-	 * Find matching EBus nodes...
-	 */
-        node = prom_getchild(prom_root_node);
-	if ((node = prom_searchsiblings(node, "pci")) == 0) {
-		return -ENODEV;		/* Plain sparc */
-	}
-
-	/*
-	 * Check for SUNW,sabre on Ultra 5/10/AXi.
-	 */
-	len = prom_getproperty(node, "model", prop, sizeof(prop));
-	if ((len > 0) && !strncmp(prop, "SUNW,sabre", len)) {
-        	node = prom_getchild(node);
-		node = prom_searchsiblings(node, "pci");
-	}
-
-	/*
-	 * For each PCI bus...
-	 */
-	while (node) {
-		enode = prom_getchild(node);
-		enode = prom_searchsiblings(enode, "ebus");
-
-		/*
-		 * For each EBus on this PCI...
-		 */
-		while (enode) {
-			sunode = prom_getchild(enode);
-			tnode = prom_searchsiblings(sunode, "su");
-			if (!tnode)
-				tnode = prom_searchsiblings(sunode, "su_pnp");
-			sunode = tnode;
-
-			/*
-			 * For each 'su' on this EBus...
-			 */
-			while (sunode) {
-				/*
-				 * Does it match?
-				 */
-				if (sunode == kbnode) {
-					info->kbd_node = sunode;
-					++info;
-					++devices;
-				}
-				if (sunode == msnode) {
-					info->ms_node = sunode;
-					++info;
-					++devices;
-				}
-
-				/*
-				 * Found everything we need?
-				 */
-				if (devices == NR_PORTS)
-					goto found;
-
-				sunode = prom_getsibling(sunode);
-				tnode = prom_searchsiblings(sunode, "su");
-				if (!tnode)
-					tnode = prom_searchsiblings(sunode,
-								    "su_pnp");
-				sunode = tnode;
-			}
-			enode = prom_getsibling(enode);
-			enode = prom_searchsiblings(enode, "ebus");
-		}
-		node = prom_getsibling(node);
-		node = prom_searchsiblings(node, "pci");
-	}
-	return -ENODEV;
-
-found:
-        sunserial_setinitfunc(memory_start, su_init);
-        rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
-	sunkbd_setinitfunc(memory_start, sun_kbd_init);
-	kbd_ops.compute_shiftstate = sun_compute_shiftstate;
-	kbd_ops.setledstate = sun_setledstate;
-	kbd_ops.getledstate = sun_getledstate;
-	kbd_ops.setkeycode = sun_setkeycode;
-	kbd_ops.getkeycode = sun_getkeycode;
-#ifdef CONFIG_PCI
-	sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
-			       sun_func_buf, sun_func_table,
-			       sun_funcbufsize, sun_funcbufleft,
-			       sun_accent_table, sun_accent_table_size);
-#endif
-	return 0;
-}
-
-#if 0
-#ifdef MODULE
-int init_module(void)
-{
-	return su_init();	/* rs_init? su_probe? XXX */
-}
-
-void cleanup_module(void) 
-{
-	unsigned long flags;
-	int e1, e2;
-	int i;
-
-	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
-	save_flags(flags);
-	cli();
-	timer_active &= ~(1 << RS_TIMER);
-	timer_table[RS_TIMER].fn = NULL;
-	timer_table[RS_TIMER].expires = 0;
-        remove_bh(SERIAL_BH);
-	if ((e1 = tty_unregister_driver(&serial_driver)))
-		printk("SERIAL: failed to unregister serial driver (%d)\n",
-		       e1);
-	if ((e2 = tty_unregister_driver(&callout_driver)))
-		printk("SERIAL: failed to unregister callout driver (%d)\n", 
-		       e2);
-	restore_flags(flags);
-
-	for (i = 0; i < NR_PORTS; i++) {
-		if (su_table[i].type != PORT_UNKNOWN)
-			release_region(su_table[i].port, 8);
-	}
-	if (tmp_buf) {
-		free_page((unsigned long) tmp_buf);
-		tmp_buf = NULL;
-	}
-}
-#endif /* MODULE */
-#endif /* deadwood */
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_CONSOLE
-
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- *	Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct su_struct *info)
-{
-	int lsr;
-	unsigned int tmout = 1000000;
-
-	do {
-		lsr = su_inb(info, UART_LSR);
-		if (--tmout == 0)
-			break;
-	} while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
-}
-
-/*
- *	Print a string to the serial port trying not to disturb
- *	any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
-				unsigned count)
-{
-	struct su_struct *info;
-	int ier;
-	unsigned i;
-
-	info = su_table + co->index;
-	/*
-	 *	First save the IER then disable the interrupts
-	 */
-	ier = su_inb(info, UART_IER);
-	su_outb(info, UART_IER, 0x00);
-
-	/*
-	 *	Now, do each character
-	 */
-	for (i = 0; i < count; i++, s++) {
-		wait_for_xmitr(info);
-
-		/*
-		 *	Send the character out.
-		 *	If a LF, also do CR...
-		 */
-		su_outb(info, UART_TX, *s);
-		if (*s == 10) {
-			wait_for_xmitr(info);
-			su_outb(info, UART_TX, 13);
-		}
-	}
-
-	/*
-	 *	Finally, Wait for transmitter & holding register to empty
-	 * 	and restore the IER
-	 */
-	wait_for_xmitr(info);
-	su_outb(info, UART_IER, ier);
-}
-
-/*
- *	Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
-	struct su_struct *info;
-	int ier;
-	int lsr;
-	int c;
-
-	info = su_table + co->index;
-
-	/*
-	 *	First save the IER then disable the interrupts so
-	 *	that the real driver for the port does not get the
-	 *	character.
-	 */
-	ier = su_inb(info, UART_IER);
-	su_outb(info, UART_IER, 0x00);
-
-	do {
-		lsr = su_inb(info, UART_LSR);
-	} while (!(lsr & UART_LSR_DR));
-	c = su_inb(info, UART_RX);
-
-	/*
-	 *	Restore the interrupts
-	 */
-	su_outb(info, UART_IER, ier);
-
-	return c;
-}
-
-static kdev_t serial_console_device(struct console *c)
-{
-	return MKDEV(TTY_MAJOR, 64 + c->index);
-}
-
-/*
- *	Setup initial baud/bits/parity. We do two things here:
- *	- construct a cflag setting for the first su_open()
- *	- initialize the serial port
- *	Return non-zero if we didn't find a serial port.
- */
-__initfunc(static int serial_console_setup(struct console *co, char *options))
-{
-	struct su_struct *info;
-	unsigned cval;
-	int	baud = 9600;
-	int	bits = 8;
-	int	parity = 'n';
-	int	cflag = CREAD | HUPCL | CLOCAL;
-	int	quot = 0;
-	char	*s;
-
-	if (options) {
-		baud = simple_strtoul(options, NULL, 10);
-		s = options;
-		while(*s >= '0' && *s <= '9')
-			s++;
-		if (*s) parity = *s++;
-		if (*s) bits   = *s - '0';
-	}
-
-	/*
-	 *	Now construct a cflag setting.
-	 */
-	switch(baud) {
-		case 1200:
-			cflag |= B1200;
-			break;
-		case 2400:
-			cflag |= B2400;
-			break;
-		case 4800:
-			cflag |= B4800;
-			break;
-		case 19200:
-			cflag |= B19200;
-			break;
-		case 38400:
-			cflag |= B38400;
-			break;
-		case 57600:
-			cflag |= B57600;
-			break;
-		case 115200:
-			cflag |= B115200;
-			break;
-		case 9600:
-		default:
-			cflag |= B9600;
-			break;
-	}
-	switch(bits) {
-		case 7:
-			cflag |= CS7;
-			break;
-		default:
-		case 8:
-			cflag |= CS8;
-			break;
-	}
-	switch(parity) {
-		case 'o': case 'O':
-			cflag |= PARODD;
-			break;
-		case 'e': case 'E':
-			cflag |= PARENB;
-			break;
-	}
-	co->cflag = cflag;
-
-	/*
-	 *	Divisor, bytesize and parity
-	 */
-	info = su_table + co->index;
-	quot = BAUD_BASE / baud;
-	cval = cflag & (CSIZE | CSTOPB);
-#if defined(__powerpc__) || defined(__alpha__)
-	cval >>= 8;
-#else /* !__powerpc__ && !__alpha__ */
-	cval >>= 4;
-#endif /* !__powerpc__ && !__alpha__ */
-	if (cflag & PARENB)
-		cval |= UART_LCR_PARITY;
-	if (!(cflag & PARODD))
-		cval |= UART_LCR_EPAR;
-
-	/*
-	 *	Disable UART interrupts, set DTR and RTS high
-	 *	and set speed.
-	 */
-	su_outb(info, UART_IER, 0);
-	su_outb(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
-	su_outb(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
-	su_outb(info, UART_DLL, quot & 0xff);		/* LS of divisor */
-	su_outb(info, UART_DLM, quot >> 8);		/* MS of divisor */
-	su_outb(info, UART_LCR, cval);			/* reset DLAB */
-	info->quot = quot;
-
-	/*
-	 *	If we read 0xff from the LSR, there is no UART here.
-	 */
-	if (su_inb(info, UART_LSR) == 0xff)
-		return -1;
-
-	return 0;
-}
-
-static struct console sercons = {
-	"ttyS",
-	serial_console_write,
-	NULL,
-	serial_console_device,
-	serial_console_wait_key,
-	NULL,
-	serial_console_setup,
-	CON_PRINTBUFFER,
-	-1,
-	0,
-	NULL
-};
-
-/*
- *	Register console.
- */
-__initfunc(int su_serial_console_init(void))
-{
-	extern int con_is_present(void);
-
-	if (con_is_present())
-		return 0;
-	if (serial_console == 0)
-		return 0;
-	if (su_table[0].port == 0 || su_table[0].port_node == 0)
-		return 0;
-	sercons.index = 0;
-	register_console(&sercons);
-	return 0;
-}
-
-#endif /* CONFIG_SERIAL_CONSOLE */
diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c
--- v2.1.126/linux/drivers/sbus/char/sunserial.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/sunserial.c	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.66 1998/09/21 05:48:48 jj Exp $
+/* $Id: sunserial.c,v 1.67 1998/10/25 03:22:46 jj Exp $
  * serial.c: Serial port driver infrastructure for the Sparc.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -399,6 +399,14 @@
 
 	if (!ret)
 		return memory_start;
+		
+#ifdef __sparc_v9__
+	ret = prom_finddevice("/ssp-serial");
+	if (ret && ret != -1) {
+		/* Hello, Starfire. Pleased to meet you :) */
+		return memory_start;
+	}
+#endif
 
 	prom_printf("No serial devices found, bailing out.\n");
 	prom_halt();
diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c
--- v2.1.126/linux/drivers/sbus/char/vfc_dev.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/vfc_dev.c	Tue Oct 27 09:52:21 1998
@@ -218,7 +218,7 @@
 			return -ENOMEM;
 
 		if(copy_from_user(buffer, inout.buffer, 
-				  inout.len*sizeof(char));) {
+				  inout.len*sizeof(char))) {
 			kfree_s(buffer,inout.len*sizeof(char));
 			return -EFAULT;
 		}
diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.1.126/linux/drivers/sbus/char/zs.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/zs.c	Thu Nov  5 09:58:44 1998
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.29 1998/09/21 05:06:53 jj Exp $
+/* $Id: zs.c,v 1.31 1998/10/07 11:35:29 jj Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1354,10 +1354,9 @@
 	if (!info->port)
 		return;
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + duration;
 	cli();
 	write_zsreg(info->zs_channel, 5, (info->curregs[5] | SND_BRK));
-	schedule();
+	schedule_timeout(duration);
 	write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	sti();
 }
@@ -1543,8 +1542,7 @@
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
+			schedule_timeout(info->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
@@ -1808,7 +1806,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.29 $";
+	char *revision = "$Revision: 1.31 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -1830,6 +1828,7 @@
 get_zs(int chip))
 {
 	unsigned int vaddr[2] = { 0, 0 };
+	unsigned long mapped_addr = 0;
 	int busnode, seen, zsnode, sun4u_ino;
 	static int irq = 0;
 
@@ -1854,7 +1853,30 @@
 			int len = prom_getproperty(zsnode, "address",
 						   (void *) vaddr, sizeof(vaddr));
 
-			if(len % sizeof(unsigned int)) {
+			if(len == -1) {
+				struct linux_sbus *sbus;
+				struct linux_sbus_device *sdev = NULL;
+
+				/* "address" property is not guarenteed,
+				 * everything in I/O is implicitly mapped
+				 * anyways by our clever TLB miss handling
+				 * scheme, so don't fail here.  -DaveM
+				 */
+				for_each_sbus(sbus) {
+					for_each_sbusdev(sdev, sbus) {
+						if (sdev->prom_node == zsnode)
+							goto found;
+					}
+				}
+			found:
+				if (sdev == NULL)
+					prom_halt();
+				prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev);
+				mapped_addr = (unsigned long)
+					sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
+						       PAGE_SIZE, "Zilog Registers",
+						       sdev->reg_addrs[0].which_io, 0x0);
+			} else if(len % sizeof(unsigned int)) {
 				prom_printf("WHOOPS:  proplen for %s "
 					    "was %d, need multiple of "
 					    "%d\n", "address", len,
@@ -1883,9 +1905,12 @@
 	}
 	if(!zsnode)
 		panic("get_zs: whee chip not found");
-	if(!vaddr[0])
+	if(!vaddr[0] && !mapped_addr)
 		panic("get_zs: whee no serial chip mappable");
-	return (struct sun_zslayout *)(unsigned long) vaddr[0];
+	if (mapped_addr != 0)
+		return (struct sun_zslayout *) mapped_addr;
+	else
+		return (struct sun_zslayout *) (unsigned long) vaddr[0];
 }
 #else /* !(__sparc_v9__) */
 __initfunc(static struct sun_zslayout *
@@ -2119,7 +2144,7 @@
 	kbd_ops.getledstate = sun_getledstate;
 	kbd_ops.setkeycode = sun_setkeycode;
 	kbd_ops.getkeycode = sun_getkeycode;
-#ifdef CONFIG_PCI
+#if defined(__sparc_v9__) && defined(CONFIG_PCI)
 	sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
 			       sun_func_buf, sun_func_table,
 			       sun_funcbufsize, sun_funcbufleft,
diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- v2.1.126/linux/drivers/sbus/sbus.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/sbus.c	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.72 1998/09/05 17:25:51 jj Exp $
+/* $Id: sbus.c,v 1.73 1998/10/07 11:35:50 jj Exp $
  * sbus.c:  SBus support routines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -278,8 +278,16 @@
 		if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||
 		   (nd = prom_getchild(iommund)) == 0 ||
 		   (nd = prom_searchsiblings(nd, "sbus")) == 0) {
+#ifdef CONFIG_PCI
+                        if (!pcibios_present()) {       
+                                prom_printf("Neither SBUS nor PCI found.\n");
+                                prom_halt();
+                        }
+                        return;
+#else
 			/* No reason to run further - the data access trap will occur. */
 			panic("sbus not found");
+#endif
 		}
 	}
 
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.1.126/linux/drivers/scsi/ChangeLog.ncr53c8xx	Fri Oct  9 13:27:10 1998
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Sun Oct 25 14:46:44 1998
@@ -1,3 +1,26 @@
+Wed Oct 21 21:00 1998 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.1a
+	- Changes from Eddie Dost for Sparc and Alpha:
+	  ioremap/iounmap support for Sparc.
+	  pcivtophys changed to bus_dvma_to_phys.
+	- Add the 53c876 description to the chip table. This is only usefull 
+	  for printing the right name of the controller.
+	- DEL-441 Item 2 work-around for the 53c876 rev <= 5 (0x15).
+	- Add additionnal checking of INQUIRY data:
+	  Check INQUIRY data received length is at least 7. Byte 7 of 
+	  inquiry data contains device features bits and the driver might 
+	  be confused by garbage. Also check peripheral qualifier.
+	- Cleanup of the SCSI tasks management:
+	  Remove the special case for 32 tags. Now the driver only uses the 
+	  scheme that allows up to 64 tags per LUN.
+	  Merge some code from the 896 driver.
+	  Use a 1,3,5,...MAXTAGS*2+1 tag numbering. Previous driver could  
+	  use any tag number from 1 to 253 and some non conformant devices  
+	  might have problems with large tag numbers.
+	- 'no_sync' changed to 'no_disc' in the README file. This is an old 
+	  and trivial mistake that seems to demonstrate the README file is 
+	  not often read. :)
+
 Sun Oct  4 14:00 1998 Gerard Roudier (groudier@club-internet.fr)
 	* revision 3.0i
 	- Cosmetic changes for sparc (but not for the driver) that needs  
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.126/linux/drivers/scsi/Config.in	Fri Oct 23 22:01:21 1998
+++ linux/drivers/scsi/Config.in	Wed Nov  4 11:27:23 1998
@@ -75,7 +75,7 @@
 if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then
   dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
   if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then
-    int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
+    int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 4
     int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
     int  '  synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20
     bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
@@ -104,8 +104,11 @@
   dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
 fi
 dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
-if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then
-  dep_tristate 'Tekram DC-390(T) (AMD PCscsi) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" ]; then
+  dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+  if [ "$CONFIG_SCSI_DC390T" != "n" ]; then
+    bool '  _omit_ support for non-DC390 adapters' CONFIG_SCSI_DC390T_NOGENSUPP
+  fi
 fi
 dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
 dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx
--- v2.1.126/linux/drivers/scsi/README.ncr53c8xx	Wed Jul  1 19:38:54 1998
+++ linux/drivers/scsi/README.ncr53c8xx	Sun Oct 25 14:46:44 1998
@@ -4,7 +4,7 @@
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
-27 June 1998
+18 October 1998
 ===============================================================================
 
 1.  Introduction
@@ -21,7 +21,7 @@
       8.4  Set order type for tagged command
       8.5  Set debug mode
       8.6  Clear profile counters
-      8.7  Set flag (no_sync)
+      8.7  Set flag (no_disc)
       8.8  Set verbose level
 9.  Configuration parameters
 10. Boot setup commands
@@ -424,7 +424,7 @@
     The "clearprof" command allows you to clear these counters at any time.
 
 
-8.7 Set flag (no_sync)
+8.7 Set flag (no_disc)
  
     setflag <target> <flag>
 
@@ -432,11 +432,11 @@
 
     For the moment, only one flag is available:
 
-        no_sync:   not allow target to disconnect.
+        no_disc:   not allow target to disconnect.
 
     Do not specify any flag in order to reset the flag. For example:
     - setflag 4
-      will reset no_sync flag for target 4, so will allow it disconnections.
+      will reset no_disc flag for target 4, so will allow it disconnections.
     - setflag all
       will allow disconnection for all devices on the SCSI bus.
 
@@ -1067,7 +1067,7 @@
   Will enable fast synchronous data transfer negotiation for all targets.
 
 - echo "setflag 3" >/proc/scsi/ncr53c8xx/0
-  Will reset flags (no_sync) for target 3, and so will allow it to disconnect 
+  Will reset flags (no_disc) for target 3, and so will allow it to disconnect 
   the SCSI Bus.
 
 - echo "settags 3 8" >/proc/scsi/ncr53c8xx/0
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/README.tmscsim linux/drivers/scsi/README.tmscsim
--- v2.1.126/linux/drivers/scsi/README.tmscsim	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/README.tmscsim	Tue Oct 27 10:10:08 1998
@@ -0,0 +1,413 @@
+The tmscsim driver
+==================
+
+1. Purpose and history
+2. Installation
+3. Features
+4. Configuration via /proc/scsi/tmscsim/?
+5. Configuration via boot/module params
+6. Potential improvements
+7. Bug reports, debugging and updates
+8. Acknowledgements
+
+
+1. Purpose and history
+----------------------
+The tmscsim driver supports PCI SCSI Host Adapters based on the AM53C974
+chip. AM53C974 based SCSI adapters include: 
+ Tekram DC390, DC390T
+ Dawicontrol 2974
+ some on-board adapters
+(This is most probably not a complete list)
+
+It has originally written by C.L. Huang from the Tekram corp. to support the
+Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram
+scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F
+(NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter,
+tmscsimw, which supported DC390W/U/F adapters. It's not maintained any more,
+as the ncr53c8xx is perfectly supporting these adpaters since some time.
+
+The driver first appeared in April 1996, exclusively supported the DC390 
+and has been enhanced since then in various steps. In May 1998 support for 
+general AM53C974 based adapters and some possibilities to configure it were
+added. The non-DC390 support works by assuming some values for the data
+normally taken from the DC390 EEPROM. See below (chapter 5) for details.
+
+When using the DC390, the configuration is still be done using the DC390
+BIOS setup. The DC390 EEPROM is read and used by the driver, any boot or
+module parameters (chapter 5) are ignored! However, you can change settings
+dynamically, as described in chapter 4. 
+
+For a more detailed description of the driver's history, see the first lines
+of tmscsim.c.
+The numbering scheme isn't consistent. The first versions went from 1.00 to
+1.12, then 1.20a to 1.20t. Finally I decided to use the ncr53c8xx scheme. So
+the next revisions will be 2.0a to 2.0X (stable), 2.1a to 2.1X (experimental),
+2.2a to 2.2X (stable, again) etc. (X = anything between a and z.) If I send
+fixes to people for testing, those will have a digit appended, e.g. 2.0a1.
+
+
+2. Installation
+---------------
+If you got any recent kernel with this driver and document included in
+linux/drivers/scsi, you basically have to do nothing special to use this
+driver. Of course you have to choose to compile SCSI support and DC390(T)
+support into your kernel or as module when configuring your kernel for
+compiling.
+
+If you got an older kernel with an old version of this driver included, you
+should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and
+README.tmscsim) from this directory to linux/drivers/scsi. You have to
+recompile your kernel/module of course.
+
+You should apply the three patches included in dc390-20-kernel.diff
+(Applying them: cd /usr/src; patch -p0 <~/dc390-20-kernel.diff)
+The patches are against 2.1.103, so you might have to manually resolve
+rejections when applying to another kernel version.
+
+The patches will update the kernel startup code to allow boot parameters to
+be passed to the driver, update the Documentation and finally offer you the
+possibility to omit the non-DC390 parts of the driver.
+(By selecting "Omit support for non DC390" you basically disable the
+emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes
+of memory.)
+
+If you got a very old kernel without the tmscsim driver (pre 2.0.31)
+I recommend upgrading your kernel. However, if you don't want to, please
+contact me to get the appropriate patches.
+
+Testing a SCSI driver is always a delicate thing to do. The 2.0 driver has
+proven stable on many systems, but it's still a good idea to take some
+precautions. In an ideal world you would have a full backup of your disks.
+The world isn't ideal and most people don't have full backups (me neither).
+So take at least the following two measures:
+* make your kernel remount the FS read-only on detecting an error:
+  tune2fs -e remount-ro /dev/sd??
+* have copies of your SCSI disk's partition tables on some safe location:
+  dd if=/dev/sda of=/mnt/floppy/sda bs=512 count=1
+* make sure you are able to boot Linux (e.g. from floppy disk using InitRD)
+  if your SCSI disk gets corrupted. You can use 
+  ftp://student.physik.uni-dortmund.de/pub/linux/kernel/bootdisk.gz
+
+One more warning: I used to overclock my PCI bus to 41.67 MHz. My Tekram
+DC390F (Sym53c875) accepted this as well as my Millenium. But the Am53C974
+produced errors and started to corrupt my disks. So don't do that! A 37.50
+MHz PCI bus works for me, though, but I don't recommend using higher clocks
+than the 33.33 MHz being in the PCI spec.
+
+If you want to share the IRQ with another device and the driver refuses to
+do, you might succeed with changing the DC390_IRQ type in tmscsim.c to 
+SA_SHIRQ | SA_INTERRUPT.
+
+
+3.Features
+----------
+- SCSI
+ * Tagged queueing
+ * Sync speed up to 10 MHz
+ * Disconnection
+ * Multiple LUNs
+
+- General / Linux interface
+ * Support for up to 4 adapters.
+ * DC390 EEPROM usage or boot/module params
+ * Information via cat /proc/scsi/tmscsim/?
+ * Dynamically configurable by writing to /proc/scsi/tmscsim/?
+ * Dynamic allocation of resources
+ * SMP support: Adapter specific locks (Linux 2.1.x)
+ * Uniform source code for Linux-2.x.y
+ * Support for dyn. addition/removal of devices via add/remove-single-device
+   (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi 
+    H = Host, C = Channel, I = SCSI ID, L = SCSI LUN.) Use with care!
+ * Try to use the partition table for the determination of the mapping
+
+
+4. Configuration via /proc/scsi/tmscsim/?
+-----------------------------------------
+First of all look at the output of /proc/scsi/tmscsim/? by typing
+ cat /proc/scsi/tmscsim/?
+The "?" should be replaced by the SCSI host number. (The shell might do this
+for you.)
+You will see some info regarding the adapter and, at the end, a listing of
+the attached devices and their settings.
+
+Here's an example:
+garloff@kg1:/home/garloff > cat /proc/scsi/tmscsim/0
+Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 1.20s, 1998/08/20
+SCSI Host Nr 0, AM53C974 Adapter Nr 0
+IOPortBase 0x6200, IRQLevel 0x09
+MaxID 7, MaxLUN 8, AdapterID 7, SelTimeout 250 ms
+TagMaxNum 16, Status 0, ACBFlag 0, GlitchEater 24 ns
+Statistics: Nr of Cmnds 39563, Cmnds not sent directly 0, Out of SRB conds 0
+            Nr of lost arbitrations 17
+Nr of attached devices: 4, Nr of DCBs: 4
+Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs
+00  00  00  Yes  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15
+01  01  00  Yes  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15
+02  03  00  Yes  Yes  Yes  Yes  No   No    100 ns    10.0 M      15
+03  05  00  Yes  No   Yes  Yes  No   No   (200 ns)
+
+Note that the settings MaxID and MaxLUN are not zero- but one-based, which
+means that a setting MaxLUN=4, will result in the support of LUNs 0..3. This
+is somehow inconvenient, but the way the mid-level SCSI code expects it to be.
+
+ACB and DCB are acronyms for Adapter Control Block and Device Control Block.
+These are data structures of the driver containing information about the
+adapter and the connected SCSI devices respectively.
+
+Idx is the device index (just a consecutive number for the driver), ID and
+LUN are the SCSI ID and LUN, Prty means Parity checking, Sync synchronous
+negotiation, DsCn Disconnection, SndS Send Start command on startup (not
+used by the driver) and TagQ Tagged Command Queueing. NegoPeriod and
+SyncSpeed are somehow redundant, because they are reciprocal values 
+(1 / 112 ns = 8.9 MHz). At least in theory. The driver is able to adjust the
+NegoPeriod more accurate (4ns) than the SyncSpeed (1 / 25ns). I don't know
+if certain devices will have problems with this discrepancy. Max. speed is
+10 MHz corresp. to a min. NegoPeriod of 100 ns. 
+(The driver allows slightly higher speeds if the devices (Ultra SCSI) accept
+it, but that's out of adapter spec, on your own risk and unlikely to improve
+performance. You're likely to crash your disks.) 
+SyncOffs is the offset used for synchronous negotiations; max. is 15. 
+The last values are only shown, if Sync is enabled. (NegoPeriod is still
+displayed in brackets to show the values which will be used after enabling
+Sync.)
+The STOP parameter is for testing/debugging purposes only and should bet set
+to No. Please don't fiddle with it, unless you want to get rid of the
+contents of your disk.
+
+If you want to change a setting, you can do that by writing to
+/proc/scsi/tmscsim/?. Basically you have to imitate the output of driver.
+(Don't use the brackets for NegoPeriod on Sync disabled devices.)
+You don't have to care about capitalisation. The driver will accept space,
+tab, comma, = and : as separators.
+
+There are three kinds of changes: 
+
+(1) Change driver settings: 
+    You type the names of the parameters and the params following it.
+    Example:
+     echo "MaxLUN=8 seltimeout 200" >/proc/scsi/tmscsim/0
+
+    Note that you can only change MaxID, MaxLUN, AdapterID, SelTimeOut,
+    TagMaxNum, ACBFlag and GlitchEater. Don't change ACBFlag unless you
+    want to see what happens, if the driver hangs.
+
+(2) Change device settings: You write a config line to the driver. The Nr
+    must match the ID and LUN given. If you give "-" as parameter, it is
+    ignored and the corresponding setting won't be changed. 
+    You can use "y" or "n" instead of "Yes" and "No" if you want to.
+    You don't need to specify a full line. The driver automatically performs
+    an INQUIRY on the device if necessary to check if it is capable to operate
+    with the given settings (Sync, TagQ).
+    Examples:
+     echo "0 0 0 y y y - y - 10" >/proc/scsi/tmscsim/0
+     echo "3 5 0 y n y" >/proc/scsi/tmscsim/0
+
+    To give a short explanation of the first example: 
+    The first three numbers, "0 0 0" (Device index 0, SCSI ID 0, SCSI LUN 0),
+    select the device to which the following parameters apply. Note that it
+    would be sufficient to use the index or both SCSI ID and LUN, but I chose
+    to require all three to have a syntax similar to the output.
+    The following "y y y - y" enables Parity checking, enables Synchronous
+    transfers, Disconnection, leaves Send Start (not used) untouched and
+    enables Tagged Command Queueing for the selected device. The "-" skips
+    the Negotiation Period setting but the "10" sets the max sync. speed to
+    10 MHz. It's useless to specify both NegoPeriod and SyncSpeed as
+    discussed above. The values used in this example will result in maximum
+    performance.
+
+(3) Special commands: You can force a SCSI bus reset, an INQUIRY command and
+    the removal of a device's DCB.
+    This is only used for debugging when you meet problems. The parameter of
+    the INQUIRY and remove command is the device index as shown by the
+    output of /proc/scsi/tmscsim/? in the device listing in the first column
+    (Idx).
+    Examples:
+     echo "reset" >/proc/scsi/tmscsim/0
+     echo "inquiry 1" >/proc/scsi/tmscsim/0
+     echo "remove 2" >/proc/scsi/tmscsim/1
+
+    Note that you will meet problems when you remove a device's DCB with the
+    remove command if it contains partitions which are mounted. Only use it
+    after unmounting its partitions, telling the SCSI mid-level code to
+    remove it (scsi remove-single-device) and you really need a few bytes of
+    memory.
+
+
+I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing
+settings to see if everything changed as requested.
+
+
+5. Configuration via boot/module parameters
+-------------------------------------------
+With the DC390, the driver reads its EEPROM settings and IGNORES boot / 
+module parameters. If you want to override the EEPROM settings of a DC390, 
+you have to use the /proc/scsi/tmscsim/? interface described in the above
+chapter.
+
+However, if you do have another AM53C974 based adapter you might want to
+adjust some settings before you are able to write to the /proc/scsi/tmscsim/?
+pseudo-file, e.g. if you want to use another adapter ID than 7. (Note that
+the log message "DC390: No EEPROM found!" is normal without a DC390.)
+For this purpose, you can pass options to the driver before it is initialised
+by using kernel or module parameters. See lilo(8) or modprobe(1) manual
+pages on how to pass params to the kernel or a module.
+
+The syntax of the params is much shorter than the syntax of the /proc/...
+interface. This makes it a little bit more difficult to use. However, long
+parameter lines have the risk to be misinterpreted and the length of kernel
+parameters is limited.
+
+As the support for non-DC390 adapters works by simulating the values of the
+DC390 EEPROM, the settings are given in a DC390 BIOS' way.
+
+Here's the syntax:
+tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds
+
+Each of the parameters is a number, containing the described information:
+
+* AdaptID: The SCSI ID of the host adapter. Must be in the range 0..7
+  Default is 7.
+
+* SpdIdx: The index of the maximum speed as in the DC390 BIOS. The values
+  0..7 mean 10, 8.0, 6.7, 5.7, 5.0, 4.0, 3.1 and 2 MHz resp. Default is
+  1 (8.0 MHz).
+
+* DevMode is a bit mapped value describing the per-device features. It
+  applies to all devices. (Sync, Disc and TagQ will only apply, if the
+  device supports it.) The meaning of the bits (* = default):
+
+   Bit Val(hex) Val(dec)  Meaning
+   *0	 0x01	    1	  Parity check
+   *1	 0x02	    2	  Synchronous Negotiation
+   *2	 0x04	    4	  Disconnection
+   *3	 0x08	    8	  Send Start command on startup. (Not used)
+   *4	 0x10	   16	  Tagged Queueing
+
+  As usual, the desired value is obtained by adding the wanted values. If
+  you want to enable all values, e.g., you would use 31(0x1f). Default is 31.
+
+* AdaptMode is a bit mapped value describing the enabled adapter features.
+
+   Bit Val(hex) Val(dec)  Meaning
+   *0	 0x01	    1	  Support more than two drives. (Not used)
+   *1	 0x02	    2	  Use DOS compatible mapping for HDs greater than 1GB.
+   *2	 0x04	    4	  Reset SCSI Bus on startup.
+   *3	 0x08	    8	  Active Negation: Improves SCSI Bus noise immunity.
+    4	 0x10	   16	  Immediate return on BIOS seek command. (Not used)
+ (*)5	 0x20	   32	  Check for LUNs >= 1.
+  
+  The default for LUN Check depends on CONFIG_SCSI_MULTI_LUN.
+
+* TaggedCmnds is a number indicating the maximum number of Tagged Commands.
+  It is the binary logarithm - 1 of the actual number. Max is 4 (32).
+   Value  Number of Tagged Commands
+     0		 2
+     1		 4
+     2		 8
+    *3		16
+     4		32
+
+Example:
+ modprobe tmscsim tmscsim=6,2,31
+would set the adapter ID to 6, max. speed to 6.7 MHz, enable all device
+features and leave the adapter features and the number of Tagged Commands 
+to the defaults.
+
+As you can see, you don't need to specify all of the five params.
+
+The defaults (7,1,31,15,3) are aggressive to allow good performance. You can
+use tmscsim=7,0,31,63,4 for maximum performance, if your SCSI chain is
+perfect. If you meet problems, you can use tmscsim=-1 which is a shortcut
+for tmscsim=7,4,9,15,2. 
+
+
+6. Potential improvements
+-------------------------
+Most of the intended work on the driver has been done. Here are a few ideas
+to further improve its usability:
+
+* More intelligent abort() routine
+* Implement new_eh code (Linux-2.1+)
+* Have the mid-level code (and not the driver) handle more of the various
+  conditions.
+* Rework command queueing in the driver
+* More user friendly boot/module param syntax
+
+Further investigation on these problems:
+
+* TagQ and Disconnection (Resel: SRB Tag Seleection)
+* Problems with IRQ sharing (IO-APIC on SMP Systems) (??)
+* Driver crashes with readcdda (xcdroast)
+
+Known problems:
+
+* There was a report that with a certain Scanner, the last SCSI command
+  won't be finished correctly. This might be a command queueing bug or a bug
+  in SCSI implementation of the scanner. Issueing another command to the
+  scanner seems to help. (Try echo "INQUIRY x" >/proc/scsi/tmscsim/?, where
+  x is the index (not the SCSI ID!) of the scanner. See 4.(3).)
+* If there is a valid partition table, the driver will use it for determing
+  the mapping. Other operating systems may not like this mapping, though
+  it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the
+  partition table and used a H/S = 64/32 or 255/63 translation. So if you
+  want to be compatible to those, use this old mapping when creating
+  partition tables.
+* In some situations, the driver will get stuck in an abort loop. Please
+  disable DsCn, if you meet this problem. Please contact me for further
+  debugging.
+* 2.1.115+: Linux misses locks in sr_ioctl.c and scsi_ioctl.c
+  There used to be a patch included here, which partially solved the
+  problem. I suggest you contact Chiaki Ishikawa <ishikawa@yk.rim.or.jp>, 
+  Richard Waltham <dormouse@farsrobt.demon.co.uk> or Doug Ledford
+  <dledford@dialnet.net>, if you want to help further debugging it.
+* 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because
+  the mid-level code doesn't handle BLIST_SINGLELUN correctly. Apply
+  the patch 2035-scsi-singlelun.diff. Thanks to Chiaki Ishikawa.
+  I was told that this fix will be in 2.0.36, so you don't need it for
+  2.0.36. 
+[The patch file is contained in the dc390-XXX.tar.gz files which can be found
+on the ftp server. See below.]
+
+
+7. Bug reports, debugging and updates
+-------------------------------------
+Whenever you have problems with the driver, you are invited to ask the
+author for help. However, I'd suggest reading the docs and trying to solve
+the problem yourself, first. 
+If you find something, which you believe to be a bug, please report it to me. 
+Please append the output of /proc/scsi/scsi, /proc/scsi/tmscsim/? and
+maybe the DC390 log messages to the report. 
+
+Bug reports should be send to me (Kurt Garloff <K.Garloff@ping.de>) as well
+as to the linux-scsi list (<linux-scsi@vger.rutgers.edu>), as sometimes bugs
+are caused by the SCSI mid-level code.
+
+I will ask you for some more details and probably I will also ask you to
+enable some of the DEBUG options in the driver (tmscsim.c:DC390_DEBUGXXX
+defines). The driver will produce some data for the syslog facility then.
+Beware: If your syslog gets written to a SCSI disk connected to your
+AM53C974, the logging might produce log output again, and you might end
+having your box spending most of its time doing the logging.
+
+The latest version of the driver can be found at:
+ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+
+
+8. Acknowledgements
+-------------------
+Thanks to Linus Torvalds, Alan Cox, David Miller, Rik v. Riel, the FSF
+people, the XFree86 team and all the others for the wonderful OS and
+software. 
+Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver
+release and support.
+Thanks to Doug Ledford, Gerard Roudier for support with SCSI coding.
+Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert 
+Tonneau) for intensively testing the driver (and even risking data loss
+doing this during early revisions). 
+
+
+-------------------------------------------------------------------------
+Written by Kurt Garloff <K.Garloff@ping.de> 1998/06/11
+Last updated 1998/10/15, driver revision 2.0b
+$Id: README.tmscsim,v 2.4 1998/10/24 08:45:02 garloff Exp $
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.1.126/linux/drivers/scsi/aic7xxx.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/scsi/aic7xxx.c	Fri Nov  6 14:01:13 1998
@@ -349,7 +349,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.2"
+#define AIC7XXX_C_VERSION  "5.1.3"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -3429,10 +3429,7 @@
    * here so that we can delay all re-sent commands for this device for the
    * 4 seconds and then have our timer routine pick them back up.
    */
-        if(p->dev_timer[i].expires)
-        {
-          del_timer(&p->dev_timer[i]);
-        }
+        del_timer(&p->dev_timer[i]);
         p->dev_timer[i].expires = jiffies + (4 * HZ);
         add_timer(&p->dev_timer[i]);
       }
@@ -3481,12 +3478,8 @@
             "delayed_scbs queue!\n", p->host_no, channel, i, lun);
         scbq_init(&p->delayed_scbs[i]);
       }
-      if ( (p->delayed_scbs[i].head == NULL) &&
-           (p->dev_timer[i].expires) )
-      {
+      if ( p->delayed_scbs[i].head == NULL )
         del_timer(&p->dev_timer[i]);
-        p->dev_timer[i].expires = 0;
-      }
     }
   }
 
@@ -4007,7 +4000,7 @@
     }
     if ( (p->dev_active_cmds[tindex] >=
           p->dev_temp_queue_depth[tindex]) ||
-         (p->dev_last_reset[tindex] >= (jiffies - (4 * HZ))) )
+         time_after_eq(p->dev_last_reset[tindex], jiffies - 4 * HZ) )
     {
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
       if (aic7xxx_verbose > 0xffff)
@@ -4015,7 +4008,7 @@
                p->host_no, CTL_OF_SCB(scb));
 #endif
       scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-      if ( !(p->dev_timer[tindex].expires) &&
+      if ( !timer_pending(&p->dev_timer[tindex]) &&
            !(p->dev_active_cmds[tindex]) )
       {
         p->dev_timer[tindex].expires = p->dev_last_reset[tindex] + (4 * HZ);
@@ -4154,15 +4147,8 @@
 #endif
   for(i=0; i<MAX_TARGETS; i++)
   {
-    if ( (p->dev_timer[i].expires) && 
-          (p->dev_timer[i].expires <= jiffies) )
+    if ( del_timer(&p->dev_timer[i]) )
     {
-      p->dev_timer[i].expires = 0;
-      if ( (p->dev_timer[i].prev != NULL) ||
-           (p->dev_timer[i].next != NULL) )
-      {
-        del_timer(&p->dev_timer[i]);
-      }
       p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
       j = 0;
       while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
@@ -4895,7 +4881,7 @@
               p->activescbs--;
               scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
                   
-              if (p->dev_timer[tindex].expires == 0) 
+              if ( !timer_pending(&p->dev_timer[tindex]) ) 
               {
                 if ( p->dev_active_cmds[tindex] )
                 {
@@ -7462,7 +7448,7 @@
   }
 
   p->host = host;
-  p->last_reset = 0;
+  p->last_reset = jiffies;
   p->host_no = host->host_no;
   host->unique_id = p->instance;
   p->isr_count = 0;
@@ -7489,7 +7475,7 @@
     p->dev_commands_sent[i] = 0;
     p->dev_flags[i] = 0;
     p->dev_active_cmds[i] = 0;
-    p->dev_last_reset[i] = 0;
+    p->dev_last_reset[i] = jiffies;
     p->dev_last_queue_full[i] = 0;
     p->dev_last_queue_full_count[i] = 0;
     p->dev_max_queue_depth[i] = 1;
@@ -7497,7 +7483,6 @@
     p->dev_mid_level_queue_depth[i] = 3;
     scbq_init(&p->delayed_scbs[i]);
     init_timer(&p->dev_timer[i]);
-    p->dev_timer[i].expires = 0;
     p->dev_timer[i].data = (unsigned long)p;
     p->dev_timer[i].function = (void *)aic7xxx_timer;
   }
@@ -9184,6 +9169,27 @@
               aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
                                 CACHETHEN | MPARCKEN) & ~DPARCKEN,
                        DSCOMMAND0);
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7880:
+              /*
+               * Only set the DSCOMMAND0 register if this is a Rev B.
+               * chipset.  For those, we also enable Ultra mode by
+               * force due to brain-damage on the part of some BIOSes
+               * We overload the devconfig variable here since we can.
+               */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+#else
+              pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                                        &devconfig);
+#endif
+              if ((devconfig & 0xff) >= 1)
+              {
+                aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
+                                  CACHETHEN | MPARCKEN) & ~DPARCKEN,
+                         DSCOMMAND0);
+              }
               aic7xxx_load_seeprom(temp_p, &sxfrctl1);
               break;
           }
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/dc390.h linux/drivers/scsi/dc390.h
--- v2.1.126/linux/drivers/scsi/dc390.h	Fri Jul 31 17:07:58 1998
+++ linux/drivers/scsi/dc390.h	Sat Nov  7 11:29:55 1998
@@ -4,16 +4,20 @@
  *	Description: Device Driver for Tekram DC-390(T) PCI SCSI       *
  *		     Bus Master Host Adapter			       *
  ***********************************************************************/
+/* $Id: dc390.h,v 2.3 1998/10/24 08:45:02 garloff Exp $ */
 
 #include <linux/version.h>
 
 /*
- * AMD 53C974 driver, header file
+ * DC390/AMD 53C974 driver, header file
  */
 
 #ifndef DC390_H
 #define DC390_H
 
+#define DC390_BANNER "Tekram DC390/AM53C974"
+#define DC390_VERSION "2.0b 1998/10/24"
+
 #if defined(HOSTS_C) || defined(MODULE)
 
 #include <scsi/scsicam.h>
@@ -30,24 +34,24 @@
 # define DC390_release NULL
 #endif
 
-extern struct proc_dir_entry proc_scsi_tmscsim;
-extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+extern struct proc_dir_entry DC390_proc_scsi_tmscsim;
+extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
 
-#define DC390_T    {			          \
-   proc_dir:       &proc_scsi_tmscsim,            \
-   proc_info:      tmscsim_proc_info,             \
-   name:           "Tekram DC390(T) V1.12 Feb-25-1998",\
-   detect:         DC390_detect,   		  \
-   release:        DC390_release,		  \
-   queuecommand:   DC390_queue_command,	          \
-   abort:          DC390_abort,    		  \
-   reset:          DC390_reset,    		  \
-   bios_param:     DC390_bios_param,		  \
-   can_queue:      10,                 	          \
-   this_id:        7,                             \
-   sg_tablesize:   SG_ALL,            		  \
-   cmd_per_lun:    2,                 		  \
-   use_clustering: DISABLE_CLUSTERING 		  \
+#define DC390_T    {					\
+   proc_dir:       &DC390_proc_scsi_tmscsim,		\
+   proc_info:      DC390_proc_info,			\
+   name:           DC390_BANNER " V" DC390_VERSION,	\
+   detect:         DC390_detect,			\
+   release:        DC390_release,			\
+   queuecommand:   DC390_queue_command,			\
+   abort:          DC390_abort,				\
+   reset:          DC390_reset,				\
+   bios_param:     DC390_bios_param,			\
+   can_queue:      17,					\
+   this_id:        7,					\
+   sg_tablesize:   SG_ALL,				\
+   cmd_per_lun:    8,					\
+   use_clustering: DISABLE_CLUSTERING			\
    }
 
 #endif /* defined(HOSTS_C) || defined(MODULE) */
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.1.126/linux/drivers/scsi/ncr53c8xx.c	Fri Oct  9 13:27:11 1998
+++ linux/drivers/scsi/ncr53c8xx.c	Sun Oct 25 14:46:44 1998
@@ -73,7 +73,7 @@
 */
 
 /*
-**	October 4 1998, version 3.0i
+**	October 21 1998, version 3.1a
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -169,9 +169,11 @@
 #endif
 
 /*
-**	Define the BSD style u_int32 type
+**	Define the BSD style u_int32 and u_int64 type.
+**	Are in fact u_int32_t and u_int64_t :-)
 */
 typedef u32 u_int32;
+typedef u64 u_int64;
 
 #include "ncr53c8xx.h"
 
@@ -366,25 +368,14 @@
 #define NO_TAG	(255)
 
 /*
-**    For more than 32 TAGS support, we do some address calculation 
-**    from the SCRIPTS using 2 additionnal SCR_COPY's and a fiew 
-**    bit handling on 64 bit integers. For these reasons, support for 
-**    32 up to 64 TAGS is compiled conditionnaly.
+**	Choose appropriate type for tag bitmap.
 */
-
-#if	SCSI_NCR_MAX_TAGS <= 32
-struct nlink {
-	ncrcmd	l_cmd;
-	ncrcmd	l_paddr;
-};
+#if	SCSI_NCR_MAX_TAGS > 32
+typedef u_int64 tagmap_t;
 #else
-struct nlink {
-	ncrcmd	l_paddr;
-};
-typedef u64 u_int64;
+typedef u_int32 tagmap_t;
 #endif
 
-
 /*
 **    Number of targets supported by the driver.
 **    n permits target numbers 0..n-1.
@@ -583,16 +574,12 @@
 #define iounmap vfree
 #endif
 
-#ifdef __sparc__
+#if defined (__sparc__)
 #include <asm/irq.h>
-#define remap_pci_mem(base, size)	((vm_offset_t) __va(base))
-#define unmap_pci_mem(vaddr, size)
-#define pcivtophys(p)			((p) & pci_dvma_mask)
-#else
-#if defined(__alpha__)
-#define pcivtophys(p)			((p) & 0xfffffffful)
+#elif defined (__alpha__)
+#define bus_dvma_to_mem(p)		((p) & 0xfffffffful)
 #else
-#define pcivtophys(p)			(p)
+#define bus_dvma_to_mem(p)		(p)
 #endif
 
 #ifndef NCR_IOMAPPED
@@ -615,7 +602,6 @@
 		iounmap((void *) (vaddr & PAGE_MASK));
 }
 #endif	/* !NCR_IOMAPPED */
-#endif	/* __sparc__ */
 
 /*
 **	Insert a delay in micro-seconds and milli-seconds.
@@ -1488,8 +1474,8 @@
 	**	64 possible tags.
 	**----------------------------------------------------------------
 	*/
-	struct nlink	jump_ccb_0;	/* Default table if no tags	*/
-	struct nlink	*jump_ccb;	/* Virtual address		*/
+	u_int32		jump_ccb_0;	/* Default table if no tags	*/
+	u_int32		*jump_ccb;	/* Virtual address		*/
 
 	/*----------------------------------------------------------------
 	**	CCB queue management.
@@ -1514,11 +1500,7 @@
 	*/
 	u_char		ia_tag;		/* Allocation index		*/
 	u_char		if_tag;		/* Freeing index		*/
-#if SCSI_NCR_MAX_TAGS <= 32
-	u_char		cb_tags[32];	/* Circular tags buffer		*/
-#else
-	u_char		cb_tags[64];	/* Circular tags buffer		*/
-#endif
+	u_char cb_tags[SCSI_NCR_MAX_TAGS];	/* Circular tags buffer	*/
 	u_char		usetags;	/* Command queuing is active	*/
 	u_char		maxtags;	/* Max nr of tags asked by user	*/
 	u_char		numtags;	/* Current number of tags	*/
@@ -1528,14 +1510,13 @@
 	**	QUEUE FULL control and ORDERED tag control.
 	**----------------------------------------------------------------
 	*/
+	/*----------------------------------------------------------------
+	**	QUEUE FULL and ORDERED tag control.
+	**----------------------------------------------------------------
+	*/
 	u_short		num_good;	/* Nr of GOOD since QUEUE FULL	*/
-#if SCSI_NCR_MAX_TAGS <= 32
-	u_int		tags_umap;	/* Used tags bitmap		*/
-	u_int		tags_smap;	/* Tags in use at 'tag_stime'	*/
-#else
-	u_int64		tags_umap;	/* Used tags bitmap		*/
-	u_int64		tags_smap;	/* Tags in use at 'tag_stime'	*/
-#endif
+	tagmap_t	tags_umap;	/* Used tags bitmap		*/
+	tagmap_t	tags_smap;	/* Tags in use at 'tag_stime'	*/
 	u_long		tags_stime;	/* Last time we set smap=umap	*/
 	ccb_p		held_ccb;	/* CCB held for QUEUE FULL	*/
 };
@@ -2065,18 +2046,10 @@
 	ncrcmd	loadpos1	[  4];
 #endif
 	ncrcmd  resel_lun	[  6];
-#if SCSI_NCR_MAX_TAGS <= 32
-	ncrcmd	resel_tag	[  8];
-#else
 	ncrcmd	resel_tag	[  6];
 	ncrcmd	jump_to_nexus	[  4];
 	ncrcmd	nexus_indirect	[  4];
-#endif
-#if SCSI_NCR_MAX_TAGS <= 32
-	ncrcmd	resel_notag	[  4];
-#else
 	ncrcmd	resel_notag	[  4];
-#endif
 	ncrcmd  data_in		[MAX_SCATTERL * 4];
 	ncrcmd  data_in2	[  4];
 	ncrcmd  data_out	[MAX_SCATTERL * 4];
@@ -2987,18 +2960,12 @@
 	/*
 	**	Read the TAG from the SIDL.
 	**	Still an aggressive optimization. ;-)
+	**	Compute the CCB indirect jump address which 
+	**	is (#TAG*2 & 0xfc) due to tag numbering using 
+	**	1,3,5..MAXTAGS*2+1 actual values.
 	*/
-	SCR_FROM_REG (sidl),
-		0,
-	/*
-	**	JUMP indirectly to the restart point of the CCB.
-	*/
-#if SCSI_NCR_MAX_TAGS <= 32
-	SCR_SFBR_REG (temp, SCR_AND, 0xf8),
+	SCR_REG_SFBR (sidl, SCR_SHL, 0),
 		0,
-	SCR_RETURN,
-		0,
-#else
 	SCR_SFBR_REG (temp, SCR_AND, 0xfc),
 		0,
 }/*-------------------------< JUMP_TO_NEXUS >-------------------*/,{
@@ -3011,7 +2978,6 @@
 		RADDR (temp),
 	SCR_RETURN,
 		0,
-#endif
 }/*-------------------------< RESEL_NOTAG >-------------------*/,{
 	/*
 	**	No tag expected.
@@ -3019,13 +2985,8 @@
 	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin),
-#if SCSI_NCR_MAX_TAGS <= 32
-	SCR_RETURN,
-		0,
-#else
 	SCR_JUMP,
 		PADDR (jump_to_nexus),
-#endif
 }/*-------------------------< DATA_IN >--------------------*/,{
 /*
 **	Because the size depends on the
@@ -3907,7 +3868,7 @@
 				switch (old & RELOC_MASK) {
 				case RELOC_REGISTER:
 					new = (old & ~RELOC_MASK)
-							+ pcivtophys(np->paddr);
+						+ bus_dvma_to_mem(np->paddr);
 					break;
 				case RELOC_LABEL:
 					new = (old & ~RELOC_MASK) + np->p_script;
@@ -4654,7 +4615,7 @@
 	np->scripth	= np->scripth0;
 	np->p_scripth	= vtophys(np->scripth);
 
-	np->p_script	= (np->paddr2) ? pcivtophys(np->paddr2) : vtophys(np->script0);
+	np->p_script	= (np->paddr2) ? bus_dvma_to_mem(np->paddr2) : vtophys(np->script0);
 
 	ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
 	ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
@@ -5063,12 +5024,12 @@
 			}
 		}
 		msgptr[msglen++] = order;
-#if SCSI_NCR_MAX_TAGS <= 32
-		msgptr[msglen++] = (cp->tag << 3) + 1;
-#else
-		msgptr[msglen++] = (cp->tag << 2) + 1;
-#endif
-
+		/*
+		**	Actual tags are numbered 1,3,5,..2*MAXTAGS+1,
+		**	since we may have to deal with devices that have 
+		**	problems with #TAG 0 or too great #TAG numbers.
+		*/
+		msgptr[msglen++] = (cp->tag << 1) + 1;
 	}
 
 	switch (nego) {
@@ -5316,7 +5277,7 @@
 		++lp->queuedccbs;
 		cp = xpt_que_entry(qp, struct ccb, link_ccbq);
 		xpt_insque_tail(qp, &lp->busy_ccbq);
-		lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag].l_paddr =
+		lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag] =
 			cpu_to_scr(CCB_PHYS (cp, restart));
 		ncr_put_start_queue(np, cp);
 	}
@@ -5705,7 +5666,7 @@
 #ifdef DEBUG_NCR53C8XX
 	printk("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
 #endif
-				if (lp->maxnxs > 1)
+				if (lp->jump_ccb != &lp->jump_ccb_0)
 					m_free(lp->jump_ccb, 256);
 				m_free(lp, sizeof(*lp));
 			}
@@ -5861,9 +5822,10 @@
 		/*
 		**	On standard INQUIRY response (EVPD and CmDt 
 		**	not set), setup logical unit according to 
-		**	announced capabilities.
+		**	announced capabilities (we need the 1rst 7 bytes).
 		*/
-		if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3)) {
+		if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
+		    cmd->cmnd[4] >= 7) {
 			ncr_setup_lcb (np, cmd->target, cmd->lun,
 				       (char *) cmd->request_buffer);
 		}
@@ -6219,6 +6181,14 @@
 	}
 
 	/*
+	**	DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2.
+	**	Disable overlapped arbitration.
+	*/
+	if (np->device_id == PCI_DEVICE_ID_NCR_53C875 &&
+	    np->revision_id >= 0x10 && np->revision_id <= 0x15)
+		OUTB (nc_ctest0, (1<<5));
+
+	/*
 	**	Fill in target structure.
 	**	Reinitialize usrsync.
 	**	Reinitialize usrwide.
@@ -7778,7 +7748,7 @@
 		**	We just assume lun=0, 1 CCB, no tag.
 		*/
 		if (tp->lp[0]) { 
-			OUTL (nc_dsp, scr_to_cpu(tp->lp[0]->jump_ccb[0].l_paddr));
+			OUTL (nc_dsp, scr_to_cpu(tp->lp[0]->jump_ccb[0]));
 			return;
 		}
 	case SIR_RESEL_BAD_TARGET:	/* Will send a TARGET RESET message */
@@ -8307,17 +8277,9 @@
 	if (lp) {
 		if (tag != NO_TAG) {
 			++lp->ia_tag;
-#if SCSI_NCR_MAX_TAGS <= 32
-			if (lp->ia_tag == 32)
-#else
-			if (lp->ia_tag == 64)
-#endif
+			if (lp->ia_tag == SCSI_NCR_MAX_TAGS)
 				lp->ia_tag = 0;
-#if SCSI_NCR_MAX_TAGS <= 32
-			lp->tags_umap |= (1u << tag);
-#else
-			lp->tags_umap |= (((u_int64) 1) << tag);
-#endif
+			lp->tags_umap |= (((tagmap_t) 1) << tag);
 		}
 	}
 
@@ -8363,22 +8325,14 @@
 	if (lp) {
 		if (cp->tag != NO_TAG) {
 			lp->cb_tags[lp->if_tag++] = cp->tag;
-#if SCSI_NCR_MAX_TAGS <= 32
-			if (lp->if_tag == 32)
-#else
-			if (lp->if_tag == 64)
-#endif
+			if (lp->if_tag == SCSI_NCR_MAX_TAGS)
 				lp->if_tag = 0;
-#if SCSI_NCR_MAX_TAGS <= 32
-			lp->tags_umap &= ~(1u << cp->tag);
-#else
-			lp->tags_umap &= ~(((u_int64) 1) << cp->tag);
-#endif
+			lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
 			lp->tags_smap &= lp->tags_umap;
-			lp->jump_ccb[cp->tag].l_paddr =
+			lp->jump_ccb[cp->tag] =
 				cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l_q));
 		} else {
-			lp->jump_ccb[0].l_paddr =
+			lp->jump_ccb[0] =
 				cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l));
 		}
 	}
@@ -8412,7 +8366,7 @@
 
 
 #define ncr_reg_bus_addr(r) \
-	(pcivtophys(np->paddr) + offsetof (struct ncr_reg, r))
+	(bus_dvma_to_mem(np->paddr) + offsetof (struct ncr_reg, r))
 
 /*------------------------------------------------------------------------
 **	Initialize the fixed part of a CCB structure.
@@ -8579,28 +8533,6 @@
 
 
 /*------------------------------------------------------------------------
-**	Reselection JUMP table initialisation.
-**------------------------------------------------------------------------
-**	The SCRIPTS processor jumps on reselection to the entry 
-**	corresponding to the CCB using the tag as offset.
-**------------------------------------------------------------------------
-*/
-static void ncr_setup_jump_ccb(ncb_p np, lcb_p lp)
-{
-	int i;
-
-	lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb));
-	for (i = 0 ; i < lp->maxnxs ; i++) {
-#if SCSI_NCR_MAX_TAGS <= 32
-		lp->jump_ccb[i].l_cmd   = cpu_to_scr(SCR_JUMP);
-#endif
-		lp->jump_ccb[i].l_paddr =
-			cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
-		lp->cb_tags[i] = i;
-	}
-}
-
-/*------------------------------------------------------------------------
 **	Lun control block allocation and initialization.
 **------------------------------------------------------------------------
 **	This data structure is allocated and initialized after a SCSI 
@@ -8649,12 +8581,12 @@
 	xpt_que_init(&lp->skip_ccbq);
 
 	/*
-	**	Set max CCBs to 1 and use the default jump table 
-	**	by default.
+	**	Set max CCBs to 1 and use the default 1 entry 
+	**	jump table by default.
 	*/
-	lp->maxnxs = 1;
-	lp->jump_ccb = &lp->jump_ccb_0;
-	ncr_setup_jump_ccb(np, lp);
+	lp->maxnxs	= 1;
+	lp->jump_ccb	= &lp->jump_ccb_0;
+	lp->p_jump_ccb	= cpu_to_scr(vtophys(lp->jump_ccb));
 
 	/*
 	**	Initilialyze the reselect script:
@@ -8733,6 +8665,13 @@
 		inq_byte7 = inq_data[7];
 
 	/*
+	**	Throw away announced LUN capabilities if we are told 
+	**	that there is no real device supported by the logical unit.
+	*/
+	if ((inq_data[0] & 0xe0) > 0x20 || (inq_data[0] & 0x1f) == 0x1f)
+		inq_byte7 &= (INQ7_SYNC | INQ7_WIDE16);
+
+	/*
 	**	If user is wanting SYNC, force this feature.
 	*/
 	if (driver_setup.force_sync_nego)
@@ -8751,19 +8690,21 @@
 	**	If unit supports tagged commands, allocate the 
 	**	CCB JUMP table if not yet.
 	*/
-	if ((inq_byte7 & INQ7_QUEUE) && lp->maxnxs < 2) {
-		struct nlink *jumps;
-		jumps = m_alloc(256, 8);
-		if (!jumps)
+	if ((inq_byte7 & INQ7_QUEUE) && lp->jump_ccb == &lp->jump_ccb_0) {
+		int i;
+		lp->jump_ccb = m_alloc(256, 8);
+		if (!lp->jump_ccb) {
+			lp->jump_ccb = &lp->jump_ccb_0;
 			goto fail;
-#if SCSI_NCR_MAX_TAGS <= 32
-		lp->maxnxs   = 32;
-#else
-		lp->maxnxs   = 64;
-#endif
-		lp->jump_ccb = jumps;
-		ncr_setup_jump_ccb(np, lp);
-		lp->tags_stime	= jiffies;
+		}
+		lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb));
+		for (i = 0 ; i < 64 ; i++)
+			lp->jump_ccb[i] =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
+		for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++)
+			lp->cb_tags[i] = i;
+		lp->maxnxs = SCSI_NCR_MAX_TAGS;
+		lp->tags_stime = jiffies;
 	}
 
 	/*
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h
--- v2.1.126/linux/drivers/scsi/ncr53c8xx.h	Fri Oct  9 13:27:11 1998
+++ linux/drivers/scsi/ncr53c8xx.h	Sat Nov  7 11:29:54 1998
@@ -45,7 +45,7 @@
 /*
 **	Name and revision of the driver
 */
-#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 3.0i"
+#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 3.1a"
 
 /*
 **	Check supported Linux versions
@@ -468,7 +468,10 @@
  {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  6, 16, 5,			\
  FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
  ,									\
- {PCI_DEVICE_ID_NCR_53C875, 0xff, "875",  6, 16, 5,			\
+ {PCI_DEVICE_ID_NCR_53C875, 0x0f, "875",  6, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "876",  6, 16, 5,			\
  FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5,			\
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c
--- v2.1.126/linux/drivers/scsi/scsi_obsolete.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/scsi/scsi_obsolete.c	Mon Nov  2 09:14:08 1998
@@ -607,8 +607,10 @@
 	if ((++SCpnt->retries) < SCpnt->allowed)
 	{
 	    if ((SCpnt->retries >= (SCpnt->allowed >> 1))
-		&& !(SCpnt->host->last_reset > 0 &&
-		     jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
+		/* FIXME: last_reset == 0 is allowed
+                 *  && !(SCpnt->host->last_reset > 0 */ &&
+		     time_before(jiffies, SCpnt->host->last_reset
+                                 + MIN_RESET_PERIOD)
 		&& !(SCpnt->flags & WAS_RESET))
 	    {
 		printk("scsi%d channel %d : resetting for second half of retries.\n",
@@ -954,8 +956,8 @@
 		host->last_reset = jiffies;
 	        SCpnt->flags |= (WAS_RESET | IS_RESETTING);
 		temp = host->hostt->reset(SCpnt, reset_flags);
-		if ((host->last_reset < jiffies) ||
-		    (host->last_reset > (jiffies + 20 * HZ)))
+		if (time_before(host->last_reset, jiffies) ||
+		    (time_after(host->last_reset, jiffies + 20 * HZ)))
 		  host->last_reset = jiffies;
 		if (!host->block) host->host_busy--;
 	    }
@@ -1070,7 +1072,7 @@
    * timers for timeout.
    */
 
-  if( SCset->eh_timeout.expires == 0 )
+  if( !timer_pending(&SCset->eh_timeout) )
     {
       rtn = 0;
     }
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c
--- v2.1.126/linux/drivers/scsi/scsiiom.c	Sun Jun  7 11:16:35 1998
+++ linux/drivers/scsi/scsiiom.c	Tue Oct 27 10:10:08 1998
@@ -4,198 +4,264 @@
  *	Description: Device Driver for Tekram DC-390 (T) PCI SCSI      *
  *		     Bus Master Host Adapter			       *
  ***********************************************************************/
+/* $Id: scsiiom.c,v 2.3 1998/10/24 09:10:28 garloff Exp $ */
 
-
-static USHORT
-DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
+UCHAR
+dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
-    USHORT ioport, rc;
-    UCHAR  bval, bval1, i, cnt;
-    PUCHAR ptr;
-    ULONG  wlval;
+    USHORT wlval;
+    UCHAR  bval, bval1;
 
     pSRB->TagNumber = 31;
-    ioport = pACB->IOPortBase;
-    bval = pDCB->UnitSCSIID;
-    outb(bval,ioport+Scsi_Dest_ID);
-    bval = pDCB->SyncPeriod;
-    outb(bval,ioport+Sync_Period);
-    bval = pDCB->SyncOffset;
-    outb(bval,ioport+Sync_Offset);
-    bval = pDCB->CtrlR1;
-    outb(bval,ioport+CtrlReg1);
-    bval = pDCB->CtrlR3;
-    outb(bval,ioport+CtrlReg3);
-    bval = pDCB->CtrlR4;
-    outb(bval,ioport+CtrlReg4);
-    bval = CLEAR_FIFO_CMD;	   /* Flush FIFO */
-    outb(bval,ioport+ScsiCmd);
-
+    DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
+    DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+    DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+    DC390_write8 (CtrlReg1, pDCB->CtrlR1);
+    DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+    DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);		/* Flush FIFO */
+    DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\
+	    pSRB->CmdBlock[0], pDCB->SyncMode);)
     pSRB->ScsiPhase = SCSI_NOP0;
+    //pSRB->MsgOutBuf[0] = MSG_NOP;
+    //pSRB->MsgCnt = 0;
     bval = pDCB->IdentifyMsg;
-    if( !(pDCB->SyncMode & EN_ATN_STOP) )
+    if( !(pDCB->SyncMode & EN_ATN_STOP) )	/* Don't always try send Extended messages on arbitration */
     {
 	if( (pSRB->CmdBlock[0] == INQUIRY) ||
 	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
 	    (pSRB->SRBFlag & AUTO_REQSENSE) )
 	{
-	    bval &= 0xBF;	/* NO disconnection */
-	    outb(bval,ioport+ScsiFifo);
-	    bval1 = SELECT_W_ATN;
+	    bval &= 0xBF;	/* No DisConn */
+	    DC390_write8 (ScsiFifo, bval);
+	    bval1 = SEL_W_ATN;
 	    pSRB->SRBState = SRB_START_;
+	    DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
 	    if( pDCB->SyncMode & SYNC_ENABLE )
-	    {
-		if( !(pDCB->IdentifyMsg & 7) ||
+		{
+		if( !(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
 		    (pSRB->CmdBlock[0] != INQUIRY) )
 		{
-		    bval1 = SEL_W_ATN_STOP;
+		    bval1 = SEL_W_ATN_STOP;	/* Try to establish SYNC nego */
 		    pSRB->SRBState = SRB_MSGOUT;
 		}
 	    }
 	}
-	else
+	else	/* TagQ ? */
 	{
-	    if(pDCB->SyncMode & EN_TAG_QUEUING)
+	    DC390_write8 (ScsiFifo, bval);
+	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
 	    {
-		outb(bval,ioport+ScsiFifo);
-		bval = MSG_SIMPLE_QTAG;
-		outb(bval,ioport+ScsiFifo);
-		wlval = 1;
-		bval = 0;
-		while( wlval & pDCB->TagMask )
-		{
-		    wlval = wlval << 1;
-		    bval++;
-		}
-		outb(bval,ioport+ScsiFifo);
+	        DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG);
+		    DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
+	        bval = 0; wlval = 1;
+	        while (wlval & pDCB->TagMask)
+		  { bval++; wlval <<= 1; };
 		pDCB->TagMask |= wlval;
+	        DC390_write8 (ScsiFifo, bval);
 		pSRB->TagNumber = bval;
-		bval1 = SEL_W_ATN2;
+		DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
+		bval1 = SEL_W_ATN3;
 		pSRB->SRBState = SRB_START_;
 	    }
-	    else
+	    else	/* No TagQ */
 	    {
-		outb(bval,ioport+ScsiFifo);
-		bval1 = SELECT_W_ATN;
+		bval1 = SEL_W_ATN;
+		    DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
 		pSRB->SRBState = SRB_START_;
 	    }
 	}
 
-	if( pSRB->SRBFlag & AUTO_REQSENSE )
-	{
-	    bval = REQUEST_SENSE;
-	    outb(bval,ioport+ScsiFifo);
-	    bval = pDCB->IdentifyMsg << 5;
-	    outb(bval,ioport+ScsiFifo);
-	    bval = 0;
-	    outb(bval,ioport+ScsiFifo);
-	    outb(bval,ioport+ScsiFifo);
-	    bval = sizeof(pSRB->pcmd->sense_buffer);
-	    outb(bval,ioport+ScsiFifo);
-	    bval = 0;
-	    outb(bval,ioport+ScsiFifo);
-	}
-	else
-	{
-	    cnt = pSRB->ScsiCmdLen;
-	    ptr = (PUCHAR) pSRB->CmdBlock;
-	    for(i=0; i<cnt; i++)
-	    {
-		bval = *ptr++;
-		outb(bval,ioport+ScsiFifo);
-	    }
-	}
     }
-    else	/* ATN_STOP */
+    else	/* ATN_STOP: Always try to establish Sync nego */
     {
 	if( (pSRB->CmdBlock[0] == INQUIRY) ||
 	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
 	    (pSRB->SRBFlag & AUTO_REQSENSE) )
 	{
-	    bval &= 0xBF;
-	    outb(bval,ioport+ScsiFifo);
-	    bval1 = SELECT_W_ATN;
+	    bval &= 0xBF;	/* No DisConn */
+	    DC390_write8 (ScsiFifo, bval);
+	    bval1 = SEL_W_ATN;
+	    DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
 	    pSRB->SRBState = SRB_START_;
+	      /* ??? */
 	    if( pDCB->SyncMode & SYNC_ENABLE )
 	    {
-		if( !(pDCB->IdentifyMsg & 7) ||
+		if( !(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
 		    (pSRB->CmdBlock[0] != INQUIRY) )
 		{
-		    bval1 = SEL_W_ATN_STOP;
+		    bval1 = SEL_W_ATN_STOP;	/* Try to establish Sync nego */
 		    pSRB->SRBState = SRB_MSGOUT;
 		}
 	    }
 	}
-	else
+	else	/* TagQ ? */
 	{
-	    if(pDCB->SyncMode & EN_TAG_QUEUING)
+	    DC390_write8 (ScsiFifo, bval);
+	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
 	    {
-		outb(bval,ioport+ScsiFifo);
 		pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
-		wlval = 1;
-		bval = 0;
-		while( wlval & pDCB->TagMask )
-		{
-		    wlval = wlval << 1;
-		    bval++;
-		}
+		DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
+		bval = 0; wlval = 1;
+	        while (wlval & pDCB->TagMask)
+		  { bval++; wlval <<= 1; };
 		pDCB->TagMask |= wlval;
 		pSRB->TagNumber = bval;
+		DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
 		pSRB->MsgOutBuf[1] = bval;
 		pSRB->MsgCnt = 2;
 		bval1 = SEL_W_ATN_STOP;
-		pSRB->SRBState = SRB_START_;
+		pSRB->SRBState = SRB_START_;	/* ?? */
 	    }
-	    else
+	    else	/* No TagQ */
 	    {
-		outb(bval,ioport+ScsiFifo);
 		pSRB->MsgOutBuf[0] = MSG_NOP;
 		pSRB->MsgCnt = 1;
 		pSRB->SRBState = SRB_START_;
 		bval1 = SEL_W_ATN_STOP;
-	    }
+		DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
+	    };
 	}
     }
-    bval = inb( ioport+Scsi_Status );
-    if( bval & INTERRUPT )
+    if (bval1 != SEL_W_ATN_STOP)
+      {	/* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
+	if( pSRB->SRBFlag & AUTO_REQSENSE )
+	  {
+	    bval = 0;
+	    DC390_write8 (ScsiFifo, REQUEST_SENSE);
+	    DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
+	    DC390_write8 (ScsiFifo, bval);
+	    DC390_write8 (ScsiFifo, bval);
+	    DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+	    DC390_write8 (ScsiFifo, bval);
+	    DEBUG1(printk ("DC390: AutoReqSense !\n");)
+	  }
+	else	/* write cmnd to bus */ 
+	  {
+	    PUCHAR ptr; UCHAR i;
+	    ptr = (PUCHAR) pSRB->CmdBlock;
+	    for (i=0; i<pSRB->ScsiCmdLen; i++)
+	      DC390_write8 (ScsiFifo, *(ptr++));
+	  };
+      }
+
+    /* Check if we can't win arbitration */
+    if (DC390_read8 (Scsi_Status) & INTERRUPT)
     {
 	pSRB->SRBState = SRB_READY;
 	pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
-	rc = 1;
+	DEBUG0(printk ("DC390: Interrupt during StartSCSI!\n");)
+	return 1;
     }
     else
     {
 	pSRB->ScsiPhase = SCSI_NOP1;
+	DEBUG0(if (pACB->pActiveDCB)	\
+		    printk ("DC390: ActiveDCB != 0\n");)
+	DEBUG0(if (pDCB->pActiveSRB)	\
+		    printk ("DC390: ActiveSRB != 0\n");)
 	pACB->pActiveDCB = pDCB;
 	pDCB->pActiveSRB = pSRB;
-	rc = 0;
-	outb(bval1,ioport+ScsiCmd);
+	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+	DC390_write8 (ScsiCmd, bval1);
+	return 0;
     }
-    return( rc );
 }
 
+//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
+#define DMA_INT 0
+
+#if DMA_INT
+/* This is similar to AM53C974.c ... */
+static UCHAR 
+dc390_dma_intr (PACB pACB)
+{
+  PSRB pSRB;
+  UCHAR dstate;
+  DEBUG0(USHORT pstate;PDEVDECL1;)
+  
+  DEBUG0(PDEVSET1;)
+  DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);)
+  DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
+	{ printk("DC390: PCI state = %04x!\n", pstate); \
+	  PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};)
+
+  dstate = DC390_read8 (DMA_Status);
+  DC390_write8 (DMA_Status, dstate);	/* clear */
+  //DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+
+  if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
+  else pSRB  = pACB->pActiveDCB->pActiveSRB;
+  
+  if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT))
+    {
+	printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
+	return dstate;
+    };
+  if (dstate & DMA_XFER_DONE)
+    {
+	ULONG residual, xferCnt; int ctr = 5000000;
+	if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
+	  {
+	    do
+	      {
+		DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");)
+		dstate = DC390_read8 (DMA_Status);
+		DC390_write8 (DMA_Status, dstate);	/* clear */
+		residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
+		  DC390_read8 (CtcReg_High) << 16;
+		residual += DC390_read8 (Current_Fifo) & 0x1f;
+	      } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
+	    if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    /* residual =  ... */
+	  }
+	else
+	    residual = 0;
+	
+	/* ??? */
+	
+	xferCnt = pSRB->SGToBeXferLen - residual;
+	pSRB->SGBusAddr += xferCnt;
+	pSRB->TotalXferredLen += xferCnt;
+	pSRB->SGToBeXferLen = residual;
+# ifdef DC390_DEBUG0
+	printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", 
+		(unsigned int)residual, (unsigned int)xferCnt);
+# endif
+	
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    }
+  return dstate;
+};
+#endif
 
-static void
+void __inline__
 DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
 {
     PACB   pACB;
     PDCB   pDCB;
     PSRB   pSRB;
-    USHORT ioport = 0;
-    USHORT phase, i;
+    UCHAR  sstatus=0;
+    UCHAR  phase, i;
     void   (*stateV)( PACB, PSRB, PUCHAR );
-    UCHAR  istate = 0;
-    UCHAR  sstatus=0, istatus;
+    UCHAR  istate, istatus;
+    UCHAR  dstatus;
+    DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS
+
+    pACB = dc390_pACB_start;
 
-    pACB = pACB_start;
-    if( pACB == NULL )
+    if (pACB == 0)
+    {
+	printk(KERN_ERR "DC390: Interrupt on uninitialized adapter!\n");
 	return;
-    for( i=0; i < adapterCnt; i++ )
+    }
+    DC390_LOCK_DRV;
+
+    for( i=0; i < dc390_adapterCnt; i++ )
     {
 	if( pACB->IRQLevel == (UCHAR) irq )
 	{
-	     ioport = pACB->IOPortBase;
-	     sstatus = inb( ioport+Scsi_Status );
+	     sstatus = DC390_read8 (Scsi_Status);
 	     if( sstatus & INTERRUPT )
 		 break;
 	     else
@@ -207,99 +273,128 @@
 	}
     }
 
-#ifdef DC390_DEBUG1
-	printk("sstatus=%2x,",sstatus);
-#endif
+    DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);)
 
-    if( pACB == (PACB )-1 )
-    {
-	printk("DC390: Spurious interrupt detected!\n");
+    if( pACB == (PACB )-1) { DC390_UNLOCK_DRV; return; };
+   
+#if DMA_INT
+    DC390_LOCK_IO;
+    DC390_LOCK_ACB;
+    dstatus = dc390_dma_intr (pACB);
+    DC390_UNLOCK_ACB;
+    DC390_UNLOCK_IO;
+
+    DEBUG1(printk ("dstatus=%02x,", dstatus);)
+    if (! (dstatus & SCSI_INTERRUPT))
+      {
+	DEBUG0(printk ("DC390 Int w/o SCSI actions (only DMA?)\n");)
+	DC390_UNLOCK_DRV;
 	return;
-    }
-
-    istate = inb( ioport+Intern_State );
-    istatus = inb( ioport+INT_Status );
-
-#ifdef DC390_DEBUG1
-	printk("Istatus=%2x,",istatus);
+      };
+#else
+    dstatus = DC390_read8 (DMA_Status);
 #endif
 
+    DC390_LOCK_IO;
+    DC390_LOCK_ACB;
+    DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */
+
+    istate = DC390_read8 (Intern_State);
+    istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
+
+    DEBUG1(printk ("Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);)
+    dc390_laststatus = dstatus<<24 | sstatus<<16 | istate<<8 | istatus;
+
+    if (sstatus & ILLEGAL_OP_ERR)
+       {
+	       printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
+	       dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
+       };
+	
     if(istatus &  DISCONNECTED)
     {
-	DC390_Disconnect( pACB );
-	return;
+	dc390_Disconnect( pACB );
+	goto unlock;
     }
 
     if(istatus &  RESELECTED)
     {
-	DC390_Reselect( pACB );
-	return;
+	dc390_Reselect( pACB );
+	goto unlock;
     }
 
     if(istatus &  INVALID_CMD)
     {
-	DC390_InvalidCmd( pACB );
-	return;
+	dc390_InvalidCmd( pACB );
+	goto unlock;
     }
 
     if(istatus &  SCSI_RESET)
     {
-	DC390_ScsiRstDetect( pACB );
-	return;
+	dc390_ScsiRstDetect( pACB );
+	goto unlock;
     }
 
-    if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) )
+    if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
     {
 	pDCB = pACB->pActiveDCB;
-	pSRB = pDCB->pActiveSRB;
-	if( pDCB )
+	if (!pDCB)
 	{
-	    if( pDCB->DCBFlag & ABORT_DEV_ )
-		EnableMsgOut( pACB, pSRB );
-	}
+		printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n");
+		goto unlock;
+	};
+	pSRB = pDCB->pActiveSRB;
+	if( pDCB->DCBFlag & ABORT_DEV_ )
+		dc390_EnableMsgOut( pACB, pSRB );
 
-	phase = (USHORT) pSRB->ScsiPhase;
-	stateV = (void *) DC390_phase0[phase];
-	stateV( pACB, pSRB, &sstatus );
+	phase = pSRB->ScsiPhase;
+	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);)
+	stateV = (void *) dc390_phase0[phase];
+	( *stateV )( pACB, pSRB, &sstatus );
 
 	pSRB->ScsiPhase = sstatus & 7;
-	phase = (USHORT) sstatus & 7;
-	stateV = (void *) DC390_phase1[phase];
-	stateV( pACB, pSRB, &sstatus );
-    }
+	phase = (UCHAR) sstatus & 7;
+	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);)
+	stateV = (void *) dc390_phase1[phase];
+	( *stateV )( pACB, pSRB, &sstatus );
+    }
+ unlock:
+    DC390_LOCK_DRV_NI;
+    DC390_UNLOCK_ACB;
+    DC390_UNLOCK_IO;
+    DC390_UNLOCK_DRV; /* Restore initial flags */
 }
 
-static void
+void
 do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
 {
-    unsigned long flags;
-
-    spin_lock_irqsave(&io_request_lock, flags);
+    DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq);)
+    /* Locking is done in DC390_Interrupt */
     DC390_Interrupt(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    DEBUG1(printk (".. IRQ returned\n");)
 }
 
-static void
-DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR   sstatus, bval;
-    USHORT  ioport;
+    UCHAR   sstatus;
     PSGL    psgl;
     ULONG   ResidCnt, xferCnt;
 
-    ioport = pACB->IOPortBase;
     sstatus = *psstatus;
 
     if( !(pSRB->SRBState & SRB_XFERPAD) )
     {
-	if( sstatus & PARITY_ERR )
+	if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) )
 	    pSRB->SRBStatus |= PARITY_ERROR;
 
 	if( sstatus & COUNT_2_ZERO )
 	{
-	    bval = inb(ioport+DMA_Status);
-	    while( !(bval & DMA_XFER_DONE) )
-		bval = inb(ioport+DMA_Status);
+	    int ctr = 5000000; /* only try for about a tenth of a second */
+	    while( --ctr && !(DC390_read8 (DMA_Status) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
+		DC390_write8 (DMA_Status,  DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+	    if (!ctr) printk (KERN_CRIT "DC390: DataOut_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    DC390_write8 (DMA_Status,  DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
 	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
 	    pSRB->SGIndex++;
 	    if( pSRB->SGIndex < pSRB->SGcount )
@@ -307,7 +402,7 @@
 		pSRB->pSegmentList++;
 		psgl = pSRB->pSegmentList;
 
-		pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+		pSRB->SGBusAddr = virt_to_bus( psgl->address );
 		pSRB->SGToBeXferLen = (ULONG) psgl->length;
 	    }
 	    else
@@ -315,51 +410,50 @@
 	}
 	else
 	{
-	    bval = inb( ioport+Current_Fifo );
-	    bval &= 0x1f;
-	    ResidCnt = (ULONG) inb(ioport+CtcReg_High);
-	    ResidCnt = ResidCnt << 8;
-	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
-	    ResidCnt = ResidCnt << 8;
-	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
-	    ResidCnt += (ULONG) bval;
+	    ResidCnt = (ULONG) DC390_read8 (Current_Fifo) & 0x1f;
+	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_High) << 16;
+	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid) << 8; 
+	    ResidCnt += (ULONG) DC390_read8 (CtcReg_Low);
 
 	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-	    pSRB->SGPhysAddr += xferCnt;
+	    pSRB->SGBusAddr += xferCnt;
 	    pSRB->TotalXferredLen += xferCnt;
 	    pSRB->SGToBeXferLen = ResidCnt;
 	}
     }
-    bval = WRITE_DIRECTION+DMA_IDLE_CMD;
-    outb( bval, ioport+DMA_Cmd);
+    DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 }
 
-static void
-DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR   sstatus, bval;
-    USHORT  i, ioport, residual;
+    UCHAR   sstatus, residual, bval;
     PSGL    psgl;
-    ULONG   ResidCnt, xferCnt;
+    ULONG   ResidCnt, xferCnt, i;
     PUCHAR  ptr;
 
-
-    ioport = pACB->IOPortBase;
     sstatus = *psstatus;
 
     if( !(pSRB->SRBState & SRB_XFERPAD) )
     {
-	if( sstatus & PARITY_ERR )
+	if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR))
 	    pSRB->SRBStatus |= PARITY_ERROR;
 
 	if( sstatus & COUNT_2_ZERO )
 	{
-	    bval = inb(ioport+DMA_Status);
-	    while( !(bval & DMA_XFER_DONE) )
-		bval = inb(ioport+DMA_Status);
+	    int ctr = 5000000; /* only try for about a tenth of a second */
+	    int dstate = 0;
+	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
+		DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+	    if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate);
+	    DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16)	\
+		+ ((ULONG) DC390_read8 (CtcReg_Mid) << 8)		\
+		+ ((ULONG) DC390_read8 (CtcReg_Low));)
+	    DEBUG1(printk ("Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
+	    DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
 
-	    bval = READ_DIRECTION+DMA_IDLE_CMD;
-	    outb( bval, ioport+DMA_Cmd);
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 
 	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
 	    pSRB->SGIndex++;
@@ -368,7 +462,7 @@
 		pSRB->pSegmentList++;
 		psgl = pSRB->pSegmentList;
 
-		pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+		pSRB->SGBusAddr = virt_to_bus( psgl->address );
 		pSRB->SGToBeXferLen = (ULONG) psgl->length;
 	    }
 	    else
@@ -377,14 +471,15 @@
 	else	/* phase changed */
 	{
 	    residual = 0;
-	    bval = inb(ioport+Current_Fifo);
+	    bval = DC390_read8 (Current_Fifo);
 	    while( bval & 0x1f )
 	    {
+		DEBUG1(printk ("Check for residuals,");)
 		if( (bval & 0x1f) == 1 )
 		{
-		    for(i=0; i< 0x100; i++)
+		    for(i=0; i < 0x100; i++)
 		    {
-			bval = inb(ioport+Current_Fifo);
+			bval = DC390_read8 (Current_Fifo);
 			if( !(bval & 0x1f) )
 			    goto din_1;
 			else if( i == 0x0ff )
@@ -395,87 +490,85 @@
 		    }
 		}
 		else
-		    bval = inb(ioport+Current_Fifo);
+		    bval = DC390_read8 (Current_Fifo);
 	    }
 din_1:
-	    bval = READ_DIRECTION+DMA_BLAST_CMD;
-	    outb(bval, ioport+DMA_Cmd);
-	    for(i=0; i<0x8000; i++)
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD);
+	    for (i=0; i<0x8000; i++)
 	    {
-		bval = inb(ioport+DMA_Status);
-		if(bval & BLAST_COMPLETE)
+		bval = DC390_read8 (DMA_Status);
+		DC390_write8 (DMA_Status, BLAST_COMPLETE | DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+		if (bval & BLAST_COMPLETE)
 		    break;
 	    }
-	    bval = READ_DIRECTION+DMA_IDLE_CMD;
-	    outb(bval, ioport+DMA_Cmd);
+	    if (i == 0x8000) printk (KERN_CRIT "DC390: DMA Blast aborted unfinished!!\n");
+	    //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 
-	    ResidCnt = (ULONG) inb(ioport+CtcReg_High);
-	    ResidCnt = ResidCnt << 8;
-	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
-	    ResidCnt = ResidCnt << 8;
-	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+	    DEBUG1(printk ("Blast: Read %i times DMA_Status %02x", i, bval);)
+	    ResidCnt = (ULONG) DC390_read8 (CtcReg_High);
+	    ResidCnt <<= 8;
+	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid);
+	    ResidCnt <<= 8;
+	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low);
 
 	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-	    pSRB->SGPhysAddr += xferCnt;
+	    pSRB->SGBusAddr += xferCnt;
 	    pSRB->TotalXferredLen += xferCnt;
 	    pSRB->SGToBeXferLen = ResidCnt;
 
 	    if( residual )
 	    {
-		bval = inb(ioport+ScsiFifo);	    /* get residual byte */
-		ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );
+		bval = DC390_read8 (ScsiFifo);	    /* get one residual byte */
+		ptr = (PUCHAR) bus_to_virt( pSRB->SGBusAddr );
 		*ptr = bval;
-		pSRB->SGPhysAddr++;
+		pSRB->SGBusAddr++; xferCnt++;
 		pSRB->TotalXferredLen++;
 		pSRB->SGToBeXferLen--;
 	    }
+	    DEBUG1(printk ("Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+			   pSRB->TotalXferredLen, pSRB->SGToBeXferLen);)
+
 	}
     }
 }
 
 static void
-DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
 }
 
 static void
-DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  bval;
-    USHORT ioport;
 
-    ioport = pACB->IOPortBase;
-    bval = inb(ioport+ScsiFifo);
-    pSRB->TargetStatus = bval;
-    bval++;
-    bval = inb(ioport+ScsiFifo);	/* get message */
-    pSRB->EndMessage = bval;
+    pSRB->TargetStatus = DC390_read8 (ScsiFifo);
+    //udelay (1);
+    pSRB->EndMessage = DC390_read8 (ScsiFifo);	/* get message */
 
     *psstatus = SCSI_NOP0;
     pSRB->SRBState = SRB_COMPLETED;
-    bval = MSG_ACCEPTED_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
 }
 
 static void
-DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
 	*psstatus = SCSI_NOP0;
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-static void
-DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     UCHAR  bval;
-    USHORT ioport, wval, wval1;
+    USHORT wval, wval1;
     PDCB   pDCB;
     PSRB   psrb;
 
-    ioport = pACB->IOPortBase;
     pDCB = pACB->pActiveDCB;
 
-    bval = inb( ioport+ScsiFifo );
+    bval = DC390_read8 (ScsiFifo);
     if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
     {
 	if(bval == MSG_DISCONNECT)
@@ -490,12 +583,12 @@
 	    pSRB->SRBState |= SRB_MSGIN_MULTI;
 	    pSRB->MsgInBuf[0] = bval;
 	    pSRB->MsgCnt = 1;
-	    pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
+	    pSRB->pMsgPtr = &(pSRB->MsgInBuf[1]);
 	}
 	else if(bval == MSG_REJECT_)
 	{
-	    bval = RESET_ATN_CMD;
-	    outb(bval, ioport+ScsiCmd);
+	    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+	    pDCB->NegoPeriod = 50;
 	    if( pSRB->SRBState & DO_SYNC_NEGO)
 		goto  set_async;
 	}
@@ -521,7 +614,7 @@
 		psrb = pDCB->pGoingLast;
 		if( pSRB )
 		{
-		    for( ;; )
+		    for( ;pSRB ; )
 		    {
 			if(pSRB->TagNumber != bval)
 			{
@@ -535,7 +628,7 @@
 		    if( pDCB->DCBFlag & ABORT_DEV_ )
 		    {
 			pSRB->SRBState = SRB_ABORT_SENT;
-			EnableMsgOut( pACB, pSRB );
+			dc390_EnableMsgOut( pACB, pSRB );
 		    }
 		    if( !(pSRB->SRBState & SRB_DISCONNECT) )
 			goto  mingx0;
@@ -549,234 +642,199 @@
 		    pSRB->SRBState = SRB_UNEXPECT_RESEL;
 		    pDCB->pActiveSRB = pSRB;
 		    pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
-		    EnableMsgOut2( pACB, pSRB );
+		    dc390_EnableMsgOut2( pACB, pSRB );
 		}
 	    }
 	}
 	else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
-	{
-	    pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO);
-	    if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) )
+	{	/* Note: This will fail for target initiated SDTR ? */
+	    pSRB->SRBState &= ~(SRB_MSGIN_MULTI);
+	    if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != EXTENDED_SDTR) )
 	    {	/* reject_msg: */
 		pSRB->MsgCnt = 1;
 		pSRB->MsgInBuf[0] = MSG_REJECT_;
-		bval = SET_ATN_CMD;
-		outb(bval, ioport+ScsiCmd);
+		DC390_write8 (ScsiCmd, SET_ATN_CMD);
 	    }
 	    else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
 	    {
 set_async:
 		pDCB = pSRB->pSRBDCB;
+		if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
+			printk ("DC390: Target (%i,%i) initiates Non-Sync?\n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+		pSRB->SRBState &= ~DO_SYNC_NEGO;
 		pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
 		pDCB->SyncPeriod = 0;
 		pDCB->SyncOffset = 0;
-		pDCB->CtrlR3 = FAST_CLK;     /* ;non_fast */
+		pDCB->CtrlR3 = FAST_CLK;	/* fast clock / normal scsi */
 		pDCB->CtrlR4 &= 0x3f;
-		pDCB->CtrlR4 |= EATER_25NS;  /* ; 25ns glitch eater */
-		goto  re_prog;
+		pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
+		goto re_prog;
 	    }
 	    else
 	    {	/* set_sync: */
 
 		pDCB = pSRB->pSRBDCB;
+		if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
+			printk ("DC390: Target (%i,%i) initiates Sync: %ins %i ?\n", 
+				pDCB->UnitSCSIID, pDCB->UnitSCSILUN, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
+		pSRB->SRBState &= ~DO_SYNC_NEGO;
 		pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
 		pDCB->SyncOffset &= 0x0f0;
 		pDCB->SyncOffset |= pSRB->MsgInBuf[4];
 		pDCB->NegoPeriod = pSRB->MsgInBuf[3];
 		wval = (USHORT) pSRB->MsgInBuf[3];
-		wval = wval << 2;
-		wval--;
-		wval1 = wval / 25;
+		wval = wval << 2; wval -= 3; wval1 = wval / 25;	/* compute speed */
 		if( (wval1 * 25) != wval)
 		    wval1++;
-		bval = FAST_CLK+FAST_SCSI;
-		pDCB->CtrlR4 &= 0x3f;
-		if(wval1 >= 8)
+		bval = FAST_CLK+FAST_SCSI;	/* fast clock / fast scsi */
+		pDCB->CtrlR4 &= 0x3f;		/* Glitch eater: 12ns less than normal */
+		if (pACB->glitch_cfg != NS_TO_GLITCH(0))
+			pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
+		else
+			pDCB->CtrlR4 |= NS_TO_GLITCH(0);
+		if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
+		if (wval1 >= 8)
 		{
-		    wval1--;
-		    bval = FAST_CLK;	    /* ;fast clock/normal scsi */
-		    pDCB->CtrlR4 |= EATER_25NS;   /* ;25 ns glitch eater */
+		    wval1--;	/* Timing computation differs by 1 from FAST_SCSI */
+		    bval = FAST_CLK;		/* fast clock / normal scsi */
+		    pDCB->CtrlR4 |= pACB->glitch_cfg; 	/* glitch eater */
 		}
 		pDCB->CtrlR3 = bval;
 		pDCB->SyncPeriod = (UCHAR)wval1;
 re_prog:
-		bval = pDCB->SyncPeriod;
-		outb(bval, ioport+Sync_Period);
-		bval = pDCB->SyncOffset;
-		outb(bval, ioport+Sync_Offset);
-		bval = pDCB->CtrlR3;
-		outb(bval, ioport+CtrlReg3);
-		bval = pDCB->CtrlR4;
-		outb(bval, ioport+CtrlReg4);
-		SetXferRate( pACB, pDCB);
+	        DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+	        DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+	        DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+	        DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+		dc390_SetXferRate (pACB, pDCB);
 	    }
 	}
     }
 min6:
     *psstatus = SCSI_NOP0;
-    bval = MSG_ACCEPTED_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-static void
-DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
+void
+dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
 {
     PSGL   psgl;
-    UCHAR  bval;
-    USHORT ioport;
     ULONG  lval;
 
-
-    ioport = pACB->IOPortBase;
     if( pSRB->SGIndex < pSRB->SGcount )
     {
-	bval = DMA_IDLE_CMD | ioDir;   /* ;+EN_DMA_INT */
-	outb( bval, ioport+DMA_Cmd);
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
 	if( !pSRB->SGToBeXferLen )
 	{
 	    psgl = pSRB->pSegmentList;
-	    pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+	    pSRB->SGBusAddr = virt_to_bus( psgl->address );
 	    pSRB->SGToBeXferLen = (ULONG) psgl->length;
+	    DEBUG1(printk (" DC390: Next SG segment.");)
 	}
 	lval = pSRB->SGToBeXferLen;
-	bval = (UCHAR) lval;
-	outb(bval,ioport+CtcReg_Low);
-	lval = lval >> 8;
-	bval = (UCHAR) lval;
-	outb(bval,ioport+CtcReg_Mid);
-	lval = lval >> 8;
-	bval = (UCHAR) lval;
-	outb(bval,ioport+CtcReg_High);
+	DEBUG1(printk (" DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
+	DC390_write8 (CtcReg_Low, (UCHAR) lval);
+	lval >>= 8;
+	DC390_write8 (CtcReg_Mid, (UCHAR) lval);
+	lval >>= 8;
+	DC390_write8 (CtcReg_High, (UCHAR) lval);
 
-	lval = pSRB->SGToBeXferLen;
-	outl(lval, ioport+DMA_XferCnt);
-
-	lval = pSRB->SGPhysAddr;
-	outl( lval, ioport+DMA_XferAddr);
-
-	bval = DMA_COMMAND+INFO_XFER_CMD;
-	outb(bval, ioport+ScsiCmd);
+	DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
+	DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
 
+	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
 	pSRB->SRBState = SRB_DATA_XFER;
 
-	bval = DMA_IDLE_CMD | ioDir;	/* ;+EN_DMA_INT */
-	outb(bval, ioport+DMA_Cmd);
+	DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
 
-	bval = DMA_START_CMD | ioDir;	/* ;+EN_DMA_INT */
-	outb(bval, ioport+DMA_Cmd);
+	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+	//DEBUG1(printk ("DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));)
     }
     else    /* xfer pad */
     {
+	UCHAR bval = 0;
 	if( pSRB->SGcount )
 	{
 	    pSRB->AdaptStatus = H_OVER_UNDER_RUN;
 	    pSRB->SRBStatus |= OVER_RUN;
+	    DEBUG0(printk (" DC390: Overrun -");)
 	}
-	bval = 0;
-	outb(bval,ioport+CtcReg_Low);
-	outb(bval,ioport+CtcReg_Mid);
-	outb(bval,ioport+CtcReg_High);
+	DEBUG0(printk (" Clear transfer pad \n");)
+	DC390_write8 (CtcReg_Low, bval);
+	DC390_write8 (CtcReg_Mid, bval);
+	DC390_write8 (CtcReg_High, bval);
 
 	pSRB->SRBState |= SRB_XFERPAD;
-	bval = DMA_COMMAND+XFER_PAD_BYTE;
-	outb(bval, ioport+ScsiCmd);
+	DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
 /*
-	bval = DMA_IDLE_CMD | ioDir;	;+EN_DMA_INT
-	outb(bval, ioport+DMA_Cmd);
-	bval = DMA_START_CMD | ioDir;	;+EN_DMA_INT
-	outb(bval, ioport+DMA_Cmd);
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
+	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
 */
     }
 }
 
 
 static void
-DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  ioDir;
-
-    ioDir = WRITE_DIRECTION;
-    DataIO_Comm( pACB, pSRB, ioDir);
+    dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION);
 }
 
 static void
-DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  ioDir;
-
-    ioDir = READ_DIRECTION;
-    DataIO_Comm( pACB, pSRB, ioDir);
+    dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION);
 }
 
-static void
-DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     PDCB   pDCB;
-    UCHAR  bval;
+    UCHAR  i, cnt;
     PUCHAR ptr;
-    USHORT ioport, i,  cnt;
-
 
-    ioport = pACB->IOPortBase;
-    bval = RESET_ATN_CMD;
-    outb(bval, ioport+ScsiCmd);
-    bval = CLEAR_FIFO_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
     {
-	cnt = (USHORT) pSRB->ScsiCmdLen;
+	cnt = (UCHAR) pSRB->ScsiCmdLen;
 	ptr = (PUCHAR) pSRB->CmdBlock;
 	for(i=0; i < cnt; i++)
-	{
-	    outb(*ptr, ioport+ScsiFifo);
-	    ptr++;
-	}
+	    DC390_write8 (ScsiFifo, *(ptr++));
     }
     else
     {
-	bval = REQUEST_SENSE;
-	outb(bval, ioport+ScsiFifo);
+	UCHAR bval = 0;
+	DC390_write8 (ScsiFifo, REQUEST_SENSE);
 	pDCB = pACB->pActiveDCB;
-	bval = pDCB->IdentifyMsg << 5;
-	outb(bval, ioport+ScsiFifo);
-	bval = 0;
-	outb(bval, ioport+ScsiFifo);
-	outb(bval, ioport+ScsiFifo);
-	bval = sizeof(pSRB->pcmd->sense_buffer);
-	outb(bval, ioport+ScsiFifo);
-	bval = 0;
-	outb(bval, ioport+ScsiFifo);
+	DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
+	DC390_write8 (ScsiFifo, bval);
+	DC390_write8 (ScsiFifo, bval);
+	DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+	DC390_write8 (ScsiFifo, bval);
     }
     pSRB->SRBState = SRB_COMMAND;
-    bval = INFO_XFER_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
 }
 
 static void
-DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  bval;
-    USHORT ioport;
-
-    ioport = pACB->IOPortBase;
-    bval = CLEAR_FIFO_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     pSRB->SRBState = SRB_STATUS;
-    bval = INITIATOR_CMD_CMPLTE;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-static void
-DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR   bval;
-    USHORT  ioport, i, cnt;
+    UCHAR   bval, i, cnt;
     PUCHAR  ptr;
     PDCB    pDCB;
 
-    ioport = pACB->IOPortBase;
-    bval = CLEAR_FIFO_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     pDCB = pACB->pActiveDCB;
     if( !(pSRB->SRBState & SRB_MSGOUT) )
     {
@@ -785,10 +843,7 @@
 	{
 	    ptr = (PUCHAR) pSRB->MsgOutBuf;
 	    for(i=0; i < cnt; i++)
-	    {
-		outb(*ptr, ioport+ScsiFifo);
-		ptr++;
-	    }
+		DC390_write8 (ScsiFifo, *(ptr++));
 	    pSRB->MsgCnt = 0;
 	    if( (pDCB->DCBFlag & ABORT_DEV_) &&
 		(pSRB->MsgOutBuf[0] == MSG_ABORT) )
@@ -804,76 +859,67 @@
 		if( pDCB->SyncMode & SYNC_ENABLE )
 		    goto  mop1;
 	    }
-	    outb(bval, ioport+ScsiFifo);
+	    DC390_write8 (ScsiFifo, bval);
 	}
-	bval = INFO_XFER_CMD;
-	outb( bval, ioport+ScsiCmd);
+	DC390_write8 (ScsiCmd, INFO_XFER_CMD);
     }
     else
     {
 mop1:
-	bval = MSG_EXTENDED;
-	outb(bval, ioport+ScsiFifo);
-	bval = 3;	/*    ;length of extended msg */
-	outb(bval, ioport+ScsiFifo);
-	bval = 1;	/*    ; sync nego */
-	outb(bval, ioport+ScsiFifo);
-	bval = pDCB->NegoPeriod;
-	outb(bval, ioport+ScsiFifo);
-	bval = SYNC_NEGO_OFFSET;
-	outb(bval, ioport+ScsiFifo);
+	//printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+	DC390_write8 (ScsiFifo, MSG_EXTENDED);
+	DC390_write8 (ScsiFifo, 3);	/*    ;length of extended msg */
+	DC390_write8 (ScsiFifo, EXTENDED_SDTR);	/*    ; sync nego */
+	DC390_write8 (ScsiFifo, pDCB->NegoPeriod);
+	if (pDCB->SyncOffset & 0x0f)
+		    DC390_write8 (ScsiFifo, pDCB->SyncOffset);
+	else
+		    DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET);		    
 	pSRB->SRBState |= DO_SYNC_NEGO;
-	bval = INFO_XFER_CMD;
-	outb(bval, ioport+ScsiCmd);
+	DC390_write8 (ScsiCmd, INFO_XFER_CMD);
     }
 }
 
 static void
-DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR  bval;
-    USHORT ioport;
-
-    ioport = pACB->IOPortBase;
-    bval = CLEAR_FIFO_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     if( !(pSRB->SRBState & SRB_MSGIN) )
     {
-	pSRB->SRBState &= SRB_DISCONNECT;
+	pSRB->SRBState &= ~SRB_DISCONNECT;
 	pSRB->SRBState |= SRB_MSGIN;
     }
-    bval = INFO_XFER_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
 static void
-DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
 }
 
 static void
-DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
 }
 
 
 static void
-SetXferRate( PACB pACB, PDCB pDCB )
+dc390_SetXferRate( PACB pACB, PDCB pDCB )
 {
-    UCHAR  bval;
-    USHORT cnt, i;
+    UCHAR  bval, i, cnt;
     PDCB   ptr;
 
     if( !(pDCB->IdentifyMsg & 0x07) )
     {
 	if( pACB->scan_devices )
 	{
-	    CurrSyncOffset = pDCB->SyncOffset;
+	    dc390_CurrSyncOffset = pDCB->SyncOffset;
 	}
 	else
 	{
 	    ptr = pACB->pLinkDCB;
-	    cnt = pACB->DeviceCnt;
+	    cnt = pACB->DCBCnt;
 	    bval = pDCB->UnitSCSIID;
 	    for(i=0; i<cnt; i++)
 	    {
@@ -893,39 +939,34 @@
 }
 
 
-static void
-DC390_Disconnect( PACB pACB )
+void
+dc390_Disconnect( PACB pACB )
 {
     PDCB   pDCB;
     PSRB   pSRB, psrb;
-    ULONG  flags;
-    USHORT ioport, i, cnt;
-    UCHAR  bval;
+    UCHAR  i, cnt;
 
-#ifdef DC390_DEBUG0
-    printk("DISC,");
-#endif
+    DEBUG0(printk(KERN_INFO "DISC,");)
 
-    save_flags(flags);
-    cli();
-    ioport = pACB->IOPortBase;
     pDCB = pACB->pActiveDCB;
     if (!pDCB)
      {
-#ifdef DC390_DEBUG0
-	printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB);
-#endif
-	restore_flags(flags); return;
+	int j = 400;
+	DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\
+	       (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);)
+	while (--j) udelay (1000);
+	DC390_read8 (INT_Status);	/* Reset Pending INT */
+	DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+	return;
      }
     pSRB = pDCB->pActiveSRB;
     pACB->pActiveDCB = 0;
     pSRB->ScsiPhase = SCSI_NOP0;
-    bval = EN_SEL_RESEL;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, EN_SEL_RESEL);
     if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
     {
 	pSRB->SRBState = 0;
-	DoWaitingSRB( pACB );
+	dc390_DoWaitingSRB( pACB );
     }
     else if( pSRB->SRBState & SRB_ABORT_SENT )
     {
@@ -942,7 +983,7 @@
 	    pSRB = psrb;
 	}
 	pDCB->pGoingSRB = 0;
-	DoWaitingSRB( pACB );
+	dc390_DoWaitingSRB( pACB );
     }
     else
     {
@@ -952,7 +993,7 @@
 	    if( !(pACB->scan_devices) )
 	    {
 		pSRB->SRBState = SRB_READY;
-		RewaitSRB( pDCB, pSRB);
+		dc390_RewaitSRB( pDCB, pSRB);
 	    }
 	    else
 	    {
@@ -962,76 +1003,66 @@
 	}
 	else if( pSRB->SRBState & SRB_DISCONNECT )
 	{
-	    DoWaitingSRB( pACB );
+	    dc390_DoWaitingSRB( pACB );
 	}
 	else if( pSRB->SRBState & SRB_COMPLETED )
 	{
 disc1:
 	    if(pDCB->MaxCommand > 1)
 	    {
-	       bval = pSRB->TagNumber;
-	       pDCB->TagMask &= (~(1 << bval));   /* free tag mask */
+	       pDCB->TagMask &= (~(1 << pSRB->TagNumber));   /* free tag mask */
 	    }
 	    pDCB->pActiveSRB = 0;
 	    pSRB->SRBState = SRB_FREE;
-	    SRBdone( pACB, pDCB, pSRB);
+	    dc390_SRBdone( pACB, pDCB, pSRB);
 	}
     }
-    restore_flags(flags);
     return;
 }
 
 
-static void
-DC390_Reselect( PACB pACB )
+void
+dc390_Reselect( PACB pACB )
 {
-    PDCB   pDCB, pdcb;
+    PDCB   pDCB;
     PSRB   pSRB;
-    USHORT ioport, wval;
-    UCHAR  bval, bval1;
-
+    USHORT wval;
+    UCHAR  bval;
 
-#ifdef DC390_DEBUG0
-    printk("RSEL,");
-#endif
-    ioport = pACB->IOPortBase;
+    DEBUG0(printk(KERN_INFO "RSEL,");)
     pDCB = pACB->pActiveDCB;
     if( pDCB )
     {	/* Arbitration lost but Reselection win */
+	DEBUG0(printk ("(ActiveDCB != 0)");)
 	pSRB = pDCB->pActiveSRB;
 	if( !( pACB->scan_devices ) )
 	{
 	    pSRB->SRBState = SRB_READY;
-	    RewaitSRB( pDCB, pSRB);
+	    dc390_RewaitSRB( pDCB, pSRB);
 	}
     }
-    bval = inb(ioport+ScsiFifo);	/* get ID */
-    bval = bval ^ pACB->HostID_Bit;
+    bval = DC390_read8 (ScsiFifo);	/* get ID */
+    DEBUG0(printk ("Dev %02x,", bval);)
+    bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */
     wval = 0;
-    bval1 = 1;
-    for(;;)
-    {
-	if( !(bval & bval1) )
-	{
-	    bval1 = bval1 << 1;
-	    wval++;
-	}
-	else
-	    break;
-    }
-    wval |=  ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8;  /* get LUN */
+    while (bval >>= 1) wval++;
+    wval |=  ( (USHORT) DC390_read8 (ScsiFifo) & 7) << 8;  /* get LUN */
+    DEBUG0(printk ("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);)
     pDCB = pACB->pLinkDCB;
-    pdcb = pDCB;
     while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
     {
 	pDCB = pDCB->pNextDCB;
-	if( pDCB == pdcb )
+	if( pDCB == pACB->pLinkDCB )
+	 {
+	    printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n",
+		    wval & 0xff, (wval & 0xff00) >> 8);
 	    return;
+	 }
     }
     pACB->pActiveDCB = pDCB;
-    if( pDCB->SyncMode & EN_TAG_QUEUING )
+    if( pDCB->SyncMode & EN_TAG_QUEUEING )
     {
-	pSRB = pACB->pTmpSRB;
+	pSRB = pACB->pTmpSRB; /* ?? */
 	pDCB->pActiveSRB = pSRB;
     }
     else
@@ -1041,57 +1072,163 @@
 	{
 	    pSRB= pACB->pTmpSRB;
 	    pSRB->SRBState = SRB_UNEXPECT_RESEL;
+	    printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n",
+		    wval & 0xff, (wval & 0xff00) >> 8);
 	    pDCB->pActiveSRB = pSRB;
-	    EnableMsgOut( pACB, pSRB );
+	    dc390_EnableMsgOut( pACB, pSRB );
 	}
 	else
 	{
 	    if( pDCB->DCBFlag & ABORT_DEV_ )
 	    {
 		pSRB->SRBState = SRB_ABORT_SENT;
-		EnableMsgOut( pACB, pSRB );
+		printk (KERN_NOTICE "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
+			wval & 0xff, (wval & 0xff00) >> 8);
+		dc390_EnableMsgOut( pACB, pSRB );
 	    }
 	    else
 		pSRB->SRBState = SRB_DATA_XFER;
 	}
     }
+
+    DEBUG1(printk ("Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);)
     pSRB->ScsiPhase = SCSI_NOP0;
-    bval = pDCB->UnitSCSIID;
-    outb( bval, ioport+Scsi_Dest_ID);
-    bval = pDCB->SyncPeriod;
-    outb(bval, ioport+Sync_Period);
-    bval = pDCB->SyncOffset;
-    outb( bval, ioport+Sync_Offset);
-    bval = pDCB->CtrlR1;
-    outb(bval, ioport+CtrlReg1);
-    bval = pDCB->CtrlR3;
-    outb(bval, ioport+CtrlReg3);
-    bval = pDCB->CtrlR4;	/* ; Glitch eater */
-    outb(bval, ioport+CtrlReg4);
-    bval = MSG_ACCEPTED_CMD;	/* ;to rls the /ACK signal */
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
+    DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+    DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+    DC390_write8 (CtrlReg1, pDCB->CtrlR1);
+    DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+    DC390_write8 (CtrlReg4, pDCB->CtrlR4);	/* ; Glitch eater */
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);	/* ;to release the /ACK signal */
 }
 
 
-static void
-SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
+static void 
+dc390_remove_dev (PACB pACB, PDCB pDCB)
+{
+   PDCB pPrevDCB = pACB->pLinkDCB;
+
+   pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN);
+   if (pDCB->GoingSRBCnt > 1)
+     {
+	DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\
+		pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB, pDCB->GoingSRBCnt);)
+	return;
+     };
+   
+   if (pDCB == pACB->pLinkDCB) 
+     {
+	if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 0;
+	pACB->pLinkDCB = pDCB->pNextDCB;
+	pACB->pLastDCB->pNextDCB = pDCB->pNextDCB;
+     }
+   else
+     {
+	while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB;
+	pPrevDCB->pNextDCB = pDCB->pNextDCB;
+	if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB;
+     }
+
+   DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n",\
+	   pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
+   kfree (pDCB); if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0;
+   pACB->DCBCnt--;
+   /* pACB->DeviceCnt--; */
+};
+
+
+static UCHAR __inline__
+dc390_tagq_blacklist (char* name)
+{
+   UCHAR i;
+   for(i=0; i<BADDEVCNT; i++)
+     if (memcmp (name, dc390_baddevname1[i], 28) == 0)
+	return 1;
+   return 0;
+};
+   
+
+static void 
+dc390_disc_tagq_set (PDCB pDCB, PSCSI_INQDATA ptr)
+{
+   /* Check for SCSI format (ANSI and Response data format) */
+   if ( (ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 )
+   {
+	if ( (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
+	    (pDCB->DevMode & TAG_QUEUEING_) &&
+	    /* ((pDCB->DevType == TYPE_DISK) 
+		|| (pDCB->DevType == TYPE_MOD)) &&*/
+	    !dc390_tagq_blacklist (((char*)ptr)+8) )
+	  {
+	     pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum;
+	     pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */;
+	     pDCB->TagMask = 0;
+	  }
+	else
+	  {
+	     /* Do we really need to check for DevType here ? */
+	     if ( 0 /*(pDCB->DevMode & EN_DISCONNECT_)*/
+		 /* && ((pDCB->DevType == TYPE_DISK) 
+		     || (pDCB->DevType == TYPE_MOD))*/ )
+		pDCB->SyncMode |= EN_ATN_STOP;
+	     else
+	       //pDCB->SyncMode &= ~EN_ATN_STOP;
+	       pDCB->SyncMode &= ~0;
+	  }
+     }
+};
+
+
+static void 
+dc390_add_dev (PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr)
+{
+   UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE;
+   pDCB->DevType = bval1;
+   /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
+	dc390_disc_tagq_set (pDCB, ptr);
+};
+
+
+void
+dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
     PSRB   psrb;
-    UCHAR  bval, bval1, i, j, status;
+    UCHAR  bval, status, i;
     PSCSICMD pcmd;
     PSCSI_INQDATA  ptr;
-    USHORT disable_tag;
-    ULONG  flags;
     PSGL   ptr2;
     ULONG  swlval;
 
     pcmd = pSRB->pcmd;
     status = pSRB->TargetStatus;
+    DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
+		pSRB, pcmd->pid);)
     if(pSRB->SRBFlag & AUTO_REQSENSE)
-    {
+    {	/* Last command was a Request Sense */
 	pSRB->SRBFlag &= ~AUTO_REQSENSE;
 	pSRB->AdaptStatus = 0;
 	pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
+#ifdef DC390_REMOVABLEDEBUG
+	switch (pcmd->sense_buffer[2] & 0x0f)
+	{	    
+	 case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+				 pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				 status, pACB->scan_devices); break;
+	 case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+				      pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				      status, pACB->scan_devices); break;
+	 case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+				       pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				       status, pACB->scan_devices); break;
+	 case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+				    pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				    status, pACB->scan_devices); break;
+	 case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+				      pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				      status, pACB->scan_devices); break;
+	}
+#endif
+	//pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status;
 	if(status == SCSI_STAT_CHECKCOND)
 	{
 	    pcmd->result = DID_BAD_TARGET << 16;
@@ -1099,7 +1236,7 @@
 	}
 	if(pSRB->RetryCnt == 0)
 	{
-	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+	    (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0];
 	    pSRB->TotalXferredLen = pSRB->Segment1[1];
 	    if( (pSRB->TotalXferredLen) &&
 		(pSRB->TotalXferredLen >= pcmd->underflow) )
@@ -1107,28 +1244,29 @@
 	    else
 		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
 				SCSI_STAT_CHECKCOND;
-#ifdef DC390_DEBUG0
-	printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0],
-		(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
-#endif
+	    REMOVABLEDEBUG(printk("Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\
+		(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
 	    goto ckc_e;
 	}
-	else
+	else /* Retry */
 	{
 	    pSRB->RetryCnt--;
 	    pSRB->AdaptStatus = 0;
 	    pSRB->TargetStatus = 0;
 	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
 	    *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
-	    if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+	    /* Don't retry on TEST_UNIT_READY */
+	    if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */)
 	    {
-		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
-				SCSI_STAT_CHECKCOND;
+		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) 
+			    | SCSI_STAT_CHECKCOND;
+		REMOVABLEDEBUG(printk("Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\
+		       (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
 		goto ckc_e;
 	    }
 	    pcmd->result |= (DRIVER_SENSE << 24);
-	    pSRB->SGcount		 = (UCHAR) pSRB->Segment1[0];
-	    pSRB->ScsiCmdLen		 = (UCHAR) (pSRB->Segment1[0] >> 8);
+	    pSRB->SGcount	 = (UCHAR) pSRB->Segment1[0];
+	    pSRB->ScsiCmdLen	 = (UCHAR) (pSRB->Segment1[0] >> 8);
 	    pSRB->SGIndex = 0;
 	    pSRB->TotalXferredLen = 0;
 	    pSRB->SGToBeXferLen = 0;
@@ -1140,8 +1278,8 @@
 		pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
 		pSRB->Segmentx.length = pcmd->request_bufflen;
 	    }
-	    if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
-		RewaitSRB( pDCB, pSRB );
+	    if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+		dc390_RewaitSRB( pDCB, pSRB );
 	    return;
 	}
     }
@@ -1149,6 +1287,8 @@
     {
 	if( status == SCSI_STAT_CHECKCOND)
 	{
+	    REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\
+		    pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
 	    if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
 	    {
 		bval = pSRB->SGcount;
@@ -1159,12 +1299,10 @@
 		    swlval += ptr2->length;
 		    ptr2++;
 		}
-#ifdef	DC390_DEBUG0
-		printk("XferredLen=%8x,NotXferLen=%8x,",
-			(UINT) pSRB->TotalXferredLen, (UINT) swlval);
-#endif
+		REMOVABLEDEBUG(printk("XferredLen=%08x,NotXferLen=%08x\n",\
+			(UINT) pSRB->TotalXferredLen, (UINT) swlval);)
 	    }
-	    RequestSense( pACB, pDCB, pSRB );
+	    dc390_RequestSense( pACB, pDCB, pSRB );
 	    return;
 	}
 	else if( status == SCSI_STAT_QUEUEFULL )
@@ -1172,7 +1310,7 @@
 	    bval = (UCHAR) pDCB->GoingSRBCnt;
 	    bval--;
 	    pDCB->MaxCommand = bval;
-	    RewaitSRB( pDCB, pSRB );
+	    dc390_RewaitSRB( pDCB, pSRB );
 	    pSRB->AdaptStatus = 0;
 	    pSRB->TargetStatus = 0;
 	    return;
@@ -1182,12 +1320,22 @@
 	    pSRB->AdaptStatus = H_SEL_TIMEOUT;
 	    pSRB->TargetStatus = 0;
 	    pcmd->result = DID_BAD_TARGET << 16;
+	    /* Devices are removed below ... */
 	}
-	else
+	else if (status == SCSI_STAT_BUSY && 
+		 (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) &&
+		 pACB->scan_devices)
 	{
 	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = status;
+	    pcmd->result = (ULONG) (pSRB->EndMessage << 8)
+				/* | (ULONG) status */;
+	}
+	else
+	{   /* Another error */
+	    pSRB->AdaptStatus = 0;
 	    if( pSRB->RetryCnt )
-	    {
+	    {	/* Retry */
 		pSRB->RetryCnt--;
 		pSRB->TargetStatus = 0;
 		pSRB->SGIndex = 0;
@@ -1201,19 +1349,19 @@
 		    pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
 		    pSRB->Segmentx.length = pcmd->request_bufflen;
 		}
-		if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
-		    RewaitSRB( pDCB, pSRB );
+		if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+		    dc390_RewaitSRB( pDCB, pSRB );
 		return;
 	    }
 	    else
-	    {
+	    {	/* Report error */
 		pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
 			       (ULONG) status;
 	    }
 	}
     }
     else
-    {
+    {	/*  Target status == 0 */
 	status = pSRB->AdaptStatus;
 	if(status & H_OVER_UNDER_RUN)
 	{
@@ -1237,95 +1385,57 @@
     {
 	if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
 	{
-	    if(pcmd->result != (DID_OK << 16))
-	    {
-		if( pcmd->result & SCSI_STAT_CHECKCOND )
-		{
-		    goto RTN_OK;
-		}
-		else
-		{
-		    pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
-		    pPrevDCB->pNextDCB = pACB->pLinkDCB;
-		    if( (pcmd->target == pACB->max_id) &&
-		       ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) )
-		    {
-			pACB->scan_devices = 0;
-		    }
-		}
-	    }
-	    else
-	    {
-RTN_OK:
-		pPrevDCB->pNextDCB = pDCB;
-		pDCB->pNextDCB = pACB->pLinkDCB;
-		if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) )
-		    pACB->scan_devices = END_SCAN;
-	    }
-	}
-	else if( pSRB->CmdBlock[0] == INQUIRY )
-	{
-	    if( (pcmd->target == pACB->max_id) &&
-		(pcmd->lun == pACB->max_lun) )
-	    {
-		pACB->scan_devices = 0;
-	    }
-	    ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
-	    if( pcmd->use_sg )
-		ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
-	    bval1 = ptr->DevType & SCSI_DEVTYPE;
-	    if(bval1 == SCSI_NODEV)
-	    {
-		pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
-		pPrevDCB->pNextDCB = pACB->pLinkDCB;
+#ifdef DC390_DEBUG0
+	    printk (KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result);
+	    if (pcmd->result & DRIVER_SENSE << 24) printk (" (sense: %02x %02x %02x %02x)\n",
+				   pcmd->sense_buffer[0], pcmd->sense_buffer[1],
+				   pcmd->sense_buffer[2], pcmd->sense_buffer[3]);
+	    else printk ("\n");
+#endif
+	    if((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) ||
+	       ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 &&
+		(pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16)
+	    {
+	       /* device not present: remove */ 
+	       dc390_remove_dev (pACB, pDCB);
+	       
+	       if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
+		  ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) )
+		 pACB->scan_devices = 0;
 	    }
 	    else
 	    {
-		pACB->DeviceCnt++;
-		pPrevDCB = pDCB;
-		pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB ));
-		pDCB->DevType = bval1;
-		if(bval1 == TYPE_DISK || bval1 == TYPE_MOD)
-		{
-		    if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) &&
-			(ptr->Flags & SCSI_INQ_CMDQUEUE) &&
-			(pDCB->DevMode & TAG_QUEUING_) &&
-			(pDCB->DevMode & EN_DISCONNECT_) )
-		    {
-			disable_tag = 0;
-			for(i=0; i<BADDEVCNT; i++)
-			{
-			    for(j=0; j<28; j++)
-			    {
-				if( ((PUCHAR)ptr)[8+j] != baddevname1[i][j])
-				    break;
-			    }
-			    if(j == 28)
-			    {
-				disable_tag = 1;
-				break;
-			    }
-			}
-
-			if( !disable_tag )
-			{
-			    pDCB->MaxCommand = pACB->TagMaxNum;
-			    pDCB->SyncMode |= EN_TAG_QUEUING;
-			    pDCB->TagMask = 0;
-			}
-			else
-			{
-			    pDCB->SyncMode |= EN_ATN_STOP;
-			}
-		    }
-		}
+	        /* device present: add */
+		if( (pcmd->target == pACB->pScsiHost->max_id - 1) && 
+		    (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
+		    pACB->scan_devices = END_SCAN ;
+	        /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */
 	    }
 	}
     }
-
-    save_flags( flags );
-    cli();
-/*  ReleaseSRB( pDCB, pSRB ); */
+   
+   if( pSRB->CmdBlock[0] == INQUIRY && 
+      (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) )
+     {
+	ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
+	if( pcmd->use_sg )
+	  ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
+	if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV)
+	  {
+	     /* device not present: remove */
+	     dc390_remove_dev (pACB, pDCB);
+	  }
+	else
+	  {
+	     /* device found: add */ 
+	     dc390_add_dev (pACB, pDCB, ptr);
+	     if (pACB->scan_devices) pACB->DeviceCnt++;
+	  }
+	if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
+	    (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
+	  pACB->scan_devices = 0;
+     };
+/*  dc390_ReleaseSRB( pDCB, pSRB ); */
 
     if(pSRB == pDCB->pGoingSRB )
     {
@@ -1344,33 +1454,34 @@
     pACB->pFreeSRB = pSRB;
     pDCB->GoingSRBCnt--;
 
-    DoWaitingSRB( pACB );
-    restore_flags(flags);
+    dc390_DoWaitingSRB( pACB );
 
-/*  Notify cmd done */
+    DC390_UNLOCK_ACB_NI;
     pcmd->scsi_done( pcmd );
+    DC390_LOCK_ACB_NI;
 
     if( pDCB->QIORBCnt )
-	DoNextCmd( pACB, pDCB );
+	dc390_DoNextCmd( pACB, pDCB );
     return;
 }
 
 
-static void
-DoingSRB_Done( PACB pACB )
+/* Remove all SRBs and tell midlevel code DID_RESET */
+void
+dc390_DoingSRB_Done( PACB pACB )
 {
-    PDCB  pDCB, pdcb;
-    PSRB  psrb, psrb2;
-    USHORT  cnt, i;
+    PDCB   pDCB, pdcb;
+    PSRB   psrb, psrb2;
+    UCHAR  i;
     PSCSICMD pcmd;
 
     pDCB = pACB->pLinkDCB;
     pdcb = pDCB;
+    if (! pdcb) return;
     do
     {
-	cnt = pdcb->GoingSRBCnt;
 	psrb = pdcb->pGoingSRB;
-	for( i=0; i<cnt; i++)
+	for( i=0; i<pdcb->GoingSRBCnt; i++)
 	{
 	    psrb2 = psrb->pNextSRB;
 	    pcmd = psrb->pcmd;
@@ -1381,63 +1492,46 @@
 	    psrb->pNextSRB = pACB->pFreeSRB;
 	    pACB->pFreeSRB = psrb;
 
+	    DC390_UNLOCK_ACB_NI;
 	    pcmd->scsi_done( pcmd );
+	    DC390_LOCK_ACB_NI;
 	    psrb  = psrb2;
 	}
 	pdcb->GoingSRBCnt = 0;;
 	pdcb->pGoingSRB = NULL;
 	pdcb->TagMask = 0;
 	pdcb = pdcb->pNextDCB;
-    }
-    while( pdcb != pDCB );
+    } while( pdcb != pDCB );
 }
 
 
 static void
-DC390_ResetSCSIBus( PACB pACB )
+dc390_ResetSCSIBus( PACB pACB )
 {
-    USHORT ioport;
-    UCHAR  bval;
-    ULONG  flags;
-
-    save_flags(flags);
-    cli();
     pACB->ACBFlag |= RESET_DEV;
-    ioport = pACB->IOPortBase;
-
-    bval = DMA_IDLE_CMD;
-    outb(bval,ioport+DMA_Cmd);
 
-    bval = RST_SCSI_BUS_CMD;
-    outb(bval,ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+    udelay (250);
+    DC390_write8 (ScsiCmd, NOP_CMD);
+
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD);
 
-    restore_flags(flags);
     return;
 }
 
-
 static void
-DC390_ScsiRstDetect( PACB pACB )
+dc390_ScsiRstDetect( PACB pACB )
 {
-    ULONG wlval, flags;
-    USHORT ioport;
-    UCHAR  bval;
-
-#ifdef DC390_DEBUG0
-    printk("RST_DETEC");
-#endif
+    printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus);
+    //DEBUG0(printk(KERN_INFO "RST_DETECT,");)
 
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    /* Unlock before ? */
     /* delay a second */
-    mdelay(1000);
-
-    save_flags(flags);
-    cli();
-
-    ioport = pACB->IOPortBase;
-    bval = DMA_IDLE_CMD;
-    outb(bval,ioport+DMA_Cmd);
-    bval = CLEAR_FIFO_CMD;
-    outb(bval,ioport+ScsiCmd);
+    { unsigned int msec = 1*1000; while (--msec) udelay(1000); }
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
 
     if( pACB->ACBFlag & RESET_DEV )
 	pACB->ACBFlag |= RESET_DONE;
@@ -1445,30 +1539,32 @@
     {
 	pACB->ACBFlag |= RESET_DETECT;
 
-	ResetDevParam( pACB );
-/*	DoingSRB_Done( pACB ); ???? */
-	RecoverSRB( pACB );
+	dc390_ResetDevParam( pACB );
+/*	dc390_DoingSRB_Done( pACB ); ???? */
+	dc390_RecoverSRB( pACB );
 	pACB->pActiveDCB = NULL;
 	pACB->ACBFlag = 0;
-	DoWaitingSRB( pACB );
+	dc390_DoWaitingSRB( pACB );
     }
-    restore_flags(flags);
     return;
 }
 
 
-static void
-RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
+static void __inline__
+dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
     PSCSICMD  pcmd;
 
+    REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\
+	    pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+
     pSRB->SRBFlag |= AUTO_REQSENSE;
-    pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0]));
-    pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4]));
+    pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0];
+    pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4];
     pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
     pSRB->Segment1[1] = pSRB->TotalXferredLen;
     pSRB->AdaptStatus = 0;
-    pSRB->TargetStatus = 0;
+    pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */
 
     pcmd = pSRB->pcmd;
 
@@ -1478,52 +1574,40 @@
     pSRB->SGcount = 1;
     pSRB->SGIndex = 0;
 
-    *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003;
+    pSRB->CmdBlock[0] = REQUEST_SENSE;
     pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
-    *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer);
+    (USHORT) pSRB->CmdBlock[2] = 0;
+    (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer);
     pSRB->ScsiCmdLen = 6;
 
     pSRB->TotalXferredLen = 0;
     pSRB->SGToBeXferLen = 0;
-    if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
-	RewaitSRB( pDCB, pSRB );
+    if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+	dc390_RewaitSRB( pDCB, pSRB );
 }
 
 
-static void
-EnableMsgOut2( PACB pACB, PSRB pSRB )
+static void __inline__
+dc390_EnableMsgOut2( PACB pACB, PSRB pSRB )
 {
-    USHORT ioport;
-    UCHAR  bval;
-
-    ioport = pACB->IOPortBase;
     pSRB->MsgCnt = 1;
-    bval = SET_ATN_CMD;
-    outb(bval, ioport+ScsiCmd);
+    DC390_write8 (ScsiCmd, SET_ATN_CMD);
 }
 
 
-static void
-EnableMsgOut( PACB pACB, PSRB pSRB )
+static void __inline__
+dc390_EnableMsgOut( PACB pACB, PSRB pSRB )
 {
     pSRB->MsgOutBuf[0] = MSG_ABORT;
-    EnableMsgOut2( pACB, pSRB );
+    dc390_EnableMsgOut2( pACB, pSRB );
+    pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
 }
 
 
-static void
-DC390_InvalidCmd( PACB pACB )
+static void __inline__
+dc390_InvalidCmd( PACB pACB )
 {
-   UCHAR bval;
-   USHORT ioport;
-   PSRB   pSRB;
-
-    pSRB = pACB->pActiveDCB->pActiveSRB;
-    if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
-    {
-	ioport = pACB->IOPortBase;
-	bval = CLEAR_FIFO_CMD;
-	outb(bval,(ioport+ScsiCmd));
-    }
+    if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
+	DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
 }
 
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.1.126/linux/drivers/scsi/sd.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/scsi/sd.c	Mon Oct 26 14:04:21 1998
@@ -65,7 +65,8 @@
 #define SD_MINOR_NUMBER(i)	((i) & 255)
 #define MKDEV_SD_PARTITION(i)	MKDEV(SD_MAJOR_NUMBER(i), (i) & 255)
 #define MKDEV_SD(index)		MKDEV_SD_PARTITION((index) << 4)
-#define N_USED_SD_MAJORS	((sd_template.dev_max + SCSI_DISKS_PER_MAJOR - 1) / SCSI_DISKS_PER_MAJOR)
+#define N_USED_SCSI_DISKS  (sd_template.dev_max + SCSI_DISKS_PER_MAJOR - 1)
+#define N_USED_SD_MAJORS   (N_USED_SCSI_DISKS / SCSI_DISKS_PER_MAJOR)
 
 #define MAX_RETRIES 5
 
@@ -1765,7 +1766,7 @@
     scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
 
     for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++) 
-    unregister_blkdev(SD_MAJOR(i),"sd");
+	unregister_blkdev(SD_MAJOR(i),"sd");
     
     sd_registered--;
     if( rscsi_disks != NULL )
@@ -1783,13 +1784,13 @@
 
 	for (sdgd = gendisk_head; sdgd; sdgd = sdgd->next)
 	{
-	    if (sdgd->next >= sd_gendisks && sdgd->next <= LAST_SD_GENDISK)
+	    if (sdgd->next >= sd_gendisks && sdgd->next <= LAST_SD_GENDISK.max_nr)
 	    	    removed++, sdgd->next = sdgd->next->next;
 	    else sdgd = sdgd->next;
 	}
-	if (removed != N_USED_SCSI_DISKS)
+	if (removed != N_USED_SD_MAJORS)
 	    printk("%s %d sd_gendisks in disk chain",
-	    	removed > N_USED_SCSI_DISKS ? "total" : "just", removed);
+		removed > N_USED_SD_MAJORS ? "total" : "just", removed);
 	
     }
 
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.1.126/linux/drivers/scsi/tmscsim.c	Sun Jun  7 11:16:35 1998
+++ linux/drivers/scsi/tmscsim.c	Tue Oct 27 10:10:08 1998
@@ -5,35 +5,132 @@
  *		     Bus Master Host Adapter			       *
  * (C)Copyright 1995-1996 Tekram Technology Co., Ltd.		       *
  ***********************************************************************/
-/*	Minor enhancements and bugfixes by				*
+/* $Id: tmscsim.c,v 2.4 1998/10/24 08:50:47 garloff Exp $		*/
+/*	Enhancements and bugfixes by					*
  *	Kurt Garloff <K.Garloff@ping.de>				*
  ***********************************************************************/
 /*	HISTORY:							*
  *									*
  *	REV#	DATE	NAME	DESCRIPTION				*
- *	1.00  04/24/96	CLH	First release				*
- *	1.01  06/12/96	CLH	Fixed bug of Media Change for Removable *
+ *	1.00  96/04/24	CLH	First release				*
+ *	1.01  96/06/12	CLH	Fixed bug of Media Change for Removable *
  *				Device, scan all LUN. Support Pre2.0.10 *
- *	1.02  06/18/96	CLH	Fixed bug of Command timeout ...	*
- *	1.03  09/25/96	KG	Added tmscsim_proc_info()		*
- *	1.04  10/11/96	CLH	Updating for support KV 2.0.x		*
- *	1.05  10/18/96	KG	Fixed bug in DC390_abort(null ptr deref)*
- *	1.06  10/25/96	KG	Fixed module support			*
- *	1.07  11/09/96	KG	Fixed tmscsim_proc_info()		*
- *	1.08  11/18/96	KG	Fixed null ptr in DC390_Disconnect()	*
- *	1.09  11/30/96	KG	Added register the allocated IO space	*
- *	1.10  12/05/96	CLH	Modified tmscsim_proc_info(), and reset *
+ *	1.02  96/06/18	CLH	Fixed bug of Command timeout ...	*
+ *	1.03  96/09/25	KG	Added tmscsim_proc_info()		*
+ *	1.04  96/10/11	CLH	Updating for support KV 2.0.x		*
+ *	1.05  96/10/18	KG	Fixed bug in DC390_abort(null ptr deref)*
+ *	1.06  96/10/25	KG	Fixed module support			*
+ *	1.07  96/11/09	KG	Fixed tmscsim_proc_info()		*
+ *	1.08  96/11/18	KG	Fixed null ptr in DC390_Disconnect()	*
+ *	1.09  96/11/30	KG	Added register the allocated IO space	*
+ *	1.10  96/12/05	CLH	Modified tmscsim_proc_info(), and reset *
  *				pending interrupt in DC390_detect()	*
- * 	1.11  02/05/97	KG/CLH	Fixeds problem with partitions greater	*
- * 				than 1GB				*
- *      1.12  15/02/98  MJ      Rewritten PCI probing			*
+ *	1.11  97/02/05	KG/CLH	Fixeds problem with partitions greater	*
+ *				than 1GB				*
+ *	1.12  98/02/15  MJ      Rewritten PCI probing			*
+ *	1.13  98/04/08	KG	Support for non DC390, __initfunc decls,*
+ *				changed max devs from 10 to 16		*
+ *	1.14a 98/05/05	KG	Dynamic DCB allocation, add-single-dev	*
+ *				for LUNs if LUN_SCAN (BIOS) not set	*
+ *				runtime config using /proc interface	*
+ *	1.14b 98/05/06	KG	eliminated cli (); sti (); spinlocks	*
+ *	1.14c 98/05/07	KG	2.0.x compatibility			*
+ *	1.20a 98/05/07	KG	changed names of funcs to be consistent *
+ *				DC390_ (entry points), dc390_ (internal)*
+ *				reworked locking			*
+ *	1.20b 98/05/12	KG	bugs: version, kfree, _ctmp		*
+ *				debug output				*
+ *	1.20c 98/05/12	KG	bugs: kfree, parsing, EEpromDefaults	*
+ *	1.20d 98/05/14	KG	bugs: list linkage, clear flag after  	*
+ *				reset on startup, code cleanup		*
+ *	1.20e 98/05/15	KG	spinlock comments, name space cleanup	*
+ *				pLastDCB now part of ACB structure	*
+ *				added stats, timeout for 2.1, TagQ bug	*
+ *				RESET and INQUIRY interface commands	*
+ *	1.20f 98/05/18	KG	spinlocks fixes, max_lun fix, free DCBs	*
+ *				for missing LUNs, pending int		*
+ *	1.20g 98/05/19	KG	Clean up: Avoid short			*
+ *	1.20h 98/05/21	KG	Remove AdaptSCSIID, max_lun ...		*
+ *	1.20i 98/05/21	KG	Aiiie: Bug with TagQMask       		*
+ *	1.20j 98/05/24	KG	Handle STAT_BUSY, handle pACB->pLinkDCB	*
+ *				== 0 in remove_dev and DoingSRB_Done	*
+ *	1.20k 98/05/25	KG	DMA_INT	(experimental)	       		*
+ *	1.20l 98/05/27	KG	remove DMA_INT; DMA_IDLE cmds added;	*
+ *	1.20m 98/06/10	KG	glitch configurable; made some global	*
+ *				vars part of ACB; use DC390_readX	*
+ *	1.20n 98/06/11	KG	startup params				*
+ *	1.20o 98/06/15	KG	added TagMaxNum to boot/module params	*
+ *				Device Nr -> Idx, TagMaxNum power of 2  *
+ *	1.20p 98/06/17	KG	Docu updates. Reset depends on settings *
+ *				pci_set_master added; 2.0.xx: pcibios_*	*
+ *				used instead of MechNum things ...	*
+ *	1.20q 98/06/23	KG	Changed defaults. Added debug code for	*
+ *				removable media and fixed it. TagMaxNum	*
+ *				fixed for DC390. Locking: ACB, DRV for	*
+ *				better IRQ sharing. Spelling: Queueing	*
+ *				Parsing and glitch_cfg changes. Display	*
+ *				real SyncSpeed value. Made DisConn	*
+ *				functional (!)				*
+ *	1.20r 98/06/30	KG	Debug macros, allow disabling DsCn, set	*
+ *				BIT4 in CtrlR4, EN_PAGE_INT, 2.0 module	*
+ *				param -1 fixed.				*
+ *	1.20s 98/08/20	KG	Debug info on abort(), try to check PCI,*
+ *				phys_to_bus instead of phys_to_virt,	*
+ *				fixed sel. process, fixed locking,	*
+ *				added MODULE_XXX infos, changed IRQ	*
+ *				request flags, disable DMA_INT		*
+ *	1.20t 98/09/07	KG	TagQ report fixed; Write Erase DMA Stat;*
+ *				initfunc -> __init; better abort;	*
+ *				Timeout for XFER_DONE & BLAST_COMPLETE;	*
+ *				Allow up to 33 commands being processed *
+ *	2.0a  98/10/14	KG	Max Cmnds back to 17. DMA_Stat clearing *
+ *				all flags. Clear within while() loops	*
+ *				in DataIn_0/Out_0. Null ptr in dumpinfo	*
+ *				for pSRB==0. Better locking during init.*
+ *				bios_param() now respects part. table.	*
+ *	2.0b  98/10/24	KG	Docu fixes. Timeout Msg in DMA Blast.	*
+ *				Disallow illegal idx in INQUIRY/REMOVE	*
  ***********************************************************************/
 
+/* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */
+#define DC390_IRQ SA_SHIRQ /* | SA_INTERRUPT */
 
-#define DC390_DEBUG
+/* DEBUG options */
+//#define DC390_DEBUG0
+//#define DC390_DEBUG1
+//#define DC390_DCBDEBUG
+//#define DC390_PARSEDEBUG
+//#define DC390_REMOVABLEDEBUG
 
-#define SCSI_MALLOC
+/* Debug definitions */
+#ifdef DC390_DEBUG0
+# define DEBUG0(x) x;
+#else
+# define DEBUG0(x)
+#endif
+#ifdef DC390_DEBUG1
+# define DEBUG1(x) x;
+#else
+# define DEBUG1(x)
+#endif
+#ifdef DC390_DCBDEBUG
+# define DCBDEBUG(x) x;
+#else
+# define DCBDEBUG(x)
+#endif
+#ifdef DC390_PARSEDEBUG
+# define PARSEDEBUG(x) x;
+#else
+# define PARSEDEBUG(x)
+#endif
+#ifdef DC390_REMOVABLEDEBUG
+# define REMOVABLEDEBUG(x) x;
+#else
+# define REMOVABLEDEBUG(x)
+#endif
+#define DCBDEBUG1(x)
 
+/* Includes */
 #ifdef MODULE
 # include <linux/module.h>
 #endif
@@ -41,7 +138,6 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <linux/delay.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -51,14 +147,14 @@
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/mm.h>
 #include <linux/config.h>
-#include <linux/init.h>
+#include <linux/version.h>
 #include <linux/blk.h>
 
 #include "scsi.h"
 #include "hosts.h"
-#include "tmscsim.h"
 #include "constants.h"
 #include "sd.h"
 #include <linux/stat.h>
@@ -67,107 +163,350 @@
 
 #define PCI_DEVICE_ID_AMD53C974 	PCI_DEVICE_ID_AMD_SCSI
 
-struct proc_dir_entry	proc_scsi_tmscsim ={
-       PROC_SCSI_DC390T, 7 ,"tmscsim",
-       S_IFDIR | S_IRUGO | S_IXUGO, 2
-       };
+/* Locking */
 
-static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-
-static void SetXferRate( PACB pACB, PDCB pDCB );
-static void DC390_Disconnect( PACB pACB );
-static void DC390_Reselect( PACB pACB );
-static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void DoingSRB_Done( PACB pACB );
-static void DC390_ScsiRstDetect( PACB pACB );
-static void DC390_ResetSCSIBus( PACB pACB );
-static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void EnableMsgOut2( PACB pACB, PSRB pSRB );
-static void EnableMsgOut( PACB pACB, PSRB pSRB );
-static void DC390_InvalidCmd( PACB pACB );
+/* Note: Starting from 2.1.9x, the mid-level scsi code issues a 
+ * spinlock_irqsave (&io_request_lock) before calling the driver's 
+ * routines, so we don't need to lock.
+ * TODO: Verify, if we are locked in every case!
+ * The policy 3, let the midlevel scsi code do the io_request_locks
+ * and us locking on a driver specific lock, shouldn't hurt anybody; it
+ * just causes a minor performance degradation for setting the locks.
+ */
+
+/* spinlock things
+ * level 3: lock on both adapter specific locks and (global) io_request_lock
+ * level 2: lock on adapter specific locks only
+ * level 1: rely on the locking of the mid level code (io_request_lock)
+ * undef  : traditional save_flags; cli; restore_flags;
+ */
+
+//#define DEBUG_SPINLOCKS 2	/* Set to 0, 1 or 2 in include/asm/spinlock.h */
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+# include <linux/init.h>
+# include <asm/spinlock.h>
+#endif
 
-int    DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );
-void   DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) 
+# define USE_SPINLOCKS 1
+# define NEW_PCI 1
+#else
+# undef NEW_PCI
+# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+#  define USE_SPINLOCKS 2
+# endif
+#endif
+
+#ifdef USE_SPINLOCKS
+
+# if USE_SPINLOCKS == 3 /* both */
+
+#  if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+#   define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+#  else
+#   define DC390_LOCK_INIT
+#  endif
+   spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+
+#  define DC390_AFLAGS unsigned long aflags;
+#  define DC390_IFLAGS unsigned long iflags;
+#  define DC390_DFLAGS unsigned long dflags; 
+
+#  define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
+#  define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+
+#  define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+#  define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+#  define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+#  define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+
+#  define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags)
+#  define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
+#  define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
+#  define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
+//#  define DC390_LOCK_INIT spin_lock_init (&(pACB->lock))
+
+# else
+
+#  if USE_SPINLOCKS == 2 /* adapter specific locks */
+
+#   if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+#    define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+#   else
+#    define DC390_LOCK_INIT
+#   endif
+    spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+#   define DC390_AFLAGS unsigned long aflags;
+#   define DC390_IFLAGS 
+#  define DC390_DFLAGS unsigned long dflags; 
+#   define DC390_LOCK_IO /* spin_lock_irqsave (&io_request_lock, iflags) */
+#   define DC390_UNLOCK_IO /* spin_unlock_irqrestore (&io_request_lock, iflags) */
+#   define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+#   define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+#   define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+#   define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+#   define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags)
+#   define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
+#   define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
+#   define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
+//#   define DC390_LOCK_INIT spin_lock_init (&(pACB->lock))
+
+#  else /* USE_SPINLOCKS == 1: global lock io_request_lock */
+
+#   define DC390_AFLAGS 
+#   define DC390_IFLAGS unsigned long iflags;
+#   define DC390_DFLAGS unsigned long dflags; 
+    spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+#   define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
+#   define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+#   define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+#   define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+#   define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+#   define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+#   define DC390_LOCK_ACB /* DC390_LOCK_IO */
+#   define DC390_UNLOCK_ACB /* DC390_UNLOCK_IO */
+#   define DC390_LOCK_ACB_NI /* spin_lock (&(pACB->lock)) */
+#   define DC390_UNLOCK_ACB_NI /* spin_unlock (&(pACB->lock)) */
+#   define DC390_LOCK_INIT /* DC390_LOCK_INIT */
+
+#  endif /* 2 */
+# endif /* 3 */
+
+#else /* USE_SPINLOCKS undefined */
+
+# define DC390_AFLAGS unsigned long aflags;
+# define DC390_IFLAGS unsigned long iflags;
+# define DC390_DFLAGS unsigned long dflags; 
+# define DC390_LOCK_IO save_flags (iflags); cli ()
+# define DC390_UNLOCK_IO restore_flags (iflags)
+# define DC390_LOCK_DRV save_flags (dflags); cli ()
+# define DC390_UNLOCK_DRV restore_flags (dflags)
+# define DC390_LOCK_DRV_NI
+# define DC390_UNLOCK_DRV_NI
+# define DC390_LOCK_ACB save_flags (aflags); cli ()
+# define DC390_UNLOCK_ACB restore_flags (aflags)
+# define DC390_LOCK_ACB_NI
+# define DC390_UNLOCK_ACB_NI
+# define DC390_LOCK_INIT
+#endif /* def */
+
+
+/* These macros are used for uniform access to 2.0.x and 2.1.x PCI config space*/
+
+#ifdef NEW_PCI
+# define PDEV pdev
+# define PDEVDECL struct pci_dev *pdev
+# define PDEVDECL0 struct pci_dev *pdev = NULL
+# define PDEVDECL1 struct pci_dev *pdev
+# define PDEVSET pACB->pdev=pdev
+# define PDEVSET1 pdev=pACB->pdev
+# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pci_write_config_byte (pd, rv, bv)
+# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pci_read_config_byte (pd, rv, bv)
+# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pci_write_config_word (pd, rv, bv)
+# define PCI_READ_CONFIG_WORD(pd, rv, bv) pci_read_config_word (pd, rv, bv)
+# define PCI_BUS_DEV pdev->bus->number, pdev->devfn
+# define PCI_PRESENT pci_present ()
+# define PCI_SET_MASTER pci_set_master (pdev)
+# define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev))
+# define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq
+#else
+# include <linux/bios32.h>
+# define PDEV pbus, pdevfn
+# define PDEVDECL UCHAR pbus, UCHAR pdevfn
+# define PDEVDECL0 UCHAR pbus = 0; UCHAR pdevfn = 0; USHORT pci_index = 0; int error
+# define PDEVDECL1 UCHAR pbus; UCHAR pdevfn /*; USHORT pci_index */
+# define PDEVSET pACB->pbus=pbus; pACB->pdevfn=pdevfn /*; pACB->pci_index=pci_index */
+# define PDEVSET1 pbus=pACB->pbus; pdevfn=pACB->pdevfn /*; pci_index=pACB->pci_index */
+# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pcibios_write_config_byte (pd, rv, bv)
+# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pcibios_read_config_byte (pd, rv, bv)
+# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pcibios_write_config_word (pd, rv, bv)
+# define PCI_READ_CONFIG_WORD(pd, rv, bv) pcibios_read_config_word (pd, rv, bv)
+# define PCI_BUS_DEV pbus, pdevfn
+# define PCI_PRESENT pcibios_present ()
+# define PCI_SET_MASTER dc390_set_master (pbus, pdevfn)
+# define PCI_FIND_DEVICE(vend, id) (!pcibios_find_device (vend, id, pci_index++, &pbus, &pdevfn))
+# define PCI_GET_IO_AND_IRQ error = pcibios_read_config_dword (pbus, pdevfn, PCI_BASE_ADDRESS_0, &io_port);	\
+ error |= pcibios_read_config_byte (pbus, pdevfn, PCI_INTERRUPT_LINE, &irq);	\
+ io_port &= 0xfffe;	\
+ if (error) { printk (KERN_ERR "DC390_detect: Error reading PCI config registers!\n"); continue; }
+#endif 
+
+#include "tmscsim.h"
+
+#ifndef __init
+# define __init
+#endif
+
+UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
+void dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+
+static void dc390_SetXferRate( PACB pACB, PDCB pDCB );
+void dc390_Disconnect( PACB pACB );
+void dc390_Reselect( PACB pACB );
+void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
+void dc390_DoingSRB_Done( PACB pACB );
+static void dc390_ScsiRstDetect( PACB pACB );
+static void dc390_ResetSCSIBus( PACB pACB );
+static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void __inline__ dc390_EnableMsgOut2( PACB pACB, PSRB pSRB );
+static void __inline__ dc390_EnableMsgOut( PACB pACB, PSRB pSRB );
+static void __inline__ dc390_InvalidCmd( PACB pACB );
+static void dc390_remove_dev (PACB pACB, PDCB pDCB);
+void do_DC390_Interrupt( int, void *, struct pt_regs *);
+
+int    dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index );
+void   dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd );
+void   dc390_updateDCB (PACB pACB, PDCB pDCB);
 
 #ifdef MODULE
-static int DC390_release(struct Scsi_Host *host);
-static int DC390_shutdown (struct Scsi_Host *host);
+ static int DC390_release(struct Scsi_Host *host);
+ static int dc390_shutdown (struct Scsi_Host *host);
 #endif
 
 
-static PSHT	pSHT_start = NULL;
-static PSH	pSH_start = NULL;
-static PSH	pSH_current = NULL;
-static PACB	pACB_start= NULL;
-static PACB	pACB_current = NULL;
-static PDCB	pPrevDCB = NULL;
-static USHORT	adapterCnt = 0;
-static USHORT	InitialTime = 0;
-static USHORT	CurrSyncOffset = 0;
-
-static PVOID DC390_phase0[]={
-       DC390_DataOut_0,
-       DC390_DataIn_0,
-       DC390_Command_0,
-       DC390_Status_0,
-       DC390_Nop_0,
-       DC390_Nop_0,
-       DC390_MsgOut_0,
-       DC390_MsgIn_0,
-       DC390_Nop_1
-       };
+//static PSHT	dc390_pSHT_start = NULL;
+//static PSH	dc390_pSH_start = NULL;
+//static PSH	dc390_pSH_current = NULL;
+static PACB	dc390_pACB_start= NULL;
+static PACB	dc390_pACB_current = NULL;
+static UCHAR	dc390_adapterCnt = 0;
+static UCHAR	dc390_CurrSyncOffset = 0;
+static ULONG	dc390_lastabortedpid = 0;
+static ULONG	dc390_laststatus = 0;
+
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+/* Startup values, to be overriden on the commandline */
+int tmscsim[] = {7, 1 /* 8MHz */, 
+		PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_
+		| SYNC_NEGO_ | TAG_QUEUEING_,
+		MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION
+		/* | NO_SEEK */
+# ifdef CONFIG_SCSI_MULTI_LUN
+		| LUN_CHECK
+# endif
+		, 3 /* 16 Tags per LUN */};
+
+# if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_PARM(tmscsim, "1-5i");
+MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1)");
+# endif
+
+#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+
+#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_AUTHOR("C.L. Huang / Kurt Garloff");
+MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters");
+MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
+#endif
 
-static PVOID DC390_phase1[]={
-       DC390_DataOutPhase,
-       DC390_DataInPhase,
-       DC390_CommandPhase,
-       DC390_StatusPhase,
-       DC390_Nop_0,
-       DC390_Nop_0,
-       DC390_MsgOutPhase,
-       DC390_MsgInPhase,
-       DC390_Nop_1,
+static PVOID dc390_phase0[]={
+       dc390_DataOut_0,
+       dc390_DataIn_0,
+       dc390_Command_0,
+       dc390_Status_0,
+       dc390_Nop_0,
+       dc390_Nop_0,
+       dc390_MsgOut_0,
+       dc390_MsgIn_0,
+       dc390_Nop_1
        };
 
-UCHAR  eepromBuf[MAX_ADAPTER_NUM][128];
-
+static PVOID dc390_phase1[]={
+       dc390_DataOutPhase,
+       dc390_DataInPhase,
+       dc390_CommandPhase,
+       dc390_StatusPhase,
+       dc390_Nop_0,
+       dc390_Nop_0,
+       dc390_MsgOutPhase,
+       dc390_MsgInPhase,
+       dc390_Nop_1
+       };
 
-UCHAR  clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+#ifdef DC390_DEBUG1
+static char* dc390_p0_str[] = {
+       "dc390_DataOut_0",
+       "dc390_DataIn_0",
+       "dc390_Command_0",
+       "dc390_Status_0",
+       "dc390_Nop_0",
+       "dc390_Nop_0",
+       "dc390_MsgOut_0",
+       "dc390_MsgIn_0",
+       "dc390_Nop_1"
+       };
+     
+static char* dc390_p1_str[] = {
+       "dc390_DataOutPhase",
+       "dc390_DataInPhase",
+       "dc390_CommandPhase",
+       "dc390_StatusPhase",
+       "dc390_Nop_0",
+       "dc390_Nop_0",
+       "dc390_MsgOutPhase",
+       "dc390_MsgInPhase",
+       "dc390_Nop_1"
+       };
+#endif   
 
-UCHAR  baddevname1[2][28] ={
+/* Devices erroneously pretending to be able to do TagQ */
+UCHAR  dc390_baddevname1[2][28] ={
        "SEAGATE ST3390N         9546",
        "HP      C3323-300       4269"};
-
 #define BADDEVCNT	2
 
+static char*  dc390_adapname = "DC390";
+UCHAR  dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN];
+UCHAR  dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+
+struct proc_dir_entry	DC390_proc_scsi_tmscsim ={
+       PROC_SCSI_DC390T, 7 ,"tmscsim",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2
+       };
 
 /***********************************************************************
  *
  *
  *
  **********************************************************************/
-static void
-QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd)
 {
-    ULONG  flags;
-    PSCSICMD  pcmd;
+   PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0;
+   while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun)
+     {
+	pDCB = pDCB->pNextDCB;
+	if (pDCB == pACB->pLinkDCB)
+	  {
+	     printk (KERN_ERR "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n",
+		     (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]);
+	     return 0;
+	  }
+     };
+   DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n",	\
+	   (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+   return pDCB;
+};
 
-    save_flags(flags);
-    cli();
+static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+{
+    PSCSICMD  pcmd;
 
     if( !pDCB->QIORBCnt )
     {
@@ -185,83 +524,61 @@
 	cmd->next = NULL;
     }
 
-    restore_flags(flags);
 }
 
 
-static PSCSICMD
-Getcmd( PDCB pDCB )
+static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB )
 {
-    ULONG  flags;
     PSCSICMD  pcmd;
 
-    save_flags(flags);
-    cli();
-
     pcmd = pDCB->pQIORBhead;
     pDCB->pQIORBhead = pcmd->next;
     pcmd->next = NULL;
     pDCB->QIORBCnt--;
 
-    restore_flags(flags);
     return( pcmd );
 }
 
 
-static PSRB
-GetSRB( PACB pACB )
+static __inline__ PSRB dc390_GetSRB( PACB pACB )
 {
-    ULONG  flags;
     PSRB   pSRB;
 
-    save_flags(flags);
-    cli();
-
     pSRB = pACB->pFreeSRB;
     if( pSRB )
     {
 	pACB->pFreeSRB = pSRB->pNextSRB;
 	pSRB->pNextSRB = NULL;
     }
-    restore_flags(flags);
+
     return( pSRB );
 }
 
 
-static void
-RewaitSRB0( PDCB pDCB, PSRB pSRB )
+static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB )
 {
     PSRB   psrb1;
-    ULONG  flags;
-
-    save_flags(flags);
-    cli();
 
     if( (psrb1 = pDCB->pWaitingSRB) )
     {
 	pSRB->pNextSRB = psrb1;
-	pDCB->pWaitingSRB = pSRB;
     }
     else
     {
 	pSRB->pNextSRB = NULL;
-	pDCB->pWaitingSRB = pSRB;
 	pDCB->pWaitLast = pSRB;
     }
-    restore_flags(flags);
+    pDCB->pWaitingSRB = pSRB;
 }
 
 
-static void
-RewaitSRB( PDCB pDCB, PSRB pSRB )
+static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB )
 {
     PSRB   psrb1;
-    ULONG  flags;
     UCHAR  bval;
 
-    save_flags(flags);
-    cli();
-    pDCB->GoingSRBCnt--;
+    pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++;
+    DEBUG0(printk("DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);)
     psrb1 = pDCB->pGoingSRB;
     if( pSRB == psrb1 )
     {
@@ -289,20 +606,14 @@
 
     bval = pSRB->TagNumber;
     pDCB->TagMask &= (~(1 << bval));	  /* Free TAG number */
-    restore_flags(flags);
 }
 
 
-static void
-DoWaitingSRB( PACB pACB )
+static void dc390_DoWaitingSRB( PACB pACB )
 {
-    ULONG  flags;
     PDCB   ptr, ptr1;
     PSRB   pSRB;
 
-    save_flags(flags);
-    cli();
-
     if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
     {
 	ptr = pACB->pDCBRunRobin;
@@ -324,7 +635,7 @@
 	    }
 	    else
 	    {
-		if( !DC390_StartSCSI(pACB, ptr1, pSRB) )
+		if( !dc390_StartSCSI(pACB, ptr1, pSRB) )
 		{
 		    ptr1->GoingSRBCnt++;
 		    if( ptr1->pWaitLast == pSRB )
@@ -348,55 +659,47 @@
 	    }
 	}
     }
-    restore_flags(flags);
     return;
 }
 
 
-static void
-SRBwaiting( PDCB pDCB, PSRB pSRB)
+static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB)
 {
     if( pDCB->pWaitingSRB )
     {
 	pDCB->pWaitLast->pNextSRB = pSRB;
-	pDCB->pWaitLast = pSRB;
 	pSRB->pNextSRB = NULL;
     }
     else
     {
 	pDCB->pWaitingSRB = pSRB;
-	pDCB->pWaitLast = pSRB;
     }
+    pDCB->pWaitLast = pSRB;
 }
 
 
-static void
-SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
+static void dc390_SendSRB( PACB pACB, PSRB pSRB )
 {
-    ULONG  flags;
     PDCB   pDCB;
 
-    save_flags(flags);
-    cli();
-
     pDCB = pSRB->pSRBDCB;
     if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
 	(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
     {
-	SRBwaiting(pDCB, pSRB);
+	dc390_SRBwaiting(pDCB, pSRB);
 	goto SND_EXIT;
     }
 
     if( pDCB->pWaitingSRB )
     {
-	SRBwaiting(pDCB, pSRB);
-/*	pSRB = GetWaitingSRB(pDCB); */
+	dc390_SRBwaiting(pDCB, pSRB);
+/*	pSRB = GetWaitingSRB(pDCB); */	/* non-existent */
 	pSRB = pDCB->pWaitingSRB;
 	pDCB->pWaitingSRB = pSRB->pNextSRB;
 	pSRB->pNextSRB = NULL;
     }
 
-    if( !DC390_StartSCSI(pACB, pDCB, pSRB) )
+    if( !dc390_StartSCSI(pACB, pDCB, pSRB) )
     {
 	pDCB->GoingSRBCnt++;
 	if( pDCB->pGoingSRB )
@@ -411,13 +714,52 @@
 	}
     }
     else
-	RewaitSRB0( pDCB, pSRB );
+	dc390_RewaitSRB0( pDCB, pSRB );
 
 SND_EXIT:
-    restore_flags(flags);
     return;
 }
 
+static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB)
+{
+    pSRB->pSRBDCB = pDCB;
+    pSRB->pcmd = pcmd;
+    pSRB->ScsiCmdLen = pcmd->cmd_len;
+    memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len);
+    
+    if( pcmd->use_sg )
+    {
+	pSRB->SGcount = (UCHAR) pcmd->use_sg;
+	pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+    }
+    else if( pcmd->request_buffer )
+    {
+	pSRB->SGcount = 1;
+	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+	pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+	pSRB->Segmentx.length = pcmd->request_bufflen;
+    }
+    else
+	pSRB->SGcount = 0;
+
+    pSRB->SGIndex = 0;
+    pSRB->AdaptStatus = 0;
+    pSRB->TargetStatus = 0;
+    pSRB->MsgCnt = 0;
+    if( pDCB->DevType != TYPE_TAPE )
+	pSRB->RetryCnt = 1;
+    else
+	pSRB->RetryCnt = 0;
+    pSRB->SRBStatus = 0;
+    pSRB->SRBFlag = 0;
+    pSRB->SRBState = 0;
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGBusAddr = 0;
+    pSRB->SGToBeXferLen = 0;
+    pSRB->ScsiPhase = 0;
+    pSRB->EndMessage = 0;
+};
+
 
 /***********************************************************************
  * Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
@@ -425,272 +767,305 @@
  *
  * Purpose : enqueues a SCSI command
  *
- * Inputs : cmd - SCSI command, done - function called on completion, with
- *	    a pointer to the command descriptor.
+ * Inputs : cmd - SCSI command, done - callback function called on 
+ *	    completion, with a pointer to the command descriptor.
  *
- * Returns : 0
+ * Returns : (depending on kernel version)
+ * 2.0.x: always return 0
+ * 2.1.x: old model: (use_new_eh_code == 0): like 2.0.x
+ *	  TO BE DONE:
+ *	  new model: return 0 if successful
+ *	  	     return 1 if command cannot be queued (queue full)
+ *		     command will be inserted in midlevel queue then ...
  *
  ***********************************************************************/
 
-int
-DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
 {
-    USHORT ioport, i;
     Scsi_Cmnd *pcmd;
-    struct Scsi_Host *psh;
-    PACB   pACB;
     PDCB   pDCB;
     PSRB   pSRB;
-    ULONG  flags;
-    PUCHAR ptr,ptr1;
+    DC390_AFLAGS
+    PACB   pACB = (PACB) cmd->host->hostdata;
 
-    psh = cmd->host;
-    pACB = (PACB ) psh->hostdata;
-    ioport = pACB->IOPortBase;
 
-#ifdef DC390_DEBUG0
-/*  if(pACB->scan_devices) */
-	printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);
-#endif
+    DEBUG0(/*  if(pACB->scan_devices) */	\
+	printk(KERN_DEBUG "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\
+		cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);)
+
+    DC390_LOCK_ACB;
+    
+    /* Assume BAD_TARGET; will be cleared later */
+    cmd->result = DID_BAD_TARGET << 16;
+   
+    /* TODO: Change the policy: Alway accept TEST_UNIT_READY or INQUIRY 
+     * commands and alloc a DCB for the device if not yet there. DCB will
+     * be removed in dc390_SRBdone if SEL_TIMEOUT */
 
     if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
-    {
 	pACB->scan_devices = 0;
-	pPrevDCB->pNextDCB = pACB->pLinkDCB;
-    }
-    else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) )
-    {
+
+    else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) )
 	pACB->scan_devices = 0;
-	pPrevDCB->pNextDCB = pACB->pLinkDCB;
-    }
 
-    if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) )
+    if ( ( cmd->target >= pACB->pScsiHost->max_id ) || 
+	 (cmd->lun >= pACB->pScsiHost->max_lun) )
     {
 /*	printk("DC390: Ignore target %d lun %d\n",
 		cmd->target, cmd->lun); */
-	cmd->result = (DID_BAD_TARGET << 16);
+	DC390_UNLOCK_ACB;
 	done(cmd);
 	return( 0 );
     }
 
-    if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+    if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
     {
-	if( pACB->DeviceCnt < MAX_DEVICES )
-	{
-	    pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
-	    pDCB = pACB->pDCB_free;
-#ifdef DC390_DEBUG0
-	    printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
-#endif
-	    DC390_initDCB( pACB, pDCB, cmd );
-	}
-	else	/* ???? */
-	{
-/*	    printk("DC390: Ignore target %d lun %d\n",
-		    cmd->target, cmd->lun); */
-	    cmd->result = (DID_BAD_TARGET << 16);
+	pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
+        pACB->scan_devices = 1;
+
+	dc390_initDCB( pACB, &pDCB, cmd );
+	if (!pDCB)
+	  {
+	    printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target);
+	    DC390_UNLOCK_ACB;
 	    done(cmd);
 	    return(0);
-	}
+	  };
+            
     }
     else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
     {
-/*	printk("DC390: Ignore target %d lun %d\n",
-		cmd->target, cmd->lun); */
-	cmd->result = (DID_BAD_TARGET << 16);
+	printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n",
+		cmd->target, cmd->lun); 
+	DC390_UNLOCK_ACB;
 	done(cmd);
 	return(0);
     }
     else
     {
-	pDCB = pACB->pLinkDCB;
-	while( (pDCB->UnitSCSIID != cmd->target) ||
-	       (pDCB->UnitSCSILUN != cmd->lun) )
-	{
-	    pDCB = pDCB->pNextDCB;
-	}
-#ifdef DC390_DEBUG0
-	    printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
-#endif
+	pDCB = dc390_findDCB (pACB, cmd);
+	if (!pDCB)
+	 {  /* should never happen */
+	    DC390_UNLOCK_ACB;
+	    done(cmd);
+	    return(0);
+	 };
     }
 
+    pACB->Cmds++;
     cmd->scsi_done = done;
     cmd->result = 0;
 
-    save_flags(flags);
-    cli();
-
-    if( pDCB->QIORBCnt )
+    if( pDCB->QIORBCnt ) /* Unsent commands ? */
     {
-	QLinkcmd( cmd, pDCB );
-	pcmd = Getcmd( pDCB );
+	dc390_QLinkcmd( cmd, pDCB );
+	pcmd = dc390_Getcmd( pDCB ); /* Get first command */
+        pACB->CmdInQ++;
     }
     else
 	pcmd = cmd;
 
-    pSRB = GetSRB( pACB );
+    pSRB = dc390_GetSRB( pACB );
 
     if( !pSRB )
     {
-	QLinkcmd( pcmd, pDCB );
-	restore_flags(flags);
+        dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */
+	pACB->CmdOutOfSRB++;
+	DC390_UNLOCK_ACB;
 	return(0);
     }
 
-/*  BuildSRB(pSRB); */
+    dc390_BuildSRB (pcmd, pDCB, pSRB);
+    dc390_SendSRB( pACB, pSRB );
 
-    pSRB->pSRBDCB = pDCB;
-    pSRB->pcmd = pcmd;
-    ptr = (PUCHAR) pSRB->CmdBlock;
-    ptr1 = (PUCHAR) pcmd->cmnd;
-    pSRB->ScsiCmdLen = pcmd->cmd_len;
-    for(i=0; i< pcmd->cmd_len; i++)
-    {
-	*ptr = *ptr1;
-	ptr++;
-	ptr1++;
-    }
-    if( pcmd->use_sg )
-    {
-	pSRB->SGcount = (UCHAR) pcmd->use_sg;
-	pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
-    }
-    else if( pcmd->request_buffer )
-    {
-	pSRB->SGcount = 1;
-	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
-	pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
-	pSRB->Segmentx.length = pcmd->request_bufflen;
-    }
-    else
-	pSRB->SGcount = 0;
-
-    pSRB->SGIndex = 0;
-    pSRB->AdaptStatus = 0;
-    pSRB->TargetStatus = 0;
-    pSRB->MsgCnt = 0;
-    if( pDCB->DevType != TYPE_TAPE )
-	pSRB->RetryCnt = 1;
-    else
-	pSRB->RetryCnt = 0;
-    pSRB->SRBStatus = 0;
-    pSRB->SRBFlag = 0;
-    pSRB->SRBState = 0;
-    pSRB->TotalXferredLen = 0;
-    pSRB->SGPhysAddr = 0;
-    pSRB->SGToBeXferLen = 0;
-    pSRB->ScsiPhase = 0;
-    pSRB->EndMessage = 0;
-    SendSRB( pcmd, pACB, pSRB );
-
-    restore_flags(flags);
+    DC390_UNLOCK_ACB;
+    DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);)
     return(0);
 }
 
 
-static void
-DoNextCmd( PACB pACB, PDCB pDCB )
+static void dc390_DoNextCmd( PACB pACB, PDCB pDCB )
 {
     Scsi_Cmnd *pcmd;
     PSRB   pSRB;
-    ULONG  flags;
-    PUCHAR ptr,ptr1;
-    USHORT i;
-
 
     if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
 	return;
-    save_flags(flags);
-    cli();
 
-    pcmd = Getcmd( pDCB );
-    pSRB = GetSRB( pACB );
+    pcmd = dc390_Getcmd( pDCB );
+    pSRB = dc390_GetSRB( pACB );
     if( !pSRB )
-    {
-	QLinkcmd( pcmd, pDCB );
-	restore_flags(flags);
-	return;
-    }
-
-    pSRB->pSRBDCB = pDCB;
-    pSRB->pcmd = pcmd;
-    ptr = (PUCHAR) pSRB->CmdBlock;
-    ptr1 = (PUCHAR) pcmd->cmnd;
-    pSRB->ScsiCmdLen = pcmd->cmd_len;
-    for(i=0; i< pcmd->cmd_len; i++)
-    {
-	*ptr = *ptr1;
-	ptr++;
-	ptr1++;
-    }
-    if( pcmd->use_sg )
-    {
-	pSRB->SGcount = (UCHAR) pcmd->use_sg;
-	pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
-    }
-    else if( pcmd->request_buffer )
-    {
-	pSRB->SGcount = 1;
-	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
-	pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
-	pSRB->Segmentx.length = pcmd->request_bufflen;
-    }
+	dc390_QLinkcmd( pcmd, pDCB );
     else
-	pSRB->SGcount = 0;
-
-    pSRB->SGIndex = 0;
-    pSRB->AdaptStatus = 0;
-    pSRB->TargetStatus = 0;
-    pSRB->MsgCnt = 0;
-    if( pDCB->DevType != TYPE_TAPE )
-	pSRB->RetryCnt = 1;
-    else
-	pSRB->RetryCnt = 0;
-    pSRB->SRBStatus = 0;
-    pSRB->SRBFlag = 0;
-    pSRB->SRBState = 0;
-    pSRB->TotalXferredLen = 0;
-    pSRB->SGPhysAddr = 0;
-    pSRB->SGToBeXferLen = 0;
-    pSRB->ScsiPhase = 0;
-    pSRB->EndMessage = 0;
-    SendSRB( pcmd, pACB, pSRB );
-
-    restore_flags(flags);
-    return;
+      {
+	dc390_BuildSRB (pcmd, pDCB, pSRB);
+	dc390_SendSRB( pACB, pSRB );
+      };
+}
+
+/* We ignore mapping problems, as we expect everybody to respect 
+ * valid partition tables. Waiting for complaints ;-) */
+
+#ifdef CONFIG_SCSI_DC390T_TRADMAP
+/* 
+ * The next function, partsize(), is copied from scsicam.c.
+ *
+ * This is ugly code duplication, but I didn't find another way to solve it:
+ * We want to respect the partition table and if it fails, we apply the 
+ * DC390 BIOS heuristic. Too bad, just calling scsicam_bios_param() doesn't do
+ * the job, because we don't know, whether the values returned are from
+ * the part. table or determined by setsize(). Unfortunately the setsize() 
+ * values differ from the ones chosen by the DC390 BIOS.
+ *
+ * Looking forward to seeing suggestions for a better solution! KG, 98/10/14
+ */
+#include <asm/unaligned.h>
+
+/*
+ * Function : static int partsize(struct buffer_head *bh, unsigned long 
+ *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
+ *
+ * Purpose : to determine the BIOS mapping used to create the partition
+ *	table, storing the results in *cyls, *hds, and *secs 
+ *
+ * Returns : -1 on failure, 0 on success.
+ *
+ */
+
+static int partsize(struct buffer_head *bh, unsigned long capacity,
+    unsigned int  *cyls, unsigned int *hds, unsigned int *secs) {
+    struct partition *p, *largest = NULL;
+    int i, largest_cyl;
+    int cyl, ext_cyl, end_head, end_cyl, end_sector;
+    unsigned int logical_end, physical_end, ext_physical_end;
+    
+
+    if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
+	for (largest_cyl = -1, p = (struct partition *) 
+    	    (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
+    	    if (!p->sys_ind)
+    	    	continue;
+    	    cyl = p->cyl + ((p->sector & 0xc0) << 2);
+    	    if (cyl > largest_cyl) {
+    	    	largest_cyl = cyl;
+    	    	largest = p;
+    	    }
+    	}
+    }
+
+    if (largest) {
+    	end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
+    	end_head = largest->end_head;
+    	end_sector = largest->end_sector & 0x3f;
+
+    	physical_end =  end_cyl * (end_head + 1) * end_sector +
+    	    end_head * end_sector + end_sector;
+
+	/* This is the actual _sector_ number at the end */
+	logical_end = get_unaligned(&largest->start_sect)
+			+ get_unaligned(&largest->nr_sects);
+
+	/* This is for >1023 cylinders */
+        ext_cyl= (logical_end-(end_head * end_sector + end_sector))
+                                        /(end_head + 1) / end_sector;
+	ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
+            end_head * end_sector + end_sector;
+
+    	if ((logical_end == physical_end) ||
+	    (end_cyl==1023 && ext_physical_end==logical_end)) {
+    	    *secs = end_sector;
+    	    *hds = end_head + 1;
+    	    *cyls = capacity / ((end_head + 1) * end_sector);
+    	    return 0;
+    	}
+    }
+    return -1;
 }
 
-
 /***********************************************************************
  * Function:
  *   DC390_bios_param
  *
  * Description:
  *   Return the disk geometry for the given SCSI device.
+ *   Respect the partition table, otherwise try own heuristic
+ *
+ * Note:
+ *   In contrary to other externally callable funcs (DC390_), we don't lock
  ***********************************************************************/
-int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
+int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
 {
     int heads, sectors, cylinders;
-    PACB pACB;
+    PACB pACB = (PACB) disk->device->host->hostdata;
+    struct buffer_head *bh;
+    int ret_code = -1;
+    int size = disk->capacity;
 
-    pACB = (PACB) disk->device->host->hostdata;
-    heads = 64;
-    sectors = 32;
-    cylinders = disk->capacity / (heads * sectors);
-
-    if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
+    if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024)))
     {
-      heads = 255;
-      sectors = 63;
-      cylinders = disk->capacity / (heads * sectors);
+	/* try to infer mapping from partition table */
+	ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2,
+			     (unsigned int *) geom + 0, (unsigned int *) geom + 1);
+	brelse (bh);
     }
+    if (ret_code == -1)
+    {
+	heads = 64;
+	sectors = 32;
+	cylinders = size / (heads * sectors);
+
+	if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
+	{
+		heads = 255;
+		sectors = 63;
+		cylinders = size / (heads * sectors);
+	}
 
-    geom[0] = heads;
-    geom[1] = sectors;
-    geom[2] = cylinders;
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+    }
 
     return (0);
 }
+#else
+int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
+{
+    return scsicam_bios_param (disk, devno, geom);
+};
+#endif
+
+
+void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB)
+{
+    USHORT pstat; PDEVDECL1;
+
+    if (pSRB) 
+    {
+	printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, Phase %02x\n",
+		pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState,
+		pSRB->ScsiPhase);
+	printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus);
+    };
+    printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08lx\n", dc390_laststatus);
+    printk ("DC390: Register dump: SCSI block:\n");
+    printk ("DC390: XferCnt  Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n");
+    printk ("DC390:  %06x   %02x   %02x   %02x",
+	    DC390_read8(CtcReg_Low) + (DC390_read8(CtcReg_Mid) << 8) + (DC390_read8(CtcReg_High) << 16),
+	    DC390_read8(ScsiCmd), DC390_read8(Scsi_Status), DC390_read8(Intern_State));
+    printk ("   %02x   %02x   %02x   %02x   %02x   %02x\n",
+	    DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1),
+	    DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4));
+    printk ("DC390: Register dump: DMA engine:\n");
+    printk ("DC390: Cmd   STrCnt    SBusA    WrkBC    WrkAC Stat SBusCtrl\n");
+    printk ("DC390:  %02x %08x %08x %08x %08x   %02x %08x\n",
+	    DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr),
+	    DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr),
+	    DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl));
+    PDEVSET1; PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstat);
+    printk ("DC390: Register dump: PCI Status: %04x\n", pstat);
+    printk ("DC390: Please report driver trouble to K.Garloff@ping.de\n");
+};
 
 
 /***********************************************************************
@@ -703,35 +1078,28 @@
  * Returns : 0 on success, -1 on failure.
  ***********************************************************************/
 
-int
-DC390_abort (Scsi_Cmnd *cmd)
+int DC390_abort (Scsi_Cmnd *cmd)
 {
-    ULONG flags;
-    PACB  pACB;
-    PDCB  pDCB, pdcb;
+    PDCB  pDCB;
     PSRB  pSRB, psrb;
-    USHORT count, i;
+    ULONG count, i;
     PSCSICMD  pcmd, pcmd1;
     int   status;
+    ULONG sbac;
+    DC390_AFLAGS
+    PACB  pACB = (PACB) cmd->host->hostdata;
+
+    DC390_LOCK_ACB;
+
+    pDCB = dc390_findDCB (pACB, cmd);
+    /* abort() is too buggy at the moment. If it's called we are in trouble anyway.
+     * so let's dump some info into the syslog at least. (KG, 98/08/20) */
+    if (pDCB) pSRB = pDCB->pActiveSRB; else pSRB = 0;
+    printk ("DC390: Abort command (pid %li, DCB %p, SRB %p)\n",
+	    cmd->pid, pDCB, pSRB);
+    dc390_dumpinfo (pACB, pDCB, pSRB);
 
-
-#ifdef DC390_DEBUG0
-    printk("DC390 : Abort Cmd.");
-#endif
-
-    save_flags(flags);
-    cli();
-
-    pACB = (PACB) cmd->host->hostdata;
-    pDCB = pACB->pLinkDCB;
-    pdcb = pDCB;
-    while( (pDCB->UnitSCSIID != cmd->target) ||
-	   (pDCB->UnitSCSILUN != cmd->lun) )
-    {
-	pDCB = pDCB->pNextDCB;
-	if( pDCB == pdcb )
-	    goto  NOT_RUN;
-    }
+    if( !pDCB ) goto  NOT_RUN;
 
     if( pDCB->QIORBCnt )
     {
@@ -761,7 +1129,12 @@
 	    }
 	}
     }
-
+	
+    /* Added 98/07/02 KG */
+    pSRB = pDCB->pActiveSRB;
+    if (pSRB && pSRB->pcmd == cmd )
+	goto ON_GOING;
+	
     pSRB = pDCB->pWaitingSRB;
     if( !pSRB )
 	goto  ON_GOING;
@@ -778,7 +1151,7 @@
 	while( psrb->pNextSRB->pcmd != cmd )
 	{
 	    psrb = psrb->pNextSRB;
-	    if( !(psrb->pNextSRB) )
+	    if( !(psrb->pNextSRB) || psrb == pSRB)
 		goto ON_GOING;
 	}
 	pSRB = psrb->pNextSRB;
@@ -795,6 +1168,8 @@
 
 ON_GOING:
     pSRB = pDCB->pGoingSRB;
+    pDCB->DCBFlag |= ABORT_DEV_;
+    /* Now for the hard part: The command is currently processed */
     for( count = pDCB->GoingSRBCnt, i=0; i<count; i++)
     {
 	if( pSRB->pcmd != cmd )
@@ -804,6 +1179,8 @@
 	    if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
 	    {
 		status = SCSI_ABORT_BUSY;
+		printk ("DC390: Abort current command (pid %li, SRB %p)\n",
+			cmd->pid, pSRB);
 		goto  ABO_X;
 	    }
 	    else
@@ -819,20 +1196,51 @@
 
 ABO_X:
     cmd->result = DID_ABORT << 16;
+    printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status);
+    if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */
+	{
+		/* Let's do something to help the bus getting clean again */
+		DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+		DC390_write8 (ScsiCmd, DMA_COMMAND);
+			//DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+		//DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+		DC390_write8 (ScsiCmd, NOP_CMD);
+		//udelay (10000);
+		//DC390_read8 (INT_Status);
+		//DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+	};
+    sbac = DC390_read32 (DMA_ScsiBusCtrl);
+    if (sbac & SCSI_BUSY)
+    {	/* clear BSY, SEL and ATN */
+	printk (KERN_WARNING "DC390: Reset SCSI device: ");
+	//DC390_write32 (DMA_ScsiBusCtrl, (sbac | SCAM) & ~SCSI_LINES);
+	//udelay (250);
+	//sbac = DC390_read32 (DMA_ScsiBusCtrl);
+	//printk ("%08lx ", sbac);
+	//DC390_write32 (DMA_ScsiBusCtrl, sbac & ~(SCSI_LINES | SCAM));
+	//udelay (100);
+	//sbac = DC390_read32 (DMA_ScsiBusCtrl);
+	//printk ("%08lx ", sbac);
+	DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+	udelay (250);
+	DC390_write8 (ScsiCmd, NOP_CMD);
+	sbac = DC390_read32 (DMA_ScsiBusCtrl);
+	printk ("%08lx\n", sbac);
+    };
+    dc390_lastabortedpid = cmd->pid;
+    DC390_UNLOCK_ACB;
+    //do_DC390_Interrupt (pACB->IRQLevel, 0, 0);
     cmd->scsi_done(cmd);
-    restore_flags(flags);
     return( status );
 }
 
 
-static void
-ResetDevParam( PACB pACB )
+static void dc390_ResetDevParam( PACB pACB )
 {
     PDCB   pDCB, pdcb;
 
     pDCB = pACB->pLinkDCB;
-    if( pDCB == NULL )
-	return;
+    if (! pDCB) return;
     pdcb = pDCB;
     do
     {
@@ -840,24 +1248,22 @@
 	pDCB->SyncPeriod = 0;
 	pDCB->SyncOffset = 0;
 	pDCB->CtrlR3 = FAST_CLK;
-	pDCB->CtrlR4 &= NEGATE_REQACKDATA;
-	pDCB->CtrlR4 |= EATER_25NS;
+	pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK;
+	pDCB->CtrlR4 |= pACB->glitch_cfg;
 	pDCB = pDCB->pNextDCB;
     }
     while( pdcb != pDCB );
 }
 
 
-static void
-RecoverSRB( PACB pACB )
+static void dc390_RecoverSRB( PACB pACB )
 {
     PDCB   pDCB, pdcb;
     PSRB   psrb, psrb2;
-    USHORT cnt, i;
+    ULONG  cnt, i;
 
     pDCB = pACB->pLinkDCB;
-    if( pDCB == NULL )
-	return;
+    if( !pDCB ) return;
     pdcb = pDCB;
     do
     {
@@ -867,7 +1273,7 @@
 	{
 	    psrb2 = psrb;
 	    psrb = psrb->pNextSRB;
-/*	    RewaitSRB( pDCB, psrb ); */
+/*	    dc390_RewaitSRB( pDCB, psrb ); */
 	    if( pdcb->pWaitingSRB )
 	    {
 		psrb2->pNextSRB = pdcb->pWaitingSRB;
@@ -884,8 +1290,7 @@
 	pdcb->pGoingSRB = NULL;
 	pdcb->TagMask = 0;
 	pdcb = pdcb->pNextDCB;
-    }
-    while( pdcb != pDCB );
+    } while( pdcb != pDCB );
 }
 
 
@@ -901,77 +1306,80 @@
 
 int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
 {
-    USHORT   ioport;
-    unsigned long flags;
-    PACB  pACB;
-    UCHAR    bval;
-    USHORT  i;
-
+    UCHAR   bval;
+    ULONG   i;
+    DC390_AFLAGS
+    PACB    pACB = (PACB) cmd->host->hostdata;
 
-#ifdef DC390_DEBUG1
-    printk("DC390: RESET,");
-#endif
+    printk(KERN_INFO "DC390: RESET ... ");
 
-    pACB = (PACB ) cmd->host->hostdata;
-    ioport = pACB->IOPortBase;
-    save_flags(flags);
-    cli();
-    bval = inb(ioport+CtrlReg1);
+    DC390_LOCK_ACB;
+    bval = DC390_read8 (CtrlReg1);
     bval |= DIS_INT_ON_SCSI_RST;
-    outb(bval,ioport+CtrlReg1);  /* disable interrupt */
-    DC390_ResetSCSIBus( pACB );
-    for( i=0; i<500; i++ )
-	mdelay(1);
-    bval = inb(ioport+CtrlReg1);
-    bval &= ~DIS_INT_ON_SCSI_RST;
-    outb(bval,ioport+CtrlReg1); /* re-enable interrupt */
-
-    bval = DMA_IDLE_CMD;
-    outb(bval,ioport+DMA_Cmd);
-    bval = CLEAR_FIFO_CMD;
-    outb(bval,ioport+ScsiCmd);
+    DC390_write8 (CtrlReg1, bval);	/* disable interrupt */
 
-    ResetDevParam( pACB );
-    DoingSRB_Done( pACB );
+    dc390_ResetSCSIBus( pACB );
+    /* Unlock ? */
+    for( i=0; i<600; i++ )
+	udelay(1000);
+
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    DC390_read8 (INT_Status);		/* Reset Pending INT */
+
+    dc390_ResetDevParam( pACB );
+    dc390_DoingSRB_Done( pACB );
+    /* dc390_RecoverSRB (pACB); */
     pACB->pActiveDCB = NULL;
 
     pACB->ACBFlag = 0;
-    DoWaitingSRB( pACB );
+    bval = DC390_read8 (CtrlReg1);
+    bval &= ~DIS_INT_ON_SCSI_RST;
+    DC390_write8 (CtrlReg1, bval);	/* re-enable interrupt */
 
-    restore_flags(flags);
-#ifdef DC390_DEBUG1
-    printk("DC390: RESET1,");
-#endif
+    dc390_DoWaitingSRB( pACB );
+
+    DC390_UNLOCK_ACB;
+    printk("done\n");
     return( SCSI_RESET_SUCCESS );
 }
 
-
 #include "scsiiom.c"
 
 
 /***********************************************************************
- * Function : static void DC390_initDCB
+ * Function : static void dc390_initDCB
  *
  * Purpose :  initialize the internal structures for a given DCB
  *
  * Inputs : cmd - pointer to this scsi cmd request block structure
  *
  ***********************************************************************/
-void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
+void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd )
 {
     PEEprom	prom;
-    UCHAR	bval;
-    USHORT	index;
+    UCHAR	index;
+    PDCB pDCB;
 
-    if( pACB->DeviceCnt == 0 )
+    pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC);
+    DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): 0x%08x\n",	\
+	    cmd->target, cmd->lun, (int)pDCB);)
+ 
+    *ppDCB = pDCB;
+    if (!pDCB) return;
+    if( pACB->DCBCnt == 0 )
     {
 	pACB->pLinkDCB = pDCB;
 	pACB->pDCBRunRobin = pDCB;
-	pDCB->pNextDCB = pDCB;
-	pPrevDCB = pDCB;
     }
     else
-	pPrevDCB->pNextDCB = pDCB;
+    {
+	pACB->pLastDCB->pNextDCB = pDCB;
+    };
+   
+    pACB->DCBCnt++;
+   
+    pACB->pLastDCB = pDCB;
+    pDCB->pNextDCB = pACB->pLinkDCB;
 
     pDCB->pDCBACB = pACB;
     pDCB->QIORBCnt = 0;
@@ -983,122 +1391,143 @@
     pDCB->pActiveSRB = NULL;
     pDCB->TagMask = 0;
     pDCB->MaxCommand = 1;
-    pDCB->AdaptIndex = pACB->AdapterIndex;
     index = pACB->AdapterIndex;
     pDCB->DCBFlag = 0;
 
-    prom = (PEEprom) &eepromBuf[index][cmd->target << 2];
+    prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2];
     pDCB->DevMode = prom->EE_MODE1;
-    pDCB->AdpMode = eepromBuf[index][EE_MODE2];
-
-    if( pDCB->DevMode & EN_DISCONNECT_ )
-	bval = 0xC0;
-    else
-	bval = 0x80;
-    bval |= cmd->lun;
-    pDCB->IdentifyMsg = bval;
 
     pDCB->SyncMode = 0;
-    if( pDCB->DevMode & SYNC_NEGO_ )
-    {
-	if( !(cmd->lun) || CurrSyncOffset )
-	    pDCB->SyncMode = SYNC_ENABLE;
-    }
+    dc390_updateDCB(pACB, pDCB);
 
     pDCB->SyncPeriod = 0;
     pDCB->SyncOffset = 0;
-    pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2;
-
-    pDCB->CtrlR1 = pACB->AdaptSCSIID;
-    if( pDCB->DevMode & PARITY_CHK_ )
-	pDCB->CtrlR1 |= PARITY_ERR_REPO;
+    pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2;
 
     pDCB->CtrlR3 = FAST_CLK;
 
-    pDCB->CtrlR4 = EATER_25NS;
-    if( pDCB->AdpMode & ACTIVE_NEGATION)
-	pDCB->CtrlR4 |= NEGATE_REQACKDATA;
+    pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED;
+    if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION)
+	pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK;
 }
 
+/***********************************************************************
+ * Function : static void dc390_updateDCB
+ *
+ * Purpose :  Set the configuration dependent DCB parameters
+ *
+ ***********************************************************************/
+void dc390_updateDCB (PACB pACB, PDCB pDCB)
+{
+  pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN);
+  
+  if (pDCB->DevMode & TAG_QUEUEING_) pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | EN_ATN_STOP;
+  else pDCB->SyncMode &= SYNC_NEGO_DONE | EN_ATN_STOP;
+  
+  if( pDCB->DevMode & SYNC_NEGO_ && (!(pDCB->UnitSCSILUN) || dc390_CurrSyncOffset) )
+     pDCB->SyncMode |= SYNC_ENABLE;
+  else
+     {
+	pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_ENABLE);
+	pDCB->SyncOffset &= ~0x0f;
+     };
+   
+  if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; 
+  
+  pDCB->CtrlR1 = pACB->pScsiHost->this_id;
+  if( pDCB->DevMode & PARITY_CHK_ )
+    pDCB->CtrlR1 |= PARITY_ERR_REPO;
+};  
+
+
+/***********************************************************************
+ * Function : static void dc390_updateDCBs
+ *
+ * Purpose :  Set the configuration dependent DCB params for all DCBs
+ *
+ ***********************************************************************/
+static void dc390_updateDCBs (PACB pACB)
+{
+  int i;
+  PDCB pDCB = pACB->pLinkDCB;
+  for (i = 0; i < pACB->DeviceCnt; i++)
+    {
+      dc390_updateDCB (pACB, pDCB);
+      pDCB = pDCB->pNextDCB;
+    };
+};
+  
 
 /***********************************************************************
- * Function : static void DC390_initSRB
+ * Function : static void dc390_initSRB
  *
  * Purpose :  initialize the internal structures for a given SRB
  *
  * Inputs : psrb - pointer to this scsi request block structure
  *
  ***********************************************************************/
-void DC390_initSRB( PSRB psrb )
+static void __inline__ dc390_initSRB( PSRB psrb )
 {
-#ifdef DC390_DEBUG0
-   printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
-#endif
-	psrb->PhysSRB = virt_to_bus( psrb );
+  /* psrb->PhysSRB = virt_to_phys( psrb ); */
 }
 
 
-void DC390_linkSRB( PACB pACB )
+void dc390_linkSRB( PACB pACB )
 {
-    USHORT  count, i;
-    PSRB    psrb;
+    ULONG   count, i;
 
     count = pACB->SRBCount;
-
     for( i=0; i< count; i++)
     {
 	if( i != count - 1)
 	    pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
 	else
 	    pACB->SRB_array[i].pNextSRB = NULL;
-	psrb = (PSRB) &pACB->SRB_array[i];
-	DC390_initSRB( psrb );
+	dc390_initSRB( &pACB->SRB_array[i] );
     }
 }
 
 
 /***********************************************************************
- * Function : static void DC390_initACB
+ * Function : static void dc390_initACB
  *
  * Purpose :  initialize the internal structures for a given SCSI host
  *
  * Inputs : psh - pointer to this host adapter's structure
  *
  ***********************************************************************/
-__initfunc(void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ))
+void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
 {
     PACB    pACB;
-    USHORT  i;
+    UCHAR   i;
+    DC390_AFLAGS
 
     psh->can_queue = MAX_CMD_QUEUE;
     psh->cmd_per_lun = MAX_CMD_PER_LUN;
-    psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID];
+    psh->this_id = (int) dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
     psh->io_port = io_port;
     psh->n_io_port = 0x80;
     psh->irq = Irq;
 
     pACB = (PACB) psh->hostdata;
+    DC390_LOCK_INIT;
+    DC390_LOCK_ACB;
 
+    pACB->pScsiHost = psh;
+    pACB->IOPortBase = (USHORT) io_port;
+    pACB->IRQLevel = Irq;
+
+    DEBUG0(printk (KERN_DEBUG "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n",	\
+	    index, psh->this_id, (int)io_port, Irq);)
+   
     psh->max_id = 8;
-#ifdef	CONFIG_SCSI_MULTI_LUN
-    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
-	psh->max_lun = 8;
-    else
-#endif
-	psh->max_lun = 1;
 
-    pACB->max_id = 7;
-    if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
-	pACB->max_id--;
-#ifdef	CONFIG_SCSI_MULTI_LUN
-    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
-	pACB->max_lun = 7;
-    else
-#endif
-	pACB->max_lun = 0;
+    if( psh->max_id - 1 == dc390_eepromBuf[index][EE_ADAPT_SCSI_ID] )
+	psh->max_id--;
+    psh->max_lun = 1;
+    if( dc390_eepromBuf[index][EE_MODE2] & LUN_CHECK )
+	psh->max_lun = 8;
 
-    pACB->pScsiHost = psh;
-    pACB->IOPortBase = (USHORT) io_port;
     pACB->pLinkDCB = NULL;
     pACB->pDCBRunRobin = NULL;
     pACB->pActiveDCB = NULL;
@@ -1106,42 +1535,39 @@
     pACB->SRBCount = MAX_SRB_CNT;
     pACB->AdapterIndex = index;
     pACB->status = 0;
-    pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID];
-    pACB->HostID_Bit = (1 << pACB->AdaptSCSIID);
-    pACB->AdaptSCSILUN = 0;
+    psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
     pACB->DeviceCnt = 0;
-    pACB->IRQLevel = Irq;
-    pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2;
+    pACB->DCBCnt = 0;
+    pACB->TagMaxNum = 2 << dc390_eepromBuf[index][EE_TAG_CMD_NUM];
     pACB->ACBFlag = 0;
     pACB->scan_devices = 1;
-    pACB->Gmode2 = eepromBuf[index][EE_MODE2];
-    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
-	pACB->LUNchk = 1;
-    pACB->pDCB_free = &pACB->DCB_array[0];
-    DC390_linkSRB( pACB );
+    pACB->Gmode2 = dc390_eepromBuf[index][EE_MODE2];
+    dc390_linkSRB( pACB );
     pACB->pTmpSRB = &pACB->TmpSRB;
-    DC390_initSRB( pACB->pTmpSRB );
+    dc390_initSRB( pACB->pTmpSRB );
     for(i=0; i<MAX_SCSI_ID; i++)
 	pACB->DCBmap[i] = 0;
+    pACB->sel_timeout = SEL_TIMEOUT;
+    pACB->glitch_cfg = EATER_25NS;
+    pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0;
 }
 
 
 /***********************************************************************
- * Function : static int DC390_initAdapter
+ * Function : static int dc390_initAdapter
  *
  * Purpose :  initialize the SCSI chip ctrl registers
  *
  * Inputs : psh - pointer to this host adapter's structure
  *
  ***********************************************************************/
-__initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index))
+int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
 {
-    USHORT ioport;
-    UCHAR  bval;
     PACB   pACB, pacb;
-    USHORT used_irq = 0;
+    UCHAR  used_irq = 0, dstate;
+    int    i;
 
-    pacb = pACB_start;
+    pacb = dc390_pACB_start;
     if( pacb != NULL )
     {
 	for ( ; (pacb != (PACB) -1) ; )
@@ -1158,49 +1584,54 @@
 
     if( !used_irq )
     {
-	if( request_irq(Irq, do_DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
+	if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) ))
+	    {
+		    printk(KERN_ERR "DC390: register IRQ error!\n");
+		    return( -1 );
+	    }
+    }
+
+    if (check_region (io_port, psh->n_io_port))
 	{
-	    printk("DC390: register IRQ error!\n");
+	    printk(KERN_ERR "DC390: register IO ports error!\n");
 	    return( -1 );
 	}
-    }
-
-    request_region(io_port,psh->n_io_port,"tmscsim");
-
-    ioport = (USHORT) io_port;
-
+    else
+	request_region (io_port, psh->n_io_port, "tmscsim");
+   
     pACB = (PACB) psh->hostdata;
-    bval = SEL_TIMEOUT; 		/* 250ms selection timeout */
-    outb(bval,ioport+Scsi_TimeOut);
-
-    bval = CLK_FREQ_40MHZ;		/* Conversion factor = 0 , 40MHz clock */
-    outb(bval,ioport+Clk_Factor);
-
-    bval = NOP_CMD;			/* NOP cmd - clear command register */
-    outb(bval,ioport+ScsiCmd);
-
-    bval = EN_FEATURE+EN_SCSI2_CMD;	/* Enable Feature and SCSI-2 */
-    outb(bval,ioport+CtrlReg2);
-
-    bval = FAST_CLK;			/* fast clock */
-    outb(bval,ioport+CtrlReg3);
+    /* pACB->IOPortBase = (USHORT) io_port; */
 
-    bval = EATER_25NS;
-    if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
-	 bval |= NEGATE_REQACKDATA;
-    outb(bval,ioport+CtrlReg4);
+    DC390_write8_ (CtrlReg1, DIS_INT_ON_SCSI_RST | psh->this_id, io_port);	/* Disable SCSI bus reset interrupt */
 
-    bval = DIS_INT_ON_SCSI_RST; 	/* Disable SCSI bus reset interrupt */
-    outb(bval,ioport+CtrlReg1);
+    if (pACB->Gmode2 & RST_SCSI_BUS)
+    {
+	dc390_ResetSCSIBus( pACB );
+	/* Unlock before ? */
+	for( i=0; i<600; i++ )
+		udelay(1000);
+    };
+    pACB->ACBFlag = 0;
+    
+    DC390_write8 (Scsi_TimeOut, SEL_TIMEOUT);		/* 250ms selection timeout */
+    DC390_write8 (Clk_Factor, CLK_FREQ_40MHZ);		/* Conversion factor = 0 , 40MHz clock */
+    DC390_write8 (ScsiCmd, NOP_CMD);			/* NOP cmd - clear command register */
+    DC390_write8 (CtrlReg2, EN_FEATURE+EN_SCSI2_CMD);	/* Enable Feature and SCSI-2 */
+    DC390_write8 (CtrlReg3, FAST_CLK);			/* fast clock */
+    DC390_write8 (CtrlReg4, pACB->glitch_cfg |			/* glitch eater */
+		(dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0);	/* Negation */
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+    dstate = DC390_read8 (DMA_Status);
+    DC390_write8 (DMA_Status, dstate);	/* clear */
 
     return(0);
 }
 
 
-void
-DC390_EnDisableCE( UCHAR mode, struct pci_dev *pdev, PUCHAR regval )
+static void __init dc390_EnDisableCE( UCHAR mode, PDEVDECL, PUCHAR regval )
 {
-
     UCHAR bval;
 
     bval = 0;
@@ -1208,15 +1639,68 @@
 	*regval = 0xc0;
     else
 	*regval = 0x80;
-    pci_write_config_byte(pdev, *regval, bval);
+    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     if(mode == DISABLE_CE)
-	pci_write_config_byte(pdev, *regval, bval);
+        PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     udelay(160);
 }
 
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+static void __init dc390_EEpromDefaults (UCHAR index)
+{
+    PUCHAR ptr;
+    UCHAR  id;
+    ptr = (PUCHAR) dc390_eepromBuf[index];
+    
+    /* Adapter Settings */
+    ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */
+    ptr[EE_MODE2] = (UCHAR)tmscsim[3];
+    ptr[EE_DELAY] = 0; /* ?? */
+    ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */
+    
+    /* Device Settings */
+    for (id = 0; id < MAX_SCSI_ID; id++)
+    {
+      ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */
+      ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */
+    };
+    dc390_adapname = "AM53C974";
+}
+
+static void __init dc390_checkparams (void)
+{
+	PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\
+		      tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);)
+	if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */
+	{
+		tmscsim[0] = 7; tmscsim[1] = 4; 
+		tmscsim[2] = 9; tmscsim[3] = 15;
+		tmscsim[4] = 2;
+		printk (KERN_INFO "DC390: Using safe settings.\n");
+	}
+	else
+	{
+		/* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */
+		if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4;
+		if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4;
+	};
+};
+/* Override defaults on cmdline:
+ * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped)
+ */
+void __init dc390_setup (char *str, int *ints)
+{
+	int i;
+	for (i = 0; i < ints[0]; i++)
+		tmscsim[i] = ints[i+1];
+	if (ints[0] > 5)
+		printk (KERN_NOTICE "DC390: ignore extra params!\n");
+	/* dc390_checkparams (); */
+};
+#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+
 
-void
-DC390_EEpromOutDI( struct pci_dev *pdev, PUCHAR regval, USHORT Carry )
+static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry )
 {
     UCHAR bval;
 
@@ -1225,28 +1709,27 @@
     {
 	bval = 0x40;
 	*regval = 0x80;
-	pci_write_config_byte(pdev, *regval, bval);
+	PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     }
     udelay(160);
     bval |= 0x80;
-    pci_write_config_byte(pdev, *regval, bval);
+    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     udelay(160);
     bval = 0;
-    pci_write_config_byte(pdev, *regval, bval);
+    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
     udelay(160);
 }
 
 
-UCHAR
-DC390_EEpromInDO( struct pci_dev *pdev )
+static UCHAR __init dc390_EEpromInDO( PDEVDECL )
 {
     UCHAR bval;
 
-    pci_write_config_byte(pdev, 0x80, 0x80);
+    PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x80);
     udelay(160);
-    pci_write_config_byte(pdev, 0x80, 0x40);
+    PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x40);
     udelay(160);
-    pci_read_config_byte(pdev, 0x00, &bval);
+    PCI_READ_CONFIG_BYTE(PDEV, 0x00, &bval);
     if(bval == 0x22)
 	return(1);
     else
@@ -1254,8 +1737,7 @@
 }
 
 
-USHORT
-EEpromGetData1( struct pci_dev *pdev )
+static USHORT __init dc390_EEpromGetData1( PDEVDECL )
 {
     UCHAR i;
     UCHAR carryFlag;
@@ -1265,67 +1747,59 @@
     for(i=0; i<16; i++)
     {
 	wval <<= 1;
-	carryFlag = DC390_EEpromInDO(pdev);
+	carryFlag = dc390_EEpromInDO(PDEV);
 	wval |= carryFlag;
     }
     return(wval);
 }
 
 
-void
-DC390_Prepare( struct pci_dev *pdev, PUCHAR regval, UCHAR EEpromCmd )
+static void __init dc390_Prepare( PDEVDECL, PUCHAR regval, UCHAR EEpromCmd )
 {
     UCHAR i,j;
-    USHORT carryFlag;
+    UCHAR carryFlag;
 
     carryFlag = 1;
     j = 0x80;
     for(i=0; i<9; i++)
     {
-	DC390_EEpromOutDI(pdev,regval,carryFlag);
+	dc390_EEpromOutDI(PDEV,regval,carryFlag);
 	carryFlag = (EEpromCmd & j) ? 1 : 0;
 	j >>= 1;
     }
 }
 
 
-void
-DC390_ReadEEprom( struct pci_dev *pdev, int index )
+static void __init dc390_ReadEEprom( PDEVDECL, PUSHORT ptr)
 {
     UCHAR   regval,cmd;
-    PUSHORT ptr;
-    USHORT  i;
+    UCHAR   i;
 
-    ptr = (PUSHORT) &eepromBuf[index][0];
     cmd = EEPROM_READ;
     for(i=0; i<0x40; i++)
     {
-	DC390_EnDisableCE(ENABLE_CE, pdev, &regval);
-	DC390_Prepare(pdev, &regval, cmd);
-	*ptr = EEpromGetData1(pdev);
-	ptr++;
-	cmd++;
-	DC390_EnDisableCE(DISABLE_CE, pdev, &regval);
+	dc390_EnDisableCE(ENABLE_CE, PDEV, &regval);
+	dc390_Prepare(PDEV, &regval, cmd++);
+	*ptr++ = dc390_EEpromGetData1(PDEV);
+	dc390_EnDisableCE(DISABLE_CE, PDEV, &regval);
     }
 }
 
 
-USHORT
-DC390_CheckEEpromCheckSum( struct pci_dev *pdev, int index )
+static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index )
 {
-    USHORT wval, rc, *ptr;
     UCHAR  i;
+    char  EEbuf[128];
+    USHORT wval, *ptr = (PUSHORT)EEbuf;
 
-    DC390_ReadEEprom( pdev, index );
+    dc390_ReadEEprom( PDEV, ptr );
+    memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID);
+    memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], 
+	    &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID);
     wval = 0;
-    ptr = (PUSHORT) &eepromBuf[index][0];
-    for(i=0; i<128 ;i+=2, ptr++)
+    for(i=0; i<0x40; i++, ptr++)
 	wval += *ptr;
-    if( wval == 0x1234 )
-	rc = 0;
-    else
-	rc = -1;
-    return( rc );
+    return (wval == 0x1234 ? 0 : 1);
 }
 
 
@@ -1338,71 +1812,95 @@
  *
  * Preconditions : when this function is called, the chip_type
  *	field of the pACB structure MUST have been set.
+ *
+ * Note: written in capitals, because the locking is only done here,
+ *	not in DC390_detect, called from outside 
  ***********************************************************************/
 
-__initfunc(static int
-DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, int index))
+static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, int index)
 {
     PSH   psh;
     PACB  pACB;
-
-    if( !DC390_CheckEEpromCheckSum( pdev, index ) )
+    DC390_AFLAGS
+    
+    if (dc390_CheckEEpromCheckSum (PDEV, index))
     {
-	psh = scsi_register( psht, sizeof(DC390_ACB) );
-	if( !psh )
-	    return( -1 );
-	if( !pSH_start )
-	{
-	    pSH_start = psh;
-	    pSH_current = psh;
-	}
-	else
-	{
-	    pSH_current->next = psh;
-	    pSH_current = psh;
-	}
+#ifdef CONFIG_SCSI_DC390T_NOGENSUPP
+	printk (KERN_ERR "DC390_init: No EEPROM found!\n");
+	return( -1 );
+#else
+	int period;
+	printk (KERN_INFO "DC390_init: No EEPROM found!\n");
+	printk (KERN_INFO "DC390_init: Trying default EEPROM settings:\n");
+	dc390_checkparams ();
+	period = dc390_clock_period1[tmscsim[1]];
+	printk (KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz),"
+		" DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i)\n", tmscsim[0], tmscsim[1],
+		40 / period, ((40%period)*10 + period/2) / period,
+		(UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]));
+	dc390_EEpromDefaults (index);
+#endif
+    };
+   
+    psh = scsi_register( psht, sizeof(DC390_ACB) );
+    if( !psh ) return( -1 );
+	
+    pACB = (PACB) psh->hostdata;
+    DC390_LOCK_INIT;
+    DC390_LOCK_ACB;
 
-#ifdef DC390_DEBUG0
-	printk("DC390: pSH = %8x,", (UINT) psh);
-	printk("DC390: Index %02i,", index);
+#if 0
+    if( !dc390_pSH_start )
+    {
+        dc390_pSH_start = psh;
+        dc390_pSH_current = psh;
+    }
+    else
+    {
+        dc390_pSH_current->next = psh;
+        dc390_pSH_current = psh;
+    }
 #endif
 
-	DC390_initACB( psh, io_port, Irq, index );
-	if( !DC390_initAdapter( psh, io_port, Irq, index ) )
-	{
-	    pACB = (PACB) psh->hostdata;
-	    if( !pACB_start )
-	    {
-		pACB_start = pACB;
-		pACB_current = pACB;
-		pACB->pNextACB = (PACB) -1;
-	    }
-	    else
-	    {
-		pACB_current->pNextACB = pACB;
-		pACB_current = pACB;
-		pACB->pNextACB = (PACB)  -1;
-	    }
+    DEBUG0(printk("DC390: pSH = %8x,", (UINT) psh);)
+    DEBUG0(printk("DC390: Index %02i,", index);)
 
-#ifdef DC390_DEBUG0
-	printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
-	      (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
-	printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
-	      sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
-#endif
+    dc390_initACB( psh, io_port, Irq, index );
+    PDEVSET;
+
+    DC390_read8_ (INT_Status, io_port);		/* Reset Pending INT */
 
+    if( !dc390_initAdapter( psh, io_port, Irq, index ) )
+    {
+	pACB = (PACB) psh->hostdata;
+	if( !dc390_pACB_start )
+	{
+	    dc390_pACB_start = pACB;
+	    dc390_pACB_current = pACB;
+	    pACB->pNextACB = (PACB) -1;
 	}
 	else
 	{
-	    pSH_start = NULL;
-	    scsi_unregister( psh );
-	    return( -1 );
+	    dc390_pACB_current->pNextACB = pACB;
+	    dc390_pACB_current = pACB;
+	    pACB->pNextACB = (PACB)  -1;
 	}
-	return( 0 );
+        
+	DEBUG0(printk("DC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\
+		(UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array);)
+	DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\
+		sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );)
+
+	DC390_read8_ (INT_Status, io_port);		/* Reset Pending INT */
+
+	DC390_UNLOCK_ACB;
+        return (0);
     }
     else
     {
-	printk("DC390_init: EEPROM reading error!\n");
+	//dc390_pSH_start = NULL;
+	scsi_unregister( psh );
+	DC390_UNLOCK_ACB;
 	return( -1 );
     }
 }
@@ -1421,54 +1919,437 @@
  *
  ***********************************************************************/
 
-__initfunc(int
-DC390_detect(Scsi_Host_Template *psht))
+#ifndef NEW_PCI
+/* Acc. to PCI 2.1 spec it's up to the driver to enable Bus mastering:
+ * We use pci_set_master () for 2.1.x and this func for 2.0.x:	*/
+static void __init dc390_set_master (PDEVDECL)
+{
+	USHORT cmd;
+	UCHAR lat;
+	
+	PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd);
+	
+        if (! (cmd & PCI_COMMAND_MASTER)) {	
+		printk("PCI: Enabling bus mastering for device %02x:%02x\n",
+		       PCI_BUS_DEV);
+		cmd |= PCI_COMMAND_MASTER;
+		PCI_WRITE_CONFIG_WORD(PDEV, PCI_COMMAND, cmd);
+	}
+	PCI_READ_CONFIG_BYTE (PDEV, PCI_LATENCY_TIMER, &lat);
+	if (lat < 16 /* || lat == 255 */) {
+		printk("PCI: Setting latency timer of device %02x:%02x from %i to 64\n",
+		       PCI_BUS_DEV, lat);
+		PCI_WRITE_CONFIG_BYTE(PDEV, PCI_LATENCY_TIMER, 64);
+	}
+	
+};
+#endif /* ! NEW_PCI */
+
+static void __init dc390_set_pci_cfg (PDEVDECL)
+{
+	USHORT cmd;
+	PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
+	PCI_WRITE_CONFIG_WORD (PDEV, PCI_COMMAND, cmd);
+	PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));
+};
+	
+
+int __init DC390_detect (Scsi_Host_Template *psht)
 {
-    struct pci_dev *pdev = NULL;
-    UINT    irq;
+    PDEVDECL0;
+    UCHAR   irq;
     UINT    io_port;
-    USHORT  adaptCnt = 0;	/* Number of boards detected */
+    UCHAR   adaptCnt = 0;	/* Number of boards detected */
+    DC390_IFLAGS DC390_DFLAGS
 
-    psht->proc_dir = &proc_scsi_tmscsim;
+    DC390_LOCK_DRV;
+    //dc390_pSHT_start = psht;
+    dc390_pACB_start = NULL;
 
-    InitialTime = 1;
-    pSHT_start = psht;
-    pACB_start = NULL;
-
-    if ( pci_present() )
-	while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974, pdev)))
+    if ( PCI_PRESENT )
+	while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974))
 	{
-	    io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
-	    irq = pdev->irq;
-#ifdef DC390_DEBUG0
-	    printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
-#endif
-	    if( !DC390_init(psht, io_port, irq, pdev, adaptCnt))
+	    DC390_LOCK_IO;		/* Remove this when going to new eh */
+	    PCI_GET_IO_AND_IRQ;
+	    DEBUG0(printk(KERN_DEBUG "DC390(%i): IO_PORT=%04x,IRQ=%x\n", adaptCnt, (UINT) io_port, irq);)
+
+	    if( !DC390_init(psht, io_port, irq, PDEV, adaptCnt))
+	    {
+		PCI_SET_MASTER;
+		dc390_set_pci_cfg (PDEV);
 		adaptCnt++;
+	    };
+	    DC390_UNLOCK_IO;		/* Remove when going to new eh */
 	}
-
-    InitialTime = 0;
-    adapterCnt = adaptCnt;
+    else
+	printk (KERN_ERR "DC390: No PCI BIOS found!\n");
+   
+    if (adaptCnt)
+	psht->proc_dir = &DC390_proc_scsi_tmscsim;
+
+    printk(KERN_INFO "DC390: %i adapters found\n", adaptCnt);
+    dc390_adapterCnt = adaptCnt;
+    DC390_UNLOCK_DRV;
     return( adaptCnt );
 }
 
 
+static void dc390_inquiry_done (Scsi_Cmnd* cmd)
+{
+   printk (KERN_INFO "DC390: INQUIRY (ID %02x LUN %02x) returned %08x\n",
+	   cmd->target, cmd->lun, cmd->result);
+   if (cmd->result)
+   {
+	PACB pACB = (PACB)cmd->host->hostdata;
+	PDCB pDCB = dc390_findDCB (pACB, cmd);
+	printk ("DC390: Unsetting DsCn, Sync and TagQ!\n");
+	if (pDCB)
+	{
+		pDCB->DevMode &= ~(SYNC_NEGO_ | TAG_QUEUEING_ | EN_DISCONNECT_ );
+		dc390_updateDCB (pACB, pDCB);
+	};
+   };
+   kfree (cmd->buffer);
+   kfree (cmd);
+};
+
+void dc390_inquiry (PACB pACB, PDCB pDCB)
+{
+   char* buffer;
+   Scsi_Cmnd* cmd;
+   buffer = kmalloc (256, GFP_ATOMIC);
+   cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC);
+
+   memset (buffer, 0, 256);
+   memset (cmd, 0, sizeof(Scsi_Cmnd));
+   cmd->cmnd[0] = INQUIRY;
+   cmd->cmnd[1] = (pDCB->UnitSCSILUN << 5) & 0xe0;
+   cmd->cmnd[4] = 0xff;
+   
+   cmd->cmd_len = 6; cmd->old_cmd_len = 6;
+   cmd->host = pACB->pScsiHost;
+   cmd->target = pDCB->UnitSCSIID;
+   cmd->lun = pDCB->UnitSCSILUN; 
+   cmd->serial_number = 1;
+   cmd->bufflen = 128;
+   cmd->buffer = buffer;
+   cmd->request_bufflen = 128;
+   cmd->request_buffer = &buffer[128];
+   cmd->done = dc390_inquiry_done;
+   cmd->scsi_done = dc390_inquiry_done;
+   cmd->timeout_per_command = HZ;
+
+   cmd->request.rq_status = RQ_SCSI_BUSY;
+
+   printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n",
+	   pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+   DC390_queue_command (cmd, dc390_inquiry_done);
+};
+
 /********************************************************************
- * Function: tmscsim_set_info()
- *
- * Purpose: Set adapter info (!)
+ * Function: dc390_set_info()
  *
- * Not yet implemented
+ * Purpose: Change adapter config
  *
+ * Strings are parsed similar to the output of tmscsim_proc_info ()
+ * '-' means no change
  *******************************************************************/
 
-int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+static int dc390_scanf (char** p1, char** p2, int* var)
 {
-  return(-ENOSYS);  /* Currently this is a no-op */
-}
+   *p2 = *p1;
+   *var = simple_strtoul (*p2, p1, 10);
+   if (*p2 == *p1) return -1;
+   *p1 = strtok (0, " \t\n:=,;.");
+   return 0;
+};
+
+#define SCANF(p1, p2, var, min, max)		\
+if (dc390_scanf (&p1, &p2, &var)) goto einv;	\
+else if (var<min || var>max) goto einv2
+
+static int dc390_yesno (char** p, char* var, char bmask)
+{
+   switch (**p)
+     {
+      case 'Y': *var |= bmask; break;
+      case 'N': *var &= ~bmask; break;
+      case '-': break;
+      default: return -1;
+     }
+   *p = strtok (0, " \t\n:=,;");
+   return 0;
+};
+
+#define YESNO(p, var, bmask)			\
+if (dc390_yesno (&p, &var, bmask)) goto einv;	\
+else dc390_updateDCB (pACB, pDCB);		\
+if (!p) goto ok
+
+static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign)
+{
+   int dum;
+   if (! memcmp (*p1, txt, strlen(txt)))
+     {
+	*p2 = strtok (0, " \t\n:=,;");
+	if (!*p2) return -1;
+	dum = simple_strtoul (*p2, p1, 10);
+	if (*p2 == *p1) return -1;
+	if (dum >= 0 && dum <= max) 
+	  { *var = (dum * 100) / scale; }
+	else return -2;
+	*p1 = strtok (0, " \t\n:=,;");
+	if (*ign && *p1 && strlen(*p1) >= strlen(ign) && 
+	    !(memcmp (*p1, ign, strlen(ign)))) 
+		*p1 = strtok (0, " \t\n:=,;");
+
+     }
+   return 0;
+};
+
+#define SEARCH(p1, p2, var, txt, max)						\
+if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2;	\
+else if (!p1) goto ok2
+
+#define SEARCH2(p1, p2, var, txt, max, scale)					\
+if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; 		\
+else if (!p1) goto ok2
+
+#define SEARCH3(p1, p2, var, txt, max, scale, ign)				\
+if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2;		\
+else if (!p1) goto ok2
+
+
+#ifdef DC390_PARSEDEBUG
+static char _prstr[256];
+char* prstr (char* p, char* e)
+{
+   char* c = _prstr;
+   while (p < e)
+     if (*p == 0) { *c++ = ':'; p++; }
+     else if (*p == 10) { *c++ = '\\'; *c++ = 'n'; p++; }
+     else *c++ = *p++;
+   *c = 0;
+   return _prstr;
+};
+#endif
+
+int dc390_set_info (char *buffer, int length, PACB pACB)
+{
+  char *pos = buffer, *p0 = buffer;
+  char needs_inquiry = 0; 
+  int dum = 0;
+  char dev;
+  PDCB pDCB = pACB->pLinkDCB;
+  DC390_IFLAGS
+  DC390_AFLAGS 
+  pos[length] = 0;
+
+  DC390_LOCK_IO;
+  DC390_LOCK_ACB;
+  /* UPPERCASE */ 
+  /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */
+  while (*pos) 
+    { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; };
+  
+  /* We should protect __strtok ! */
+  /* spin_lock (strtok_lock); */
+
+  /* Remove WS */
+  pos = strtok (buffer, " \t:\n=,;");
+  if (!pos) goto ok;
+   
+ next:
+  if (!memcmp (pos, "RESET", 5)) goto reset;
+  else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry;
+  else if (!memcmp (pos, "REMOVE", 6)) goto remove;
+  
+  if (isdigit (*pos))
+    {
+      /* Device config line */
+      int dev, id, lun; char* pdec;
+      char olddevmode;
+      
+      SCANF (pos, p0, dev, 0, pACB->DCBCnt-1);
+      if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
+      if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+      if (!pos) goto einv;
+      
+      PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));)
+      pDCB = pACB->pLinkDCB;
+      for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+      /* Sanity Check */
+      if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun) 
+	 {
+	    printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n",
+		    dev, id, lun);
+	    goto einv2;
+	 };
+
+      olddevmode = pDCB->DevMode;
+      YESNO (pos, pDCB->DevMode, PARITY_CHK_);
+      needs_inquiry++;
+      YESNO (pos, pDCB->DevMode, SYNC_NEGO_);
+      if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--;
+      needs_inquiry++;
+      YESNO (pos, pDCB->DevMode, EN_DISCONNECT_);
+      if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--;
+      YESNO (pos, pDCB->DevMode, SEND_START_);
+      needs_inquiry++;
+      YESNO (pos, pDCB->DevMode, TAG_QUEUEING_);
+      if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
+      YESNO (pos, pDCB->SyncMode, EN_ATN_STOP);
+      
+      dc390_updateDCB (pACB, pDCB);
+      if (!pos) goto ok;
+       
+      olddevmode = pDCB->NegoPeriod;
+      /* Look for decimal point (Speed) */
+      pdec = pos; 
+      while (pdec++ < &buffer[length]) if (*pdec == '.') break;
+      /* NegoPeriod */
+      if (*pos != '-')
+	{
+	  SCANF (pos, p0, dum, 76, 800); 
+	  pDCB->NegoPeriod = dum >> 2;
+	  if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
+	  if (!pos) goto ok;
+	  if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;.");
+	}
+      else pos = strtok (0, " \t\n:=,;.");
+      if (!pos) goto ok;
+      
+      /* Speed: NegoPeriod */
+      if (*pos != '-')
+	{
+	  SCANF (pos, p0, dum, 1, 13); 
+	  pDCB->NegoPeriod = (1000/dum) >> 2;
+	  if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++;
+	  if (!pos) goto ok;
+	  /* decimal */
+	  if (pos-1 == pdec)
+	     {
+		int dumold = dum;
+		dum = simple_strtoul (pos, &p0, 10) * 10;
+		for (; p0-pos > 1; p0--) dum /= 10;
+		pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
+		if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
+		if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
+		pos = strtok (0, " \t\n:=,;");
+		if (!pos) goto ok;
+	     };
+	  if (*pos == 'M') pos = strtok (0, " \t\n:=,;");
+	}
+      else pos = strtok (0, " \t\n:=,;");
+      /* dc390_updateDCB (pACB, pDCB); */
+      if (!pos) goto ok;
+
+      olddevmode = pDCB->SyncOffset;
+      /* SyncOffs */
+      if (*pos != '-')
+	{
+	  SCANF (pos, p0, dum, 0, 0x0f); 
+	  pDCB->SyncOffset = dum;
+	  if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
+	}
+      else pos = strtok (0, " \t\n:=,;");
+      dc390_updateDCB (pACB, pDCB);
+    }
+  else
+    {
+      char* p1 = pos; UCHAR dum;
+      PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));)
+      dum = GLITCH_TO_NS (pACB->glitch_cfg);
+      /* Adapter setting */
+      SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); 
+      SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); 
+      SEARCH (pos, p0, pACB->pScsiHost->this_id, "ADAPTERID", 7); 
+      SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
+      SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
+      SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
+      SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
+    ok2:
+      pACB->glitch_cfg = NS_TO_GLITCH (dum);
+      if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
+      dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++;
+      pACB->TagMaxNum &= (1 << --dum);
+      if (pos == p1) goto einv;
+      dc390_updateDCBs (pACB);
+    }
+  if (pos) goto next;
+      
+ ok:
+  /* spin_unlock (strtok_lock); */
+  DC390_UNLOCK_ACB;
+  if (needs_inquiry) 
+     { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); };
+  DC390_UNLOCK_IO;
+  return (length);
+
+ einv2:
+  pos = p0;
+ einv:
+  /* spin_unlock (strtok_lock); */
+  DC390_UNLOCK_ACB;
+  DC390_UNLOCK_IO;
+  printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
+  return (-EINVAL);
+   
+ reset:
+     {
+	Scsi_Cmnd cmd; cmd.host = pACB->pScsiHost;
+	printk (KERN_WARNING "DC390: Driver reset requested!\n");
+	DC390_UNLOCK_ACB;
+	DC390_reset (&cmd, 0);
+	DC390_UNLOCK_IO;
+     };
+  return (length);
+  
+ inquiry:
+     {
+	pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+	dev = simple_strtoul (pos, &p0, 10);
+	if (dev >= pACB->DCBCnt) goto einv_dev;
+	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+	printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n",
+		dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+	DC390_UNLOCK_ACB;
+	dc390_inquiry (pACB, pDCB);
+	DC390_UNLOCK_IO;
+     };
+   return (length);
+
+ remove:
+     {
+	pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+	dev = simple_strtoul (pos, &p0, 10);
+	if (dev >= pACB->DCBCnt) goto einv_dev;
+	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+	printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n",
+		dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+	dc390_remove_dev (pACB, pDCB);
+	DC390_UNLOCK_ACB;
+	DC390_UNLOCK_IO;
+     };
+   return (length);
+
+ einv_dev:
+   printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n", 
+	   dev, pACB->DCBCnt - 1);
+   DC390_UNLOCK_ACB;
+   DC390_UNLOCK_IO;
+   return (-EINVAL);
+	     
+	     
+}
+
+#undef SEARCH
+#undef YESNO
+#undef SCANF
 
 /********************************************************************
- * Function: tmscsim_proc_info(char* buffer, char **start,
+ * Function: DC390_proc_info(char* buffer, char **start,
  *			     off_t offset, int length, int hostno, int inout)
  *
  * Purpose: return SCSI Adapter/Device Info
@@ -1491,79 +2372,86 @@
 #undef SPRINTF
 #define SPRINTF(args...) pos += sprintf(pos, ## args)
 
-#define YESNO(YN)\
-if (YN) SPRINTF(" Yes ");\
-else SPRINTF(" No  ")
+#define YESNO(YN)		\
+ if (YN) SPRINTF(" Yes ");	\
+ else SPRINTF(" No  ")
+
 
-int tmscsim_proc_info(char *buffer, char **start,
-		      off_t offset, int length, int hostno, int inout)
+int DC390_proc_info (char *buffer, char **start,
+		     off_t offset, int length, int hostno, int inout)
 {
   int dev, spd, spd1;
   char *pos = buffer;
   PSH shpnt;
-  PACB acbpnt;
-  PDCB dcbpnt;
-  unsigned long flags;
-/*  Scsi_Cmnd *ptr; */
+  PACB pACB;
+  PDCB pDCB;
+  DC390_AFLAGS
 
-  acbpnt = pACB_start;
+  pACB = dc390_pACB_start;
 
-  while(acbpnt != (PACB)-1)
+  while(pACB != (PACB)-1)
      {
-	shpnt = acbpnt->pScsiHost;
+	shpnt = pACB->pScsiHost;
 	if (shpnt->host_no == hostno) break;
-	acbpnt = acbpnt->pNextACB;
+	pACB = pACB->pNextACB;
      }
 
-  if (acbpnt == (PACB)-1) return(-ESRCH);
+  if (pACB == (PACB)-1) return(-ESRCH);
   if(!shpnt) return(-ESRCH);
 
   if(inout) /* Has data been written to the file ? */
-    return(tmscsim_set_info(buffer, length, shpnt));
+      return dc390_set_info(buffer, length, pACB);
+   
+  SPRINTF("Tekram DC390/AM53C974 PCI SCSI Host Adapter, ");
+  SPRINTF("Driver Version %s\n", DC390_VERSION);
 
-  SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
-  SPRINTF("Driver Version 1.12, 1998/02/25\n");
-
-  save_flags(flags);
-  cli();
+  DC390_LOCK_ACB;
 
   SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
-  SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex);
-  SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase);
-  SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel);
-
-  SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun);
-  SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN);
-
-  SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status);
+  SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex);
+  SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase);
+  SPRINTF("IRQLevel 0x%02x\n", pACB->IRQLevel);
+
+  SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun);
+  SPRINTF("AdapterID %i, SelTimeout %i ms\n", 
+	  shpnt->this_id, (pACB->sel_timeout*164)/100);
+
+  SPRINTF("TagMaxNum %i, Status %i, ACBFlag %i, GlitchEater %i ns\n",
+	  pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12);
+
+  SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %li, Out of SRB conds %li\n",
+	  pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB);
+  SPRINTF("            Lost arbitrations %li\n", pACB->SelLost);
+   
+  SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt);
 
-  SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt);
+  SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n");
 
-  SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n");
-
-  dcbpnt = acbpnt->pLinkDCB;
-  for (dev = 0; dev < acbpnt->DeviceCnt; dev++)
+  pDCB = pACB->pLinkDCB;
+  for (dev = 0; dev < pACB->DCBCnt; dev++)
      {
-      SPRINTF("%02i %02i  %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN);
-      YESNO(dcbpnt->DevMode & PARITY_CHK_);
-      YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE);
-      YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
-      YESNO(dcbpnt->DevMode & SEND_START_);
-      YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING);
-      SPRINTF("  %03i ns ", (dcbpnt->NegoPeriod) << 2);
-      if (dcbpnt->SyncOffset & 0x0f)
+      SPRINTF("%02i  %02i  %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+      YESNO(pDCB->DevMode & PARITY_CHK_);
+      YESNO(pDCB->SyncMode & SYNC_NEGO_DONE);
+      YESNO(pDCB->DevMode & EN_DISCONNECT_);
+      //YESNO(pDCB->SyncMode & EN_ATN_STOP);
+      YESNO(pDCB->DevMode & SEND_START_);
+      YESNO(pDCB->SyncMode & EN_TAG_QUEUEING);
+      YESNO(pDCB->SyncMode & EN_ATN_STOP);
+      if (pDCB->SyncOffset & 0x0f)
       {
-	 spd = 1000/(dcbpnt->NegoPeriod <<2);
-	 spd1 = 1000%(dcbpnt->NegoPeriod <<2);
-	 spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2);
-	 SPRINTF("   %2i.%1i M      %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f));
+	 int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++;
+	 SPRINTF("  %03i ns ", (pDCB->NegoPeriod) << 2);
+	 spd = 40/(sp); spd1 = 40%(sp);
+	 spd1 = (spd1 * 10 + sp/2) / (sp);
+	 SPRINTF("   %2i.%1i M      %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f));
       }
-      else SPRINTF("\n");
+      else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2);
       /* Add more info ...*/
-      dcbpnt = dcbpnt->pNextDCB;
+      pDCB = pDCB->pNextDCB;
      }
 
-  restore_flags(flags);
+  DC390_UNLOCK_ACB;
   *start = buffer + offset;
 
   if (pos - buffer < offset)
@@ -1574,75 +2462,92 @@
     return length;
 }
 
+#undef YESNO
+#undef SPRINTF
 
 #ifdef MODULE
 
 /***********************************************************************
- * Function : static int DC390_shutdown (struct Scsi_Host *host)
+ * Function : static int dc390_shutdown (struct Scsi_Host *host)
  *
  * Purpose : does a clean (we hope) shutdown of the SCSI chip.
  *	     Use prior to dumping core, unloading the driver, etc.
  *
  * Returns : 0 on success
  ***********************************************************************/
-static int
-DC390_shutdown (struct Scsi_Host *host)
+static int dc390_shutdown (struct Scsi_Host *host)
 {
     UCHAR    bval;
-    USHORT   ioport;
-    unsigned long flags;
     PACB pACB = (PACB)(host->hostdata);
-
-    ioport = (unsigned int) pACB->IOPortBase;
-
-    save_flags (flags);
-    cli();
-
+   
 /*  pACB->soft_reset(host); */
 
-#ifdef DC390_DEBUG0
-    printk("DC390: shutdown,");
-#endif
+    printk(KERN_INFO "DC390: shutdown\n");
 
-    bval = inb(ioport+CtrlReg1);
+    pACB->ACBFlag = RESET_DONE;
+    bval = DC390_read8 (CtrlReg1);
     bval |= DIS_INT_ON_SCSI_RST;
-    outb(bval,ioport+CtrlReg1);  /* disable interrupt */
-    DC390_ResetSCSIBus( pACB );
+    DC390_write8 (CtrlReg1, bval);	/* disable interrupt */
+    if (pACB->Gmode2 & RST_SCSI_BUS)
+		dc390_ResetSCSIBus (pACB);
 
-    restore_flags (flags);
     return( 0 );
 }
 
+void dc390_freeDCBs (struct Scsi_Host *host)
+{
+    PDCB pDCB, nDCB;
+    PACB pACB = (PACB)(host->hostdata);
+    
+    pDCB = pACB->pLinkDCB;
+    if (!pDCB) return;
+    do
+    {
+	nDCB = pDCB->pNextDCB;
+	DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): 0x%08x\n",\
+		pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
+	kfree (pDCB);
+	pDCB = nDCB;
+    } while (pDCB && pDCB != pACB->pLinkDCB);
+
+};
 
 int DC390_release(struct Scsi_Host *host)
 {
-    int irq_count;
-    struct Scsi_Host *tmp;
+    int irq_count; 
+    PACB pACB;
+    DC390_AFLAGS DC390_IFLAGS
+#if USE_SPINLOCKS > 1
+    PACB pACB = (PACB)(host->hostdata);
+#endif
+
+    DC390_LOCK_IO;
+    DC390_LOCK_ACB;
 
-    DC390_shutdown (host);
+    dc390_shutdown (host);
 
     if (host->irq != IRQ_NONE)
     {
-	for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next)
+	for (irq_count = 0, pACB = dc390_pACB_start; 
+	     pACB && pACB != (PACB)-1; pACB = pACB->pNextACB)
 	{
-	    if ( tmp->irq == host->irq )
+	    if ( pACB->IRQLevel == host->irq )
 		++irq_count;
 	}
 	if (irq_count == 1)
 	 {
-#ifdef DC390_DEBUG0
-	    printk("DC390: Free IRQ %i.",host->irq);
-#endif
+	    DEBUG0(printk(KERN_DEBUG "DC390: Free IRQ %i\n",host->irq);)
 	    free_irq(host->irq,NULL);
 	 }
     }
 
     release_region(host->io_port,host->n_io_port);
-
+    dc390_freeDCBs (host);
+    DC390_UNLOCK_ACB;
+    DC390_UNLOCK_IO;
     return( 1 );
 }
 
 Scsi_Host_Template driver_template = DC390_T;
 #include "scsi_module.c"
 #endif /* def MODULE */
-
diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h
--- v2.1.126/linux/drivers/scsi/tmscsim.h	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/tmscsim.h	Tue Oct 27 10:10:08 1998
@@ -3,12 +3,23 @@
 ;*		    TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter  *
 ;*		    Device Driver				       *
 ;***********************************************************************/
+/* $Id: tmscsim.h,v 2.1 1998/10/14 10:31:48 garloff Exp $ */
 
 #ifndef _TMSCSIM_H
 #define _TMSCSIM_H
 
 #define IRQ_NONE 255
 
+#define MAX_ADAPTER_NUM 	4
+#define MAX_SG_LIST_BUF 	16
+#define MAX_CMD_PER_LUN 	8
+#define MAX_CMD_QUEUE		2*MAX_CMD_PER_LUN+1	
+#define MAX_SCSI_ID		8
+#define MAX_SRB_CNT		MAX_CMD_QUEUE+1	/* Max number of started commands */
+#define END_SCAN		2
+
+#define SEL_TIMEOUT		153	/* 250 ms selection timeout (@ 40 MHz) */
+
 typedef unsigned char	UCHAR;
 typedef unsigned short	USHORT;
 typedef unsigned long	ULONG;
@@ -54,17 +65,6 @@
 } SGentry1, *PSGE;
 
 
-#define MAX_ADAPTER_NUM 	4
-#define MAX_DEVICES		10
-#define MAX_SG_LIST_BUF 	16
-#define MAX_CMD_QUEUE		20
-#define MAX_CMD_PER_LUN 	8
-#define MAX_SCSI_ID		8
-#define MAX_SRB_CNT		MAX_CMD_QUEUE+4
-#define END_SCAN		2
-
-#define SEL_TIMEOUT		153	/* 250 ms selection timeout (@ 40 MHz) */
-
 /*
 ;-----------------------------------------------------------------------
 ; SCSI Request Block
@@ -79,40 +79,46 @@
 PSCSICMD	pcmd;
 PSGL		pSegmentList;
 
-ULONG		PhysSRB;
+ULONG		Segment0[2];
+ULONG		Segment1[2];
+
+/* 0x2c:*/
 ULONG		TotalXferredLen;
-ULONG		SGPhysAddr;	/*;a segment starting address */
+ULONG		SGBusAddr;	/*;a segment starting address as seen by AM53C974A*/
 ULONG		SGToBeXferLen;	/*; to be xfer length */
+ULONG		SRBState;
+
+/* 0x3c: */
+UCHAR		MsgInBuf[6];
+UCHAR		MsgOutBuf[6];
 
+/* 0x48: */
 SGL		Segmentx;	/* make a one entry of S/G list table */
 
 PUCHAR		pMsgPtr;
-USHORT		SRBState;
-USHORT		Revxx2; 	/* ??? */
 
-UCHAR		MsgInBuf[6];
-UCHAR		MsgOutBuf[6];
+UCHAR		ScsiCmdLen;
+UCHAR		ScsiPhase;
 
 UCHAR		AdaptStatus;
 UCHAR		TargetStatus;
+
+/* 0x5c: */
 UCHAR		MsgCnt;
 UCHAR		EndMessage;
+UCHAR		RetryCnt;
+UCHAR		SRBFlag;	/*; b0-AutoReqSense,b6-Read,b7-write */
+				/*; b4-settimeout,b5-Residual valid */
 UCHAR		TagNumber;
 UCHAR		SGcount;
 UCHAR		SGIndex;
-UCHAR		IORBFlag;	/*;81h-Reset, 2-retry */
-
 UCHAR		SRBStatus;
-UCHAR		RetryCnt;
-UCHAR		SRBFlag;	/*; b0-AutoReqSense,b6-Read,b7-write */
-				/*; b4-settimeout,b5-Residual valid */
-UCHAR		ScsiCmdLen;
-UCHAR		ScsiPhase;
-UCHAR		Reserved3[3];	/*;for dword alignment */
-ULONG		Segment0[2];
-ULONG		Segment1[2];
+  //UCHAR		IORBFlag;	/*;81h-Reset, 2-retry */
+
+/* 0x64: */
 };
 
+
 typedef  struct  _SRB	 DC390_SRB, *PSRB;
 
 /*
@@ -129,42 +135,44 @@
 PSCSICMD	pQIORBtail;
 PSCSICMD	AboIORBhead;
 PSCSICMD	AboIORBtail;
-USHORT		QIORBCnt;
-USHORT		AboIORBcnt;
+ULONG		QIORBCnt;
+ULONG		AboIORBcnt;
 
+/* 0x20: */
 PSRB		pWaitingSRB;
 PSRB		pWaitLast;
 PSRB		pGoingSRB;
 PSRB		pGoingLast;
 PSRB		pActiveSRB;
-USHORT		GoingSRBCnt;
-USHORT		WaitSRBCnt;	/* ??? */
+UCHAR		GoingSRBCnt;
+UCHAR		WaitSRBCnt;	/* ??? */
+UCHAR		DevType;
+UCHAR		MaxCommand;
 
+/* 0x38: */
 ULONG		TagMask;
 
-USHORT		MaxCommand;
-USHORT		AdaptIndex;	/*; UnitInfo struc start */
-USHORT		UnitIndex;	/*; nth Unit on this card */
 UCHAR		UnitSCSIID;	/*; SCSI Target ID  (SCSI Only) */
 UCHAR		UnitSCSILUN;	/*; SCSI Log.  Unit (SCSI Only) */
-
+UCHAR		DevMode;
 UCHAR		IdentifyMsg;
+
 UCHAR		CtrlR1;
 UCHAR		CtrlR3;
 UCHAR		CtrlR4;
 
-UCHAR		InqDataBuf[8];
-UCHAR		CapacityBuf[8];
-UCHAR		DevMode;
-UCHAR		AdpMode;
+UCHAR		DCBFlag;
+
+/* 0x44: */
 UCHAR		SyncMode;	/*; 0:async mode */
 UCHAR		NegoPeriod;	/*;for nego. */
 UCHAR		SyncPeriod;	/*;for reg. */
 UCHAR		SyncOffset;	/*;for reg. and nego.(low nibble) */
-UCHAR		UnitCtrlFlag;
-UCHAR		DCBFlag;
-UCHAR		DevType;
-UCHAR		Reserved2[3];	/*;for dword alignment */
+
+/* 0x48:*/
+//UCHAR		InqDataBuf[8];
+//UCHAR		CapacityBuf[8];
+/* 0x58: */
 };
 
 typedef  struct  _DCB	 DC390_DCB, *PDCB;
@@ -175,40 +183,55 @@
 */
 struct	_ACB
 {
-ULONG		PhysACB;
 PSH		pScsiHost;
 struct _ACB	*pNextACB;
 USHORT		IOPortBase;
-USHORT		Revxx1; 	/* ??? */
+UCHAR		IRQLevel;
+UCHAR		status;
+
+UCHAR		SRBCount;
+UCHAR		AdapterIndex;	/*; nth Adapter this driver */
+UCHAR		DeviceCnt;
+UCHAR		DCBCnt;
+
+/* 0x10: */
+UCHAR		TagMaxNum;
+UCHAR		ACBFlag;
+UCHAR		Gmode2;
+UCHAR		scan_devices;
 
 PDCB		pLinkDCB;
+PDCB		pLastDCB;
 PDCB		pDCBRunRobin;
 PDCB		pActiveDCB;
-PDCB		pDCB_free;
 PSRB		pFreeSRB;
 PSRB		pTmpSRB;
-USHORT		SRBCount;
-USHORT		AdapterIndex;	/*; nth Adapter this driver */
-USHORT		max_id;
-USHORT		max_lun;
+
+/* 0x2c: */
 
 UCHAR		msgin123[4];
-UCHAR		status;
-UCHAR		AdaptSCSIID;	/*; Adapter SCSI Target ID */
-UCHAR		AdaptSCSILUN;	/*; Adapter SCSI LUN */
-UCHAR		DeviceCnt;
-UCHAR		IRQLevel;
-UCHAR		TagMaxNum;
-UCHAR		ACBFlag;
-UCHAR		Gmode2;
-UCHAR		LUNchk;
-UCHAR		scan_devices;
-UCHAR		HostID_Bit;
-UCHAR		Reserved1[1];	/*;for dword alignment */
 UCHAR		DCBmap[MAX_SCSI_ID];
-DC390_DCB	DCB_array[MAX_DEVICES]; 	/* +74h,  Len=3E8 */
-DC390_SRB	SRB_array[MAX_SRB_CNT]; 	/* +45Ch, Len=	*/
+
+#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0)
+spinlock_t	lock;
+#endif
+UCHAR		sel_timeout;
+UCHAR		glitch_cfg;
+
+UCHAR		reserved[2];	/* alignment */
+
+PDEVDECL1;			/* Pointer to PCI cfg. space */
+/* 0x44/0x40: */
+ULONG		Cmds;
+ULONG		CmdInQ;
+ULONG		CmdOutOfSRB;
+ULONG		SelLost;
+	
+/* 0x50/0x4c: */	
 DC390_SRB	TmpSRB;
+/* 0xb4/0xb0: */
+DC390_SRB	SRB_array[MAX_SRB_CNT]; 	/* 18 SRBs */
+/* 0x7bc/0x7b8: */
 };
 
 typedef  struct  _ACB	 DC390_ACB, *PACB;
@@ -278,14 +301,6 @@
 #define DO_SYNC_NEGO	BIT13
 #define SRB_UNEXPECT_RESEL BIT14
 
-/*;---ACBFlag */
-#define RESET_DEV	BIT0
-#define RESET_DETECT	BIT1
-#define RESET_DONE	BIT2
-
-/*;---DCBFlag */
-#define ABORT_DEV_	BIT0
-
 /*;---SRBstatus */
 #define SRB_OK		BIT0
 #define ABORTION	BIT1
@@ -294,6 +309,14 @@
 #define PARITY_ERROR	BIT4
 #define SRB_ERROR	BIT5
 
+/*;---ACBFlag */
+#define RESET_DEV	BIT0
+#define RESET_DETECT	BIT1
+#define RESET_DONE	BIT2
+
+/*;---DCBFlag */
+#define ABORT_DEV_	BIT0
+
 /*;---SRBFlag */
 #define DATAOUT 	BIT7
 #define DATAIN		BIT6
@@ -316,7 +339,7 @@
 #define H_BAD_CCB_OR_SG  0x1A
 #define H_ABORT 	 0x0FF
 
-/*; SCSI Status byte codes*/
+/*; SCSI Status byte codes*/ /* Twice the values defined in scsi/scsi.h */
 #define SCSI_STAT_GOOD		0x0	/*;  Good status */
 #define SCSI_STAT_CHECKCOND	0x02	/*;  SCSI Check Condition */
 #define SCSI_STAT_CONDMET	0x04	/*;  Condition Met */
@@ -335,9 +358,9 @@
 #define SYNC_DISABLE	0
 #define SYNC_ENABLE	BIT0
 #define SYNC_NEGO_DONE	BIT1
-#define WIDE_ENABLE	BIT2
-#define WIDE_NEGO_DONE	BIT3
-#define EN_TAG_QUEUING	BIT4
+#define WIDE_ENABLE	BIT2	/* Not used ;-) */
+#define WIDE_NEGO_DONE	BIT3	/* Not used ;-) */
+#define EN_TAG_QUEUEING	BIT4
 #define EN_ATN_STOP	BIT5
 
 #define SYNC_NEGO_OFFSET 15
@@ -352,7 +375,7 @@
 #define SCSI_MSG_OUT	6
 #define SCSI_MSG_IN	7
 
-/*;----SCSI MSG BYTE*/
+/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */
 #define MSG_COMPLETE		0x00
 #define MSG_EXTENDED		0x01
 #define MSG_SAVE_PTR		0x02
@@ -373,13 +396,6 @@
 #define MSG_IDENTIFY		0x80
 #define MSG_HOST_ID		0x0C0
 
-/*;----SCSI STATUS BYTE*/
-#define STATUS_GOOD		0x00
-#define CHECK_CONDITION_	0x02
-#define STATUS_BUSY		0x08
-#define STATUS_INTERMEDIATE	0x10
-#define RESERVE_CONFLICT	0x18
-
 /* cmd->result */
 #define STATUS_MASK_		0xFF
 #define MSG_MASK		0xFF00
@@ -389,7 +405,7 @@
 **  Inquiry Data format
 */
 
-typedef struct	_SCSIInqData { /* INQ */
+typedef struct	_SCSIInqData { /* INQUIRY */
 
 	UCHAR	 DevType;		/* Periph Qualifier & Periph Dev Type*/
 	UCHAR	 RMB_TypeMod;		/* rem media bit & Dev Type Modifier */
@@ -412,6 +428,7 @@
 
 #define SCSI_DEVTYPE	    0x1F      /* Peripheral Device Type 	    */
 #define SCSI_PERIPHQUAL     0xE0      /* Peripheral Qualifier		    */
+#define TYPE_NODEV	    SCSI_DEVTYPE    /* Unknown or no device type    */
 
 
 /*  Inquiry byte 1 mask */
@@ -420,18 +437,10 @@
 
 
 /*  Peripheral Device Type definitions */
+/*  see include/scsi/scsi.h for the rest */
 
-#define SCSI_DASD		 0x00	   /* Direct-access Device	   */
-#define SCSI_SEQACESS		 0x01	   /* Sequential-access device	   */
-#define SCSI_PRINTER		 0x02	   /* Printer device		   */
-#define SCSI_PROCESSOR		 0x03	   /* Processor device		   */
-#define SCSI_WRITEONCE		 0x04	   /* Write-once device 	   */
-#define SCSI_CDROM		 0x05	   /* CD-ROM device		   */
-#define SCSI_SCANNER		 0x06	   /* Scanner device		   */
-#define SCSI_OPTICAL		 0x07	   /* Optical memory device	   */
-#define SCSI_MEDCHGR		 0x08	   /* Medium changer device	   */
-#define SCSI_COMM		 0x09	   /* Communications device	   */
-#define SCSI_NODEV		 0x1F	   /* Unknown or no device type    */
+#define TYPE_PRINTER		 0x02	   /* Printer device		   */
+#define TYPE_COMM		 0x09	   /* Communications device	   */
 
 /*
 ** Inquiry flag definitions (Inq data byte 7)
@@ -459,17 +468,24 @@
 UCHAR	xx2;
 } EEprom, *PEEprom;
 
-#define EE_ADAPT_SCSI_ID 64
-#define EE_MODE2	65
-#define EE_DELAY	66
-#define EE_TAG_CMD_NUM	67
+#define REAL_EE_ADAPT_SCSI_ID 64
+#define REAL_EE_MODE2	65
+#define REAL_EE_DELAY	66
+#define REAL_EE_TAG_CMD_NUM	67
+
+#define EE_ADAPT_SCSI_ID 32
+#define EE_MODE2	33
+#define EE_DELAY	34
+#define EE_TAG_CMD_NUM	35
+
+#define EE_LEN		40
 
 /*; EE_MODE1 bits definition*/
 #define PARITY_CHK_	BIT0
 #define SYNC_NEGO_	BIT1
 #define EN_DISCONNECT_	BIT2
 #define SEND_START_	BIT3
-#define TAG_QUEUING_	BIT4
+#define TAG_QUEUEING_	BIT4
 
 /*; EE_MODE2 bits definition*/
 #define MORE2_DRV	BIT0
@@ -494,34 +510,42 @@
 ;====================
 */
 
-/*; Command Reg.(+0CH) */
+/*; Command Reg.(+0CH) (rw) */
 #define DMA_COMMAND		BIT7
 #define NOP_CMD 		0
 #define CLEAR_FIFO_CMD		1
 #define RST_DEVICE_CMD		2
 #define RST_SCSI_BUS_CMD	3
+
 #define INFO_XFER_CMD		0x10
 #define INITIATOR_CMD_CMPLTE	0x11
 #define MSG_ACCEPTED_CMD	0x12
 #define XFER_PAD_BYTE		0x18
 #define SET_ATN_CMD		0x1A
 #define RESET_ATN_CMD		0x1B
-#define SELECT_W_ATN		0x42
+
+#define SEL_WO_ATN		0x41	/* currently not used */
+#define SEL_W_ATN		0x42
 #define SEL_W_ATN_STOP		0x43
+#define SEL_W_ATN3		0x46
 #define EN_SEL_RESEL		0x44
-#define SEL_W_ATN2		0x46
+#define DIS_SEL_RESEL		0x45	/* currently not used */
+#define RESEL			0x40	/* " */
+#define RESEL_ATN3		0x47	/* " */
+
 #define DATA_XFER_CMD		INFO_XFER_CMD
 
 
-/*; SCSI Status Reg.(+10H) */
+/*; SCSI Status Reg.(+10H) (r) */
 #define INTERRUPT		BIT7
 #define ILLEGAL_OP_ERR		BIT6
 #define PARITY_ERR		BIT5
 #define COUNT_2_ZERO		BIT4
 #define GROUP_CODE_VALID	BIT3
-#define SCSI_PHASE_MASK 	(BIT2+BIT1+BIT0)
+#define SCSI_PHASE_MASK 	(BIT2+BIT1+BIT0) 
+/* BIT2: MSG phase; BIT1: C/D physe; BIT0: I/O phase */
 
-/*; Interrupt Status Reg.(+14H) */
+/*; Interrupt Status Reg.(+14H) (r) */
 #define SCSI_RESET		BIT7
 #define INVALID_CMD		BIT6
 #define DISCONNECTED		BIT5
@@ -531,11 +555,12 @@
 #define SEL_ATTENTION		BIT1
 #define SELECTED		BIT0
 
-/*; Internal State Reg.(+18H) */
+/*; Internal State Reg.(+18H) (r) */
 #define SYNC_OFFSET_FLAG	BIT3
 #define INTRN_STATE_MASK	(BIT2+BIT1+BIT0)
+/* 0x04: Sel. successful (w/o stop), 0x01: Sel. successful (w/ stop) */
 
-/*; Clock Factor Reg.(+24H) */
+/*; Clock Factor Reg.(+24H) (w) */
 #define CLK_FREQ_40MHZ		0
 #define CLK_FREQ_35MHZ		(BIT2+BIT1+BIT0)
 #define CLK_FREQ_30MHZ		(BIT2+BIT1)
@@ -544,47 +569,54 @@
 #define CLK_FREQ_15MHZ		(BIT1+BIT0)
 #define CLK_FREQ_10MHZ		BIT1
 
-/*; Control Reg. 1(+20H) */
+/*; Control Reg. 1(+20H) (rw) */
 #define EXTENDED_TIMING 	BIT7
 #define DIS_INT_ON_SCSI_RST	BIT6
 #define PARITY_ERR_REPO 	BIT4
-#define SCSI_ID_ON_BUS		(BIT2+BIT1+BIT0)
+#define SCSI_ID_ON_BUS		(BIT2+BIT1+BIT0) /* host adapter ID */
 
-/*; Control Reg. 2(+2CH) */
+/*; Control Reg. 2(+2CH) (rw) */
 #define EN_FEATURE		BIT6
 #define EN_SCSI2_CMD		BIT3
 
-/*; Control Reg. 3(+30H) */
+/*; Control Reg. 3(+30H) (rw) */
 #define ID_MSG_CHECK		BIT7
 #define EN_QTAG_MSG		BIT6
 #define EN_GRP2_CMD		BIT5
 #define FAST_SCSI		BIT4	/* ;10MB/SEC */
 #define FAST_CLK		BIT3	/* ;25 - 40 MHZ */
 
-/*; Control Reg. 4(+34H) */
+/*; Control Reg. 4(+34H) (rw) */
 #define EATER_12NS		0
 #define EATER_25NS		BIT7
 #define EATER_35NS		BIT6
 #define EATER_0NS		(BIT7+BIT6)
+#define REDUCED_POWER		BIT5
+#define CTRL4_RESERVED		BIT4	/* must be 1 acc. to AM53C974.c */
 #define NEGATE_REQACKDATA	BIT2
 #define NEGATE_REQACK		BIT3
+
+#define GLITCH_TO_NS(x) (((~x>>6 & 2) >> 1) | ((x>>6 & 1) << 1 ^ (x>>6 & 2)))
+#define NS_TO_GLITCH(y) (((~y<<7) | ~((y<<6) ^ ((y<<5 & 1<<6) | ~0x40))) & 0xc0)
+
 /*
 ;====================
 ; DMA Register
 ;====================
 */
-/*; DMA Command Reg.(+40H) */
+/*; DMA Command Reg.(+40H) (rw) */
 #define READ_DIRECTION		BIT7
 #define WRITE_DIRECTION 	0
 #define EN_DMA_INT		BIT6
-#define MAP_TO_MDL		BIT5
-#define DIAGNOSTIC		BIT4
+#define EN_PAGE_INT		BIT5	/* page transfer interrupt enable */
+#define MAP_TO_MDL		BIT4
+#define DIAGNOSTIC		BIT2
 #define DMA_IDLE_CMD		0
 #define DMA_BLAST_CMD		BIT0
 #define DMA_ABORT_CMD		BIT1
 #define DMA_START_CMD		(BIT1+BIT0)
 
-/*; DMA Status Reg.(+54H) */
+/*; DMA Status Reg.(+54H) (r) */
 #define PCI_MS_ABORT		BIT6
 #define BLAST_COMPLETE		BIT5
 #define SCSI_INTERRUPT		BIT4
@@ -593,71 +625,77 @@
 #define DMA_XFER_ERROR		BIT1
 #define POWER_DOWN		BIT0
 
-/*
-; DMA SCSI Bus and Ctrl.(+70H)
-;EN_INT_ON_PCI_ABORT
-*/
+/*; DMA SCSI Bus and Ctrl.(+70H) */
+#define EN_INT_ON_PCI_ABORT	BIT25
+#define WRT_ERASE_DMA_STAT	BIT24
+#define PW_DOWN_CTRL		BIT21
+#define SCSI_BUSY		BIT20
+#define SCLK			BIT19
+#define SCAM			BIT18
+#define SCSI_LINES		0x0003ffff
 
 /*
 ;==========================================================
 ; SCSI Chip register address offset
 ;==========================================================
+;Registers are rw unless declared otherwise 
 */
-#define CtcReg_Low	0x00
-#define CtcReg_Mid	0x04
+#define CtcReg_Low	0x00	/* r	curr. transfer count */
+#define CtcReg_Mid	0x04	/* r */
+#define CtcReg_High	0x38	/* r */
 #define ScsiFifo	0x08
 #define ScsiCmd 	0x0C
-#define Scsi_Status	0x10
-#define INT_Status	0x14
-#define Sync_Period	0x18
-#define Sync_Offset	0x1C
-#define CtrlReg1	0x20
-#define Clk_Factor	0x24
+#define Scsi_Status	0x10	/* r */
+#define INT_Status	0x14	/* r */
+#define Sync_Period	0x18	/* w */
+#define Sync_Offset	0x1C	/* w */
+#define Clk_Factor	0x24	/* w */
+#define CtrlReg1	0x20	
 #define CtrlReg2	0x2C
 #define CtrlReg3	0x30
 #define CtrlReg4	0x34
-#define CtcReg_High	0x38
 #define DMA_Cmd 	0x40
-#define DMA_XferCnt	0x44
-#define DMA_XferAddr	0x48
-#define DMA_Wk_ByteCntr 0x4C
-#define DMA_Wk_AddrCntr 0x50
-#define DMA_Status	0x54
-#define DMA_MDL_Addr	0x58
-#define DMA_Wk_MDL_Cntr 0x5C
-#define DMA_ScsiBusCtrl 0x70
-
-#define StcReg_Low	CtcReg_Low
-#define StcReg_Mid	CtcReg_Mid
-#define Scsi_Dest_ID	Scsi_Status
-#define Scsi_TimeOut	INT_Status
-#define Intern_State	Sync_Period
-#define Current_Fifo	Sync_Offset
-#define StcReg_High	CtcReg_High
-
-#define am_target	Scsi_Status
-#define am_timeout	INT_Status
-#define am_seq_step	Sync_Period
-#define am_fifo_count	Sync_Offset
-
-
-#define DC390_read8(address)			       \
-	inb(DC390_ioport + (address)))
-
-#define DC390_read16(address)			       \
-	inw(DC390_ioport + (address)))
-
-#define DC390_read32(address)			       \
-	inl(DC390_ioport + (address)))
+#define DMA_XferCnt	0x44	/* rw	starting transfer count (32 bit) */
+#define DMA_XferAddr	0x48	/* rw	starting physical address (32 bit) */
+#define DMA_Wk_ByteCntr 0x4C	/* r	working byte counter */
+#define DMA_Wk_AddrCntr 0x50	/* r	working address counter */
+#define DMA_Status	0x54	/* r */
+#define DMA_MDL_Addr	0x58	/* rw	starting MDL address */
+#define DMA_Wk_MDL_Cntr 0x5C	/* r	working MDL counter */
+#define DMA_ScsiBusCtrl 0x70	/* rw	SCSI Bus, PCI/DMA Ctrl */
+
+#define StcReg_Low	CtcReg_Low	/* w	start transfer count */
+#define StcReg_Mid	CtcReg_Mid	/* w */
+#define StcReg_High	CtcReg_High	/* w */
+#define Scsi_Dest_ID	Scsi_Status	/* w */
+#define Scsi_TimeOut	INT_Status	/* w */
+#define Intern_State	Sync_Period	/* r */
+#define Current_Fifo	Sync_Offset	/* r	Curr. FIFO / int. state */
+
+
+#define DC390_read8(address)			\
+	(inb (pACB->IOPortBase + (address)))
+
+#define DC390_read8_(address, base)		\
+	(inb ((USHORT)(base) + (address)))
+
+#define DC390_read16(address)			\
+	(inw (pACB->IOPortBase + (address)))
+
+#define DC390_read32(address)			\
+	(inl (pACB->IOPortBase + (address)))
+
+#define DC390_write8(address,value)		\
+	outb ((value), pACB->IOPortBase + (address))
 
-#define DC390_write8(address,value)		       \
-	outb((value), DC390_ioport + (address)))
+#define DC390_write8_(address,value,base)	\
+	outb ((value), (USHORT)(base) + (address))
 
-#define DC390_write16(address,value)		       \
-	outw((value), DC390_ioport + (address)))
+#define DC390_write16(address,value)		\
+	outw ((value), pACB->IOPortBase + (address))
 
-#define DC390_write32(address,value)		       \
-	outl((value), DC390_ioport + (address)))
+#define DC390_write32(address,value)		\
+	outl ((value), pACB->IOPortBase + (address))
 
 
 #endif /* _TMSCSIM_H */
diff -u --recursive --new-file v2.1.126/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c
--- v2.1.126/linux/drivers/sgi/char/sgiserial.c	Fri May  8 23:14:50 1998
+++ linux/drivers/sgi/char/sgiserial.c	Thu Nov  5 09:58:44 1998
@@ -1279,10 +1279,9 @@
 	if (!info->port)
 		return;
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + duration;
 	cli();
 	write_zsreg(info->zs_channel, 5, (info->curregs[5] | SND_BRK));
-	schedule();
+	schedule_timeout(duration);
 	write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	sti();
 }
@@ -1483,8 +1482,7 @@
 	if (info->blocked_open) {
 		if (info->close_delay) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->close_delay;
-			schedule();
+			schedule_timeout(info->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c
--- v2.1.126/linux/drivers/sound/cs4232.c	Sun Jul 26 11:57:16 1998
+++ linux/drivers/sound/cs4232.c	Wed Nov  4 09:47:14 1998
@@ -96,9 +96,7 @@
 static void sleep(unsigned howlong)
 {
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + howlong;
-	schedule();
-	current->timeout = 0;
+	schedule_timeout(howlong);
 }
 
 int probe_cs4232(struct address_info *hw_config)
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v2.1.126/linux/drivers/sound/dmabuf.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/sound/dmabuf.c	Wed Nov  4 09:50:43 1998
@@ -16,8 +16,8 @@
  *                   12k or so
  * Thomas Sailer   : remove {in,out}_sleep_flag. It was used for the sleeper to
  *                   determine if it was woken up by the expiring timeout or by
- *                   an explicit wake_up. current->timeout can be used instead;
- *                   if 0, the wakeup was due to the timeout.
+ *                   an explicit wake_up. The return value from schedule_timeout
+ *		     can be used instead; if 0, the wakeup was due to the timeout.
  */
 #include <linux/config.h>
 
@@ -38,9 +38,9 @@
 static int debugmem = 0;	/* switched off by default */
 static int dma_buffsize = DSP_BUFFSIZE;
 
-static void dmabuf_set_timeout(struct dma_buffparms *dmap)
+static long dmabuf_timeout(struct dma_buffparms *dmap)
 {
-	unsigned long tmout;
+	long tmout;
 
 	tmout = (dmap->fragment_size * HZ) / dmap->data_rate;
 	tmout += HZ / 5;	/* Some safety distance */
@@ -48,7 +48,7 @@
 		tmout = HZ / 2;
 	if (tmout > 20 * HZ)
 		tmout = 20 * HZ;
-	current->timeout = jiffies + tmout;
+	return tmout;
 }
 
 static int sound_alloc_dmap(struct dma_buffparms *dmap)
@@ -332,11 +332,9 @@
 
 	adev->dmap_out->underrun_count = 0;
 	if (!signal_pending(current) && adev->dmap_out->qlen && 
-	    adev->dmap_out->underrun_count == 0) {
-		dmabuf_set_timeout(dmap);
-		interruptible_sleep_on(&adev->out_sleeper);
-		current->timeout = 0;
-	}
+	    adev->dmap_out->underrun_count == 0)
+		interruptible_sleep_on_timeout(&adev->out_sleeper,
+					       dmabuf_timeout(dmap));
 	adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
 
 	/*
@@ -427,14 +425,14 @@
 		adev->dmap_out->underrun_count = 0;
 		while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs && 
 		       adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) {
-			dmabuf_set_timeout(dmap);
-			interruptible_sleep_on(&adev->out_sleeper);
-			if (!current->timeout) {
+			long t = dmabuf_timeout(dmap);
+			t = interruptible_sleep_on_timeout(&adev->out_sleeper,
+							   t);
+			if (!t) {
 				adev->dmap_out->flags &= ~DMA_SYNCING;
 				restore_flags(flags);
 				return adev->dmap_out->qlen;
 			}
-			current->timeout = 0;
 		}
 		adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
 		restore_flags(flags);
@@ -447,11 +445,10 @@
 		save_flags(flags);
 		cli();
 		if (adev->d->local_qlen) {   /* Device has hidden buffers */
-			while (!signal_pending(current) && adev->d->local_qlen(dev)) {
-				dmabuf_set_timeout(dmap);
-				interruptible_sleep_on(&adev->out_sleeper);
-				current->timeout = 0;
-			}
+			while (!signal_pending(current) &&
+			       adev->d->local_qlen(dev))
+				interruptible_sleep_on_timeout(&adev->out_sleeper,
+							       dmabuf_timeout(dmap));
 		}
 		restore_flags(flags);
 	}
@@ -546,6 +543,7 @@
 		  restore_flags(flags);
 		  return -EINVAL;
 	} else while (dmap->qlen <= 0 && n++ < 10) {
+		long timeout = MAX_SCHEDULE_TIMEOUT;
 		if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) {
 			restore_flags(flags);
 			return -EAGAIN;
@@ -560,19 +558,17 @@
 			restore_flags(flags);
 			return -EAGAIN;
 		}
-		if (!(go = adev->go))
-			current->timeout = 0;
-		else 
-			dmabuf_set_timeout(dmap);
-		interruptible_sleep_on(&adev->in_sleeper);
-		if (go && !current->timeout) {
+		if ((go = adev->go))
+			timeout = dmabuf_timeout(dmap);
+		timeout = interruptible_sleep_on_timeout(&adev->in_sleeper,
+							 timeout);
+		if (!timeout) {
 			/* FIXME: include device name */
 			err = -EIO;
 			printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
 			dma_reset_input(dev);
 		} else
 			err = -EINTR;
-		current->timeout = 0;
 	}
 	restore_flags(flags);
 
@@ -725,6 +721,7 @@
 	int err = 0;
 	struct dma_buffparms *dmap = adev->dmap_out;
 	int timeout;
+	long timeout_value;
 
 	if (dontblock)
 		return -EAGAIN;
@@ -738,15 +735,15 @@
 		return -EIO;
 	timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT));
 	if (timeout) 
-		dmabuf_set_timeout(dmap);
+		timeout_value = dmabuf_timeout(dmap);
 	else
-		current->timeout = 0;
-	interruptible_sleep_on(&adev->out_sleeper);
-	if (timeout && !current->timeout) {
+		timeout_value = MAX_SCHEDULE_TIMEOUT;
+	timeout_value = interruptible_sleep_on_timeout(&adev->out_sleeper,
+						       timeout_value);
+	if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) {
 		printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
 		dma_reset_output(dev);
 	} else {
-		current->timeout = 0;
 		if (signal_pending(current))
 			err = -EINTR;
 	}
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.1.126/linux/drivers/sound/dmasound.c	Wed Aug 26 11:37:39 1998
+++ linux/drivers/sound/dmasound.c	Wed Nov  4 09:47:40 1998
@@ -816,8 +816,7 @@
 #define ONE_SECOND	HZ	/* in jiffies (100ths of a second) */
 #define NO_TIME_LIMIT	0xffffffff
 #define SLEEP(queue, time_limit) \
-	current->timeout = jiffies+(time_limit); \
-	interruptible_sleep_on(&queue);
+	interruptible_sleep_on(&queue, (time_limit));
 #define WAKE_UP(queue)	(wake_up_interruptible(&queue))
 
 /*
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.1.126/linux/drivers/sound/es1370.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/sound/es1370.c	Thu Nov  5 09:58:46 1998
@@ -101,6 +101,7 @@
 
 /*****************************************************************************/
       
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -1016,11 +1017,8 @@
                 }
 		tmo = (count * HZ) / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-		current->timeout = jiffies + (tmo ? tmo : 1);
-                schedule();
-		if (tmo && !current->timeout)
+		if (!schedule_timeout(tmo ? : 1) && tmo)
 			printk(KERN_DEBUG "es1370: dma timed out??\n");
-		current->timeout = 0;
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
         current->state = TASK_RUNNING;
@@ -1054,11 +1052,8 @@
                 }
 		tmo = (count * HZ) / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-		current->timeout = jiffies + (tmo ? tmo : 1);
-                schedule();
-		if (tmo && !current->timeout)
+		if (!schedule_timeout(tmo ? : 1) && tmo)
 			printk(KERN_DEBUG "es1370: dma timed out??\n");
-		current->timeout = 0;
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
         current->state = TASK_RUNNING;
@@ -2200,11 +2195,8 @@
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
-			current->timeout = tmo ? jiffies + tmo : 0;
-			schedule();
-			if (tmo && !current->timeout)
+			if (!schedule_timeout(tmo ? : 1) && tmo)
 				printk(KERN_DEBUG "es1370: midi timed out??\n");
-			current->timeout = 0;
 		}
 		remove_wait_queue(&s->midi.owait, &wait);
 		current->state = TASK_RUNNING;
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.1.126/linux/drivers/sound/es1371.c	Sat Sep  5 16:46:41 1998
+++ linux/drivers/sound/es1371.c	Thu Nov  5 09:58:46 1998
@@ -1462,11 +1462,8 @@
                 }
 		tmo = (count * HZ) / s->dac1rate;
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-		current->timeout = jiffies + (tmo ? tmo : 1);
-                schedule();
-		if (tmo && !current->timeout)
+		if (!schedule_timeout(tmo ? : 1) && tmo)
 			printk(KERN_DEBUG "es1371: dma timed out??\n");
-		current->timeout = 0;
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
         current->state = TASK_RUNNING;
@@ -1500,11 +1497,8 @@
                 }
 		tmo = (count * HZ) / s->dac2rate;
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-		current->timeout = jiffies + (tmo ? tmo : 1);
-                schedule();
-		if (tmo && !current->timeout)
+		if (!schedule_timeout(tmo ? : 1) && tmo)
 			printk(KERN_DEBUG "es1371: dma timed out??\n");
-		current->timeout = 0;
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
         current->state = TASK_RUNNING;
@@ -2635,11 +2629,8 @@
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
-			current->timeout = tmo ? jiffies + tmo : 0;
-			schedule();
-			if (tmo && !current->timeout)
+			if (!schedule_timeout(tmo ? : 1) && tmo)
 				printk(KERN_DEBUG "es1371: midi timed out??\n");
-			current->timeout = 0;
 		}
 		remove_wait_queue(&s->midi.owait, &wait);
 		current->state = TASK_RUNNING;
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v2.1.126/linux/drivers/sound/gus_wave.c	Fri Oct 23 22:01:22 1998
+++ linux/drivers/sound/gus_wave.c	Wed Nov  4 09:41:13 1998
@@ -1927,11 +1927,8 @@
 			 */
 			active_device = GUS_DEV_WAVE;
 
-			current->timeout = jiffies + HZ;
-			interruptible_sleep_on(&dram_sleeper);
-			if (!current->timeout)
+			if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ))
 				printk("GUS: DMA Transfer timed out\n");
-			current->timeout = 0;
 			restore_flags(flags);
 		}
 
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v2.1.126/linux/drivers/sound/maui.c	Thu May 14 19:47:42 1998
+++ linux/drivers/sound/maui.c	Thu Nov  5 09:58:46 1998
@@ -81,10 +81,8 @@
 	{
 		if (inb(HOST_STAT_PORT) & mask)
 			return 1;
-		current->timeout = jiffies + HZ / 10;
 		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		current->timeout = 0;
+		schedule_timeout(HZ / 10);
 		if (signal_pending(current))
 			return 0;
 	}
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
--- v2.1.126/linux/drivers/sound/midibuf.c	Thu May 14 19:47:42 1998
+++ linux/drivers/sound/midibuf.c	Sat Oct 31 10:17:22 1998
@@ -90,11 +90,8 @@
 
 	if (midi_devs[dev]->buffer_status != NULL)
 		while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev)) 
-		{
-			current->timeout = jiffies + HZ / 10;
-			interruptible_sleep_on(&midi_sleeper[dev]);
-			current->timeout = 0;
-		}
+			interruptible_sleep_on_timeout(&midi_sleeper[dev],
+						       HZ/10);
 }
 
 static void midi_input_intr(int dev, unsigned char data)
@@ -181,7 +178,7 @@
 				 midi_input_intr, midi_output_intr)) < 0)
 		return err;
 
-	parms[dev].prech_timeout = 0;
+	parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
 	midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
 
 	if (midi_in_buf[dev] == NULL)
@@ -325,9 +322,9 @@
 	if (!DATA_AVAIL(midi_in_buf[dev])) {	/*
 						 * No data yet, wait
 						 */
-		current->timeout = parms[dev].prech_timeout ? jiffies + parms[dev].prech_timeout : 0;
-		interruptible_sleep_on(&input_sleeper[dev]);
-		current->timeout = 0;
+		interruptible_sleep_on_timeout(&input_sleeper[dev],
+					       parms[dev].prech_timeout);
+
 		if (signal_pending(current))
 			c = -EINTR;	/* The user is getting restless */
 	}
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c
--- v2.1.126/linux/drivers/sound/msnd_pinnacle.c	Fri Oct 23 22:01:22 1998
+++ linux/drivers/sound/msnd_pinnacle.c	Wed Nov  4 09:46:36 1998
@@ -639,16 +639,12 @@
 	if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags))
 		return;
 	set_bit(F_WRITEFLUSH, &dev.flags);
-	current->timeout = jiffies + get_play_delay_jiffies(dev.DAPF.len) + HZ / 8;
-	interruptible_sleep_on(&dev.writeflush);
+	interruptible_sleep_on_timeout(&dev.writeflush, get_play_delay_jiffies(dev.DAPF.len) + HZ / 8);
 	clear_bit(F_WRITEFLUSH, &dev.flags);
 	if (!signal_pending(current)) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + get_play_delay_jiffies(DAP_BUFF_SIZE);
-		schedule();
-		current->timeout = 0;
-	} else
-		current->timeout = 0;
+		schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE));
+	}
 	clear_bit(F_WRITING, &dev.flags);
 }
 
@@ -923,12 +919,8 @@
 
 		if (count > 0) {
 			set_bit(F_READBLOCK, &dev.flags);
-			current->timeout = jiffies + get_rec_delay_jiffies(DAR_BUFF_SIZE);
-			interruptible_sleep_on(&dev.readblock);
-			if (current->timeout == 0)
+			if (!interruptible_sleep_on_timeout(&dev.readblock, get_rec_delay_jiffies(DAR_BUFF_SIZE)))
 				clear_bit(F_READING, &dev.flags);
-			else
-				current->timeout = 0;
 			clear_bit(F_READBLOCK, &dev.flags);
 			if (signal_pending(current))
 				return -EINTR;
@@ -968,9 +960,7 @@
 
 		if (count > 0) {
 			set_bit(F_WRITEBLOCK, &dev.flags);
-			current->timeout = jiffies + get_play_delay_jiffies(DAP_BUFF_SIZE);
-			interruptible_sleep_on(&dev.writeblock);
-			current->timeout = 0;
+			interruptible_sleep_on_timeout(&dev.writeblock, get_play_delay_jiffies(DAP_BUFF_SIZE));
 			clear_bit(F_WRITEBLOCK, &dev.flags);
 			if (signal_pending(current))
 				return -EINTR;
@@ -1300,9 +1290,7 @@
 	if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
 	    chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + HZ / 3;
-		schedule();
-		current->timeout = 0;
+		schedule_timeout(HZ / 3);
 		printk("successful\n");
 		return 0;
 	}
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v2.1.126/linux/drivers/sound/sequencer.c	Thu Sep 17 17:53:37 1998
+++ linux/drivers/sound/sequencer.c	Sat Oct 31 10:17:22 1998
@@ -113,9 +113,9 @@
   			restore_flags(flags);
   			return -EAGAIN;
   		}
- 		current->timeout = pre_event_timeout ? jiffies + pre_event_timeout : 0;
- 		interruptible_sleep_on(&midi_sleeper);
- 		current->timeout = 0;
+
+ 		interruptible_sleep_on_timeout(&midi_sleeper,
+					       pre_event_timeout);
 		if (!iqlen)
 		{
 			restore_flags(flags);
@@ -355,7 +355,6 @@
 		/*
 		 * Sleep until there is enough space on the queue
 		 */
-		current->timeout = 0;
 		interruptible_sleep_on(&seq_sleeper);
 	}
 	if (qlen >= SEQ_MAX_QUEUE)
@@ -1026,7 +1025,7 @@
 
 	max_mididev = num_midis;
 	max_synthdev = num_synths;
-	pre_event_timeout = 0;
+	pre_event_timeout = MAX_SCHEDULE_TIMEOUT;
 	seq_mode = SEQ_1;
 
 	if (pending_timer != -1)
@@ -1153,11 +1152,9 @@
 		 * Let's have a delay
 		 */
 
- 		if (n) {
- 			current->timeout = jiffies + HZ / 10;
- 			interruptible_sleep_on(&seq_sleeper);
- 			current->timeout = 0;
-  		}
+ 		if (n)
+ 			interruptible_sleep_on_timeout(&seq_sleeper,
+						       HZ/10);
 	}
 }
 
@@ -1179,9 +1176,8 @@
 		while (!signal_pending(current) && qlen > 0)
 		{
   			seq_sync();
- 			current->timeout = jiffies + 3 * HZ;
- 			interruptible_sleep_on(&seq_sleeper);
- 			current->timeout = 0;
+ 			interruptible_sleep_on_timeout(&seq_sleeper,
+						       3*HZ);
  			/* Extra delay */
 		}
 	}
@@ -1233,11 +1229,8 @@
 
 	save_flags(flags);
 	cli();
- 	if (qlen > 0) {
- 		current->timeout = jiffies + HZ;
- 		interruptible_sleep_on(&seq_sleeper);
- 		current->timeout = 0;
-  	}
+ 	if (qlen > 0)
+ 		interruptible_sleep_on_timeout(&seq_sleeper, HZ);
 	restore_flags(flags);
 	return qlen;
 }
@@ -1262,9 +1255,7 @@
 	save_flags(flags);
 	cli();
  	while (n && !midi_devs[dev]->outputc(dev, data)) {
- 		current->timeout = jiffies + 4;
- 		interruptible_sleep_on(&seq_sleeper);
- 		current->timeout = 0;
+ 		interruptible_sleep_on_timeout(&seq_sleeper, HZ/25);
   		n--;
   	}
 	restore_flags(flags);
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/sgalaxy.c linux/drivers/sound/sgalaxy.c
--- v2.1.126/linux/drivers/sound/sgalaxy.c	Fri Oct 23 22:01:22 1998
+++ linux/drivers/sound/sgalaxy.c	Thu Nov  5 09:58:46 1998
@@ -29,9 +29,7 @@
 static void sleep( unsigned howlong )
 {
 	current->state   = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + howlong;
-	schedule();
-	current->timeout = 0;
+	schedule(howlong);
 }
 
 #define DPORT 0x80
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.1.126/linux/drivers/sound/sonicvibes.c	Sat Sep  5 16:46:41 1998
+++ linux/drivers/sound/sonicvibes.c	Thu Nov  5 09:58:46 1998
@@ -1245,11 +1245,8 @@
                 }
 		tmo = (count * HZ) / s->ratedac;
 		tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK];
-		current->timeout = jiffies + (tmo ? tmo : 1);
-                schedule();
-		if (tmo && !current->timeout)
+		if (!schedule_timeout(tmo ? : 1) && tmo)
 			printk(KERN_DEBUG "sv: dma timed out??\n");
-		current->timeout = 0;
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
         current->state = TASK_RUNNING;
@@ -2025,11 +2022,8 @@
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
-			current->timeout = tmo ? jiffies + tmo : 0;
-			schedule();
-			if (tmo && !current->timeout)
+			if (!schedule_timeout(tmo ? : 1) && tmo)
 				printk(KERN_DEBUG "sv: midi timed out??\n");
-			current->timeout = 0;
 		}
 		remove_wait_queue(&s->midi.owait, &wait);
 		current->state = TASK_RUNNING;
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v2.1.126/linux/drivers/sound/sscape.c	Thu May 14 19:47:42 1998
+++ linux/drivers/sound/sscape.c	Tue Nov  3 22:46:00 1998
@@ -124,10 +124,8 @@
 
 static void sleep(unsigned howlong)
 {
-	current->timeout = jiffies + 1;
 	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	current->timeout = 0;
+	schedule_timeout(1);
 }
 
 static unsigned char sscape_read(struct sscape_info *devc, int reg)
diff -u --recursive --new-file v2.1.126/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c
--- v2.1.126/linux/drivers/sound/wavfront.c	Thu Sep 17 17:53:37 1998
+++ linux/drivers/sound/wavfront.c	Wed Nov  4 09:50:01 1998
@@ -343,11 +343,8 @@
 wavefront_sleep (wf_config *hw, int limit)
 
 {
-	current->timeout = jiffies + limit;
 	current->state = TASK_INTERRUPTIBLE;
-	schedule();
-	current->timeout = 0;
-
+	schedule_timeout(limit);
 	return signal_pending(current);
 }
     
@@ -2266,8 +2263,7 @@
 	cli();
 	hw->irq_ok = 0;
 	outb (val,port);
-	current->timeout = jiffies + timeout;
-	interruptible_sleep_on (&hw->interrupt_sleeper);
+	interruptible_sleep_on_timeout(&hw->interrupt_sleeper, timeout);
 	restore_flags (flags);
 }
 
diff -u --recursive --new-file v2.1.126/linux/drivers/video/mdacon.c linux/drivers/video/mdacon.c
--- v2.1.126/linux/drivers/video/mdacon.c	Fri Oct  9 13:27:12 1998
+++ linux/drivers/video/mdacon.c	Wed Oct 28 22:04:59 1998
@@ -3,6 +3,8 @@
  *
  *	(c) 1998 Andrew Apted <ajapted@netspace.net.au>
  *
+ *      including portions (c) 1995-1998 Patrick Caulfield.
+ *
  *  This file is based on the VGA console driver (vgacon.c):
  *	
  *	Created 28 Sep 1997 by Geert Uytterhoeven
@@ -34,6 +36,7 @@
 #include <linux/vt_buffer.h>
 #include <linux/selection.h>
 #include <linux/ioport.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
@@ -50,6 +53,8 @@
 static unsigned int	mda_index_port;		/* Register select port */
 static unsigned int	mda_value_port;		/* Register value port */
 static unsigned int	mda_mode_port;		/* Mode control port */
+static unsigned int	mda_status_port;	/* Status and Config port */
+static unsigned int	mda_gfx_port;		/* Graphics control port */
 
 /* current hardware state */
 
@@ -58,24 +63,48 @@
 static int	mda_cursor_size_from=-1;
 static int	mda_cursor_size_to=-1;
 
+static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type;
+static char *mda_type_name;
+
 /* console information */
 
-static int	mda_first_vc = 12;
-static int	mda_last_vc  = 15;
+static int	mda_first_vc = 13;
+static int	mda_last_vc  = 16;
 
 static struct vc_data	*mda_display_fg = NULL;
 
 #ifdef MODULE_PARM
-MODULE_PARM(mda_first_vc, "0-255i");
-MODULE_PARM(mda_last_vc,  "0-255i");
+MODULE_PARM(mda_first_vc, "1-255i");
+MODULE_PARM(mda_last_vc,  "1-255i");
 #endif
 
 
+/* MDA register values
+ */
+
+#define MDA_CURSOR_BLINKING	0x00
+#define MDA_CURSOR_OFF		0x20
+#define MDA_CURSOR_SLOWBLINK	0x60
+
+#define MDA_MODE_GRAPHICS	0x02
+#define MDA_MODE_VIDEO_EN	0x08
+#define MDA_MODE_BLINK_EN	0x20
+#define MDA_MODE_GFX_PAGE1	0x80
+
+#define MDA_STATUS_HSYNC	0x01
+#define MDA_STATUS_VSYNC	0x80
+#define MDA_STATUS_VIDEO	0x08
+
+#define MDA_CONFIG_COL132	0x08
+#define MDA_GFX_MODE_EN		0x01
+#define MDA_GFX_PAGE_EN		0x02
+
+
 /*
  * MDA could easily be classified as "pre-dinosaur hardware".
  */
 
-static void write_mda_b(unsigned char reg, unsigned int val)
+static void write_mda_b(unsigned int val, unsigned char reg)
 {
 	unsigned long flags;
 
@@ -87,24 +116,40 @@
 	restore_flags(flags);
 }
 
-static void write_mda_w(unsigned char reg, unsigned int val)
+static void write_mda_w(unsigned int val, unsigned char reg)
 {
 	unsigned long flags;
 
 	save_flags(flags); cli();
 
-	outb_p(reg,   mda_index_port); outb_p(val>>8,   mda_value_port);
-	outb_p(reg+1, mda_index_port); outb_p(val&0xff, mda_value_port);
+	outb_p(reg,   mda_index_port); outb_p(val >> 8,   mda_value_port);
+	outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port);
 
 	restore_flags(flags);
 }
 
+static int test_mda_b(unsigned char val, unsigned char reg)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	outb_p(reg, mda_index_port); 
+	outb  (val, mda_value_port);
+
+	udelay(20); val = (inb_p(mda_value_port) == val);
+
+	restore_flags(flags);
+
+	return val;
+}
+
 static inline void mda_set_origin(unsigned int location)
 {
 	if (mda_origin_loc == location)
 		return;
 
-	write_mda_w(0x0c, location >> 1);
+	write_mda_w(location >> 1, 0x0c);
 
 	mda_origin_loc = location;
 }
@@ -114,7 +159,7 @@
 	if (mda_cursor_loc == location)
 		return;
 
-	write_mda_w(0x0e, location >> 1);
+	write_mda_w(location >> 1, 0x0e);
 
 	mda_cursor_loc = location;
 }
@@ -125,10 +170,10 @@
 		return;
 	
 	if (from > to) {
-		write_mda_b(0x0a, 0x20);	/* disable cursor */
+		write_mda_b(MDA_CURSOR_OFF, 0x0a);	/* disable cursor */
 	} else {
-		write_mda_b(0x0a, from);	/* cursor start */
-		write_mda_b(0x0b, to);		/* cursor end */
+		write_mda_b(from, 0x0a);	/* cursor start */
+		write_mda_b(to,   0x0b);	/* cursor end */
 	}
 
 	mda_cursor_size_from = from;
@@ -144,53 +189,158 @@
 	if (ints[0] < 2)
 		return;
 
-	if (ints[1] < 0 || ints[1] >= MAX_NR_CONSOLES || 
-	    ints[2] < 0 || ints[2] >= MAX_NR_CONSOLES)
+	if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || 
+	    ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
 		return;
 
-	mda_first_vc = ints[1];
-	mda_last_vc  = ints[2];
+	mda_first_vc = ints[1]-1;
+	mda_last_vc  = ints[2]-1;
 }
 #endif
 
 #ifdef MODULE
-static const char *mdacon_startup(void)
+static int mda_detect(void)
 #else
-__initfunc(static const char *mdacon_startup(void))
+__initfunc(static int mda_detect(void))
 #endif
 {
 	int count=0;
-	u16 saved;
-	u16 *p;
+	u16 *p, p_save;
+	u16 *q, q_save;
+
+	/* do a memory check */
+
+	p = (u16 *) mda_vram_base;
+	q = (u16 *) (mda_vram_base + 0x01000);
+
+	p_save = scr_readw(p); q_save = scr_readw(q);
+
+	scr_writew(0xAA55, p); if (scr_readw(p) == 0xAA55) count++;
+	scr_writew(0x55AA, p); if (scr_readw(p) == 0x55AA) count++;
+	scr_writew(p_save, p);
+
+	if (count != 2) {
+		return 0;
+	}
+
+	/* check if we have 4K or 8K */
+
+	scr_writew(0xA55A, q); scr_writew(0x0000, p);
+	if (scr_readw(q) == 0xA55A) count++;
+	
+	scr_writew(0x5AA5, q); scr_writew(0x0000, p);
+	if (scr_readw(q) == 0x5AA5) count++;
 
+	scr_writew(p_save, p); scr_writew(q_save, q);
+	
+	if (count == 4) {
+		mda_vram_len = 0x02000;
+	}
+	
+	/* Ok, there is definitely a card registering at the correct
+	 * memory location, so now we do an I/O port test.
+	 */
+	
+	if (! test_mda_b(0x66, 0x0f)) {	    /* cursor low register */
+		return 0;
+	}
+	if (! test_mda_b(0x99, 0x0f)) {     /* cursor low register */
+		return 0;
+	}
+
+	/* See if the card is a Hercules, by checking whether the vsync
+	 * bit of the status register is changing.  This test lasts for
+	 * approximately 1/10th of a second.
+	 */
+	
+	p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC;
+
+	for (count=0; count < 50000 && p_save == q_save; count++) {
+		q_save = inb(mda_status_port) & MDA_STATUS_VSYNC;
+		udelay(2);
+	}
+
+	if (p_save != q_save) {
+		switch (inb_p(mda_status_port) & 0x70) {
+			case 0x10:
+				mda_type = TYPE_HERCPLUS;
+				mda_type_name = "HerculesPlus";
+				break;
+			case 0x50:
+				mda_type = TYPE_HERCCOLOR;
+				mda_type_name = "HerculesColor";
+				break;
+			default:
+				mda_type = TYPE_HERC;
+				mda_type_name = "Hercules";
+				break;
+		}
+	}
+
+	return 1;
+}
+
+#ifdef MODULE
+static void mda_initialize(void)
+#else
+__initfunc(static void mda_initialize(void))
+#endif
+{
+	write_mda_b(97, 0x00);		/* horizontal total */
+	write_mda_b(80, 0x01);		/* horizontal displayed */
+	write_mda_b(82, 0x02);		/* horizontal sync pos */
+	write_mda_b(15, 0x03);		/* horizontal sync width */
+
+	write_mda_b(25, 0x04);		/* vertical total */
+	write_mda_b(6,  0x05);		/* vertical total adjust */
+	write_mda_b(25, 0x06);		/* vertical displayed */
+	write_mda_b(25, 0x07);		/* vertical sync pos */
+
+	write_mda_b(2,  0x08);		/* interlace mode */
+	write_mda_b(13, 0x09);		/* maximum scanline */
+	write_mda_b(12, 0x0a);		/* cursor start */
+	write_mda_b(13, 0x0b);		/* cursor end */
+
+	write_mda_w(0x0000, 0x0c);	/* start address */
+	write_mda_w(0x0000, 0x0e);	/* cursor location */
+
+	outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port);
+	outb_p(0x00, mda_status_port);
+	outb_p(0x00, mda_gfx_port);
+}
+
+#ifdef MODULE
+static const char *mdacon_startup(void)
+#else
+__initfunc(static const char *mdacon_startup(void))
+#endif
+{
 	mda_num_columns = 80;
 	mda_num_lines   = 25;
 
 	mda_vram_base = VGA_MAP_MEM(0xb0000);
 	mda_vram_len  = 0x01000;
 
-	mda_index_port = 0x3b4;
-	mda_value_port = 0x3b5;
-	mda_mode_port  = 0x3b8;
-
-	/*  Make sure there is an MDA card present.
-	 *  Are there smarter methods around?
-	 */
-
-	p = (u16 *) mda_vram_base;
-	saved = scr_readw(p);
+	mda_index_port  = 0x3b4;
+	mda_value_port  = 0x3b5;
+	mda_mode_port   = 0x3b8;
+	mda_status_port = 0x3ba;
+	mda_gfx_port    = 0x3bf;
 
-	scr_writew(0xAA55, p); if (scr_readw(p) == 0xAA55) count++;
-	scr_writew(0x55AA, p); if (scr_readw(p) == 0x55AA) count++;
-	scr_writew(saved, p);
+	mda_type = TYPE_MDA;
+	mda_type_name = "MDA";
 
-	if (count != 2) {
+	if (! mda_detect()) {
 		printk("mdacon: MDA card not detected.");
 		return NULL;
 	}
 
-	printk("mdacon: MDA with %ldK of memory detected.\n",
-		mda_vram_len/1024);
+	if (mda_type != TYPE_MDA) {
+		mda_initialize();
+	}
+
+	printk("mdacon: %s with %ldK of memory detected.\n",
+		mda_type_name, mda_vram_len/1024);
 
 	return "MDA-2";
 }
@@ -347,7 +497,7 @@
 	if (blank) {
 		outb_p(0x00, mda_mode_port);	/* disable video */
 	} else {
-		outb_p(0x28, mda_mode_port);	/* enable video & blinking */
+		outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port);
 	}
 	
 	return 0;
@@ -380,7 +530,7 @@
 		case CUR_BLOCK:		mda_set_cursor_size(1,  13); break;
 		case CUR_NONE:		mda_set_cursor_size(14, 13); break;
 		default:		mda_set_cursor_size(12, 13); break;
-    }
+	}
 }
 
 static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
diff -u --recursive --new-file v2.1.126/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h
--- v2.1.126/linux/fs/autofs/autofs_i.h	Tue Aug 18 22:02:05 1998
+++ linux/fs/autofs/autofs_i.h	Sat Nov  7 11:29:58 1998
@@ -2,7 +2,7 @@
  *   
  * linux/fs/autofs/autofs_i.h
  *
- *   Copyright 1997 Transmeta Corporation - All Rights Reserved
+ *   Copyright 1997-1998 Transmeta Corporation - All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -47,11 +47,13 @@
 
 struct autofs_dir_ent {
 	int hash;
-	struct autofs_dir_ent *next;
-	struct autofs_dir_ent **back;
 	char *name;
 	int len;
 	ino_t ino;
+	struct dentry *dentry;
+	/* Linked list of entries */
+	struct autofs_dir_ent *next;
+	struct autofs_dir_ent **back;
 	/* The following entries are for the expiry system */
 	unsigned long last_usage;
 	struct autofs_dir_ent *exp_next;
@@ -123,7 +125,7 @@
 struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,struct qstr *);
 void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
 void autofs_hash_delete(struct autofs_dir_ent *);
-struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *);
+struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *,struct autofs_dir_ent *);
 void autofs_hash_nuke(struct autofs_dirhash *);
 
 /* Expiration-handling functions */
diff -u --recursive --new-file v2.1.126/linux/fs/autofs/dir.c linux/fs/autofs/dir.c
--- v2.1.126/linux/fs/autofs/dir.c	Wed Aug 26 11:37:40 1998
+++ linux/fs/autofs/dir.c	Tue Oct 27 14:13:53 1998
@@ -2,7 +2,7 @@
  *
  * linux/fs/autofs/dir.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
diff -u --recursive --new-file v2.1.126/linux/fs/autofs/dirhash.c linux/fs/autofs/dirhash.c
--- v2.1.126/linux/fs/autofs/dirhash.c	Tue Aug 18 22:02:05 1998
+++ linux/fs/autofs/dirhash.c	Tue Oct 27 14:13:53 1998
@@ -59,13 +59,11 @@
 			return ent; /* Symlinks are always expirable */
 
 		/* Get the dentry for the autofs subdirectory */
-		dentry = lookup_dentry(ent->name, dget(sb->s_root), 0);
+		dentry = ent->dentry;
 
-		if ( IS_ERR(dentry) ) {
-			printk("autofs: no such dentry on expiry queue: %s\n",
-			       ent->name);
+		if ( !dentry ) {
+			printk("autofs: dentry == NULL but inode range is directory, entry %s\n", ent->name);
 			autofs_delete_usage(ent);
-			continue;
 		}
 
 		if ( !dentry->d_inode ) {
@@ -79,24 +77,12 @@
 		/* Make sure entry is mounted and unused; note that dentry will
 		   point to the mounted-on-top root. */
 		if ( !S_ISDIR(dentry->d_inode->i_mode)
-		     || dentry->d_covers == dentry ) {
-			dput(dentry);
+		     || dentry->d_mounts == dentry ) {
 			DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
 			continue;
 		}
 
-		/*
-		 * Now, this is known to be a mount point; therefore the dentry
-		 * will be held by the superblock.  is_root_busy() will break if
-		 * we hold a use count here, so we have to dput() it before calling
-		 * is_root_busy().  However, since it is a mount point (already
-		 * verified), dput() will be a nonblocking operation and the use
-		 * count will not go to zero; therefore the call to is_root_busy()
-		 * here is legal.
-		 */
-		dput(dentry);
-
-		if ( !is_root_busy(dentry) ) {
+		if ( !is_root_busy(dentry->d_mounts) ) {
 			DPRINTK(("autofs: signaling expire on %s\n", ent->name));
 			return ent; /* Expirable! */
 		}
@@ -136,6 +122,8 @@
 	autofs_say(ent->name,ent->len);
 
 	autofs_init_usage(dh,ent);
+	if ( ent->dentry )
+		ent->dentry->d_count++;
 
 	dhnp = &dh->h[(unsigned) ent->hash % AUTOFS_HASH_SIZE];
 	ent->next = *dhnp;
@@ -153,6 +141,8 @@
 
 	autofs_delete_usage(ent);
 
+	if ( ent->dentry )
+		dput(ent->dentry);
 	kfree(ent->name);
 	kfree(ent);
 }
@@ -161,8 +151,12 @@
  * Used by readdir().  We must validate "ptr", so we can't simply make it
  * a pointer.  Values below 0xffff are reserved; calling with any value
  * <= 0x10000 will return the first entry found.
+ *
+ * "last" can be NULL or the value returned by the last search *if* we
+ * want the next sequential entry.
  */
-struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, off_t *ptr)
+struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh,
+					off_t *ptr, struct autofs_dir_ent *last)
 {
 	int bucket, ecount, i;
 	struct autofs_dir_ent *ent;
@@ -176,19 +170,23 @@
 
 	DPRINTK(("autofs_hash_enum: bucket %d, entry %d\n", bucket, ecount));
 
-	ent = NULL;
+	ent = last ? last->next : NULL;
 
-	while  ( bucket < AUTOFS_HASH_SIZE ) {
-		ent = dh->h[bucket];
-		for ( i = ecount ; ent && i ; i-- )
-			ent = ent->next;
-
-		if (ent) {
-			ecount++; /* Point to *next* entry */
-			break;
+	if ( ent ) {
+		ecount++;
+	} else {
+		while  ( bucket < AUTOFS_HASH_SIZE ) {
+			ent = dh->h[bucket];
+			for ( i = ecount ; ent && i ; i-- )
+				ent = ent->next;
+			
+			if (ent) {
+				ecount++; /* Point to *next* entry */
+				break;
+			}
+			
+			bucket++; ecount = 0;
 		}
-
-		bucket++; ecount = 0;
 	}
 
 #ifdef DEBUG
@@ -214,6 +212,8 @@
 	for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) {
 		for ( ent = dh->h[i] ; ent ; ent = nent ) {
 			nent = ent->next;
+			if ( ent->dentry )
+				dput(ent->dentry);
 			kfree(ent->name);
 			kfree(ent);
 		}
diff -u --recursive --new-file v2.1.126/linux/fs/autofs/init.c linux/fs/autofs/init.c
--- v2.1.126/linux/fs/autofs/init.c	Fri Sep  5 20:15:37 1997
+++ linux/fs/autofs/init.c	Tue Oct 27 14:13:53 1998
@@ -2,7 +2,7 @@
  *
  * linux/fs/autofs/init.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
diff -u --recursive --new-file v2.1.126/linux/fs/autofs/inode.c linux/fs/autofs/inode.c
--- v2.1.126/linux/fs/autofs/inode.c	Mon Apr  6 17:41:00 1998
+++ linux/fs/autofs/inode.c	Tue Oct 27 14:13:53 1998
@@ -2,7 +2,7 @@
  *
  * linux/fs/autofs/inode.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
diff -u --recursive --new-file v2.1.126/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.1.126/linux/fs/autofs/root.c	Wed Aug 26 11:37:40 1998
+++ linux/fs/autofs/root.c	Tue Oct 27 15:13:47 1998
@@ -2,7 +2,7 @@
  *
  * linux/fs/autofs/root.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -66,7 +66,7 @@
 
 static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-	struct autofs_dir_ent *ent;
+	struct autofs_dir_ent *ent = NULL;
 	struct autofs_dirhash *dirhash;
 	struct inode * inode = filp->f_dentry->d_inode;
 	off_t onr, nr;
@@ -90,10 +90,12 @@
 		filp->f_pos = ++nr;
 		/* fall through */
 	default:
-		while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr) ) {
-			if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
-				return 0;
-			filp->f_pos = nr;
+		while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
+			if ( !ent->dentry || ent->dentry->d_mounts != ent->dentry ) {
+				if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
+					return 0;
+				filp->f_pos = nr;
+			}
 		}
 		break;
 	}
@@ -110,8 +112,8 @@
 	if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
 		do {
 			if ( status && dentry->d_inode ) {
-				printk("autofs warning: lookup failure on existing dentry, status = %d, name = %s\n", status, dentry->d_name.name);
-				break;
+				printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
+				return 0; /* Try to get the kernel to invalidate this dentry */
 			}
 
 			/* Turn this into a real negative dentry? */
@@ -148,8 +150,9 @@
 
 	/* We don't update the usages for the autofs daemon itself, this
 	   is necessary for recursive autofs mounts */
-	if ( !autofs_oz_mode(sbi) )
+	if ( !autofs_oz_mode(sbi) ) {
 		autofs_update_usage(&sbi->dirhash,ent);
+	}
 
 	dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
 	return 1;
@@ -193,7 +196,8 @@
 	/* Update the usage list */
 	if ( !autofs_oz_mode(sbi) ) {
 		ent = (struct autofs_dir_ent *) dentry->d_time;
-		autofs_update_usage(&sbi->dirhash,ent);
+		if ( ent )
+			autofs_update_usage(&sbi->dirhash,ent);
 	}
 	return 1;
 }
@@ -207,7 +211,6 @@
 static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
 {
 	struct autofs_sb_info *sbi;
-	struct inode *res;
 	int oz_mode;
 
 	DPRINTK(("autofs_root_lookup: name = "));
@@ -216,7 +219,6 @@
 	if (!S_ISDIR(dir->i_mode))
 		return -ENOTDIR;
 
-	res = NULL;
 	sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
 
 	oz_mode = autofs_oz_mode(sbi);
@@ -249,6 +251,15 @@
 			return -ERESTARTNOINTR;
 	}
 
+	/*
+	 * If this dentry is unhashed, then we shouldn't honour this
+	 * lookup even if the dentry is positive.  Returning ENOENT here
+	 * doesn't do the right thing for all system calls, but it should
+	 * be OK for the operations we permit from an autofs.
+	 */
+	if ( dentry->d_inode && list_empty(&dentry->d_hash) )
+		return -ENOENT;
+
 	return 0;
 }
 
@@ -304,6 +315,7 @@
 	ent->ino = AUTOFS_FIRST_SYMLINK + n;
 	ent->hash = dentry->d_name.hash;
 	memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len));
+	ent->dentry = NULL;	/* We don't keep the dentry for symlinks */
 
 	autofs_hash_insert(dh,ent);
 	d_instantiate(dentry, iget(dir->i_sb,ent->ino));
@@ -339,7 +351,8 @@
 	n = ent->ino - AUTOFS_FIRST_SYMLINK;
 	if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap) )
 		return -EINVAL;	/* Not a symlink inode, can't unlink */
-
+       
+	dentry->d_time = (unsigned long)(struct autofs_dirhash *)NULL;
 	autofs_hash_delete(ent);
 	clear_bit(n,sbi->symlink_bitmap);
 	kfree(sbi->symlink[n].data);
@@ -364,6 +377,11 @@
 	if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO )
 		return -ENOTDIR; /* Not a directory */
 
+	if ( ent->dentry != dentry ) {
+		printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name);
+	}
+
+	dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL;
 	autofs_hash_delete(ent);
 	dir->i_nlink--;
 	d_drop(dentry);
@@ -399,12 +417,14 @@
 		return -ENOSPC;
 	}
 
+	dir->i_nlink++;
+	d_instantiate(dentry, iget(dir->i_sb,ent->ino));
+
 	ent->hash = dentry->d_name.hash;
 	memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len));
 	ent->ino = sbi->next_dir_ino++;
+	ent->dentry = dentry;
 	autofs_hash_insert(dh,ent);
-	dir->i_nlink++;
-	d_instantiate(dentry, iget(dir->i_sb,ent->ino));
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.126/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c
--- v2.1.126/linux/fs/autofs/symlink.c	Mon Sep 28 10:51:34 1998
+++ linux/fs/autofs/symlink.c	Tue Oct 27 14:13:53 1998
@@ -2,7 +2,7 @@
  *
  * linux/fs/autofs/symlink.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
diff -u --recursive --new-file v2.1.126/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c
--- v2.1.126/linux/fs/autofs/waitq.c	Mon Dec  1 10:34:11 1997
+++ linux/fs/autofs/waitq.c	Tue Oct 27 14:13:53 1998
@@ -2,7 +2,7 @@
  *
  * linux/fs/autofs/waitq.c
  *
- *  Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -20,6 +20,9 @@
    is better if we don't reassign numbers easily even across filesystems */
 static int autofs_next_wait_queue = 1;
 
+/* These are the signals we allow interrupting a pending mount */
+#define SHUTDOWN_SIGS	(sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT))
+
 void autofs_catatonic_mode(struct autofs_sb_info *sbi)
 {
 	struct autofs_wait_queue *wq, *nwq;
@@ -133,9 +136,25 @@
 	} else
 		wq->wait_ctr++;
 
+	/* wq->name is NULL if and only if the lock is already released */
+
 	if ( wq->name ) {
-		/* wq->name is NULL if and only if the lock is released */
+		/* Block all but "shutdown" signals while waiting */
+		sigset_t oldset;
+		unsigned long irqflags;
+
+		spin_lock_irqsave(&current->sigmask_lock, irqflags);
+		oldset = current->blocked;
+		siginitsetinv(&current->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
+		recalc_sigpending(current);
+		spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+
 		interruptible_sleep_on(&wq->queue);
+
+		spin_lock_irqsave(&current->sigmask_lock, irqflags);
+		current->blocked = oldset;
+		recalc_sigpending(current);
+		spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
 	} else {
 		DPRINTK(("autofs_wait: skipped sleeping\n"));
 	}
diff -u --recursive --new-file v2.1.126/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.1.126/linux/fs/binfmt_elf.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/binfmt_elf.c	Tue Oct 27 10:23:40 1998
@@ -608,7 +608,7 @@
 	   base, as well as whatever program they might try to exec.  This
 	   is because the brk will follow the loader, and is not movable.  */
 
-	load_bias = (elf_ex.e_type == ET_DYN ? ELF_ET_DYN_BASE : 0);
+	load_bias = ELF_PAGESTART(elf_ex.e_type==ET_DYN ? ELF_ET_DYN_BASE : 0);
 
 	/* Now we do a little grungy work by mmaping the ELF image into
 	   the correct location in memory.  At this point, we assume that
@@ -618,51 +618,50 @@
 	old_fs = get_fs();
 	set_fs(get_ds());
 	for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
-		if (elf_ppnt->p_type == PT_LOAD) {
-			int elf_prot = 0, elf_flags;
-			unsigned long vaddr;
-
-			if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
-			if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-			if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-
-			elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
-
-			vaddr = elf_ppnt->p_vaddr;
-			if (elf_ex.e_type == ET_EXEC || load_addr_set) {
-				elf_flags |= MAP_FIXED;
-			}
+		int elf_prot = 0, elf_flags;
+		unsigned long vaddr;
+
+		if (elf_ppnt->p_type != PT_LOAD)
+			continue;
+
+		if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
+		if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+		if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+
+		elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+
+		vaddr = elf_ppnt->p_vaddr;
+		if (elf_ex.e_type == ET_EXEC || load_addr_set) {
+			elf_flags |= MAP_FIXED;
+		}
 
-			error = do_mmap(file,
-					ELF_PAGESTART(load_bias + vaddr),
-					(elf_ppnt->p_filesz +
-					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
-					elf_prot, elf_flags,
-					(elf_ppnt->p_offset -
-					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-
-			if (!load_addr_set) {
-				load_addr_set = 1;
-				load_addr = (elf_ppnt->p_vaddr -
-					     elf_ppnt->p_offset);
-				if (elf_ex.e_type == ET_DYN) {
-					load_bias = error - ELF_PAGESTART(load_bias + vaddr);
-					load_addr += error;
-				}
+		error = do_mmap(file, ELF_PAGESTART(load_bias + vaddr),
+		                (elf_ppnt->p_filesz +
+		                ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
+		                elf_prot, elf_flags, (elf_ppnt->p_offset -
+		                ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+
+		if (!load_addr_set) {
+			load_addr_set = 1;
+			load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
+			if (elf_ex.e_type == ET_DYN) {
+				load_bias += error -
+				             ELF_PAGESTART(load_bias + vaddr);
+				load_addr += error;
 			}
-			k = elf_ppnt->p_vaddr;
-			if (k < start_code) start_code = k;
-			k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
-			if (k > elf_bss)
-				elf_bss = k;
-			if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
-				end_code = k;
-			if (end_data < k)
-				end_data = k;
-			k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
-			if (k > elf_brk)
-				elf_brk = k;
 		}
+		k = elf_ppnt->p_vaddr;
+		if (k < start_code) start_code = k;
+		k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+		if (k > elf_bss)
+			elf_bss = k;
+		if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
+			end_code = k;
+		if (end_data < k)
+			end_data = k;
+		k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
+		if (k > elf_brk)
+			elf_brk = k;
 	}
 	set_fs(old_fs);
 	fput(file); /* all done with the file */
diff -u --recursive --new-file v2.1.126/linux/fs/exec.c linux/fs/exec.c
--- v2.1.126/linux/fs/exec.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/exec.c	Mon Nov  2 15:00:30 1998
@@ -54,9 +54,6 @@
 #include <linux/kmod.h>
 #endif
 
-asmlinkage int sys_exit(int exit_code);
-asmlinkage int sys_brk(unsigned long);
-
 /*
  * Here are the actual binaries that will be accepted:
  * add more with "register_binfmt()" if using modules...
@@ -752,24 +749,28 @@
 	/* handle /sbin/loader.. */
 	{
 	    struct exec * eh = (struct exec *) bprm->buf;
+	    struct linux_binprm bprm_loader;
 
 	    if (!bprm->loader && eh->fh.f_magic == 0x183 &&
 		(eh->fh.f_flags & 0x3000) == 0x3000)
 	    {
+		int i;
 		char * dynloader[] = { "/sbin/loader" };
 		struct dentry * dentry;
 
 		dput(bprm->dentry);
 		bprm->dentry = NULL;
-		remove_arg_zero(bprm);
-		bprm->p = copy_strings(1, dynloader, bprm->page, bprm->p, 2);
-		bprm->argc++;
-		bprm->loader = bprm->p;
+
+	        bprm_loader.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+	        for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
+                    bprm_loader.page[i] = 0;
+
 		dentry = open_namei(dynloader[0], 0, 0);
 		retval = PTR_ERR(dentry);
 		if (IS_ERR(dentry))
 			return retval;
 		bprm->dentry = dentry;
+		bprm->loader = bprm_loader.p;
 		retval = prepare_binprm(bprm);
 		if (retval<0)
 			return retval;
diff -u --recursive --new-file v2.1.126/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- v2.1.126/linux/fs/ext2/balloc.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/ext2/balloc.c	Wed Oct 28 21:54:56 1998
@@ -721,7 +721,7 @@
 		
 		bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 
-		if (!(le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) &
+		if (!(sb->u.ext2_sb.s_feature_ro_compat &
 		     EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
 		    ext2_group_sparse(i)) {
 			if (!ext2_test_bit (0, bh->b_data))
diff -u --recursive --new-file v2.1.126/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.1.126/linux/fs/ext2/super.c	Mon Sep 28 10:51:34 1998
+++ linux/fs/ext2/super.c	Wed Oct 28 21:54:56 1998
@@ -786,7 +786,7 @@
 		 * superblocks is turned on, then not all groups have
 		 * this.
 		 */
-		if (le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) &
+		if (sb->u.ext2_sb.s_feature_ro_compat &
 		    EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) {
 			ngroups = 0;
 			for (i=0 ; i < sb->u.ext2_sb.s_groups_count; i++)
diff -u --recursive --new-file v2.1.126/linux/fs/fat/mmap.c linux/fs/fat/mmap.c
--- v2.1.126/linux/fs/fat/mmap.c	Tue Mar 10 10:03:33 1998
+++ linux/fs/fat/mmap.c	Mon Nov  2 13:26:51 1998
@@ -58,6 +58,7 @@
 		}
 		filp.f_reada = 0;
 		filp.f_pos = pos;
+		filp.f_dentry=area->vm_file->f_dentry;
 		need_read = PAGE_SIZE - clear;
 		{
 			mm_segment_t cur_fs = get_fs();
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/ChangeLog linux/fs/hfs/ChangeLog
--- v2.1.126/linux/fs/hfs/ChangeLog	Fri Oct  9 13:27:14 1998
+++ linux/fs/hfs/ChangeLog	Mon Nov  2 09:35:16 1998
@@ -1,3 +1,57 @@
+1998-11-02  a sun  <asun@hecate.darksunrising.blah>
+
+	* mdb.c (hfs_mdb_get): plugged up an mdb failed initialization
+	leak.
+
+1998-10-31  a sun  <asun@hecate.darksunrising.blah>
+
+	* version.c (hfs_version): bumped to version 0.96.
+
+	* mdb.c (hfs_mdb_commit): you only write out the alternate MDB
+	when the catalog or extents overflow files grow. that just leaves
+	the btree corruption problems. bleah (whilst deleting a bunch of
+	files, more of the btree can get pruned away than desired).
+
+1998-10-30  a sun  <asun@hecate.darksunrising.blah>
+
+	* dir.c: fixed a bunch of silliness with deletions. make sure to
+	zero out stuff and set mark_inode_dirty().
+	
+1998-10-29  a sun  <asun@hecate.darksunrising.blah>
+
+	* string.c (hfs_strcmp, hfs_streq, hfs_strhash): converted them to
+	take name/len arguments instead of hfs_name to reduce copying.
+
+	* dir.c, dir_nat.c, dir_cap.c, dir_dbl.c, sysdep.c: modified
+	relevant areas to reflect string.c changes.
+	
+1998-10-28  a sun  <asun@hecate.darksunrising.blah>
+
+	* hfs.h (hfs_lookup_dentry): oh my. more silliness. make sure to
+	have the d_lookup use the same hash value as the one generated by
+	hfs_hash_dentry. i also changed the argument order.
+	(hfs_drop_special): change the argument order to be more in line
+	with what the dcache stuff looks like.
+
+	* sysdep.c (hfs_compare_dentry): the compare was returning the
+	wrong value for correct matches and causing all sorts of
+	mischief. this fixes both directory counts and mounting on top of
+	hfs volumes.
+
+	* file.c, file_cap.c, file_hdr.c: added mark_inode_dirty()'s in
+	the relevant places.
+
+1998-10-11  root  <asun@hecate.darksunrising.blah>
+
+	* mdb.c (hfs_mdb_get): moved initialization of mdb->entry_dirty
+	list to here to deal with trying to read a bad hfs volume.
+
+1998-10-10  a sun  <asun@zoology.washington.edu>
+
+	* inode.c, catalog.c, dir_*.c, sysdep.c: parts of the dcache
+	conversion didn't get done properly. specifically, i forgot to
+	move the hfs_cat_puts into the right place. that's fixed now.
+
 1998-09-11  a sun  <asun@purgatorius.zoology.washington.edu>
 
 	* mdb.c: altered mdb struct to reflect hfs plus usage.
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/TODO linux/fs/hfs/TODO
--- v2.1.126/linux/fs/hfs/TODO	Sun Jan  4 10:40:17 1998
+++ linux/fs/hfs/TODO	Mon Nov  2 09:35:16 1998
@@ -10,10 +10,8 @@
 1.	Header files have compiled-in limit (currently 10) on descriptors.
 
 Missing features:
-1.	The partition code should be migrated into the kernel to allow
-	simultaneous access to multiple partitions on a single disk.
-2.	1k block support is needed for some devices.
-3.	An ioctl()-based interface is needed to provide a consistent way
+1.	1k block support is needed for some devices.
+2.	An ioctl()-based interface is needed to provide a consistent way
 	to do things under all of the representations of forked files.
 
 Possible additional "fork" mount options:
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/bnode.c linux/fs/hfs/bnode.c
--- v2.1.126/linux/fs/hfs/bnode.c	Sun Jan  4 10:40:17 1998
+++ linux/fs/hfs/bnode.c	Mon Nov  2 09:35:16 1998
@@ -510,6 +510,8 @@
 	} else {
 		hfs_warn("hfs_bnode_find: use %d(%d) lvl %d [%d]\n", bn->count,
 			 bn->buf->b_count, bn->ndNHeight, bnode_count);
+		hfs_warn("hfs_bnode_find: blnk %u flnk %u recs %u\n", 
+			 bn->ndBLink, bn->ndFLink, bn->ndNRecs);
 	}
 #endif
 
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/catalog.c linux/fs/hfs/catalog.c
--- v2.1.126/linux/fs/hfs/catalog.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/hfs/catalog.c	Mon Nov  2 09:35:16 1998
@@ -127,17 +127,15 @@
  *
  * hash an (struct mdb *) and a (struct hfs_cat_key *) to an integer.
  */
-static inline unsigned long hashfn(const struct hfs_mdb *mdb,
+static inline unsigned int hashfn(const struct hfs_mdb *mdb,
 				  const struct hfs_cat_key *key)
 {
-#define LSB(X) (((unsigned char *)(&X))[3])
-	unsigned long hash;
+	unsigned int hash;
 	
-	hash = (unsigned long) mdb | (unsigned long) key->ParID[3] |
-	  hfs_strhash(&key->CName);
+	hash = (unsigned long) mdb | (unsigned long) key->ParID[3] | 
+		hfs_strhash(key->CName.Name, key->CName.Len);
 	hash = hash ^ (hash >> C_HASHBITS) ^ (hash >> C_HASHBITS*2);
 	return hash & C_HASHMASK;
-#undef LSB
 }
 
 /*
@@ -533,7 +531,6 @@
 				 HFS_BKEY(key), HFS_BFIND_READ_EQ)) {
 		        /* uh oh. we failed to read the record.
 			 * the entry doesn't actually exist. */
-		        entry->state |= HFS_DELETED;
 		        goto read_fail;
 		   }
 
@@ -564,12 +561,14 @@
 	return NULL;
 
 read_fail: 
-	/* spinlock unlocked already. we don't need to mark the entry
-	 * dirty here because we know that it doesn't exist. */
-	remove_hash(entry);
-	entry->state &= ~HFS_LOCK;
-	hfs_wake_up(&entry->wait);
-	hfs_cat_put(entry);
+	/* short-cut hfs_cat_put by doing everything here. */
+	spin_lock(&entry_lock);
+	list_del(&entry->hash);
+	list_del(&entry->list);
+	init_entry(entry);
+	list_add(&entry->list, &entry_unused);
+	entries_stat.nr_free_entries++;
+	spin_unlock(&entry_lock);
 	return NULL;
 }
 
@@ -586,6 +585,11 @@
 {
 	struct hfs_cat_entry * entry;
 
+#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
+	hfs_warn("hfs_get_entry: mdb=%p key=%s read=%d\n",
+		 mdb, key->CName.Name, read);
+#endif
+
 	spin_lock(&entry_lock);
 	entry = find_entry(mdb, key);
 	if (!entry) {
@@ -759,6 +763,7 @@
 	/* complete the cache entry and return success */
 	__read_entry(entry, record);
 	unlock_entry(entry);
+
 	if (result) {
 		*result = entry;
 	} else {
@@ -786,17 +791,7 @@
  *
  * Release an entry we aren't using anymore.
  *
- * NOTE: We must be careful any time we sleep on a non-deleted
- * entry that the entry is in a consistent state, since another
- * process may get the entry while we sleep. That is why we
- * 'goto repeat' after each operation that might sleep.
- *
- * ADDITIONAL NOTE: the sys_entries will remove themselves from 
- *                  the sys_entry list on the final iput, so we don't need 
- *                  to worry about them here.
- *
- *                  nothing in hfs_cat_put goes to sleep now except 
- *                  on the initial entry.
+ * nothing in hfs_cat_put goes to sleep now except on the initial entry.  
  */
 void hfs_cat_put(struct hfs_cat_entry * entry)
 {
@@ -810,9 +805,13 @@
 		  return;
 		}
 
+#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
+		hfs_warn("hfs_cat_put: %p(%u) type=%d state=%lu\n", 
+			 entry, entry->count, entry->type, entry->state);
+#endif
 		spin_lock(&entry_lock);
 		if (!--entry->count) {
-		        if ((entry->state & HFS_DELETED))
+			if ((entry->state & HFS_DELETED))
 			        goto entry_deleted;
 
 			if ((entry->type == HFS_CDR_FIL)) {
@@ -840,10 +839,7 @@
 			        HFS_DELETE(entry);
 				entries_stat.nr_entries--;
 			} else {
-			        spin_unlock(&entry_lock);
-				wait_on_entry(entry);
 				init_entry(entry);
-				spin_lock(&entry_lock);
 				list_add(&entry->list, &entry_unused);
 				entries_stat.nr_free_entries++;
 			}
@@ -919,7 +915,7 @@
  * hfs_cat_invalidate()
  *
  * Called by hfs_mdb_put() to remove all the entries
- * in the cache which are associated with a given MDB.
+ * in the cache that are associated with a given MDB.
  */
 void hfs_cat_invalidate(struct hfs_mdb *mdb)
 {
@@ -931,6 +927,11 @@
 	spin_unlock(&entry_lock);
 
 	delete_list(&throw_away);
+#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
+	hfs_warn("hfs_cat_invalidate: free=%d total=%d\n",
+		 entries_stat.nr_free_entries,
+		 entries_stat.nr_entries);
+#endif
 }
 
 /*
@@ -941,7 +942,7 @@
 void hfs_cat_commit(struct hfs_mdb *mdb)
 {
         struct list_head *tmp, *head = &mdb->entry_dirty;
-	struct hfs_cat_entry * entry;
+	struct hfs_cat_entry *entry;
 
 	spin_lock(&entry_lock);
 	while ((tmp = head->prev) != head) {
@@ -1018,7 +1019,8 @@
 	if (parents != 0) {
 		retval = (int)parents;
 	} else {
-		retval = hfs_strcmp(&key1->CName, &key2->CName);
+		retval = hfs_strcmp(key1->CName.Name, key1->CName.Len,
+				    key2->CName.Name, key2->CName.Len);
 	}
 	return retval;
 }
@@ -1170,9 +1172,6 @@
  * Create a new file with the indicated name in the indicated directory.
  * The file will have the indicated flags, type and creator.
  * If successful an (struct hfs_cat_entry) is returned in '*result'.
- *
- * XXX: the presence of "record" probably means that the following two
- *      aren't currently SMP safe and need spinlocks.
  */
 int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
 		   hfs_u8 flags, hfs_u32 type, hfs_u32 creator,
@@ -1182,6 +1181,10 @@
 	hfs_u32 id = new_cnid(parent->mdb);
 	hfs_u32 mtime = hfs_time();
 
+#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
+	hfs_warn("hfs_cat_create: %p/%s flags=%d res=%p\n",
+		 parent, key->CName.Name, flags, result);
+#endif
 	/* init some fields for the file record */
 	memset(&record, 0, sizeof(record));
 	record.cdrType = HFS_CDR_FIL;
@@ -1209,6 +1212,11 @@
 	hfs_u32 id = new_cnid(parent->mdb);
 	hfs_u32 mtime = hfs_time();
 
+#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
+	hfs_warn("hfs_cat_mkdir: %p/%s res=%p\n", parent, key->CName.Name,
+		 result);
+#endif
+
 	/* init some fields for the directory record */
 	memset(&record, 0, sizeof(record));
 	record.cdrType = HFS_CDR_DIR;
@@ -1234,6 +1242,10 @@
 	struct hfs_mdb *mdb = parent->mdb;
 	int is_dir, error = 0;
 
+#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)
+	hfs_warn("hfs_cat_delete: %p/%p type=%d state=%lu, thread=%d\n",
+		 parent, entry, entry->type, entry->state, with_thread);
+#endif
 	if (parent->mdb != entry->mdb) {
 		return -EINVAL;
 	}
@@ -1252,39 +1264,39 @@
 	if (entry->type == HFS_CDR_DIR) {
 		start_read(entry);
 
-		if (entry->u.dir.files || entry->u.dir.dirs) {
-			error = -ENOTEMPTY;
-		}
+		error = -ENOTEMPTY;
+		if (entry->u.dir.files || entry->u.dir.dirs) 
+			goto hfs_delete_end;
 	}
 
 	/* try to delete the file or directory */
-	if (!error) {
-		lock_entry(entry);
-		if ((entry->state & HFS_DELETED)) {
-			/* somebody beat us to it */
-			error = -ENOENT;
-		} else {
-			error = hfs_bdelete(mdb->cat_tree,
-					    HFS_BKEY(&entry->key));
-		}
-		unlock_entry(entry);
+	lock_entry(entry);
+	error = -ENOENT;
+	if ((entry->state & HFS_DELETED)) {
+		/* somebody beat us to it. */
+		goto hfs_delete_unlock;
+	}
+		
+	/* delete the catalog record */
+	if ((error = hfs_bdelete(mdb->cat_tree, HFS_BKEY(&entry->key)))) {
+		goto hfs_delete_unlock;
 	}
 
-	if (!error) {
-		/* Mark the entry deleted and remove it from the cache */
-		lock_entry(entry);
-		delete_entry(entry);
-
-		/* try to delete the thread entry if it exists */
-		if (with_thread) {
-			hfs_cat_build_key(entry->cnid, NULL, &key);
-			(void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key));
-		}
-
-		unlock_entry(entry);
-		update_dir(mdb, parent, is_dir, -1);
+	/* Mark the entry deleted and remove it from the cache */
+	delete_entry(entry);
+
+	/* try to delete the thread entry if it exists */
+	if (with_thread) {
+		hfs_cat_build_key(entry->cnid, NULL, &key);
+		(void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key));
 	}
+	
+	update_dir(mdb, parent, is_dir, -1);
+
+hfs_delete_unlock:
+	unlock_entry(entry);
 
+hfs_delete_end:
 	if (entry->type == HFS_CDR_DIR) {
 		end_read(entry);
 	}
@@ -1332,10 +1344,10 @@
 		return -EINVAL;
 	}
 
-	spin_lock(&entry_lock);
 	while (mdb->rename_lock) {
 		hfs_sleep_on(&mdb->rename_wait);
 	}
+	spin_lock(&entry_lock);
 	mdb->rename_lock = 1;
 	spin_unlock(&entry_lock);
 
@@ -1575,5 +1587,3 @@
                 i--;
         } while (i);
 }
-
-
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/dir.c linux/fs/hfs/dir.c
--- v2.1.126/linux/fs/hfs/dir.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/hfs/dir.c	Mon Nov  2 09:35:16 1998
@@ -41,7 +41,8 @@
 	/* check against reserved names */
 	reserved = HFS_SB(dir->i_sb)->s_reserved1;
 	while (reserved->Len) {
-		if (hfs_streq(reserved, &cname)) {
+		if (hfs_streq(reserved->Name, reserved->Len, 
+			      cname.Name, cname.Len)) {
 			return 1;
 		}
 		++reserved;
@@ -51,7 +52,8 @@
 	if (HFS_I(dir)->entry->cnid == htonl(HFS_ROOT_CNID)) {
 		reserved = HFS_SB(dir->i_sb)->s_reserved2;
 		while (reserved->Len) {
-			if (hfs_streq(reserved, &cname)) {
+			if (hfs_streq(reserved->Name, reserved->Len,
+				      cname.Name, cname.Len)) {
 				return 1;
 			}
 			++reserved;
@@ -129,16 +131,23 @@
  *
  * Update inodes associated with a deleted entry to reflect its deletion.
  * Well, we really just drop the dentry.
+ *
+ * XXX: we should be using delete_inode for some of this stuff.
  */
 static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, 
 				       struct dentry *dentry)
 {
 	struct dentry *de;
+	struct inode *tmp;
 	int i;
 
 	for (i = 0; i < 4; ++i) {
 		if ((de = entry->sys_entry[i]) && (dentry != de)) {
 		      dget(de);
+		      tmp = de->d_inode;
+		      tmp->i_nlink = 0;
+		      tmp->i_ctime = CURRENT_TIME;
+		      mark_inode_dirty(tmp);
 		      d_delete(de);
 		      dput(de);
 		}
@@ -177,32 +186,32 @@
 	int error;
 
 	/* build the key, checking against reserved names */
-	if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) {
-		error = -EEXIST;
-	} else {
-		/* try to create the file */
-		error = hfs_cat_create(entry, &key, 
-				       (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK,
-				       HFS_SB(dir->i_sb)->s_type,
-				       HFS_SB(dir->i_sb)->s_creator, &new);
-	}
-
-	if (!error) {
-		update_dirs_plus(entry, 0);
-
-		/* create an inode for the new file */
-		inode = hfs_iget(new, HFS_I(dir)->file_type, dentry);
-		if (!inode) {
-		        /* XXX correct error? */
-		        error = -EIO;
-   		} else {
-		  if (HFS_I(dir)->d_drop_op)
-		    HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type);
-		  d_instantiate(dentry, inode);
-		}
-	}
+	if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) 
+		return -EEXIST;
 
-	return error;
+	if ((error = hfs_cat_create(entry, &key, 
+			       (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK,
+			       HFS_SB(dir->i_sb)->s_type,
+			       HFS_SB(dir->i_sb)->s_creator, &new)))
+		return error;
+
+	/* create an inode for the new file. back out if we run
+	 * into trouble. */
+	new->count++; /* hfs_iget() eats one */
+	if (!(inode = hfs_iget(new, HFS_I(dir)->file_type, dentry))) {
+		hfs_cat_delete(entry, new, 1);
+		hfs_cat_put(new);
+		return -EIO;
+	}
+
+	hfs_cat_put(new);
+	update_dirs_plus(entry, 0);
+	/* toss any relevant negative dentries */
+	if (HFS_I(dir)->d_drop_op)
+		HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type);
+	mark_inode_dirty(inode);
+	d_instantiate(dentry, inode);
+	return 0;
 }
 
 /*
@@ -223,23 +232,26 @@
 
 	/* build the key, checking against reserved names */
 	if (build_key(&key, parent, dentry->d_name.name, 
-		      dentry->d_name.len)) {
-		error = -EEXIST;
-	} else {
-		/* try to create the directory */
-		error = hfs_cat_mkdir(entry, &key, &new);
-	}
-
-	if (!error) {
-	        update_dirs_plus(entry, 1);
-	        inode = hfs_iget(new, HFS_I(parent)->file_type, dentry);
-		if (!inode) {
-		        error = -EIO;
-		} else
-		  d_instantiate(dentry, inode);
-	}
+		      dentry->d_name.len)) 
+		return -EEXIST;
 
-	return error;
+	/* try to create the directory */
+	if ((error = hfs_cat_mkdir(entry, &key, &new)))
+		return error;
+
+	/* back out if we run into trouble */
+	new->count++; /* hfs_iget eats one */
+	if (!(inode = hfs_iget(new, HFS_I(parent)->file_type, dentry))) {
+		hfs_cat_delete(entry, new, 1);
+		hfs_cat_put(new);
+		return -EIO;
+	}
+
+	hfs_cat_put(new);
+	update_dirs_plus(entry, 1);
+	mark_inode_dirty(inode);
+	d_instantiate(dentry, inode);
+	return 0;
 }
 
 /*
@@ -257,16 +269,14 @@
  */
 int hfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
 {
-	int error;
+	if (!dir) 
+		return -ENOENT;
 
-	if (!dir) {
-		error = -ENOENT;
-	} else if (S_ISREG(mode)) {
-		error = hfs_create(dir, dentry, mode);
-	} else {
-		error = -EPERM;
-	}
-	return error;
+	/* the only thing we currently do. */
+	if (S_ISREG(mode)) 
+		return hfs_create(dir, dentry, mode);
+
+	return -EPERM;
 }
 
 /*
@@ -285,18 +295,28 @@
 	int error;
 
 	if (build_key(&key, dir, dentry->d_name.name,
-		      dentry->d_name.len)) {
-		error = -EPERM;
-	} else if (!(victim = hfs_cat_get(entry->mdb, &key))) {
-		error = -ENOENT;
-	} else if (victim->type != HFS_CDR_FIL) {
-		error = -EPERM;
-	} else if (!(error = hfs_cat_delete(entry, victim, 1))) {
+		      dentry->d_name.len)) 
+		return -EPERM;
+
+	if (!(victim = hfs_cat_get(entry->mdb, &key))) 
+		return -ENOENT;
+
+	error = -EPERM;
+	if (victim->type != HFS_CDR_FIL)
+		goto hfs_unlink_put;
+
+	if (!(error = hfs_cat_delete(entry, victim, 1))) {
+		struct inode *inode = dentry->d_inode;
+
 		mark_inodes_deleted(victim, dentry);
+		inode->i_nlink--; 
+		inode->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(inode);
 		d_delete(dentry);
 		update_dirs_minus(entry, 0);
 	}
 
+hfs_unlink_put:
 	hfs_cat_put(victim);	/* Note that hfs_cat_put(NULL) is safe. */
 	return error;
 }
@@ -313,31 +333,50 @@
 {
 	struct hfs_cat_entry *entry = HFS_I(parent)->entry;
 	struct hfs_cat_entry *victim = NULL;
+	struct inode *inode = dentry->d_inode;
 	struct hfs_cat_key key;
 	int error;
 
+	if (parent == inode) /* can't delete . */
+		return -EPERM;
+
 	if (build_key(&key, parent, dentry->d_name.name,
-		      dentry->d_name.len)) {
-		error = -EPERM;
-	} else if (!(victim = hfs_cat_get(entry->mdb, &key))) {
-		error = -ENOENT;
-	} else if (victim->type != HFS_CDR_DIR) {
-		error = -ENOTDIR;
-	} else if (/* we only have to worry about 2 and 3 for mount points */
-		   (victim->sys_entry[2] &&
-		    (victim->sys_entry[2] !=
-		     victim->sys_entry[2]->d_mounts)) ||
-		   (victim->sys_entry[3] &&
-		    (victim->sys_entry[3] != 
-		     victim->sys_entry[3]->d_mounts))
-		   ) {
-		error = -EBUSY;
-	} else if (!(error = hfs_cat_delete(entry, victim, 1))) {
-		mark_inodes_deleted(victim, dentry);
-		d_delete(dentry);
-		update_dirs_minus(entry, 1);
-	}
+		      dentry->d_name.len))
+		return -EPERM;
+
+	if (!(victim = hfs_cat_get(entry->mdb, &key)))
+		return -ENOENT;
+
+	error = -ENOTDIR;
+	if (victim->type != HFS_CDR_DIR) 
+		goto hfs_rmdir_put;
+
+	error = -EBUSY;
+	if (dentry->d_count > 1)
+		goto hfs_rmdir_put;
+
+	if (/* we only have to worry about 2 and 3 for mount points */
+		(victim->sys_entry[2] &&
+		 (victim->sys_entry[2]->d_mounts !=
+		  victim->sys_entry[2]->d_covers)) ||
+		(victim->sys_entry[3] &&
+		 (victim->sys_entry[3]->d_mounts != 
+		  victim->sys_entry[3]->d_covers))
+		) 
+		goto hfs_rmdir_put;
+
+	
+	if ((error = hfs_cat_delete(entry, victim, 1)))
+		goto hfs_rmdir_put;
+
+	mark_inodes_deleted(victim, dentry);
+	inode->i_nlink = 0;
+	inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(inode);
+	d_delete(dentry);
+	update_dirs_minus(entry, 1);
 	 
+hfs_rmdir_put:
 	hfs_cat_put(victim);	/* Note that hfs_cat_put(NULL) is safe. */
 	return error;
 }
@@ -365,35 +404,40 @@
 
 	if (build_key(&key, old_dir, old_dentry->d_name.name,
 		      old_dentry->d_name.len) ||
-	    (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino))) {
-		error = -EPERM;
-	} else if (!(victim = hfs_cat_get(old_parent->mdb, &key))) {
-		error = -ENOENT;
-	} else if (build_key(&key, new_dir, new_dentry->d_name.name,
-			     new_dentry->d_name.len)) {
-		error = -EPERM;
-	} else if (!(error = hfs_cat_move(old_parent, new_parent,
-					  victim, &key, &deleted))) {
-		int is_dir = (victim->type == HFS_CDR_DIR);
+	    (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino))) 
+		return -EPERM;
 
+	if (!(victim = hfs_cat_get(old_parent->mdb, &key))) 
+		return -ENOENT;
+
+	error = -EPERM;
+	if (build_key(&key, new_dir, new_dentry->d_name.name,
+			     new_dentry->d_name.len)) 
+		goto hfs_rename_put;
+
+	if (!(error = hfs_cat_move(old_parent, new_parent,
+				   victim, &key, &deleted))) {
+		int is_dir = (victim->type == HFS_CDR_DIR);
+		
 		/* drop the old dentries */
 		mark_inodes_deleted(victim, old_dentry);
 		update_dirs_minus(old_parent, is_dir);
 		if (deleted) {
-		  mark_inodes_deleted(deleted, new_dentry);
-		  hfs_cat_put(deleted);
+			mark_inodes_deleted(deleted, new_dentry);
+			hfs_cat_put(deleted);
 		} else {
-		  /* no existing inodes. just drop negative dentries */
-		  if (HFS_I(new_dir)->d_drop_op) 
-		    HFS_I(new_dir)->d_drop_op(new_dentry, 
-					      HFS_I(new_dir)->file_type);
-		  update_dirs_plus(new_parent, is_dir);
+			/* no existing inodes. just drop negative dentries */
+			if (HFS_I(new_dir)->d_drop_op) 
+				HFS_I(new_dir)->d_drop_op(new_dentry, 
+					  HFS_I(new_dir)->file_type);
+			update_dirs_plus(new_parent, is_dir);
 		}
-
+	
 		/* update dcache */
 		d_move(old_dentry, new_dentry);
 	}
 
+hfs_rename_put:
 	hfs_cat_put(victim);	/* Note that hfs_cat_put(NULL) is safe. */
 	return error;
 }
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/dir_cap.c linux/fs/hfs/dir_cap.c
--- v2.1.126/linux/fs/hfs/dir_cap.c	Wed Aug 26 11:37:41 1998
+++ linux/fs/hfs/dir_cap.c	Mon Nov  2 09:35:16 1998
@@ -167,43 +167,26 @@
 	hfs_nameout(dir, &cname, dentry->d_name.name, 
 		    dentry->d_name.len);
 
-	/* Check for "." */
-	if (hfs_streq(&cname, DOT)) {
-		/* this little trick skips the iget and iput */
-		d_add(dentry, dir);
-		return 0;
-	}
-
-	/* Check for "..". */
-	if (hfs_streq(&cname, DOT_DOT)) {
-		struct hfs_cat_entry *parent;
-
-		if (dtype != HFS_CAP_NDIR) {
-			/* Case for ".." in ".finderinfo" or ".resource" */
-			parent = entry;
-			++entry->count; /* __hfs_iget() eats one */
-		} else {
-			/* Case for ".." in a normal directory */
-			parent = hfs_cat_parent(entry);
-		}
-		inode = hfs_iget(parent, HFS_CAP_NDIR, dentry);
-		goto done;
-	}
+	/* no need to check for "."  or ".." */
 
 	/* Check for special directories if in a normal directory.
 	   Note that cap_dupdir() does an iput(dir). */
 	if (dtype==HFS_CAP_NDIR) {
 		/* Check for ".resource", ".finderinfo" and ".rootinfo" */
-		if (hfs_streq(&cname, DOT_RESOURCE)) {
+		if (hfs_streq(cname.Name, cname.Len, 
+			      DOT_RESOURCE->Name, DOT_RESOURCE_LEN)) {
 			++entry->count; /* __hfs_iget() eats one */
 			inode = hfs_iget(entry, HFS_CAP_RDIR, dentry);
 			goto done;
-		} else if (hfs_streq(&cname, DOT_FINDERINFO)) {
+		} else if (hfs_streq(cname.Name, cname.Len, 
+				     DOT_FINDERINFO->Name, 
+				     DOT_FINDERINFO_LEN)) {
 			++entry->count; /* __hfs_iget() eats one */
 			inode = hfs_iget(entry, HFS_CAP_FDIR, dentry);
 			goto done;
 		} else if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
-			   hfs_streq(&cname, DOT_ROOTINFO)) {
+			   hfs_streq(cname.Name, cname.Len, 
+				     DOT_ROOTINFO->Name, DOT_ROOTINFO_LEN)) {
 			++entry->count; /* __hfs_iget() eats one */
 			inode = hfs_iget(entry, HFS_CAP_FNDR, dentry);
 			goto done;
@@ -372,15 +355,14 @@
 void hfs_cap_drop_dentry(struct dentry *dentry, const ino_t type)
 {
   if (type == HFS_CAP_DATA) { /* given name */
-    hfs_drop_special(DOT_FINDERINFO, dentry->d_parent, dentry);
-    hfs_drop_special(DOT_RESOURCE, dentry->d_parent, dentry);
+    hfs_drop_special(dentry->d_parent, DOT_FINDERINFO, dentry);
+    hfs_drop_special(dentry->d_parent, DOT_RESOURCE, dentry);
   } else {
     struct dentry *de;
 
-    /* look for name */
-    if ((de = hfs_lookup_dentry(dentry->d_name.name,
-			       dentry->d_name.len,
-			       dentry->d_parent->d_parent))) {
+    /* given {.resource,.finderinfo}/name, look for name */
+    if ((de = hfs_lookup_dentry(dentry->d_parent->d_parent,
+				dentry->d_name.name, dentry->d_name.len))) {
       if (!de->d_inode)
 	d_drop(de);
       dput(de);
@@ -389,13 +371,13 @@
     switch (type) {
     case HFS_CAP_RSRC: /* given .resource/name */
        /* look for .finderinfo/name */
-      hfs_drop_special(DOT_FINDERINFO, dentry->d_parent->d_parent,
+      hfs_drop_special(dentry->d_parent->d_parent, DOT_FINDERINFO, 
 		       dentry);
       break;
     case HFS_CAP_FNDR: /* given .finderinfo/name. i don't this 
 			* happens. */
       /* look for .resource/name */
-      hfs_drop_special(DOT_RESOURCE, dentry->d_parent->d_parent,
+      hfs_drop_special(dentry->d_parent->d_parent, DOT_RESOURCE, 
 		       dentry);
       break;
     }
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/dir_dbl.c linux/fs/hfs/dir_dbl.c
--- v2.1.126/linux/fs/hfs/dir_dbl.c	Wed Aug 26 11:37:41 1998
+++ linux/fs/hfs/dir_dbl.c	Mon Nov  2 09:35:16 1998
@@ -147,22 +147,12 @@
 	/* Perform name-mangling */
 	hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len);
  
-	/* Check for "." */
-	if (hfs_streq(&cname, DOT)) {
-		/* this little trick skips the iget and iput */
-		d_add(dentry, dir);
-		return 0;
-	}
-
-	/* Check for "..". */
-	if (hfs_streq(&cname, DOT_DOT)) {
-		inode = hfs_iget(hfs_cat_parent(entry), HFS_DBL_DIR, dentry);
-		goto done;
-	}
+	/* no need to check for "."  or ".." */
 
 	/* Check for "%RootInfo" if in the root directory. */
 	if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
-	    hfs_streq(&cname, PCNT_ROOTINFO)) {
+	    hfs_streq(cname.Name, cname.Len, 
+		      PCNT_ROOTINFO->Name, PCNT_ROOTINFO_LEN)) {
 		++entry->count; /* __hfs_iget() eats one */
 		inode = hfs_iget(entry, HFS_DBL_HDR, dentry);
 		goto done;
@@ -445,15 +435,15 @@
   switch (type) {
   case HFS_DBL_HDR:
    /* given %name, look for name. i don't think this happens. */
-   de = hfs_lookup_dentry(dentry->d_name.name + 1, dentry->d_name.len - 1,
-			   dentry->d_parent);
+   de = hfs_lookup_dentry(dentry->d_parent,
+			  dentry->d_name.name + 1, dentry->d_name.len - 1);
     break;
   case HFS_DBL_DATA:
     /* given name, look for %name */
     tmp_name[0] = '%';
     strncpy(tmp_name + 1, dentry->d_name.name, HFS_NAMELEN - 1);
-    de = hfs_lookup_dentry(tmp_name, dentry->d_name.len + 1,
-			     dentry->d_parent);
+    de = hfs_lookup_dentry(dentry->d_parent, 
+			   tmp_name, dentry->d_name.len + 1);
   }
 
   if (de) {
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/dir_nat.c linux/fs/hfs/dir_nat.c
--- v2.1.126/linux/fs/hfs/dir_nat.c	Wed Aug 26 11:37:41 1998
+++ linux/fs/hfs/dir_nat.c	Mon Nov  2 09:35:16 1998
@@ -42,6 +42,7 @@
 #define DOT_DOT_LEN		2
 #define DOT_APPLEDOUBLE_LEN	12
 #define DOT_PARENT_LEN		7
+#define ROOTINFO_LEN            8
 
 const struct hfs_name hfs_nat_reserved1[] = {
 	{DOT_LEN,		"."},
@@ -52,13 +53,14 @@
 };
 
 const struct hfs_name hfs_nat_reserved2[] = {
-	{0,			""},
+	{ROOTINFO_LEN,			"RootInfo"},
 };
 
 #define DOT		(&hfs_nat_reserved1[0])
 #define DOT_DOT		(&hfs_nat_reserved1[1])
 #define DOT_APPLEDOUBLE	(&hfs_nat_reserved1[2])
 #define DOT_PARENT	(&hfs_nat_reserved1[3])
+#define ROOTINFO        (&hfs_nat_reserved2[0])
 
 static struct file_operations hfs_nat_dir_operations = {
 	NULL,			/* lseek - default */
@@ -153,44 +155,33 @@
 	/* Perform name-mangling */
 	hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len);
 
-	/* Check for "." */
-	if (hfs_streq(&cname, DOT)) {
-		/* this little trick skips the iget and iput */
-	        d_add(dentry, dir);
-		return 0;
-	}
-
-	/* Check for "..". */
-	if (hfs_streq(&cname, DOT_DOT)) {
-		struct hfs_cat_entry *parent;
-
-		if (dtype != HFS_NAT_NDIR) {
-			/* Case for ".." in ".AppleDouble" */
-			parent = entry;
-			++entry->count; /* __hfs_iget() eats one */
-		} else {
-			/* Case for ".." in a normal directory */
-			parent = hfs_cat_parent(entry);
-		}
-		inode = hfs_iget(parent, HFS_NAT_NDIR, dentry);
-		goto done;
-	}
+	/* no need to check for "."  or ".." */
 
 	/* Check for ".AppleDouble" if in a normal directory,
 	   and for ".Parent" in ".AppleDouble". */
 	if (dtype==HFS_NAT_NDIR) {
 		/* Check for ".AppleDouble" */
-		if (hfs_streq(&cname, DOT_APPLEDOUBLE)) {
+		if (hfs_streq(cname.Name, cname.Len, 
+			      DOT_APPLEDOUBLE->Name, DOT_APPLEDOUBLE_LEN)) {
 			++entry->count; /* __hfs_iget() eats one */
 			inode = hfs_iget(entry, HFS_NAT_HDIR, dentry);
 			goto done;
 		}
 	} else if (dtype==HFS_NAT_HDIR) {
-		if (hfs_streq(&cname, DOT_PARENT)) {
+		if (hfs_streq(cname.Name, cname.Len, 
+			      DOT_PARENT->Name, DOT_PARENT_LEN)) {
 			++entry->count; /* __hfs_iget() eats one */
 			inode = hfs_iget(entry, HFS_NAT_HDR, dentry);
 			goto done;
 		}
+
+		if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
+		    hfs_streq(cname.Name, cname.Len, 
+			      ROOTINFO->Name, ROOTINFO_LEN)) {
+			++entry->count; /* __hfs_iget() eats one */
+			inode = hfs_iget(entry, HFS_NAT_HDR, dentry);
+                        goto done;
+		}
 	}
 
 	/* Do an hfs_iget() on the mangled name. */
@@ -271,7 +262,7 @@
 		filp->f_pos = 2;
 	}
 
-	if (filp->f_pos < (dir->i_size - 1)) {
+	if (filp->f_pos < (dir->i_size - 2)) {
 		hfs_u32 cnid;
 		hfs_u8 type;
 
@@ -279,7 +270,7 @@
 		    hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) {
 			return 0;
 		}
-		while (filp->f_pos < (dir->i_size - 1)) {
+		while (filp->f_pos < (dir->i_size - 2)) {
 			if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) {
 				return 0;
 			}
@@ -302,7 +293,7 @@
 		hfs_cat_close(entry, &brec);
 	}
 
-	if (filp->f_pos == (dir->i_size - 1)) {
+	if (filp->f_pos == (dir->i_size - 2)) {
 		if (type == HFS_NAT_NDIR) {
 			/* In normal dirs entry 2 is for ".AppleDouble" */
 			if (filldir(dirent, DOT_APPLEDOUBLE->Name,
@@ -321,6 +312,19 @@
 		++filp->f_pos;
 	}
 
+	if (filp->f_pos == (dir->i_size - 1)) {
+		/* handle ROOT/.AppleDouble/RootInfo as the last entry. */
+		if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
+		    (type == HFS_NAT_HDIR)) {
+			if (filldir(dirent, ROOTINFO->Name,
+				    ROOTINFO_LEN, filp->f_pos,
+				    ntohl(entry->cnid) | HFS_NAT_HDR)) {
+				return 0;
+			}
+		}
+		++filp->f_pos;
+	}
+
 	return 0;
 }
 
@@ -337,9 +341,9 @@
   switch (type) {
   case HFS_NAT_HDR: /* given .AppleDouble/name */
     /* look for name */
-    de = hfs_lookup_dentry(dentry->d_name.name,
-			   dentry->d_name.len,
-			   dentry->d_parent->d_parent);
+    de = hfs_lookup_dentry(dentry->d_parent->d_parent,
+			   dentry->d_name.name, dentry->d_name.len);
+
     if (de) {
       if (!de->d_inode)
 	d_drop(de);
@@ -348,9 +352,10 @@
     break;
   case HFS_NAT_DATA: /* given name */
     /* look for .AppleDouble/name */
-    hfs_drop_special(DOT_APPLEDOUBLE, dentry->d_parent, dentry);
+    hfs_drop_special(dentry->d_parent, DOT_APPLEDOUBLE, dentry);
     break;
   }
+
 }
 
 /*
@@ -370,7 +375,8 @@
 	int error;
 
 	hfs_nameout(parent, &cname, dentry->d_name.name, dentry->d_name.len);
-	if (hfs_streq(&cname, DOT_APPLEDOUBLE)) {
+	if (hfs_streq(cname.Name, cname.Len,
+		      DOT_APPLEDOUBLE->Name, DOT_APPLEDOUBLE_LEN)) {
 		if (!HFS_SB(parent->i_sb)->s_afpd) {
 			/* Not in AFPD compatibility mode */
 			error = -EPERM;
@@ -415,7 +421,8 @@
 
 		hfs_nameout(dir, &cname, dentry->d_name.name, 
 			    dentry->d_name.len);
-		if (!hfs_streq(&cname, DOT_PARENT)) {
+		if (!hfs_streq(cname.Name, cname.Len,
+			       DOT_PARENT->Name, DOT_PARENT_LEN)) {
 			struct hfs_cat_entry *victim;
 			struct hfs_cat_key key;
 
@@ -465,7 +472,8 @@
 
 		hfs_nameout(old_dir, &cname, old_dentry->d_name.name,
 			    old_dentry->d_name.len);
-		if (!hfs_streq(&cname, DOT_PARENT)) {
+		if (!hfs_streq(cname.Name, cname.Len, 
+			       DOT_PARENT->Name, DOT_PARENT_LEN)) {
 			struct hfs_cat_entry *victim;
 			struct hfs_cat_key key;
 
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/extent.c linux/fs/hfs/extent.c
--- v2.1.126/linux/fs/hfs/extent.c	Mon Jan 12 14:46:24 1998
+++ linux/fs/hfs/extent.c	Mon Nov  2 09:35:16 1998
@@ -339,6 +339,7 @@
 	if (error) {
 		hfs_warn("hfs_truncate: error %d deleting an extent.\n", error);
 	}
+
 	HFS_DELETE(ext);
 }
 
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/file.c linux/fs/hfs/file.c
--- v2.1.126/linux/fs/hfs/file.c	Thu Sep 17 17:53:37 1998
+++ linux/fs/hfs/file.c	Mon Nov  2 09:35:16 1998
@@ -98,11 +98,11 @@
 		/* If writing the block, then we have exclusive access
 		   to the file until we return, so it can't have moved.
 		*/
-	       if (tmp) {
-		 hfs_cat_mark_dirty(fork->entry);
-		 return getblk(dev, tmp, HFS_SECTOR_SIZE);
-	       }
-	       return NULL;
+		if (tmp) {
+			hfs_cat_mark_dirty(fork->entry);
+			return getblk(dev, tmp, HFS_SECTOR_SIZE);
+		}
+		return NULL;
 	} else {
 		/* If reading the block, then retry since the
 		   location on disk could have changed while
@@ -220,8 +220,10 @@
 	        pos += written;
 
 	*ppos = pos;
-	if (*ppos > inode->i_size) 
+	if (*ppos > inode->i_size) {
 	        inode->i_size = *ppos;
+		mark_inode_dirty(inode);
+	}
 
 	return written;
 }
@@ -236,7 +238,6 @@
  */
 static void hfs_file_truncate(struct inode * inode)
 {
- 	/*struct inode *inode = dentry->d_inode;*/
 	struct hfs_fork *fork = HFS_I(inode)->fork;
 
 	fork->lsize = inode->i_size;
@@ -245,6 +246,7 @@
 
 	inode->i_size = fork->lsize;
 	inode->i_blocks = fork->psize;
+	mark_inode_dirty(inode);
 }
 
 /*
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/file_cap.c linux/fs/hfs/file_cap.c
--- v2.1.126/linux/fs/hfs/file_cap.c	Thu Sep 17 17:53:37 1998
+++ linux/fs/hfs/file_cap.c	Mon Nov  2 09:35:16 1998
@@ -180,6 +180,7 @@
 	if (read) {
 		inode->i_atime = CURRENT_TIME;
 		*ppos = pos;
+		mark_inode_dirty(inode);
 	}
 
 	return read;
@@ -280,6 +281,7 @@
 	}
 
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(inode);
 	return count;
 }
 
@@ -291,9 +293,8 @@
  */
 static void cap_info_truncate(struct inode *inode)
 {
-  	/*struct inode *inode = dentry->d_inode;*/
-
 	if (inode->i_size > HFS_FORK_MAX) {
 		inode->i_size = HFS_FORK_MAX;
+		mark_inode_dirty(inode);
 	}
 }
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/file_hdr.c linux/fs/hfs/file_hdr.c
--- v2.1.126/linux/fs/hfs/file_hdr.c	Thu Sep 17 17:53:37 1998
+++ linux/fs/hfs/file_hdr.c	Mon Nov  2 09:35:16 1998
@@ -559,6 +559,7 @@
 	if (read) {
 		inode->i_atime = CURRENT_TIME;
 		*ppos = pos;
+		mark_inode_dirty(inode);
 	}
 	return read;
 }
@@ -874,6 +875,7 @@
 	        if (pos > inode->i_size)
 		        inode->i_size = pos;
 	        inode->i_mtime = inode->i_atime = CURRENT_TIME;
+		mark_inode_dirty(inode);
 	}
 	return written;
 }
@@ -887,7 +889,6 @@
  */
 static void hdr_truncate(struct inode *inode)
 {
-  	/*struct inode *inode = dentry->d_inode;*/
 	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
 	struct hfs_hdr_layout *layout;
 	size_t size = inode->i_size;
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/hfs.h linux/fs/hfs/hfs.h
--- v2.1.126/linux/fs/hfs/hfs.h	Tue Mar 17 22:18:15 1998
+++ linux/fs/hfs/hfs.h	Mon Nov  2 09:35:16 1998
@@ -64,12 +64,16 @@
 #define HFS_EXT_CNID	3	/* EXTents B-tree */
 #define HFS_CAT_CNID	4	/* CATalog B-tree */
 #define HFS_BAD_CNID	5	/* BAD blocks file */
+#define HFS_ALLOC_CNID  6       /* ALLOCation file (HFS+) */
+#define HFS_START_CNID  7       /* STARTup file (HFS+) */
+#define HFS_ATTR_CNID   8       /* ATTRibutes file (HFS+) */
+#define HFS_EXCH_CNID  15       /* ExchangeFiles temp id */
 
 /* values for hfs_cat_rec.cdrType */
-#define HFS_CDR_DIR	0x01
-#define HFS_CDR_FIL	0x02
-#define HFS_CDR_THD	0x03
-#define HFS_CDR_FTH	0x04
+#define HFS_CDR_DIR    0x01    /* folder (directory) */
+#define HFS_CDR_FIL    0x02    /* file */
+#define HFS_CDR_THD    0x03    /* folder (directory) thread */
+#define HFS_CDR_FTH    0x04    /* file thread */
 
 /* legal values for hfs_ext_key.FkType and hfs_file.fork */
 #define HFS_FK_DATA	0x00
@@ -484,42 +488,43 @@
 extern int hfs_part_find(hfs_sysmdb, int, int, hfs_s32 *, hfs_s32 *);
 
 /* string.c */
-extern unsigned long hfs_strhash(const struct hfs_name *);
-extern int hfs_strcmp(const struct hfs_name *, const struct hfs_name *);
-extern int hfs_streq(const struct hfs_name *, const struct hfs_name *);
+extern unsigned int hfs_strhash(const unsigned char *, unsigned int);
+extern int hfs_strcmp(const unsigned char *, unsigned int, 
+		      const unsigned char *, unsigned int);
+extern int hfs_streq(const unsigned char *, unsigned int, 
+		     const unsigned char *, unsigned int);
 extern void hfs_tolower(unsigned char *, int);
 
-extern __inline__ struct dentry 
-*hfs_lookup_dentry(const char *name, const int len, 
-		   struct dentry *base)
+static __inline__ struct dentry 
+*hfs_lookup_dentry(struct dentry *base, const char *name, const int len)
 {
   struct qstr this;
 
   this.name = name;
   this.len = len;
-  this.hash = full_name_hash(name, len);
+  this.hash = hfs_strhash(name, len);
 
   return d_lookup(base, &this);
 }
 
-/* drop a dentry for one of the special subdirectories */
-extern __inline__ void hfs_drop_special(const struct hfs_name *name,
-					struct dentry *base,
+/* drop a dentry for one of the special directories.
+ * it's in the form of base/name/dentry. */
+static __inline__ void hfs_drop_special(struct dentry *base,
+					const struct hfs_name *name,
 					struct dentry *dentry)
 {
   struct dentry *dparent, *de;
   
-  dparent = hfs_lookup_dentry(name->Name, name->Len, base);
+  dparent = hfs_lookup_dentry(base, name->Name, name->Len);
   if (dparent) {
-    de = hfs_lookup_dentry(dentry->d_name.name, dentry->d_name.len,
-			   dparent);
-    dput(dparent);
-
-    if (de) {
-      if (!de->d_inode)
-	d_drop(de);
-      dput(de);
-    }
+	  de = hfs_lookup_dentry(dparent, dentry->d_name.name, 
+				 dentry->d_name.len);
+	  if (de) {
+		  if (!de->d_inode)
+			  d_drop(de);
+		  dput(de);
+	  }
+	  dput(dparent);
   }
 }
 
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/inode.c linux/fs/hfs/inode.c
--- v2.1.126/linux/fs/hfs/inode.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/hfs/inode.c	Mon Nov  2 09:35:16 1998
@@ -73,6 +73,9 @@
  */
 void hfs_put_inode(struct inode * inode)
 {
+	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
+
+	hfs_cat_put(entry);
 	if (inode->i_count == 1) {
 	  struct hfs_hdr_layout *tmp = HFS_I(inode)->layout;
 
@@ -243,7 +246,7 @@
 	if (inode->i_dev != sb->s_dev) {
 	        iput(inode); /* automatically does an hfs_cat_put */
 		inode = NULL;
-	} else if (!inode->i_mode) {
+	} else if (!inode->i_mode || (*sys_entry == NULL)) {
 		/* Initialize the inode */
 		struct hfs_sb_info *hsb = HFS_SB(sb);
 
@@ -266,8 +269,7 @@
 		inode->i_mode &= ~hsb->s_umask;
 
 		if (!inode->i_mode) {
-			clear_inode(inode);
-			hfs_cat_put(entry);
+			iput(inode); /* does an hfs_cat_put */
 			inode = NULL;
 		} else
 			*sys_entry = dentry; /* cache dentry */
@@ -398,7 +400,7 @@
 		struct hfs_dir *hdir = &entry->u.dir;
 
 		inode->i_blocks = 0;
-		inode->i_size = hdir->files + hdir->dirs + 3;
+		inode->i_size = hdir->files + hdir->dirs + 4;
 		inode->i_mode = S_IRWXUGO | S_IFDIR;
 		HFS_I(inode)->dir_size = 1;
 		if (type == HFS_NAT_NDIR) {
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/mdb.c linux/fs/hfs/mdb.c
--- v2.1.126/linux/fs/hfs/mdb.c	Thu Sep 17 17:53:37 1998
+++ linux/fs/hfs/mdb.c	Mon Nov  2 09:35:16 1998
@@ -99,24 +99,30 @@
 	memset(mdb, 0, sizeof(*mdb));
 	mdb->magic = HFS_MDB_MAGIC;
 	mdb->sys_mdb = sys_mdb;
+	INIT_LIST_HEAD(&mdb->entry_dirty);  
 
 	/* See if this is an HFS filesystem */
 	buf = hfs_buffer_get(sys_mdb, part_start + HFS_MDB_BLK, 1);
 	if (!hfs_buffer_ok(buf)) {
 		hfs_warn("hfs_fs: Unable to read superblock\n");
+		HFS_DELETE(mdb);
 		goto bail2;
 	}
+
 	raw = (struct raw_mdb *)hfs_buffer_data(buf);
 	if (hfs_get_ns(raw->drSigWord) != htons(HFS_SUPER_MAGIC)) {
 		hfs_buffer_put(buf);
+		HFS_DELETE(mdb);
 		goto bail2;
 	}
 	mdb->buf = buf;
-
+	
 	bs = hfs_get_hl(raw->drAlBlkSiz);
 	if (!bs || bs > HFS_USHRT_MAX || (bs & (HFS_SECTOR_SIZE-1))) {
 		hfs_warn("hfs_fs: bad allocation block size %d != 512\n", bs);
-		goto bail1;
+		hfs_buffer_put(buf);
+		HFS_DELETE(mdb);
+		goto bail2;
 	}
 	mdb->alloc_blksz = bs >> HFS_SECTOR_SIZE_BITS;
 
@@ -127,7 +133,7 @@
 	mdb->backup_date = hfs_get_hl(raw->drVolBkUp);
 	mdb->clumpablks  = (hfs_get_hl(raw->drClpSiz) / mdb->alloc_blksz)
 						 >> HFS_SECTOR_SIZE_BITS;
-	memcpy(mdb->vname, raw->drVN, 28);
+	memcpy(mdb->vname, raw->drVN, sizeof(raw->drVN));
 
 	/* These parameters are read from and written to the MDB */
 	mdb->modify_date  = hfs_get_nl(raw->drLsMod);
@@ -139,8 +145,8 @@
 	mdb->root_dirs    = hfs_get_hs(raw->drNmRtDirs);
 	mdb->file_count   = hfs_get_hl(raw->drFilCnt);
 	mdb->dir_count    = hfs_get_hl(raw->drDirCnt);
-	
-	/* TRY to get the alternate (backup) MDB */
+
+	/* TRY to get the alternate (backup) MDB. */
 	lcv = mdb->fs_start + mdb->fs_ablocks * mdb->alloc_blksz;
 	limit = lcv + mdb->alloc_blksz;
 	for (; lcv < limit; ++lcv) {
@@ -148,20 +154,21 @@
 		if (hfs_buffer_ok(buf)) {
 			struct raw_mdb *tmp =
 				(struct raw_mdb *)hfs_buffer_data(buf);
-
+			
 			if (hfs_get_ns(tmp->drSigWord) ==
-						htons(HFS_SUPER_MAGIC)) {
+			    htons(HFS_SUPER_MAGIC)) {
 				mdb->alt_buf = buf;
 				break;
 			}
-			hfs_buffer_put(buf);
 		}
+		hfs_buffer_put(buf);
 	}
+	
 	if (mdb->alt_buf == NULL) {
 		hfs_warn("hfs_fs: unable to locate alternate MDB\n");
 		hfs_warn("hfs_fs: continuing without an alternate MDB\n");
 	}
-
+	
 	/* read in the bitmap */
 	block = hfs_get_hs(raw->drVBMSt) + part_start;
 	bmbuf = mdb->bitmap;
@@ -253,23 +260,29 @@
 	hfs_put_hl(mdb->file_count,    raw->drFilCnt);
 	hfs_put_hl(mdb->dir_count,     raw->drDirCnt);
 
-	/* write MDB to disk */
-	hfs_buffer_dirty(mdb->buf);
-
-       	/* write the backup MDB, not returning until it is written */
+       	/* write the backup MDB, not returning until it is written. 
+         * we only do this when either the catalog or extents overflow
+         * files grow. */
         if (backup && hfs_buffer_ok(mdb->alt_buf)) {
-                memcpy(hfs_buffer_data(mdb->alt_buf),
-		       hfs_buffer_data(mdb->buf), HFS_SECTOR_SIZE);
-                hfs_buffer_dirty(mdb->alt_buf);
-                hfs_buffer_sync(mdb->alt_buf);
+		struct raw_mdb *tmp = (struct raw_mdb *)
+			hfs_buffer_data(mdb->alt_buf);
+		
+		if ((hfs_get_hl(tmp->drCTFlSize) < 
+		     hfs_get_hl(raw->drCTFlSize)) ||
+		    (hfs_get_hl(tmp->drXTFlSize) <
+		     hfs_get_hl(raw->drXTFlSize))) {
+			memcpy(hfs_buffer_data(mdb->alt_buf), 
+			       hfs_buffer_data(mdb->buf), HFS_SECTOR_SIZE); 
+			hfs_buffer_dirty(mdb->alt_buf);
+			hfs_buffer_sync(mdb->alt_buf);
+		}
         }
 }
 
 /*
  * hfs_mdb_put()
  *
- * Release the resources associated with the in-core MDB.
- */
+ * Release the resources associated with the in-core MDB.  */
 void hfs_mdb_put(struct hfs_mdb *mdb, int readonly) {
 	int lcv;
 
@@ -287,7 +300,7 @@
 
 	/* update volume attributes */
 	if (!readonly) {
-		struct raw_mdb *raw =
+		struct raw_mdb *raw = 
 				(struct raw_mdb *)hfs_buffer_data(mdb->buf);
 		hfs_put_ns(mdb->attrib, raw->drAtrb);
 		hfs_buffer_dirty(mdb->buf);
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/string.c linux/fs/hfs/string.c
--- v2.1.126/linux/fs/hfs/string.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/hfs/string.c	Mon Nov  2 09:35:16 1998
@@ -81,13 +81,13 @@
 /*
  * Hash a string to an integer in a case-independent way
  */
-unsigned long hfs_strhash(const struct hfs_name *cname)
+unsigned int hfs_strhash(const unsigned char *name, unsigned int len)
 {
 	unsigned long hash = init_name_hash();
-	unsigned int i;
-	for (i = 0; i < cname->Len; i++) {
-	        hash = partial_name_hash(caseorder[cname->Name[i]], hash);
-	}
+
+	while (len--)
+	        hash = partial_name_hash(caseorder[*name++],
+					 hash);
 	return end_name_hash(hash);
 }
 
@@ -98,45 +98,34 @@
  * Equivalent to ARDI's call:
  *	ROMlib_RelString(s1+1, s2+1, true, false, (s1[0]<<16) | s2[0])
  */
-int hfs_strcmp(const struct hfs_name *s1, const struct hfs_name *s2)
+int hfs_strcmp(const unsigned char *s1, unsigned int len1,
+	       const unsigned char *s2, unsigned int len2)
 {
 	int len, tmp;
-	const unsigned char *p1, *p2;
-
-	if (!s1 || !s2) {
-		return 0;
-	}
 
-	len = (s1->Len > s2->Len) ? s2->Len : s1->Len;
-	p1 = s1->Name;
-	p2 = s2->Name;
+	len = (len1 > len2) ? len2 : len1;
 
 	while (len--) {
-		if ((tmp = (int)caseorder[*(p1++)]-(int)caseorder[*(p2++)])) {
+		if ((tmp = (int)caseorder[*(s1++)] -
+		     (int)caseorder[*(s2++)])) {
 			return tmp;
 		}
 	}
-	return s1->Len - s2->Len;
+	return len1 - len2;
 }
 
 /*
  * Test for equality of two strings in the HFS filename character ordering.
  */
-int hfs_streq(const struct hfs_name *s1, const struct hfs_name *s2)
+int hfs_streq(const unsigned char *s1, unsigned int len1,
+	      const unsigned char *s2, unsigned int len2)
 {
-	int len;
-	const unsigned char *p1, *p2;
-
-	if (!s1 || !s2 || (s1->Len != s2->Len)) {
+	if (len1 != len2) {
 		return 0;
 	}
 
-	len = s1->Len;
-	p1 = s1->Name;
-	p2 = s2->Name;
-
-	while (len--) {
-		if (caseorder[*(p1++)] != caseorder[*(p2++)]) {
+	while (len1--) {
+		if (caseorder[*(s1++)] != caseorder[*(s2++)]) {
 			return 0;
 		}
 	}
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/super.c linux/fs/hfs/super.c
--- v2.1.126/linux/fs/hfs/super.c	Thu Aug 27 19:56:29 1998
+++ linux/fs/hfs/super.c	Mon Nov  2 09:35:17 1998
@@ -34,7 +34,7 @@
 
 /*================ Forward declarations ================*/
 
-static void hfs_read_inode(struct inode *inode);
+static void hfs_read_inode(struct inode *);
 static void hfs_put_super(struct super_block *);
 static int hfs_statfs(struct super_block *, struct statfs *, int);
 static void hfs_write_super(struct super_block *);
@@ -45,7 +45,7 @@
 	hfs_read_inode,		/* read_inode */
 	NULL,			/* write_inode */
 	hfs_put_inode,		/* put_inode     - in inode.c */
-	NULL,                   /* delete inode */
+	NULL,                   /* delete_inode  */
 	hfs_notify_change,	/* notify_change - in inode.c */
 	hfs_put_super,		/* put_super */
 	hfs_write_super,	/* write_super */
@@ -75,7 +75,6 @@
   inode->i_op = NULL;
 }
 
-
 /*
  * hfs_write_super()
  *
@@ -134,8 +133,6 @@
 	set_blocksize(sb->s_dev, BLOCK_SIZE);
 
 	MOD_DEC_USE_COUNT;
-
-	return;
 }
 
 /*
@@ -145,7 +142,7 @@
  * HFS filesystems.  The purpose is to return various data about the
  * filesystem.
  *
- * XXX: changed f_files/f_ffree to reflect the fs_ablock/free_ablocks.
+ * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks.
  */
 static int hfs_statfs(struct super_block *sb, struct statfs *buf, int len)
 {
@@ -434,14 +431,13 @@
 
 	if (!mdb) {
 		if (!silent) {
-			printk("VFS: Can't find a HFS filesystem on dev %s.\n",
+			hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n",
 			       kdevname(dev));
 		}
 		goto bail2;
 	}
-	HFS_SB(s)->s_mdb = mdb;
-	INIT_LIST_HEAD(&mdb->entry_dirty);
 
+	HFS_SB(s)->s_mdb = mdb;
 	if (HFS_ITYPE(mdb->next_id) != 0) {
 		hfs_warn("hfs_fs: too many files.\n");
 		goto bail1;
@@ -480,8 +476,8 @@
 	hfs_mdb_put(mdb, s->s_flags & MS_RDONLY);
 bail2:
 	set_blocksize(dev, BLOCK_SIZE);
-	MOD_DEC_USE_COUNT;
 	unlock_super(s);
+	MOD_DEC_USE_COUNT;
 bail3:
 	s->s_dev = 0;
 	return NULL;	
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/sysdep.c linux/fs/hfs/sysdep.c
--- v2.1.126/linux/fs/hfs/sysdep.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/hfs/sysdep.c	Mon Nov  2 09:35:17 1998
@@ -61,29 +61,23 @@
 /* hfs_strhash now uses the same hashing function as the dcache. */
 static int hfs_hash_dentry(struct dentry *dentry, struct qstr *this)
 {
-        struct hfs_name cname;
-	
-	if ((cname.Len = this->len) > HFS_NAMELEN)
+	if (this->len > HFS_NAMELEN)
 	        return 0;
 	
-	strncpy(cname.Name, this->name, this->len);
-	this->hash = hfs_strhash(&cname);
+	this->hash = hfs_strhash(this->name, this->len);
 	return 0;
 }
 
+/* return 1 on failure and 0 on success */
 static int hfs_compare_dentry(struct dentry *dentry, struct qstr *a, 
 			      struct qstr *b)
 {
-	struct hfs_name s1, s2;
-
 	if (a->len != b->len) return 1;
 
-	if ((s1.Len = s2.Len = a->len) > HFS_NAMELEN)
+	if (a->len > HFS_NAMELEN)
 	  return 1;
 
-	strncpy(s1.Name, a->name, s1.Len);
-	strncpy(s2.Name, b->name, s2.Len);
-	return hfs_streq(&s1, &s2);
+	return !hfs_streq(a->name, a->len, b->name, b->len);
 }
 
 static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode)
@@ -91,6 +85,5 @@
 	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
 
 	entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL;
-        hfs_cat_put(entry);
 	iput(inode);
 }
diff -u --recursive --new-file v2.1.126/linux/fs/hfs/version.c linux/fs/hfs/version.c
--- v2.1.126/linux/fs/hfs/version.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/hfs/version.c	Mon Nov  2 09:35:17 1998
@@ -7,4 +7,4 @@
  * This file contains the version string for this release.
  */
 
-const char hfs_version[]="0.95+asun3";
+const char hfs_version[]="0.96";
diff -u --recursive --new-file v2.1.126/linux/fs/lockd/clntlock.c linux/fs/lockd/clntlock.c
--- v2.1.126/linux/fs/lockd/clntlock.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/lockd/clntlock.c	Sat Oct 31 10:17:23 1998
@@ -71,7 +71,11 @@
 	 * a 1 minute timeout would do. See the comment before
 	 * nlmclnt_lock for an explanation.
 	 */
-	current->timeout = jiffies + 30 * HZ;
+	/*
+	 * FIXME, can we be not interruptible and so be allowed to use
+	 * a timeout here? -arca
+	 */
+/*  	current->timeout = jiffies + 30 * HZ; */
 	sleep_on(&block.b_wait);
 
 	for (head = &nlm_blocked; *head; head = &(*head)->b_next) {
diff -u --recursive --new-file v2.1.126/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c
--- v2.1.126/linux/fs/lockd/clntproc.c	Wed Aug 26 11:37:41 1998
+++ linux/fs/lockd/clntproc.c	Sat Oct 31 10:17:22 1998
@@ -174,9 +174,9 @@
 nlmclnt_grace_wait(struct nlm_host *host)
 {
 	if (!host->h_reclaiming)
-		current->timeout = jiffies + 10 * HZ;
-	interruptible_sleep_on(&host->h_gracewait);
-	current->timeout = 0;
+		interruptible_sleep_on_timeout(&host->h_gracewait, 10*HZ);
+	else
+		interruptible_sleep_on(&host->h_gracewait);
 	return signalled()? -ERESTARTSYS : 0;
 }
 
@@ -194,10 +194,8 @@
 		if (call)
 			return call;
 		printk("nlmclnt_alloc_call: failed, waiting for memory\n");
-		current->timeout = jiffies + 5 * HZ;
 		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		current->timeout = 0;
+		schedule_timeout(5*HZ);
 	}
 	return NULL;
 }
@@ -247,9 +245,7 @@
 		}
 
 		/* Back off a little and try again */
-		current->timeout = jiffies + 15 * HZ;
-		interruptible_sleep_on(&host->h_gracewait);
-		current->timeout = 0;
+		interruptible_sleep_on_timeout(&host->h_gracewait, 15*HZ);
 	} while (!signalled());
 
 	return -ERESTARTSYS;
diff -u --recursive --new-file v2.1.126/linux/fs/lockd/svc.c linux/fs/lockd/svc.c
--- v2.1.126/linux/fs/lockd/svc.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/lockd/svc.c	Mon Nov  2 09:37:52 1998
@@ -46,7 +46,7 @@
 unsigned long			nlmsvc_grace_period = 0;
 unsigned long			nlmsvc_timeout = 0;
 
-static struct wait_queue *	lockd_start = NULL;
+static struct semaphore lockd_start = MUTEX_LOCKED;
 static struct wait_queue *	lockd_exit = NULL;
 
 /*
@@ -73,7 +73,7 @@
 	 * Let our maker know we're running.
 	 */
 	nlmsvc_pid = current->pid;
-	wake_up(&lockd_start);
+	up(&lockd_start);
 
 	exit_mm(current);
 	current->session = 1;
@@ -121,6 +121,7 @@
 	 */
 	while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid)
 	{
+		long timeout = MAX_SCHEDULE_TIMEOUT;
 		if (signalled()) {
 			spin_lock_irq(&current->sigmask_lock);
 			flush_signals(current);
@@ -134,7 +135,7 @@
 		 * during grace period).
 		 */
 		if (!nlmsvc_grace_period) {
-			current->timeout = nlmsvc_retry_blocked();
+			timeout = nlmsvc_retry_blocked() - jiffies;
 		} else if (nlmsvc_grace_period < jiffies)
 			nlmsvc_grace_period = 0;
 
@@ -142,7 +143,7 @@
 		 * Find a socket with data available and call its
 		 * recvfrom routine.
 		 */
-		if ((err = svc_recv(serv, rqstp)) == -EAGAIN)
+		if ((err = svc_recv(serv, rqstp, timeout)) == -EAGAIN)
 			continue;
 		if (err < 0) {
 			if (err != -EINTR)
@@ -250,7 +251,7 @@
 			"lockd_up: create thread failed, error=%d\n", error);
 		goto destroy_and_out;
 	}
-	sleep_on(&lockd_start);
+	down(&lockd_start);
 
 	/*
 	 * Note: svc_serv structures have an initial use count of 1,
@@ -291,9 +292,7 @@
 	 * the lockd semaphore, we can't wait around forever ...
 	 */
 	current->sigpending = 0;
-	current->timeout = jiffies + HZ;
-	interruptible_sleep_on(&lockd_exit);
-	current->timeout = 0;
+	interruptible_sleep_on_timeout(&lockd_exit, HZ);
 	if (nlmsvc_pid) {
 		printk(KERN_WARNING 
 			"lockd_down: lockd failed to exit, clearing pid\n");
diff -u --recursive --new-file v2.1.126/linux/fs/namei.c linux/fs/namei.c
--- v2.1.126/linux/fs/namei.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/namei.c	Thu Nov  5 09:54:04 1998
@@ -28,10 +28,23 @@
 #include <asm/unaligned.h>
 #include <asm/semaphore.h>
 #include <asm/spinlock.h>
-#include <asm/namei.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
+/*
+ * The bitmask for a lookup event:
+ *  - follow links at the end
+ *  - require a directory
+ *  - ending slashes ok even for nonexistent files
+ *  - internal "there are more path compnents" flag
+ */
+#define LOOKUP_FOLLOW		(1)
+#define LOOKUP_DIRECTORY	(2)
+#define LOOKUP_SLASHOK		(4)
+#define LOOKUP_CONTINUE		(8)
+
+#include <asm/namei.h>
+
 /* This can be removed after the beta phase. */
 #define CACHE_SUPERVISE	/* debug the correctness of dcache entries */
 #undef DEBUG		/* some other debugging */
@@ -282,18 +295,6 @@
 	return result;
 }
 
-/*
- * The bitmask for a lookup event:
- *  - follow links at the end
- *  - require a directory
- *  - ending slashes ok even for nonexistent files
- *  - internal "there are more path compnents" flag
- */
-#define LOOKUP_FOLLOW		(1)
-#define LOOKUP_DIRECTORY	(2)
-#define LOOKUP_SLASHOK		(4)
-#define LOOKUP_CONTINUE		(8)
-
 static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow)
 {
 	struct inode * inode = dentry->d_inode;
@@ -342,10 +343,10 @@
 	if (*name == '/') {
 		if (base)
 			dput(base);
-		base = dget(current->fs->root);
 		do {
 			name++;
 		} while (*name == '/');
+		base = dget(current->fs->root);
 	} else if (!base) {
 		base = dget(current->fs->pwd);
 	}
@@ -626,7 +627,7 @@
 	if (!inode)
 		goto exit;
 
-	error = -EACCES;
+	error = -ELOOP;
 	if (S_ISLNK(inode->i_mode))
 		goto exit;
 	
@@ -1195,7 +1196,7 @@
 
 	error = -ENOENT;
 	if (!old_dentry->d_inode)
-		goto exit;
+		goto exit_old;
 
 	{
 		unsigned int flags = 0;
diff -u --recursive --new-file v2.1.126/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v2.1.126/linux/fs/ncpfs/sock.c	Tue Mar 10 10:03:34 1998
+++ linux/fs/ncpfs/sock.c	Thu Nov  5 09:58:46 1998
@@ -94,7 +94,7 @@
 	poll_table wait_table;
 	struct poll_table_entry entry;
 	int init_timeout, max_timeout;
-	int timeout;
+	int timeout; long tmp_timeout;
 	int retrans;
 	int major_timeout_seen;
 	int acknowledge_seen;
@@ -173,6 +173,7 @@
 		wait_table.entry = &entry;
 		current->state = TASK_INTERRUPTIBLE;
 		if (!(file->f_op->poll(file, &wait_table) & POLLIN)) {
+			int timed_out;
 			if (timeout > max_timeout) {
 				/* JEJB/JSP 2/7/94
 				 * This is useful to see if the system is
@@ -182,17 +183,15 @@
 				}
 				timeout = max_timeout;
 			}
-			current->timeout = jiffies + timeout;
-			schedule();
+			timed_out = !schedule_timeout(timeout);
 			remove_wait_queue(entry.wait_address, &entry.wait);
 			fput(file);
 			current->state = TASK_RUNNING;
 			if (signal_pending(current)) {
-				current->timeout = 0;
 				result = -ERESTARTSYS;
 				break;
 			}
-			if (!current->timeout) {
+			if (timed_out) {
 				if (n < retrans)
 					continue;
 				if (server->m.flags & NCP_MOUNT_SOFT) {
@@ -208,8 +207,7 @@
 				}
 				major_timeout_seen = 1;
 				continue;
-			} else
-				current->timeout = 0;
+			}
 		} else if (wait_table.nr) {
 			remove_wait_queue(entry.wait_address, &entry.wait);
 			fput(file);
diff -u --recursive --new-file v2.1.126/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.1.126/linux/fs/nfs/inode.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/nfs/inode.c	Sat Oct 31 10:17:23 1998
@@ -106,10 +106,10 @@
 printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
 #endif
 		nfs_invalidate_pages(inode);
-		while (NFS_WRITEBACK(inode) != NULL && jiffies < timeout) {
+		while (NFS_WRITEBACK(inode) != NULL &&
+		       time_before(jiffies, timeout)) {
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + HZ/10;
-			schedule();
+			schedule_timeout(HZ/10);
 		}
 		current->state = TASK_RUNNING;
 		if (NFS_WRITEBACK(inode) != NULL)
diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/auth.c linux/fs/nfsd/auth.c
--- v2.1.126/linux/fs/nfsd/auth.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/nfsd/auth.c	Sat Oct 31 10:49:35 1998
@@ -41,7 +41,21 @@
 		current->fsgid = cred->cr_gid;
 	else
 		current->fsgid = exp->ex_anon_gid;
-	for (i = 0; i < NGROUPS; i++)
-		current->groups[i] = cred->cr_groups[i];
+	for (i = 0; i < NGROUPS; i++) {
+		gid_t group = cred->cr_groups[i];
+		if (group == (gid_t) NOGROUP)
+			break;
+		current->groups[i] = group;
+	}
+	current->ngroups = i;
+
+	if ((cred->cr_uid)) {
+		cap_lower(current->cap_effective, CAP_DAC_OVERRIDE);
+		cap_lower(current->cap_effective, CAP_DAC_READ_SEARCH);
+	} else {
+		cap_raise(current->cap_effective, CAP_DAC_OVERRIDE);
+		cap_raise(current->cap_effective, CAP_DAC_READ_SEARCH);
+	}
+
 	rqstp->rq_userset = 1;
 }
diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.1.126/linux/fs/nfsd/export.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/nfsd/export.c	Tue Oct 27 15:15:35 1998
@@ -457,14 +457,17 @@
 	   char *path, struct knfs_fh *f)
 {
 	struct svc_export	*exp;
-	struct dentry		*dentry;
+	struct dentry		*dentry = NULL;
 	struct inode		*inode;
 	struct svc_fh		fh;
 	int			err;
 
+	err = -EPERM;
 	if (path) {
-		dentry = lookup_dentry(path, NULL, 0);
-
+		if (!(dentry = lookup_dentry(path, NULL, 0))) {
+			printk("nfsd: exp_rootfh path not found %s", path);
+			return -EPERM;
+		}
 		dev = dentry->d_inode->i_dev;
 		ino = dentry->d_inode->i_ino;
 	
@@ -474,17 +477,21 @@
 	} else {
 		dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
 		         clp->cl_ident, dev, ino);
-		exp = exp_get(clp, dev, ino);
-		dentry = dget(exp->ex_dentry);
+		if ((exp = exp_get(clp, dev, ino)))
+			if (!(dentry = dget(exp->ex_dentry))) {
+				printk("exp_rootfh: Aieee, NULL dentry\n");
+				return -EPERM;
+			}
 	}
-	err = -EPERM;
-	if (!exp)
+	if (!exp) {
+		dprintk("nfsd: exp_rootfh export not found.\n");
 		goto out;
+	}
 
 	inode = dentry->d_inode;
 	if (!inode) {
 		printk("exp_rootfh: Aieee, NULL d_inode\n");
-		return -EPERM;
+		goto out;
 	}
 	if (inode->i_dev != dev || inode->i_ino != ino) {
 		printk("exp_rootfh: Aieee, ino/dev mismatch\n");
diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.1.126/linux/fs/nfsd/nfsfh.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/nfsd/nfsfh.c	Tue Oct 27 15:15:35 1998
@@ -1061,31 +1061,6 @@
 		goto out;
 
 	/*
-	 * Security: Check that the export is valid for dentry <gam3@acm.org>
-	 */
-	if (fh->fh_dev != fh->fh_xdev) {
-		printk("fh_verify: Security: export on other device"
-		       " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
-		goto out;
-	} else {
-		struct dentry *tdentry = dentry;
-
-		do {
-			if (exp->ex_dentry == tdentry) {
-				error = 0;
-				break;
-			}
-			if (tdentry->d_parent == tdentry)
-				break;
-		} while ((tdentry = tdentry->d_parent));
-		if (error) {
-			printk("fh_verify: Security: %s/%s bad export.\n",
-			       dentry->d_parent->d_name.name,
-			       dentry->d_name.name);
-			goto out;
-		}
-	}
-	/*
 	 * Note:  it's possible the returned dentry won't be the one in the
 	 * file handle.  We can correct the file handle for our use, but
 	 * unfortunately the client will keep sending the broken one.  Let's
@@ -1105,6 +1080,7 @@
 check_type:
 	dentry = fhp->fh_dentry;
 	inode = dentry->d_inode;
+	exp = fhp->fh_export;
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
 		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
 		goto out;
@@ -1114,9 +1090,45 @@
 		goto out;
 	}
 
+	/*
+	 * Security: Check that the export is valid for dentry <gam3@acm.org>
+	 */
+	if (fh->fh_dev != fh->fh_xdev) {
+		printk("fh_verify: Security: export on other device"
+		       " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
+		goto out;
+	} else if (exp->ex_dentry != dentry) {
+		struct dentry *tdentry = dentry;
+		int err2 = 0;
+
+		error = nfserr_stale;
+		do {
+			tdentry = tdentry->d_parent;
+			if (exp->ex_dentry == tdentry) {
+				error = 0;
+				break;
+			}
+			if ((err2 = nfsd_permission(exp, tdentry, MAY_READ))) {
+				error = err2;
+#ifdef NFSD_PARANOIA
+				goto out1;
+#else
+				goto out;
+#endif
+			}
+		} while ((tdentry != tdentry->d_parent));
+		if (error) {
+			printk("fh_verify: Security: %s/%s bad export.\n",
+			       dentry->d_parent->d_name.name,
+			       dentry->d_name.name);
+			goto out;
+		}
+	}
+
 	/* Finally, check access permissions. */
-	error = nfsd_permission(fhp->fh_export, dentry, access);
+	error = nfsd_permission(exp, dentry, access);
 #ifdef NFSD_PARANOIA
+out1:
 if (error)
 printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, access, error);
diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- v2.1.126/linux/fs/nfsd/nfssvc.c	Wed Sep  9 14:51:09 1998
+++ linux/fs/nfsd/nfssvc.c	Sat Oct 31 10:37:14 1998
@@ -115,7 +115,7 @@
 		 * Find a socket with data available and call its
 		 * recvfrom routine.
 		 */
-		while ((err = svc_recv(serv, rqstp)) == -EAGAIN)
+		while ((err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT)) == -EAGAIN)
 			;
 		if (err < 0)
 			break;
diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.1.126/linux/fs/nfsd/vfs.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/nfsd/vfs.c	Wed Nov  4 10:11:14 1998
@@ -14,6 +14,7 @@
  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
  */
 
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -554,13 +555,10 @@
 		if (EX_WGATHER(exp) && (inode->i_writecount > 1
 		 || (last_ino == inode->i_ino && last_dev == inode->i_dev))) {
 #if 0
-			current->timeout = jiffies + 10 * HZ / 1000;
-			interruptible_sleep_on(&inode->i_wait);
+			interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000);
 #else
 			dprintk("nfsd: write defer %d\n", current->pid);
-			current->need_resched = 1;
-			current->timeout = jiffies + HZ / 100;
-			schedule();
+			schedule_timeout((HZ+99)/100);
 			dprintk("nfsd: write resume %d\n", current->pid);
 #endif
 		}
diff -u --recursive --new-file v2.1.126/linux/fs/nls/nls_base.c linux/fs/nls/nls_base.c
--- v2.1.126/linux/fs/nls/nls_base.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/nls/nls_base.c	Sun Oct 25 14:16:35 1998
@@ -49,7 +49,6 @@
 	int c0, c, nc;
 	struct utf8_table *t;
   
-	printk("utf8_mbtowc\n");
 	nc = 0;
 	c0 = *s;
 	l = c0;
@@ -80,11 +79,9 @@
 	const __u8 *ip;
 	int size;
 
-	printk("\nutf8_mbstowcs: n=%d\n", n);
 	op = pwcs;
 	ip = s;
 	while (*ip && n > 0) {
-		printk(" %02x", *ip);
 		if (*ip & 0x80) {
 			size = utf8_mbtowc(op, ip, n);
 			if (size == -1) {
diff -u --recursive --new-file v2.1.126/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.126/linux/fs/proc/array.c	Fri Oct 23 22:01:22 1998
+++ linux/fs/proc/array.c	Sat Oct 31 10:17:22 1998
@@ -887,7 +887,7 @@
 		tsk->times.tms_cstime,
 		priority,
 		nice,
-		tsk->timeout,
+		0UL /* removed */,
 		tsk->it_real_value,
 		tsk->start_time,
 		vsize,
diff -u --recursive --new-file v2.1.126/linux/fs/select.c linux/fs/select.c
--- v2.1.126/linux/fs/select.c	Wed Jul  1 19:38:56 1998
+++ linux/fs/select.c	Sat Oct 31 10:17:22 1998
@@ -124,28 +124,25 @@
 #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
 #define POLLEX_SET (POLLPRI)
 
-int do_select(int n, fd_set_buffer *fds, unsigned long timeout)
+int do_select(int n, fd_set_buffer *fds, long *timeout)
 {
 	poll_table wait_table, *wait;
-	int retval;
-	int i;
-
-	lock_kernel();
+	int retval, i;
+	long __timeout = *timeout;
 
 	wait = NULL;
-	current->timeout = timeout;
-	if (timeout) {
-		struct poll_table_entry *entry = (struct poll_table_entry *)
-			__get_free_page(GFP_KERNEL);
-		if (!entry) {
-			retval = -ENOMEM;
-			goto out_nowait;
-		}
+	if (__timeout) {
+		struct poll_table_entry *entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
+		if (!entry)
+			return -ENOMEM;
+
 		wait_table.nr = 0;
 		wait_table.entry = entry;
 		wait = &wait_table;
 	}
 
+	lock_kernel();
+
 	retval = max_select_fd(n, fds);
 	if (retval < 0)
 		goto out;
@@ -190,18 +187,22 @@
 			}
 		}
 		wait = NULL;
-		if (retval || !current->timeout || signal_pending(current))
+		if (retval || !__timeout || signal_pending(current))
 			break;
-		schedule();
+		__timeout = schedule_timeout(__timeout);
 	}
 	current->state = TASK_RUNNING;
 
 out:
-	if (timeout) {
+	if (*timeout) {
 		free_wait(&wait_table);
 		free_page((unsigned long) wait_table.entry);
 	}
-out_nowait:
+
+	/*
+	 * Up-to-date the caller timeout.
+	 */
+	*timeout = __timeout;
 	unlock_kernel();
 	return retval;
 }
@@ -218,10 +219,10 @@
 sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
 	fd_set_buffer *fds;
-	unsigned long timeout;
+	long timeout;
 	int ret;
 
-	timeout = ~0UL;
+	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (tvp) {
 		time_t sec, usec;
 
@@ -232,8 +233,6 @@
 
 		timeout = ROUND_UP(usec, 1000000/HZ);
 		timeout += sec * (unsigned long) HZ;
-		if (timeout)
-			timeout += jiffies + 1;
 	}
 
 	ret = -ENOMEM;
@@ -253,12 +252,11 @@
 	zero_fd_set(n, fds->res_out);
 	zero_fd_set(n, fds->res_ex);
 
-	ret = do_select(n, fds, timeout);
+	ret = do_select(n, fds, &timeout);
 
 	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		unsigned long timeout = current->timeout - jiffies - 1;
 		time_t sec = 0, usec = 0;
-		if ((long) timeout > 0) {
+		if (timeout) {
 			sec = timeout / HZ;
 			usec = timeout % HZ;
 			usec *= (1000000/HZ);
@@ -266,7 +264,6 @@
 		put_user(sec, &tvp->tv_sec);
 		put_user(usec, &tvp->tv_usec);
 	}
-	current->timeout = 0;
 
 	if (ret < 0)
 		goto out;
@@ -287,7 +284,8 @@
 	return ret;
 }
 
-static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
+static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait,
+		   long timeout)
 {
 	int count = 0;
 
@@ -321,15 +319,15 @@
 		}
 
 		wait = NULL;
-		if (count || !current->timeout || signal_pending(current))
+		if (count || !timeout || signal_pending(current))
 			break;
-		schedule();
+		timeout = schedule_timeout(timeout);
 	}
 	current->state = TASK_RUNNING;
 	return count;
 }
 
-asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
+asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
 {
 	int i, fdcount, err, size;
 	struct pollfd * fds, *fds1;
@@ -342,9 +340,9 @@
 		goto out;
 
 	if (timeout < 0)
-		timeout = 0x7fffffff;
+		timeout = MAX_SCHEDULE_TIMEOUT;
 	else if (timeout)
-		timeout = ((unsigned long)timeout*HZ+999)/1000+jiffies+1;
+		timeout = (timeout*HZ+999)/1000+1;
 
 	err = -ENOMEM;
 	if (timeout) {
@@ -366,9 +364,7 @@
 	if (copy_from_user(fds, ufds, size))
 		goto out_fds;
 
-	current->timeout = timeout;
-	fdcount = do_poll(nfds, fds, wait);
-	current->timeout = 0;
+	fdcount = do_poll(nfds, fds, wait, timeout);
 
 	/* OK, now copy the revents fields back to user space. */
 	fds1 = fds;
diff -u --recursive --new-file v2.1.126/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.1.126/linux/fs/smbfs/proc.c	Thu Aug 27 19:56:30 1998
+++ linux/fs/smbfs/proc.c	Tue Nov  3 21:56:58 1998
@@ -520,9 +520,7 @@
 	/*
 	 * Wait for the new connection.
 	 */
-	current->timeout = jiffies + 5*HZ;
-	interruptible_sleep_on(&server->wait);
-	current->timeout = 0;
+	interruptible_sleep_on_timeout(&server->wait,  5*HZ);
 	if (signal_pending(current))
 		printk("smb_retry: caught signal\n");
 
@@ -1602,10 +1600,8 @@
 				/* Windows 95 is not able to deliver answers
 				 * to FIND_NEXT fast enough, so sleep 0.2 sec
 				 */
-				current->timeout = jiffies + HZ / 5;
 				current->state = TASK_INTERRUPTIBLE;
-				schedule();
-				current->timeout = 0;
+				schedule_timeout(HZ/5);
 			}
 		}
 
diff -u --recursive --new-file v2.1.126/linux/fs/ufs/util.h linux/fs/ufs/util.h
--- v2.1.126/linux/fs/ufs/util.h	Fri Oct 23 22:01:22 1998
+++ linux/fs/ufs/util.h	Mon Nov  2 09:09:46 1998
@@ -305,7 +305,7 @@
 		count = min (size + offset, uspi->s_bpf);
 		size -= count - offset;
 		pos = ext2_find_next_zero_bit (ubh->bh[base]->b_data, count, offset);
-		if (pos < count + offset || !size)
+		if (pos < count || !size)
 			break;
 		base++;
 		offset = 0;
diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/README-WIP.txt linux/fs/umsdos/README-WIP.txt
--- v2.1.126/linux/fs/umsdos/README-WIP.txt	Thu Sep 17 17:53:38 1998
+++ linux/fs/umsdos/README-WIP.txt	Thu Nov  5 15:29:43 1998
@@ -1,6 +1,6 @@
 Changes by Matija Nalis (mnalis@jagor.srce.hr) on umsdos dentry fixing
 (started by Peter T. Waltenberg <peterw@karaka.chch.cri.nz>)
-Final conversion to dentries Bill Hawes <whawes@star.net>
+(Final conversion to dentries Bill Hawes <whawes@star.net>)
 
 ---------- WARNING --------- WARNING --------- WARNING -----------
 There is no warning any more.
@@ -16,7 +16,7 @@
 Legend: those lines marked with '+' on the beggining of line indicates it
 passed all of my tests, and performed perfect in all of them.
 
-Current status (980915) - UMSDOS dentry-Beta 0.83:
+Current status (981018) - UMSDOS dentry-Beta 0.83:
 
 (1) pure MSDOS (no --linux-.--- EMD file):
 
@@ -47,18 +47,18 @@
 + read file			- works
 + switching MSDOS/UMSDOS	- works
 + switching UMSDOS/MSDOS	- works
-- pseudo root things		- DOES NOT WORK. COMMENTED OUT. See Notes below.
+- pseudo root things		- works mostly. See notes below.
 + resolve symlink		- works
 + dereference symlink		- works
 + dangling symlink		- works
-- hard links			- DOES NOT WORK CORRECTLY ALWAYS.
+- hard links			- seems to work mostly
 + special files (block/char devices, FIFOs, sockets...)	- works
 - various umsdos ioctls		- works
 
 
 WRITE:
-- create symlink		- sometimes works, but see WARNING below
-- create hardlink		- works
+- create symlink		- works mostly, but see WARNING below
+- create hardlink		- works, but see portability WARNING below
 + create file			- works
 + create special file		- works
 + write to file			- works
@@ -88,7 +88,8 @@
 
 Note: creating and using pseudo-hardlinks is always non-perfect, especially
 in filesystems that might be externally modified like umsdos. There is
-example is specs file about it.
+example is specs file about it. Specifically, moving directory which
+contains hardlinks will break them.
 
 Warning: moving symlinks around may break them until umount/remount.
 
@@ -97,17 +98,22 @@
 file instead of symlink until next umount/mount pair. Tracking this one
 down...
 
-Wanted: I am currently looking for volunteers that already have UMSDOS
-filesystems in pseudo-root, or are able to get them, to test PSEUDO-ROOT
-stuff (and get new patches from me), which I currently can't do. Anyone know
-of URL of nice UMSDOS pseudo-root ready image ? As always, any patches or
-pointer to things done in wrong way (or ideas of better ways) are greatly
-appreciated !
-
-Note: If you are currently trying to use UMSDOS as root partition (with
-linux installed in c:\linux) it will not work. Pseudo-root is currently
-commented out. See 'wanted' above and contact me if you are interested in
-testing it.
+Note: (about pseudoroot) If you are currently trying to use UMSDOS as root
+partition (with linux installed in c:\linux) it will boot, but there are
+some problems. Volunteers ready to test pseudoroot are needed (preferably
+ones with working backups or unimportant data). There are problems with
+different interpretation of hard links in normal in pseudo-root modes,
+resulting is 'silent delete' of them sometimes. Also, '/DOS' pseudo
+directory is only partially re-implemented and buggy. It works most of the
+time, though.
+
+Warning: (about creating hardlinks in pseudoroot mode) - hardlinks created in
+pseudoroot mode are not compatibile with 'normal' hardlinks, and vice versa.
+That is because harlink which is /foo in pseudoroot mode, becomes
+/linux/foo in normal mode. I'm thinking about this one. However, since most
+people either always use pseudoroot, or always use normal umsdos filesystem,
+this is no showstopper.
+
 
 ------------------------------------------------------------------------------
 
diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/check.c linux/fs/umsdos/check.c
--- v2.1.126/linux/fs/umsdos/check.c	Wed Sep  9 14:51:09 1998
+++ linux/fs/umsdos/check.c	Thu Nov  5 15:29:43 1998
@@ -13,6 +13,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/umsdos_fs.h>
 
 #include <asm/system.h>
 
@@ -75,6 +76,7 @@
 /*
  * check an inode
  */
+extern struct inode_operations umsdos_rdir_inode_operations;
 
 void check_inode (struct inode *inode)
 {
diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.1.126/linux/fs/umsdos/dir.c	Mon Sep 28 10:51:35 1998
+++ linux/fs/umsdos/dir.c	Thu Nov  5 15:29:43 1998
@@ -44,7 +44,7 @@
 	}
 }
 
-static struct dentry_operations umsdos_dentry_operations =
+struct dentry_operations umsdos_dentry_operations =
 {
 	umsdos_dentry_validate,	/* d_validate(struct dentry *) */
 	NULL,			/* d_hash */
@@ -123,7 +123,6 @@
 	if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS &&
 	    dir == pseudo_root && !internal_read) {
 
-Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
 		/*
 		 * We don't need to simulate this pseudo directory
 		 * when umsdos_readdir_x is called for internal operation
@@ -134,6 +133,8 @@
 		 * linux root), it simulate a directory /DOS which points to
 		 * the real root of the file system.
 		 */
+
+		Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n"));
 		if (filldir (dirbuf, "DOS", 3, 
 				UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) {
 			filp->f_pos++;
@@ -477,6 +478,7 @@
 		 * A lookup of DOS in the pseudo root will always succeed
 		 * and return the inode of the real root.
 		 */
+		Printk ((KERN_DEBUG "umsdos_lookup_x: following /DOS\n"));
 		inode = saved_root->d_inode;
 		goto out_add;
 	}
@@ -542,7 +544,7 @@
 		 * which are recorded independently of the pseudo-root
 		 * mode.
 		 */
-printk(KERN_WARNING "umsdos_lookup_x: untested, inode == Pseudo_root\n");
+printk("umsdos_lookup_x: skipping DOS/linux\n");
 		ret = -ENOENT;
 		goto out_dput;
 	}
@@ -557,7 +559,7 @@
 	ret = 0;
 
 out_dput:
-	if (dret != dentry)
+	if (dret && dret != dentry)
 		d_drop(dret);
 	dput(dret);
 out:
diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.1.126/linux/fs/umsdos/inode.c	Mon Sep 28 10:51:35 1998
+++ linux/fs/umsdos/inode.c	Thu Nov  5 15:29:43 1998
@@ -148,13 +148,13 @@
 {
 	struct inode *inode = dentry->d_inode;
 
-Printk (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino));
+PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino));
 
 	/*
 	 * Classify the inode based on EMD/non-EMD status.
 	 */
-Printk (("umsdos_patch_inode: call x_set_dirinfo(%p,%p,%lu)\n",
-inode, dir, f_pos));
+PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",
+dentry, f_pos));
 	umsdos_set_dirinfo_new(dentry, f_pos);
 
 	inode->u.umsdos_i.i_emd_dir = 0;
@@ -275,8 +275,8 @@
 
 	fill_new_filp (&filp, demd);
 	filp.f_pos = inode->u.umsdos_i.pos;
-Printk(("UMSDOS_notify_change: %s/%s reading at %u\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, filp.f_pos));
+Printk(("UMSDOS_notify_change: %s/%s reading at %d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, (int) filp.f_pos));
 
 	/* Read only the start of the entry since we don't touch the name */
 	ret = umsdos_emd_dir_read (&filp, (char *) &entry, UMSDOS_REC_SIZE);
@@ -398,11 +398,14 @@
 
 	/* Check whether to change to the /linux root */
 	new_root = check_pseudo_root(sb);
+
 	if (new_root) {
-		pseudo_root = new_root->d_inode;
 		/* sanity check */
 		if (new_root->d_op != &umsdos_dentry_operations)
 			printk("umsdos_read_super: pseudo-root wrong ops!\n");
+
+		pseudo_root = new_root->d_inode;
+
 		saved_root = sb->s_root;
 		sb->s_root = new_root;
 		printk(KERN_INFO "UMSDOS: changed to alternate root\n");
@@ -411,6 +414,9 @@
 	/* if d_count is not 1, mount will fail with -EBUSY! */
 	if (sb->s_root->d_count > 1) {
 		shrink_dcache_sb(sb);
+		if (sb->s_root->d_count > 1) {
+			printk(KERN_ERR "UMSDOS: root count %d > 1 !", sb->s_root->d_count);
+		}
 	}
 	return sb;
 
diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.1.126/linux/fs/umsdos/namei.c	Mon Sep 28 10:51:35 1998
+++ linux/fs/umsdos/namei.c	Thu Nov  5 15:29:43 1998
@@ -1033,12 +1033,12 @@
 	if (empty == 1) {
 		struct dentry *demd;
 
-Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
 		demd = umsdos_get_emd_dentry(dentry);
 		if (!IS_ERR(demd)) {
 			err = -ENOENT;
 			if (demd->d_inode)
 				err = msdos_unlink (dentry->d_inode, demd);
+Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
 #ifdef UMSDOS_PARANOIA
 if (err)
 printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.1.126/linux/fs/umsdos/rdir.c	Mon Sep 28 10:51:35 1998
+++ linux/fs/umsdos/rdir.c	Thu Nov  5 15:29:43 1998
@@ -107,8 +107,8 @@
 		 * depending on whether this is an MS-DOS or 
 		 * a UMSDOS directory
 		 */
-Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n",
-inode->i_ino));
+Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name));
 		umsdos_patch_dentry_inode(dentry, 0);
 
 		/* N.B. Won't work -- /linux dentry will already have
diff -u --recursive --new-file v2.1.126/linux/include/asm-i386/spinlock.h linux/include/asm-i386/spinlock.h
--- v2.1.126/linux/include/asm-i386/spinlock.h	Thu Aug  6 14:06:33 1998
+++ linux/include/asm-i386/spinlock.h	Tue Nov  3 22:11:55 1998
@@ -14,10 +14,10 @@
  */
 #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
   typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { }
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
 #else
   typedef struct { int gcc_is_buggy; } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { 0 }
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 #endif
 
 #define spin_lock_init(lock)	do { } while(0)
@@ -38,7 +38,7 @@
 typedef struct {
 	volatile unsigned int lock;
 } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0 }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 
 #define spin_lock_init(x)	do { (x)->lock = 0; } while (0)
 #define spin_trylock(lock)	(!test_and_set_bit(0,(lock)))
@@ -61,7 +61,7 @@
 	volatile unsigned int babble;
 	const char *module;
 } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0, 25, __BASE_FILE__ }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ }
 
 #include <linux/kernel.h>
 
@@ -88,9 +88,16 @@
  * can "mix" irq-safe locks - any writer needs to get a
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
+ *
+ * Gcc-2.7.x has a nasty bug with empty initializers.
  */
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } rwlock_t;
+  #define RW_LOCK_UNLOCKED (rwlock_t) { }
+#else
+  typedef struct { int gcc_is_buggy; } rwlock_t;
+  #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#endif
 
 #define read_lock(lock)		do { } while(0)
 #define read_unlock(lock)	do { } while(0)
@@ -120,7 +127,7 @@
 	volatile unsigned int lock;
 } spinlock_t;
 
-#define SPIN_LOCK_UNLOCKED { 0 }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 
 #define spin_lock_init(x)	do { (x)->lock = 0; } while(0)
 /*
@@ -188,7 +195,7 @@
 	unsigned long previous;
 } rwlock_t;
 
-#define RW_LOCK_UNLOCKED { 0, 0 }
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
 
 /*
  * On x86, we implement read-write locks as a 32-bit counter
diff -u --recursive --new-file v2.1.126/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.1.126/linux/include/asm-i386/system.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-i386/system.h	Tue Oct 27 10:20:56 1998
@@ -88,7 +88,7 @@
 		"1:\t"				\
 		"movl %0,%%" #seg "\n"		\
 		"2:\n"				\
-		".section fixup,\"ax\"\n"	\
+		".section .fixup,\"ax\"\n"	\
 		"3:\t"				\
 		"pushl $0\n\t"			\
 		"popl %%" #seg "\n\t"		\
diff -u --recursive --new-file v2.1.126/linux/include/asm-mips/floppy.h linux/include/asm-mips/floppy.h
--- v2.1.126/linux/include/asm-mips/floppy.h	Fri Oct 23 22:01:22 1998
+++ linux/include/asm-mips/floppy.h	Mon Oct 26 09:57:56 1998
@@ -11,7 +11,6 @@
 #ifndef __ASM_MIPS_FLOPPY_H
 #define __ASM_MIPS_FLOPPY_H
 
-#include <linux/config.h>
 #include <asm/bootinfo.h>
 #include <asm/jazz.h>
 #include <asm/jazzdma.h>
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h
--- v2.1.126/linux/include/asm-sparc/asm_offsets.h	Thu Aug  6 14:06:33 1998
+++ linux/include/asm-sparc/asm_offsets.h	Tue Oct 27 09:52:21 1998
@@ -146,19 +146,21 @@
 #define ASIZ_task_cap_inheritable	0x00000004
 #define AOFF_task_cap_permitted	0x0000016c
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_rlim	0x00000170
+#define AOFF_task_user	0x00000170
+#define ASIZ_task_user	0x00000004
+#define AOFF_task_rlim	0x00000174
 #define ASIZ_task_rlim	0x00000050
-#define AOFF_task_used_math	0x000001c0
+#define AOFF_task_used_math	0x000001c4
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x000001c2
+#define AOFF_task_comm	0x000001c6
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x000001d4
+#define AOFF_task_link_count	0x000001d8
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x000001d8
+#define AOFF_task_tty	0x000001dc
 #define ASIZ_task_tty	0x00000004
-#define AOFF_task_semundo	0x000001dc
+#define AOFF_task_semundo	0x000001e0
 #define ASIZ_task_semundo	0x00000004
-#define AOFF_task_semsleeping	0x000001e0
+#define AOFF_task_semsleeping	0x000001e4
 #define ASIZ_task_semsleeping	0x00000004
 #define AOFF_task_tss	0x000001e8
 #define ASIZ_task_tss	0x00000388
@@ -169,20 +171,20 @@
 #define AOFF_task_mm	0x00000578
 #define ASIZ_task_mm	0x00000004
 #define AOFF_task_sigmask_lock	0x0000057c
-#define ASIZ_task_sigmask_lock	0x00000000
-#define AOFF_task_sig	0x0000057c
+#define ASIZ_task_sigmask_lock	0x00000001
+#define AOFF_task_sig	0x00000580
 #define ASIZ_task_sig	0x00000004
-#define AOFF_task_signal	0x00000580
+#define AOFF_task_signal	0x00000584
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000588
+#define AOFF_task_blocked	0x0000058c
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000590
+#define AOFF_task_sigqueue	0x00000594
 #define ASIZ_task_sigqueue	0x00000004
-#define AOFF_task_sigqueue_tail	0x00000594
+#define AOFF_task_sigqueue_tail	0x00000598
 #define ASIZ_task_sigqueue_tail	0x00000004
-#define AOFF_task_sas_ss_sp	0x00000598
+#define AOFF_task_sas_ss_sp	0x0000059c
 #define ASIZ_task_sas_ss_sp	0x00000004
-#define AOFF_task_sas_ss_size	0x0000059c
+#define AOFF_task_sas_ss_size	0x000005a0
 #define ASIZ_task_sas_ss_size	0x00000004
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000004
@@ -419,19 +421,21 @@
 #define ASIZ_task_cap_inheritable	0x00000004
 #define AOFF_task_cap_permitted	0x00000264
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_rlim	0x00000268
+#define AOFF_task_user	0x00000268
+#define ASIZ_task_user	0x00000004
+#define AOFF_task_rlim	0x0000026c
 #define ASIZ_task_rlim	0x00000050
-#define AOFF_task_used_math	0x000002b8
+#define AOFF_task_used_math	0x000002bc
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x000002ba
+#define AOFF_task_comm	0x000002be
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x000002cc
+#define AOFF_task_link_count	0x000002d0
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x000002d0
+#define AOFF_task_tty	0x000002d4
 #define ASIZ_task_tty	0x00000004
-#define AOFF_task_semundo	0x000002d4
+#define AOFF_task_semundo	0x000002d8
 #define ASIZ_task_semundo	0x00000004
-#define AOFF_task_semsleeping	0x000002d8
+#define AOFF_task_semsleeping	0x000002dc
 #define ASIZ_task_semsleeping	0x00000004
 #define AOFF_task_tss	0x000002e0
 #define ASIZ_task_tss	0x00000388
@@ -442,20 +446,20 @@
 #define AOFF_task_mm	0x00000670
 #define ASIZ_task_mm	0x00000004
 #define AOFF_task_sigmask_lock	0x00000674
-#define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x00000678
+#define ASIZ_task_sigmask_lock	0x00000008
+#define AOFF_task_sig	0x0000067c
 #define ASIZ_task_sig	0x00000004
-#define AOFF_task_signal	0x0000067c
+#define AOFF_task_signal	0x00000680
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000684
+#define AOFF_task_blocked	0x00000688
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x0000068c
+#define AOFF_task_sigqueue	0x00000690
 #define ASIZ_task_sigqueue	0x00000004
-#define AOFF_task_sigqueue_tail	0x00000690
+#define AOFF_task_sigqueue_tail	0x00000694
 #define ASIZ_task_sigqueue_tail	0x00000004
-#define AOFF_task_sas_ss_sp	0x00000694
+#define AOFF_task_sas_ss_sp	0x00000698
 #define ASIZ_task_sas_ss_sp	0x00000004
-#define AOFF_task_sas_ss_size	0x00000698
+#define AOFF_task_sas_ss_size	0x0000069c
 #define ASIZ_task_sas_ss_size	0x00000004
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000004
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h
--- v2.1.126/linux/include/asm-sparc/dma.h	Fri May  8 23:14:56 1998
+++ linux/include/asm-sparc/dma.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.26 1998/04/13 07:27:05 davem Exp $
+/* $Id: dma.h,v 1.28 1998/10/26 20:03:09 davem Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -15,6 +15,22 @@
 #include <asm/sbus.h>
 #include <asm/delay.h>
 #include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dma_spin_lock, flags);
+	return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
 
 /* These are irrelevant for Sparc DMA, but we leave it in so that
  * things can compile.
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h
--- v2.1.126/linux/include/asm-sparc/fcntl.h	Fri Oct 23 22:01:26 1998
+++ linux/include/asm-sparc/fcntl.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: fcntl.h,v 1.10 1998/08/26 10:33:29 davem Exp $ */
+/* $Id: fcntl.h,v 1.11 1998/10/26 20:03:10 davem Exp $ */
 #ifndef _SPARC_FCNTL_H
 #define _SPARC_FCNTL_H
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/hardirq.h linux/include/asm-sparc/hardirq.h
--- v2.1.126/linux/include/asm-sparc/hardirq.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-sparc/hardirq.h	Tue Oct 27 09:52:21 1998
@@ -1,6 +1,7 @@
 /* hardirq.h: 32-bit Sparc hard IRQ support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
  */
 
 #ifndef __SPARC_HARDIRQ_H
@@ -9,19 +10,25 @@
 #include <linux/tasks.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+	(local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
 
 #ifndef __SMP__
 
 #define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
-#define hardirq_endlock(cpu)	do { } while(0)
+#define hardirq_endlock(cpu)	do { } while (0)
 
 #define hardirq_enter(cpu)	(local_irq_count[cpu]++)
 #define hardirq_exit(cpu)	(local_irq_count[cpu]--)
 
 #define synchronize_irq()	barrier()
 
-#else /* __SMP__ */
+#else
 
 #include <asm/atomic.h>
 #include <asm/spinlock.h>
@@ -32,37 +39,33 @@
 extern spinlock_t global_irq_lock;
 extern atomic_t global_irq_count;
 
-#define release_irqlock(cpu)				\
-do {	if(global_irq_holder == (unsigned char) cpu) {	\
-		global_irq_holder = NO_PROC_ID;		\
-		spin_unlock(&global_irq_lock);		\
-	}						\
-} while(0)
-
-/* Ordering of the counter bumps is _deadly_ important. */
-#define hardirq_enter(cpu) \
-	do { ++local_irq_count[cpu]; atomic_inc(&global_irq_count); } while(0)
-
-#define hardirq_exit(cpu) \
-	do { atomic_dec(&global_irq_count); --local_irq_count[cpu]; } while(0)
-
-#define hardirq_trylock(cpu)					\
-({	unsigned long flags; int ret = 1;			\
-	__save_flags(flags);					\
-	__cli();						\
-	if(atomic_add_return(1, &global_irq_count) != 1 ||	\
-	   *(((unsigned char *)(&global_irq_lock)))) {		\
-		atomic_dec(&global_irq_count);			\
-		__restore_flags(flags);				\
-		ret = 0;					\
-	} else {						\
-		++local_irq_count[cpu];				\
-		__sti();					\
-	}							\
-	ret;							\
-})
+static inline void release_irqlock(int cpu)
+{
+	/* if we didn't own the irq lock, just ignore.. */
+	if (global_irq_holder == (unsigned char) cpu) {
+		global_irq_holder = NO_PROC_ID;
+		spin_unlock(&global_irq_lock);
+	}
+}
+
+static inline void hardirq_enter(int cpu)
+{
+	++local_irq_count[cpu];
+	atomic_inc(&global_irq_count);
+}
+
+static inline void hardirq_exit(int cpu)
+{
+	atomic_dec(&global_irq_count);
+	--local_irq_count[cpu];
+}
+
+static inline int hardirq_trylock(int cpu)
+{
+	return !atomic_read(&global_irq_count) && !*(((volatile unsigned char *)(&global_irq_lock)));
+}
 
-#define hardirq_endlock(cpu) do { __cli(); hardirq_exit(cpu); __sti(); } while(0)
+#define hardirq_endlock(cpu)	do { } while (0)
 
 extern void synchronize_irq(void);
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/perfctr.h linux/include/asm-sparc/perfctr.h
--- v2.1.126/linux/include/asm-sparc/perfctr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc/perfctr.h	Tue Oct 27 09:52:21 1998
@@ -0,0 +1,101 @@
+/*----------------------------------------
+  PERFORMANCE INSTRUMENTATION  
+  Guillaume Thouvenin           08/10/98
+  David S. Miller               10/06/98
+  ---------------------------------------*/
+#ifndef PERF_COUNTER_API
+#define PERF_COUNTER_API
+
+/* sys_perfctr() interface.  First arg is operation code
+ * from enumeration below.  The meaning of further arguments
+ * are determined by the operation code.
+ *
+ * int sys_perfctr(int opcode, unsigned long arg0,
+ *                 unsigned long arg1, unsigned long arg2)
+ *
+ * Pointers which are passed by the user are pointers to 64-bit
+ * integers.
+ *
+ * Once enabled, performance counter state is retained until the
+ * process either exits or performs an exec.  That is, performance
+ * counters remain enabled for fork/clone children.
+ */
+enum perfctr_opcode {
+	/* Enable UltraSparc performance counters, ARG0 is pointer
+	 * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer
+	 * to 64-bit accumulator for D1 counter.  ARG2 is a pointer to
+	 * the initial PCR register value to use.
+	 */
+	PERFCTR_ON,
+
+	/* Disable UltraSparc performance counters.  The PCR is written
+	 * with zero and the user counter accumulator pointers and
+	 * working PCR register value are forgotten.
+	 */
+	PERFCTR_OFF,
+
+	/* Add current D0 and D1 PIC values into user pointers given
+	 * in PERFCTR_ON operation.  The PIC is cleared before returning.
+	 */
+	PERFCTR_READ,
+
+	/* Clear the PIC register. */
+	PERFCTR_CLRPIC,
+
+	/* Begin using a new PCR value, the pointer to which is passed
+	 * in ARG0.  The PIC is also cleared after the new PCR value is
+	 * written.
+	 */
+	PERFCTR_SETPCR,
+
+	/* Store in pointer given in ARG0 the current PCR register value
+	 * being used.
+	 */
+	PERFCTR_GETPCR
+};
+
+/* I don't want the kernel's namespace to be polluted with this
+ * stuff when this file is included.  --DaveM
+ */
+#ifndef __KERNEL__
+
+#define  PRIV 0x00000001
+#define  USR  0x00000002
+#define  SYS  0x00000004
+
+/* Pic.S0 Selection Bit Field Encoding  */
+#define  CYCLE_CNT            0x00000000
+#define  INSTR_CNT            0x00000010
+#define  DISPATCH0_IC_MISS    0x00000020
+#define  DISPATCH0_STOREBUF   0x00000030
+#define  IC_REF               0x00000080
+#define  DC_RD                0x00000090
+#define  DC_WR                0x000000A0
+#define  LOAD_USE             0x000000B0
+#define  EC_REF               0x000000C0
+#define  EC_WRITE_HIT_RDO     0x000000D0
+#define  EC_SNOOP_INV         0x000000E0
+#define  EC_RD_HIT            0x000000F0
+
+/* Pic.S1 Selection Bit Field Encoding  */
+#define  CYCLE_CNT_D1         0x00000000
+#define  INSTR_CNT_D1         0x00000800
+#define  DISPATCH0_IC_MISPRED 0x00001000
+#define  DISPATCH0_FP_USE     0x00001800
+#define  IC_HIT               0x00004000
+#define  DC_RD_HIT            0x00004800
+#define  DC_WR_HIT            0x00005000
+#define  LOAD_USE_RAW         0x00005800
+#define  EC_HIT               0x00006000
+#define  EC_WB                0x00006800
+#define  EC_SNOOP_CB          0x00007000
+#define  EC_IT_HIT            0x00007800
+
+struct vcounter_struct {
+  unsigned long long vcnt0;
+  unsigned long long vcnt1;
+};
+
+#endif /* !(__KERNEL__) */
+
+#endif /* !(PERF_COUNTER_API) */
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/sigcontext.h linux/include/asm-sparc/sigcontext.h
--- v2.1.126/linux/include/asm-sparc/sigcontext.h	Mon Mar 17 14:54:31 1997
+++ linux/include/asm-sparc/sigcontext.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: sigcontext.h,v 1.12 1997/03/03 16:51:52 jj Exp $ */
+/* $Id: sigcontext.h,v 1.13 1998/10/06 09:28:35 jj Exp $ */
 #ifndef __SPARC_SIGCONTEXT_H
 #define __SPARC_SIGCONTEXT_H
 
@@ -51,6 +51,16 @@
 		unsigned long insn;
 	} si_fpqueue [16];
 } __siginfo_fpu_t;
+
+/* This magic should be in g_upper[0] for all upper parts
+   to be valid.
+   This is generated by sparc64 only, but for 32bit processes,
+   so we define it here as well.  */
+#define SIGINFO_EXTRA_V8PLUS_MAGIC      0x130e269
+typedef struct {
+	unsigned   int g_upper[8];
+	unsigned   int o_upper[8];
+} siginfo_extra_v8plus_t;
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/softirq.h linux/include/asm-sparc/softirq.h
--- v2.1.126/linux/include/asm-sparc/softirq.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-sparc/softirq.h	Tue Oct 27 09:52:21 1998
@@ -1,133 +1,173 @@
 /* softirq.h: 32-bit Sparc soft IRQ support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
  */
 
 #ifndef __SPARC_SOFTIRQ_H
 #define __SPARC_SOFTIRQ_H
 
 #include <asm/atomic.h>
+#include <asm/smp.h>
 #include <asm/hardirq.h>
 
-/* The locking mechanism for base handlers, to prevent re-entrancy,
- * is entirely private to an implementation, it should not be
- * referenced at all outside of this file.
- */
+extern unsigned int local_bh_count[NR_CPUS];
+
 #define get_active_bhs()	(bh_mask & bh_active)
 
 #ifdef __SMP__
 
-extern atomic_t __sparc_bh_counter;
-
-#define start_bh_atomic() \
-	do { atomic_inc(&__sparc_bh_counter); synchronize_irq(); } while(0)
-
-#define end_bh_atomic()		atomic_dec(&__sparc_bh_counter)
-
-#include <asm/spinlock.h>
-
-extern spinlock_t global_bh_lock;
-
-#define init_bh(nr, routine)				\
-do {	unsigned long flags;				\
-	int ent = nr;					\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_base[ent] = routine;				\
-	bh_mask_count[ent] = 0;				\
-	bh_mask |= 1 << ent;				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define remove_bh(nr)					\
-do {	unsigned long flags;				\
-	int ent = nr;					\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_base[ent] = NULL;				\
-	bh_mask &= ~(1 << ent);				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define mark_bh(nr)					\
-do {	unsigned long flags;				\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_active |= (1 << nr);				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define disable_bh(nr)					\
-do {	unsigned long flags;				\
-	int ent = nr;					\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_mask &= ~(1 << ent);				\
-	bh_mask_count[ent]++;				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define enable_bh(nr)					\
-do {	unsigned long flags;				\
-	int ent = nr;					\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	if (!--bh_mask_count[ent])			\
-		bh_mask |= 1 << ent;			\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define softirq_trylock(cpu)					\
-({								\
-	int ret = 1;						\
-	if(atomic_add_return(1, &__sparc_bh_counter) != 1) {	\
-		atomic_dec(&__sparc_bh_counter);		\
-		ret = 0;					\
-	}							\
-	ret;							\
-})
-#define softirq_endlock(cpu)	atomic_dec(&__sparc_bh_counter)
-#define clear_active_bhs(mask)				\
-do {	unsigned long flags;				\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_active &= ~(mask);				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#else /* !(__SMP__) */
-
-extern int __sparc_bh_counter;
+/*
+ * The locking mechanism for base handlers, to prevent re-entrancy,
+ * is entirely private to an implementation, it should not be
+ * referenced at all outside of this file.
+ */
+extern atomic_t global_bh_lock;
+extern atomic_t global_bh_count;
+extern spinlock_t sparc_bh_lock;
+
+extern void synchronize_bh(void);
+
+static inline void clear_active_bhs(unsigned int mask)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&sparc_bh_lock, flags);
+	bh_active &= ~(mask);
+	spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+	unsigned long flags;
+	spin_lock_irqsave(&sparc_bh_lock, flags);
+	bh_base[nr] = routine;
+	bh_mask_count[nr] = 0;
+	bh_mask |= 1 << nr;
+	spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+extern inline void remove_bh(int nr)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&sparc_bh_lock, flags);
+	bh_base[nr] = NULL;
+	bh_mask &= ~(1 << nr);
+	spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+extern inline void mark_bh(int nr)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&sparc_bh_lock, flags);
+	bh_active |= (1 << nr);
+	spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&sparc_bh_lock, flags);
+	bh_mask &= ~(1 << nr);
+	bh_mask_count[nr]++;
+	spin_unlock_irqrestore(&sparc_bh_lock, flags);
+	synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&sparc_bh_lock, flags);
+	if (!--bh_mask_count[nr])
+		bh_mask |= 1 << nr;
+	spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+static inline void start_bh_atomic(void)
+{
+	atomic_inc(&global_bh_lock);
+	synchronize_bh();
+}
+
+static inline void end_bh_atomic(void)
+{
+	atomic_dec(&global_bh_lock);
+}
+
+/* These are for the IRQs testing the lock */
+static inline int softirq_trylock(int cpu)
+{
+	if (atomic_add_return(1, &global_bh_count) == 1) {
+		if (atomic_read(&global_bh_lock) == 0) {
+			++local_bh_count[cpu];
+			return 1;
+		}
+	}
+	atomic_dec(&global_bh_count);
+	return 0;
+}
+
+static inline void softirq_endlock(int cpu)
+{
+	local_bh_count[cpu]--;
+	atomic_dec(&global_bh_count);
+}
 
-#define start_bh_atomic()	do { __sparc_bh_counter++; barrier(); } while(0)
-#define end_bh_atomic()		do { barrier(); __sparc_bh_counter--; } while(0)
+#else
 
-#define softirq_trylock(cpu) (__sparc_bh_counter ? 0 : (__sparc_bh_counter=1))
-#define softirq_endlock(cpu) (__sparc_bh_counter = 0)
 #define clear_active_bhs(x)	(bh_active &= ~(x))
-#define synchronize_bh()	barrier() /* XXX implement SMP version -DaveM */
-
-#define init_bh(nr, routine)	\
-do {	int ent = nr;		\
-	bh_base[ent] = routine;	\
-	bh_mask_count[ent] = 0;	\
-	bh_mask |= 1 << ent;	\
-} while(0)
-
-#define remove_bh(nr)		\
-do {	int ent = nr;		\
-	bh_base[ent] = NULL;	\
-	bh_mask &= ~(1 << ent);	\
-} while(0)
-
 #define mark_bh(nr)		(bh_active |= (1 << (nr)))
 
-#define disable_bh(nr)		\
-do {	int ent = nr;		\
-	bh_mask &= ~(1 << ent);	\
-	bh_mask_count[ent]++;	\
-} while(0)
-
-#define enable_bh(nr)			\
-do {	int ent = nr;			\
-	if (!--bh_mask_count[ent])	\
-		bh_mask |= 1 << ent;	\
-} while(0)
+/* These are for the irq's testing the lock */
+#define softirq_trylock(cpu)	(local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1))
+#define softirq_endlock(cpu)	(local_bh_count[cpu] = 0)
+#define synchronize_bh()	barrier()
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+	bh_mask &= ~(1 << nr);
+	bh_mask_count[nr]++;
+	synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+	if (!--bh_mask_count[nr])
+		bh_mask |= 1 << nr;
+}
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+	bh_base[nr] = routine;
+	bh_mask_count[nr] = 0;
+	bh_mask |= 1 << nr;
+}
+
+extern inline void remove_bh(int nr)
+{
+	bh_base[nr] = NULL;
+	bh_mask &= ~(1 << nr);
+}
+
+extern inline void start_bh_atomic(void)
+{
+	local_bh_count[0]++;
+	barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+	barrier();
+	local_bh_count[0]--;
+}
 
-#endif /* __SMP__ */
+#endif	/* SMP */
 
-#endif /* __SPARC_SOFTIRQ_H */
+#endif	/* __SPARC_SOFTIRQ_H */
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h
--- v2.1.126/linux/include/asm-sparc/spinlock.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-sparc/spinlock.h	Tue Oct 27 09:52:21 1998
@@ -10,13 +10,8 @@
 
 #ifndef __SMP__
 
-#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8)
-  typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { }
-#else
-  typedef unsigned char spinlock_t;
-  #define SPIN_LOCK_UNLOCKED 0
-#endif
+typedef unsigned char spinlock_t;
+#define SPIN_LOCK_UNLOCKED 0
 
 #define spin_lock_init(lock)	do { } while(0)
 #define spin_lock(lock)		do { } while(0)
@@ -270,18 +265,16 @@
 /* Sort of like atomic_t's on Sparc, but even more clever.
  *
  *	------------------------------------
- *	| 16-bit counter   | clock | wlock |  rwlock_t
+ *	| 24-bit counter           | wlock |  rwlock_t
  *	------------------------------------
- *	 31              16 15    8 7     0
+ *	 31                       8 7     0
  *
- * wlock signifies the one writer is in, the clock protects
- * counter bumping, however a reader must acquire wlock
- * before he can bump the counter on a read_lock().
- * Similarly a writer, once he has the wlock, must await
- * for the top 24 bits to all clear before he can finish
- * going in (this includes the clock of course).
+ * wlock signifies the one writer is in or somebody is updating
+ * counter. For a writer, if he successfully acquires the wlock,
+ * but counter is non-zero, he has to release the lock and wait,
+ * till both counter and wlock are zero.
  *
- * Unfortunately this scheme limits us to ~65,000 cpus.
+ * Unfortunately this scheme limits us to ~16,000,000 cpus.
  */
 extern __inline__ void _read_lock(rwlock_t *rw)
 {
@@ -310,7 +303,7 @@
 	__asm__ __volatile__("
 	mov	%%o7, %%g4
 	call	___rw_read_exit
-	 ldstub	[%%g1 + 2], %%g2
+	 ldstub	[%%g1 + 3], %%g2
 "	: /* no outputs */
 	: "r" (lp)
 	: "g2", "g4", "g7", "memory", "cc");
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v2.1.126/linux/include/asm-sparc/system.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-sparc/system.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.70 1998/09/29 09:46:32 davem Exp $ */
+/* $Id: system.h,v 1.71 1998/10/13 03:51:06 jj Exp $ */
 #include <linux/config.h>
 
 #ifndef __SPARC_SYSTEM_H
@@ -235,18 +235,16 @@
 
 extern unsigned char global_irq_holder;
 
-#define save_flags(x) \
-do {	((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
-		((getipl() & PSR_PIL) ? 2 : 0))); } while(0)
-
 #define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
 
 #ifdef DEBUG_IRQLOCK
 extern void __global_cli(void);
 extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
 extern void __global_restore_flags(unsigned long flags);
 #define cli()			__global_cli()
 #define sti()			__global_sti()
+#define save_flags(flags)	((flags)=__global_save_flags())
 #define restore_flags(flags)	__global_restore_flags(flags)
 #else
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v2.1.126/linux/include/asm-sparc/unistd.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc/unistd.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.47 1998/09/21 05:07:22 jj Exp $ */
+/* $Id: unistd.h,v 1.48 1998/10/07 01:27:50 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -33,7 +33,7 @@
 #define __NR_chmod               15 /* Common                                      */
 #define __NR_lchown              16 /* Common                                      */
 #define __NR_brk                 17 /* Common                                      */
-/* #define __NR_ni_syscall       18    ENOSYS under SunOS                          */
+/* #define __NR_ni_syscall       18    RESERVED for sparc64 perf-counter syscall   */
 #define __NR_lseek               19 /* Common                                      */
 #define __NR_getpid              20 /* Common                                      */
 #define __NR_capget		 21 /* Linux Specific				   */
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.1.126/linux/include/asm-sparc64/asm_offsets.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/asm_offsets.h	Tue Oct 27 09:52:21 1998
@@ -163,30 +163,30 @@
 #define AOFF_task_semsleeping	0x00000370
 #define ASIZ_task_semsleeping	0x00000008
 #define AOFF_task_tss	0x00000380
-#define ASIZ_task_tss	0x00000440
-#define AOFF_task_fs	0x000007c0
+#define ASIZ_task_tss	0x00000470
+#define AOFF_task_fs	0x000007f0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000007c8
+#define AOFF_task_files	0x000007f8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x000007d0
+#define AOFF_task_mm	0x00000800
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000007d8
-#define ASIZ_task_sigmask_lock	0x00000000
-#define AOFF_task_sig	0x000007d8
+#define AOFF_task_sigmask_lock	0x00000808
+#define ASIZ_task_sigmask_lock	0x00000001
+#define AOFF_task_sig	0x00000810
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x000007e0
+#define AOFF_task_signal	0x00000818
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x000007e8
+#define AOFF_task_blocked	0x00000820
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x000007f0
+#define AOFF_task_sigqueue	0x00000828
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x000007f8
+#define AOFF_task_sigqueue_tail	0x00000830
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000800
+#define AOFF_task_sas_ss_sp	0x00000838
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000808
+#define AOFF_task_sas_ss_size	0x00000840
 #define ASIZ_task_sas_ss_size	0x00000008
-#define ASIZ_task	0x00000810
+#define ASIZ_task	0x00000850
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_cache	0x00000008
@@ -266,18 +266,30 @@
 #define ASIZ_thread_sig_address	0x00000008
 #define AOFF_thread_sig_desc	0x000003f0
 #define ASIZ_thread_sig_desc	0x00000008
-#define AOFF_thread_fpdepth	0x000003f8
+#define AOFF_thread_user_cntd0	0x000003f8
+#define ASIZ_thread_user_cntd0	0x00000008
+#define AOFF_thread_user_cntd1	0x00000400
+#define ASIZ_thread_user_cntd1	0x00000008
+#define AOFF_thread_kernel_cntd0	0x00000408
+#define ASIZ_thread_kernel_cntd0	0x00000008
+#define AOFF_thread_kernel_cntd1	0x00000410
+#define ASIZ_thread_kernel_cntd1	0x00000008
+#define AOFF_thread_pcr_reg	0x00000418
+#define ASIZ_thread_pcr_reg	0x00000008
+#define AOFF_thread_fpdepth	0x00000420
 #define ASIZ_thread_fpdepth	0x00000001
-#define AOFF_thread_fpsaved	0x000003f9
+#define AOFF_thread_fpsaved	0x00000421
 #define ASIZ_thread_fpsaved	0x00000007
-#define AOFF_thread_gsr	0x00000400
+#define AOFF_thread_gsr	0x00000428
 #define ASIZ_thread_gsr	0x00000007
-#define AOFF_thread_xfsr	0x00000408
+#define AOFF_thread_xfsr	0x00000430
 #define ASIZ_thread_xfsr	0x00000038
-#define ASIZ_thread	0x00000440
+#define ASIZ_thread	0x00000470
 
 #else /* __SMP__ */
 
+#ifndef SPIN_LOCK_DEBUG
+
 #define AOFF_task_state	0x00000000
 #define ASIZ_task_state	0x00000008
 #define AOFF_task_flags	0x00000008
@@ -437,30 +449,314 @@
 #define AOFF_task_semsleeping	0x00000560
 #define ASIZ_task_semsleeping	0x00000008
 #define AOFF_task_tss	0x00000570
-#define ASIZ_task_tss	0x00000440
-#define AOFF_task_fs	0x000009b0
+#define ASIZ_task_tss	0x00000470
+#define AOFF_task_fs	0x000009e0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000009b8
+#define AOFF_task_files	0x000009e8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x000009c0
+#define AOFF_task_mm	0x000009f0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000009c8
+#define AOFF_task_sigmask_lock	0x000009f8
 #define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x000009d0
+#define AOFF_task_sig	0x00000a00
+#define ASIZ_task_sig	0x00000008
+#define AOFF_task_signal	0x00000a08
+#define ASIZ_task_signal	0x00000008
+#define AOFF_task_blocked	0x00000a10
+#define ASIZ_task_blocked	0x00000008
+#define AOFF_task_sigqueue	0x00000a18
+#define ASIZ_task_sigqueue	0x00000008
+#define AOFF_task_sigqueue_tail	0x00000a20
+#define ASIZ_task_sigqueue_tail	0x00000008
+#define AOFF_task_sas_ss_sp	0x00000a28
+#define ASIZ_task_sas_ss_sp	0x00000008
+#define AOFF_task_sas_ss_size	0x00000a30
+#define ASIZ_task_sas_ss_size	0x00000008
+#define ASIZ_task	0x00000a40
+#define AOFF_mm_mmap	0x00000000
+#define ASIZ_mm_mmap	0x00000008
+#define AOFF_mm_mmap_cache	0x00000008
+#define ASIZ_mm_mmap_cache	0x00000008
+#define AOFF_mm_pgd	0x00000010
+#define ASIZ_mm_pgd	0x00000008
+#define AOFF_mm_count	0x00000018
+#define ASIZ_mm_count	0x00000004
+#define AOFF_mm_map_count	0x0000001c
+#define ASIZ_mm_map_count	0x00000004
+#define AOFF_mm_mmap_sem	0x00000020
+#define ASIZ_mm_mmap_sem	0x00000010
+#define AOFF_mm_context	0x00000030
+#define ASIZ_mm_context	0x00000008
+#define AOFF_mm_start_code	0x00000038
+#define ASIZ_mm_start_code	0x00000008
+#define AOFF_mm_end_code	0x00000040
+#define ASIZ_mm_end_code	0x00000008
+#define AOFF_mm_start_data	0x00000048
+#define ASIZ_mm_start_data	0x00000008
+#define AOFF_mm_end_data	0x00000050
+#define ASIZ_mm_end_data	0x00000008
+#define AOFF_mm_start_brk	0x00000058
+#define ASIZ_mm_start_brk	0x00000008
+#define AOFF_mm_brk	0x00000060
+#define ASIZ_mm_brk	0x00000008
+#define AOFF_mm_start_stack	0x00000068
+#define ASIZ_mm_start_stack	0x00000008
+#define AOFF_mm_arg_start	0x00000070
+#define ASIZ_mm_arg_start	0x00000008
+#define AOFF_mm_arg_end	0x00000078
+#define ASIZ_mm_arg_end	0x00000008
+#define AOFF_mm_env_start	0x00000080
+#define ASIZ_mm_env_start	0x00000008
+#define AOFF_mm_env_end	0x00000088
+#define ASIZ_mm_env_end	0x00000008
+#define AOFF_mm_rss	0x00000090
+#define ASIZ_mm_rss	0x00000008
+#define AOFF_mm_total_vm	0x00000098
+#define ASIZ_mm_total_vm	0x00000008
+#define AOFF_mm_locked_vm	0x000000a0
+#define ASIZ_mm_locked_vm	0x00000008
+#define AOFF_mm_def_flags	0x000000a8
+#define ASIZ_mm_def_flags	0x00000008
+#define AOFF_mm_cpu_vm_mask	0x000000b0
+#define ASIZ_mm_cpu_vm_mask	0x00000008
+#define AOFF_mm_segments	0x000000b8
+#define ASIZ_mm_segments	0x00000008
+#define ASIZ_mm	0x000000c0
+#define AOFF_thread_ksp	0x00000000
+#define ASIZ_thread_ksp	0x00000008
+#define AOFF_thread_wstate	0x00000008
+#define ASIZ_thread_wstate	0x00000002
+#define AOFF_thread_cwp	0x0000000a
+#define ASIZ_thread_cwp	0x00000002
+#define AOFF_thread_flags	0x0000000c
+#define ASIZ_thread_flags	0x00000002
+#define AOFF_thread_ctx	0x0000000e
+#define ASIZ_thread_ctx	0x00000002
+#define AOFF_thread_w_saved	0x00000010
+#define ASIZ_thread_w_saved	0x00000002
+#define AOFF_thread_new_signal	0x00000012
+#define ASIZ_thread_new_signal	0x00000002
+#define AOFF_thread____pad	0x00000014
+#define ASIZ_thread____pad	0x00000004
+#define AOFF_thread_current_ds	0x00000018
+#define ASIZ_thread_current_ds	0x00000008
+#define AOFF_thread_kregs	0x00000020
+#define ASIZ_thread_kregs	0x00000008
+#define AOFF_thread_utraps	0x00000028
+#define ASIZ_thread_utraps	0x00000008
+#define AOFF_thread_reg_window	0x00000030
+#define ASIZ_thread_reg_window	0x00000380
+#define AOFF_thread_rwbuf_stkptrs	0x000003b0
+#define ASIZ_thread_rwbuf_stkptrs	0x00000038
+#define AOFF_thread_sig_address	0x000003e8
+#define ASIZ_thread_sig_address	0x00000008
+#define AOFF_thread_sig_desc	0x000003f0
+#define ASIZ_thread_sig_desc	0x00000008
+#define AOFF_thread_user_cntd0	0x000003f8
+#define ASIZ_thread_user_cntd0	0x00000008
+#define AOFF_thread_user_cntd1	0x00000400
+#define ASIZ_thread_user_cntd1	0x00000008
+#define AOFF_thread_kernel_cntd0	0x00000408
+#define ASIZ_thread_kernel_cntd0	0x00000008
+#define AOFF_thread_kernel_cntd1	0x00000410
+#define ASIZ_thread_kernel_cntd1	0x00000008
+#define AOFF_thread_pcr_reg	0x00000418
+#define ASIZ_thread_pcr_reg	0x00000008
+#define AOFF_thread_fpdepth	0x00000420
+#define ASIZ_thread_fpdepth	0x00000001
+#define AOFF_thread_fpsaved	0x00000421
+#define ASIZ_thread_fpsaved	0x00000007
+#define AOFF_thread_gsr	0x00000428
+#define ASIZ_thread_gsr	0x00000007
+#define AOFF_thread_xfsr	0x00000430
+#define ASIZ_thread_xfsr	0x00000038
+#define ASIZ_thread	0x00000470
+
+#else /* SPIN_LOCK_DEBUG */
+
+#define AOFF_task_state	0x00000000
+#define ASIZ_task_state	0x00000008
+#define AOFF_task_flags	0x00000008
+#define ASIZ_task_flags	0x00000008
+#define AOFF_task_sigpending	0x00000010
+#define ASIZ_task_sigpending	0x00000004
+#define AOFF_task_addr_limit	0x00000018
+#define ASIZ_task_addr_limit	0x00000008
+#define AOFF_task_exec_domain	0x00000020
+#define ASIZ_task_exec_domain	0x00000008
+#define AOFF_task_need_resched	0x00000028
+#define ASIZ_task_need_resched	0x00000008
+#define AOFF_task_counter	0x00000030
+#define ASIZ_task_counter	0x00000008
+#define AOFF_task_priority	0x00000038
+#define ASIZ_task_priority	0x00000008
+#define AOFF_task_has_cpu	0x00000040
+#define ASIZ_task_has_cpu	0x00000004
+#define AOFF_task_processor	0x00000044
+#define ASIZ_task_processor	0x00000004
+#define AOFF_task_last_processor	0x00000048
+#define ASIZ_task_last_processor	0x00000004
+#define AOFF_task_lock_depth	0x0000004c
+#define ASIZ_task_lock_depth	0x00000004
+#define AOFF_task_next_task	0x00000050
+#define ASIZ_task_next_task	0x00000008
+#define AOFF_task_prev_task	0x00000058
+#define ASIZ_task_prev_task	0x00000008
+#define AOFF_task_next_run	0x00000060
+#define ASIZ_task_next_run	0x00000008
+#define AOFF_task_prev_run	0x00000068
+#define ASIZ_task_prev_run	0x00000008
+#define AOFF_task_binfmt	0x00000070
+#define ASIZ_task_binfmt	0x00000008
+#define AOFF_task_exit_code	0x00000078
+#define ASIZ_task_exit_code	0x00000004
+#define AOFF_task_exit_signal	0x0000007c
+#define ASIZ_task_exit_signal	0x00000004
+#define AOFF_task_pdeath_signal	0x00000080
+#define ASIZ_task_pdeath_signal	0x00000004
+#define AOFF_task_personality	0x00000088
+#define ASIZ_task_personality	0x00000008
+#define AOFF_task_pid	0x00000094
+#define ASIZ_task_pid	0x00000004
+#define AOFF_task_pgrp	0x00000098
+#define ASIZ_task_pgrp	0x00000004
+#define AOFF_task_tty_old_pgrp	0x0000009c
+#define ASIZ_task_tty_old_pgrp	0x00000004
+#define AOFF_task_session	0x000000a0
+#define ASIZ_task_session	0x00000004
+#define AOFF_task_leader	0x000000a4
+#define ASIZ_task_leader	0x00000004
+#define AOFF_task_p_opptr	0x000000a8
+#define ASIZ_task_p_opptr	0x00000008
+#define AOFF_task_p_pptr	0x000000b0
+#define ASIZ_task_p_pptr	0x00000008
+#define AOFF_task_p_cptr	0x000000b8
+#define ASIZ_task_p_cptr	0x00000008
+#define AOFF_task_p_ysptr	0x000000c0
+#define ASIZ_task_p_ysptr	0x00000008
+#define AOFF_task_p_osptr	0x000000c8
+#define ASIZ_task_p_osptr	0x00000008
+#define AOFF_task_pidhash_next	0x000000d0
+#define ASIZ_task_pidhash_next	0x00000008
+#define AOFF_task_pidhash_pprev	0x000000d8
+#define ASIZ_task_pidhash_pprev	0x00000008
+#define AOFF_task_tarray_ptr	0x000000e0
+#define ASIZ_task_tarray_ptr	0x00000008
+#define AOFF_task_wait_chldexit	0x000000e8
+#define ASIZ_task_wait_chldexit	0x00000008
+#define AOFF_task_timeout	0x000000f0
+#define ASIZ_task_timeout	0x00000008
+#define AOFF_task_policy	0x000000f8
+#define ASIZ_task_policy	0x00000008
+#define AOFF_task_rt_priority	0x00000100
+#define ASIZ_task_rt_priority	0x00000008
+#define AOFF_task_it_real_value	0x00000108
+#define ASIZ_task_it_real_value	0x00000008
+#define AOFF_task_it_prof_value	0x00000110
+#define ASIZ_task_it_prof_value	0x00000008
+#define AOFF_task_it_virt_value	0x00000118
+#define ASIZ_task_it_virt_value	0x00000008
+#define AOFF_task_it_real_incr	0x00000120
+#define ASIZ_task_it_real_incr	0x00000008
+#define AOFF_task_it_prof_incr	0x00000128
+#define ASIZ_task_it_prof_incr	0x00000008
+#define AOFF_task_it_virt_incr	0x00000130
+#define ASIZ_task_it_virt_incr	0x00000008
+#define AOFF_task_real_timer	0x00000138
+#define ASIZ_task_real_timer	0x00000028
+#define AOFF_task_times	0x00000160
+#define ASIZ_task_times	0x00000020
+#define AOFF_task_start_time	0x00000180
+#define ASIZ_task_start_time	0x00000008
+#define AOFF_task_per_cpu_utime	0x00000188
+#define ASIZ_task_per_cpu_utime	0x00000100
+#define AOFF_task_min_flt	0x00000388
+#define ASIZ_task_min_flt	0x00000008
+#define AOFF_task_maj_flt	0x00000390
+#define ASIZ_task_maj_flt	0x00000008
+#define AOFF_task_nswap	0x00000398
+#define ASIZ_task_nswap	0x00000008
+#define AOFF_task_cmin_flt	0x000003a0
+#define ASIZ_task_cmin_flt	0x00000008
+#define AOFF_task_cmaj_flt	0x000003a8
+#define ASIZ_task_cmaj_flt	0x00000008
+#define AOFF_task_cnswap	0x000003b0
+#define ASIZ_task_cnswap	0x00000008
+#define AOFF_task_swap_address	0x000003c0
+#define ASIZ_task_swap_address	0x00000008
+#define AOFF_task_old_maj_flt	0x000003c8
+#define ASIZ_task_old_maj_flt	0x00000008
+#define AOFF_task_dec_flt	0x000003d0
+#define ASIZ_task_dec_flt	0x00000008
+#define AOFF_task_swap_cnt	0x000003d8
+#define ASIZ_task_swap_cnt	0x00000008
+#define AOFF_task_uid	0x000003e0
+#define ASIZ_task_uid	0x00000004
+#define AOFF_task_euid	0x000003e4
+#define ASIZ_task_euid	0x00000004
+#define AOFF_task_suid	0x000003e8
+#define ASIZ_task_suid	0x00000004
+#define AOFF_task_fsuid	0x000003ec
+#define ASIZ_task_fsuid	0x00000004
+#define AOFF_task_gid	0x000003f0
+#define ASIZ_task_gid	0x00000004
+#define AOFF_task_egid	0x000003f4
+#define ASIZ_task_egid	0x00000004
+#define AOFF_task_sgid	0x000003f8
+#define ASIZ_task_sgid	0x00000004
+#define AOFF_task_fsgid	0x000003fc
+#define ASIZ_task_fsgid	0x00000004
+#define AOFF_task_ngroups	0x00000400
+#define ASIZ_task_ngroups	0x00000004
+#define AOFF_task_groups	0x00000404
+#define ASIZ_task_groups	0x00000080
+#define AOFF_task_cap_effective	0x00000484
+#define ASIZ_task_cap_effective	0x00000004
+#define AOFF_task_cap_inheritable	0x00000488
+#define ASIZ_task_cap_inheritable	0x00000004
+#define AOFF_task_cap_permitted	0x0000048c
+#define ASIZ_task_cap_permitted	0x00000004
+#define AOFF_task_user	0x00000490
+#define ASIZ_task_user	0x00000008
+#define AOFF_task_rlim	0x00000498
+#define ASIZ_task_rlim	0x000000a0
+#define AOFF_task_used_math	0x00000538
+#define ASIZ_task_used_math	0x00000002
+#define AOFF_task_comm	0x0000053a
+#define ASIZ_task_comm	0x00000010
+#define AOFF_task_link_count	0x0000054c
+#define ASIZ_task_link_count	0x00000004
+#define AOFF_task_tty	0x00000550
+#define ASIZ_task_tty	0x00000008
+#define AOFF_task_semundo	0x00000558
+#define ASIZ_task_semundo	0x00000008
+#define AOFF_task_semsleeping	0x00000560
+#define ASIZ_task_semsleeping	0x00000008
+#define AOFF_task_tss	0x00000570
+#define ASIZ_task_tss	0x00000470
+#define AOFF_task_fs	0x000009e0
+#define ASIZ_task_fs	0x00000008
+#define AOFF_task_files	0x000009e8
+#define ASIZ_task_files	0x00000008
+#define AOFF_task_mm	0x000009f0
+#define ASIZ_task_mm	0x00000008
+#define AOFF_task_sigmask_lock	0x000009f8
+#define ASIZ_task_sigmask_lock	0x0000000c
+#define AOFF_task_sig	0x00000a08
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x000009d8
+#define AOFF_task_signal	0x00000a10
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x000009e0
+#define AOFF_task_blocked	0x00000a18
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x000009e8
+#define AOFF_task_sigqueue	0x00000a20
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x000009f0
+#define AOFF_task_sigqueue_tail	0x00000a28
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x000009f8
+#define AOFF_task_sas_ss_sp	0x00000a30
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000a00
+#define AOFF_task_sas_ss_size	0x00000a38
 #define ASIZ_task_sas_ss_size	0x00000008
-#define ASIZ_task	0x00000a10
+#define ASIZ_task	0x00000a40
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_cache	0x00000008
@@ -540,15 +836,26 @@
 #define ASIZ_thread_sig_address	0x00000008
 #define AOFF_thread_sig_desc	0x000003f0
 #define ASIZ_thread_sig_desc	0x00000008
-#define AOFF_thread_fpdepth	0x000003f8
+#define AOFF_thread_user_cntd0	0x000003f8
+#define ASIZ_thread_user_cntd0	0x00000008
+#define AOFF_thread_user_cntd1	0x00000400
+#define ASIZ_thread_user_cntd1	0x00000008
+#define AOFF_thread_kernel_cntd0	0x00000408
+#define ASIZ_thread_kernel_cntd0	0x00000008
+#define AOFF_thread_kernel_cntd1	0x00000410
+#define ASIZ_thread_kernel_cntd1	0x00000008
+#define AOFF_thread_pcr_reg	0x00000418
+#define ASIZ_thread_pcr_reg	0x00000008
+#define AOFF_thread_fpdepth	0x00000420
 #define ASIZ_thread_fpdepth	0x00000001
-#define AOFF_thread_fpsaved	0x000003f9
+#define AOFF_thread_fpsaved	0x00000421
 #define ASIZ_thread_fpsaved	0x00000007
-#define AOFF_thread_gsr	0x00000400
+#define AOFF_thread_gsr	0x00000428
 #define ASIZ_thread_gsr	0x00000007
-#define AOFF_thread_xfsr	0x00000408
+#define AOFF_thread_xfsr	0x00000430
 #define ASIZ_thread_xfsr	0x00000038
-#define ASIZ_thread	0x00000440
+#define ASIZ_thread	0x00000470
+#endif /* SPIN_LOCK_DEBUG */
 
 #endif /* __SMP__ */
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h
--- v2.1.126/linux/include/asm-sparc64/dma.h	Fri May  8 23:14:56 1998
+++ linux/include/asm-sparc64/dma.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.8 1998/04/13 07:27:06 davem Exp $
+/* $Id: dma.h,v 1.9 1998/10/26 20:03:15 davem Exp $
  * include/asm-sparc64/dma.h
  *
  * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -13,6 +13,21 @@
 #include <asm/sbus.h>
 #include <asm/delay.h>
 #include <asm/oplib.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dma_spin_lock, flags);
+	return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
 
 /* These are irrelevant for Sparc DMA, but we leave it in so that
  * things can compile.
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/fcntl.h linux/include/asm-sparc64/fcntl.h
--- v2.1.126/linux/include/asm-sparc64/fcntl.h	Fri Oct 23 22:01:26 1998
+++ linux/include/asm-sparc64/fcntl.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: fcntl.h,v 1.4 1998/08/26 10:33:36 davem Exp $ */
+/* $Id: fcntl.h,v 1.5 1998/10/26 20:03:15 davem Exp $ */
 #ifndef _SPARC64_FCNTL_H
 #define _SPARC64_FCNTL_H
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h
--- v2.1.126/linux/include/asm-sparc64/floppy.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/floppy.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: floppy.h,v 1.15 1998/09/14 18:28:37 ecd Exp $
+/* $Id: floppy.h,v 1.16 1998/10/06 20:32:15 ecd Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -661,8 +661,9 @@
 			tmp |= FCR_LDE;
 			ns87303_writeb(config, FCR, tmp);
 
+			tmp = sun_floppy_types[0];
 			sun_floppy_types[0] = sun_floppy_types[1];
-			sun_floppy_types[1] = 0;
+			sun_floppy_types[1] = tmp;
 
 			if (sun_pci_broken_drive != -1) {
 				sun_pci_broken_drive = 1 - sun_pci_broken_drive;
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.1.126/linux/include/asm-sparc64/hardirq.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/hardirq.h	Tue Oct 27 09:52:21 1998
@@ -1,6 +1,6 @@
 /* hardirq.h: 64-bit Sparc hard IRQ support.
  *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #ifndef __SPARC64_HARDIRQ_H
@@ -13,7 +13,12 @@
 #else
 #define local_irq_count		(cpu_data[smp_processor_id()].irq_count)
 #endif
-#define in_interrupt()		(local_irq_count != 0)
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ((local_irq_count + local_bh_count) != 0)
 
 #ifndef __SMP__
 
@@ -47,7 +52,7 @@
 
 static inline void hardirq_enter(int cpu)
 {
-	++cpu_data[cpu].irq_count;
+	++(cpu_data[cpu].irq_count);
 	atomic_inc(&global_irq_count);
 	membar("#StoreLoad | #StoreStore");
 }
@@ -56,31 +61,16 @@
 {
 	membar("#StoreStore | #LoadStore");
 	atomic_dec(&global_irq_count);
-	--cpu_data[cpu].irq_count;
+	--(cpu_data[cpu].irq_count);
 }
 
 static inline int hardirq_trylock(int cpu)
 {
-	unsigned long flags;
-
-	__save_and_cli(flags);
-	atomic_inc(&global_irq_count);
-	if(atomic_read(&global_irq_count) != 1 ||
-	   (*(((unsigned char *)(&global_irq_lock)))) != 0) {
-		atomic_dec(&global_irq_count);
-		__restore_flags(flags);
-		return 0;
-	}
-	++cpu_data[cpu].irq_count;
-	return 1;
+	return (! atomic_read(&global_irq_count) &&
+		! spin_is_locked (&global_irq_lock));
 }
 
-static inline void hardirq_endlock(int cpu)
-{
-	__cli();
-	hardirq_exit(cpu);
-	__sti();
-}
+#define hardirq_endlock(cpu)	do { } while (0)
 
 extern void synchronize_irq(void);
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/ioctl.h linux/include/asm-sparc64/ioctl.h
--- v2.1.126/linux/include/asm-sparc64/ioctl.h	Fri Dec 13 01:37:47 1996
+++ linux/include/asm-sparc64/ioctl.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: ioctl.h,v 1.1 1996/12/02 00:05:36 davem Exp $ */
+/* $Id: ioctl.h,v 1.2 1998/10/15 05:40:38 jj Exp $ */
 #ifndef _SPARC64_IOCTL_H
 #define _SPARC64_IOCTL_H
 
@@ -39,5 +39,13 @@
 #define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
 #define _IOC_NR(nr)         (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
 #define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the PCMCIA... */
+
+#define IOC_IN          (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT         (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT       ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK    (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT   (_IOC_SIZESHIFT)
 
 #endif /* !(_SPARC64_IOCTL_H) */
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- v2.1.126/linux/include/asm-sparc64/mmu_context.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/mmu_context.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.31 1998/09/24 03:22:01 davem Exp $ */
+/* $Id: mmu_context.h,v 1.32 1998/10/13 14:03:52 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -118,11 +118,10 @@
  * the context for the new mm so we see the new mappings.
  */
 #define activate_context(__tsk)		\
-do {	unsigned long __flags;		\
-	__save_and_cli(__flags);	\
-	flushw_user();			\
+do {	flushw_user();			\
+	spin_lock(&scheduler_lock);	\
 	__get_mmu_context(__tsk);	\
-	__restore_flags(__flags);	\
+	spin_unlock(&scheduler_lock);	\
 } while(0)
 
 #endif /* !(__ASSEMBLY__) */
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h
--- v2.1.126/linux/include/asm-sparc64/namei.h	Thu Apr 23 20:21:38 1998
+++ linux/include/asm-sparc64/namei.h	Tue Oct 27 14:48:45 1998
@@ -12,7 +12,7 @@
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
 static inline struct dentry *
-__sparc64_lookup_dentry(const char *name, int follow_link)
+__sparc64_lookup_dentry(const char *name, int lookup_flags)
 {
 	struct dentry *base;
 	char *emul;
@@ -29,18 +29,18 @@
 		return NULL;
 	}
 
-	base = lookup_dentry (emul, dget (current->fs->root), 1);
+	base = lookup_dentry (emul, dget (current->fs->root), (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
 			
 	if (IS_ERR (base)) return NULL;
 	
-	base = lookup_dentry (name, base, follow_link);
+	base = lookup_dentry (name, base, lookup_flags);
 	
 	if (IS_ERR (base)) return NULL;
 	
 	if (!base->d_inode) {
 		struct dentry *fromroot;
 		
-		fromroot = lookup_dentry (name, dget (current->fs->root), follow_link);
+		fromroot = lookup_dentry (name, dget (current->fs->root), lookup_flags);
 		
 		if (IS_ERR (fromroot)) return base;
 		
@@ -55,9 +55,9 @@
 	return base;
 }
 
-#define __prefix_lookup_dentry(name, follow_link)				\
+#define __prefix_lookup_dentry(name, lookup_flags)				\
 	if (current->personality) {						\
-		dentry = __sparc64_lookup_dentry (name, follow_link);		\
+		dentry = __sparc64_lookup_dentry (name, lookup_flags);		\
 		if (dentry) return dentry;					\
 	}
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/oplib.h linux/include/asm-sparc64/oplib.h
--- v2.1.126/linux/include/asm-sparc64/oplib.h	Thu Jul 31 13:09:18 1997
+++ linux/include/asm-sparc64/oplib.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.8 1997/07/24 12:15:15 davem Exp $
+/* $Id: oplib.h,v 1.9 1998/10/06 20:56:05 ecd Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -117,8 +117,8 @@
  * kernel is still active, the prom will call this routine.
  *
  */
-typedef void (*sync_func_t)(long *cmd);
-extern void prom_setsync(sync_func_t func_ptr);
+typedef int (*callback_func_t)(long *cmd);
+extern void prom_setcallback(callback_func_t func_ptr);
 
 /* Acquire the IDPROM of the root node in the prom device tree.  This
  * gets passed a buffer where you would like it stuffed.  The return value
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- v2.1.126/linux/include/asm-sparc64/page.h	Thu Aug  6 14:06:34 1998
+++ linux/include/asm-sparc64/page.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.23 1998/06/12 14:54:33 jj Exp $ */
+/* $Id: page.h,v 1.24 1998/10/20 03:09:16 jj Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -18,7 +18,7 @@
 
 #ifndef __ASSEMBLY__
 
-#define clear_page(page)		memset((void *)(page), 0, PAGE_SIZE)
+extern void clear_page(unsigned long page);
 extern void copy_page(unsigned long to, unsigned long from);
 
 /* GROSS, defining this makes gcc pass these types as aggregates,
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/perfctr.h linux/include/asm-sparc64/perfctr.h
--- v2.1.126/linux/include/asm-sparc64/perfctr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/perfctr.h	Tue Oct 27 09:52:21 1998
@@ -0,0 +1,101 @@
+/*----------------------------------------
+  PERFORMANCE INSTRUMENTATION  
+  Guillaume Thouvenin           08/10/98
+  David S. Miller               10/06/98
+  ---------------------------------------*/
+#ifndef PERF_COUNTER_API
+#define PERF_COUNTER_API
+
+/* sys_perfctr() interface.  First arg is operation code
+ * from enumeration below.  The meaning of further arguments
+ * are determined by the operation code.
+ *
+ * int sys_perfctr(int opcode, unsigned long arg0,
+ *                 unsigned long arg1, unsigned long arg2)
+ *
+ * Pointers which are passed by the user are pointers to 64-bit
+ * integers.
+ *
+ * Once enabled, performance counter state is retained until the
+ * process either exits or performs an exec.  That is, performance
+ * counters remain enabled for fork/clone children.
+ */
+enum perfctr_opcode {
+	/* Enable UltraSparc performance counters, ARG0 is pointer
+	 * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer
+	 * to 64-bit accumulator for D1 counter.  ARG2 is a pointer to
+	 * the initial PCR register value to use.
+	 */
+	PERFCTR_ON,
+
+	/* Disable UltraSparc performance counters.  The PCR is written
+	 * with zero and the user counter accumulator pointers and
+	 * working PCR register value are forgotten.
+	 */
+	PERFCTR_OFF,
+
+	/* Add current D0 and D1 PIC values into user pointers given
+	 * in PERFCTR_ON operation.  The PIC is cleared before returning.
+	 */
+	PERFCTR_READ,
+
+	/* Clear the PIC register. */
+	PERFCTR_CLRPIC,
+
+	/* Begin using a new PCR value, the pointer to which is passed
+	 * in ARG0.  The PIC is also cleared after the new PCR value is
+	 * written.
+	 */
+	PERFCTR_SETPCR,
+
+	/* Store in pointer given in ARG0 the current PCR register value
+	 * being used.
+	 */
+	PERFCTR_GETPCR
+};
+
+/* I don't want the kernel's namespace to be polluted with this
+ * stuff when this file is included.  --DaveM
+ */
+#ifndef __KERNEL__
+
+#define  PRIV 0x00000001
+#define  USR  0x00000002
+#define  SYS  0x00000004
+
+/* Pic.S0 Selection Bit Field Encoding  */
+#define  CYCLE_CNT            0x00000000
+#define  INSTR_CNT            0x00000010
+#define  DISPATCH0_IC_MISS    0x00000020
+#define  DISPATCH0_STOREBUF   0x00000030
+#define  IC_REF               0x00000080
+#define  DC_RD                0x00000090
+#define  DC_WR                0x000000A0
+#define  LOAD_USE             0x000000B0
+#define  EC_REF               0x000000C0
+#define  EC_WRITE_HIT_RDO     0x000000D0
+#define  EC_SNOOP_INV         0x000000E0
+#define  EC_RD_HIT            0x000000F0
+
+/* Pic.S1 Selection Bit Field Encoding  */
+#define  CYCLE_CNT_D1         0x00000000
+#define  INSTR_CNT_D1         0x00000800
+#define  DISPATCH0_IC_MISPRED 0x00001000
+#define  DISPATCH0_FP_USE     0x00001800
+#define  IC_HIT               0x00004000
+#define  DC_RD_HIT            0x00004800
+#define  DC_WR_HIT            0x00005000
+#define  LOAD_USE_RAW         0x00005800
+#define  EC_HIT               0x00006000
+#define  EC_WB                0x00006800
+#define  EC_SNOOP_CB          0x00007000
+#define  EC_IT_HIT            0x00007800
+
+struct vcounter_struct {
+  unsigned long long vcnt0;
+  unsigned long long vcnt1;
+};
+
+#endif /* !(__KERNEL__) */
+
+#endif /* !(PERF_COUNTER_API) */
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.1.126/linux/include/asm-sparc64/pgtable.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/pgtable.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.90 1998/09/24 03:21:56 davem Exp $
+/* $Id: pgtable.h,v 1.95 1998/10/22 03:05:57 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -169,10 +169,9 @@
 #define flush_cache_range(mm, start, end)	flushw_user()
 #define flush_cache_page(vma, page)		flushw_user()
 
-extern void flush_page_to_ram(unsigned long page);
-
-/* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
+/* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */
 #define flush_icache_range(start, end)		do { } while (0)
+#define flush_page_to_ram(page)			do { } while (0)
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
 
@@ -379,7 +378,7 @@
 		if(ret) {
 			struct page *page = mem_map + MAP_NR(ret);
 			
-			clear_page(ret);
+			memset(ret, 0, PAGE_SIZE);
 			(unsigned long)page->pprev_hash = 2;
 			(unsigned long *)page->next_hash = pgd_quicklist;
 			pgd_quicklist = (unsigned long *)page;
@@ -409,7 +408,7 @@
 	} else {
 		ret = (unsigned long *) __get_free_page(GFP_KERNEL);
 		if(ret)
-			clear_page(ret);
+			memset(ret, 0, PAGE_SIZE);
 	}
 	return (pgd_t *)ret;
 }
@@ -562,26 +561,41 @@
 #define mmu_lockarea(vaddr, len)		(vaddr)
 #define mmu_unlockarea(vaddr, len)		do { } while(0)
 
+/* There used to be some funny code here which tried to guess which
+ * TLB wanted the mapping, that wasn't accurate enough to justify it's
+ * existance.  The real way to do that is to have each TLB miss handler
+ * pass in a distinct code to do_sparc64_fault() and do it more accurately
+ * there.
+ *
+ * What we do need to handle here is prevent I-cache corruption.  The
+ * deal is that the I-cache snoops stores from other CPUs and all DMA
+ * activity, however stores from the local processor are not snooped.
+ * The dynamic linker and our signal handler mechanism take care of
+ * the cases where they write into instruction space, but when a page
+ * is copied in the kernel and then executed in user-space is not handled
+ * right.  This leads to corruptions if things are "just right", consider
+ * the following scenerio:
+ * 1) Process 1 frees up a page that was used for the PLT of libc in
+ *    it's address space.
+ * 2) Process 2 writes into a page in the PLT of libc for the first
+ *    time.  do_wp_page() copies the page locally, the local I-cache of
+ *    the processor does not notice the writes during the page copy.
+ *    The new page used just so happens to be the one just freed in #1.
+ * 3) After the PLT write, later the cpu calls into an unresolved PLT
+ *    entry, the CPU executes old instructions from process 1's PLT
+ *    table.
+ * 4) Splat.
+ */
+extern void flush_icache_page(unsigned long phys_page);
 #define update_mmu_cache(__vma, __address, _pte) \
-__asm__ __volatile__( \
-	"rdpr	%%pstate, %%g1\n\t" \
-	"wrpr	%%g1, %0, %%pstate\n\t" \
-	"brz,pt	%1, 1f\n\t" \
-	" mov	%2, %%g2\n\t" \
-	"stxa	%3, [%%g2] %5\n\t" \
-	"ba,pt	%%xcc, 2f\n\t" \
-	" stxa	%4, [%%g0] %6\n\t" \
-"1:	stxa	%3, [%%g2] %7\n\t" \
-"	stxa	%4, [%%g0] %8\n\t" \
-"2:	wrpr	%%g1, 0x0, %%pstate\n" \
-	: /* no outputs */ \
-	: "i" (PSTATE_IE), \
-          "r" (((__vma)->vm_flags&(VM_READ|VM_WRITE|VM_EXEC))==(VM_READ|VM_EXEC)), \
-	  "i" (TLB_TAG_ACCESS), \
-	  "r" ((__address) | ((__vma)->vm_mm->context & 0x3ff)), \
-	  "r" (pte_val(_pte)), "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_IN), \
-	  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_IN) \
-	: "g1", "g2")
+do { \
+	unsigned short __flags = ((__vma)->vm_flags); \
+	if ((__flags & VM_EXEC) != 0 && \
+	    ((pte_val(_pte) & (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED)) == \
+	     (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED))) { \
+		flush_icache_page(pte_page(_pte) - page_offset); \
+	} \
+} while(0)
 
 /* Make a non-present pseudo-TTE. */
 extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- v2.1.126/linux/include/asm-sparc64/processor.h	Thu Aug  6 14:06:34 1998
+++ linux/include/asm-sparc64/processor.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.49 1998/07/31 10:42:40 jj Exp $
+/* $Id: processor.h,v 1.51 1998/10/21 03:21:19 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -61,6 +61,11 @@
 	unsigned long sig_address __attribute__ ((aligned (8)));
 	unsigned long sig_desc;
 	
+	/* Performance counter state */
+	u64 *user_cntd0, *user_cntd1;
+	u64 kernel_cntd0, kernel_cntd1;
+	u64 pcr_reg;
+
 	unsigned char fpdepth;
 	unsigned char fpsaved[7];
 	unsigned char gsr[7];
@@ -74,6 +79,7 @@
 #define SPARC_FLAG_NEWSIGNALS   0x040    /* task wants new-style signals */
 #define SPARC_FLAG_32BIT        0x080    /* task is older 32-bit binary */
 #define SPARC_FLAG_NEWCHILD     0x100    /* task is just-spawned child process */
+#define SPARC_FLAG_PERFCTR	0x200    /* task has performance counters active */
 
 #define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \
 		    PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
@@ -91,6 +97,8 @@
    { 0, 0, 0, 0, 0, 0, 0, },					\
 /* sig_address, sig_desc */					\
    0,           0,						\
+/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
+   0,          0,          0,		 0,            0,	\
 /* fpdepth, fpsaved, gsr,   xfsr */				\
    0,       { 0 },   { 0 }, { 0 },				\
 }
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/psrcompat.h linux/include/asm-sparc64/psrcompat.h
--- v2.1.126/linux/include/asm-sparc64/psrcompat.h	Mon Jul  7 08:18:56 1997
+++ linux/include/asm-sparc64/psrcompat.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: psrcompat.h,v 1.4 1997/06/20 11:54:39 davem Exp $ */
+/* $Id: psrcompat.h,v 1.5 1998/10/06 09:28:39 jj Exp $ */
 #ifndef _SPARC64_PSRCOMPAT_H
 #define _SPARC64_PSRCOMPAT_H
 
@@ -21,21 +21,24 @@
 #define PSR_VERS    0x0f000000         /* cpu-version field          */
 #define PSR_IMPL    0xf0000000         /* cpu-implementation field   */
 
+#define PSR_V8PLUS  0xff000000         /* fake impl/ver, meaning a 64bit CPU is present */
+#define PSR_XCC	    0x000f0000         /* if PSR_V8PLUS, this is %xcc */
+
 extern inline unsigned int tstate_to_psr(unsigned long tstate)
 {
-	unsigned long vers;
-
-	__asm__ __volatile__("rdpr	%%ver, %0" : "=r" (vers));
 	return ((tstate & TSTATE_CWP)			|
 		PSR_S					|
 		((tstate & TSTATE_ICC) >> 12)		|
-		(((vers << 8) >> 32) & PSR_IMPL)	|
-		(((vers << 24) >> 36) & PSR_VERS));
+		((tstate & TSTATE_XCC) >> 20)		|
+		PSR_V8PLUS);
 }
 
 extern inline unsigned long psr_to_tstate_icc(unsigned int psr)
 {
-	return ((unsigned long)(psr & PSR_ICC)) << 12;
+	unsigned long tstate = ((unsigned long)(psr & PSR_ICC)) << 12;
+	if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS)
+		tstate |= ((unsigned long)(psr & PSR_XCC)) << 20;
+	return tstate;
 }
 
 #endif /* !(_SPARC64_PSRCOMPAT_H) */
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/sab82532.h linux/include/asm-sparc64/sab82532.h
--- v2.1.126/linux/include/asm-sparc64/sab82532.h	Thu Sep  4 12:54:49 1997
+++ linux/include/asm-sparc64/sab82532.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: sab82532.h,v 1.3 1997/09/03 11:55:04 ecd Exp $
+/* $Id: sab82532.h,v 1.4 1998/10/25 23:04:29 ecd Exp $
  * sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -143,7 +143,7 @@
 	int				 xmit_fifo_size;
 	int				 recv_fifo_size;
 	int				 custom_divisor;
-	int				 quot;
+	int				 baud;
 	int				 x_char;
 	int				 close_delay;
 	unsigned short			 closing_wait;
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h
--- v2.1.126/linux/include/asm-sparc64/semaphore.h	Sat Aug 16 09:51:10 1997
+++ linux/include/asm-sparc64/semaphore.h	Tue Oct 27 09:52:21 1998
@@ -24,17 +24,24 @@
 
 #define wake_one_more(sem)      atomic_inc(&sem->waking);
 
-#define waking_non_zero(sem) \
-({	unsigned long flags; \
-	int ret = 0; \
-	save_and_cli(flags); \
-	if (atomic_read(&sem->waking) > 0) { \
-		atomic_dec(&sem->waking); \
-		ret = 1; \
-	} \
-	restore_flags(flags); \
-	ret; \
-})
+static __inline__ int waking_non_zero(struct semaphore *sem)
+{
+	int ret;
+
+	__asm__ __volatile__("
+1:	ldsw		[%1], %%g5
+	brlez,pt	%%g5, 2f
+	 mov		0, %0
+	sub		%%g5, 1, %%g7
+	cas		[%1], %%g5, %%g7
+	cmp		%%g5, %%g7
+	bne,pn		%%icc, 1b
+	 mov		1, %0
+2:"	: "=r" (ret)
+	: "r" (&((sem)->waking))
+	: "g5", "g7", "cc", "memory");
+	return ret;
+}
 
 extern __inline__ void down(struct semaphore * sem)
 {
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/sigcontext.h linux/include/asm-sparc64/sigcontext.h
--- v2.1.126/linux/include/asm-sparc64/sigcontext.h	Mon Jan 12 15:15:58 1998
+++ linux/include/asm-sparc64/sigcontext.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: sigcontext.h,v 1.10 1997/12/11 15:16:11 jj Exp $ */
+/* $Id: sigcontext.h,v 1.11 1998/10/06 09:28:37 jj Exp $ */
 #ifndef __SPARC64_SIGCONTEXT_H
 #define __SPARC64_SIGCONTEXT_H
 
@@ -76,6 +76,14 @@
 	unsigned   long si_gsr;
 	unsigned   long si_fprs;
 } __siginfo_fpu_t;
+
+/* This magic should be in g_upper[0] for all upper parts
+   to be valid.  */
+#define SIGINFO_EXTRA_V8PLUS_MAGIC	0x130e269
+typedef struct {
+	unsigned   int g_upper[8];
+	unsigned   int o_upper[8];
+} siginfo_extra_v8plus_t;
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- v2.1.126/linux/include/asm-sparc64/smp.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/smp.h	Tue Oct 27 09:52:21 1998
@@ -34,16 +34,16 @@
 struct cpuinfo_sparc {
 	/* Dcache line 1 */
 	unsigned long	irq_count;
+	unsigned long	bh_count;
 	unsigned int	multiplier;
 	unsigned int	counter;
-	unsigned long	pgcache_size;
-	unsigned long	pgdcache_size;
+	unsigned long	udelay_val;
 
 	/* Dcache line 2 */
-	unsigned long	*pgd_cache;
+	unsigned long	pgcache_size;
 	unsigned long	*pte_cache;
-	unsigned long	udelay_val;
-	unsigned long	dummy;
+	unsigned long	pgdcache_size;
+	unsigned long	*pgd_cache;
 };
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/smplock.h linux/include/asm-sparc64/smplock.h
--- v2.1.126/linux/include/asm-sparc64/smplock.h	Mon Aug  3 17:48:28 1998
+++ linux/include/asm-sparc64/smplock.h	Tue Oct 27 09:52:21 1998
@@ -3,6 +3,7 @@
  *
  * Default SMP lock implementation
  */
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <asm/spinlock.h>
 
@@ -36,14 +37,14 @@
  * so we only need to worry about other
  * CPU's.
  */
-extern __inline__ void lock_kernel(void)
-{
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
+#define lock_kernel() \
+do { \
+	if (!++current->lock_depth) \
+		spin_lock(&kernel_flag); \
+} while(0)
+
+#define unlock_kernel() \
+do { \
+	if (--current->lock_depth < 0) \
+		spin_unlock(&kernel_flag); \
+} while(0)
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h
--- v2.1.126/linux/include/asm-sparc64/softirq.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/softirq.h	Tue Oct 27 09:52:21 1998
@@ -1,6 +1,6 @@
 /* softirq.h: 64-bit Sparc soft IRQ support.
  *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #ifndef __SPARC64_SOFTIRQ_H
@@ -9,129 +9,121 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
+#ifndef __SMP__
+extern unsigned int local_bh_count;
+#else
+#define local_bh_count		(cpu_data[smp_processor_id()].bh_count)
+#endif
+
 /* The locking mechanism for base handlers, to prevent re-entrancy,
  * is entirely private to an implementation, it should not be
  * referenced at all outside of this file.
  */
 
 #define get_active_bhs()	(bh_mask & bh_active)
+#define clear_active_bhs(mask)			\
+	__asm__ __volatile__(			\
+"1:	ldx	[%1], %%g7\n"			\
+"	andn	%%g7, %0, %%g5\n"		\
+"	casx	[%1], %%g7, %%g5\n"		\
+"	cmp	%%g7, %%g5\n"			\
+"	bne,pn	%%xcc, 1b\n"			\
+"	 nop"					\
+	: /* no outputs */			\
+	: "HIr" (mask), "r" (&bh_active)	\
+	: "g5", "g7", "cc", "memory")
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+	bh_base[nr] = routine;
+	bh_mask_count[nr] = 0;
+	bh_mask |= 1 << nr;
+}
+
+extern inline void remove_bh(int nr)
+{
+	bh_base[nr] = NULL;
+	bh_mask &= ~(1 << nr);
+}
+
+extern inline void mark_bh(int nr)
+{
+	set_bit(nr, &bh_active);
+}
 
 #ifndef __SMP__
 
-extern int __sparc64_bh_counter;
-
-#define softirq_trylock(cpu)	(__sparc64_bh_counter ? 0 : (__sparc64_bh_counter=1))
-#define softirq_endlock(cpu)	(__sparc64_bh_counter = 0)
-#define clear_active_bhs(x)	(bh_active &= ~(x))
-#define synchronize_bh()	barrier() /* XXX implement SMP version -DaveM */
-
-#define init_bh(nr, routine)	\
-do {	int ent = nr;		\
-	bh_base[ent] = routine;	\
-	bh_mask_count[ent] = 0;	\
-	bh_mask |= 1 << ent;	\
-} while(0)
-
-#define remove_bh(nr)		\
-do {	int ent = nr;		\
-	bh_base[ent] = NULL;	\
-	bh_mask &= ~(1 << ent);	\
-} while(0)
-
-#define mark_bh(nr)		(bh_active |= (1 << (nr)))
-
-#define disable_bh(nr)		\
-do {	int ent = nr;		\
-	bh_mask &= ~(1 << ent);	\
-	bh_mask_count[ent]++;	\
-	barrier();		\
-} while(0)
-
-#define enable_bh(nr)			\
-do {	int ent = nr;			\
-	barrier();			\
-	if (!--bh_mask_count[ent])	\
-		bh_mask |= 1 << ent;	\
-} while(0)
-
-#define start_bh_atomic() do { __sparc64_bh_counter++; barrier(); } while(0)
-
-#define end_bh_atomic()	  do { barrier(); __sparc64_bh_counter--; } while(0)
+extern inline void start_bh_atomic(void)
+{
+	local_bh_count++;
+	barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+	barrier();
+	local_bh_count--;
+}
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock(cpu)	(local_bh_count ? 0 : (local_bh_count=1))
+#define softirq_endlock(cpu)	(local_bh_count = 0)
+#define synchronize_bh()	barrier()
 
 #else /* (__SMP__) */
 
-extern atomic_t __sparc64_bh_counter;
+extern atomic_t global_bh_lock;
+extern spinlock_t global_bh_count;
 
-#define start_bh_atomic() \
-	do { atomic_inc(&__sparc64_bh_counter); synchronize_irq(); } while(0)
+extern void synchronize_bh(void);
 
-#define end_bh_atomic()	atomic_dec(&__sparc64_bh_counter)
-
-#include <asm/spinlock.h>
-
-extern spinlock_t global_bh_lock;
-
-#define init_bh(nr, routine)				\
-do {	unsigned long flags;				\
-	int ent = nr;					\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_base[ent] = routine;				\
-	bh_mask_count[ent] = 0;				\
-	bh_mask |= 1 << ent;				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define remove_bh(nr)					\
-do {	unsigned long flags;				\
-	int ent = nr;					\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_base[ent] = NULL;				\
-	bh_mask &= ~(1 << ent);				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define mark_bh(nr)					\
-do {	unsigned long flags;				\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_active |= (1 << nr);				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define disable_bh(nr)					\
-do {	unsigned long flags;				\
-	int ent = nr;					\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_mask &= ~(1 << ent);				\
-	bh_mask_count[ent]++;				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define enable_bh(nr)					\
-do {	unsigned long flags;				\
-	int ent = nr;					\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	if (!--bh_mask_count[ent])			\
-		bh_mask |= 1 << ent;			\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
-
-#define softirq_trylock(cpu)					\
-({								\
-	int ret = 1;						\
-	if(atomic_add_return(1, &__sparc64_bh_counter) != 1) {	\
-		atomic_dec(&__sparc64_bh_counter);		\
-		ret = 0;					\
-	}							\
-	ret;							\
-})
-#define softirq_endlock(cpu)	atomic_dec(&__sparc64_bh_counter)
-#define clear_active_bhs(mask)				\
-do {	unsigned long flags;				\
-	spin_lock_irqsave(&global_bh_lock, flags);	\
-	bh_active &= ~(mask);				\
-	spin_unlock_irqrestore(&global_bh_lock, flags);	\
-} while(0)
+static inline void start_bh_atomic(void)
+{
+	atomic_inc(&global_bh_lock);
+	synchronize_bh();
+}
+
+static inline void end_bh_atomic(void)
+{
+	atomic_dec(&global_bh_lock);
+}
+
+/* These are for the IRQs testing the lock */
+static inline int softirq_trylock(int cpu)
+{
+	if (spin_trylock(&global_bh_count)) {
+		if (atomic_read(&global_bh_lock) == 0) {
+			++(cpu_data[cpu].bh_count);
+			return 1;
+		}
+		spin_unlock(&global_bh_count);
+	}
+	return 0;
+}
+
+static inline void softirq_endlock(int cpu)
+{
+	(cpu_data[cpu].bh_count)--;
+	spin_unlock(&global_bh_count);
+}
 
 #endif /* (__SMP__) */
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+	bh_mask &= ~(1 << nr);
+	bh_mask_count[nr]++;
+	synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+	if (!--bh_mask_count[nr])
+		bh_mask |= 1 << nr;
+}
 
 #endif /* !(__SPARC64_SOFTIRQ_H) */
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- v2.1.126/linux/include/asm-sparc64/spinlock.h	Thu Aug  6 14:06:34 1998
+++ linux/include/asm-sparc64/spinlock.h	Tue Oct 27 09:52:21 1998
@@ -10,13 +10,8 @@
 
 #ifndef __SMP__
 
-#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8)
-  typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { }
-#else
-  typedef unsigned char spinlock_t;
-  #define SPIN_LOCK_UNLOCKED 0
-#endif
+typedef unsigned char spinlock_t;
+#define SPIN_LOCK_UNLOCKED 0
 
 #define spin_lock_init(lock)	do { } while(0)
 #define spin_lock(lock)		do { } while(0)
@@ -58,6 +53,11 @@
 
 #else /* !(__SMP__) */
 
+/* To get debugging spinlocks which detect and catch
+ * deadlock situations, set DEBUG_SPINLOCKS in the sparc64
+ * specific makefile and rebuild your kernel.
+ */
+
 /* All of these locking primitives are expected to work properly
  * even in an RMO memory model, which currently is what the kernel
  * runs in.
@@ -71,10 +71,13 @@
  * must be pre-V9 branches.
  */
 
+#ifndef SPIN_LOCK_DEBUG
+
 typedef unsigned char spinlock_t;
 #define SPIN_LOCK_UNLOCKED	0
 
 #define spin_lock_init(lock)	(*((unsigned char *)(lock)) = 0)
+#define spin_is_locked(lock)	(*((volatile unsigned char *)(lock)) != 0)
 
 #define spin_unlock_wait(lock)	\
 do {	membar("#LoadLoad");	\
@@ -177,8 +180,42 @@
 	: "memory");
 }
 
+#else /* !(SPIN_LOCK_DEBUG) */
+
+typedef struct {
+	unsigned char lock;
+	unsigned int owner_pc, owner_cpu;
+} spinlock_t;
+#define SPIN_LOCK_UNLOCKED { 0, 0, NO_PROC_ID }
+#define spin_lock_init(__lock)	\
+do {	(__lock)->lock = 0; \
+	(__lock)->owner_pc = 0; \
+	(__lock)->owner_cpu = NO_PROC_ID; \
+} while(0)
+#define spin_is_locked(__lock)	(*((volatile unsigned char *)(&((__lock)->lock))) != 0)
+#define spin_unlock_wait(__lock)	\
+do { \
+	membar("#LoadLoad"); \
+} while(*((volatile unsigned char *)(&((__lock)->lock))))
+
+extern void _do_spin_lock (spinlock_t *lock, char *str);
+extern void _do_spin_unlock (spinlock_t *lock);
+extern int _spin_trylock (spinlock_t *lock);
+
+#define spin_trylock(lp)	_spin_trylock(lp)
+#define spin_lock(lock)		_do_spin_lock(lock, "spin_lock")
+#define spin_lock_irq(lock)	do { __cli(); _do_spin_lock(lock, "spin_lock_irq"); } while(0)
+#define spin_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_spin_lock(lock, "spin_lock_irqsave"); } while(0)
+#define spin_unlock(lock)	_do_spin_unlock(lock)
+#define spin_unlock_irq(lock)	do { _do_spin_unlock(lock); __sti(); } while(0)
+#define spin_unlock_irqrestore(lock, flags) do { _do_spin_unlock(lock); __restore_flags(flags); } while(0)
+
+#endif /* SPIN_LOCK_DEBUG */
+
 /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
 
+#ifndef SPIN_LOCK_DEBUG
+
 typedef unsigned long rwlock_t;
 #define RW_LOCK_UNLOCKED	0
 
@@ -277,6 +314,58 @@
 	do { __save_and_cli(flags); write_lock(lock); } while (0)
 #define write_unlock_irqrestore(lock, flags) \
 	do { write_unlock(lock); __restore_flags(flags); } while (0)
+
+#else /* !(SPIN_LOCK_DEBUG) */
+
+typedef struct {
+	unsigned long lock;
+	unsigned int writer_pc, writer_cpu;
+	unsigned int reader_pc[4];
+} rwlock_t;
+#define RW_LOCK_UNLOCKED	{ 0, 0, NO_PROC_ID, { 0, 0, 0, 0 } }
+
+extern void _do_read_lock(rwlock_t *rw, char *str);
+extern void _do_read_unlock(rwlock_t *rw, char *str);
+extern void _do_write_lock(rwlock_t *rw, char *str);
+extern void _do_write_unlock(rwlock_t *rw);
+
+#define read_lock(lock)	\
+do {	unsigned long flags; \
+	__save_and_cli(flags); \
+	_do_read_lock(lock, "read_lock"); \
+	__restore_flags(flags); \
+} while(0)
+#define read_lock_irq(lock)	do { __cli(); _do_read_lock(lock, "read_lock_irq"); } while(0)
+#define read_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_read_lock(lock, "read_lock_irqsave"); } while(0)
+
+#define read_unlock(lock) \
+do {	unsigned long flags; \
+	__save_and_cli(flags); \
+	_do_read_unlock(lock, "read_unlock"); \
+	__restore_flags(flags); \
+} while(0)
+#define read_unlock_irq(lock)	do { _do_read_unlock(lock, "read_unlock_irq"); __sti() } while(0)
+#define read_unlock_irqrestore(lock, flags) do { _do_read_unlock(lock, "read_unlock_irqrestore"); __restore_flags(flags); } while(0)
+
+#define write_lock(lock) \
+do {	unsigned long flags; \
+	__save_and_cli(flags); \
+	_do_write_lock(lock, "write_lock"); \
+	__restore_flags(flags); \
+} while(0)
+#define write_lock_irq(lock)	do { __cli(); _do_write_lock(lock, "write_lock_irq"); } while(0)
+#define write_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_write_lock(lock, "write_lock_irqsave"); } while(0)
+
+#define write_unlock(lock) \
+do {	unsigned long flags; \
+	__save_and_cli(flags); \
+	_do_write_unlock(lock); \
+	__restore_flags(flags); \
+} while(0)
+#define write_unlock_irq(lock)	do { _do_write_unlock(lock); __sti(); } while(0)
+#define write_unlock_irqrestore(lock, flags) do { _do_write_unlock(lock); __restore_flags(flags); } while(0)
+
+#endif /* SPIN_LOCK_DEBUG */
 
 #endif /* __SMP__ */
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h
--- v2.1.126/linux/include/asm-sparc64/string.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/string.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.12 1998/10/04 08:44:27 davem Exp $
+/* $Id: string.h,v 1.14 1998/10/20 03:09:18 jj Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -65,23 +65,7 @@
 
 #define __HAVE_ARCH_MEMSET
 
-extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count)
-{
-	extern __kernel_size_t __bzero(void *, __kernel_size_t);
-	extern void *__bzero_1page(void *);
-
-	if(!c) {
-		if (count == 8192)
-			__bzero_1page(s);
-		else
-			__bzero(s, count);
-	} else {
-		__memset(s, c, count);
-	}
-	return s;
-}
-
-extern inline void *__constant_c_memset(void *s, char c, __kernel_size_t count)
+extern inline void *__constant_memset(void *s, char c, __kernel_size_t count)
 {
 	extern __kernel_size_t __bzero(void *, __kernel_size_t);
 
@@ -100,10 +84,9 @@
 
 #undef memset
 #define memset(s, c, count) \
-(__builtin_constant_p(c) ? (__builtin_constant_p(count) ? \
-                            __constant_c_and_count_memset((s), (c), (count)) : \
-                            __constant_c_memset((s), (c), (count))) \
-                          : __nonconstant_memset((s), (c), (count)))
+(__builtin_constant_p(c) ? \
+ __constant_memset((s), (c), (count)) : \
+ __nonconstant_memset((s), (c), (count)))
 
 #define __HAVE_ARCH_MEMSCAN
 
@@ -128,14 +111,19 @@
 /* Now the str*() stuff... */
 #define __HAVE_ARCH_STRLEN
 
-/* Ugly but it works around a bug in our original sparc64-linux-gcc.  */
 extern __kernel_size_t __strlen(const char *);
+
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
+extern __kernel_size_t strlen(const char *);
+#else /* !EGCS */
+/* Ugly but it works around a bug in our original sparc64-linux-gcc.  */
 #undef strlen
 #define strlen(__arg0)					\
 ({	int __strlen_res = __strlen(__arg0) + 1;	\
 	__strlen_res -= 1;				\
 	__strlen_res;					\
 })
+#endif /* !EGCS */
 
 #define __HAVE_ARCH_STRNCMP
 
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.1.126/linux/include/asm-sparc64/system.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/system.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.44 1998/09/21 03:57:22 davem Exp $ */
+/* $Id: system.h,v 1.47 1998/10/21 03:21:20 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -76,24 +76,17 @@
 #else
 
 #ifndef __ASSEMBLY__
-extern unsigned char global_irq_holder;
-#endif
-
-#define save_flags(x) \
-do {	((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
-		((getipl() != 0) ? 2 : 0))); } while(0)
-
-#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
-
-#ifndef __ASSEMBLY__
 extern void __global_cli(void);
 extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
 extern void __global_restore_flags(unsigned long flags);
 #endif
 
 #define cli()			__global_cli()
 #define sti()			__global_sti()
+#define save_flags(x)		((x) = __global_save_flags())
 #define restore_flags(flags)	__global_restore_flags(flags)
+#define save_and_cli(flags)	do { save_flags(flags); cli(); } while(0)
 
 #endif
 
@@ -107,6 +100,12 @@
 
 #define flushw_all()	__asm__ __volatile__("flushw")
 
+/* Performance counter register access. */
+#define read_pcr(__p)  __asm__ __volatile__("rd	%%pcr, %0" : "=r" (__p))
+#define write_pcr(__p) __asm__ __volatile__("wr	%0, 0x0, %%pcr" : : "r" (__p));
+#define read_pic(__p)  __asm__ __volatile__("rd %%pic, %0" : "=r" (__p))
+#define reset_pic()    __asm__ __volatile__("wr	%g0, 0x0, %pic");
+
 #ifndef __ASSEMBLY__
 
 extern void synchronize_user_stack(void);
@@ -124,21 +123,6 @@
 
 #define flush_user_windows flushw_user
 
-#define DEBUG_SWITCH
-
-#ifdef DEBUG_SWITCH
-#define SWITCH_CTX_CHECK(__tsk) \
-do {	unsigned short ctx_now; \
-	ctx_now = spitfire_get_secondary_context(); \
-	if(ctx_now != (__tsk)->tss.ctx) \
-		printk("[%s:%d] Bogus ctx after switch [%x:%x]\n", \
-		       (__tsk)->comm, (__tsk)->pid, \
-		       (__tsk)->tss.ctx, ctx_now); \
-} while(0)
-#else
-#define SWITCH_CTX_CHECK(__tsk)	do { } while(0)
-#endif
-
 	/* See what happens when you design the chip correctly?
 	 *
 	 * XXX What we are doing here assumes a lot about gcc reload
@@ -156,7 +140,15 @@
 	 *           not reference %g6.
 	 */
 #define switch_to(prev, next)							\
-do {	save_and_clear_fpu();							\
+do {	if (current->tss.flags & SPARC_FLAG_PERFCTR) {				\
+		unsigned long __tmp;						\
+		read_pcr(__tmp);						\
+		current->tss.pcr_reg = __tmp;					\
+		read_pic(__tmp);						\
+		current->tss.kernel_cntd0 += (unsigned int)(__tmp);		\
+		current->tss.kernel_cntd1 += ((__tmp) >> 32);			\
+	}									\
+	save_and_clear_fpu();							\
 	__asm__ __volatile__(							\
 	"flushw\n\t"								\
 	"wrpr	%g0, 0x94, %pstate\n\t");					\
@@ -201,7 +193,11 @@
 	  "l2", "l3", "l4", "l5", "l6", "l7",					\
 	  "i0", "i1", "i2", "i3", "i4", "i5",					\
 	  "o0", "o1", "o2", "o3", "o4", "o5", "o7");				\
-	SWITCH_CTX_CHECK(current);						\
+	/* If you fuck with this, update ret_from_syscall code too. */		\
+	if (current->tss.flags & SPARC_FLAG_PERFCTR) {				\
+		write_pcr(current->tss.pcr_reg);				\
+		reset_pic();							\
+	}									\
 } while(0)
 
 extern __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h
--- v2.1.126/linux/include/asm-sparc64/uaccess.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/uaccess.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.27 1998/09/23 02:04:57 davem Exp $ */
+/* $Id: uaccess.h,v 1.28 1998/10/11 06:58:34 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -45,10 +45,8 @@
 
 #define set_fs(val)								\
 do {										\
-	unsigned long flags;							\
 	if (current->tss.current_ds.seg != val.seg) {				\
 		spin_lock(&scheduler_lock);					\
-		__save_and_cli(flags);						\
 		current->tss.current_ds = (val);				\
 		if (segment_eq((val), KERNEL_DS)) {				\
 			flushw_user ();						\
@@ -58,7 +56,6 @@
 		}								\
 		spitfire_set_secondary_context(current->tss.ctx); 		\
 		__asm__ __volatile__("flush %g6");				\
-		__restore_flags(flags);						\
 		spin_unlock(&scheduler_lock);					\
 	}									\
 } while(0)
diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h
--- v2.1.126/linux/include/asm-sparc64/unistd.h	Mon Oct  5 13:13:44 1998
+++ linux/include/asm-sparc64/unistd.h	Tue Oct 27 09:52:21 1998
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.22 1998/09/13 04:33:14 davem Exp $ */
+/* $Id: unistd.h,v 1.23 1998/10/07 01:28:02 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -33,7 +33,7 @@
 #define __NR_chmod               15 /* Common                                      */
 #define __NR_lchown              16 /* Common                                      */
 #define __NR_brk                 17 /* Common                                      */
-/* #define __NR_ni_syscall       18    ENOSYS under SunOS                          */
+#define __NR_perfctr             18 /* Performance counter operations              */
 #define __NR_lseek               19 /* Common                                      */
 #define __NR_getpid              20 /* Common                                      */
 #define __NR_capget		 21 /* Linux Specific				   */
diff -u --recursive --new-file v2.1.126/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.1.126/linux/include/linux/cdrom.h	Thu Sep 17 17:53:38 1998
+++ linux/include/linux/cdrom.h	Sat Oct 24 10:43:47 1998
@@ -5,6 +5,8 @@
  *               1994, 1995   Eberhard Moenkeberg, emoenke@gwdg.de
  *               1996         David van Leeuwen, david@tm.tno.nl
  *               1997, 1998   Erik Andersen, andersee@debian.org
+ *               1998         Jens Axboe, axboe@image.dk and
+ *                            Chris Zwilling, chris@cloudnet.com
  */
  
 #ifndef	_LINUX_CDROM_H
diff -u --recursive --new-file v2.1.126/linux/include/linux/if.h linux/include/linux/if.h
--- v2.1.126/linux/include/linux/if.h	Sat Sep  5 16:46:41 1998
+++ linux/include/linux/if.h	Sat Nov  7 11:00:31 1998
@@ -43,7 +43,9 @@
 
 #define IFF_PORTSEL	0x2000          /* can set media type		*/
 #define IFF_AUTOMEDIA	0x4000		/* auto media select active	*/
-#define IFF_NODYNARP	0x8000		/* use static ARP only (HIPPI)	*/
+#define IFF_DYNAMIC	0x8000		/* dialup device with changing addresses*/
+
+#ifdef __KERNEL__
 /*
  * The ifaddr structure contains information about one address
  * of an interface.  They are maintained by the different address
@@ -66,6 +68,8 @@
 #define	ifa_broadaddr	ifa_ifu.ifu_broadaddr	/* broadcast address	*/
 #define	ifa_dstaddr	ifa_ifu.ifu_dstaddr	/* other end of link	*/
 
+#endif /* __KERNEL__ */ 
+
 /*
  *	Device mapping structure. I'd just gone off and designed a 
  *	beautiful scheme using only loadable modules with arguments
@@ -115,7 +119,7 @@
 		struct  ifmap ifru_map;
 		char	ifru_slave[IFNAMSIZ];	/* Just fits the size */
 		char	ifru_newname[IFNAMSIZ];
-		__kernel_caddr_t	ifru_data;
+		char *	ifru_data;
 	} ifr_ifru;
 };
 
@@ -148,7 +152,7 @@
 	int	ifc_len;			/* size of buffer	*/
 	union 
 	{
-		__kernel_caddr_t	ifcu_buf;
+		char *			ifcu_buf;
 		struct	ifreq 		*ifcu_req;
 	} ifc_ifcu;
 };
diff -u --recursive --new-file v2.1.126/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.1.126/linux/include/linux/kernel.h	Tue Apr 14 14:29:25 1998
+++ linux/include/linux/kernel.h	Tue Oct 27 09:53:09 1998
@@ -11,7 +11,8 @@
 #include <linux/linkage.h>
 
 /* Optimization barrier */
-#define barrier() __asm__("": : :"memory")
+/* The "volatile" is due to gcc bugs */
+#define barrier() __asm__ __volatile__("": : :"memory")
 
 #define INT_MAX		((int)(~0U>>1))
 #define UINT_MAX	(~0U)
diff -u --recursive --new-file v2.1.126/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.126/linux/include/linux/mm.h	Fri Oct 23 22:01:27 1998
+++ linux/include/linux/mm.h	Sat Nov  7 11:31:11 1998
@@ -254,12 +254,6 @@
 
 /* memory.c & swap.c*/
 
-/*
- * Decide if we should try to do some swapout..
- */
-extern int free_memory_available(void);
-extern struct wait_queue * kswapd_wait;
-
 #define free_page(addr) free_pages((addr),0)
 extern void FASTCALL(free_pages(unsigned long addr, unsigned long order));
 extern void FASTCALL(__free_page(struct page *));
@@ -278,7 +272,7 @@
 extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
 
 extern void vmtruncate(struct inode * inode, unsigned long offset);
-extern void handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
+extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern void make_pages_present(unsigned long addr, unsigned long end);
 
 extern int pgt_cache_water[2];
@@ -330,6 +324,11 @@
 
 #define GFP_DMA		__GFP_DMA
 
+/*
+ * Decide if we should try to do some swapout..
+ */
+extern int free_memory_available(void);
+			
 /* vma is the first one with  address < vma->vm_end,
  * and even  address < vma->vm_start. Have to extend vma. */
 static inline int expand_stack(struct vm_area_struct * vma, unsigned long address)
@@ -378,11 +377,6 @@
 	if (vma && end_addr <= vma->vm_start)
 		vma = NULL;
 	return vma;
-}
-
-extern __inline__ void kswapd_wakeup(void)
-{
-	wake_up(&kswapd_wait);
 }
 
 #define buffer_under_min()	((buffermem >> PAGE_SHIFT) * 100 < \
diff -u --recursive --new-file v2.1.126/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.1.126/linux/include/linux/pagemap.h	Fri Jul 31 17:05:53 1998
+++ linux/include/linux/pagemap.h	Sat Nov  7 11:31:11 1998
@@ -83,7 +83,6 @@
 static inline void __add_page_to_hash_queue(struct page * page, struct page **p)
 {
 	page_cache_size++;
-	set_bit(PG_referenced, &page->flags);
 	page->age = PAGE_AGE_VALUE;
 	if((page->next_hash = *p) != NULL)
 		(*p)->pprev_hash = &page->next_hash;
diff -u --recursive --new-file v2.1.126/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.1.126/linux/include/linux/parport.h	Fri Oct 23 22:01:27 1998
+++ linux/include/linux/parport.h	Sat Nov  7 11:30:03 1998
@@ -208,7 +208,7 @@
 	int number;		/* port index - the `n' in `parportn' */
 	spinlock_t pardevice_lock;
 	spinlock_t waitlist_lock;
-	spinlock_t cad_lock;
+	rwlock_t cad_lock;
 };
 
 /* parport_register_port registers a new parallel port at the given address (if
diff -u --recursive --new-file v2.1.126/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.126/linux/include/linux/pci.h	Fri Oct 23 22:01:27 1998
+++ linux/include/linux/pci.h	Sat Nov  7 11:28:41 1998
@@ -841,6 +841,7 @@
 #define PCI_DEVICE_ID_ATT_L56XMF	0x0440
 
 #define PCI_VENDOR_ID_SPECIALIX		0x11cb
+#define PCI_DEVICE_ID_SPECIALIX_IO8	0x2000
 #define PCI_DEVICE_ID_SPECIALIX_XIO	0x4000
 #define PCI_DEVICE_ID_SPECIALIX_RIO	0x8000
 
diff -u --recursive --new-file v2.1.126/linux/include/linux/poll.h linux/include/linux/poll.h
--- v2.1.126/linux/include/linux/poll.h	Fri Jul 31 17:07:03 1998
+++ linux/include/linux/poll.h	Sat Nov  7 11:31:12 1998
@@ -103,7 +103,7 @@
 	memset(fdset, 0, nr);
 }
 
-extern int do_select(int n, fd_set_buffer *fds, unsigned long timeout);
+extern int do_select(int n, fd_set_buffer *fds, long *timeout);
 
 #endif /* KERNEL */
 
diff -u --recursive --new-file v2.1.126/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.126/linux/include/linux/sched.h	Mon Oct  5 13:13:46 1998
+++ linux/include/linux/sched.h	Sat Nov  7 11:31:11 1998
@@ -119,9 +119,10 @@
 extern void show_state(void);
 extern void trap_init(void);
 
+#define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
+extern signed long FASTCALL(schedule_timeout(signed long timeout));
 asmlinkage void schedule(void);
 
-
 /*
  * Open file table structure
  */
@@ -258,7 +259,7 @@
 	struct task_struct **tarray_ptr;
 
 	struct wait_queue *wait_chldexit;	/* for wait4() */
-	unsigned long timeout, policy, rt_priority;
+	unsigned long policy, rt_priority;
 	unsigned long it_real_value, it_prof_value, it_virt_value;
 	unsigned long it_real_incr, it_prof_incr, it_virt_incr;
 	struct timer_list real_timer;
@@ -348,7 +349,7 @@
 /* pidhash */	NULL, NULL, \
 /* tarray */	&task[0], \
 /* chld wait */	NULL, \
-/* timeout */	0,SCHED_OTHER,0,0,0,0,0,0,0, \
+/* timeout */	SCHED_OTHER,0,0,0,0,0,0,0, \
 /* timer */	{ NULL, NULL, 0, 0, it_real_fn }, \
 /* utime */	{0,0,0,0},0, \
 /* per CPU times */ {0, }, {0, }, \
@@ -457,7 +458,10 @@
 
 extern void FASTCALL(__wake_up(struct wait_queue ** p, unsigned int mode));
 extern void FASTCALL(sleep_on(struct wait_queue ** p));
+extern void FASTCALL(sleep_on(struct wait_queue ** p));
 extern void FASTCALL(interruptible_sleep_on(struct wait_queue ** p));
+extern long FASTCALL(interruptible_sleep_on_timeout(struct wait_queue ** p,
+						    signed long timeout));
 extern void FASTCALL(wake_up_process(struct task_struct * tsk));
 
 #define wake_up(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
diff -u --recursive --new-file v2.1.126/linux/include/linux/serial.h linux/include/linux/serial.h
--- v2.1.126/linux/include/linux/serial.h	Thu Apr 23 20:21:38 1998
+++ linux/include/linux/serial.h	Tue Nov  3 22:05:25 1998
@@ -42,11 +42,11 @@
 #define PORT_16450	2
 #define PORT_16550	3
 #define PORT_16550A	4
-#define PORT_CIRRUS     5
+#define PORT_CIRRUS     5	/* usurped by cyclades.c */
 #define PORT_16650	6
 #define PORT_16650V2	7
 #define PORT_16750	8
-#define PORT_STARTECH	9
+#define PORT_STARTECH	9	/* usurped by cyclades.c */
 #define PORT_MAX	9
 
 struct serial_uart_config {
@@ -87,7 +87,7 @@
 
 #define ASYNC_LOW_LATENCY 0x2000 /* Request low latency behaviour */
 
-#define ASYNC_FLAGS	0x2FFF	/* Possible legal async flags */
+#define ASYNC_FLAGS	0x3FFF	/* Possible legal async flags */
 #define ASYNC_USR_MASK	0x3430	/* Legal flags that non-privileged
 				 * users can set or reset */
 
diff -u --recursive --new-file v2.1.126/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.126/linux/include/linux/socket.h	Mon Sep 28 10:51:35 1998
+++ linux/include/linux/socket.h	Sat Nov  7 11:00:31 1998
@@ -250,6 +250,7 @@
 /* TCP options - this way around because someone left a set in the c library includes */
 #define TCP_NODELAY	1
 #define TCP_MAXSEG	2
+#define TCP_CORK	3	/* Linux specific (for use with sendfile) */
 
 #ifdef __KERNEL__
 extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
diff -u --recursive --new-file v2.1.126/linux/include/linux/soundcard.h linux/include/linux/soundcard.h
--- v2.1.126/linux/include/linux/soundcard.h	Sun Jul 26 11:57:19 1998
+++ linux/include/linux/soundcard.h	Sat Oct 24 11:40:16 1998
@@ -771,6 +771,8 @@
 #define SOUND_MIXER_CAPS	0xfc
 #	define SOUND_CAP_EXCL_INPUT	0x00000001	/* Only one recording source at a time */
 #define SOUND_MIXER_STEREODEVS	0xfb	/* Mixer channels supporting stereo */
+#define SOUND_MIXER_OUTSRC	0xfa	/* Arg contains a bit for each input source to output */
+#define SOUND_MIXER_OUTMASK	0xf9	/* Arg contains a bit for each supported input source to output */
 
 /*	Device mask bits	*/
 
diff -u --recursive --new-file v2.1.126/linux/include/linux/sunrpc/svcsock.h linux/include/linux/sunrpc/svcsock.h
--- v2.1.126/linux/include/linux/sunrpc/svcsock.h	Fri Jul 31 17:10:04 1998
+++ linux/include/linux/sunrpc/svcsock.h	Wed Nov  4 10:21:46 1998
@@ -51,7 +51,7 @@
  */
 int		svc_makesock(struct svc_serv *, int, unsigned short);
 void		svc_delete_socket(struct svc_sock *);
-int		svc_recv(struct svc_serv *, struct svc_rqst *);
+int		svc_recv(struct svc_serv *, struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
 void		svc_drop(struct svc_rqst *);
 
diff -u --recursive --new-file v2.1.126/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.126/linux/include/linux/sysctl.h	Mon Oct  5 13:13:47 1998
+++ linux/include/linux/sysctl.h	Tue Oct 27 09:57:19 1998
@@ -163,8 +163,7 @@
 	NET_IPV4_ROUTE = 18,
 	NET_IPV4_FIB_HASH = 19,
 
-/*32*/	NET_IPV4_TCP_HOE_RETRANSMITS=32,
-	NET_IPV4_TCP_TIMESTAMPS,
+/*33*/	NET_IPV4_TCP_TIMESTAMPS=33,
 	NET_IPV4_TCP_WINDOW_SCALING,
 	NET_IPV4_TCP_SACK,
 	NET_IPV4_TCP_RETRANS_COLLAPSE,
diff -u --recursive --new-file v2.1.126/linux/include/linux/timer.h linux/include/linux/timer.h
--- v2.1.126/linux/include/linux/timer.h	Tue Jun 23 10:01:29 1998
+++ linux/include/linux/timer.h	Mon Nov  2 09:34:36 1998
@@ -71,22 +71,26 @@
 	timer->prev = NULL;
 }
 
+extern inline int timer_pending(struct timer_list * timer)
+{
+	return timer->prev != NULL;
+}
+
 /*
  *	These inlines deal with timer wrapping correctly. You are 
  *	strongly encouraged to use them
  *	1. Because people otherwise forget
  *	2. Because if the timer wrap changes in future you wont have to
  *	   alter your driver code.
+ *
+ * Do this with "<0" and ">=0" to only test the sign of the result. A
+ * good compiler would generate better code (and a really good compiler
+ * wouldn't care). Gcc is currently neither.
  */
+#define time_after(a,b)		((long)(b) - (long)(a) < 0)
+#define time_before(a,b)	time_after(b,a)
 
-extern inline int time_before(unsigned long a, unsigned long b)
-{
-	return((long)((a) - (b)) < 0L);
-}
-
-extern inline int time_after(unsigned long a, unsigned long b)
-{
-	return((long)((a) - (b)) > 0L);
-}
+#define time_after_eq(a,b)	((long)(a) - (long)(b) >= 0)
+#define time_before_eq(a,b)	time_after_eq(b,a)
 
 #endif
diff -u --recursive --new-file v2.1.126/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.1.126/linux/include/linux/tty.h	Mon Sep 28 10:51:36 1998
+++ linux/include/linux/tty.h	Sat Nov  7 11:31:10 1998
@@ -355,7 +355,7 @@
 extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
 			      const char *routine);
 extern char *tty_name(struct tty_struct *tty, char *buf);
-extern void tty_wait_until_sent(struct tty_struct * tty, int timeout);
+extern void tty_wait_until_sent(struct tty_struct * tty, long timeout);
 extern int tty_check_change(struct tty_struct * tty);
 extern void stop_tty(struct tty_struct * tty);
 extern void start_tty(struct tty_struct * tty);
diff -u --recursive --new-file v2.1.126/linux/include/net/scm.h linux/include/net/scm.h
--- v2.1.126/linux/include/net/scm.h	Tue Mar 10 10:03:35 1998
+++ linux/include/net/scm.h	Tue Oct 27 09:57:19 1998
@@ -17,8 +17,6 @@
 	struct ucred		creds;		/* Skb credentials	*/
 	struct scm_fp_list	*fp;		/* Passed files		*/
 	unsigned long		seq;		/* Connection seqno	*/
-	struct file 		*file;		/* file for socket	*/
-	struct socket 		*sock;		/* Passed socket	*/
 };
 
 extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
@@ -39,7 +37,6 @@
 	scm->creds.uid = current->uid;
 	scm->creds.gid = current->gid;
 	scm->creds.pid = current->pid;
-	scm->sock      = sock;
 	if (msg->msg_controllen <= 0)
 		return 0;
 	return __scm_send(sock, msg, scm);
diff -u --recursive --new-file v2.1.126/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.126/linux/include/net/sock.h	Mon Oct  5 13:13:47 1998
+++ linux/include/net/sock.h	Sat Nov  7 11:31:12 1998
@@ -535,7 +535,7 @@
 	struct sock		*sklist_prev;
 
 	void			(*close)(struct sock *sk, 
-					unsigned long timeout);
+					long timeout);
 	int			(*connect)(struct sock *sk,
 				        struct sockaddr *uaddr, 
 					int addr_len);
diff -u --recursive --new-file v2.1.126/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.1.126/linux/include/net/tcp.h	Thu Sep 17 17:53:39 1998
+++ linux/include/net/tcp.h	Sat Nov  7 11:31:13 1998
@@ -511,7 +511,7 @@
 							   unsigned len);
 
 extern void			tcp_close(struct sock *sk, 
-					  unsigned long timeout);
+					  long timeout);
 extern struct sock *		tcp_accept(struct sock *sk, int flags);
 extern unsigned int		tcp_poll(struct file * file, struct socket *sock, struct poll_table_struct *wait);
 extern void			tcp_write_space(struct sock *sk); 
@@ -675,7 +675,7 @@
  * scaling applied to the result.  The caller does these things
  * if necessary.  This is a "raw" window selection.
  */
-extern u32	__tcp_select_window(struct sock *sk, u32 cur_win);
+extern u32	__tcp_select_window(struct sock *sk);
 
 /* Chose a new window to advertise, update state in tcp_opt for the
  * socket, and return result with RFC1323 scaling applied.  The return
@@ -686,13 +686,20 @@
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	u32 cur_win = tcp_receive_window(tp);
-	u32 new_win = __tcp_select_window(sk, cur_win);
+	u32 new_win = __tcp_select_window(sk);
 
 	/* Never shrink the offered window */
-	if(new_win < cur_win)
+	if(new_win < cur_win) {
+		/* Danger Will Robinson!
+		 * Don't update rcv_wup/rcv_wnd here or else
+		 * we will not be able to advertise a zero
+		 * window in time.  --DaveM
+		 */
 		new_win = cur_win;
-	tp->rcv_wnd = new_win;
-	tp->rcv_wup = tp->rcv_nxt;
+	} else {
+		tp->rcv_wnd = new_win;
+		tp->rcv_wup = tp->rcv_nxt;
+	}
 
 	/* RFC1323 scaling applied */
 	return new_win >> tp->rcv_wscale;
@@ -706,7 +713,7 @@
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	u32 cur_win = tcp_receive_window(tp);
-	u32 new_win = __tcp_select_window(sk, cur_win);
+	u32 new_win = __tcp_select_window(sk);
 
 	return (new_win && (new_win > (cur_win << 1)));
 }
@@ -790,8 +797,11 @@
 	 *
 	 * 	Don't use the nagle rule for urgent data.
 	 */
-	if (!sk->nonagle && skb->len < (tp->mss_cache >> 1) && tp->packets_out &&
-	    !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG))
+	if ((sk->nonagle == 2 && (skb->len < tp->mss_cache)) ||
+	    (!sk->nonagle &&
+	     skb->len < (tp->mss_cache >> 1) &&
+	     tp->packets_out &&
+	     !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG)))
 		nagle_check = 0;
 
 	return (nagle_check &&
diff -u --recursive --new-file v2.1.126/linux/init/main.c linux/init/main.c
--- v2.1.126/linux/init/main.c	Fri Oct 23 22:01:27 1998
+++ linux/init/main.c	Thu Nov  5 15:29:43 1998
@@ -194,6 +194,7 @@
 extern void in2000_setup(char *str, int *ints);
 extern void NCR53c406a_setup(char *str, int *ints);
 extern void wd7000_setup(char *str, int *ints);
+extern void dc390_setup(char* str, int *ints);
 extern void scsi_luns_setup(char *str, int *ints);
 extern void scsi_logging_setup(char *str, int *ints);
 extern void sound_setup(char *str, int *ints);
@@ -704,6 +705,9 @@
 #ifdef CONFIG_SCSI_IBMMCA
         { "ibmmcascsi=", ibmmca_scsi_setup },
 #endif
+#if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP)
+        { "tmscsim=", dc390_setup },
+#endif
 #ifdef CONFIG_BLK_DEV_XD
 	{ "xd=", xd_setup },
 	{ "xd_geo=", xd_manual_geo_init },
@@ -1304,8 +1308,8 @@
 		*/
 		extern struct inode *pseudo_root;
 		if (pseudo_root != NULL){
-			current->fs->root = pseudo_root;
-			current->fs->pwd  = pseudo_root;
+			current->fs->root = pseudo_root->i_sb->s_root;
+			current->fs->pwd  = pseudo_root->i_sb->s_root;
 		}
 	}
 #endif
diff -u --recursive --new-file v2.1.126/linux/kernel/acct.c linux/kernel/acct.c
--- v2.1.126/linux/kernel/acct.c	Fri Oct 23 22:01:27 1998
+++ linux/kernel/acct.c	Sat Oct 24 08:54:33 1998
@@ -87,7 +87,7 @@
 	if (!acct_file || !acct_needcheck)
 		return;
 
-	sb = acct_file->f_dentry->f_inode->i_sb;
+	sb = acct_file->f_dentry->d_inode->i_sb;
 	if (!sb->s_op || !sb->s_op->statfs)
 		return;
 
diff -u --recursive --new-file v2.1.126/linux/kernel/itimer.c linux/kernel/itimer.c
--- v2.1.126/linux/kernel/itimer.c	Mon Dec  8 23:58:05 1997
+++ linux/kernel/itimer.c	Sat Oct 31 10:17:21 1998
@@ -102,11 +102,9 @@
 	send_sig(SIGALRM, p, 1);
 	interval = p->it_real_incr;
 	if (interval) {
-		unsigned long timeout = jiffies + interval;
-		/* check for overflow */
-		if (timeout < interval)
-			timeout = ULONG_MAX;
-		p->real_timer.expires = timeout;
+		if (interval > (unsigned long) LONG_MAX)
+			interval = LONG_MAX;
+		p->real_timer.expires = jiffies + interval;
 		add_timer(&p->real_timer);
 	}
 }
@@ -127,10 +125,9 @@
 			current->it_real_incr = i;
 			if (!j)
 				break;
+			if (j > (unsigned long) LONG_MAX)
+				j = LONG_MAX;
 			i = j + jiffies;
-			/* check for overflow.. */
-			if (i < j)
-				i = ULONG_MAX;
 			current->real_timer.expires = i;
 			add_timer(&current->real_timer);
 			break;
diff -u --recursive --new-file v2.1.126/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.126/linux/kernel/ksyms.c	Fri Oct 23 22:01:27 1998
+++ linux/kernel/ksyms.c	Sat Oct 31 10:17:21 1998
@@ -317,7 +317,9 @@
 EXPORT_SYMBOL(__wake_up);
 EXPORT_SYMBOL(sleep_on);
 EXPORT_SYMBOL(interruptible_sleep_on);
+EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 EXPORT_SYMBOL(schedule);
+EXPORT_SYMBOL(schedule_timeout);
 EXPORT_SYMBOL(jiffies);
 EXPORT_SYMBOL(xtime);
 EXPORT_SYMBOL(do_gettimeofday);
diff -u --recursive --new-file v2.1.126/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.126/linux/kernel/sched.c	Sat Sep  5 16:46:42 1998
+++ linux/kernel/sched.c	Fri Nov  6 17:15:02 1998
@@ -230,7 +230,7 @@
  * "current->state = TASK_RUNNING" to mark yourself runnable
  * without the overhead of this.
  */
-inline void wake_up_process(struct task_struct * p)
+void wake_up_process(struct task_struct * p)
 {
 	unsigned long flags;
 
@@ -248,7 +248,6 @@
 {
 	struct task_struct * p = (struct task_struct *) __data;
 
-	p->timeout = 0;
 	wake_up_process(p);
 }
 
@@ -372,12 +371,12 @@
 	} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
 		int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
 		insert_timer(timer, tv4.vec, i);
-	} else if (expires < timer_jiffies) {
+	} else if ((signed long) idx < 0) {
 		/* can happen if you add a timer with expires == jiffies,
 		 * or you set a timer to go off in the past
 		 */
 		insert_timer(timer, tv1.vec, tv1.index);
-	} else if (idx < 0xffffffffUL) {
+	} else if (idx <= 0xffffffffUL) {
 		int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
 		insert_timer(timer, tv5.vec, i);
 	} else {
@@ -445,6 +444,74 @@
 
 #endif
 
+signed long schedule_timeout(signed long timeout)
+{
+	struct timer_list timer;
+	unsigned long expire;
+
+	/*
+	 * PARANOID.
+	 */
+	if (current->state == TASK_UNINTERRUPTIBLE)
+	{
+		printk(KERN_WARNING "schedule_timeout: task not interrutible "
+		       "from %p\n", __builtin_return_address(0));
+		/*
+		 * We don' t want to interrupt a not interruptible task
+		 * risking to cause corruption. Better a a deadlock ;-).
+		 */
+		timeout = MAX_SCHEDULE_TIMEOUT;
+	}
+
+	/*
+	 * Here we start for real.
+	 */
+	switch (timeout)
+	{
+	case MAX_SCHEDULE_TIMEOUT:
+		/*
+		 * These two special cases are useful to be comfortable
+		 * in the caller. Nothing more. We could take
+		 * MAX_SCHEDULE_TIMEOUT from one of the negative value
+		 * but I' d like to return a valid offset (>=0) to allow
+		 * the caller to do everything it want with the retval.
+		 */
+		schedule();
+		goto out;
+	default:
+		/*
+		 * Another bit of PARANOID. Note that the retval will be
+		 * 0 since no piece of kernel is supposed to do a check
+		 * for a negative retval of schedule_timeout() (since it
+		 * should never happens anyway). You just have the printk()
+		 * that will tell you if something is gone wrong and where.
+		 */
+		if (timeout < 0)
+		{
+			printk(KERN_ERR "schedule_timeout: wrong timeout "
+			       "value %lx from %p\n", timeout,
+			       __builtin_return_address(0));
+			goto out;
+		}
+	}
+
+	expire = timeout + jiffies;
+
+	init_timer(&timer);
+	timer.expires = expire;
+	timer.data = (unsigned long) current;
+	timer.function = process_timeout;
+
+	add_timer(&timer);
+	schedule();
+	del_timer(&timer);
+
+	timeout = expire - jiffies;
+
+ out:
+	return timeout < 0 ? 0 : timeout;
+}
+
 /*
  *  'schedule()' is the scheduler function. It's a very simple and nice
  * scheduler: it's not perfect, but certainly works for most things.
@@ -458,7 +525,6 @@
 asmlinkage void schedule(void)
 {
 	struct task_struct * prev, * next;
-	unsigned long timeout;
 	int this_cpu;
 
 	prev = current;
@@ -481,16 +547,10 @@
 		prev->counter = prev->priority;
 		move_last_runqueue(prev);
 	}
-	timeout = 0;
+
 	switch (prev->state) {
 		case TASK_INTERRUPTIBLE:
-			if (signal_pending(prev))
-				goto makerunnable;
-			timeout = prev->timeout;
-			if (timeout && (timeout <= jiffies)) {
-				prev->timeout = 0;
-				timeout = 0;
-		makerunnable:
+			if (signal_pending(prev)) {
 				prev->state = TASK_RUNNING;
 				break;
 			}
@@ -550,21 +610,9 @@
 #endif
 
 	if (prev != next) {
-		struct timer_list timer;
-
 		kstat.context_swtch++;
-		if (timeout) {
-			init_timer(&timer);
-			timer.expires = timeout;
-			timer.data = (unsigned long) prev;
-			timer.function = process_timeout;
-			add_timer(&timer);
-		}
 		get_mmu_context(next);
 		switch_to(prev,next);
-
-		if (timeout)
-			del_timer(&timer);
 	}
 
 	spin_unlock(&scheduler_lock);
@@ -702,7 +750,6 @@
 		schedule();
 		tsk->state = task_state;
 	}
-
 	tsk->state = TASK_RUNNING;
 	remove_wait_queue(&sem->wait, &wait);
 	return ret;
@@ -718,32 +765,54 @@
 	return __do_down(sem,TASK_INTERRUPTIBLE);
 }
 
-
-static void FASTCALL(__sleep_on(struct wait_queue **p, int state));
-static void __sleep_on(struct wait_queue **p, int state)
-{
-	unsigned long flags;
+#define	SLEEP_ON_VAR				\
+	unsigned long flags;			\
 	struct wait_queue wait;
 
-	current->state = state;
-	wait.task = current;
-	write_lock_irqsave(&waitqueue_lock, flags);
-	__add_wait_queue(p, &wait);
+#define	SLEEP_ON_HEAD					\
+	wait.task = current;				\
+	write_lock_irqsave(&waitqueue_lock, flags);	\
+	__add_wait_queue(p, &wait);			\
 	write_unlock(&waitqueue_lock);
-	schedule();
-	write_lock_irq(&waitqueue_lock);
-	__remove_wait_queue(p, &wait);
+
+#define	SLEEP_ON_TAIL						\
+	write_lock_irq(&waitqueue_lock);			\
+	__remove_wait_queue(p, &wait);				\
 	write_unlock_irqrestore(&waitqueue_lock, flags);
-}
 
 void interruptible_sleep_on(struct wait_queue **p)
 {
-	__sleep_on(p,TASK_INTERRUPTIBLE);
+	SLEEP_ON_VAR
+
+	current->state = TASK_INTERRUPTIBLE;
+
+	SLEEP_ON_HEAD
+	schedule();
+	SLEEP_ON_TAIL
+}
+
+long interruptible_sleep_on_timeout(struct wait_queue **p, long timeout)
+{
+	SLEEP_ON_VAR
+
+	current->state = TASK_INTERRUPTIBLE;
+
+	SLEEP_ON_HEAD
+	timeout = schedule_timeout(timeout);
+	SLEEP_ON_TAIL
+
+	return timeout;
 }
 
 void sleep_on(struct wait_queue **p)
 {
-	__sleep_on(p,TASK_UNINTERRUPTIBLE);
+	SLEEP_ON_VAR
+	
+	current->state = TASK_UNINTERRUPTIBLE;
+
+	SLEEP_ON_HEAD
+	schedule();
+	SLEEP_ON_TAIL
 }
 
 void scheduling_functions_end_here(void) { }
@@ -803,7 +872,7 @@
 			break;
 		if (!(mask & timer_active))
 			continue;
-		if (tp->expires > jiffies)
+		if (time_after(tp->expires, jiffies))
 			continue;
 		timer_active &= ~mask;
 		tp->fn();
@@ -1488,7 +1557,8 @@
 {
 	spin_lock(&scheduler_lock);
 	spin_lock_irq(&runqueue_lock);
-	current->policy |= SCHED_YIELD;
+	if (current->policy == SCHED_OTHER)
+		current->policy |= SCHED_YIELD;
 	current->need_resched = 1;
 	move_last_runqueue(current);
 	spin_unlock_irq(&runqueue_lock);
@@ -1563,16 +1633,14 @@
 		return 0;
 	}
 
-	expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec) + jiffies;
+	expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
 
-	current->timeout = expire;
 	current->state = TASK_INTERRUPTIBLE;
-	schedule();
+	expire = schedule_timeout(expire);
 
-	if (expire > jiffies) {
+	if (expire) {
 		if (rmtp) {
-			jiffies_to_timespec(expire - jiffies -
-					    (expire > jiffies + 1), &t);
+			jiffies_to_timespec(expire, &t);
 			if (copy_to_user(rmtp, &t, sizeof(struct timespec)))
 				return -EFAULT;
 		}
diff -u --recursive --new-file v2.1.126/linux/kernel/signal.c linux/kernel/signal.c
--- v2.1.126/linux/kernel/signal.c	Thu Sep 17 17:53:39 1998
+++ linux/kernel/signal.c	Sat Oct 31 10:17:21 1998
@@ -712,6 +712,7 @@
 	sigset_t these;
 	struct timespec ts;
 	siginfo_t info;
+	long timeout = 0;
 
 	/* XXX: Don't preclude handling different sized sigset_t's.  */
 	if (sigsetsize != sizeof(sigset_t))
@@ -738,22 +739,18 @@
 	if (!sig) {
 		/* None ready -- temporarily unblock those we're interested
 		   in so that we'll be awakened when they arrive.  */
-		unsigned long expire;
 		sigset_t oldblocked = current->blocked;
 		sigandsets(&current->blocked, &current->blocked, &these);
 		recalc_sigpending(current);
 		spin_unlock_irq(&current->sigmask_lock);
 
-		expire = ~0UL;
-		if (uts) {
-			expire = (timespec_to_jiffies(&ts)
-				  + (ts.tv_sec || ts.tv_nsec));
-			expire += jiffies;
-		}
-		current->timeout = expire;
+		timeout = MAX_SCHEDULE_TIMEOUT;
+		if (uts)
+			timeout = (timespec_to_jiffies(&ts)
+				   + (ts.tv_sec || ts.tv_nsec));
 
 		current->state = TASK_INTERRUPTIBLE;
-		schedule();
+		timeout = schedule_timeout(timeout);
 
 		spin_lock_irq(&current->sigmask_lock);
 		sig = dequeue_signal(&these, &info);
@@ -770,10 +767,8 @@
 		}
 	} else {
 		ret = -EAGAIN;
-		if (current->timeout != 0) {
-			current->timeout = 0;
+		if (timeout)
 			ret = -EINTR;
-		}
 	}
 
 	return ret;
diff -u --recursive --new-file v2.1.126/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.1.126/linux/kernel/sysctl.c	Mon Oct  5 13:13:47 1998
+++ linux/kernel/sysctl.c	Wed Nov  4 10:00:50 1998
@@ -38,7 +38,7 @@
 
 /* External variables not in a header file. */
 extern int panic_timeout;
-extern int console_loglevel, C_A_D, swapout_interval;
+extern int console_loglevel, C_A_D;
 extern int bdf_prm[], bdflush_min[], bdflush_max[];
 extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
 extern int sysctl_overcommit_memory;
@@ -199,8 +199,6 @@
 static ctl_table vm_table[] = {
 	{VM_SWAPCTL, "swapctl", 
 	 &swap_control, sizeof(swap_control_t), 0644, NULL, &proc_dointvec},
-	{VM_SWAPOUT, "swapout_interval",
-	 &swapout_interval, sizeof(int), 0644, NULL, &proc_dointvec},
 	{VM_FREEPG, "freepages", 
 	 &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec},
 	{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
diff -u --recursive --new-file v2.1.126/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.126/linux/mm/filemap.c	Fri Oct 23 22:01:27 1998
+++ linux/mm/filemap.c	Tue Nov  3 08:39:50 1998
@@ -293,7 +293,7 @@
 	struct page **hash)
 {
 	atomic_inc(&page->count);
-	page->flags &= ~((1 << PG_uptodate) | (1 << PG_error));
+	page->flags = (page->flags & ~((1 << PG_uptodate) | (1 << PG_error))) | (1 << PG_referenced);
 	page->offset = offset;
 	add_page_to_inode_queue(inode, page);
 	__add_page_to_hash_queue(page, hash);
@@ -314,7 +314,7 @@
 	offset &= PAGE_MASK;
 	switch (page_cache) {
 	case 0:
-		page_cache = __get_free_page(GFP_KERNEL);
+		page_cache = __get_free_page(GFP_USER);
 		if (!page_cache)
 			break;
 	default:
@@ -328,7 +328,6 @@
 			 */
 			page = mem_map + MAP_NR(page_cache);
 			add_to_page_cache(page, inode, offset, hash);
-			set_bit(PG_referenced, &page->flags);
 			inode->i_op->readpage(file, page);
 			page_cache = 0;
 		}
@@ -737,7 +736,7 @@
 		 * page..
 		 */
 		if (!page_cache) {
-			page_cache = __get_free_page(GFP_KERNEL);
+			page_cache = __get_free_page(GFP_USER);
 			/*
 			 * That could have slept, so go around to the
 			 * very beginning..
@@ -1003,7 +1002,7 @@
 	 * extra page -- better to overlap the allocation with the I/O.
 	 */
 	if (no_share && !new_page) {
-		new_page = __get_free_page(GFP_KERNEL);
+		new_page = __get_free_page(GFP_USER);
 		if (!new_page)
 			goto failure;
 	}
@@ -1040,7 +1039,7 @@
 	return new_page;
 
 no_cached_page:
-	new_page = __get_free_page(GFP_KERNEL);
+	new_page = __get_free_page(GFP_USER);
 	if (!new_page)
 		goto no_page;
 
@@ -1570,7 +1569,7 @@
 		hash = page_hash(inode, pgpos);
 		if (!(page = __find_page(inode, pgpos, *hash))) {
 			if (!page_cache) {
-				page_cache = __get_free_page(GFP_KERNEL);
+				page_cache = __get_free_page(GFP_USER);
 				if (page_cache)
 					continue;
 				status = -ENOMEM;
diff -u --recursive --new-file v2.1.126/linux/mm/memory.c linux/mm/memory.c
--- v2.1.126/linux/mm/memory.c	Fri Oct 23 22:01:27 1998
+++ linux/mm/memory.c	Fri Nov  6 17:40:21 1998
@@ -629,7 +629,7 @@
  * change only once the write actually happens. This avoids a few races,
  * and potentially makes it more efficient.
  */
-static void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
+static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
 	unsigned long address, pte_t *page_table)
 {
 	pte_t pte;
@@ -637,7 +637,7 @@
 	struct page * page_map;
 	
 	pte = *page_table;
-	new_page = __get_free_page(GFP_KERNEL);
+	new_page = __get_free_page(GFP_USER);
 	/* Did someone else copy this page for us while we slept? */
 	if (pte_val(*page_table) != pte_val(pte))
 		goto end_wp_page;
@@ -655,40 +655,42 @@
 	 * Do we need to copy?
 	 */
 	if (is_page_shared(page_map)) {
-		if (new_page) {
-			if (PageReserved(mem_map + MAP_NR(old_page)))
-				++vma->vm_mm->rss;
-			copy_cow_page(old_page,new_page);
-			flush_page_to_ram(old_page);
-			flush_page_to_ram(new_page);
-			flush_cache_page(vma, address);
-			set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
-			free_page(old_page);
-			flush_tlb_page(vma, address);
-			return;
-		}
+		unlock_kernel();
+		if (!new_page)
+			return 0;
+
+		if (PageReserved(mem_map + MAP_NR(old_page)))
+			++vma->vm_mm->rss;
+		copy_cow_page(old_page,new_page);
+		flush_page_to_ram(old_page);
+		flush_page_to_ram(new_page);
 		flush_cache_page(vma, address);
-		set_pte(page_table, BAD_PAGE);
-		flush_tlb_page(vma, address);
+		set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
 		free_page(old_page);
-		oom(tsk);
-		return;
+		flush_tlb_page(vma, address);
+		return 1;
 	}
+
 	if (PageSwapCache(page_map))
 		delete_from_swap_cache(page_map);
+
+	/* We can release the kernel lock now.. */
+	unlock_kernel();
+
 	flush_cache_page(vma, address);
 	set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
 	flush_tlb_page(vma, address);
+end_wp_page:
 	if (new_page)
 		free_page(new_page);
-	return;
+	return 1;
+
 bad_wp_page:
 	printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
 	send_sig(SIGKILL, tsk, 1);
-end_wp_page:
 	if (new_page)
 		free_page(new_page);
-	return;
+	return 0;
 }
 
 /*
@@ -777,30 +779,53 @@
 }
 
 
-static inline void do_swap_page(struct task_struct * tsk, 
+/*
+ * This is called with the kernel lock held, we need
+ * to return without it.
+ */
+static int do_swap_page(struct task_struct * tsk, 
 	struct vm_area_struct * vma, unsigned long address,
 	pte_t * page_table, pte_t entry, int write_access)
 {
-	pte_t page;
-
 	if (!vma->vm_ops || !vma->vm_ops->swapin) {
 		swap_in(tsk, vma, page_table, pte_val(entry), write_access);
 		flush_page_to_ram(pte_page(*page_table));
-		return;
+	} else {
+		pte_t page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry));
+		if (pte_val(*page_table) != pte_val(entry)) {
+			free_page(pte_page(page));
+		} else {
+			if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1 &&
+			    !(vma->vm_flags & VM_SHARED))
+				page = pte_wrprotect(page);
+			++vma->vm_mm->rss;
+			++tsk->maj_flt;
+			flush_page_to_ram(pte_page(page));
+			set_pte(page_table, page);
+		}
 	}
-	page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry));
-	if (pte_val(*page_table) != pte_val(entry)) {
-		free_page(pte_page(page));
-		return;
+	unlock_kernel();
+	return 1;
+}
+
+/*
+ * This only needs the MM semaphore
+ */
+static int do_anonymous_page(struct task_struct * tsk, struct vm_area_struct * vma, pte_t *page_table, int write_access)
+{
+	pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE, vma->vm_page_prot));
+	if (write_access) {
+		unsigned long page = __get_free_page(GFP_USER);
+		if (!page)
+			return 0;
+		clear_page(page);
+		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+		vma->vm_mm->rss++;
+		tsk->min_flt++;
+		flush_page_to_ram(page);
 	}
-	if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1 &&
-	    !(vma->vm_flags & VM_SHARED))
-		page = pte_wrprotect(page);
-	++vma->vm_mm->rss;
-	++tsk->maj_flt;
-	flush_page_to_ram(pte_page(page));
-	set_pte(page_table, page);
-	return;
+	put_page(page_table, entry);
+	return 1;
 }
 
 /*
@@ -811,26 +836,33 @@
  *
  * As this is called only for pages that do not currently exist, we
  * do not need to flush old virtual caches or the TLB.
+ *
+ * This is called with the MM semaphore and the kernel lock held.
+ * We need to release the kernel lock as soon as possible..
  */
-static void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
-	unsigned long address, int write_access, pte_t *page_table, pte_t entry)
+static int do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
+	unsigned long address, int write_access, pte_t *page_table)
 {
 	unsigned long page;
+	pte_t entry;
+
+	if (!vma->vm_ops || !vma->vm_ops->nopage) {
+		unlock_kernel();
+		return do_anonymous_page(tsk, vma, page_table, write_access);
+	}
 
-	if (!pte_none(entry))
-		goto swap_page;
-	address &= PAGE_MASK;
-	if (!vma->vm_ops || !vma->vm_ops->nopage)
-		goto anonymous_page;
 	/*
 	 * The third argument is "no_share", which tells the low-level code
 	 * to copy, not share the page even if sharing is possible.  It's
-	 * essentially an early COW detection 
+	 * essentially an early COW detection.
 	 */
-	page = vma->vm_ops->nopage(vma, address, 
+	page = vma->vm_ops->nopage(vma, address & PAGE_MASK,
 		(vma->vm_flags & VM_SHARED)?0:write_access);
+
+	unlock_kernel();
 	if (!page)
-		goto sigbus;
+		return 0;
+
 	++tsk->maj_flt;
 	++vma->vm_mm->rss;
 	/*
@@ -852,32 +884,7 @@
 		entry = pte_wrprotect(entry);
 	put_page(page_table, entry);
 	/* no need to invalidate: a not-present page shouldn't be cached */
-	return;
-
-anonymous_page:
-	entry = pte_wrprotect(mk_pte(ZERO_PAGE, vma->vm_page_prot));
-	if (write_access) {
-		unsigned long page = __get_free_page(GFP_KERNEL);
-		if (!page)
-			goto sigbus;
-		clear_page(page);
-		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-		vma->vm_mm->rss++;
-		tsk->min_flt++;
-		flush_page_to_ram(page);
-	}
-	put_page(page_table, entry);
-	return;
-
-sigbus:
-	force_sig(SIGBUS, current);
-	put_page(page_table, BAD_PAGE);
-	/* no need to invalidate, wasn't present */
-	return;
-
-swap_page:
-	do_swap_page(tsk, vma, address, page_table, entry, write_access);
-	return;
+	return 1;
 }
 
 /*
@@ -889,54 +896,57 @@
  * with external mmu caches can use to update those (ie the Sparc or
  * PowerPC hashed page tables that act as extended TLBs).
  */
-static inline void handle_pte_fault(struct task_struct *tsk,
+static inline int handle_pte_fault(struct task_struct *tsk,
 	struct vm_area_struct * vma, unsigned long address,
 	int write_access, pte_t * pte)
 {
-	pte_t entry = *pte;
+	pte_t entry;
+
+	lock_kernel();
+	entry = *pte;
 
 	if (!pte_present(entry)) {
-		do_no_page(tsk, vma, address, write_access, pte, entry);
-		return;
+		if (pte_none(entry))
+			return do_no_page(tsk, vma, address, write_access, pte);
+		return do_swap_page(tsk, vma, address, pte, entry, write_access);
 	}
+
 	entry = pte_mkyoung(entry);
 	set_pte(pte, entry);
 	flush_tlb_page(vma, address);
-	if (!write_access)
-		return;
-	if (pte_write(entry)) {
+	if (write_access) {
+		if (!pte_write(entry))
+			return do_wp_page(tsk, vma, address, pte);
+
 		entry = pte_mkdirty(entry);
 		set_pte(pte, entry);
 		flush_tlb_page(vma, address);
-		return;
 	}
-	do_wp_page(tsk, vma, address, pte);
+	unlock_kernel();
+	return 1;
 }
 
 /*
  * By the time we get here, we already hold the mm semaphore
  */
-void handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
+int handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
 	unsigned long address, int write_access)
 {
 	pgd_t *pgd;
 	pmd_t *pmd;
-	pte_t *pte;
 
 	pgd = pgd_offset(vma->vm_mm, address);
 	pmd = pmd_alloc(pgd, address);
-	if (!pmd)
-		goto no_memory;
-	pte = pte_alloc(pmd, address);
-	if (!pte)
-		goto no_memory;
-	lock_kernel();
-	handle_pte_fault(tsk, vma, address, write_access, pte);
-	unlock_kernel();
-	update_mmu_cache(vma, address, *pte);
-	return;
-no_memory:
-	oom(tsk);
+	if (pmd) {
+		pte_t * pte = pte_alloc(pmd, address);
+		if (pte) {
+			if (handle_pte_fault(tsk, vma, address, write_access, pte)) {
+				update_mmu_cache(vma, address, *pte);
+				return 1;
+			}
+		}
+	}
+	return 0;
 }
 
 /*
diff -u --recursive --new-file v2.1.126/linux/mm/mmap.c linux/mm/mmap.c
--- v2.1.126/linux/mm/mmap.c	Wed Aug 26 11:37:45 1998
+++ linux/mm/mmap.c	Thu Oct 29 22:35:02 1998
@@ -93,7 +93,21 @@
 	struct mm_struct *mm = current->mm;
 
 	down(&mm->mmap_sem);
+
+	/*
+	 * This lock-kernel is one of the main contention points for
+	 * certain normal loads.  And it really should not be here: almost
+	 * everything in brk()/mmap()/munmap() is protected sufficiently by
+	 * the mmap semaphore that we got above.
+	 *
+	 * We should move this into the few things that really want the
+	 * lock, namely anything that actually touches a file descriptor
+	 * etc.  We can do all the normal anonymous mapping cases without
+	 * ever getting the lock at all - the actual memory management
+	 * code is already completely thread-safe.
+	 */
 	lock_kernel();
+
 	if (brk < mm->end_code)
 		goto out;
 	newbrk = PAGE_ALIGN(brk);
diff -u --recursive --new-file v2.1.126/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.1.126/linux/mm/page_alloc.c	Fri Oct 23 22:01:27 1998
+++ linux/mm/page_alloc.c	Thu Oct 29 12:53:39 1998
@@ -268,14 +268,15 @@
 	spin_unlock_irqrestore(&page_alloc_lock, flags);
 
 	/*
-	 * If we failed to find anything, we'll return NULL, but we'll
-	 * wake up kswapd _now_ ad even wait for it synchronously if
-	 * we can.. This way we'll at least make some forward progress
-	 * over time.
+	 * If we can schedule, do so, and make sure to yield.
+	 * We may be a real-time process, and if kswapd is
+	 * waiting for us we need to allow it to run a bit.
 	 */
-	wake_up(&kswapd_wait);
-	if (gfp_mask & __GFP_WAIT)
+	if (gfp_mask & __GFP_WAIT) {
+		current->policy |= SCHED_YIELD;
 		schedule();
+	}
+
 nopage:
 	return 0;
 }
diff -u --recursive --new-file v2.1.126/linux/mm/slab.c linux/mm/slab.c
--- v2.1.126/linux/mm/slab.c	Fri Oct 23 22:01:27 1998
+++ linux/mm/slab.c	Wed Nov  4 14:17:45 1998
@@ -650,9 +650,9 @@
 	}
 
 	slabp->s_magic = SLAB_MAGIC_DESTROYED;
-	kmem_freepages(cachep, slabp->s_mem-slabp->s_offset);
 	if (slabp->s_index)
 		kmem_cache_free(cachep->c_index_cachep, slabp->s_index);
+	kmem_freepages(cachep, slabp->s_mem-slabp->s_offset);
 	if (SLAB_OFF_SLAB(cachep->c_flags))
 		kmem_cache_free(cache_slabp, slabp);
 }
@@ -1190,7 +1190,6 @@
 	cachep->c_dflags = SLAB_CFLGS_GROWN;
 
 	cachep->c_growing++;
-re_try:
 	spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
 
 	/* A series of memory allocations for a new slab.
@@ -1257,15 +1256,6 @@
 	kmem_freepages(cachep, objp); 
 failed:
 	spin_lock_irq(&cachep->c_spinlock);
-	if (local_flags != SLAB_ATOMIC && cachep->c_gfporder) {
-		/* For large order (>0) slabs, we try again.
-		 * Needed because the gfp() functions are not good at giving
-		 * out contiguous pages unless pushed (but do not push too hard).
-		 */
-		if (cachep->c_failures++ < 4 && cachep->c_freep == kmem_slab_end(cachep))
-			goto re_try;
-		cachep->c_failures = 1;	/* Memory is low, don't try as hard next time. */
-	}
 	cachep->c_growing--;
 	spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
 	return 0;
diff -u --recursive --new-file v2.1.126/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.126/linux/mm/swapfile.c	Wed Sep  9 14:51:13 1998
+++ linux/mm/swapfile.c	Thu Oct 29 09:38:24 1998
@@ -559,8 +559,17 @@
 			if (p->swap_device == swap_info[i].swap_device)
 				goto bad_swap;
 		}
-	} else if (!S_ISREG(swap_dentry->d_inode->i_mode))
+	} else if (S_ISREG(swap_dentry->d_inode->i_mode)) {
+		error = -EBUSY;
+		for (i = 0 ; i < nr_swapfiles ; i++) {
+			if (i == type)
+				continue;
+			if (p->swap_file == swap_info[i].swap_file)
+				goto bad_swap;
+		}
+	} else
 		goto bad_swap;
+
 	swap_header = (void *) __get_free_page(GFP_USER);
 	if (!swap_header) {
 		printk("Unable to start swapping: out of memory :-)\n");
diff -u --recursive --new-file v2.1.126/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.126/linux/mm/vmscan.c	Fri Oct 23 22:01:27 1998
+++ linux/mm/vmscan.c	Fri Nov  6 17:16:48 1998
@@ -29,20 +29,9 @@
 #include <asm/pgtable.h>
 
 /* 
- * When are we next due for a page scan? 
- */
-static unsigned long next_swap_jiffies = 0;
-
-/* 
- * How often do we do a pageout scan during normal conditions?
- * Default is four times a second.
- */
-int swapout_interval = HZ / 4;
-
-/* 
  * The wait queue for waking up the pageout daemon:
  */
-struct wait_queue * kswapd_wait = NULL;
+static struct task_struct * kswapd_task = NULL;
 
 static void init_swap_timer(void);
 
@@ -123,8 +112,13 @@
 	}
 	
 	if (pte_young(pte)) {
+		/*
+		 * Transfer the "accessed" bit from the page
+		 * tables to the global page map.
+		 */
 		set_pte(page_table, pte_mkold(pte));
-		touch_page(page_map);
+		set_bit(PG_referenced, &page_map->flags);
+
 		/* 
 		 * We should test here to see if we want to recover any
 		 * swap cache page here.  We do this if the page seeing
@@ -137,10 +131,6 @@
 		return 0;
 	}
 
-	age_page(page_map);
-	if (page_map->age)
-		return 0;
-
 	if (pte_dirty(pte)) {
 		if (vma->vm_ops && vma->vm_ops->swapout) {
 			pid_t pid = tsk->pid;
@@ -310,8 +300,9 @@
 }
 
 static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma,
-	pgd_t *pgdir, unsigned long start, int gfp_mask)
+	unsigned long address, int gfp_mask)
 {
+	pgd_t *pgdir;
 	unsigned long end;
 
 	/* Don't swap out areas like shared memory which have their
@@ -319,12 +310,14 @@
 	if (vma->vm_flags & (VM_SHM | VM_LOCKED))
 		return 0;
 
+	pgdir = pgd_offset(tsk->mm, address);
+
 	end = vma->vm_end;
-	while (start < end) {
-		int result = swap_out_pgd(tsk, vma, pgdir, start, end, gfp_mask);
+	while (address < end) {
+		int result = swap_out_pgd(tsk, vma, pgdir, address, end, gfp_mask);
 		if (result)
 			return result;
-		start = (start + PGDIR_SIZE) & PGDIR_MASK;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		pgdir++;
 	}
 	return 0;
@@ -344,22 +337,23 @@
 	 * Find the proper vm-area
 	 */
 	vma = find_vma(p->mm, address);
-	if (!vma) {
-		p->swap_address = 0;
-		return 0;
+	if (vma) {
+		if (address < vma->vm_start)
+			address = vma->vm_start;
+
+		for (;;) {
+			int result = swap_out_vma(p, vma, address, gfp_mask);
+			if (result)
+				return result;
+			vma = vma->vm_next;
+			if (!vma)
+				break;
+			address = vma->vm_start;
+		}
 	}
-	if (address < vma->vm_start)
-		address = vma->vm_start;
 
-	for (;;) {
-		int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, gfp_mask);
-		if (result)
-			return result;
-		vma = vma->vm_next;
-		if (!vma)
-			break;
-		address = vma->vm_start;
-	}
+	/* We didn't find anything for the process */
+	p->swap_cnt = 0;
 	p->swap_address = 0;
 	return 0;
 }
@@ -420,20 +414,12 @@
 		}
 		pbest->swap_cnt--;
 
-		switch (swap_out_process(pbest, gfp_mask)) {
-		case 0:
-			/*
-			 * Clear swap_cnt so we don't look at this task
-			 * again until we've tried all of the others.
-			 * (We didn't block, so the task is still here.)
-			 */
-			pbest->swap_cnt = 0;
-			break;
-		case 1:
-			return 1;
-		default:
-			break;
-		};
+		/*
+		 * Nonzero means we cleared out something, but only "1" means
+		 * that we actually free'd up a page as a result.
+		 */
+		if (swap_out_process(pbest, gfp_mask) == 1)
+				return 1;
 	}
 out:
 	return 0;
@@ -448,16 +434,10 @@
 {
 	static int state = 0;
 	int i=6;
-	int stop;
 
 	/* Always trim SLAB caches when memory gets low. */
 	kmem_cache_reap(gfp_mask);
 
-	/* We try harder if we are waiting .. */
-	stop = 3;
-	if (gfp_mask & __GFP_WAIT)
-		stop = 0;
-
 	if (buffer_over_borrow() || pgcache_over_borrow())
 		shrink_mmap(i, gfp_mask);
 
@@ -479,7 +459,7 @@
 			shrink_dcache_memory(i, gfp_mask);
 			state = 0;
 		i--;
-		} while ((i - stop) >= 0);
+		} while (i >= 0);
 	}
 	return 0;
 }
@@ -509,8 +489,6 @@
  */
 int kswapd(void *unused)
 {
-	struct wait_queue wait = { current, NULL };
-
 	current->session = 1;
 	current->pgrp = 1;
 	strcpy(current->comm, "kswapd");
@@ -523,11 +501,12 @@
 	 */
 	lock_kernel();
 
-	/* Give kswapd a realtime priority. */
-	current->policy = SCHED_FIFO;
-	current->rt_priority = 32;  /* Fixme --- we need to standardise our
-				    namings for POSIX.4 realtime scheduling
-				    priorities.  */
+	/*
+	 * Set the base priority to something smaller than a
+	 * regular process. We will scale up the priority
+	 * dynamically depending on how much memory we need.
+	 */
+	current->priority = (DEF_PRIORITY * 2) / 3;
 
 	/*
 	 * Tell the memory management that we're a "memory allocator",
@@ -544,9 +523,9 @@
 	current->flags |= PF_MEMALLOC;
 
 	init_swap_timer();
-	add_wait_queue(&kswapd_wait, &wait);
+	kswapd_task = current;
 	while (1) {
-		int tries;
+		unsigned long end_time;
 
 		current->state = TASK_INTERRUPTIBLE;
 		flush_signals(current);
@@ -554,39 +533,15 @@
 		schedule();
 		swapstats.wakeups++;
 
-		/*
-		 * Do the background pageout: be
-		 * more aggressive if we're really
-		 * low on free memory.
-		 *
-		 * We try page_daemon.tries_base times, divided by
-		 * an 'urgency factor'. In practice this will mean
-		 * a value of pager_daemon.tries_base / 8 or 4 = 64
-		 * or 128 pages at a time.
-		 * This gives us 64 (or 128) * 4k * 4 (times/sec) =
-		 * 1 (or 2) MB/s swapping bandwidth in low-priority
-		 * background paging. This number rises to 8 MB/s
-		 * when the priority is highest (but then we'll be
-		 * woken up more often and the rate will be even
-		 * higher).
-		 */
-		tries = pager_daemon.tries_base;
-		tries >>= 4*free_memory_available();
-
+		/* max one hundreth of a second */
+		end_time = jiffies + (HZ-1)/100;
 		do {
-			do_try_to_free_page(0);
-			/*
-			 * Syncing large chunks is faster than swapping
-			 * synchronously (less head movement). -- Rik.
-			 */
-			if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster)
-				run_task_queue(&tq_disk);
-			if (free_memory_available() > 1)
+			if (!do_try_to_free_page(0))
 				break;
-		} while (--tries > 0);
+		} while (time_before_eq(jiffies,end_time));
 	}
 	/* As if we could ever get here - maybe we want to make this killable */
-	remove_wait_queue(&kswapd_wait, &wait);
+	kswapd_task = NULL;
 	unlock_kernel();
 	return 0;
 }
@@ -620,41 +575,63 @@
 	return retval;
 }
 
+/*
+ * Wake up kswapd according to the priority
+ *	0 - no wakeup
+ *	1 - wake up as a low-priority process
+ *	2 - wake up as a normal process
+ *	3 - wake up as an almost real-time process
+ *
+ * This plays mind-games with the "goodness()"
+ * function in kernel/sched.c.
+ */
+static inline void kswapd_wakeup(struct task_struct *p, int priority)
+{
+	if (priority) {
+		p->counter = p->priority << priority;
+		wake_up_process(p);
+	}
+}
+
 /* 
  * The swap_tick function gets called on every clock tick.
  */
 void swap_tick(void)
 {
-	unsigned long now, want;
-	int want_wakeup = 0;
-
-	want = next_swap_jiffies;
-	now = jiffies;
+	struct task_struct *p = kswapd_task;
 
 	/*
-	 * Examine the memory queues. Mark memory low
-	 * if there is nothing available in the three
-	 * highest queues.
-	 *
-	 * Schedule for wakeup if there isn't lots
-	 * of free memory.
+	 * Only bother to try to wake kswapd up
+	 * if the task exists and can be woken.
 	 */
-	switch (free_memory_available()) {
-	case 0:
-		want = now;
-		/* Fall through */
-	case 1:
-		want_wakeup = 1;
-	default:
-	}
- 
-	if ((long) (now - want) >= 0) {
-		if (want_wakeup || buffer_over_max() || pgcache_over_max()) {
-			/* Set the next wake-up time */
-			next_swap_jiffies = now + swapout_interval;
-			kswapd_wakeup();
-		}
+	if (p && (p->state & TASK_INTERRUPTIBLE)) {
+		unsigned int pages;
+		int want_wakeup;
+
+		/*
+		 * Schedule for wakeup if there isn't lots
+		 * of free memory or if there is too much
+		 * of it used for buffers or pgcache.
+		 *
+		 * "want_wakeup" is our priority: 0 means
+		 * not to wake anything up, while 3 means
+		 * that we'd better give kswapd a realtime
+		 * priority.
+		 */
+		want_wakeup = 0;
+		if (buffer_over_max() || pgcache_over_max())
+			want_wakeup = 1;
+		pages = nr_free_pages;
+		if (pages < freepages.high)
+			want_wakeup = 1;
+		if (pages < freepages.low)
+			want_wakeup = 2;
+		if (pages < freepages.min)
+			want_wakeup = 3;
+	
+		kswapd_wakeup(p,want_wakeup);
 	}
+
 	timer_active |= (1<<SWAP_TIMER);
 }
 
@@ -664,7 +641,7 @@
 
 void init_swap_timer(void)
 {
-	timer_table[SWAP_TIMER].expires = 0;
+	timer_table[SWAP_TIMER].expires = jiffies;
 	timer_table[SWAP_TIMER].fn = swap_tick;
 	timer_active |= (1<<SWAP_TIMER);
 }
diff -u --recursive --new-file v2.1.126/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.126/linux/net/appletalk/ddp.c	Sat Sep  5 16:46:42 1998
+++ linux/net/appletalk/ddp.c	Wed Nov  4 10:11:52 1998
@@ -383,9 +383,8 @@
 						/*
 						 * Defer 1/10th
 						 */
-						current->timeout = jiffies + (HZ/10);
 						current->state = TASK_INTERRUPTIBLE;
-						schedule();
+						schedule_timeout(HZ/10);
 						if(atif->status & ATIF_PROBE_FAIL)
 							break;
 					}
diff -u --recursive --new-file v2.1.126/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.126/linux/net/core/dev.c	Sat Sep  5 16:46:42 1998
+++ linux/net/core/dev.c	Sat Nov  7 11:00:32 1998
@@ -1375,7 +1375,7 @@
 	 */
 
 	dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_RUNNING|IFF_NOARP|
-			       IFF_NODYNARP|IFF_SLAVE|IFF_MASTER|
+			       IFF_SLAVE|IFF_MASTER|IFF_DYNAMIC|
 			       IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) |
 				       (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI));
 
diff -u --recursive --new-file v2.1.126/linux/net/core/scm.c linux/net/core/scm.c
--- v2.1.126/linux/net/core/scm.c	Sat Sep  5 16:46:42 1998
+++ linux/net/core/scm.c	Tue Oct 27 09:57:19 1998
@@ -103,7 +103,6 @@
 void __scm_destroy(struct scm_cookie *scm)
 {
 	struct scm_fp_list *fpl = scm->fp;
-	struct file *file;
 	int i;
 
 	if (fpl) {
@@ -112,34 +111,18 @@
 			fput(fpl->fp[i]);
 		kfree(fpl);
 	}
-
-	file = scm->file;
-	if (file) {
-		scm->sock = NULL;
-		scm->file = NULL;
-		fput(file);
-	}
-}
-
-
-
-extern __inline__ int not_one_bit(unsigned val)
-{
-	return (val-1) & val;
 }
 
-
 int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
 {
 	struct cmsghdr *cmsg;
-	struct file *file;
-	int acc_fd, err;
-	unsigned int scm_flags=0;
+	int err;
 
 	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
 	{
 		err = -EINVAL;
 
+		/* Verify that cmsg_len is at least sizeof(struct cmsghdr) */
 		if ((unsigned long)(((char*)cmsg - (char*)msg->msg_control)
 				    + cmsg->cmsg_len) > msg->msg_controllen)
 			goto error;
@@ -162,30 +145,6 @@
 			if (err)
 				goto error;
 			break;
-		case SCM_CONNECT:
-			if (scm_flags)
-				goto error;
-			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
-				goto error;
-			memcpy(&acc_fd, CMSG_DATA(cmsg), sizeof(int));
-			p->sock = NULL;
-			if (acc_fd != -1) {
-				err = -EBADF;
-				file = fget(acc_fd);
-				if (!file)
-					goto error;
-				p->file = file;
-				err = -ENOTSOCK;
-				if (!file->f_dentry->d_inode ||
-				    !file->f_dentry->d_inode->i_sock)
-					goto error;
-				p->sock = &file->f_dentry->d_inode->u.socket_i;
-				err = -EINVAL;
-				if (p->sock->state != SS_UNCONNECTED) 
-					goto error;
-			}
-			scm_flags |= MSG_SYN;
-			break;
 		default:
 			goto error;
 		}
@@ -196,16 +155,13 @@
 		kfree(p->fp);
 		p->fp = NULL;
 	}
-	
-	err = -EINVAL;
-	msg->msg_flags |= scm_flags;
-	scm_flags = msg->msg_flags&MSG_CTLFLAGS;
-	if (not_one_bit(scm_flags))
-		goto error;
 
-	if (!(scm_flags && p->fp))
-		return 0;
+	err = -EINVAL; 
+	if (msg->msg_flags & MSG_CTLFLAGS)
+		goto error;
 
+	return 0;
+	
 error:
 	scm_destroy(p);
 	return err;
diff -u --recursive --new-file v2.1.126/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.126/linux/net/core/sock.c	Mon Oct  5 13:13:47 1998
+++ linux/net/core/sock.c	Sat Nov  7 11:00:32 1998
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.73 1998/10/03 16:08:10 freitag Exp $
+ * Version:	$Id: sock.c,v 1.75 1998/11/07 10:54:38 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -294,6 +294,10 @@
 		{
 			char devname[IFNAMSIZ]; 
 
+			/* Sorry... */ 
+			if (!capable(CAP_NET_RAW)) 
+				return -EPERM; 
+
 			/* Bind this socket to a particular device like "eth0",
 			 * as specified in the passed interface name. If the
 			 * name is "" or the option length is zero the socket 
@@ -965,8 +969,7 @@
 
 void sock_def_error_report(struct sock *sk)
 {
-	if (!sk->dead) 
-	{
+	if (!sk->dead) {
 		wake_up_interruptible(sk->sleep);
 		sock_wake_async(sk->socket,0); 
 	}
@@ -974,8 +977,7 @@
 
 void sock_def_readable(struct sock *sk, int len)
 {
-	if(!sk->dead)
-	{
+	if(!sk->dead) {
 		wake_up_interruptible(sk->sleep);
 		sock_wake_async(sk->socket,1);
 	}
@@ -983,11 +985,14 @@
 
 void sock_def_write_space(struct sock *sk)
 {
-	if(!sk->dead)
-	{
+	/* Do not wake up a writer until he can make "significant"
+	 * progress.  --DaveM
+	 */
+	if(!sk->dead &&
+	   ((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf)) {
 		wake_up_interruptible(sk->sleep);
 
-		/* Should agree with poll, otherwise some programs break */ 
+		/* Should agree with poll, otherwise some programs break */
 		if (sock_writeable(sk))
 			sock_wake_async(sk->socket, 2);
 	}
diff -u --recursive --new-file v2.1.126/linux/net/core/sysctl_net_core.c linux/net/core/sysctl_net_core.c
--- v2.1.126/linux/net/core/sysctl_net_core.c	Mon Oct  5 13:13:47 1998
+++ linux/net/core/sysctl_net_core.c	Sat Nov  7 11:00:32 1998
@@ -25,6 +25,7 @@
 extern int sysctl_optmem_max;
 
 ctl_table core_table[] = {
+#ifdef CONFIG_NET
 	{NET_CORE_WMEM_MAX, "wmem_max",
 	 &sysctl_wmem_max, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
@@ -54,6 +55,7 @@
 	{NET_CORE_OPTMEM_MAX, "optmem_max",
 	 &sysctl_optmem_max, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
+#endif /* CONFIG_NET */
 	{ 0 }
 };
 #endif
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.1.126/linux/net/ipv4/af_inet.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/af_inet.c	Tue Nov  3 12:20:11 1998
@@ -464,7 +464,7 @@
 	struct sock *sk = sock->sk;
 
 	if (sk) {
-		unsigned long timeout;
+		long timeout;
 
 		/* Begin closedown and wake up sleepers. */
 		if (sock->state != SS_UNCONNECTED)
@@ -483,11 +483,11 @@
 		 */
 		timeout = 0;
 		if (sk->linger && !(current->flags & PF_EXITING)) {
-			timeout = ~0UL;
+			timeout = MAX_SCHEDULE_TIMEOUT;
 
 			/* XXX This makes no sense whatsoever... -DaveM */
 			if (!sk->lingertime)
-				timeout = jiffies + HZ*sk->lingertime;
+				timeout = HZ*sk->lingertime;
 		}
 		sock->sk = NULL;
 		sk->socket = NULL;
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.126/linux/net/ipv4/arp.c	Fri Oct  9 13:27:17 1998
+++ linux/net/ipv4/arp.c	Sat Nov  7 11:00:32 1998
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:	$Id: arp.c,v 1.70 1998/08/26 12:03:18 davem Exp $
+ * Version:	$Id: arp.c,v 1.74 1998/11/01 22:15:06 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -431,7 +431,7 @@
 	 *	No arp on this interface.
 	 */
 	
-	if (dev->flags&(IFF_NOARP|IFF_NODYNARP))
+	if (dev->flags&IFF_NOARP)
 		return;
 
 	/*
@@ -547,7 +547,7 @@
  */  
 	if (in_dev == NULL ||
 	    arp->ar_hln != dev->addr_len    || 
-	    dev->flags & (IFF_NOARP|IFF_NODYNARP) ||
+	    dev->flags & IFF_NOARP ||
 	    skb->pkt_type == PACKET_OTHERHOST ||
 	    skb->pkt_type == PACKET_LOOPBACK ||
 	    arp->ar_pln != 4)
@@ -1027,7 +1027,7 @@
 				"%-17s0x%-10x0x%-10x%s",
 				in_ntoa(*(u32*)n->key),
 				hatype,
-				ATF_PUBL|ATF_PERM,       
+ 				ATF_PUBL|ATF_PERM,
 				"00:00:00:00:00:00");
 			size += sprintf(buffer+len+size,
 				 "     %-17s %s\n",
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.1.126/linux/net/ipv4/icmp.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/icmp.c	Tue Oct 27 09:57:19 1998
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@cymru.net>
  *
- *	Version: $Id: icmp.c,v 1.46 1998/10/03 09:37:15 davem Exp $
+ *	Version: $Id: icmp.c,v 1.47 1998/10/21 05:32:24 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -359,6 +359,11 @@
  *	This function is generic and could be used for other purposes
  *	too. It uses a Token bucket filter as suggested by Alexey Kuznetsov.
  *
+ *	Note that the same dst_entry fields are modified by functions in 
+ *	route.c too, but these work for packet destinations while xrlim_allow
+ *	works for icmp destinations. This means the rate limiting information
+ *	for one "ip object" is shared.
+ *
  *	RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
  *			  SHOULD allow setting of rate limits 
  *
@@ -374,6 +379,7 @@
 	if (dst->rate_tokens > XRLIM_BURST_FACTOR*timeout)
 		dst->rate_tokens = XRLIM_BURST_FACTOR*timeout;
 	if (dst->rate_tokens >= timeout) {
+		dst->rate_last = now;
 		dst->rate_tokens -= timeout;
 		return 1;
 	}
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- v2.1.126/linux/net/ipv4/ip_masq.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/ip_masq.c	Sat Nov  7 11:00:32 1998
@@ -4,7 +4,7 @@
  *
  * 	Copyright (c) 1994 Pauline Middelink
  *
- *	$Id: ip_masq.c,v 1.26 1998/09/24 03:38:58 davem Exp $
+ *	$Id: ip_masq.c,v 1.27 1998/11/07 14:59:24 davem Exp $
  *
  *
  *	See ip_fw.c for original log
@@ -1011,14 +1011,19 @@
 		switch (skb->ip_summed)
 		{
 			case CHECKSUM_NONE:
+			{
+				int datasz;
 				doff = proto_doff(iph->protocol, h.raw);
-				csum = csum_partial(h.raw + doff, size - doff, 0);
+				datasz = size - doff; 
+				if (datasz < 0) 
+					return -1; 
+				csum = csum_partial(h.raw + doff, datasz, 0);
 				IP_MASQ_DEBUG(3, "O-pkt: %s I-datacsum=%d\n",
 						masq_proto_name(iph->protocol),
 						csum);
 
 				skb->csum = csum_partial(h.raw , doff, csum);
-
+			}
 			case CHECKSUM_HW:
 				if (csum_tcpudp_magic(iph->saddr, iph->daddr, 
 						size, iph->protocol, skb->csum))
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_masq_cuseeme.c linux/net/ipv4/ip_masq_cuseeme.c
--- v2.1.126/linux/net/ipv4/ip_masq_cuseeme.c	Fri Oct  9 13:27:17 1998
+++ linux/net/ipv4/ip_masq_cuseeme.c	Tue Oct 27 09:57:19 1998
@@ -2,7 +2,7 @@
  *		IP_MASQ_FTP CUSeeMe masquerading module
  *
  *
- * Version:	@(#)$Id: ip_masq_cuseeme.c,v 1.3 1998/08/29 23:51:18 davem Exp $
+ * Version:	@(#)$Id: ip_masq_cuseeme.c,v 1.4 1998/10/06 04:48:57 davem Exp $
  *
  * Author:	Richard Lynch
  *		
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c
--- v2.1.126/linux/net/ipv4/ip_masq_raudio.c	Fri Oct  9 13:27:17 1998
+++ linux/net/ipv4/ip_masq_raudio.c	Tue Oct 27 09:57:19 1998
@@ -2,7 +2,7 @@
  *		IP_MASQ_RAUDIO  - Real Audio masquerading module
  *
  *
- * Version:	@(#)$Id: ip_masq_raudio.c,v 1.10 1998/08/29 23:51:17 davem Exp $
+ * Version:	@(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $
  *
  * Author:	Nigel Metheringham
  *		Real Time Streaming code by Progressive Networks
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_masq_vdolive.c linux/net/ipv4/ip_masq_vdolive.c
--- v2.1.126/linux/net/ipv4/ip_masq_vdolive.c	Fri Oct  9 13:27:17 1998
+++ linux/net/ipv4/ip_masq_vdolive.c	Tue Oct 27 09:57:19 1998
@@ -2,7 +2,7 @@
  *		IP_MASQ_VDOLIVE  - VDO Live masquerading module
  *
  *
- * Version:	@(#)$Id: ip_masq_vdolive.c,v 1.3 1998/08/29 23:51:18 davem Exp $
+ * Version:	@(#)$Id: ip_masq_vdolive.c,v 1.4 1998/10/06 04:49:07 davem Exp $
  *
  * Author:	Nigel Metheringham <Nigel.Metheringham@ThePLAnet.net>
  *		PLAnet Online Ltd
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_nat_dumb.c linux/net/ipv4/ip_nat_dumb.c
--- v2.1.126/linux/net/ipv4/ip_nat_dumb.c	Fri Oct  9 13:27:17 1998
+++ linux/net/ipv4/ip_nat_dumb.c	Tue Oct 27 09:57:19 1998
@@ -5,7 +5,7 @@
  *
  *		Dumb Network Address Translation.
  *
- * Version:	$Id: ip_nat_dumb.c,v 1.6 1998/10/03 09:37:25 davem Exp $
+ * Version:	$Id: ip_nat_dumb.c,v 1.7 1998/10/06 04:49:09 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.1.126/linux/net/ipv4/ipconfig.c	Tue Jul 28 14:21:10 1998
+++ linux/net/ipv4/ipconfig.c	Tue Oct 27 09:57:19 1998
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.15 1998/06/19 13:22:33 davem Exp $
+ *  $Id: ipconfig.c,v 1.16 1998/10/21 22:27:26 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -260,12 +260,12 @@
 		root_server_addr = ic_servaddr;
 
 	if (ic_netmask == INADDR_NONE) {
-		if (IN_CLASSA(ic_myaddr))
-			ic_netmask = IN_CLASSA_NET;
-		else if (IN_CLASSB(ic_myaddr))
-			ic_netmask = IN_CLASSB_NET;
-		else if (IN_CLASSC(ic_myaddr))
-			ic_netmask = IN_CLASSC_NET;
+		if (IN_CLASSA(ntohl(ic_myaddr)))
+			ic_netmask = htonl(IN_CLASSA_NET);
+		else if (IN_CLASSB(ntohl(ic_myaddr)))
+			ic_netmask = htonl(IN_CLASSB_NET);
+		else if (IN_CLASSC(ntohl(ic_myaddr)))
+			ic_netmask = htonl(IN_CLASSC_NET);
 		else {
 			printk(KERN_ERR "IP-Config: Unable to guess netmask for address %08x\n", ic_myaddr);
 			return -1;
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v2.1.126/linux/net/ipv4/proc.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/proc.c	Tue Oct 27 09:57:19 1998
@@ -7,7 +7,7 @@
  *		PROC file system.  It is mainly used for debugging and
  *		statistics.
  *
- * Version:	$Id: proc.c,v 1.32 1998/10/03 09:37:42 davem Exp $
+ * Version:	$Id: proc.c,v 1.33 1998/10/21 05:44:35 davem Exp $
  *
  * Authors:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -55,21 +55,22 @@
 				char *tmpbuf, 
 				int i)
 {
-	/* FIXME: I'm not sure if the timer fields are correct. */
 	sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu",
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %u",
 		i,
 		(long unsigned int)req->af.v4_req.loc_addr,
 		ntohs(sk->sport),
 		(long unsigned int)req->af.v4_req.rmt_addr,
-		req->rmt_port,
+		ntohs(req->rmt_port),
 		TCP_SYN_RECV,
-		0,0, /* use sizeof(struct open_request) here? */
-		0, (unsigned long)(req->expires - jiffies), /* ??? */
+		0,0, /* could print option size, but that is af dependent. */
+		1,   /* timers active (only the expire timer) */  
+		(unsigned long)(req->expires - jiffies), 
 		req->retrans,
 		sk->socket ? sk->socket->inode->i_uid : 0,
-		0,      /* ??? */
-		sk->socket ? sk->socket->inode->i_ino:0);
+		0,  /* non standard timer */  
+		0 /* open_requests have no inode */
+		); 
 }
 
 /* Format a single socket into tmpbuf. */
@@ -157,6 +158,9 @@
  * KNOWN BUGS
  *  As in get_unix_netinfo, the buffer might be too small. If this
  *  happens, get__netinfo returns only part of the available infos.
+ *
+ *  Assumes that buffer length is a multiply of 128 - if not it will
+ *  write past the end.   
  */
 static int
 get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length)
@@ -172,17 +176,6 @@
 			       "  sl  local_address rem_address   st tx_queue "
 			       "rx_queue tr tm->when retrnsmt   uid  timeout inode");
 	pos = 128;
-/*
- *	This was very pretty but didn't work when a socket is destroyed
- *	at the wrong moment (eg a syn recv socket getting a reset), or
- *	a memory timer destroy. Instead of playing with timers we just
- *	concede defeat and do a start_bh_atomic().
- * 	Why not just use lock_sock()? As far as I can see all timer routines
- *	check for sock_readers before doing anything. -AK
- *      [Disabled for now again, because it hard-locked my machine, and there
- *	 is an theoretical situation then, where an user could prevent
- *	 sockets from being destroyed by constantly reading /proc/net/tcp.]
- */
 	SOCKHASH_LOCK(); 
 	sp = pro->sklist_next;
 	while(sp != (struct sock *)pro) {
@@ -196,8 +189,8 @@
 					continue;
 				get__openreq(sp, req, tmpbuf, i); 
 				len += sprintf(buffer+len, "%-127s\n", tmpbuf);
-				if(len >= length)
-					break; 
+				if(len >= length) 
+					goto out;
 			}
 		}
 		
@@ -215,6 +208,7 @@
 		sp = next;
 		i++;
 	}
+out: 
 	SOCKHASH_UNLOCK();
 	
 	begin = len - (pos - offset);
@@ -222,6 +216,8 @@
 	len -= begin;
 	if(len>length)
 		len = length;
+	if (len<0)
+		len = 0; 
 	return len;
 } 
 
@@ -265,6 +261,8 @@
 	len -= offset;
 	if (len > length)
 		len = length;
+	if (len < 0)
+		len = 0;
 	return len;
 }
 
@@ -343,6 +341,8 @@
 	len -= offset;
 	if (len > length)
 		len = length;
+	if (len < 0)
+		len = 0; 
 	return len;
 }
 
@@ -379,5 +379,7 @@
 	len -= offset;
 	if (len > length)
 		len = length;
+	if (len < 0)
+		len = 0; 
 	return len;
 }
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.1.126/linux/net/ipv4/raw.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/raw.c	Sat Oct 31 11:32:05 1998
@@ -400,7 +400,7 @@
 	return err<0 ? err : len;
 }
 
-static void raw_close(struct sock *sk, unsigned long timeout)
+static void raw_close(struct sock *sk, long timeout)
 {
 	/* Observation: when raw_close is called, processes have
 	   no access to socket anymore. But net still has.
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.1.126/linux/net/ipv4/sysctl_net_ipv4.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/sysctl_net_ipv4.c	Tue Oct 27 09:57:19 1998
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.35 1998/10/03 09:37:54 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.36 1998/10/21 05:26:59 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -43,7 +43,6 @@
 /* From ip_masq.c */
 extern int sysctl_ip_masq_debug;
 
-extern int sysctl_tcp_hoe_retransmits;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_sack;
@@ -92,9 +91,6 @@
 
 
 ctl_table ipv4_table[] = {
-        {NET_IPV4_TCP_HOE_RETRANSMITS, "tcp_hoe_retransmits",
-         &sysctl_tcp_hoe_retransmits, sizeof(int), 0644, NULL,
-         &proc_dointvec},
         {NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps",
          &sysctl_tcp_timestamps, sizeof(int), 0644, NULL,
          &proc_dointvec},
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.126/linux/net/ipv4/tcp.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/tcp.c	Sat Nov  7 11:00:32 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.127 1998/10/04 07:04:32 davem Exp $
+ * Version:	$Id: tcp.c,v 1.130 1998/11/07 14:36:10 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -860,8 +860,8 @@
 			if(copy > seglen)
 				copy = seglen;
 
+			/* Determine how large of a buffer to allocate.  */
 			tmp = MAX_HEADER + sk->prot->max_header;
-			queue_it = 0;
 			if (copy < min(mss_now, tp->max_window >> 1) &&
 			    !(flags & MSG_OOB)) {
 				tmp += min(mss_now, tp->max_window);
@@ -876,6 +876,7 @@
 				queue_it = 1;
 			} else {
 				tmp += copy;
+				queue_it = 0;
 			}
 			skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
 
@@ -1452,7 +1453,7 @@
 	tcp_synq_init(tp);
 }
 
-void tcp_close(struct sock *sk, unsigned long timeout)
+void tcp_close(struct sock *sk, long timeout)
 {
 	struct sk_buff *skb;
 	int data_was_unread = 0;
@@ -1522,7 +1523,6 @@
 		struct task_struct *tsk = current;
 		struct wait_queue wait = { tsk, NULL };
 
-		tsk->timeout = timeout;
 		add_wait_queue(sk->sleep, &wait);
 		release_sock(sk);
 
@@ -1530,12 +1530,11 @@
 			tsk->state = TASK_INTERRUPTIBLE;
 			if (!closing(sk))
 				break;
-			schedule();
-			if (signal_pending(tsk) || !tsk->timeout)
+			timeout = schedule_timeout(timeout);
+			if (signal_pending(tsk) || !timeout)
 				break;
 		}
 
-		tsk->timeout=0;
 		tsk->state = TASK_RUNNING;
 		remove_wait_queue(sk->sleep, &wait);
 		
@@ -1547,8 +1546,8 @@
          */
 	tcp_check_fin_timer(sk);
 
-	sk->dead = 1;
 	release_sock(sk);
+	sk->dead = 1;
 }
 
 /*
@@ -1619,6 +1618,8 @@
 	req->class->destructor(req);
 	tcp_openreq_free(req);
 	sk->ack_backlog--; 
+	if(sk->keepopen)
+		tcp_inc_slow_timer(TCP_SLT_KEEPALIVE);
 
 	/*
 	 * This does not pass any already set errors on the new socket
@@ -1657,48 +1658,86 @@
 		return -EFAULT;
 
 	switch(optname) {
-		case TCP_MAXSEG:
-/* values greater than interface MTU won't take effect.  however at
- * the point when this call is done we typically don't yet know
- * which interface is going to be used
- */
-	  		if(val<1||val>MAX_WINDOW)
-				return -EINVAL;
-			tp->user_mss=val;
-			return 0;
-		case TCP_NODELAY:
-			sk->nonagle=(val==0)?0:1;
-			return 0;
-		default:
-			return(-ENOPROTOOPT);
+	case TCP_MAXSEG:
+		/* values greater than interface MTU won't take effect.  however at
+		 * the point when this call is done we typically don't yet know
+		 * which interface is going to be used
+		 */
+		if(val < 1 || val > MAX_WINDOW)
+			return -EINVAL;
+		tp->user_mss = val;
+		return 0;
+
+	case TCP_NODELAY:
+		/* You cannot try to use this and TCP_CORK in
+		 * tandem, so let the user know.
+		 */
+		if (sk->nonagle == 2)
+			return -EINVAL;
+		sk->nonagle = (val == 0) ? 0 : 1;
+		return 0;
+
+	case TCP_CORK:
+		/* When set indicates to always queue non-full frames.
+		 * Later the user clears this option and we transmit
+		 * any pending partial frames in the queue.  This is
+		 * meant to be used alongside sendfile() to get properly
+		 * filled frames when the user (for example) must write
+		 * out headers with a write() call first and then use
+		 * sendfile to send out the data parts.
+		 *
+		 * You cannot try to use TCP_NODELAY and this mechanism
+		 * at the same time, so let the user know.
+		 */
+		if (sk->nonagle == 1)
+			return -EINVAL;
+		if (val != 0) {
+			sk->nonagle = 2;
+		} else {
+			sk->nonagle = 0;
+
+			if (tp->send_head) {
+				lock_sock(sk);
+				if (tp->send_head &&
+				    tcp_snd_test (sk, tp->send_head))
+					tcp_write_xmit(sk);
+				release_sock(sk);
+			}
+		}
+		return 0;
+
+	default:
+		return -ENOPROTOOPT;
 	};
 }
 
-int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, 
+int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval,
 		   int *optlen)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	int val;
-	int len;
+	int val, len;
 
 	if(level != SOL_TCP)
 		return tp->af_specific->getsockopt(sk, level, optname,
 						   optval, optlen);
-	
+
 	if(get_user(len,optlen))
 		return -EFAULT;
-		
-	len = min(len,sizeof(int));
+
+	len = min(len, sizeof(int));
 
 	switch(optname) {
-		case TCP_MAXSEG:
-			val=tp->user_mss;
-			break;
-		case TCP_NODELAY:
-			val=sk->nonagle;
-			break;
-		default:
-			return(-ENOPROTOOPT);
+	case TCP_MAXSEG:
+		val = tp->user_mss;
+		break;
+	case TCP_NODELAY:
+		val = (sk->nonagle == 1);
+		break;
+	case TCP_CORK:
+		val = (sk->nonagle == 2);
+		break;
+	default:
+		return -ENOPROTOOPT;
 	};
 
   	if(put_user(len, optlen))
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.126/linux/net/ipv4/tcp_input.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/tcp_input.c	Sat Nov  7 11:00:32 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.130 1998/10/04 07:06:47 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.136 1998/11/07 14:36:18 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -53,6 +53,8 @@
  *		Andi Kleen:		Add tcp_measure_rcv_mss to make 
  *					connections with MSS<min(MTU,ann. MSS)
  *					work without delayed acks. 
+ *		Andi Kleen:		Process packets with PSH set in the
+ *					fast path.
  */
 
 #include <linux/config.h>
@@ -75,7 +77,6 @@
 int sysctl_tcp_timestamps = 1;
 int sysctl_tcp_window_scaling = 1;
 int sysctl_tcp_sack = 1;
-int sysctl_tcp_hoe_retransmits = 1;
 
 int sysctl_tcp_syncookies = SYNC_INIT; 
 int sysctl_tcp_stdurg;
@@ -566,14 +567,6 @@
 
 /* This is Jacobson's slow start and congestion avoidance. 
  * SIGCOMM '88, p. 328.
- *
- * FIXME: What happens when the congestion window gets larger
- * than the maximum receiver window by some large factor
- * Suppose the pipeline never looses packets for a long
- * period of time, then traffic increases causing packet loss.
- * The congestion window should be reduced, but what it should
- * be reduced to is not clear, since 1/2 the old window may
- * still be larger than the maximum sending rate we ever achieved.
  */
 static void tcp_cong_avoid(struct tcp_opt *tp)
 {
@@ -1139,7 +1132,7 @@
 	/* Zap SWALK, by moving every further SACK up by one slot.
 	 * Decrease num_sacks.
 	 */
-	for(this_sack += 1; this_sack < num_sacks; this_sack++, swalk++) {
+	for(this_sack += 1; this_sack < num_sacks-1; this_sack++, swalk++) {
 		struct tcp_sack_block *next = (swalk + 1);
 		swalk->start_seq = next->start_seq;
 		swalk->end_seq = next->end_seq;
@@ -1524,7 +1517,7 @@
 	 *      - delay time <= 0.5 HZ
 	 *      - we don't have a window update to send
 	 *      - must send at least every 2 full sized packets
-	 *	- must send an ACK if we have any SACKs
+	 *	- must send an ACK if we have any out of order data
 	 *
 	 * With an extra heuristic to handle loss of packet
 	 * situations and also helping the sender leave slow
@@ -1537,8 +1530,8 @@
 	    tcp_raise_window(sk) ||
 	    /* We entered "quick ACK" mode or... */
 	    tcp_in_quickack_mode(tp) ||
-	    /* We have pending SACKs */
-	    (tp->sack_ok && tp->num_sacks)) {
+	    /* We have out of order data */
+	    (skb_peek(&tp->out_of_order_queue) != NULL)) {
 		/* Then ack it now */
 		tcp_send_ack(sk);
 	} else {
@@ -1654,8 +1647,11 @@
 			return 0;
 	}
 	
-	/* Now continue with the receive queue if it wasn't enough */
-	while ((skb = skb_peek_tail(&sk->receive_queue))) {
+	/* Now continue with the receive queue if it wasn't enough.
+	 * But only do this if we are really being abused.
+	 */
+	while ((atomic_read(&sk->rmem_alloc) >= (sk->rcvbuf * 2)) &&
+	       (skb = skb_peek_tail(&sk->receive_queue))) {
 		/* Never toss anything when we've seen the FIN.
 		 * It's just too complex to recover from it.
 		 */
@@ -1678,8 +1674,6 @@
 			   TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
 			   tp->copied_seq); 
 		kfree_skb(skb);
-		if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) 
-			break;
 	}
 	return 0;
 }
@@ -1745,14 +1739,15 @@
 		}
 	}
 
-	flg = *(((u32 *)th) + 3);
-		
+	flg = *(((u32 *)th) + 3) & ~htonl(0x8 << 16);
+
 	/*	pred_flags is 0xS?10 << 16 + snd_wnd
 	 *	if header_predition is to be made
 	 *	'S' will always be tp->tcp_header_len >> 2
 	 *	'?' will be 0 else it will be !0
 	 *	(when there are holes in the receive 
 	 *	 space for instance)
+	 *	PSH flag is ignored.
          */
 
 	if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
@@ -1769,7 +1764,7 @@
 				goto discard;
 			}
 		} else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una &&
-			atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) {
+			   atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) {
 			/* Bulk data transfer: receiver */
 			__skb_pull(skb,th->doff*4);
 
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.126/linux/net/ipv4/tcp_ipv4.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/tcp_ipv4.c	Sat Nov  7 11:00:32 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.161 1998/10/03 09:38:05 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.162 1998/11/07 11:50:26 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -1633,6 +1633,9 @@
 	/* Count it even if it's bad */
 	tcp_statistics.TcpInSegs++;
 
+	if (len < sizeof(struct tcphdr))
+		goto bad_packet;
+
 	/* Try to use the device checksum if provided. */
 	switch (skb->ip_summed) {
 	case CHECKSUM_NONE:
@@ -1647,6 +1650,7 @@
 			       ntohs(th->dest),
 			       len, skb->len,
 			       ntohs(skb->nh.iph->tot_len));
+	bad_packet:		
 			tcp_statistics.TcpInErrs++;
 			goto discard_it;
 		}
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.1.126/linux/net/ipv4/tcp_output.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/tcp_output.c	Sat Nov  7 11:00:32 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.95 1998/09/27 12:57:13 freitag Exp $
+ * Version:	$Id: tcp_output.c,v 1.96 1998/11/07 10:54:40 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -390,7 +390,7 @@
  *
  * Note, we don't "adjust" for TIMESTAMP or SACK option bytes.
  */
-u32 __tcp_select_window(struct sock *sk, u32 cur_win)
+u32 __tcp_select_window(struct sock *sk)
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 	unsigned int mss = tp->mss_cache;
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.1.126/linux/net/ipv4/tcp_timer.c	Thu Sep 17 17:53:40 1998
+++ linux/net/ipv4/tcp_timer.c	Sat Nov  7 11:00:32 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.53 1998/09/15 02:11:39 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.55 1998/11/07 11:55:42 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -183,8 +183,8 @@
 		return;
 	
 	if (atomic_read(&sk->sock_readers)) {
-		/* Try again in second. */
-		tcp_reset_xmit_timer(sk, TIME_PROBE0, HZ);
+		/* Try again later. */
+		tcp_reset_xmit_timer(sk, TIME_PROBE0, HZ/5);
 		return;
 	}
 
@@ -229,6 +229,9 @@
 					sk->err = ETIMEDOUT;
 
 				tcp_set_state(sk, TCP_CLOSE);
+				sk->shutdown = SHUTDOWN_MASK;
+				if (!sk->dead)
+					sk->state_change(sk);
 			} else {
 				tp->probes_out++;
 				tp->pending = TIME_KEEPOPEN;
@@ -433,8 +436,8 @@
 	}
 
 	if (atomic_read(&sk->sock_readers)) {
-		/* Try again in a second. */
-		tcp_reset_xmit_timer(sk, TIME_RETRANS, HZ);
+		/* Try again later */  
+		tcp_reset_xmit_timer(sk, TIME_RETRANS, HZ/20);
 		return;
 	}
 	lock_sock(sk);
@@ -463,10 +466,14 @@
 	tp->fackets_out = 0;
 	tp->retrans_out = 0;
 	if (tp->retransmits == 0) {
-		/* remember window where we lost
+		/* Remember window where we lost:
 		 * "one half of the current window but at least 2 segments"
+		 *
+		 * Here "current window" means the effective one, which
+		 * means it must be an accurate representation of our current
+		 * sending rate _and_ the snd_wnd.
 		 */
-		tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
+		tp->snd_ssthresh = max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2);
 		tp->snd_cwnd_cnt = 0;
 		tp->snd_cwnd = 1;
 	}
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/timer.c linux/net/ipv4/timer.c
--- v2.1.126/linux/net/ipv4/timer.c	Thu Sep 17 17:53:40 1998
+++ linux/net/ipv4/timer.c	Sat Nov  7 11:00:32 1998
@@ -5,7 +5,7 @@
  *
  *		TIMER - implementation of software timers for IP.
  *
- * Version:	$Id: timer.c,v 1.12 1998/08/28 01:15:29 davem Exp $
+ * Version:	$Id: timer.c,v 1.14 1998/11/07 11:55:43 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -74,7 +74,8 @@
 
 	/* Only process if socket is not in use. */
 	if (atomic_read(&sk->sock_readers)) {
-		sk->timer.expires = jiffies+HZ;
+		/* Try again later. */ 
+		sk->timer.expires = jiffies+HZ/20;
 		add_timer(&sk->timer);
 		return;
 	}
@@ -111,11 +112,10 @@
 
 		case TIME_CLOSE:
 			/* We've waited long enough, close the socket. */
-			sk->state = TCP_CLOSE;
-			net_delete_timer (sk);
+			tcp_set_state(sk, TCP_CLOSE);
+			sk->shutdown = SHUTDOWN_MASK;
 			if (!sk->dead)
 				sk->state_change(sk);
-			sk->shutdown = SHUTDOWN_MASK;
 			net_reset_timer (sk, TIME_DONE, TCP_DONE_TIME);
 			break;
 
diff -u --recursive --new-file v2.1.126/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.126/linux/net/ipv4/udp.c	Mon Oct  5 13:13:48 1998
+++ linux/net/ipv4/udp.c	Sat Oct 31 10:37:14 1998
@@ -1015,7 +1015,7 @@
 }
 
 
-static void udp_close(struct sock *sk, unsigned long timeout)
+static void udp_close(struct sock *sk, long timeout)
 {
 	/* See for explanation: raw_close in ipv4/raw.c */
 	sk->state = TCP_CLOSE;
diff -u --recursive --new-file v2.1.126/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.126/linux/net/ipv6/tcp_ipv6.c	Mon Oct  5 13:13:49 1998
+++ linux/net/ipv6/tcp_ipv6.c	Sat Nov  7 11:00:32 1998
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.93 1998/10/03 09:38:50 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.94 1998/11/07 11:50:33 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -1331,6 +1331,9 @@
 
 	tcp_statistics.TcpInSegs++;
 
+	if (len < sizeof(struct tcphdr))
+		goto bad_packet;
+
 	/*
 	 *	Try to use the device checksum if provided.
 	 */
@@ -1341,6 +1344,7 @@
 	case CHECKSUM_HW:
 		if (tcp_v6_check(th,len,saddr,daddr,skb->csum)) {
 			printk(KERN_DEBUG "tcp csum failed\n");
+	bad_packet:		
 			tcp_statistics.TcpInErrs++;
 			goto discard_it;
 		}
diff -u --recursive --new-file v2.1.126/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- v2.1.126/linux/net/netlink/af_netlink.c	Mon Oct  5 13:13:49 1998
+++ linux/net/netlink/af_netlink.c	Sat Nov  7 11:00:33 1998
@@ -427,7 +427,7 @@
 			continue;
 
 		if (failure) {
-			sk->err = -ENOBUFS;
+			sk->err = ENOBUFS;
 			sk->state_change(sk);
 			continue;
 		}
@@ -442,12 +442,12 @@
 			}
 		}
 		if (skb2 == NULL) {
-			sk->err = -ENOBUFS;
+			sk->err = ENOBUFS;
 			sk->state_change(sk);
 			/* Clone failed. Notify ALL listeners. */
 			failure = 1;
 		} else if (netlink_broadcast_deliver(sk, skb2)) {
-			sk->err = -ENOBUFS;
+			sk->err = ENOBUFS;
 			sk->state_change(sk);
 		} else
 			skb2 = NULL;
diff -u --recursive --new-file v2.1.126/linux/net/protocols.c linux/net/protocols.c
--- v2.1.126/linux/net/protocols.c	Thu Jul 16 18:09:32 1998
+++ linux/net/protocols.c	Tue Oct 27 09:57:19 1998
@@ -22,6 +22,10 @@
 #endif
 #endif	/* INET */
 
+#ifdef CONFIG_ECONET
+extern void econet_proto_init(struct net_proto *pro);
+#endif
+
 #ifdef CONFIG_NETLINK
 extern void netlink_proto_init(struct net_proto *pro);
 #endif
@@ -151,6 +155,10 @@
 
 #ifdef CONFIG_X25
   { "X.25",	x25_proto_init },			/* CCITT X.25 Packet Layer */
+#endif
+
+#ifdef CONFIG_ECONET
+  { "Econet",	econet_proto_init },			/* Acorn Econet */
 #endif
 
   { NULL,	NULL		}			/* End marker			*/
diff -u --recursive --new-file v2.1.126/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.1.126/linux/net/sunrpc/sched.c	Wed Sep  9 14:51:13 1998
+++ linux/net/sunrpc/sched.c	Sat Oct 31 10:17:23 1998
@@ -127,7 +127,7 @@
 			task->tk_pid, task->tk_timeout * 1000 / HZ);
 	if (!timer)
 		timer = __rpc_default_timer;
-	if (expires < jiffies) {
+	if (time_before(expires, jiffies)) {
 		printk(KERN_ERR "RPC: bad timeout value %ld - setting to 10 sec!\n",
 					task->tk_timeout);
 		expires = jiffies + 10 * HZ;
@@ -413,7 +413,6 @@
 							task->tk_pid);
 			if (current->pid == rpciod_pid)
 				printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
-			current->timeout = 0;
 			sleep_on(&task->tk_wait);
 
 			/*
@@ -552,9 +551,8 @@
 		}
 		if (flags & RPC_TASK_ASYNC)
 			return NULL;
-		current->timeout = jiffies + (HZ >> 4);
 		current->state = TASK_INTERRUPTIBLE;
-		schedule();
+		schedule_timeout(HZ>>4);
 	} while (!signalled());
 
 	return NULL;
@@ -846,9 +844,7 @@
 		if (all_tasks) {
 			dprintk("rpciod_killall: waiting for tasks to exit\n");
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + 1;
-			schedule();
-			current->timeout = 0;
+			schedule_timeout(1);
 		}
 	}
 
@@ -919,9 +915,7 @@
 	 */
 	current->sigpending = 0;
 	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + 1;
-	schedule();
-	current->timeout = 0;
+	schedule_timeout(1);
 	/*
 	 * Display a message if we're going to wait longer.
 	 */
diff -u --recursive --new-file v2.1.126/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.1.126/linux/net/sunrpc/svcsock.c	Mon Oct  5 13:13:49 1998
+++ linux/net/sunrpc/svcsock.c	Sat Oct 31 10:17:23 1998
@@ -731,14 +731,14 @@
  * Receive the next request on any socket.
  */
 int
-svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp)
+svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
 {
 	struct svc_sock		*svsk;
 	int			len;
 	struct wait_queue	wait = { current, NULL };
 
 	dprintk("svc: server %p waiting for data (to = %ld)\n",
-		rqstp, current->timeout);
+		rqstp, timeout);
 
 	if (rqstp->rq_sock)
 		printk(KERN_ERR 
@@ -772,7 +772,7 @@
 		current->state = TASK_INTERRUPTIBLE;
 		add_wait_queue(&rqstp->rq_wait, &wait);
 		end_bh_atomic();
-		schedule();
+		schedule_timeout(timeout);
 
 		remove_wait_queue(&rqstp->rq_wait, &wait);
 
diff -u --recursive --new-file v2.1.126/linux/scripts/Configure linux/scripts/Configure
--- v2.1.126/linux/scripts/Configure	Sat Sep  5 16:46:42 1998
+++ linux/scripts/Configure	Sun Oct 25 14:30:47 1998
@@ -53,6 +53,9 @@
 #
 # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
 # texts.
+#
+# 102598 Michael Chastain (mec@shout.net) - put temporary files in
+# current directory, not in /tmp.
 
 #
 # Make sure we're really running bash.
@@ -506,9 +509,9 @@
   echo "# Using defaults found in" $DEFAULTS
   echo "#"
   . $DEFAULTS
-  sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > /tmp/conf.$$
-  . /tmp/conf.$$
-  rm /tmp/conf.$$
+  sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > .config-is-not.$$
+  . .config-is-not.$$
+  rm .config-is-not.$$
 else
   echo "#"
   echo "# No defaults found"
