diff -u --recursive --new-file v1.1.88/linux/Makefile linux/Makefile
--- v1.1.88/linux/Makefile	Wed Feb  1 09:23:04 1995
+++ linux/Makefile	Wed Feb  1 09:20:45 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 88
+SUBLEVEL = 89
 
 ARCH = i386
 
diff -u --recursive --new-file v1.1.88/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v1.1.88/linux/arch/alpha/config.in	Sun Jan 22 21:39:37 1995
+++ linux/arch/alpha/config.in	Wed Feb  1 21:46:07 1995
@@ -5,7 +5,7 @@
 
 comment 'General setup'
 
-bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD n
+bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y
 bool 'Normal harddisk support' CONFIG_BLK_DEV_HD n
 bool 'XT harddisk support' CONFIG_BLK_DEV_XD n
 bool 'Networking support' CONFIG_NET n
diff -u --recursive --new-file v1.1.88/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v1.1.88/linux/arch/alpha/kernel/head.S	Mon Jan 16 14:18:12 1995
+++ linux/arch/alpha/kernel/head.S	Wed Feb  1 21:46:08 1995
@@ -9,6 +9,7 @@
 
 #define __ASSEMBLY__
 #include <asm/system.h>
+#include <linux/fd.h>
 
 #define halt .long PAL_halt
 
@@ -58,4 +59,7 @@
 	ret ($26)
 	.end rdusp
 
-
+.align 5
+.globl floppy_track_buffer
+floppy_track_buffer:
+	.space 512*2*MAX_BUFFER_SECTORS,1
diff -u --recursive --new-file v1.1.88/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v1.1.88/linux/arch/alpha/kernel/irq.c	Thu Jan 26 07:49:02 1995
+++ linux/arch/alpha/kernel/irq.c	Fri Feb  3 18:42:15 1995
@@ -156,9 +156,11 @@
 	action->flags = irqflags;
 	action->mask = 0;
 	action->name = devname;
-	if (irq < 8 && irq) {
-		cache_21 &= ~(1<<irq);
-		outb(cache_21,0x21);
+	if (irq < 8) {
+		if (irq) {
+			cache_21 &= ~(1<<irq);
+			outb(cache_21,0x21);
+		}
 	} else {
 		cache_21 &= ~(1<<2);
 		cache_A1 &= ~(1<<(irq-8));
@@ -298,7 +300,6 @@
 	if (irq == 1)
 		irq = 7;
 #endif
-	printk("%d%d", irq, ack);
 	kstat.interrupts[irq]++;
 	action = irq_action + irq;
 	/* quick interrupts get executed with no extra overhead */
diff -u --recursive --new-file v1.1.88/linux/arch/alpha/kernel/lca.c linux/arch/alpha/kernel/lca.c
--- v1.1.88/linux/arch/alpha/kernel/lca.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/alpha/kernel/lca.c	Fri Feb  3 18:42:15 1995
@@ -0,0 +1,300 @@
+/*
+ * Code common to all LCA chips.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/lca.h>
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+/*
+ * PCI BIOS32 interface:
+ */
+#define MAJOR_REV	0
+#define MINOR_REV	0
+
+#ifdef CONFIG_PCI
+
+#define mtpr_mces(v) \
+({ \
+    register unsigned long v0 asm ("0"); \
+    register unsigned long a0 asm ("16"); \
+    a0 = (v); \
+    asm volatile ("call_pal %1 # %0 %2" : "r="(v0) \
+		  : "i"(PAL_mtpr_mces), "r"(a0) \
+		  : "memory", "0", "1", "16", "22", "23", "24", "25"); \
+    v0; \
+})
+
+#define draina()	asm volatile ("call_pal %0" :: "i"(PAL_draina))
+
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the LCA_IOC_CONF register
+ * accordingly.  It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ */
+static int
+mk_conf_addr(unsigned char bus, unsigned char device_fn,
+	    unsigned char where, unsigned long *pci_addr)
+{
+	unsigned long addr;
+
+	if (bus == 0) {
+		int device = device_fn >> 3;
+		int func = device_fn & 0x7;
+
+		/* type 0 configuration cycle: */
+
+		if (device > 12) {
+			return -1;
+		} /* if */
+
+		*((volatile unsigned long*) LCA_IOC_CONF) = 0;
+		addr = (1 << (11 + device)) | (func << 8) | where;
+	} else {
+		/* type 1 configuration cycle: */
+		*((volatile unsigned long*) LCA_IOC_CONF) = 1;
+		addr = (bus << 16) | (device_fn << 8) | where;
+	} /* if */
+	*pci_addr = addr;
+
+	return 0;
+}
+
+
+static unsigned int
+conf_read(unsigned long addr)
+{
+	unsigned long old_ipl, code, stat0;
+	unsigned int value;
+
+	old_ipl = swpipl(7);	/* avoid getting hit by machine check */
+
+	/* reset status register to avoid loosing errors: */
+	stat0 = *((volatile unsigned long*)LCA_IOC_STAT0);
+	*((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+	mb();
+
+	/* access configuration space: */
+
+	value = *((volatile unsigned int*)addr);
+	draina();
+
+	stat0 = *((unsigned long*)LCA_IOC_STAT0);
+	if (stat0 & LCA_IOC_STAT0_ERR) {
+		code = ((stat0 >> LCA_IOC_STAT0_CODE_SHIFT)
+			& LCA_IOC_STAT0_CODE_MASK);
+		if (code != 1) {
+			printk("lca.c:conf_read: got stat0=%lx\n", stat0);
+		}
+
+		/* reset error status: */
+		*((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+		mb();
+		mtpr_mces(0x7);			/* reset machine check */
+
+		value = 0xffffffff;
+	}
+	swpipl(old_ipl);
+
+	return value;
+}
+
+
+static void
+conf_write(unsigned long addr, unsigned int value)
+{
+}
+
+
+int
+pcibios_present (void)
+{
+	return 1;		/* present if configured */
+}
+
+
+int
+pcibios_find_class (unsigned long class_code, unsigned short index,
+		    unsigned char *bus, unsigned char *device_fn)
+{
+	pci_resource_t *dev;
+	unsigned long w;
+
+	for (dev = pci_device_list; dev; dev = dev->next) {
+		pcibios_read_config_dword(dev->bus, dev->dev_fn,
+					  PCI_CLASS_REVISION, &w);
+		if ((w >> 8) == class_code) {
+			if (index == 0) {
+				*bus = dev->bus;
+				*device_fn = dev->dev_fn;
+				return PCIBIOS_SUCCESSFUL;
+			}
+			--index;
+		}
+	}
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+
+int
+pcibios_find_device (unsigned short vendor, unsigned short device_id,
+		     unsigned short index, unsigned char *bus,
+		     unsigned char *device_fn)
+{
+	unsigned long w, desired = (device_id << 16) | vendor;
+	pci_resource_t *dev;
+
+	if (vendor == 0xffff) {
+		return PCIBIOS_BAD_VENDOR_ID;
+	}
+
+	for (dev = pci_device_list; dev; dev = dev->next) {
+		pcibios_read_config_dword(dev->bus, dev->dev_fn,
+					  PCI_VENDOR_ID, &w);
+		if (w == desired) {
+			if (index == 0) {
+				*bus = dev->bus;
+				*device_fn = dev->dev_fn;
+				return PCIBIOS_SUCCESSFUL;
+			}
+			--index;
+		}
+	}
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+
+int
+pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+			  unsigned char where, unsigned char *value)
+{
+	unsigned long addr = LCA_CONF;
+	unsigned long pci_addr;
+
+	*value = 0xff;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) {
+		return PCIBIOS_SUCCESSFUL;
+	} /* if */
+
+	addr |= (pci_addr << 5) + 0x00;
+
+	*value = conf_read(addr) >> ((where & 3) * 8);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int
+pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+			  unsigned char where, unsigned short *value)
+{
+	unsigned long addr = LCA_CONF;
+	unsigned long pci_addr;
+
+	*value = 0xffff;
+
+	if (where & 0x1) {
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	} /* if */
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr)) {
+		return PCIBIOS_SUCCESSFUL;
+	} /* if */
+
+	addr |= (pci_addr << 5) + 0x08;
+
+	*value = conf_read(addr) >> ((where & 3) * 8);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int
+pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+			   unsigned char where, unsigned long *value)
+{
+	unsigned long addr = LCA_CONF;
+	unsigned long pci_addr;
+
+	*value = 0xffffffff;
+
+	if (where & 0x3) {
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	} /* if */
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr)) {
+		return PCIBIOS_SUCCESSFUL;
+	} /* if */
+
+	addr |= (pci_addr << 5) + 0x18;
+
+	*value = conf_read(addr);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+int
+pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+			   unsigned char where, unsigned char value)
+{
+	panic("pcibios_write_config_byte");
+}
+
+int
+pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+			   unsigned char where, unsigned short value)
+{
+	panic("pcibios_write_config_word");
+}
+
+int
+pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+			    unsigned char where, unsigned long value)
+{
+	panic("pcibios_write_config_dword");
+}
+
+#endif /* CONFIG_PCI */
+
+
+unsigned long
+bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+#ifdef CONFIG_PCI
+	printk("LCA PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
+
+	probe_pci();
+
+#if 0
+	{
+		char buf[4096];
+
+		get_pci_list(buf);
+		printk("%s", buf);
+	}
+#endif
+
+#if 0
+	{
+		extern void NCR53c810_test(void);
+		NCR53c810_test();
+	}
+#endif
+#endif /* CONFIG_PCI */
+
+    return memory_start;
+} /* bios32_init */
+
+			/*** end of lca.c ***/
diff -u --recursive --new-file v1.1.88/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v1.1.88/linux/arch/alpha/kernel/process.c	Mon Jan 16 14:18:12 1995
+++ linux/arch/alpha/kernel/process.c	Wed Feb  1 21:46:08 1995
@@ -41,6 +41,11 @@
 	halt();
 }
 
+void show_regs(struct pt_regs * regs)
+{
+	printk("\nPS: %04lx PC: %016lx\n", regs->ps, regs->pc);
+}
+
 /*
  * Do necessary setup to start up a newly executed thread.
  */
diff -u --recursive --new-file v1.1.88/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v1.1.88/linux/arch/alpha/kernel/setup.c	Sun Jan 22 21:39:37 1995
+++ linux/arch/alpha/kernel/setup.c	Wed Feb  1 21:46:08 1995
@@ -29,12 +29,6 @@
 unsigned char aux_device_present;
 
 /*
- * XXXXX!! Warning Will Robinson.
- * Danger! Danger! This is bogus, I'll get it to link if it kills me
- */
-unsigned char floppy_track_buffer[256];
-
-/*
  * The format of "screen_info" is strange, and due to early
  * i386-setup code. This is just enough to make the console
  * code think we're on a EGA+ colour display.
diff -u --recursive --new-file v1.1.88/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v1.1.88/linux/arch/i386/kernel/process.c	Wed Feb  1 09:23:04 1995
+++ linux/arch/i386/kernel/process.c	Wed Feb  1 21:46:08 1995
@@ -27,6 +27,18 @@
 
 asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
 
+static int hlt_counter=0;
+
+void disable_hlt(void)
+{
+	hlt_counter++;
+}
+
+void enable_hlt(void)
+{
+	hlt_counter--;
+}
+
 /*
  * The idle loop on a i386..
  */
@@ -44,7 +56,7 @@
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	for (;;) {
-		if (hlt_works_ok && !need_resched)
+		if (hlt_works_ok && !hlt_counter && !need_resched)
 			__asm__("hlt");
 		schedule();
 	}
@@ -83,6 +95,22 @@
 		}
 		__asm__ __volatile__("\tlidt %0": "=m" (no_idt));
 	}
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	printk("\n");
+	printk("EIP: %04x:%08lx",0xffff & regs->cs,regs->eip);
+	if (regs->cs & 3)
+		printk(" ESP: %04x:%08lx",0xffff & regs->ss,regs->esp);
+	printk(" EFLAGS: %08lx\n",regs->eflags);
+	printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
+		regs->orig_eax,regs->ebx,regs->ecx,regs->edx);
+	printk("ESI: %08lx EDI: %08lx EBP: %08lx",
+		regs->esi, regs->edi, regs->ebp);
+	printk(" DS: %04x ES: %04x FS: %04x GS: %04x\n",
+		0xffff & regs->ds,0xffff & regs->es,
+		0xffff & regs->fs,0xffff & regs->gs);
 }
 
 /*
diff -u --recursive --new-file v1.1.88/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v1.1.88/linux/arch/i386/kernel/traps.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/i386/kernel/traps.c	Wed Feb  1 09:19:36 1995
@@ -199,8 +199,11 @@
 
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
 {
+#ifndef CONFIG_IGNORE_NMI
 	printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
-	printk("You probably have a hardware problem with your RAM chips\n");
+	printk("You probably have a hardware problem with your RAM chips or a\n");
+	printk("power saving mode enabled.\n");
+#endif	
 }
 
 asmlinkage void do_debug(struct pt_regs * regs, long error_code)
diff -u --recursive --new-file v1.1.88/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v1.1.88/linux/arch/i386/kernel/vm86.c	Wed Feb  1 09:23:04 1995
+++ linux/arch/i386/kernel/vm86.c	Sun Feb  5 13:21:31 1995
@@ -366,12 +366,6 @@
 		set_vflags_short(popw(ssp, sp), regs);
 		return;
 
-	/* int 3 */
-	case 0xcc:
-		IP(regs)++;
-		do_int(regs, 3, ssp, sp);
-		return;
-
 	/* int xx */
 	case 0xcd:
 		IP(regs) += 2;
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v1.1.88/linux/arch/sparc/config.in	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/config.in	Thu Feb  2 08:45:28 1995
@@ -13,9 +13,10 @@
 
 bool 'Sparc V8 kernel' CONFIG_SPARC_V8 y
 bool 'Sparc SMP support' CONFIG_LINUX_SMP n
-bool 'Networking support' CONFIG_NET y
+bool 'Networking support' CONFIG_NET n
 bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
 bool 'System V IPC' CONFIG_SYSVIPC y
+bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y
 
 if [ "$CONFIG_NET" = "y" ]; then
 comment 'Networking options'
@@ -174,16 +175,16 @@
 comment 'Filesystems'
 
 bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
-bool 'Extended fs support' CONFIG_EXT_FS n
+bool 'Extended fs support' CONFIG_EXT_FS y
 bool 'Second extended fs support' CONFIG_EXT2_FS y
-bool 'xiafs filesystem support' CONFIG_XIA_FS n
+bool 'xiafs filesystem support' CONFIG_XIA_FS y
 bool 'msdos fs support' CONFIG_MSDOS_FS y
 if [ "$CONFIG_MSDOS_FS" = "y" ]; then
 bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
 fi
-bool '/proc filesystem support' CONFIG_PROC_FS y
+bool '/proc filesystem support' CONFIG_PROC_FS n
 if [ "$CONFIG_INET" = "y" ]; then
-bool 'NFS filesystem support' CONFIG_NFS_FS y
+bool 'NFS filesystem support' CONFIG_NFS_FS n
 fi
 if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
 	bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
@@ -191,7 +192,7 @@
 	bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
 fi
 bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
-bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
+bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS y
 
 
 comment 'character devices'
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v1.1.88/linux/arch/sparc/kernel/entry.S	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/kernel/entry.S	Thu Feb  2 08:45:28 1995
@@ -8,9 +8,9 @@
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <asm/cprefix.h>
 #include <asm/head.h>
 #include <asm/asi.h>
+#include <asm/cprefix.h>
 
 /* Here are macros for routines we do often, this allows me to inline this
  * without making the code look real ugly. Well, the macro looks ugly too but
@@ -44,7 +44,7 @@
 	sethi	%hi( C_LABEL(current) ), %g6; \
 	ld	[%g6 + %lo( C_LABEL(current) )], %g6; \
 	ld	[%g6 + THREAD_UWINDOWS], %g7; /* how many user wins are active? */ \
-	subcc	%g7, 0x0, %g0
+	subcc	%g7, 0x0, %g0; \
 	bne	2f;                            /* If there are any, branch. */ \
 	save	%g0, %g0, %g0;                 /* Save into that window either way. */ \
 	std	%l0, [%sp];                    /* If above shows only kernel windows */ \
@@ -128,8 +128,7 @@
 	or	%g0, %l5, %g5;                  /* Restore the globals. */ \
 	or	%g0, %l6, %g6; \
 	or	%g0, %l7, %g7; \
-8:                                              /* We are done when we get here. */ \
-
+8:      nop;                                     /* We are done when we get here. */ \
 
 /* As if the last macro wasn't enough, we have to go through a very similar routine
  * upon entry to most traps and interrupts. This is save away the current window
@@ -191,7 +190,7 @@
 	sub	%fp, 0xb0, %sp; \
 1: 	sethi	%hi( C_LABEL(current) ), %l6; \
 	ld	[%l6 + %lo( C_LABEL(current) )], %l6; \
-	ld	[%l6 + PCB_WIM], %l5; \
+	ld	[%l6 + THREAD_WIM], %l5; \
 	and	%l0, 0x1f, %l7; \
 	cmp	%l5, %l7; \
 	ble,a	4f; \
@@ -209,7 +208,7 @@
 	sethi	%hi( C_LABEL(eintstack) ), %l7; \
 2: \
 	sub	%l7, 0xb0, %sp; \
-3: \
+3:
 
 	.text
 	.align 4
@@ -217,6 +216,11 @@
 /* Default trap handler */
 	.globl my_trap_handler
 my_trap_handler:
+#if 1
+		jmp	%l1
+		rett	%l2
+		nop
+#else
 		rd %wim, %l4
 		or %g0, 0x1, %l5
 		sll %l5, %l0, %l5
@@ -234,7 +238,18 @@
 		nop                 ! click our heels three times, "no place like home"
 		jmp %l1
 		rett %l2
+#endif /* bogon */
 	
+	.globl sparc_timer
+sparc_timer:
+	ENTER_IRQ
+	or	%g0, 0x10, %o0	
+	call	C_LABEL(do_IRQ)
+	or	%g0, %g0, %o1
+	jmp	%l1
+	rett	%l2
+	nop	
+
 /* This routine is optimized for kernel window fills. User fills take about two
  * or three extra jumps on the average. We'll see how this works out.
  */
@@ -244,10 +259,11 @@
  * see below.
  */
 
-	.globl fill_window_entry
-fill_window_entry:
+	.align 4
+	.globl spill_window_entry
+spill_window_entry:
 	andcc	%l0, 0x40, %g0		! see if this is a user window fill
-	bz,a	fill_from_user
+	bz,a	spill_from_user
 	nop
 
 	TRAP_WIN_CLEAN			/* danger, danger... */
@@ -256,7 +272,7 @@
 	jmp	%l1
 	rett	%l2
 
-fill_from_user:
+spill_from_user:
 	sethi	%hi( C_LABEL(current) ), %l6
 	ld	[%l6 + %lo( C_LABEL(current) )], %l6
 	ld	[%l6 + THREAD_WIM], %l5
@@ -301,12 +317,13 @@
  * it the first time. :>
  */
 
-	.globl spill_window_entry
-spill_window_entry:
+	.align 4
+	.globl fill_window_entry
+fill_window_entry:
 	wr	%g0, 0, %wim		! Can not enter invalid register without this.
 	andcc	%l0, 0x40, %g0          ! From user?
 	restore				! restore to where trap occurred
-	bz	spill_from_user
+	bz	fill_from_user
 	restore				! enter invalid register, whee...
 	restore %g0, 0x1, %l1		! enter one-past invalid register
 	rd	%psr, %l0		! this is the window we need to save
@@ -332,24 +349,24 @@
 	jmp	%l1
 	rett	%l2			! are you as confused as I am?
 
-spill_from_user:
+fill_from_user:
 	andcc	%sp, 0x7, %g0		! check for alignment of user stack
-	bne	spill_bad_stack
+	bne	fill_bad_stack
 	sra	%sp, 0x1e, %l7
 	cmp	%l7, 0x0
 	be,a	1f
 	andn	%sp, 0xfff, %l7
 	cmp	%l7, -1
-	bne	spill_bad_stack
+	bne	fill_bad_stack
 	andn	%sp, 0xfff, %l7
 1:	lda	[%l7] ASI_PTE, %l7
 	srl	%l7, 0x1d, %l7
 	andn	%l7, 0x2, %l7
 	cmp	%l7, 0x4
-	bne	spill_bad_stack
+	bne	fill_bad_stack
 	and	%sp, 0xfff, %l7
 	cmp	%l7, 0xfc1
-	bl,a	spill_stack_ok
+	bl,a	fill_stack_ok
 	restore	%g0, 1, %l1
 	add	%sp, 0x38, %l5
 	sra	%sp, 0x1e, %l7
@@ -357,16 +374,16 @@
 	be,a	1f
 	andn	%sp, 0xfff, %l7
 	cmp	%l7, -1
-	bne	spill_bad_stack
+	bne	fill_bad_stack
 	andn	%sp, 0xfff, %l7
 1:	lda	[%l7] ASI_PTE, %l7
 	srl	%l7, 0x1d, %l7
 	andn	%l7, 0x2, %l7
 	cmp	%l7, 0x4
-	be,a	spill_stack_ok
+	be,a	fill_stack_ok
 	restore	%g0, 0x1, %l1
 
-spill_bad_stack:
+fill_bad_stack:
 	save	%g0, %g0, %g0			! save to where restore happened
 	save	%g0, 0x1, %l4			! save is an add remember? to trap window
 	sethi	%hi( C_LABEL(current) ), %l6
@@ -450,7 +467,7 @@
 	jmp	%l1
 	rett	%l2
 
-spill_stack_ok:
+fill_stack_ok:
 	rd	%psr, %l0
 	sll	%l1, %l0, %l1
 	wr	%l1, 0x0, %wim
@@ -474,24 +491,28 @@
 	jmp	%l1
 	rett	%l2
 
+	.align 4
 	.globl trap_entry
 trap_entry:
 	TRAP_WIN_CLEAN
 	jmp	%l1
 	rett	%l2
 
+	.align 4
 	.globl linux_trap_nmi
 linux_trap_nmi:
 	TRAP_WIN_CLEAN
 	jmp	%l1
 	rett	%l2
 
+	.align 4
 	.globl sparc_trap
 sparc_trap:
 	TRAP_WIN_CLEAN
 	jmp	%l1
 	rett	%l2
 
+	.align 4
 	.globl leave_trap
 leave_trap:
 	jmp	%l1
@@ -655,3 +676,4 @@
 	.long C_LABEL(sys_setfsuid)
 	.long C_LABEL(sys_setfsgid)
 	.long C_LABEL(sys_llseek)		/* 140 */
+	.align 4
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v1.1.88/linux/arch/sparc/kernel/head.S	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/kernel/head.S	Thu Feb  2 08:45:28 1995
@@ -229,13 +229,13 @@
 _start:   /* danger danger */
 start:
 C_LABEL(trapbase):
-	b gokernel; WRITE_PAUSE		! we never get trap #0 it is special
+	b gokernel; nop; nop; nop;	! we never get trap #0 it is special 
 
 	TRAP_ENTRY(0x1, my_trap_handler) /* Instruction Access Exception */
 	TRAP_ENTRY(0x2, my_trap_handler) /* Illegal Instruction */
 	TRAP_ENTRY(0x3, my_trap_handler) /* Privileged Instruction */
 	TRAP_ENTRY(0x4, my_trap_handler) /* Floating Point Disabled */
-	TRAP_ENTRY(0x5, spill_window_entry) /* Window Overflow */
+	TRAP_ENTRY(0x5, spill_window_entry)   /* Window Overflow */
 	TRAP_ENTRY(0x6, fill_window_entry)  /* Window Underflow */
 	TRAP_ENTRY(0x7, my_trap_handler) /* Memory Address Not Aligned */
 	TRAP_ENTRY(0x8, my_trap_handler) /* Floating Point Exception */
@@ -263,7 +263,7 @@
         TRAP_ENTRY_INTERRUPT(11)            /* Interrupt Level 11 */
         TRAP_ENTRY_INTERRUPT(12)            /* Interrupt Level 12 */
         TRAP_ENTRY_INTERRUPT(13)            /* Interrupt Level 13 */
-        TRAP_ENTRY_INTERRUPT(14)            /* Interrupt Level 14 */
+        TRAP_ENTRY(0x27, sparc_timer)       /* Interrupt Level 14 */
         TRAP_ENTRY_INTERRUPT_NMI(15, linux_trap_nmi) /* Level 15 (nmi) */
 
 	TRAP_ENTRY(0x20, my_trap_handler)   /* General Register Access Error */
@@ -491,6 +491,8 @@
 	TRAP_ENTRY(0xfe, my_trap_handler)   /* Software Trap                 */
 	TRAP_ENTRY(0xff, my_trap_handler)   /* Software Trap                 */	
 
+	.skip 4096
+
 C_LABEL(msgbufmapped):
         .word   1
 
@@ -712,18 +714,24 @@
  * to all its routines which allows some sanity during bootup.
  */
 
-#if 0 /* paranoid, need to fix this routine now */
 		sethi	%hi(IE_reg_addr), %l0
 		or	%l0, %lo(IE_reg_addr), %l0
+
+		set	0xf4000000, %l3
 		sethi	%hi(INT_ENABLE_REG_PHYSADR), %l2
 		or	%l2, %lo(INT_ENABLE_REG_PHYSADR), %l2
-		srl	%l2, %g5, %l1
+		srl	%l2, %g5, %l2
+		or	%l2, %l3, %l1		
 
 		sta	%l1, [%l0] ASI_PTE
-		mov	INTS_ALL_ENAB, %l1
+	
+		or	%g0, INTS_ENAB, %l1
+		nop
+		nop
+
 		stb	%l1, [%l0]
-#endif /* paranoid, see above */
 	
+
 /* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's
  * show-time!
  */
@@ -760,7 +768,6 @@
 		wr	%g0, 0x0, %wim		! magical invalid window reg
 		WRITE_PAUSE			! see above
 
-	
 /* I keep the timer interrupt on so that BogoMIPS works and the prom
  * keeps updating it's "jiffies" counter. 100HZ clock on sparcstations.
  */	
@@ -769,29 +776,29 @@
  * write. ;-( like this (PSR_PS | PSR_S | PSR_PIL)...
  */
 
-		sethi	%hi(0x1fc0), %g2
-		or	%g2, %lo(0x1fc0), %g2
+		sethi	%hi(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
+		or	%g2, %lo(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
 		wr	%g2, 0x0, %psr
 		WRITE_PAUSE
 
 		wr	%g0, 0x2, %wim		! window 1 invalid
 		WRITE_PAUSE
+
 		or	%g0, 0x1, %g1
 		sethi	%hi( C_LABEL(current) + THREAD_WIM), %g2
 		st	%g1, [%g2 + %lo( C_LABEL(current) + THREAD_WIM)]
 
 /* I want a kernel stack NOW! */
 
-		set	( C_LABEL(init_user_stack) + 4096 - 96), %fp	
-		set	( C_LABEL(init_user_stack) + 4096), %sp
+		set	( C_LABEL(init_user_stack) + 4092 - 96 - 80), %fp	
+		set	( C_LABEL(init_user_stack) + 4092), %sp
 
-	/* now out stack is set up similarly to the way it is on the i386 */
+/* now out stack is set up similarly to the way it is on the i386 */
 
 		rd	%psr, %l0
 		wr	%l0, PSR_ET, %psr
 		WRITE_PAUSE
 
-
 /*
  * Maybe the prom zeroes out our BSS section, maybe it doesn't. I certainly 
  * don't know, do you?
@@ -852,6 +859,11 @@
 
 /* Here we go */
 
+		set	C_LABEL(trapbase), %g3
+		wr	%g3, 0x0, %tbr
+		WRITE_PAUSE
+
+
 /* First we call init_prom() to set up romvec, then off to start_kernel() */
 /* XXX put this in arch_init() */
 
@@ -985,3 +997,6 @@
 C_LABEL(empty_bad_page_table):		.skip 0x1000
 C_LABEL(empty_zero_page):		.skip 0x1000
 
+		.align 4
+diagstr:	.asciz	"DIAG\n"
+		.align 4
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v1.1.88/linux/arch/sparc/kernel/ioport.c	Wed Feb  1 09:23:04 1995
+++ linux/arch/sparc/kernel/ioport.c	Thu Feb  2 08:45:28 1995
@@ -1,6 +1,6 @@
 /* ioport.c:  I/O access on the Sparc. Work in progress.. Most of the things
  *            in this file are for the sole purpose of getting the kernel
- *	      through the compiler. :-)
+ *	      throught the compiler. :-)
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v1.1.88/linux/arch/sparc/kernel/irq.c	Mon Jan 16 14:18:15 1995
+++ linux/arch/sparc/kernel/irq.c	Thu Feb  2 08:45:28 1995
@@ -19,17 +19,58 @@
  * sa_restorer is the unused
  */
 
-#include <asm/ptrace.h>
-#include <asm/system.h>
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/psr.h>
 
 void disable_irq(unsigned int irq_nr)
 {
   unsigned long flags;
-
+  unsigned char *int_reg;
+  
   save_flags(flags);
+  cli();
+
+  /* We have mapped the irq enable register in head.S and all we
+   * have to do here is frob the bits.
+   */
+
+  int_reg = (char *) IRQ_ENA_ADR;
+
+  switch(irq_nr)
+    {
+    case 1:
+      *int_reg = ((*int_reg) & (~(0x02)));
+      break;
+    case 4:
+      *int_reg = ((*int_reg) & (~(0x04)));
+      break;
+    case 6:
+      *int_reg = ((*int_reg) & (~(0x08)));
+      break;      
+    case 8:
+      *int_reg = ((*int_reg) & (~(0x10)));
+      break;      
+    case 10:
+      *int_reg = ((*int_reg) & (~(0x20)));
+      break;      
+    case 14:
+      *int_reg = ((*int_reg) & (~(0x80)));
+      break;      
+    default:
+      printk("AIEEE, Illegal interrupt disable requested irq=%d\n", 
+	     (int) irq_nr);
+      break;
+    };
+  
   restore_flags(flags);
   return;
 }
@@ -37,19 +78,141 @@
 void enable_irq(unsigned int irq_nr)
 {
   unsigned long flags;
-
+  unsigned int *int_reg;
+  
   save_flags(flags);
+  cli();
+
+  /* We have mapped the irq enable register in head.S and all we
+   * have to do here is frob the bits.
+   */
+
+  int_reg = (unsigned int *) IRQ_ENA_ADR;
+  
+  switch(irq_nr)
+    {
+    case 1:
+      *int_reg = ((*int_reg) | 0x02);
+      break;
+    case 4:
+      *int_reg = ((*int_reg) | 0x04);
+      break;
+    case 6:
+      *int_reg = ((*int_reg) | 0x08);
+      break;      
+    case 8:
+      *int_reg = ((*int_reg) | 0x10);
+      break;      
+    case 10:
+      *int_reg = ((*int_reg) | 0x20);
+      break;      
+    case 14:
+      *int_reg = ((*int_reg) | 0x80);
+      break;      
+    default:
+      printk("AIEEE, Illegal interrupt enable requested irq=%d\n", 
+	     (int) irq_nr);
+      break;
+    };
+
   restore_flags(flags);
   return;
 }
 
+/*
+ * Initial irq handlers.
+ */
+struct irqaction {
+  void (*handler)(int, struct pt_regs *);
+  unsigned long flags;
+  unsigned long mask;
+  const char *name;
+};
+
+static struct irqaction irq_action[16] = {
+  { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+  { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+  { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+  { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+  { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+  { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+  { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+  { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
+};
+
+
 int get_irq_list(char *buf)
 {
-  int len = 0;
-
+  int i, len = 0;
+  struct irqaction * action = irq_action;
+  
+  for (i = 0 ; i < 16 ; i++, action++) {
+    if (!action->handler)
+      continue;
+    len += sprintf(buf+len, "%2d: %8d %c %s\n",
+		   i, kstat.interrupts[i],
+		   (action->flags & SA_INTERRUPT) ? '+' : ' ',
+		   action->name);
+  }
   return len;
 }
 
+void free_irq(unsigned int irq)
+{
+        struct irqaction * action = irq + irq_action;
+        unsigned long flags;
+
+        if (irq > 14) {  /* 14 irq levels on the sparc */
+                printk("Trying to free IRQ%d\n", irq);
+                return;
+        }
+        if (!action->handler) {
+                printk("Trying to free free IRQ%d\n", irq);
+                return;
+        }
+        save_flags(flags);
+        cli();
+        disable_irq(irq);
+        action->handler = NULL;
+        action->flags = 0;
+        action->mask = 0;
+        action->name = NULL;
+        restore_flags(flags);
+}
+
+#if 0
+static void handle_nmi(struct pt_regs * regs)
+{
+  printk("NMI, probably due to bus-parity error.\n");
+  printk("PC=%08lx, SP=%08lx\n", regs->pc, regs->sp);
+}
+#endif
+
+static void unexpected_irq(int irq, struct pt_regs * regs)
+{
+        int i;
+
+        printk("IO device interrupt, irq = %d\n", irq);
+        printk("PC = %08lx NPC = %08lx SP=%08lx\n", regs->pc, 
+	       regs->npc, regs->sp);
+        printk("Expecting: ");
+        for (i = 0; i < 16; i++)
+                if (irq_action[i].handler)
+                        printk("[%s:%d] ", irq_action[i].name, i);
+        printk("AIEEE\n");
+}
+
+static inline void handler_irq(int irq, struct pt_regs * regs)
+{
+  struct irqaction * action = irq + irq_action;
+
+  if (!action->handler) {
+    unexpected_irq(irq, regs);
+    return;
+  }
+  action->handler(irq, regs);
+}
+
 /*
  * do_IRQ handles IRQ's that have been installed without the
  * SA_INTERRUPT flag: it uses the full signal-handling return
@@ -59,7 +222,10 @@
  */
 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
+  struct irqaction *action = irq + irq_action;
+
   kstat.interrupts[irq]++;
+  action->handler(irq, regs);
   return;
 }
 
@@ -71,37 +237,43 @@
 asmlinkage void do_fast_IRQ(int irq)
 {
   kstat.interrupts[irq]++;
+  printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
   return;
 }
 
-#define SA_PROBE SA_ONESHOT
-
-/*
- * Using "struct sigaction" is slightly silly, but there
- * are historical reasons and it works well, so..
- */
-static int irqaction(unsigned int irq, struct sigaction * new_sa)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	restore_flags(flags);
-	return 0;
-}
 		
-int request_irq(unsigned int irq, void (*handler)(int),
-	unsigned long flags, const char * devname)
-{
-	return irqaction(irq, (struct sigaction *) 0);
-}
-
-void free_irq(unsigned int irq)
+int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
+	unsigned long irqflags, const char * devname)
 {
+  struct irqaction *action;
   unsigned long flags;
 
+  if(irq > 14)  /* Only levels 1-14 are valid on the Sparc. */
+    return -EINVAL;
+
+  if(irq == 0)  /* sched_init() requesting the timer IRQ */
+    irq = 14;
+
+  action = irq + irq_action;
+
+  if(action->handler)
+    return -EBUSY;
+
+  if(!handler)
+    return -EINVAL;
+
   save_flags(flags);
+  cli();
+
+  action->handler = handler;
+  action->flags = irqflags;
+  action->mask = 0;
+  action->name = devname;
+
+  enable_irq(irq);
+
   restore_flags(flags);
-  return;
+  return 0;
 }
 
 unsigned int probe_irq_on (void)
@@ -120,10 +292,5 @@
 
 void init_IRQ(void)
 {
-  int i;
-
-  for (i = 0; i < 16 ; i++)
-    set_intr_gate(0x20+i,bad_interrupt[i]);
-
   return;
 }
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/kernel/probe.c linux/arch/sparc/kernel/probe.c
--- v1.1.88/linux/arch/sparc/kernel/probe.c	Wed Feb  1 09:23:04 1995
+++ linux/arch/sparc/kernel/probe.c	Thu Feb  2 08:45:28 1995
@@ -5,6 +5,10 @@
 
 #include <linux/kernel.h>
 #include <asm/vac-ops.h>
+#include <asm/io.h>
+#include <asm/vaddrs.h>
+#include <asm/param.h>
+#include <asm/clock.h>
 
 /* #define DEBUG_PROBING */
 
@@ -236,7 +240,49 @@
 void
 probe_clock(int fchild)
 {
-  /* TODO :> I just can't stomach it right now... */
+  register int node, type;
+  register char *node_str;
+
+  /* This will basically traverse the node-tree of the prom to see
+   * which timer chip is on this machine.
+   */
+
+  printk("Probing timer chip... ");
+
+  type = 0;
+  for(node = fchild ; ; )
+    {
+      node_str = get_str_from_prom(node, "model", promstr_buf);
+      if(strcmp(node_str, "mk48t02") == 0)
+	{
+	  type = 2;
+	  break;
+	}
+
+      if(strcmp(node_str, "mk48t08") == 0)
+	{
+	  type = 8;
+	  break;
+	}
+
+      node = node_get_sibling(node);
+      if(node == fchild)
+	{
+	  printk("Aieee, could not find timer chip type\n");
+	  return;
+	}
+    }
+
+  printk("%s\n", node_str);
+  printk("At OBIO address: 0x%x Virtual address: 0x%x\n",
+	 (unsigned int) 0xf3000000, (unsigned int) TIMER_STRUCT);
+
+  mapioaddr((unsigned long) 0xf3000000,
+	    (unsigned long) TIMER_STRUCT);
+
+  TIMER_STRUCT->timer_limit14=(((10000) << 10) | 0x80000000);
+  TIMER_STRUCT->timer_limit10=(((10000) << 10) | 0x80000000);
+
   return;
 }
 
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v1.1.88/linux/arch/sparc/kernel/process.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/kernel/process.c	Thu Feb  2 08:45:28 1995
@@ -48,6 +48,12 @@
 	halt();
 }
 
+void show_regs(struct pt_regs * regs)
+{
+        printk("\nSP: %08lx PC: %08lx NPC: %08lx\n", regs->sp, regs->pc,
+	       regs->npc);
+}
+
 /*
  * Do necessary setup to start up a newly executed thread.
  */
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/kernel/promops.c linux/arch/sparc/kernel/promops.c
--- v1.1.88/linux/arch/sparc/kernel/promops.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/kernel/promops.c	Thu Feb  2 08:45:28 1995
@@ -8,7 +8,7 @@
 
 #include <asm/openprom.h>
 
-#define DEBUG_PROMOPS
+/* #define DEBUG_PROMOPS */
 #define MAX_PR_LEN   16           /* exotic hardware probably overshoots this */
 
 int prom_node_root;               /* initialized in init_prom */
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v1.1.88/linux/arch/sparc/kernel/setup.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/kernel/setup.c	Thu Feb  2 08:45:28 1995
@@ -92,6 +92,8 @@
 	printk("calling probe_devices...\n");
 	probe_devices();  /* cpu/fpu, mmu probes */
 
+	swpipl(13);
+
 	*memory_start_p = (((unsigned long) &end));
 }
 
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c
--- v1.1.88/linux/arch/sparc/kernel/traps.c	Mon Jan 16 14:18:15 1995
+++ linux/arch/sparc/kernel/traps.c	Thu Feb  2 08:45:28 1995
@@ -32,9 +32,11 @@
 
   /* load up the trap table */
 
+#if 0 /* not yet */
   __asm__("wr %0, 0x0, %%tbr\n\t"
 	  "nop; nop; nop\n\t" : :
 	  "r" (trapbase));
+#endif
 
   return;
 }
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v1.1.88/linux/arch/sparc/mm/fault.c	Thu Jan 26 07:49:03 1995
+++ linux/arch/sparc/mm/fault.c	Thu Feb  2 08:45:28 1995
@@ -9,6 +9,7 @@
 #include <asm/segment.h>
 #include <asm/openprom.h>
 #include <asm/page.h>
+#include <asm/pgtable.h>
 
 extern unsigned long pg0[1024];		/* page table for 0-4MB for everybody */
 extern void die_if_kernel(char *,struct pt_regs *,long);
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v1.1.88/linux/arch/sparc/mm/init.c	Wed Feb  1 09:23:04 1995
+++ linux/arch/sparc/mm/init.c	Thu Feb  2 08:45:28 1995
@@ -19,6 +19,8 @@
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/vac-ops.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
 
 extern void scsi_mem_init(unsigned long);
 extern void sound_mem_init(void);
@@ -42,16 +44,16 @@
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-unsigned long __bad_pagetable(void)
+pte_t *__bad_pagetable(void)
 {
 	memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
-	return EMPTY_PGT;
+	return (pte_t *) EMPTY_PGT;
 }
 
-unsigned long __bad_page(void)
+pte_t __bad_page(void)
 {
 	memset((void *) EMPTY_PGE, 0, PAGE_SIZE);
-	return EMPTY_PGE;
+	return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
 }
 
 unsigned long __zero_page(void)
@@ -95,7 +97,7 @@
  * unmaps the bootup page table (as we're now in KSEG, so we don't need it).
  *
  * The bootup sequence put the virtual page table into high memory: that
- * means that we can change the L1 page table by just using VL1p below.
+ * means that we cah change the L1 page table by just using VL1p below.
  */
 
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
@@ -135,12 +137,12 @@
 
 	for(a=0; a<b; a++)
 	  {
-	    for(i=1; i<num_contexts; i++)
+	    for(i=0; i<num_contexts; i++)
 	      {
 		/* map the kernel virt_addrs */
 		(*(romvec->pv_setctxt))(i, (char *) c, a);
-		c += 4096;
 	      }
+	    c += 0x40000;
 	  }
 
 	/* Ok, since now mapped in all contexts, we can free up
@@ -181,9 +183,7 @@
 	      }
 	  }
 
-#if 0 /* bogosity */
 	invalidate(); /* flush the virtual address cache */
-#endif /* bletcherous */
 
 	printk("\nCurrently in context - ");
 	for(i=0; i<num_contexts; i++)
diff -u --recursive --new-file v1.1.88/linux/arch/sparc/mm/vac-flush.c linux/arch/sparc/mm/vac-flush.c
--- v1.1.88/linux/arch/sparc/mm/vac-flush.c	Mon Jan 16 14:18:15 1995
+++ linux/arch/sparc/mm/vac-flush.c	Thu Feb  2 08:45:28 1995
@@ -5,6 +5,7 @@
 */
 
 #include <asm/vac-ops.h>
+#include <asm/page.h>
 
 /* Flush all VAC entries for the current context */
 
@@ -26,7 +27,7 @@
       while(entries_left-- >=0)
 	{
 	  hw_flush_vac_context_entry(address);
-	  address += 4096;
+	  address += PAGE_SIZE;
 	}
     }
   else
@@ -56,7 +57,7 @@
       while(entries_left-- >=0)
 	{
 	  hw_flush_vac_segment_entry(address);
-	  address += 4096;
+	  address += PAGE_SIZE;
 	}
     }
   else
diff -u --recursive --new-file v1.1.88/linux/drivers/block/README.aztcd linux/drivers/block/README.aztcd
--- v1.1.88/linux/drivers/block/README.aztcd	Wed Feb  1 09:23:04 1995
+++ linux/drivers/block/README.aztcd	Fri Feb  3 15:15:09 1995
@@ -81,6 +81,12 @@
 message, that the ISO9660-filesystem is not supported by your kernel, when
 you try to mount the CD-ROM drive, you have to recompile your kernel.
 
+If you do *not* have an Aztech/Orchid/Okano/Wearnes drive and want to bypass
+drive detection during Linux boot up, start with boot parameter aztcd=0.
+
+Joe Nardone has compiled a boot disk with the Aztech driver for installing 
+Slackware from CDROM. You can find the disk images at 'sunsite.unc.edu'; 
+see file 'aztech.gz.README' for instructions on how to use it.
 
 4. RECOMPILING YOUR KERNEL
 If your kernel is not yet configured for the AZTECH driver and the ISO9660-
@@ -428,6 +434,7 @@
           V0.4  W.Zimmermann: fixed some bugs. Dec. 17, 1994
           V0.5  W.Zimmermann: clean 'scanf' commands without compiler warnings
                               Jan. 6, 1995
+          V0.6  W.Zimmermann: volume control (still experimental). Jan. 24, 1995
 */
 
 #include <stdio.h>
@@ -444,7 +451,7 @@
   printf("                     PLAY TRACK   t      PAUSE        p       RESUME       r\n");
   printf("                     NEXT TRACK   n      REPEAT LAST  l       HELP         h\n");
   printf("                     SUB CHANNEL  c      TRACK INFO   i       PLAY AT      a\n");
-  printf("                     READ         d      READ RAW     w                     \n");
+  printf("                     READ         d      READ RAW     w       VOLUME       v\n");
 }
 
 int main(void)
@@ -459,8 +466,9 @@
   union  { struct cdrom_msf msf;
            unsigned char buf[2336];
          } azt;
+  struct cdrom_volctrl  volctrl;
 
-  printf("\nMini-Audio CD-Player V0.5   (C) 1994,1995  W.Zimmermann\n");
+  printf("\nMini-Audio CD-Player V0.6   (C) 1994,1995  W.Zimmermann\n");
   handle=open("/dev/cdrom",O_RDWR);
   ioctl(handle,CDROMRESUME);
   
@@ -580,7 +588,7 @@
                               entry.cdte_track=arg1;
                               if (entry.cdte_track<first) entry.cdte_track=first;
                               if (entry.cdte_track>last)  entry.cdte_track=last;
-                              entry.cdte_format=CDROM_MSF;
+			      entry.cdte_format=CDROM_MSF;
                               if (ioctl(handle,cmd,&entry)) 
                                { printf("Drive error or invalid track no.\n");
                                }
@@ -672,6 +680,19 @@
                            } 
                           break;
 #endif
+              case 'v':   cmd=CDROMVOLCTRL;
+                          printf("--Channel 0 Left  (0-255): ");
+                          scanf("%d",&arg1);
+                          printf("--Channel 1 Right (0-255): ");
+                          scanf("%d",&arg2);
+                          volctrl.channel0=arg1;
+                          volctrl.channel1=arg2;
+                          volctrl.channel2=0;
+                          volctrl.channel3=0;
+                          if (ioctl(handle,cmd,&volctrl)) 
+                           { printf("Drive error or unsupported command\n");
+                           }
+                          break;  
               case 'q':   if (close(handle)) printf("Drive Error: CLOSE\n");
                           exit(0);
               case 'h':   help();
diff -u --recursive --new-file v1.1.88/linux/drivers/block/aztcd.c linux/drivers/block/aztcd.c
--- v1.1.88/linux/drivers/block/aztcd.c	Wed Feb  1 09:23:05 1995
+++ linux/drivers/block/aztcd.c	Fri Feb  3 15:15:09 1995
@@ -1,11 +1,12 @@
-#define AZT_VERSION "V0.8"
-/*      $Id: aztcd.c,v 0.80 1995/01/21 19:54:53 root Exp $
+#define AZT_VERSION "V0.9"
+/*      $Id: aztcd.c,v 0.90 1995/02/02 18:14:17 root Exp $
 	linux/drivers/block/aztcd.c - AztechCD268 CDROM driver
 
 	Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
 
 	based on Mitsumi CDROM driver by  Martin Hariss and preworks by
-	Eberhard Moenkeberg.
+	Eberhard Moenkeberg; contains contributions by Joe Nardone and Robby 
+	Schirmer.
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
@@ -94,6 +95,10 @@
                 Modified the SET_TIMER and CLEAR_TIMER macros to comply with
                 the new timer scheme.
                 W.Zimmermann, Jan. 21, 1995
+        V0.90   Included CDROMVOLCTRL, but with my Aztech drive I can only turn
+                the channels on and off. If it works better with your drive, 
+                please mail me. Also implemented ACMD_CLOSE for CDROMSTART.
+                W.Zimmermann, Jan. 24, 1995
 	NOTE: 
 	Points marked with ??? are questionable !
 */
@@ -456,6 +461,7 @@
 	struct cdrom_tocentry entry;
 	struct azt_Toc *tocPtr;            
 	struct cdrom_subchnl subchnl;
+        struct cdrom_volctrl volctrl;
 
 #ifdef AZT_DEBUG
 	printk("aztcd: starting aztcd_ioctl - Command:%x\n",cmd);
@@ -468,11 +474,12 @@
 
 	switch (cmd)
 	{
-	case CDROMSTART:     /* Spin up the drive */
-		/* Don't think we can do this.  Even if we could,
-		 * I think the drive times out and stops after a while
-		 * anyway.  For now, ignore it.
-		 */
+	case CDROMSTART:     /* Spin up the drive. Don't know, what to do,
+	                        at least close the tray */
+#ifdef AZT_PRIVATE_IOCTLS 
+	        if (aztSendCmd(ACMD_CLOSE)) return -1;
+	        STEN_LOW_WAIT;
+#endif
 		break;
 	case CDROMSTOP:      /* Spin down the drive */
 		if (aztSendCmd(ACMD_STOP)) return -1;
@@ -481,8 +488,8 @@
 		aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 		break;
 	case CDROMPAUSE:     /* Pause the drive */
-/*              if (aztAudioStatus != CDROM_AUDIO_PLAY) return -EINVAL; 
-*/
+                if (aztAudioStatus != CDROM_AUDIO_PLAY) return -EINVAL; 
+
 		if (aztGetQChannelInfo(&qInfo) < 0)
 		{ /* didn't get q channel info */
 		  aztAudioStatus = CDROM_AUDIO_NO_STATUS;
@@ -629,13 +636,22 @@
 		  return -EINVAL;
 		memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
 		break;
-	case CDROMVOLCTRL:   /* Volume control */
-	/*
-	 * This is not working yet.  Setting the volume by itself does
-	 * nothing.  Following the 'set' by a 'play' results in zero
-	 * volume.  Something to work on for the next release.
-	 */
-		break;
+	case CDROMVOLCTRL:   /* Volume control 
+	 * With my Aztech CD268-01A volume control does not work, I can only
+	   turn the cannels on (any value !=0) or off (value==0). Maybe it
+           works better with your drive */
+                st=verify_area(VERIFY_READ,(void *) arg, sizeof(volctrl));
+                if (st) return (st);
+                memcpy_fromfs(&volctrl,(char *) arg,sizeof(volctrl));
+		azt_Play.start.min = 0x21;
+		azt_Play.start.sec = 0x84;
+		azt_Play.start.frame = volctrl.channel0;
+		azt_Play.end.min =     volctrl.channel1;
+		azt_Play.end.sec =     volctrl.channel2;
+		azt_Play.end.frame =   volctrl.channel3;
+                sendAztCmd(ACMD_SET_VOLUME, &azt_Play);
+                STEN_LOW_WAIT;
+                break;
 	case CDROMEJECT:
 	       /* all drives can at least stop! */
 		if (aztAudioStatus == CDROM_AUDIO_PLAY) 
diff -u --recursive --new-file v1.1.88/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.88/linux/drivers/block/floppy.c	Wed Feb  1 09:23:05 1995
+++ linux/drivers/block/floppy.c	Wed Feb  1 21:46:08 1995
@@ -135,6 +135,19 @@
 static unsigned int fake_change = 0;
 static int initialising=1;
 
+#define FLOPPY0_TYPE	((CMOS_READ(0x10) >> 4) & 15)
+#define FLOPPY1_TYPE	(CMOS_READ(0x10) & 15)
+
+/*
+ * Again, the CMOS information doesn't work on the alpha..
+ */
+#ifdef __alpha__
+#undef FLOPPY0_TYPE
+#undef FLOPPY1_TYPE
+#define FLOPPY0_TYPE 6
+#define FLOPPY1_TYPE 0
+#endif
+
 
 #ifdef CONFIG_FLOPPY_2_FDC
 #define N_FDC 2
@@ -551,7 +564,7 @@
 		}
 		/*USETF(FD_DISK_NEWCHANGE);*/
 		return 1;
-	} else if(jiffies >= DRS->select_date+DP->select_delay){
+	} else {
 		UDRS->last_checked=jiffies;
 		UCLEARF(FD_DISK_NEWCHANGE);
 	}
@@ -808,6 +821,36 @@
 	return 0;
 }
 
+static int hlt_disabled=0;
+static void floppy_disable_hlt(void)
+{
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	if(!hlt_disabled){
+		hlt_disabled=1;
+#ifdef HAVE_DISABLE_HLT
+		disable_hlt();
+#endif
+	}
+	restore_flags(flags);
+}
+
+static void floppy_enable_hlt(void)
+{
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	if(hlt_disabled){
+		hlt_disabled=0;
+#ifdef HAVE_DISABLE_HLT
+		enable_hlt();
+#endif
+	}
+	restore_flags(flags);
+}
+		
+
 static void setup_DMA(void)
 {
 #ifdef CONFIG_FLOPPY_SANITY
@@ -854,6 +897,7 @@
 	set_dma_count(FLOPPY_DMA, raw_cmd.length);
 	enable_dma(FLOPPY_DMA);
 	sti();
+	floppy_disable_hlt();
 }
 
 /* sends a command byte to the fdc */
@@ -1418,6 +1462,7 @@
 {
 	void (*handler)(void) = DEVICE_INTR;
 
+	floppy_enable_hlt();
 	CLEAR_INTR;
 	if ( fdc >= N_FDC || FDCS->address == -1){
 		/* we don't even know which FDC is the culprit */
@@ -1527,6 +1572,7 @@
 	floppy_tq.routine = (void *)(void *) empty;
 	del_timer( &fd_timer);
 
+	floppy_enable_hlt();
 	disable_dma(FLOPPY_DMA);
 	/* avoid dma going to a random drive after shutdown */
 
@@ -2877,10 +2923,10 @@
 		       sizeof( struct floppy_drive_params ));
 	}
 	printk("Floppy drive(s): ");
-	set_base_type(0, (CMOS_READ(0x10) >> 4) & 15);
-	if (CMOS_READ(0x10) & 15) {
+	set_base_type(0, FLOPPY0_TYPE);
+	if (FLOPPY1_TYPE) {
 		printk(", ");
-		set_base_type(1, CMOS_READ(0x10) & 15);
+		set_base_type(1, FLOPPY1_TYPE);
 	}
 	printk("\n");
 }
@@ -3157,7 +3203,6 @@
 	return FDC_82077;	/* Revised 82077AA passes all the tests */
 } /* get_fdc_version */
 
-#ifndef FD_MODULE
 /* lilo configuration */
 static void invert_dcl(int *ints)
 {
@@ -3198,6 +3243,8 @@
 void floppy_setup(char *str, int *ints)
 {
 	int i;
+	if(!str)
+		return;
 	for(i=0; i< ARRAY_SIZE(config_params); i++){
 		if (strcmp(str,config_params[i].name) == 0 ){
 			config_params[i].fn(ints);
@@ -3206,7 +3253,7 @@
 	}
 	printk("unknown floppy parameter %s\n", str);
 }
-#endif
+#define FLOPPY_SETUP
 
 #ifdef FD_MODULE
 static
@@ -3372,7 +3419,7 @@
 #if N_FDC > 1
 	set_dor(1, ~8, 0);
 #endif
-
+	floppy_enable_hlt();
 #ifdef CONFIG_FLOPPY_SANITY
 	for(drive=0; drive < N_FDC * 4; drive++)
 		if( motor_off_timer[drive].next )
diff -u --recursive --new-file v1.1.88/linux/drivers/block/mcd.c linux/drivers/block/mcd.c
--- v1.1.88/linux/drivers/block/mcd.c	Thu Jan 26 07:49:04 1995
+++ linux/drivers/block/mcd.c	Fri Feb  3 15:29:33 1995
@@ -248,9 +248,7 @@
 	struct cdrom_tocentry entry;
 	struct mcd_Toc *tocPtr;
 	struct cdrom_subchnl subchnl;
-#if 0
 	struct cdrom_volctrl volctrl;
-#endif
 
 	if (!ip)
 		return -EINVAL;
@@ -492,42 +490,30 @@
 		return 0;
 
 	case CDROMVOLCTRL:   /* Volume control */
-	/*
-	 * This is not working yet.  Setting the volume by itself does
-	 * nothing.  Following the 'set' by a 'play' results in zero
-	 * volume.  Something to work on for the next release.
-	 */
-#if 0
 		st = verify_area(VERIFY_READ, (void *) arg, sizeof(volctrl));
 		if (st)
 			return st;
 
 		memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
-printk("VOL %d %d\n", volctrl.channel0 & 0xFF, volctrl.channel1 & 0xFF);
 		outb(MCMD_SET_VOLUME, MCDPORT(0));
 		outb(volctrl.channel0, MCDPORT(0));
-		outb(0, MCDPORT(0));
+		outb(255, MCDPORT(0));
 		outb(volctrl.channel1, MCDPORT(0));
-		outb(1, MCDPORT(0));
+		outb(255, MCDPORT(0));
 
 		i = getMcdStatus(MCD_STATUS_DELAY);
 		if (i < 0)
 			return -EIO;
 
 		{
-			int a, b, c, d;
+			char a, b, c, d;
 
 			getValue(&a);
 			getValue(&b);
 			getValue(&c);
 			getValue(&d);
-			printk("%02X %02X %02X %02X\n", a, b, c, d);
 		}
 
-		outb(0xF8, MCDPORT(0));
-		i = getMcdStatus(MCD_STATUS_DELAY);
-		printk("F8 -> %02X\n", i & 0xFF);
-#endif
 		return 0;
 
 	case CDROMEJECT:
diff -u --recursive --new-file v1.1.88/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog
--- v1.1.88/linux/drivers/char/ChangeLog	Wed Feb  1 09:23:05 1995
+++ linux/drivers/char/ChangeLog	Wed Feb  1 09:19:36 1995
@@ -16,7 +16,7 @@
 		should happen before the receiver is shutdown; this is
 		done by reversing the values of close_wait and
 		close_wait2.  In the case of a very slow device, the
-		timeouts for close_wait or close_wait2 should be lengthed.
+		timeouts for close_wait or close_wait2 should be lengthened.
 		If either value is set to 0, the kernel will wait forever
 		for all of the data to be transmitted.  
 
diff -u --recursive --new-file v1.1.88/linux/drivers/char/console.c linux/drivers/char/console.c
--- v1.1.88/linux/drivers/char/console.c	Mon Jan 30 06:41:56 1995
+++ linux/drivers/char/console.c	Fri Feb  3 18:42:15 1995
@@ -346,6 +346,16 @@
 	}
 }
 
+static inline void memcpyw(unsigned short *to, unsigned short *from,
+			   unsigned int count)
+{
+	count /= 2;
+	while (count) {
+		count--;
+		writew(readw(from++), to++);
+	}
+}
+
 int vc_cons_allocated(unsigned int i)
 {
 	return (i < MAX_NR_CONSOLES && vc_cons[i].d);
@@ -452,7 +462,7 @@
 	      ol += (oll - ll) * osr;
 
 	    while (ol < scr_end) {
-		memcpy((void *) nl, (void *) ol, rlth);
+		memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
 		if (rrem)
 		  memsetw((void *)(nl + rlth), video_erase_char, rrem);
 		ol += osr;
@@ -2036,7 +2046,8 @@
 
 static void get_scrmem(int currcons)
 {
-	memcpy((void *)vc_scrbuf[currcons], (void *)origin, video_screen_size);
+	memcpyw((unsigned short *)vc_scrbuf[currcons],
+		(unsigned short *)origin, video_screen_size);
 	origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
 	scr_end = video_mem_end = video_mem_start + video_screen_size;
 	pos = origin + y*video_size_row + (x<<1);
@@ -2077,7 +2088,8 @@
 
 	if (video_mem_term - video_mem_base < offset + video_screen_size)
 	  offset = 0;	/* strange ... */
-	memcpy((void *)(video_mem_base + offset), (void *) origin, video_screen_size);
+	memcpyw((unsigned short *)(video_mem_base + offset),
+		(unsigned short *) origin, video_screen_size);
 	video_mem_start = video_mem_base;
 	video_mem_end = video_mem_term;
 	origin = video_mem_base + offset;
@@ -2235,13 +2247,13 @@
 				put_fs_byte(*sptr++,buf++);	
 			break;
 	    case 1:
-			put_fs_byte((char)x,buf++); put_fs_byte((char)y,buf++); 
-			memcpy_tofs(buf,(char *)origin,2*chcount);
+			put_fs_byte((char)x,buf++); put_fs_byte((char)y,buf++);
+/*XXX*/			memcpy_tofs(buf,(char *)origin,2*chcount);
 			break;
 	    case 2:
 			gotoxy(currcons, get_fs_byte(buf+2), get_fs_byte(buf+3));
 			buf+=4; /* ioctl#, console#, x,y */
-			memcpy_fromfs((char *)origin,buf,2*chcount);
+/*XXX*/			memcpy_fromfs((char *)origin,buf,2*chcount);
 			break;
 	    }
 	return(0);
diff -u --recursive --new-file v1.1.88/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v1.1.88/linux/drivers/char/cyclades.c	Thu Jan 26 07:49:04 1995
+++ linux/drivers/char/cyclades.c	Wed Feb  1 21:46:08 1995
@@ -2501,6 +2501,7 @@
 	    panic("Couldn't register Cyclom callout driver\n");
 
     bh_base[CYCLADES_BH].routine = do_cyclades_bh;
+    enable_bh(CYCLADES_BH);
 
     for (index = 0; index < 16; index++) {
 	    IRQ_cards[index] = 0;
diff -u --recursive --new-file v1.1.88/linux/drivers/char/kbd_kern.h linux/drivers/char/kbd_kern.h
--- v1.1.88/linux/drivers/char/kbd_kern.h	Tue Dec 27 09:54:44 1994
+++ linux/drivers/char/kbd_kern.h	Wed Feb  1 21:46:08 1995
@@ -66,10 +66,7 @@
 
 extern inline void set_leds(void)
 {
-       /* con_init calls (indirectly) set_leds before kbd_init
-          has been called; ignore these early calls */
-       if (bh_base[KEYBOARD_BH].routine)
-               mark_bh(KEYBOARD_BH);
+	mark_bh(KEYBOARD_BH);
 }
 
 extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
diff -u --recursive --new-file v1.1.88/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v1.1.88/linux/drivers/char/keyboard.c	Wed Feb  1 09:23:05 1995
+++ linux/drivers/char/keyboard.c	Wed Feb  1 21:46:08 1995
@@ -614,22 +614,8 @@
 
 static void show_ptregs(void)
 {
-#ifdef __i386__
-	if (!pt_regs)
-		return;
-	printk("\n");
-	printk("EIP: %04x:%08lx",0xffff & pt_regs->cs,pt_regs->eip);
-	if (pt_regs->cs & 3)
-		printk(" ESP: %04x:%08lx",0xffff & pt_regs->ss,pt_regs->esp);
-	printk(" EFLAGS: %08lx\n",pt_regs->eflags);
-	printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
-		pt_regs->orig_eax,pt_regs->ebx,pt_regs->ecx,pt_regs->edx);
-	printk("ESI: %08lx EDI: %08lx EBP: %08lx",
-		pt_regs->esi, pt_regs->edi, pt_regs->ebp);
-	printk(" DS: %04x ES: %04x FS: %04x GS: %04x\n",
-		0xffff & pt_regs->ds,0xffff & pt_regs->es,
-		0xffff & pt_regs->fs,0xffff & pt_regs->gs);
-#endif
+	if (pt_regs)
+		show_regs(pt_regs);
 }
 
 static void hold(void)
@@ -1037,7 +1023,7 @@
 		resend = 0;
 		reply_expected = 1;
 		outb_p(data, 0x60);
-		for(i=0; i<0x20000; i++) {
+		for(i=0; i<0x200000; i++) {
 			inb_p(0x64);		/* just as a delay */
 			if (acknowledge)
 				return 1;
@@ -1185,9 +1171,10 @@
 	outb(0x1,0x60);
 	while (inb(0x64) & 2)
 		/* nothing */;
-	send_data(0xf0);	/* Select scan code */
-	send_data(0x01);	/* type 1 */
-#endif		
+	if (!send_data(0xf0) || !send_data(0x01))
+		printk("Scanmode 1 change failed\n");
+#endif
 	mark_bh(KEYBOARD_BH);
+	enable_bh(KEYBOARD_BH);
 	return kmem_start;
 }
diff -u --recursive --new-file v1.1.88/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.1.88/linux/drivers/char/serial.c	Wed Feb  1 09:23:05 1995
+++ linux/drivers/char/serial.c	Wed Feb  1 21:46:08 1995
@@ -2425,6 +2425,7 @@
 	struct async_struct * info;
 	
 	bh_base[SERIAL_BH].routine = do_serial_bh;
+	enable_bh(SERIAL_BH);
 	timer_table[RS_TIMER].fn = rs_timer;
 	timer_table[RS_TIMER].expires = 0;
 #ifdef CONFIG_AUTO_IRQ
diff -u --recursive --new-file v1.1.88/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.1.88/linux/drivers/char/tty_io.c	Sun Jan 22 21:39:40 1995
+++ linux/drivers/char/tty_io.c	Wed Feb  1 08:41:02 1995
@@ -1443,8 +1443,9 @@
 			arg = get_fs_long((unsigned long *) arg);
 			return tty_set_ldisc(tty, arg);
 		case TIOCLINUX:
-			if ((current->tty != tty || 
-			     tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) && !suser())
+			if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
+				return -EINVAL;
+			if (current->tty != tty && !suser())
 				return -EPERM;
 			retval = verify_area(VERIFY_READ, (void *) arg, 1);
 			if (retval)
diff -u --recursive --new-file v1.1.88/linux/drivers/net/README.wavelan linux/drivers/net/README.wavelan
--- v1.1.88/linux/drivers/net/README.wavelan	Wed Feb  1 09:23:05 1995
+++ linux/drivers/net/README.wavelan	Wed Feb  1 09:19:36 1995
@@ -38,7 +38,7 @@
    are unique to this package and simply may be moved into place.  The
    others are modified versions of pre-existing files and must
    be incorporated more carefully.  However, the regions of modified code
-   within these files are small and are bracketted by the preprocessor
+   within these files are small and are bracketed by the preprocessor
    symbol CONFIG_WAVELAN, so incorporation should be straightforward.
 
 4. If you encounter any problems send me some email.
diff -u --recursive --new-file v1.1.88/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v1.1.88/linux/drivers/net/ni52.c	Mon Jan 16 14:18:21 1995
+++ linux/drivers/net/ni52.c	Fri Feb  3 15:19:27 1995
@@ -4,14 +4,21 @@
  * This is an extension to the Linux operating system, and is covered by the
  * same Gnu Public License that covers that work.
  * 
- * Alphacode 0.51 (94/08/19) for Linux 1.1.47 (or later)
- * Copyrights (c) 1994 by Michael Hipp (mhipp@student.uni-tuebingen.de)
+ * Alphacode 0.62 (95/01/19) for Linux 1.1.82 (or later)
+ * Copyrights (c) 1994,1995 by M.Hipp (Michael.Hipp@student.uni-tuebingen.de)
  *    [feel free to mail ....]
  *
  * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
+ * 
+ * If you find a bug, please report me:
+ *   The kernelpanic output and any kmsg from the ni52 driver
+ *   the ni5210-driver-version and the linux-kernel version 
+ *   how many shared memory (memsize) on the netcard, 
+ *   bootprom: yes/no, base_addr, mem_start
+ *   maybe the ni5210-card revision and the i82586 version
  *
  * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340
- *                mem_start: 0xd0000,0xd4000,0xd8000 (8K and 16K)
+ *                mem_start: 0xc8000,0xd0000,0xd4000,0xd8000 (8K and 16K)
  *
  * sources:
  *   skeleton.c from Donald Becker
@@ -19,16 +26,40 @@
  * I have also done a look in the following sources: (mail me if you need them)
  *   crynwr-packet-driver by Russ Nelson
  *   Garret A. Wollman's (fourth) i82586-driver for BSD
- *   (before getting an i82596 manual, the existing drivers helped
+ *   (before getting an i82596 (yes 596 not 586) manual, the existing drivers helped
  *    me a lot to understand this tricky chip.)
  *
- * Known Bugs:
+ * Known Problems:
  *   The internal sysbus seems to be slow. So we often lose packets because of
  *   overruns while receiving from a fast remote host. 
  *   This can slow down TCP connections. Maybe the newer ni5210 cards are better.
+ * 
+ * IMPORTANT NOTE:
+ *   On fast networks, it's a (very) good idea to have 16K shared memory. With
+ *   8K, we can store only 4 receive frames, so it can (easily) happen that a remote 
+ *   machine 'overruns' our system.
+ *
+ * Known i82586 bugs (I'm sure, there are many more!):
+ *   Running the NOP-mode, the i82586 sometimes seems to forget to report
+ *   every xmit-interrupt until we restart the CU.
+ *   Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit 
+ *   in the RBD-Struct which indicates an end of the RBD queue. 
+ *   Instead, the RU fetches another (randomly selected and 
+ *   usually used) RBD and begins to fill it. (Maybe, this happens only if 
+ *   the last buffer from the previous RFD fits exact into the queue and
+ *   the next RFD can't fetch an initial RBD. Anyone knows more? )
  */
 
 /*
+ * 19.Jan.95: verified (MH)
+ *
+ * 19.Sep.94: Added Multicast support (not tested yet) (MH)
+ * 
+ * 18.Sep.94: Workarround for 'EL-Bug'. Removed flexible RBD-handling. 
+ *            Now, every RFD has exact one RBD. (MH)
+ *
+ * 14.Sep.94: added promiscous mode, a few cleanups (MH)
+ *
  * 19.Aug.94: changed request_irq() parameter (MH)
  * 
  * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH)
@@ -42,12 +73,13 @@
  * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH)
  *
  * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff, too (MH)
+ *
+ * < 30.Sep.93: first versions 
  */
  
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/malloc.h>
@@ -62,15 +94,8 @@
 
 #include "ni52.h"
 
-#define DEBUG   /* debug on */
-
-/*
-#define DEBUG1
-#define DEBUG2
-#define DEBUG3
-*/
-
-#define SYSBUSVAL 1
+#define DEBUG       /* debug on */
+#define SYSBUSVAL 1 /* 8 Bit */
 
 #define ni_attn586()  {outb(0,dev->base_addr+NI52_ATTENTION);}
 #define ni_reset586() {outb(0,dev->base_addr+NI52_RESET);}
@@ -79,12 +104,11 @@
 #define make24(ptr32) ((char *) (ptr32) - p->base)
 #define make16(ptr32) ((unsigned short) ((unsigned long) (ptr32) - (unsigned long) p->memtop ))
 
-/******************* how to calc the buffers *****************************
-
-IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, do also a 
----------------   #define ONLY_ONE_XMIT_BUF
-                btw: it seems, that only the ONLY_ONE_XMIT_BUF Mode is stable
+/******************* how to calculate the buffers *****************************
 
+  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+  * --------------- in a different (more stable?) mode. Only in this mode it's
+  *                 possbile to configure the driver with 'NO_NOPCOMMANDS'
 
 sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
 sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
@@ -92,81 +116,16 @@
 sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
 sizeof(nop_cmd) = 8; 
 
-examples:
----------
+  * if you don't know the driver, better do not change this values: */
 
-->cfg1: NUM_RECV_FRAMES=16, NUM_RECV_BUFFS=48, RECV_BUFF_SIZE=256, 
-        NUM_XMIT_BUFFS=2 ,XMIT_BUFF_SIZE=1514
+#define RECV_BUFF_SIZE 1524 /* slightly oversized */
+#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
+#define NUM_XMIT_BUFFS 1    /* config for both, 8K and 16K shmem */
+#define NUM_RECV_BUFFS_8  4 /* config for 8K shared mem */
+#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
+#define NO_NOPCOMMANDS      /* only possible with NUM_XMIT_BUFFS=1 */
 
-NUM_RECV_FRAMES * sizeof(rfd) = 384;
-NUM_RECV_BUFFS * ( sizeof(rbd) + RECV_BUFF_SIZE) = 12864
-NUM_XMIT_BUFFS * ( sizeof(tbd+transmit_cmd+nop_cmd) + XMIT_BUFF_SIZE) = 3092
-INIT = 36
---------------------
-16358   (36 bytes left!)
-
-************************
-
-->cfg2: NUM_RECV_FRAMES=9, NUM_RECV_BUFFS=18, RECV_BUFF_SIZE=256, 
-        NUM_XMIT_BUFFS=2 ,XMIT_BUFF_SIZE=1514
-
-NUM_RECV_FRAMES * sizeof(rfd) = 216
-NUM_RECV_BUFFS * ( sizeof(rbd) + RECV_BUFF_SIZE) = 4824
-NUM_XMIT_BUFFS * ( sizeof(tbd+transmit_cmd+nop_cmd) + XMIT_BUFF_SIZE) = 3092
-INIT = 36
-------------------
-8180    (24 bytes left!)
-
-->cfg3: NUM_RECV_FRAMES=7, NUM_RECV_BUFFS=24, RECV_BUFF_SIZE=256, 
-        NUM_XMIT_BUFFS=1, XMIT_BUFF_SIZE=1514
-        168  +  6432  +  1538  +  36  +  16 = 8190 
-
-***************************************************************************/
-
-#if 0
-/* config-1 for 16Kram card */
-#  define NUM_RECV_FRAMES 16	/* number of frames to allow for receive */
-#  define NUM_RECV_BUFFS 48	/* number of buffers to allocate */
-#  define RECV_BUFF_SIZE 256	/* size of each buffer, POWER OF 2 & EVEN*/
-#  define XMIT_BUFF_SIZE 1514	/* length of transmit buffer (EVEN) */
-#  define NUM_XMIT_BUFFS 2	/* number of Xmit-Buffs */
-#elif 0
-/* config-2 for 8Kram card */
-#  define NUM_RECV_FRAMES 9
-#  define NUM_RECV_BUFFS 18
-#  define RECV_BUFF_SIZE 256
-#  define XMIT_BUFF_SIZE 1514
-#  define NUM_XMIT_BUFFS 2
-#elif 1
-/*
- * config-3 for 8Kram card  ___use_this_config____ seems to be stable
- */
-#  define NUM_RECV_FRAMES 7
-#  define NUM_RECV_BUFFS 24
-#  define RECV_BUFF_SIZE 256
-#  define XMIT_BUFF_SIZE 1514
-#  define NUM_XMIT_BUFFS 1
-#  define ONLY_ONE_XMIT_BUF 
-#  define NO_NOPCOMMANDS
-#elif 0
-/*
- * cfg-4 for 16K, ONLY_ONE_XMIT_BUF
- */
-#  define NUM_RECV_FRAMES 20
-#  define NUM_RECV_BUFFS 27
-#  define RECV_BUFF_SIZE 512
-#  define XMIT_BUFF_SIZE 1514
-#  define NUM_XMIT_BUFFS 1
-#  define ONLY_ONE_XMIT_BUF
-#else
-#  define NUM_RECV_FRAMES 4
-#  define NUM_RECV_BUFFS 4
-#  define RECV_BUFF_SIZE 1536
-#  define XMIT_BUFF_SIZE 1536
-#  define NUM_XMIT_BUFFS 1
-#  define ONLY_ONE_XMIT_BUF
-#  define NO_NOPCOMMANDS
-#endif
+/**************************************************************************/
 
 #define DELAY(x) {int i=jiffies; \
                   if(loops_per_sec == 1) \
@@ -175,30 +134,42 @@
                      __delay((loops_per_sec>>5)*x); \
                  }
 
+/* a much shorter delay: */
+#define DELAY_16(); { __delay( (loops_per_sec>>16)+1 ); }
+
+/* wait for command with timeout: */
+#define WAIT_4_SCB_CMD() { int i; \
+  for(i=0;i<1024;i++) { \
+    if(!p->scb->cmd) break; \
+    DELAY_16(); \
+    if(i == 1023) { \
+      printk("%s: scb_cmd timed out .. resetting i82586\n",dev->name); \
+      ni_reset586(); } } }
+
 extern void autoirq_setup(int waittime);
-extern int autoirq_report(int waittime);
+extern int  autoirq_report(int waittime);
 extern void *irq2dev_map[16];
 
-#ifndef HAVE_PORTRESERVE
-#define check_region(ioaddr, size) 		0
-#define	request_region(ioaddr, size,name)	do ; while (0)
-#endif
-
 #define NI52_TOTAL_SIZE 16
 #define NI52_ADDR0 0x02
 #define NI52_ADDR1 0x07
 #define NI52_ADDR2 0x01
 
+#ifndef HAVE_PORTRESERVE
+#define check_region(ioaddr, size)              0
+#define request_region(ioaddr, size,name)    do ; while (0)
+#endif
+
 static int     ni52_probe1(struct device *dev,int ioaddr);
-static void    ni52_interrupt(int irq, struct pt_regs *regs);
+static void    ni52_interrupt(int irq,struct pt_regs *reg_ptr);
 static int     ni52_open(struct device *dev);
 static int     ni52_close(struct device *dev);
 static int     ni52_send_packet(struct sk_buff *,struct device *);
-static struct enet_statistics *ni52_get_stats(struct device *dev);
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+static struct  enet_statistics *ni52_get_stats(struct device *dev);
+static void    set_multicast_list(struct device *dev, int num_addrs, void *addrs);
 
 /* helper-functions */
-static int     init586(struct device *dev);
+static int     init586(struct device *dev,int num_addrs,void *addrs);
 static int     check586(struct device *dev,char *where,unsigned size);
 static void    alloc586(struct device *dev);
 static void    startrecv586(struct device *dev);
@@ -211,20 +182,19 @@
 {
   struct enet_statistics stats;
   unsigned long base;
-  char *memtop,*max_cbuff32,*min_cbuff32,*max_cbuff24;
-  volatile struct rbd_struct  *rbd_last;
+  char *memtop;
   volatile struct rfd_struct  *rfd_last,*rfd_top,*rfd_first;
   volatile struct scp_struct  *scp;  /* volatile is important */
   volatile struct iscp_struct *iscp; /* volatile is important */
   volatile struct scb_struct  *scb;  /* volatile is important */
   volatile struct tbd_struct  *xmit_buffs[NUM_XMIT_BUFFS];
   volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
-#ifdef ONLY_ONE_XMIT_BUF
+#if (NUM_XMIT_BUFFS == 1)
   volatile struct nop_cmd_struct *nop_cmds[2];
 #else
   volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
 #endif
-  volatile int    nop_point;
+  volatile int    nop_point,num_recv_buffs;
   volatile char  *xmit_cbuffs[NUM_XMIT_BUFFS];
   volatile int    xmit_count,xmit_last;
 };
@@ -254,7 +224,7 @@
 static int ni52_open(struct device *dev)
 {
   alloc586(dev);
-  init586(dev);  
+  init586(dev,0,NULL);  
   startrecv586(dev);
 
   if(request_irq(dev->irq, &ni52_interrupt,0,"ni52")) 
@@ -285,7 +255,7 @@
   p->memtop = where + size;
   p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
   memset((char *)p->scp,0, sizeof(struct scp_struct));
-  p->scp->sysbus = SYSBUSVAL;        /* 1 = 8Bit-Bus */
+  p->scp->sysbus = SYSBUSVAL;        /* 1 = 8Bit-Bus, 0 = 16 Bit */
   
   iscp_addrs[0] = where;
   iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct);
@@ -302,7 +272,7 @@
     ni_attn586();
     DELAY(2);	/* wait a while... */
 
-    if(p->iscp->busy)
+    if(p->iscp->busy) /* i82586 clears 'busy' after succesful init */
       return 0;
   }
   return 1;
@@ -316,6 +286,9 @@
 {
   struct priv *p =  (struct priv *) dev->priv; 
 
+  ni_reset586();
+  DELAY(2);
+
   p->scp  = (struct scp_struct *)  (p->base + SCP_DEFAULT_ADDRESS);
   p->scb  = (struct scb_struct *)  (dev->mem_start);
   p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct));
@@ -331,12 +304,10 @@
   ni_reset586();
   ni_attn586();
 
-#ifdef DEBUG
   DELAY(2); 
 
   if(p->iscp->busy)
     printk("%s: Init-Problems (alloc).\n",dev->name);
-#endif
 
   memset((char *)p->scb,0,sizeof(struct scb_struct));
 }
@@ -376,7 +347,7 @@
 
 static int ni52_probe1(struct device *dev,int ioaddr)
 {
-  long memaddrs[] = { 0xd0000,0xd2000,0xd4000,0xd6000,0xd8000, 0 };
+  long memaddrs[] = { 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,0xd8000, 0 };
   int i,size;
 
   for(i=0;i<ETH_ALEN;i++)
@@ -399,9 +370,9 @@
    */
   if(dev->mem_start != 0) /* no auto-mem-probe */
   {
-    size = 0x4000;
+    size = 0x4000; /* check for 16K mem */
     if(!check586(dev,(char *) dev->mem_start,size)) {
-      size = 0x2000;
+      size = 0x2000; /* check for 8K mem */
       if(!check586(dev,(char *) dev->mem_start,size)) {
         printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start);
         return ENODEV;
@@ -417,18 +388,25 @@
         return ENODEV;
       }
       dev->mem_start = memaddrs[i];
-      size = 0x2000;
+      size = 0x2000; /* check for 8K mem */
       if(check586(dev,(char *)dev->mem_start,size)) /* 8K-check */
         break;
-      size = 0x4000;
+      size = 0x4000; /* check for 16K mem */
       if(check586(dev,(char *)dev->mem_start,size)) /* 16K-check */
         break;
     }
   }
-
+  dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */
+  
   ((struct priv *) (dev->priv))->base =  dev->mem_start + size - 0x01000000;
   alloc586(dev);
 
+  /* set number of receive-buffs according to memsize */
+  if(size == 0x2000)
+    ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8;
+  else
+    ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16;
+
   printk("Memaddr: 0x%lx, Memsize: %d, ",dev->mem_start,size);
 
   if(dev->irq < 2)
@@ -469,7 +447,7 @@
  * needs a correct 'allocated' memory
  */
 
-static int init586(struct device *dev)
+static int init586(struct device *dev,int num_addrs,void *addrs)
 {
   void *ptr;
   unsigned long s;
@@ -478,19 +456,26 @@
   volatile struct configure_cmd_struct  *cfg_cmd;
   volatile struct iasetup_cmd_struct *ias_cmd;
   volatile struct tdr_cmd_struct *tdr_cmd;
+  volatile struct mcsetup_cmd_struct *mc_cmd;
 
   ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
 
   cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
- 
-  cfg_cmd->byte_cnt     = 0x04; /* number of cfg bytes */
-  cfg_cmd->fifo         = 0xc8;    /* fifo-limit (8=tx:32/rx:64) | monitor */
-  cfg_cmd->sav_bf       = 0x40; /* hold or discard bad recv frames (bit 7) */
-  cfg_cmd->adr_len      = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
-  cfg_cmd->cmd_status   = 0;
-  cfg_cmd->cmd_cmd      = CMD_CONFIGURE | CMD_LAST;
-  cfg_cmd->cmd_link     = 0xffff;
+  cfg_cmd->cmd_status = 0;
+  cfg_cmd->cmd_cmd    = CMD_CONFIGURE | CMD_LAST;
+  cfg_cmd->cmd_link   = 0xffff;
 
+  cfg_cmd->byte_cnt   = 0x0a; /* number of cfg bytes */
+  cfg_cmd->fifo       = 0x08; /* fifo-limit (8=tx:32/rx:64) */
+  cfg_cmd->sav_bf     = 0x40; /* hold or discard bad recv frames (bit 7) */
+  cfg_cmd->adr_len    = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
+  cfg_cmd->priority   = 0x00;
+  cfg_cmd->ifs        = 0x60;
+  cfg_cmd->time_low   = 0x00;
+  cfg_cmd->time_high  = 0xf2;
+  cfg_cmd->promisc    = (num_addrs < 0) ? 1 : 0;  /* promisc on/off */
+  cfg_cmd->carr_coll  = 0x00;
+ 
   p->scb->cbl_offset = make16(cfg_cmd);
 
   p->scb->cmd = CUC_START; /* cmd.-unit start */
@@ -584,41 +569,78 @@
    /*
     * alloc nop/xmit-cmds
     */
-#ifdef ONLY_ONE_XMIT_BUF
+#if (NUM_XMIT_BUFFS == 1)
   for(i=0;i<2;i++)
   {
     p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
-    p->nop_cmds[i]->cmd_cmd    = 0;
+    p->nop_cmds[i]->cmd_cmd    = CMD_NOP;
     p->nop_cmds[i]->cmd_status = 0;
     p->nop_cmds[i]->cmd_link   = make16((p->nop_cmds[i]));
-    ptr += sizeof(struct nop_cmd_struct);
+    ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
   }
   p->xmit_cmds[0] = (struct transmit_cmd_struct *)ptr; /* transmit cmd/buff 0 */
-  ptr += sizeof(struct transmit_cmd_struct);
+  ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
 #else
   for(i=0;i<NUM_XMIT_BUFFS;i++)
   {
     p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
-    p->nop_cmds[i]->cmd_cmd    = 0;
+    p->nop_cmds[i]->cmd_cmd    = CMD_NOP;
     p->nop_cmds[i]->cmd_status = 0;
     p->nop_cmds[i]->cmd_link   = make16((p->nop_cmds[i]));
-    ptr += sizeof(struct nop_cmd_struct);
-    p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /* transmit cmd/buff 0 */
-    ptr += sizeof(struct transmit_cmd_struct);
+    ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+    p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
+    ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
   }
 #endif
 
   ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */ 
 
-   /*
-    * alloc xmit-buffs 
-    */
+  /* 
+   * Multicast setup
+   */
+  
+  if(num_addrs > 0)
+  { /* I don't understand this: do we really need memory after the init? */
+    int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+    if(len <= 0)
+    {
+      printk("%s: Ooooops, no memory for MC-Setup!\n",dev->name);
+    }
+    else
+    {
+      if(len < num_addrs)
+      {
+        num_addrs = len;
+        printk("%s: Sorry, can only apply %d MC-Addresse(s).\n",dev->name,num_addrs);
+      }
+      mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+      mc_cmd->cmd_status = 0;
+      mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST;
+      mc_cmd->cmd_link = 0xffff;
+      mc_cmd->mc_cnt = num_addrs * 6;
+      for(i=0;i<num_addrs;i++)
+        memcpy((char *) mc_cmd->mc_list[i],((char (*)[6]) addrs)[i],6);
+      p->scb->cbl_offset = make16(mc_cmd);
+      p->scb->cmd = CUC_START;
+      ni_attn586();
+      s = jiffies;
+      while(!(mc_cmd->cmd_status & STAT_COMPL))
+        if(jiffies - s > 30)
+          break;
+      if(!(mc_cmd->cmd_status & STAT_COMPL))
+        printk("%s: Can't apply multicast-address-list.\n",dev->name);
+    }
+  }
+
+  /*
+   * alloc xmit-buffs / init xmit_cmds
+   */
   for(i=0;i<NUM_XMIT_BUFFS;i++)
   {
     p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
-    ptr += XMIT_BUFF_SIZE;
+    ptr = (char *) ptr + XMIT_BUFF_SIZE;
     p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
-    ptr += sizeof(struct tbd_struct);
+    ptr = (char *) ptr + sizeof(struct tbd_struct);
     if((void *)ptr > (void *)p->iscp) 
     {
       printk("%s: not enough shared-mem for your configuration!\n",dev->name);
@@ -627,11 +649,12 @@
     memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
     memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
     p->xmit_cmds[i]->cmd_status = STAT_COMPL;
+    p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT;
     p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
     p->xmit_buffs[i]->next = 0xffff;
     p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
   }
-  
+
   p->xmit_count = 0; 
   p->xmit_last  = 0;
 #ifndef NO_NOPCOMMANDS
@@ -645,12 +668,8 @@
   p->scb->cbl_offset = make16(p->nop_cmds[0]);
   p->scb->cmd = CUC_START;
   ni_attn586();
-  while(p->scb->cmd);
+  WAIT_4_SCB_CMD();
 #else
-/*
-  p->nop_cmds[0]->cmd_link = make16(p->nop_cmds[1]);
-  p->nop_cmds[1]->cmd_link = make16(p->xmit_cmds[0]);
-*/
   p->xmit_cmds[0]->cmd_link = 0xffff;
   p->xmit_cmds[0]->cmd_cmd  = CMD_XMIT | CMD_LAST | CMD_INT;
 #endif
@@ -659,7 +678,7 @@
 }
 
 /******************************************************
- * This is a helper routine for ni52_nr_int() and init586(). 
+ * This is a helper routine for ni52_rnr_int() and init586(). 
  * It sets up the Receive Frame Area (RFA).
  */
 
@@ -670,38 +689,32 @@
   int i;
   struct priv *p = (struct priv *) dev->priv;
 
-  memset((char *) rfd,0,sizeof(struct rfd_struct)*NUM_RECV_FRAMES);
+  memset((char *) rfd,0,sizeof(struct rfd_struct)*p->num_recv_buffs);
   p->rfd_first = rfd;
 
-  for(i = 0; i < NUM_RECV_FRAMES; i++)
-    rfd[i].next = make16(rfd + (i+1) % NUM_RECV_FRAMES);
-  rfd[NUM_RECV_FRAMES-1].last = RFD_LAST; /* set EOL (no RU suspend) */
+  for(i = 0; i < p->num_recv_buffs; i++)
+    rfd[i].next = make16(rfd + (i+1) % p->num_recv_buffs);
+  rfd[p->num_recv_buffs-1].last = RFD_SUSP;   /* RU suspend */
 
-  ptr = (char *) (rfd + NUM_RECV_FRAMES);
+  ptr = (void *) (rfd + p->num_recv_buffs);
 
   rbd = (struct rbd_struct *) ptr;
-  ptr += sizeof(struct rbd_struct)*NUM_RECV_BUFFS;
+  ptr = (void *) (rbd + p->num_recv_buffs);
 
    /* clr descriptors */
-  memset((char *) rbd,0,sizeof(struct rbd_struct)*NUM_RECV_BUFFS);
+  memset((char *) rbd,0,sizeof(struct rbd_struct)*p->num_recv_buffs);
 
-  p->min_cbuff32 = ptr;
-  for(i=0;i<NUM_RECV_BUFFS;i++)
+  for(i=0;i<p->num_recv_buffs;i++)
   {
-    rbd[i].next = make16((rbd + (i+1) % NUM_RECV_BUFFS));
+    rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
     rbd[i].size = RECV_BUFF_SIZE;
     rbd[i].buffer = make24(ptr);
-    ptr += RECV_BUFF_SIZE;
+    ptr = (char *) ptr + RECV_BUFF_SIZE;
   }
-  rbd[NUM_RECV_BUFFS-1].size |= RBD_LAST; /* set eol */
-  p->max_cbuff32 = ptr;
-  p->max_cbuff24 = make24(p->max_cbuff32);
- 
+
   p->rfd_top  = p->rfd_first;
-  p->rfd_last = p->rfd_first + NUM_RECV_FRAMES - 1;
+  p->rfd_last = p->rfd_first + p->num_recv_buffs - 1;
 
-  p->rbd_last = rbd + NUM_RECV_BUFFS - 1;
- 
   p->scb->rfa_offset		= make16(p->rfd_first);
   p->rfd_first->rbd_offset	= make16(rbd);
 
@@ -713,29 +726,18 @@
  * Interrupt Handler ...
  */
 
-static void ni52_interrupt(int irq, struct pt_regs *regs)
+static void ni52_interrupt(int irq,struct pt_regs *reg_ptr)
 {
   struct device *dev = (struct device *) irq2dev_map[irq];
   unsigned short stat;
-  int pd = 0;
   struct priv *p;
 
-#ifdef DEBUG2
-  printk("(1)");
-#endif
-
   if (dev == NULL) {
-    printk ("ni52-interrupt: irq %d for unknown device.\n", irq);
+    printk ("ni52-interrupt: irq %d for unknown device.\n",(int) -(((struct pt_regs *)reg_ptr)->orig_eax+2));
     return;
   }
   p = (struct priv *) dev->priv;
 
-  if(dev->interrupt)
-  {
-    printk("(ni52-I)");
-    return;
-  }
-
   dev->interrupt = 1;
 
   while((stat=p->scb->status & STAT_MASK))
@@ -743,57 +745,38 @@
     p->scb->cmd = stat;
     ni_attn586(); /* ack inter. */
 
-    if(pd) 
-      printk("ni52-%04x/%04x-",(int) stat,(int) p->scb->status); /* debug */
+   if(stat & STAT_CX)    /* command with I-bit set complete */
+      ni52_xmt_int(dev);
 
-    if(stat & (STAT_FR | STAT_RNR)) 
+    if(stat & STAT_FR)   /* received a frame */
       ni52_rcv_int(dev);
 
-    if(stat & STAT_CX) 
-      ni52_xmt_int(dev);
-
 #ifndef NO_NOPCOMMANDS
-    if(stat & STAT_CNA)
-#else
-    if( (stat & STAT_CNA) && !(stat & STAT_CX) )
-#endif
-      printk("%s: oops! CU has left active state. stat: %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status);
-
-    if(stat & STAT_RNR)
+    if(stat & STAT_CNA)  /* CU went 'not ready' */
     {
-      printk("%s: rnr: %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status);
-      ni52_rnr_int(dev); 
-      pd = 1; /* local debug on */
+      if(dev->start)
+        printk("%s: oops! CU has left active state. stat: %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status);
     }
-
-#ifdef DEBUG2
-    pd++;
 #endif
 
-    while(p->scb->cmd)
-    {
-      int i; /* wait for ack. (ni52_xmt_int can be faster than ack!!) */
-      for(i=0;i<200;i++);
-    }
-  }
-
-#ifdef DEBUG
-  {
-    static int old_ovr=0;
-    int l;
-    if((l = p->scb->ovrn_errs - old_ovr))
+    if(stat & STAT_RNR) /* RU went 'not ready' */
     {
-      if(l > 0)
-        p->stats.rx_over_errors += l;
+      if(p->scb->status & RU_SUSPEND) /* special case: RU_SUSPEND */
+      {
+        WAIT_4_SCB_CMD();
+        p->scb->cmd = RUC_RESUME;
+        ni_attn586();
+      }
       else
-        old_ovr=0;
+      {
+        printk("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status);
+        ni52_rnr_int(dev); 
+      }
     }
+    WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */
+    if(p->scb->cmd)   /* timed out? */
+      break;
   }
-#endif
-
-#ifdef DEBUG2
-  printk("(2)");
-#endif
 
   dev->interrupt = 0;
 }
@@ -805,92 +788,37 @@
 static void ni52_rcv_int(struct device *dev)
 {
   int status;
-  unsigned short totlen,pnt;
+  unsigned short totlen;
   struct sk_buff *skb;
-  struct rbd_struct *rbd,*rbd_first;
+  struct rbd_struct *rbd;
   struct priv *p = (struct priv *) dev->priv;
 
   for(;(status = p->rfd_top->status) & STAT_COMPL;)
   {
-      rbd = rbd_first = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+      rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
 
-#ifdef DEBUG1
-      {
-        struct rbd_struct *rbd1 = rbd;
-        if(rbd1==p->rbd_last)
-          printk("L");
-        printk("S:%04x/%x/%02x >",(int) rbd1->status,(int) rbd1->size>>12,(int)((unsigned long) rbd1 & 0xff));
-        rbd1 = (struct rbd_struct *) make32(rbd1->next);
-        for(;rbd1 != rbd_first;rbd1 = (struct rbd_struct *)  make32(rbd1->next))
-        {
-          if(rbd1 == p->rbd_last)
-            printk("L:");
-          printk("%04x/%x-",(int) rbd1->status>>12,(int) rbd1->size>>12);
-        }
-        printk("< ");
-      }
+      if(status & STAT_OK) /* frame received without error? */
       {
-        struct rfd_struct *rfd1 = p->rfd_top;
-        if(rfd1==p->rfd_last)
-          printk("L");
-        printk("S:%04x/%x/%02x >",(int) rfd1->status,(int) rfd1->last>>12,(int)((unsigned long) rfd1 & 0xff));
-        rfd1 = (struct rfd_struct *) make32(rfd1->next);
-        for(;rfd1 != p->rfd_top;rfd1 = (struct rfd_struct *)  make32(rfd1->next))
+        if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */
         {
-          if(rfd1 == p->rfd_last)
-            printk("L:");
-          printk("%x/%x-",(int) rfd1->status>>12,(int) rfd1->last>>12);
-        }
-        printk("<\n");
-      }
-#endif
-
-      p->rfd_top->status = 0;
-      p->rfd_top->last = RFD_LAST;
-      p->rfd_last->last = 0;        /* delete RFD_LAST, no RU suspend */
-      p->rfd_last = p->rfd_top;
-      p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next);
-
-      if(status & RFD_ERRMASK)
-        printk("%s: RFD-Error ... status: %04x.\n",dev->name,status);
-
-      if(status & STAT_OK)
-      {
-        for(totlen=0; !(rbd->status & RBD_LAST); rbd=(struct rbd_struct *) make32(rbd->next)) {
-          totlen += RECV_BUFF_SIZE;
+          totlen &= RBD_MASK; /* length of this frame */
           rbd->status = 0;
-        }
-        totlen += rbd->status & RBD_MASK;
-        rbd->status = 0;
-        
-        skb = (struct sk_buff *) alloc_skb(totlen, GFP_ATOMIC);
-
-        if (skb != NULL) /* copy header */
-        {
-          skb->len = totlen;
-          skb->dev = dev;
-
-          if(rbd->buffer < rbd_first->buffer)
+          skb = (struct sk_buff *) alloc_skb(totlen, GFP_ATOMIC);
+          if(skb != NULL)
           {
-            pnt = p->max_cbuff24 - rbd_first->buffer;
-            memcpy( (char *) skb->data,p->max_cbuff32-pnt,pnt);
-            memcpy( (char *) skb->data+pnt,p->min_cbuff32,totlen-pnt);
+            skb->len = totlen;
+            skb->dev = dev;
+            memcpy( (char *) skb->data,(char *) p->base+(unsigned long) rbd->buffer, totlen);
+            netif_rx(skb);
+            p->stats.rx_packets++;
           }
           else
-            memcpy( (char *) skb->data,(char *) p->base+(unsigned long) rbd_first->buffer, totlen);
-
-          rbd->size |= RBD_LAST;
-          p->rbd_last->size &= ~RBD_LAST;
-          p->rbd_last = rbd;
-
-          netif_rx(skb);
-          p->stats.rx_packets++;
+            p->stats.rx_dropped++;
         }
         else
         {
-          rbd->size |= RBD_LAST;
-          p->rbd_last->size &= ~RBD_LAST;
-          p->rbd_last = rbd;
+          printk("%s: received oversized frame.\n",dev->name);
+          p->stats.rx_dropped++;
         }
       }
       else /* frame !(ok), only with 'save-bad-frames' */
@@ -898,13 +826,16 @@
         printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
         p->stats.rx_errors++;
       }
+      p->rfd_top->status = 0;
+      p->rfd_top->last = RFD_SUSP;
+      p->rfd_last->last = 0;        /* delete RU_SUSP  */
+      p->rfd_last = p->rfd_top;
+      p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
   }
 }
 
 /**********************************************************
- * I never got this error , (which should occur if someone 
- * wants to blast your machine) so I couldn't debug it for now.
- * but we _try_ to fix the receiver not ready int.
+ * handle 'Receiver went not ready'. 
  */
 
 static void ni52_rnr_int(struct device *dev)
@@ -913,13 +844,16 @@
 
   p->stats.rx_errors++;
 
-  while(p->scb->cmd);    /* wait for the last cmd */
-  p->scb->cmd = RUC_ABORT;
+  WAIT_4_SCB_CMD();    /* wait for the last cmd */
+  p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no ressource'-state .. abort it now. */
   ni_attn586(); 
-  while(p->scb->cmd);    /* wait for accept cmd. */
+  WAIT_4_SCB_CMD();    /* wait for accept cmd. */
 
   alloc_rfa(dev,(char *)p->rfd_first);
-  startrecv586(dev); /* restart */
+  startrecv586(dev); /* restart RU */
+
+  printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->status);
+
 }
 
 /**********************************************************
@@ -931,17 +865,14 @@
   int status;
   struct priv *p = (struct priv *) dev->priv;
 
-/*
-  if(!(p->xmit_cmds[0]->cmd_status & STAT_COMPL))
-    return;
-*/
+  status = p->xmit_cmds[p->xmit_last]->cmd_status;
+  if(!(status & STAT_COMPL))
+    printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
 
-  if( (status=p->xmit_cmds[p->xmit_last]->cmd_status) & STAT_OK)
+  if(status & STAT_OK)
   {
     p->stats.tx_packets++;
     p->stats.collisions += (status & TCMD_MAXCOLLMASK);
-    dev->tbusy = 0;
-    mark_bh(NET_BH);
   }
   else 
   {
@@ -957,6 +888,7 @@
     else if(status & TCMD_LOSTCTS) 
       printk("%s: loss of CTS detected.\n",dev->name);
     else if(status & TCMD_UNDERRUN) {
+      p->stats.tx_fifo_errors++;
       printk("%s: DMA underrun detected.\n",dev->name);
     }
     else if(status & TCMD_MAXCOLL) {
@@ -965,11 +897,13 @@
     } 
   }
 
-#ifndef ONLY_ONE_XMIT_BUF
+#if (NUM_XMIT_BUFFS != 1)
   if( (++p->xmit_last) == NUM_XMIT_BUFFS) 
     p->xmit_last = 0;
 #endif
 
+  dev->tbusy = 0;
+  mark_bh(NET_BH);
 }
 
 /***********************************************************
@@ -982,13 +916,8 @@
 
   p->scb->rfa_offset = make16(p->rfd_first);
   p->scb->cmd = RUC_START;
-  ni_attn586(); /* start cmd. */
-  while(p->scb->cmd); /* wait for accept cmd. (no timeout!!) */
-
-  DELAY(2); /* isn't necess. */
-
-  p->scb->cmd = p->scb->status & STAT_MASK;
-  ni_attn586(); /* ack interr */
+  ni_attn586();		/* start cmd. */
+  WAIT_4_SCB_CMD();	/* wait for accept cmd. (no timeout!!) */
 }
 
 /******************************************************
@@ -997,7 +926,7 @@
 
 static int ni52_send_packet(struct sk_buff *skb, struct device *dev)
 {
-  int len;
+  int len,i;
 #ifndef NO_NOPCOMMANDS
   int next_nop;
 #endif
@@ -1006,18 +935,37 @@
   if(dev->tbusy)
   {
     int tickssofar = jiffies - dev->trans_start;
-
-    if (tickssofar < 30)
+    if (tickssofar < 5)
       return 1;
 
+    if(p->scb->status & CU_ACTIVE) /* COMMAND-UNIT active? */
+    {
+      dev->tbusy = 0;
 #ifdef DEBUG
-    printk("%s: xmitter timed out, try to restart! stat: %04x\n",dev->name,p->scb->status);
-    printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status);
+      printk("%s: strange ... timeout with CU active?!?\n",dev->name);
+      printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point);
 #endif
-
-    ni52_close(dev);
-    ni52_open(dev);
+      p->scb->cmd = CUC_ABORT;
+      ni_attn586();
+      WAIT_4_SCB_CMD();
+      p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+      p->scb->cmd = CUC_START;
+      ni_attn586();
+      WAIT_4_SCB_CMD();
+      dev->trans_start = jiffies;
+      return 0;
+    }
+    else
+    {
+#ifdef DEBUG
+      printk("%s: xmitter timed out, try to restart! stat: %04x\n",dev->name,p->scb->status);
+      printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status);
+#endif
+      ni52_close(dev);
+      ni52_open(dev);
+    }
     dev->trans_start = jiffies;
+    return 0;
   }
 
   if(skb == NULL)
@@ -1028,6 +976,11 @@
 
   if (skb->len <= 0)
     return 0;
+  if(skb->len > XMIT_BUFF_SIZE)
+  {
+    printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %ld bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
+    return 0;
+  }
 
   if (set_bit(0, (void*)&dev->tbusy) != 0)
      printk("%s: Transmitter access conflict.\n", dev->name);
@@ -1036,39 +989,45 @@
     memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
     len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
 
-#ifdef ONLY_ONE_XMIT_BUF  
+#if (NUM_XMIT_BUFFS == 1)
 #  ifdef NO_NOPCOMMANDS
     p->xmit_buffs[0]->size = TBD_LAST | len;
-    p->xmit_cmds[0]->cmd_status = 0;
-    p->scb->cbl_offset = make16(p->xmit_cmds[0]);
-    p->scb->cmd = CUC_START;
-
-    dev->trans_start = jiffies;
-    ni_attn586();
-    while(p->scb->cmd)
-      for(len=0;len<256;len++);
-
-  /*  DELAY(1); */ /* TEST;TEST;TEST */
+    for(i=0;i<16;i++)
+    {
+      p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+      p->scb->cmd = CUC_START;
+      p->xmit_cmds[0]->cmd_status = 0;
+
+      ni_attn586();
+      dev->trans_start = jiffies;
+      if(!i)
+        dev_kfree_skb(skb,FREE_WRITE);
+      WAIT_4_SCB_CMD();
+      if( (p->scb->status & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
+        break;
+      if(p->xmit_cmds[0]->cmd_status)
+        break;
+      if(i==15)
+        printk("%s: Can't start transmit-command.\n",dev->name);
+    }
 #  else
     next_nop = (p->nop_point + 1) & 0x1;
     p->xmit_buffs[0]->size = TBD_LAST | len;
 
-    p->xmit_cmds[0]->cmd_cmd    = CMD_XMIT | CMD_INT;
-    p->xmit_cmds[0]->cmd_status = 0;
     p->xmit_cmds[0]->cmd_link   = p->nop_cmds[next_nop]->cmd_link 
                                 = make16((p->nop_cmds[next_nop]));
-    p->nop_cmds[next_nop]->cmd_status = 0;
+    p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
 
     p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
     dev->trans_start = jiffies;
     p->nop_point = next_nop;
+    dev_kfree_skb(skb,FREE_WRITE);
 #  endif
 #else
     p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
     if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS ) 
       next_nop = 0;
 
-    p->xmit_cmds[p->xmit_count]->cmd_cmd  = CMD_XMIT | CMD_INT;
     p->xmit_cmds[p->xmit_count]->cmd_status  = 0;
     p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link 
                                           = make16((p->nop_cmds[next_nop]));
@@ -1082,71 +1041,57 @@
     if(p->xmit_count != p->xmit_last)
       dev->tbusy = 0;
     sti();
+    dev_kfree_skb(skb,FREE_WRITE);
 #endif
   }
-
-  dev_kfree_skb(skb,FREE_WRITE);
-
   return 0;
 }
 
+/*******************************************
+ * Someone wanna have the statistics 
+ */
+
 static struct enet_statistics *ni52_get_stats(struct device *dev)
 {
   struct priv *p = (struct priv *) dev->priv;
-#ifdef DEBUG3
-  printk("ni52: errs, crc %d, align %d, resource %d, ovrn %d.\n",(int) p->scb->crc_errs,(int) p->scb->aln_errs,(int) p->scb->rsc_errs,(int) p->scb->ovrn_errs); 
-#endif
+  unsigned short crc,aln,rsc,ovrn;
+
+  crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */
+  p->scb->crc_errs -= crc;
+  aln = p->scb->aln_errs;
+  p->scb->aln_errs -= aln;
+  rsc = p->scb->rsc_errs;
+  p->scb->rsc_errs -= rsc;
+  ovrn = p->scb->ovrn_errs;
+  p->scb->ovrn_errs -= ovrn;
+
+  p->stats.rx_crc_errors += crc;
+  p->stats.rx_fifo_errors += ovrn;
+  p->stats.rx_frame_errors += aln;
+  p->stats.rx_dropped += rsc;
+
   return &p->stats;
 }
 
+/********************************************************
+ * Set MC list ..  
+ */
+
 static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
-/*
-  struct priv *p = (struct priv *) dev->priv;
-  volatile struct configure_cmd_struct  *cfg_cmd;
-*/
-
-  if(!num_addrs)
-    printk("%s: Currently, the Ni52 driver doesn't support promiscuous or multicast mode.\n",dev->name);
-
-#if 0
-  p->scb->cmd = CUC_SUSPEND;
-  ni_attn586();
-  while(p->scb->cmd);
-  p->scb->cmd = RUC_SUSPEND; 
-  ni_attn586();
-  while(p->scb->cmd);
-
-  cfg_cmd = (struct configure_cmd_struct *) p->xmit_cbuffs[0]; /* we're using a transmitcommand */
- 
-  cfg_cmd->cmd_status = 0;
-  cfg_cmd->cmd_cmd    = CMD_CONFIGURE | CMD_LAST;
-  cfg_cmd->cmd_link   = 0xffff;
-
-  cfg_cmd->byte_cnt   = 0x0a; /* number of cfg bytes */
-  cfg_cmd->fifo       = 0x08; /* fifo-limit (8=tx:32/rx:64) */
-  cfg_cmd->sav_bf     = 0x40; /* hold or discard bad recv frames (bit 7) */
-  cfg_cmd->adr_len    = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
-  cfg_cmd->priority   = 0x00;
-  cfg_cmd->ifd        = 0x60;
-  cfg_cmd->time_low   = 0x00;
-  cfg_cmd->time_high  = 0xf2;
-  cfg_cmd->promisc    = 0x01; /* promisc on */
-  cfg_cmd->carr_coll  = 0x00;
-
-  p->scb->cbl_offset = make16(cfg_cmd);
-
-  p->scb->cmd = CUC_START; /* cmd.-unit start */
-  ni_attn586();
-  while(p->scb->cmd);
-
-  p->scb->cbl_offset = p->nop_cmds[0]->cmd_link = make16(p->nop_cmds[0]);
-  p->scb->cmd = CUC_START;
-  ni_atthn586();
-  while(p->scb->cmd);
-  p->scb->cmd = RUC_RESUME;
-  ni_atthn586();
-  while(p->scb->cmd);
-#endif
+  if(!dev->start && !num_addrs)
+  {
+    printk("%s: Can't apply promiscous/multicastmode to a not running interface.\n",dev->name);
+    return;
+  }
 
+  dev->start = 0;
+  alloc586(dev);
+  init586(dev,num_addrs,addrs);  
+  startrecv586(dev);
+  dev->start = 1;
 }
+
+/*
+ * END: linux/drivers/net/ni52.c 
+ */
diff -u --recursive --new-file v1.1.88/linux/drivers/net/ni52.h linux/drivers/net/ni52.h
--- v1.1.88/linux/drivers/net/ni52.h	Fri Aug 26 09:37:38 1994
+++ linux/drivers/net/ni52.h	Fri Feb  3 15:19:28 1995
@@ -227,7 +227,7 @@
   unsigned short cmd_cmd;
   unsigned short cmd_link;
   unsigned short mc_cnt;		/* number of bytes in the MC-List */
-  unsigned char  mc_list[16][6];  	/* the list for 16 entries */
+  unsigned char  mc_list[0][6];  	/* pointer to 6 bytes entries */
 };
 
 /*
diff -u --recursive --new-file v1.1.88/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.1.88/linux/drivers/net/ppp.c	Wed Feb  1 09:23:06 1995
+++ linux/drivers/net/ppp.c	Sun Feb  5 14:29:48 1995
@@ -32,6 +32,11 @@
 #define NEW_TTY_DRIVERS				/* */
 #define OPTIMIZE_FLAG_TIME  ((HZ * 3)/2)	/* */
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -63,8 +68,8 @@
 
 #include <linux/ppp.h>
 
-#include <ip.h>
-#include <tcp.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
 
 #include "slhc.h"
 
@@ -563,6 +568,10 @@
 
   PRINTKN (2,(KERN_INFO "ppp: channel %s open\n", ppp->dev->name));
 
+#ifdef MODULE
+  MOD_INC_USE_COUNT;
+#endif
+
   return (ppp->line);
 }
 
@@ -603,6 +612,9 @@
   PRINTKN (2,(KERN_INFO "ppp: channel %s going down for IP packets!\n",
 	      dev->name));
   CHECK_PPP(-ENXIO);
+#ifdef MODULE
+  MOD_DEC_USE_COUNT;
+#endif
   return 0;
 }
 
@@ -2034,3 +2046,54 @@
 
   set_fs (old_fs);
 }
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+static struct device dev_ppp[PPP_NRUNIT] = {
+	{
+		"ppp0",		/* ppp */
+		0, 0, 0, 0,	/* memory */
+		0, 0,		/* base, irq */
+		0, 0, 0, NULL, ppp_init,
+	},
+	{ "ppp1" , 0, 0, 0, 0,  1, 0, 0, 0, 0, NULL, ppp_init },
+	{ "ppp2" , 0, 0, 0, 0,  2, 0, 0, 0, 0, NULL, ppp_init },
+	{ "ppp3" , 0, 0, 0, 0,  3, 0, 0, 0, 0, NULL, ppp_init },
+};
+
+int
+init_module(void)
+{
+	int err;
+	int i;
+
+	for (i = 0; i < PPP_NRUNIT; i++)  {
+		if ((err = register_netdev(&dev_ppp[i])))  {
+			if (err == -EEXIST)  {
+				printk("PPP: devices already present. Module not loaded.\n");
+			}
+			return err;
+		}
+	}
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+	int i;
+
+	if (MOD_IN_USE)  {
+		printk("PPP: device busy, remove delayed\n");
+		return;
+	}
+	for (i = 0; i < PPP_NRUNIT; i++)  {
+		unregister_netdev(&dev_ppp[i]);
+	}
+	if ((i = tty_register_ldisc(N_PPP, NULL)))  {
+		printk("PPP: can't unregister line discipline (err = %d)\n", i);
+	}
+}
+
+#endif
diff -u --recursive --new-file v1.1.88/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v1.1.88/linux/drivers/net/slip.c	Thu Jan 26 07:49:06 1995
+++ linux/drivers/net/slip.c	Sun Feb  5 14:29:25 1995
@@ -71,8 +71,8 @@
 #include <linux/if_arp.h>
 #include "slip.h"
 #ifdef CONFIG_INET
-#include "ip.h"
-#include "tcp.h"
+#include <linux/ip.h>
+#include <linux/tcp.h>
 #include "slhc.h"
 #endif
 
diff -u --recursive --new-file v1.1.88/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h
--- v1.1.88/linux/drivers/net/wavelan.h	Wed Feb  1 09:23:06 1995
+++ linux/drivers/net/wavelan.h	Wed Feb  1 09:19:36 1995
@@ -26,7 +26,7 @@
 	unsigned char	psa_univ_local_sel;	/* Universal Local Selection */
 #define		PSA_UNIVERSAL	0		/* Universal (factory) */
 #define		PSA_LOCAL	1		/* Local */
-	unsigned char	psa_comp_number;	/* Compatability Number: */
+	unsigned char	psa_comp_number;	/* Compatibility Number: */
 #define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz	*/
 #define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	*/
 #define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	*/
@@ -94,7 +94,7 @@
 #define		MMW_LOOPT_SEL_LT3C	0x02	/* looptest 3c */
 #define		MMW_LOOPT_SEL_LT3D	0x01	/* looptest 3d */
 	unsigned char	mmw_jabber_enable;	/* jabber timer enable */
-	unsigned char	mmw_freeze;		/* freeze / unfreeeze signal level */
+	unsigned char	mmw_freeze;		/* freeze / unfreeze signal level */
 	unsigned char	mmw_anten_sel;		/* antenna selection */
 #define		MMW_ANTEN_SEL_SEL	0x01	/* direct antenna selection */
 #define		MMW_ANTEN_SEL_ALG_EN	0x02	/* antenna selection algorithm enable */
@@ -104,7 +104,7 @@
 	unsigned char	mmw_unused2[1];		/* unused */
 	unsigned char	mmw_thr_pre_set;	/* level threshold preset */
 	unsigned char	mmw_decay_prm;		/* decay parameters */
-	unsigned char	mmw_decay_updat_prm;	/* decay update parameterz */
+	unsigned char	mmw_decay_updat_prm;	/* decay update parameters */
 	unsigned char	mmw_quality_thr;	/* quality (z-quotient) threshold */
 	unsigned char	mmw_netw_id_l;		/* NWID low order byte */
 	unsigned char	mmw_netw_id_h;		/* NWID high order byte */
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.1.88/linux/drivers/scsi/Makefile	Thu Jan 26 07:49:06 1995
+++ linux/drivers/scsi/Makefile	Wed Feb  1 19:36:35 1995
@@ -94,6 +94,8 @@
 ifdef CONFIG_SCSI_U14_34F
 SCSI_OBJS := $(SCSI_OBJS) u14-34f.o
 SCSI_SRCS := $(SCSI_SRCS) u14-34f.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) u14-34f.o
 endif
 
 ifdef CONFIG_SCSI_DEBUG
@@ -158,6 +160,8 @@
 ifdef CONFIG_SCSI_EATA
 SCSI_OBJS := $(SCSI_OBJS) eata.o
 SCSI_SRCS := $(SCSI_SRCS) eata.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata.o
 endif
 
 
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v1.1.88/linux/drivers/scsi/NCR5380.c	Mon Jan 16 14:18:21 1995
+++ linux/drivers/scsi/NCR5380.c	Wed Feb  1 09:19:36 1995
@@ -1030,7 +1030,7 @@
  *
  */
 
-static void NCR5380_intr (int irq) {
+static void NCR5380_intr (int irq, struct pt_regs * regs) {
     NCR5380_local_declare(); 
     struct Scsi_Host *instance;
     int done;
@@ -1912,7 +1912,10 @@
 	instance->hostdata;
     unsigned char msgout = NOP;
     int sink = 0;
-    int len, transfersize;
+    int len;
+#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
+    int transfersize;
+#endif
     unsigned char *data;
     unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
     Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
@@ -2014,7 +2017,7 @@
 		    } else
 			cmd->SCp.this_residual -= transfersize - len;
 		} else
-#endif /* defined(REAL_DMA) || defined(REAL_DMA_POLL) */
+#endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */
 		  NCR5380_transfer_pio(instance, &phase, 
 		    (int *) &cmd->SCp.this_residual, (unsigned char **)
 		    &cmd->SCp.ptr);
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/NCR5380.h linux/drivers/scsi/NCR5380.h
--- v1.1.88/linux/drivers/scsi/NCR5380.h	Tue Nov 22 15:40:13 1994
+++ linux/drivers/scsi/NCR5380.h	Wed Feb  1 09:19:36 1995
@@ -272,7 +272,7 @@
 #endif
 static void NCR5380_init (struct Scsi_Host *instance, int flags);
 static void NCR5380_information_transfer (struct Scsi_Host *instance);
-static void NCR5380_intr (int irq);
+static void NCR5380_intr (int irq, struct pt_regs * regs);
 static void NCR5380_main (void);
 static void NCR5380_print_options (struct Scsi_Host *instance);
 #ifndef NCR5380_abort
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v1.1.88/linux/drivers/scsi/eata.c	Mon Jan 16 14:18:22 1995
+++ linux/drivers/scsi/eata.c	Wed Feb  1 19:36:35 1995
@@ -1,6 +1,15 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      28 Jan 1995 rev. 1.14 for linux 1.1.86
+ *          Added module support.
+ *          Log and do a retry when a disk drive returns a target status 
+ *          different from zero on a recovered error.
+ *
+ *      24 Jan 1995 rev. 1.13 for linux 1.1.85
+ *          Use optimized board configuration, with a measured performance
+ *          increase in the range 10%-20% on i/o throughput.
+ *
  *      16 Jan 1995 rev. 1.12 for linux 1.1.81
  *          Fix mscp structure comments (no functional change).
  *          Display a message if check_region detects a port address
@@ -18,7 +27,7 @@
  *          for EISA boards, it just prints a warning message.
  *
  *      30 Nov 1994 rev. 1.09 for linux 1.1.68
- *          Redo i/o on target status CONDITION_GOOD for TYPE_DISK only.
+ *          Redo i/o on target status CHECK_CONDITION for TYPE_DISK only.
  *          Added optional support for using a single board at a time.
  *
  *      18 Nov 1994 rev. 1.08 for linux 1.1.64
@@ -78,6 +87,10 @@
  *  the driver sets host->block = TRUE for all ISA boards.
  */
 
+#if defined(MODULE)
+#include <linux/module.h>
+#endif
+
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -97,6 +110,8 @@
 #define ISA  0
 #define ESA 1
 
+#undef FORCE_CONFIG
+
 #undef  DEBUG_DETECT
 #undef  DEBUG_INTERRUPT
 #undef  DEBUG_STATISTICS
@@ -114,8 +129,10 @@
 #define IN_USE   1
 #define LOCKED   2
 #define IN_RESET 3
+#define IGNORE   4
 #define NO_IRQ  0xff
-#define MAXLOOP 20000
+#define NO_DMA  0xff
+#define MAXLOOP 200000
 
 #define REG_CMD         7
 #define REG_STATUS      7
@@ -127,33 +144,37 @@
 #define REG_LM          3
 #define REG_MID         4
 #define REG_MSB         5
-#define REG_REGION      9
+#define REGION_SIZE     9
 #define EISA_RANGE      0xf000
 #define BSY_ASSERTED      0x80
 #define DRQ_ASSERTED      0x08
 #define ABSY_ASSERTED     0x01
 #define IRQ_ASSERTED      0x02
-#define READ_CONFIG_PIO   0xF0
-#define SET_CONFIG_PIO    0xF1
-#define SEND_CP_PIO       0xF2
-#define RECEIVE_SP_PIO    0xF3
-#define TRUNCATE_XFR_PIO  0xF4
-#define RESET_PIO         0xF9
-#define READ_CONFIG_DMA   0xFD
-#define SET_CONFIG_DMA    0xFE
-#define SEND_CP_DMA       0xFF
+#define READ_CONFIG_PIO   0xf0
+#define SET_CONFIG_PIO    0xf1
+#define SEND_CP_PIO       0xf2
+#define RECEIVE_SP_PIO    0xf3
+#define TRUNCATE_XFR_PIO  0xf4
+#define RESET_PIO         0xf9
+#define READ_CONFIG_DMA   0xfd
+#define SET_CONFIG_DMA    0xfe
+#define SEND_CP_DMA       0xff
 #define ASOK              0x00
 #define ASST              0x01
 
 /* "EATA", in Big Endian format */
 #define EATA_SIGNATURE 0x41544145
 
+/* Number of valid bytes in the board config structure for EATA 2.0x */
+#define EATA_2_0A_SIZE 28
+#define EATA_2_0B_SIZE 30
+
 /* Board info structure */
 struct eata_info {
-   ulong  data_len;     /* Number of valid bytes after this field (30) */
+   ulong  data_len;     /* Number of valid bytes after this field */
    ulong  sign;         /* ASCII "EATA" signature */
    unchar        :4,    /* unused low nibble */
-          version:4;    /* EATA version */
+          version:4;    /* EATA version, should be 0x1 */
    unchar  ocsena:1,    /* Overlap Command Support Enabled */
            tarsup:1,    /* Target Mode Supported */
                  :2,
@@ -162,7 +183,8 @@
               ata:1,    /* This is an ATA device */
            haaval:1;    /* Host Adapter Address Valid */
    ushort cp_pad_len;   /* Number of pad bytes after cp_len */
-   ulong  host_addr;    /* Host Adapter SCSI ID */
+   unchar host_addr[3]; /* Host Adapter SCSI ID for channels 2, 1, 0 */
+   unchar reserved;
    ulong  cp_len;       /* Number of valid bytes in cp */
    ulong  sp_len;       /* Number of valid bytes in sp */
    ushort queue_size;   /* Max number of cp that can be queued */
@@ -173,7 +195,15 @@
            second:1,    /* 1 if this is a secondary (not primary) controller */
              drqx:2;    /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
    unchar  sync;        /* 1 if scsi target id 7...0 is running sync scsi */
-   ushort ipad[250];
+
+   /* Structure extension defined in EATA 2.0B */
+   unchar  isaena:1,    /* ISA i/o addressing is disabled/enabled */
+         forcaddr:1,    /* Port address has been forced */
+                 :6;
+   unchar  max_id:5,    /* Max number of SCSI target IDs */
+         max_chan:3;    /* Max SCSI channel number on this board */
+
+   ushort ipad[249];
    };
 
 /* Board config structure */
@@ -242,10 +272,12 @@
    unsigned int multicount;             /* Total ... in second ihdlr loop */
    int board_number;                    /* Number of this board */
    char board_name[16];                 /* Name of this board */
+   char board_id[256];                  /* data from INQUIRY on this board */
    int in_reset;                        /* True if board is doing a reset */
    int target_time_out[MAX_TARGET];     /* N. of timeout errors on target */
    int target_reset[MAX_TARGET];        /* If TRUE redo operation on target */
    unsigned char subversion;            /* Bus type, either ISA or ESA */
+   unsigned char protocol_rev;          /* EATA 2.0 rev., 'A' or 'B' or 'C' */
    struct mssp sp[MAX_MAILBOXES];       /* Returned status for this board */
    };
 
@@ -302,8 +334,8 @@
 static inline int port_detect(ushort *port_base, unsigned int j, 
                               Scsi_Host_Template * tpnt) {
    unsigned char irq, dma_channel, subversion;
+   unsigned char protocol_rev;
    struct eata_info info;
-   struct eata_config config;
    char *board_status;
 
    /* Allowed DMA channels for ISA (0 indicates reserved) */
@@ -313,8 +345,8 @@
 
    sprintf(name, "%s%d", driver_name, j);
 
-   if(check_region(*port_base, REG_REGION)) {
-      printk("%s: address 0x%03x already in use, detaching.\n", 
+   if(check_region(*port_base, REGION_SIZE)) {
+      printk("%s: address 0x%03x in use, skipping probe.\n", 
              name, *port_base);
       return FALSE;
       }
@@ -325,25 +357,42 @@
    if (read_pio(*port_base, (ushort *)&info, (ushort *)&info.ipad[0])) 
       return FALSE;
 
-   /* check the controller "EATA" signature */
+   /* Check the controller "EATA" signature */
    if (info.sign != EATA_SIGNATURE) return FALSE;
 
+   if (ntohl(info.data_len) < EATA_2_0A_SIZE) {
+      printk("%s: config structure size (%ld bytes) too short, detaching.\n", 
+             name, ntohl(info.data_len));
+      return FALSE;
+      }
+   else if (ntohl(info.data_len) == EATA_2_0A_SIZE)
+      protocol_rev = 'A';
+   else if (ntohl(info.data_len) == EATA_2_0B_SIZE)
+      protocol_rev = 'B';
+   else
+      protocol_rev = 'C';
+
+   if (protocol_rev != 'A' && info.max_chan > 0)
+      printk("%s: warning, only scsi channel 0 is supported.\n", name);
+
    irq = info.irq;
 
    if (*port_base & EISA_RANGE) {
 
       if (!info.haaval || info.ata || info.drqvld || !info.dmasup) {
-         printk("%s: unusable EISA board found, detaching.\n", name);
+         printk("%s: unusable EISA board found (%d%d%d%d), detaching.\n", 
+                name, info.haaval, info.ata, info.drqvld, info.dmasup);
          return FALSE;
          }
 
       subversion = ESA;
-      dma_channel = 0;
+      dma_channel = NO_DMA;
       }
    else {
 
       if (!info.haaval || info.ata || !info.drqvld || !info.dmasup) {
-         printk("%s: unusable ISA board found, detaching.\n", name);
+         printk("%s: unusable ISA board found (%d%d%d%d), detaching.\n",
+                name, info.haaval, info.ata, info.drqvld, info.dmasup);
          return FALSE;
          }
 
@@ -374,6 +423,10 @@
       return FALSE;
       }
 
+#if defined (FORCE_CONFIG)
+   {
+   struct eata_config config;
+
    /* Set board configuration */
    memset((char *)&config, 0, sizeof(struct eata_config));
    config.len = (ushort) htons((ushort)510);
@@ -383,28 +436,37 @@
       printk("%s: busy timeout sending configuration, detaching.\n", name);
       return FALSE;
       }
+   }
+#endif
 
    sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
    sh[j]->io_port = *port_base;
+   sh[j]->n_io_port = REGION_SIZE;
    sh[j]->dma_channel = dma_channel;
    sh[j]->irq = irq;
    sh[j]->sg_tablesize = (ushort) ntohs(info.scatt_size);
-   sh[j]->this_id = (ushort) ntohl(info.host_addr);
+   sh[j]->this_id = (ushort) info.host_addr[3];
    sh[j]->can_queue = (ushort) ntohs(info.queue_size);
    sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
 
    /* Register the I/O space that we use */
-   request_region(sh[j]->io_port, REG_REGION, driver_name);
+   request_region(sh[j]->io_port, REGION_SIZE, driver_name);
 
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->subversion = subversion;
+   HD(j)->protocol_rev = protocol_rev;
    HD(j)->board_number = j;
    irqlist[irq] = j;
 
    if (HD(j)->subversion == ESA)
       sh[j]->unchecked_isa_dma = FALSE;
    else {
+
+#if !defined(MODULE)
+      /* The module code does not checkin/checkout in the blocking list yet */
       sh[j]->block = sh[j];
+#endif
+
       sh[j]->unchecked_isa_dma = TRUE;
       disable_dma(dma_channel);
       clear_dma_ff(dma_channel);
@@ -414,11 +476,10 @@
 
    strcpy(BN(j), name);
 
-   printk("%s: %s, ID %d, PORT 0x%03x, IRQ %u, DMA %u, SG %d, "\
-          "Mbox %d, CmdLun %d.\n", BN(j), board_status, sh[j]->this_id, 
-           sh[j]->io_port, sh[j]->irq, 
-           sh[j]->dma_channel, sh[j]->sg_tablesize, 
-           sh[j]->can_queue, sh[j]->cmd_per_lun);
+   printk("%s: 2.0%c, %s, ID %d, PORT 0x%03x, IRQ %u, DMA %u, SG %d, "\
+          "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev, board_status, 
+           sh[j]->this_id, sh[j]->io_port, sh[j]->irq, sh[j]->dma_channel,
+           sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun);
 
    /* DPT PM2012 does not allow to detect sg_tablesize correctly */
    if (sh[j]->sg_tablesize > MAX_SGLIST || sh[j]->sg_tablesize < 2) {
@@ -433,6 +494,11 @@
       }
 
 #if defined (DEBUG_DETECT)
+   if (protocol_rev != 'A')
+      printk("%s: EATA 2.0%c, isaena %u, forcaddr %u, max_id %u,"\
+             " max_chan %u.\n", name, protocol_rev, info.isaena, 
+             info.forcaddr, info.max_id, info.max_chan);
+
    printk("%s: Version 0x%x, SYNC 0x%x, infol %ld, cpl %ld spl %ld.\n", 
           name, info.version, info.sync, ntohl(info.data_len), 
           ntohl(info.cp_len), ntohl(info.sp_len));
@@ -447,7 +513,7 @@
    ushort io_port[] = { 
       0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88,
       0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, 
-      0x330,  0x230,  0x1f0,  0x170,  0x0
+      0x1f0,  0x170,  0x330,  0x230,  0x0
       };
 
    ushort *port_base = io_port;
@@ -757,7 +823,7 @@
 
 static void eata_interrupt_handler(int irq, struct pt_regs * regs) {
    Scsi_Cmnd *SCpnt;
-   unsigned int i, j, k, flags, status, loops, total_loops = 0;
+   unsigned int i, j, k, flags, status, tstatus, loops, total_loops = 0;
    struct mssp *spp;
    struct mscp *cpp;
 
@@ -800,7 +866,11 @@
    
             spp->eoc = FALSE;
    
-            if (HD(j)->cp_stat[i] == LOCKED) {
+            if (HD(j)->cp_stat[i] == IGNORE) {
+               HD(j)->cp_stat[i] = FREE;
+               continue;
+               }
+            else if (HD(j)->cp_stat[i] == LOCKED) {
                HD(j)->cp_stat[i] = FREE;
                printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
                       BN(j), i, HD(j)->iocount);
@@ -836,30 +906,51 @@
                      " irq %d.\n", BN(j), i, SCpnt->pid, 
                      *(unsigned int *)SCpnt->host_scribble, irq);
    
+            tstatus = status_byte(spp->target_status);
+   
             switch (spp->adapter_status) {
-               case ASOK:          /* status OK */
+               case ASOK:     /* status OK */
    
-                  /* Fix a "READ CAPACITY failed" error on some disk drives */
-                  if (spp->target_status == INTERMEDIATE_GOOD
-                                        && SCpnt->device->type != TYPE_TAPE) 
+                  /* Forces a reset if a disk drive keeps returning BUSY */
+                  if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) 
                      status = DID_ERROR << 16;
    
                   /* If there was a bus reset, redo operation on each target */
-                  else if (spp->target_status == CONDITION_GOOD
-                                        && SCpnt->device->type == TYPE_DISK
-                                        && HD(j)->target_reset[SCpnt->target])
+                  else if (tstatus != GOOD
+                           && SCpnt->device->type == TYPE_DISK
+                           && HD(j)->target_reset[SCpnt->target])
                      status = DID_BUS_BUSY << 16;
+   
+                  /* Works around a flaw in scsi.c */
+                  else if (tstatus == CHECK_CONDITION
+                           && SCpnt->device->type == TYPE_DISK
+                           && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+                     status = DID_BUS_BUSY << 16;
+
+                  else if (tstatus == CHECK_CONDITION
+                           && (SCpnt->device->type == TYPE_DISK
+                            || SCpnt->device->type == TYPE_ROM)
+                           && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION)
+                     status = DID_ERROR << 16;
+   
                   else
                      status = DID_OK << 16;
    
-                  if (spp->target_status == 0)
+                  if (tstatus == GOOD)
                      HD(j)->target_reset[SCpnt->target] = FALSE;
    
+                  if (spp->target_status && (SCpnt->device->type == TYPE_DISK
+                                          || SCpnt->device->type == TYPE_ROM))
+                     printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
+                            "0x%x, sense key 0x%x.\n", BN(j), 
+                            SCpnt->target, SCpnt->lun, SCpnt->pid,
+                            spp->target_status, SCpnt->sense_buffer[2]);
+   
                   HD(j)->target_time_out[SCpnt->target] = 0;
    
                   break;
-               case ASST:          /* Selection Time Out */
-               case 0x02:          /* Command Time Out   */
+               case ASST:     /* Selection Time Out */
+               case 0x02:     /* Command Time Out   */
    
                   if (HD(j)->target_time_out[SCpnt->target] > 1)
                      status = DID_ERROR << 16;
@@ -869,7 +960,8 @@
                      }
    
                   break;
-               case 0x03:          /* SCSI Bus Reset Received */
+               case 0x03:     /* SCSI Bus Reset Received */
+               case 0x04:     /* Initial Controller Power-up */
    
                   if (SCpnt->device->type != TYPE_TAPE)
                      status = DID_BUS_BUSY << 16;
@@ -880,15 +972,14 @@
                      HD(j)->target_reset[k] = TRUE;
    
                   break;
-               case 0x07:          /* Bus Parity Error */
-               case 0x0c:          /* Controller Ram Parity */
-               case 0x04:          /* Initial Controller Power-up */
-               case 0x05:          /* Unexpected Bus Phase */
-               case 0x06:          /* Unexpected Bus Free */
-               case 0x08:          /* SCSI Hung */
-               case 0x09:          /* Unexpected Message Reject */
-               case 0x0a:          /* SCSI Bus Reset Stuck */
-               case 0x0b:          /* Auto Request-Sense Failed */
+               case 0x07:     /* Bus Parity Error */
+               case 0x0c:     /* Controller Ram Parity */
+               case 0x05:     /* Unexpected Bus Phase */
+               case 0x06:     /* Unexpected Bus Free */
+               case 0x08:     /* SCSI Hung */
+               case 0x09:     /* Unexpected Message Reject */
+               case 0x0a:     /* SCSI Bus Reset Stuck */
+               case 0x0b:     /* Auto Request-Sense Failed */
                default:
                   status = DID_ERROR << 16;
                   break;
@@ -944,3 +1035,9 @@
    restore_flags(flags);
    return;
 }
+
+#if defined(MODULE)
+Scsi_Host_Template driver_template = EATA;
+
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- v1.1.88/linux/drivers/scsi/eata.h	Mon Jan 16 14:18:22 1995
+++ linux/drivers/scsi/eata.h	Wed Feb  1 19:36:35 1995
@@ -7,7 +7,7 @@
 
 #include <linux/scsicam.h>
 
-#define EATA_VERSION "1.12.00"
+#define EATA_VERSION "1.14.03"
 
 int eata_detect(Scsi_Host_Template *);
 int eata_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
@@ -16,7 +16,7 @@
 
 #define EATA {  NULL, /* Ptr for modules */                    \
                 NULL, /* usage count for modules */	       \
-                "EATA/DMA 2.0A rev. " EATA_VERSION " by "      \
+                "EATA/DMA 2.0 rev. " EATA_VERSION " by "       \
                 "Dario_Ballabio@milano.europe.dg.com.",        \
                 eata_detect,	        	               \
                 NULL, /* Release */     	               \
@@ -32,7 +32,7 @@
                 0,   /* sg_tablesize, reset by detect */       \
                 0,   /* cmd_per_lun, reset by detect */        \
 		0,   /* number of boards present */            \
-                0,   /* unchecked isa dma, reset by detect */  \
+                1,   /* unchecked isa dma, reset by detect */  \
                 ENABLE_CLUSTERING                              \
                 }
 #endif
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- v1.1.88/linux/drivers/scsi/eata_dma.c	Mon Jan 30 06:41:57 1995
+++ linux/drivers/scsi/eata_dma.c	Wed Feb  1 20:02:39 1995
@@ -12,6 +12,8 @@
  *      -supports all PCI based EATA-DMA boards             *
  *      -supports multiple HBAs with & without IRQ sharing  *
  *      -supports all SCSI channels on multi channel boards *
+ *      -displays (more or less useful) infos in /proc/scsi *
+ *      -can be loaded as module                            *
  *                                                          *
  *  (c)1993,94,95 Michael Neuffer                           *
  *                neuffer@goofy.zdv.uni-mainz.de            *
@@ -39,14 +41,18 @@
  * very helpful and tried to give me all the infos and      *
  * support I need.                                          *
  *                                                          *
- *  Thanks also to Greg Hosler who did a lot of testing and *
- *  found quite a number of bugs during the development.    *
+ * Thanks also to Greg Hosler who did a lot of testing and  *
+ * found quite a number of bugs during the development.     *
  ************************************************************
- *  last change: 95/01/24                                   *
+ *  last change: 95/01/30                                   *
  ************************************************************/
 
 /* Look in eata_dma.h for configuration information */
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+ 
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -61,25 +67,46 @@
 #include "scsi.h"
 #include "sd.h"
 
+#if 0
+#include "eata_dma_proc.c"
+#endif
+
 static uint ISAbases[] =
 {0x1F0, 0x170, 0x330, 0x230};
 static unchar EISAbases[] =
 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
 static uint registered_HBAs = 0;
 static struct Scsi_Host *last_HBA = NULL;
+static struct Scsi_Host *first_HBA = NULL;
 static unchar reg_IRQ[] =
 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 static unchar reg_IRQL[] =
 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
 static struct eata_sp status[MAXIRQ];	/* Statuspacket array   */
 
+static uint internal_command_finished = TRUE;
+
 static struct geom_emul geometry;	/* Drive 1 & 2 geometry */
 
-#if DEBUG_EATA
 static ulong int_counter = 0;
 static ulong queue_counter = 0;
-#endif
+
+void eata_scsi_done (Scsi_Cmnd * SCpnt)
+{
+    return;
+}	
+
+int eata_release(struct Scsi_Host *sh)
+{
+  if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq);
+  else reg_IRQ[sh->irq]--;
+  if (SD(sh)->channel == 0) {
+      if (sh->dma_channel != 0xff) free_dma(sh->dma_channel);
+      if (sh->io_port && sh->n_io_port)
+	  release_region(sh->io_port, sh->n_io_port);
+  }
+  return(TRUE);
+}
 
 const char *eata_info(struct Scsi_Host *host)
 {
@@ -102,13 +129,13 @@
     save_flags(flags);
     cli();
 
-    for (x = 1, sh = last_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
+    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) {
         if (sh->irq != irq)
 	    continue;
         if (!(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ))
 	    continue;
 
-	DBG(DEBUG_EATA, int_counter++);
+	int_counter++;
 
 	sp=&SD(sh)->sp;
 
@@ -192,14 +219,14 @@
 	    break;
 	}
 	cmd->result = result | scsi_stat; 
-        if (scsi_stat == CHECK_CONDITION && 
+        if (in_scan_scsis && scsi_stat == CHECK_CONDITION && 
 	    (cmd->sense_buffer[2] & 0xf) == UNIT_ATTENTION) 
 	    cmd->result |= (DRIVER_SENSE << 24);
 
 #if DBG_INTR2
 	if (scsi_stat || result || hba_stat || eata_stat != 0x50) 
-	  printk("eata_stat: %#x hba_stat: %#.2x,scsi_stat: %#.2x, sense_key: %#x, "
-		 "result: %#.8x\n", eata_stat, hba_stat, 
+	    printk("eata_stat: %#x hba_stat: %#.2x,scsi_stat: %#.2x, "
+		   "sense_key: %#x, result: %#.8x\n", eata_stat, hba_stat, 
 		 scsi_stat,cmd->sense_buffer[2] & 0xf, cmd->result); 
 	DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
 #endif
@@ -207,9 +234,8 @@
 	cp->status = FREE;   /* now we can release the slot  */
  
 	restore_flags(flags);
-   
-	cmd->scsi_done(cmd);
- 
+	if(cmd->scsi_done != eata_scsi_done) cmd->scsi_done(cmd);
+	else internal_command_finished = TRUE;
 	save_flags(flags);
 	cli();
     }
@@ -247,8 +273,15 @@
     save_flags(flags);
     cli();
 
-    DBG(DEBUG_EATA, queue_counter++);
+    queue_counter++;
 
+    if (done == (void *)eata_scsi_done) { 
+        if (internal_command_finished == TRUE)
+	    internal_command_finished = FALSE;
+        else 
+	    cmd->result = (DID_ERROR << 16) + QUEUE_FULL;
+    }
+    
     hd = HD(cmd);
     sh = cmd->host;
  
@@ -285,11 +318,28 @@
  
     cmd->scsi_done = (void *)done;
 
-    if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10)
+    switch (cmd->cmnd[0]) {
+    case CHANGE_DEFINITION: case COMPARE:         case COPY:
+    case COPY_VERIFY:       case LOG_SELECT:      case MODE_SELECT:
+    case MODE_SELECT_10:    case SEND_DIAGNOSTIC: case WRITE_BUFFER:
+    case FORMAT_UNIT:       case REASSIGN_BLOCKS: case RESERVE:
+    case SEARCH_EQUAL:      case SEARCH_HIGH:     case SEARCH_LOW:
+    case WRITE_6:           case WRITE_10:        case WRITE_VERIFY:
+    case 0x3f:              case 0x41:            case 0xb1:
+    case 0xb0:              case 0xb2:            case 0xaa:
+    case 0xae:              case 0x24:            case 0x38:
+    case 0x3d:              case 0xb6:            
+    case 0xea:		/* alternate number for WRITE LONG */
 	cp->DataOut = TRUE;	/* Output mode */
-    else
+        break;
+    case 0x00:
+    default:
 	cp->DataIn = TRUE;	/* Input mode  */
+    }
 
+    if (done == (void *) eata_scsi_done) 
+        cp->Interpret = TRUE;   /* Interpret command */
+   
     if (cmd->use_sg) {
 	cp->scatter = TRUE;	/* SG mode     */
 	cp->cp_dataDMA = htonl((long)&cp->sg_list);
@@ -303,7 +353,7 @@
     } else {
         cp->scatter = FALSE;
 	cp->cp_datalen = htonl(cmd->request_bufflen);
-	cp->cp_dataDMA = htonl((int)cmd->request_buffer);
+	cp->cp_dataDMA = htonl((ulong)cmd->request_buffer);
     }
 
     cp->Auto_Req_Sen = TRUE;
@@ -327,7 +377,7 @@
       printk("eata_queue target %d, pid %ld, HBA busy, returning DID_ERROR, done.\n",
               cmd->target, cmd->pid);
       restore_flags(flags);
-      done(cmd);
+      if(done != (void *)eata_scsi_done) done(cmd);
       return (0);
     }
     DBG(DBG_QUEUE,printk("Queued base %#.4lx pid: %ld target: %x lun: %x slot %d irq %d\n",
@@ -460,7 +510,7 @@
     }
 
     /* hard reset the HBA  */
-    inb((uint) (cmd->host->base) + HA_RSTATUS);   /* This might cause trouble */
+    inb((uint) (cmd->host->base) + HA_RSTATUS);  /* This might cause trouble */
     eata_send_command(0, (uint) cmd->host->base, EATA_CMD_RESET);
 
     DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n"));
@@ -511,7 +561,6 @@
     }
 }
 
-
 char * get_board_data(ulong base, uint irq, uint id)
 {
     struct eata_ccb cp;
@@ -580,7 +629,7 @@
 	if (--loop == 0) 
 	    return (FALSE);
        
-    DBG(DBG_PIO && DBG_PROBE, printk("Issuing PIO READ CONFIG to HBA at %lx\n", 
+    DBG(DBG_PIO && DBG_PROBE,printk("Issuing PIO READ CONFIG to HBA at %lx\n", 
 				   (long)base));
     eata_send_command(0, (uint) base, EATA_CMD_PIO_READ_CONFIG);
     loop = R_LIMIT;
@@ -645,19 +694,31 @@
 	return (FALSE);
     }
 
+    if ((buff = get_board_data((uint)base, gc->IRQ, gc->scsi_id[3])) == NULL){
+        printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (ulong) base);
+	return (FALSE);
+    }
+
+    if(gc->HAA_valid == FALSE || ntohl(gc->len) == 0x1c || ntohl(gc->len) == 0x1e) 
+        gc->MAX_CHAN = 0;
+
+    if(strncmp("PM2322", &buff[16], 6) && strncmp("PM3021", &buff[16], 6)
+         && strncmp("PM3222", &buff[16], 6) && strncmp("PM3224", &buff[16], 6))
+        gc->MAX_CHAN = 0;
+
     /* if gc->DMA_valid it must be a PM2011 and we have to register it */
-    dma_channel = (8 - gc->DMA_channel) & 7;
+    dma_channel = 0xff;
     if (gc->DMA_valid) {
-	if (request_dma(dma_channel, "DPT_PM2011")) {
+	if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "DPT_PM2011")) {
 	    printk("Unable to allocate DMA channel %d for HBA PM2011.\n",
 		dma_channel);
 	    return (FALSE);
 	}
-    }
-
+    } 
+    
     if (!reg_IRQ[gc->IRQ]) {	/* Interrupt already registered ? */
 	if (!request_irq(gc->IRQ, eata_int_handler, SA_INTERRUPT, "EATA-DMA")){
-	    reg_IRQ[gc->IRQ]++;
+	    reg_IRQ[gc->IRQ] += (gc->MAX_CHAN+1);
 	    if (!gc->IRQ_TR)
 		reg_IRQL[gc->IRQ] = TRUE;	/* IRQ is edge triggered */
 
@@ -674,28 +735,17 @@
 		   "  if the IRQ is edge triggered. Sorry.\n");
 	    return (FALSE);
 	} else
-	    reg_IRQ[gc->IRQ]++;
+	    reg_IRQ[gc->IRQ] += (gc->MAX_CHAN+1);
     }
 
     request_region(base, 9, "eata_dma");
 
-    if ((buff = get_board_data((uint)base, gc->IRQ, gc->scsi_id[3])) == NULL){
-        printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (ulong) base);
-	return (FALSE);
-    }
-
     if(ntohs(gc->queuesiz) == 0) {
         gc->queuesiz = ntohs(64);
 	    printk("Warning: Queue size had to be corrected.\n"
 		   "This might be a PM2012 with a defective Firmware\n");
     }
 
-    if(gc->HAA_valid == FALSE || ntohl(gc->len) == 0x1c || ntohl(gc->len) == 0x1e) 
-        gc->MAX_CHAN = 0;
-
-    if(strncmp("PM2322", &buff[16], 6) && strncmp("PM3021", &buff[16], 6)
-         && strncmp("PM3222", &buff[16], 6) && strncmp("PM3224", &buff[16], 6))
-        gc->MAX_CHAN = 0;
     
     size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/
 			       (gc->MAX_CHAN + 1));
@@ -712,7 +762,8 @@
 
 	memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)) / 
 	       (gc->MAX_CHAN + 1));
-
+        memset(hd->reads, 0, sizeof(ulong) * 26); 
+ 
 	strncpy(SD(sh)->vendor, &buff[8], 8);
 	SD(sh)->vendor[8] = 0;
 	strncpy(SD(sh)->name, &buff[16], 17);
@@ -737,14 +788,11 @@
 	    SD(sh)->EATA_revision = '?';
  	}
 	sh->base = (char *) base;
-	sh->irq = gc->IRQ;
-	if (gc->DMA_valid) 
-	  sh->dma_channel = dma_channel;
-	else 
-	  sh->dma_channel = 0;
-
+	sh->io_port = (ushort) base;
+	sh->n_io_port = 9;
+ 	sh->irq = gc->IRQ;
+	sh->dma_channel = dma_channel;
 	sh->this_id = gc->scsi_id[3 - i];
-
 	sh->can_queue = ntohs(gc->queuesiz) / (gc->MAX_CHAN + 1);
 
 	if (gc->OCS_enabled == TRUE) {
@@ -761,7 +809,6 @@
 	        printk("Warning: SG size had to be corrected.\n"
 		       "This might be a PM2012 with a defective Firmware\n");
 	}
-	sh->loaded_as_module = 0;	/* Not yet supported */
 
 	hd->channel = i;
 
@@ -803,7 +850,8 @@
 	if(hd->prev != NULL)
 	    SD(hd->prev)->next = sh;
 	last_HBA = sh;
-	
+	if (first_HBA == NULL)
+	    first_HBA = sh;
 	registered_HBAs++;
     }
     return (1);
@@ -863,7 +911,7 @@
 
     for (l = 0; l < MAXISA; l++) {	
         if (ISAbases[l]) {	
-	    if (get_conf_PIO((struct eata_register *)ISAbases[l], buf) == TRUE){
+	    if (get_conf_PIO((struct eata_register *)ISAbases[l],buf) == TRUE){
 	        ret = ISAbases[l];
 		ISAbases[l] = 0;
 		return (ret);
@@ -920,7 +968,7 @@
 	    }
 
 	    if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn,
-						  PCI_BASE_ADDRESS_0, &base))) {
+						  PCI_BASE_ADDRESS_0, &base))){
 
 	        /* Check if the address is valid */
 	        if (base & 0x01) {
@@ -1005,23 +1053,18 @@
 	if (reg_IRQ[i])
 	    request_irq(i, eata_int_handler, SA_INTERRUPT, "EATA-DMA");
 
-    HBA_ptr = last_HBA;
-    for (i = 1; i < registered_HBAs; i++)
-        HBA_ptr = SD(HBA_ptr)->prev;
+    HBA_ptr = first_HBA;
 
     printk("Registered HBAs:\n");
     printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: ID: Pr: QS: SG: CPL:\n");
     for (i = 1; i <= registered_HBAs; i++) {
-        printk("scsi%-2d: %.10s v%s 2.0%c  ", HBA_ptr->host_no, 
-	       SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
-	       SD(HBA_ptr)->EATA_revision);
-	if(SD(HBA_ptr)->bustype == 'P') printk("PCI "); 
-	else if(SD(HBA_ptr)->bustype == 'E') printk("EISA"); 
-	else printk("ISA ");
-	printk(" %#.4x   %2d   %2d   %d   %d   %d  %2d  %2d   %2d\n", 
-	       (uint) HBA_ptr->base, HBA_ptr->irq, HBA_ptr->dma_channel, SD(HBA_ptr)->channel, 
-	       HBA_ptr->this_id, SD(HBA_ptr)->primary, HBA_ptr->can_queue, 
-	       HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+        printk("scsi%-2d: %.10s v%s 2.0%c  %s %#.4x   %2d   %2x   %d   %d   %d  %2d  %2d   %2d\n", 
+	       HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
+	       SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')? 
+	       "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
+	       (uint) HBA_ptr->base, HBA_ptr->irq, HBA_ptr->dma_channel, 
+	       SD(HBA_ptr)->channel, HBA_ptr->this_id, SD(HBA_ptr)->primary, 
+	       HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
         HBA_ptr = SD(HBA_ptr)->next;
     }
     DBG(DPT_DEBUG,DELAY(1200));
@@ -1029,5 +1072,11 @@
     return (registered_HBAs);
 }
 
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = EATA_DMA;
 
+#include "scsi_module.c"
+#endif
+ 
 
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h
--- v1.1.88/linux/drivers/scsi/eata_dma.h	Mon Jan 30 06:41:57 1995
+++ linux/drivers/scsi/eata_dma.h	Wed Feb  1 20:02:39 1995
@@ -2,7 +2,7 @@
 * Header file for eata_dma.c Linux EATA-DMA SCSI driver *
 * (c) 1993,94,95 Michael Neuffer                        *
 *********************************************************
-* last change: 95/01/16                                 *
+* last change: 95/01/30                                 *
 ********************************************************/
 
 
@@ -15,8 +15,8 @@
 #include <linux/scsicam.h>
 
 #define VER_MAJOR 2
-#define VER_MINOR 1
-#define VER_SUB   "0i"
+#define VER_MINOR 3
+#define VER_SUB   "0a"
 
 /************************************************************************
  * Here you can configure your drives that are using a non-standard     *
@@ -65,6 +65,7 @@
 #define DBG_QUEUE	0	/* Trace command queueing. 		*/
 #define DBG_INTR	0       /* Trace interrupt service routine. 	*/
 #define DBG_INTR2	0       /* Trace interrupt service routine. 	*/
+#define DBG_PROC        0       /* Debug proc-fs related statistics     */
 #define DBG_REGISTER    0       /* */
 #define DBG_ABNORM	1	/* Debug abnormal actions (reset, abort)*/
 
@@ -79,7 +80,7 @@
 	NULL, NULL,                  \
         "EATA (Extended Attachment) driver", \
         eata_detect,                 \
-        NULL,                        \
+        eata_release,                \
         eata_info,                   \
         eata_command,                \
         eata_queue,                  \
@@ -101,7 +102,7 @@
 int eata_queue(Scsi_Cmnd *, void *(done)(Scsi_Cmnd *));
 int eata_abort(Scsi_Cmnd *);
 int eata_reset(Scsi_Cmnd *);
-
+int eata_release(struct Scsi_Host *);
 
 /*********************************************
  * Misc. definitions                         *
@@ -127,8 +128,24 @@
 #define MAX_PCI_BUS       16             /* Maximum # Of Busses Allowed    */
 
 #define SG_SIZE           64 
-#define C_P_L_DIV          8             /* 1 <= C_P_L_DIV <= 8            */
-#define C_P_L_CURRENT_MAX  2             /* Until this limit is removed    */
+
+#define C_P_L_CURRENT_MAX 10  /* Until this limit in the mm is removed    
+			       * Kernels < 1.1.86 died horrible deaths
+			       * if you used values >2. The memory management
+			       * of pl.86 seems to cope with 10. 
+			       */
+#define C_P_L_DIV          4  /* 1 <= C_P_L_DIV <= 8            
+			       * You can use this parameter to fine-tune
+			       * the driver. Depending on the number of 
+			       * devices and their ablilty to queue commands
+			       * you will get the best results with a value
+			       * ~= numdevices-(devices_unable_to_queue_commands/2)
+			       * The reason for this is that the disk driver tents 
+			       * to flood the queue, so that other drivers have 
+			       * problems to queue commands themselves. This can 
+			       * for example result in the effect that the tape
+			       * stops during disk accesses. 
+			       */
 
 #define FREE       0
 #define USED       1
@@ -210,7 +227,7 @@
   unchar data_reg[2];     	/* R, couldn't figure this one out          */
   unchar cp_addr[4];      	/* W, CP address register                   */
   union { 
-    unchar command;     	        /* W, command code: [read|set] conf, send CP*/
+    unchar command;     	/* W, command code: [read|set] conf, send CP*/
     struct reg_bit status;	/* R, see register_bit1                     */
     unchar statusunchar;
   } ovr;   
@@ -319,8 +336,7 @@
 };
 
 
-struct eata_sp
-{
+struct eata_sp {
   unchar hba_stat:7,          /* HBA status                     */
               EOC:1;          /* True if command finished       */
   unchar scsi_stat;           /* Target SCSI status             */       
@@ -330,7 +346,7 @@
   unchar msg[12];
 };
 
-typedef struct hstd{
+typedef struct hstd {
   char   vendor[9];
   char   name[18];
   char   revision[6];
@@ -338,9 +354,11 @@
   unchar bustype;              /* bustype of HBA             */
   unchar channel;              /* no. of scsi channel        */
   unchar state;                /* state of HBA               */
+  unchar primary;              /* true if primary            */
+  ulong  reads[13];
+  ulong  writes[13];
   unchar t_state[MAXTARGET];   /* state of Target (RESET,..) */
   uint   t_timeout[MAXTARGET]; /* timeouts on target         */
-  unchar primary;              /* true if primary            */
   uint   last_ccb;             /* Last used ccb              */
   struct Scsi_Host *next;         
   struct Scsi_Host *prev;
@@ -366,28 +384,5 @@
   int bios_drives;               /* number of emulated drives */
   struct drive_geom_emul drv[2]; /* drive structures          */
 };
-
-struct lun_map {
-  unchar   id:5,
-         chan:3;
-  unchar lun;
-};
-
-typedef struct emul_pp {
-  unchar p_code:6,
-           null:1,
-         p_save:1;
-  unchar p_length;
-  ushort cylinder;
-  unchar heads;
-  unchar sectors;
-  unchar null2;
-  unchar s_lunmap:4,
-              ems:1;
-  ushort drive_type;   /* In Little Endian ! */
-  struct lun_map lunmap[4];
-}emulpp;
-
-
 
 #endif /* _EATA_H */
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.1.88/linux/drivers/scsi/hosts.c	Thu Jan 26 07:49:06 1995
+++ linux/drivers/scsi/hosts.c	Sun Feb  5 14:44:39 1995
@@ -249,6 +249,8 @@
 	retval->host_wait = NULL;
 	retval->last_reset = 0;
 	retval->irq = 0;
+	retval->dma_channel = 0xff;
+	retval->io_port = 0;
 	retval->forbidden_addr = 0;
 	retval->forbidden_size = 0;
 	retval->hostt = tpnt;
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v1.1.88/linux/drivers/scsi/hosts.h	Fri Jan 13 16:57:05 1995
+++ linux/drivers/scsi/hosts.h	Wed Feb  1 19:36:35 1995
@@ -303,6 +303,7 @@
 unsigned int scsi_init(void);
 extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j);
 extern void scsi_unregister(struct Scsi_Host * i);
+extern int scsicam_bios_param (Disk *, int, int *);
 
 #define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/qlogic.c linux/drivers/scsi/qlogic.c
--- v1.1.88/linux/drivers/scsi/qlogic.c	Thu Jan 26 07:49:06 1995
+++ linux/drivers/scsi/qlogic.c	Sun Feb  5 14:48:46 1995
@@ -4,32 +4,35 @@
    Use at your own risk.  Support Tort Reform so you won't have to read all
    these silly disclaimers.
 
-   Copyright 1994, Tom Zerucha.
+   Copyright 1994, Tom Zerucha.   
    zerucha@shell.portal.com
 
    Additional Code, and much appreciated help by
    Michael A. Griffith
    grif@cs.ucr.edu
 
+   Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
+   help respectively, and for suffering through my foolishness during the
+   debugging process.
+
    Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
    (you can reference it, but it is incomplete and inaccurate in places)
 
-   Version 0.38b
+   Version 0.39a
 
-   This also works with loadable SCSI as a module.  Check configuration
-   options QL_INT_ACTIVE_HIGH and QL_TURBO_PDMA for PCMCIA usage (which
-   also requires an enabler).
+   Functions as standalone, loadable, and PCMCIA driver, the latter from
+   Dave Hind's PCMCIA package.
 
    Redistributable under terms of the GNU Public License
 
 */
 /*----------------------------------------------------------------*/
 /* Configuration */
-/* Set this if you are using the PCMCIA adapter - it will automatically
-   take care of several settings */
-#define QL_PCMCIA 0
 
-/* Set the following to 2 to use normal interrupt (active high/totempole-
+/* The following option is normally left alone.  PCMCIA support needs to
+   change this to adapt to the different way the interrupt pin works.
+   
+   Set the following to 2 to use normal interrupt (active high/totempole-
    tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
    drain */
 #define QL_INT_ACTIVE_HIGH 2
@@ -39,16 +42,18 @@
 #define QL_USE_IRQ 1
 
 /* Set the following to max out the speed of the PIO PseudoDMA transfers,
-   again, 0 tends to be slower, but more stable.  THIS SHOULD BE ZERO FOR
-   PCMCIA */
+   again, 0 tends to be slower, but more stable.  */
 #define QL_TURBO_PDMA 1
 
 /* This will reset all devices when the driver is initialized (during bootup).
    The other linux drivers don't do this, but the DOS drivers do, and after
-   using DOS or some kind of crash or lockup this will bring things back */
+   using DOS or some kind of crash or lockup this will bring things back
+   without requiring a cold boot.  It does take some time to recover from a
+   reset, so it is slower, and I have seen timeouts so that devices weren't
+   recognized when this was set. */
 #define QL_RESET_AT_START 1
 
-/* This will set fast (10Mhz) synchronous timing, FASTCLK must also be 1*/
+/* This will set fast (10Mhz) synchronous timing, FASTCLK must also be 1 */
 #define FASTSCSI  0
 
 /* This will set a faster sync transfer rate */
@@ -72,13 +77,10 @@
 	cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
 	the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
 
-/* Option Synchronization */
-	
-#if QL_PCMCIA
+/* PCMCIA option adjustment */
+#ifdef PCMCIA
 #undef QL_INT_ACTIVE_HIGH
-#undef QL_TURBO_PDMA
 #define QL_INT_ACTIVE_HIGH 0
-#define QL_TURBO_PDMA 0
 #endif
 
 /*----------------------------------------------------------------*/
@@ -109,11 +111,11 @@
 static Scsi_Cmnd   *qlcmd;	/* current command being processed */
 
 /*----------------------------------------------------------------*/
-
+/* The qlogic card uses two register maps - These macros select which one */
 #define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
 #define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
 
-/* following is watchdog timeout */
+/* following is watchdog timeout in microseconds */
 #define WATCHDOG 5000000
 
 /*----------------------------------------------------------------*/
@@ -414,7 +416,9 @@
 	if (!(inb(qbase + 4) & 0x80))	/* false alarm? */
 		return;
 	if (qlcmd == NULL) {		/* no command to process? */
-		while (inb(qbase + 5)); /* maybe also ql_zap() */
+		int	i;
+		i = 16;
+		while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */
 		return;
 	}
 	icmd = qlcmd;
@@ -489,22 +493,15 @@
 
 /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the
    address - I check 230 first since MIDI cards are typically at 330
-   Note that this will not work for 2 Qlogic cards in 1 system.  The
-   easiest way to do that is to create 2 versions of this file, one for
-   230 and one for 330.
-
-   Alternately, the Scsi_Host structure now stores the i/o port and can
-   be used to set the port (go through and replace qbase with
-   (struct Scsi_Cmnd *) cmd->host->io_port, or for efficiency, set a local
-   copy of qbase.  There will also need to be something similar within the
-   IRQ handlers to sort out which board it came from and thus which port.
+
+   Theoretically, two Qlogic cards can coexist in the same system.  This
+   should work by simply using this as a loadable module for the second
+   card, but I haven't tested this.
 */
 
 	for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
-#ifndef PCMCIA
 		if( check_region( qbase , 0x10 ) )
 			continue;
-#endif			
 		REG1;
 		if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
 		  && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
@@ -548,20 +545,19 @@
 	while (inb(qbase + 5)); 			/* purge int */
 	while (i)					/* find on bit */
 		i >>= 1, qlirq++;	/* should check for exactly 1 on */
-	if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, SA_INTERRUPT, "qlogic"))
+	if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic"))
 		host->can_queue = 1;
 	restore_flags( flags );
 #endif
-#ifndef PCMCIA
 	request_region( qbase , 0x10 ,"qlogic");
-#endif
 	hreg = scsi_register( host , 0 );	/* no host data */
 	hreg->io_port = qbase;
 	hreg->n_io_port = 16;
+	hreg->dma_channel = -1;
 	if( qlirq != -1 )
 		hreg->irq = qlirq;
 
-	sprintf(qinfo, "Qlogic Driver version 0.38b, chip %02X at %03X, IRQ %d, Opts:%d%d",
+	sprintf(qinfo, "Qlogic Driver version 0.39a, chip %02X at %03X, IRQ %d, Opts:%d%d",
 	    qltyp, qbase, qlirq, QL_INT_ACTIVE_HIGH, QL_TURBO_PDMA );
 	host->name = qinfo;
 
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.1.88/linux/drivers/scsi/scsi.c	Wed Feb  1 09:23:06 1995
+++ linux/drivers/scsi/scsi.c	Sun Feb  5 14:44:39 1995
@@ -145,6 +145,7 @@
    {"CHINON","CD-ROM CDS-431","H42"},  /* Locks up if polled for lun != 0 */
    {"CHINON","CD-ROM CDS-535","Q14"}, /* Lockup if polled for lun != 0 */
    {"DENON","DRD-25X","V"},   /* A cdrom that locks up when probed at lun != 0 */
+   {"HITACHI","DK314C","CR21" }, /* responds to all lun */
    {"IMS", "CDD521/10","2.06"},   /* Locks-up when LUN>0 polled. */
    {"MAXTOR","XT-3280","PR02"},   /* Locks-up when LUN>0 polled. */
    {"MAXTOR","XT-4380S","B3C"},   /* Locks-up when LUN>0 polled. */
@@ -227,10 +228,10 @@
 	  up(SCpnt->request.sem);
 	}
 
-#ifdef NO_MULTI_LUN
-static int max_scsi_luns = 1;
-#else
+#ifdef CONFIG_SCSI_MULTI_LUN
 static int max_scsi_luns = 8;
+#else
+static int max_scsi_luns = 1;
 #endif
 
 void scsi_luns_setup(char *str, int *ints) {
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.1.88/linux/drivers/scsi/scsi.h	Sun Jan  1 15:44:03 1995
+++ linux/drivers/scsi/scsi.h	Wed Feb  1 20:02:39 1995
@@ -126,6 +126,7 @@
 #define INTERMEDIATE_GOOD	0x08
 #define INTERMEDIATE_C_GOOD	0x0a
 #define RESERVATION_CONFLICT	0x0c
+#define QUEUE_FULL              0x1a
 
 #define STATUS_MASK		0x1e
 	
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.1.88/linux/drivers/scsi/sd.c	Wed Feb  1 09:23:06 1995
+++ linux/drivers/scsi/sd.c	Sun Feb  5 14:44:39 1995
@@ -86,12 +86,6 @@
 	if(target >= sd_template.dev_max || !rscsi_disks[target].device)
 	  return -ENXIO;   /* No such device */
 	
-	/*
-	 * See if we are requesting a non-existent partition.
-	 */
-	if(sd_sizes[MINOR(inode->i_rdev)] == 0)
-	  return -ENXIO;
-
 /* Make sure that only one process can do a check_change_disk at one time.
  This is also used to lock out further access when the partition table is being re-read. */
 
@@ -103,6 +97,13 @@
 	  if(!rscsi_disks[target].device->access_count)
 	    sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
 	};
+	/*
+	 * See if we are requesting a non-existent partition.  Do this
+	 * after checking for disk change.
+	 */
+	if(sd_sizes[MINOR(inode->i_rdev)] == 0)
+	  return -ENXIO;
+
 	rscsi_disks[target].device->access_count++;
 	if (rscsi_disks[target].device->host->hostt->usage_count)
 	  (*rscsi_disks[target].device->host->hostt->usage_count)++;
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v1.1.88/linux/drivers/scsi/sg.c	Thu Jan 26 07:49:06 1995
+++ linux/drivers/scsi/sg.c	Wed Feb  1 19:36:35 1995
@@ -313,7 +313,7 @@
   printk("do cmd\n");
 #endif
   scsi_do_cmd (SCpnt,(void *) cmnd,
-               (void *) device->buff,device->header.pack_len-size-sizeof(struct sg_header),
+               (void *) device->buff,amt,
 	       sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
 #ifdef DEBUG
   printk("done cmd\n");
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v1.1.88/linux/drivers/scsi/sr_ioctl.c	Thu Jan 26 07:49:07 1995
+++ linux/drivers/scsi/sr_ioctl.c	Sun Feb  5 14:44:39 1995
@@ -15,7 +15,7 @@
 
 #define IOCTL_RETRIES 3
 /* The CDROM is fairly slow, so we need a little extra time */
-#define IOCTL_TIMEOUT 200
+#define IOCTL_TIMEOUT 2000
 
 extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
 
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.1.88/linux/drivers/scsi/st.c	Mon Jan 30 08:53:06 1995
+++ linux/drivers/scsi/st.c	Wed Feb  1 08:32:26 1995
@@ -11,7 +11,7 @@
   Copyright 1992, 1993, 1994, 1995 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Thu Jan 19 23:28:05 1995 by makisara@kai.home
+  Last modified: Mon Jan 30 23:20:07 1995 by root@kai.home
 */
 
 #include <linux/fs.h>
@@ -894,7 +894,8 @@
       else
 	(STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
 	  STp->block_size) * STp->block_size;
-      STp->dirty = 0;
+      STp->dirty = !((STp->buffer)->writing ==
+		     (STp->buffer)->buffer_bytes);
 
       if (STp->block_size == 0)
 	blks = (STp->buffer)->writing;
@@ -1612,18 +1613,30 @@
        STp->drv_block = 0;
      }
      else if (cmd_in == MTFSR) {
-       if (blkno >= undone)
-	 STp->drv_block = blkno - undone;
-       else
-	 STp->drv_block = (-1);
+       if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
+	 (STp->mt_status)->mt_fileno++;
+	 STp->drv_block = 0;
+       }
+       else {
+	 if (blkno >= undone)
+	   STp->drv_block = blkno - undone;
+	 else
+	   STp->drv_block = (-1);
+       }
      }
      else if (cmd_in == MTBSR) {
-       if (blkno >= 0)
-	 STp->drv_block = blkno + undone;
-       else
+       if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
+	 (STp->mt_status)->mt_fileno--;
 	 STp->drv_block = (-1);
+       }
+       else {
+	 if (blkno >= 0)
+	   STp->drv_block = blkno + undone;
+	 else
+	   STp->drv_block = (-1);
+       }
      }
-     else if (cmd_in == MTEOM) {
+     else if (cmd_in == MTEOM || cmd_in == MTSEEK) {
        (STp->mt_status)->mt_fileno = (-1);
        STp->drv_block = (-1);
      }
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v1.1.88/linux/drivers/scsi/u14-34f.c	Mon Jan 16 14:18:23 1995
+++ linux/drivers/scsi/u14-34f.c	Wed Feb  1 19:36:35 1995
@@ -1,6 +1,15 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      28 Jan 1995 rev. 1.14 for linux 1.1.86
+ *          Added module support.
+ *          Log and do a retry when a disk drive returns a target status
+ *          different from zero on a recovered error.
+ *          Auto detects if U14F boards have an old firmware revision.
+ *          Max number of scatter/gather lists set to 16 for all boards
+ *          (most installation run fine using 33 sglists, while other
+ *          has problems when using more then 16).
+ *
  *      16 Jan 1995 rev. 1.13 for linux 1.1.81
  *          Display a message if check_region detects a port address
  *          already in use.
@@ -9,7 +18,7 @@
  *          The host->block flag is set for all the detected ISA boards.
  *
  *      30 Nov 1994 rev. 1.11 for linux 1.1.68
- *          Redo i/o on target status CONDITION_GOOD for TYPE_DISK only.
+ *          Redo i/o on target status CHECK_CONDITION for TYPE_DISK only.
  *          Added optional support for using a single board at a time.
  *
  *      14 Nov 1994 rev. 1.10 for linux 1.1.63
@@ -54,8 +63,8 @@
  *
  *  Here a sample configuration using two U14F boards:
  *
- U14F0: PORT 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 33, Mbox 16, CmdLun 2, C1.
- U14F1: PORT 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 33, Mbox 16, CmdLun 2, C1.
+ U14F0: PORT 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 16, Mbox 16, CmdLun 2, C1.
+ U14F1: PORT 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 16, Mbox 16, CmdLun 2, C1.
  *
  *  The boot controller must have its BIOS enabled, while other boards can
  *  have their BIOS disabled, or enabled to an higher address.
@@ -96,13 +105,16 @@
  *    when DISABLE_CLUSTERING is in effect, but unscattered requests could be
  *    larger than 16Kbyte.
  *
- *    The new firmware has fixed all the above problems and has been tested 
- *    with up to 33 scatter/gather lists.
+ *    The new firmware has fixed all the above problems.
  *
  *  In order to support multiple ISA boards in a reliable way,
  *  the driver sets host->block = TRUE for all ISA boards.
  */
 
+#if defined(MODULE)
+#include <linux/module.h>
+#endif
+
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -137,17 +149,6 @@
 #define HA_CMD_READ_BUFF  0x3
 #define HA_CMD_WRITE_BUFF 0x4
 
-#if defined (HAVE_OLD_U14F_FIRMWARE)
-#define U14F_MAX_SGLIST 16
-#define U14F_CLUSTERING DISABLE_CLUSTERING
-#else
-#define U14F_MAX_SGLIST 33
-#define U14F_CLUSTERING ENABLE_CLUSTERING
-#endif
-
-#define U34F_MAX_SGLIST 33
-#define U34F_CLUSTERING ENABLE_CLUSTERING
-
 #undef  DEBUG_DETECT
 #undef  DEBUG_INTERRUPT
 #undef  DEBUG_STATISTICS
@@ -156,7 +157,7 @@
 #define MAX_IRQ 16
 #define MAX_BOARDS 4
 #define MAX_MAILBOXES 16
-#define MAX_SGLIST 33
+#define MAX_SGLIST 16
 #define MAX_CMD_PER_LUN 2
 
 #define FALSE 0
@@ -165,8 +166,10 @@
 #define IN_USE   1
 #define LOCKED   2
 #define IN_RESET 3
+#define IGNORE   4
 #define NO_IRQ  0xff
-#define MAXLOOP 20000
+#define NO_DMA  0xff
+#define MAXLOOP 200000
 
 #define REG_LCL_MASK      0
 #define REG_LCL_INTR      1
@@ -178,9 +181,9 @@
 #define REG_CONFIG2       7
 #define REG_OGM           8
 #define REG_ICM           12
-#define REG_REGION        0x0c
+#define REGION_SIZE       13
 #define BSY_ASSERTED      0x01
-#define INTR_ASSERTED     0x01
+#define IRQ_ASSERTED      0x01
 #define CMD_RESET         0xc0
 #define CMD_OGM_INTR      0x01
 #define CMD_CLR_INTR      0x01
@@ -230,13 +233,13 @@
    unsigned int multicount;             /* Total ... in second ihdlr loop */
    int board_number;                    /* Number of this board */
    char board_name[16];                 /* Name of this board */
+   char board_id[256];                  /* data from INQUIRY on this board */
    int in_reset;                        /* True if board is doing a reset */
    int target_time_out[MAX_TARGET];     /* N. of timeout errors on target */
    int target_reset[MAX_TARGET];        /* If TRUE redo operation on target */
-   unsigned char bios_drive_number: 1;
+   unsigned char subversion;            /* Bus type, either ISA or ESA */
    unsigned char heads;
    unsigned char sectors;
-   unsigned char subversion: 4;         /* Bus type, either ISA or ESA */
 
    /* slot != 0 for the U24F, slot == 0 for both the U14F and U34F */
    unsigned char slot;
@@ -261,6 +264,49 @@
    return FALSE;
 }
 
+static int board_inquiry(unsigned int j) {
+   struct mscp *cpp;
+   unsigned int time, limit = 0;
+
+   cpp = &HD(j)->cp[0];
+   memset(cpp, 0, sizeof(struct mscp));
+   cpp->opcode = OP_HOST_ADAPTER;
+   cpp->xdir = DTD_IN;
+   cpp->data_address = (unsigned int) HD(j)->board_id;
+   cpp->data_len = sizeof(HD(j)->board_id);
+   cpp->scsi_cdbs_len = 6;
+   cpp->scsi_cdbs[0] = HA_CMD_INQUIRY;
+
+   if (wait_on_busy(sh[j]->io_port)) {
+      printk("%s: board_inquiry, adapter busy.\n", BN(j));
+      return TRUE;
+      }
+
+   HD(j)->cp_stat[0] = IGNORE;
+
+   /* Clear the interrupt indication */
+   outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
+
+   /* Store pointer in OGM address bytes */
+   outl((unsigned int)cpp, sh[j]->io_port + REG_OGM);
+
+   /* Issue OGM interrupt */
+   outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
+
+   sti();
+   time = jiffies;
+   while (jiffies < (time + 100) && limit++ < 100000000) sti();
+   cli();
+
+   if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
+      HD(j)->cp_stat[0] = FREE;
+      printk("%s: board_inquiry, err 0x%x.\n", BN(j), cpp->adapter_status);
+      return TRUE;
+      }
+
+   return FALSE;
+}
+
 static inline int port_detect(ushort *port_base, unsigned int j, 
                               Scsi_Host_Template * tpnt) {
    unsigned char irq, dma_channel, subversion;
@@ -305,8 +351,8 @@
 
    sprintf(name, "%s%d", driver_name, j);
 
-   if(check_region(*port_base, REG_REGION)) {
-      printk("%s: address 0x%03x already in use, detaching.\n", 
+   if(check_region(*port_base, REGION_SIZE)) {
+      printk("%s: address 0x%03x in use, skipping probe.\n", 
              name, *port_base);
       return FALSE;
       }
@@ -340,8 +386,10 @@
 
    sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
    sh[j]->io_port = *port_base;
+   sh[j]->n_io_port = REGION_SIZE;
    sh[j]->base = bios_segment_table[config_1.bios_segment];
    sh[j]->irq = irq;
+   sh[j]->sg_tablesize = MAX_SGLIST;
    sh[j]->this_id = config_2.ha_scsi_id;
    sh[j]->can_queue = MAX_MAILBOXES;
    sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
@@ -360,29 +408,36 @@
    if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK);
 
    /* Register the I/O space that we use */
-   request_region(sh[j]->io_port, REG_REGION, driver_name);
+   request_region(sh[j]->io_port, REGION_SIZE, driver_name);
 
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->heads = mapping_table[config_2.mapping_mode].heads;
    HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors;
-   HD(j)->bios_drive_number = config_2.bios_drive_number;
    HD(j)->subversion = subversion;
    HD(j)->board_number = j;
    irqlist[irq] = j;
 
    if (HD(j)->subversion == ESA) {
-      sh[j]->dma_channel = 0;
+      sh[j]->dma_channel = NO_DMA;
       sh[j]->unchecked_isa_dma = FALSE;
-      sh[j]->sg_tablesize = U34F_MAX_SGLIST;
-      sh[j]->hostt->use_clustering = U34F_CLUSTERING;
+      sh[j]->hostt->use_clustering = ENABLE_CLUSTERING;
       sprintf(BN(j), "U34F%d", j);
       }
    else {
-      sh[j]->dma_channel = dma_channel;
+
+#if !defined(MODULE)
+      /* The module code does not checkin/checkout in the blocking list yet */
       sh[j]->block = sh[j];
+#endif
+
+#if defined (HAVE_OLD_U14F_FIRMWARE)
+      sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
+#else
+      sh[j]->hostt->use_clustering = ENABLE_CLUSTERING;
+#endif
+
+      sh[j]->dma_channel = dma_channel;
       sh[j]->unchecked_isa_dma = TRUE;
-      sh[j]->sg_tablesize = U14F_MAX_SGLIST;
-      sh[j]->hostt->use_clustering = U14F_CLUSTERING;
       sprintf(BN(j), "U14F%d", j);
       disable_dma(dma_channel);
       clear_dma_ff(dma_channel);
@@ -390,6 +445,17 @@
       enable_dma(dma_channel);
       }
 
+   if (HD(j)->subversion == ISA && !board_inquiry(j)) {
+      HD(j)->board_id[40] = 0;
+
+      if (strcmp(&HD(j)->board_id[32], "06000600")) {
+         printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
+         printk("%s: firmware %s is outdated, BIOS rev. should be 2.01.\n", 
+                BN(j), &HD(j)->board_id[32]);
+         sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
+         }
+      }
+
    printk("%s: PORT 0x%03x, BIOS 0x%05x, IRQ %u, DMA %u, SG %d, "\
           "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port, 
           (int)sh[j]->base, sh[j]->irq, 
@@ -716,7 +782,7 @@
 
 static void u14_34f_interrupt_handler(int irq, struct pt_regs * regs) {
    Scsi_Cmnd *SCpnt;
-   unsigned int i, j, k, flags, status, loops, total_loops = 0;
+   unsigned int i, j, k, flags, status, tstatus, loops, total_loops = 0;
    struct mscp *spp;
 
    save_flags(flags);
@@ -739,7 +805,7 @@
       loops = 0;
 
       /* Loop until all interrupts for a board are serviced */
-      while (inb(sh[j]->io_port + REG_SYS_INTR) & INTR_ASSERTED) {
+      while (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED) {
          total_loops++;
          loops++;
 
@@ -756,7 +822,11 @@
          if (i >= sh[j]->can_queue)
             panic("%s: ihdlr, invalid mscp address.\n", BN(j));
 
-         if (HD(j)->cp_stat[i] == LOCKED) {
+         if (HD(j)->cp_stat[i] == IGNORE) {
+            HD(j)->cp_stat[i] = FREE;
+            continue;
+            }
+         else if (HD(j)->cp_stat[i] == LOCKED) {
             HD(j)->cp_stat[i] = FREE;
             printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
                    BN(j), i, HD(j)->iocount);
@@ -787,29 +857,50 @@
                   " irq %d.\n", BN(j), i, SCpnt->pid, 
                   *(unsigned int *)SCpnt->host_scribble, irq);
 
+         tstatus = status_byte(spp->target_status);
+
          switch (spp->adapter_status) {
             case ASOK:     /* status OK */
 
-               /* Fix a "READ CAPACITY failed" error on some disk drives */
-               if (spp->target_status == INTERMEDIATE_GOOD
-                                     && SCpnt->device->type != TYPE_TAPE) 
+               /* Forces a reset if a disk drive keeps returning BUSY */
+               if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) 
                   status = DID_ERROR << 16;
 
                /* If there was a bus reset, redo operation on each target */
-               else if (spp->target_status == CONDITION_GOOD
-                                     && SCpnt->device->type == TYPE_DISK
-                                     && HD(j)->target_reset[SCpnt->target])
+               else if (tstatus != GOOD
+                        && SCpnt->device->type == TYPE_DISK
+                        && HD(j)->target_reset[SCpnt->target])
+                  status = DID_BUS_BUSY << 16;
+
+               /* Works around a flaw in scsi.c */
+               else if (tstatus == CHECK_CONDITION
+                        && SCpnt->device->type == TYPE_DISK
+                        && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
                   status = DID_BUS_BUSY << 16;
+
+               else if (tstatus == CHECK_CONDITION
+                        && (SCpnt->device->type == TYPE_DISK
+                         || SCpnt->device->type == TYPE_ROM)
+                        && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION)
+                  status = DID_ERROR << 16;
+   
                else
                   status = DID_OK << 16;
 
-               if (spp->target_status == 0)
+               if (tstatus == GOOD)
                   HD(j)->target_reset[SCpnt->target] = FALSE;
 
+               if (spp->target_status && (SCpnt->device->type == TYPE_DISK
+                                       || SCpnt->device->type == TYPE_ROM))
+                  printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
+                         "0x%x, sense key 0x%x.\n", BN(j), 
+                         SCpnt->target, SCpnt->lun, SCpnt->pid,
+                         spp->target_status, SCpnt->sense_buffer[2]);
+
                HD(j)->target_time_out[SCpnt->target] = 0;
 
                break;
-            case ASST:     /* SCSI bus selection time out */
+            case ASST:     /* Selection Time Out */
 
                if (HD(j)->target_time_out[SCpnt->target] > 1)
                   status = DID_ERROR << 16;
@@ -894,3 +985,9 @@
    restore_flags(flags);
    return;
 }
+
+#if defined(MODULE)
+Scsi_Host_Template driver_template = ULTRASTOR_14_34F;
+
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v1.1.88/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v1.1.88/linux/drivers/scsi/u14-34f.h	Mon Jan 16 14:18:23 1995
+++ linux/drivers/scsi/u14-34f.h	Wed Feb  1 19:36:35 1995
@@ -10,7 +10,7 @@
 int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_biosparam(Disk *, int, int *);
 
-#define U14_34F_VERSION "1.13.00"
+#define U14_34F_VERSION "1.14.05"
 
 #define ULTRASTOR_14_34F {                                            \
                 NULL,                                                 \
@@ -31,7 +31,7 @@
                 0,   /* sg_tablesize, reset by detect */              \
                 0,   /* cmd_per_lun, reset by detect */               \
 		0,   /* number of boards present */                   \
-                0,   /* unchecked isa dma, reset by detect */         \
+                1,   /* unchecked isa dma, reset by detect */         \
                 0,   /* use_clustering, reset by detect */            \
                 }
 #endif
diff -u --recursive --new-file v1.1.88/linux/fs/hpfs/Makefile linux/fs/hpfs/Makefile
--- v1.1.88/linux/fs/hpfs/Makefile	Wed Dec  1 14:44:15 1993
+++ linux/fs/hpfs/Makefile	Sun Feb  5 14:44:32 1995
@@ -14,10 +14,10 @@
 .s.o:
 	$(AS) -o $*.o $<
 
-OBJS=	hpfs_fs.o
+OBJS=	hpfs_fs.o hpfs_caps.o
 
 hpfs.o: $(OBJS)
-	ln -f hpfs_fs.o hpfs.o
+	$(LD) -r -o hpfs.o $(OBJS)
 
 dep:
 	$(CPP) -M *.c > .depend
diff -u --recursive --new-file v1.1.88/linux/fs/hpfs/hpfs_caps.c linux/fs/hpfs/hpfs_caps.c
--- v1.1.88/linux/fs/hpfs/hpfs_caps.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/hpfs/hpfs_caps.c	Sun Feb  5 14:44:32 1995
@@ -0,0 +1,161 @@
+/* Capitalization rules for HPFS */
+
+/* In OS/2, HPFS filenames preserve upper and lower case letter distinctions
+   but filename matching ignores case.  That is, creating a file "Foo"
+   actually creates a file named "Foo" which can be looked up as "Foo",
+   "foo", or "FOO", among other possibilities.
+
+   Also, HPFS is internationalized -- a table giving the uppercase
+   equivalent of every character is stored in the filesystem, so that
+   any national character set may be used.  If several different
+   national character sets are in use, several tables are stored
+   in the filesystem.
+
+   It would be perfectly reasonable for Linux HPFS to act as a Unix
+   filesystem and match "Foo" only if asked for "Foo" exactly.  But
+   the sort order of HPFS directories is case-insensitive, so Linux
+   still has to know the capitalization rules used by OS/2.  Because
+   of this, it turns out to be more natural for us to be case-insensitive
+   than not.
+
+   Currently the standard character set used by Linux is Latin-1.
+   Work is underway to permit people to use UTF-8 instead, therefore
+   all code that depends on the character set is segregated here.
+
+   (It would be wonderful if Linux HPFS could be independent of what
+   character set is in use on the Linux side, but because of the
+   necessary case folding this is impossible.)
+
+   There is a map from Latin-1 into code page 850 for every printing
+   character in Latin-1.  Most, maybe all, OS/2 installations have code
+   page 850 available, and surely all (on PC hardware) have 437 available.
+
+   It is not clear exactly how HPFS.IFS handles the situation when
+   multiple code pages are in use.  Experiments show that
+
+   - tables on the disk give uppercasing rules for the installed code pages
+
+   - each directory entry is tagged with what code page was current
+     when that name was created
+
+   - doing just CHCP, without changing what's on the disk in any way,
+     can change what DIR reports, and what name a case-folded match
+     will match.
+
+   This means, I think, that HPFS.IFS operates in the current code
+   page, without regard to the uppercasing information recorded in
+   the tables on the disk.  It does record the uppercasing rules
+   it used, perhaps for alien operating systems such as us, but it
+   does not appear to use them itself.
+
+   So: Linux, a Latin-1 system, will operate in code page 850.  We
+   recode between 850 and Latin-1 when dealing with the names actually
+   on the disk.  We don't use the uppercasing tables either.
+
+   In a hypothetical UTF-8 implementation, one reasonable way to
+   proceed that matches OS/2 (for least surprise) is: do case
+   translation in UTF-8, and recode to/from one of the code pages
+   available on the mounted filesystem.  Reject as invalid any name
+   containing chars that can't be represented on disk by one of the
+   code pages OS/2 is using.  Recoding from on-disk names to UTF-8
+   could use the code page tags, though this is not what OS/2 does. */
+
+static const unsigned char tb_cp850_to_latin1[128] =
+{
+  199, 252, 233, 226, 228, 224, 229, 231,
+  234, 235, 232, 239, 238, 236, 196, 197,
+  201, 230, 198, 244, 246, 242, 251, 249,
+  255, 214, 220, 248, 163, 216, 215, 159,
+  225, 237, 243, 250, 241, 209, 170, 186,
+  191, 174, 172, 189, 188, 161, 171, 187,
+  155, 156, 157, 144, 151, 193, 194, 192,
+  169, 135, 128, 131, 133, 162, 165, 147,
+  148, 153, 152, 150, 145, 154, 227, 195,
+  132, 130, 137, 136, 134, 129, 138, 164,
+  240, 208, 202, 203, 200, 158, 205, 206,
+  207, 149, 146, 141, 140, 166, 204, 139,
+  211, 223, 212, 210, 245, 213, 181, 254,
+  222, 218, 219, 217, 253, 221, 175, 180,
+  173, 177, 143, 190, 182, 167, 247, 184,
+  176, 168, 183, 185, 179, 178, 142, 160,
+};
+
+#if 0
+static const unsigned char tb_latin1_to_cp850[128] =
+{
+  186, 205, 201, 187, 200, 188, 204, 185,
+  203, 202, 206, 223, 220, 219, 254, 242,
+  179, 196, 218, 191, 192, 217, 195, 180,
+  194, 193, 197, 176, 177, 178, 213, 159,
+  255, 173, 189, 156, 207, 190, 221, 245,
+  249, 184, 166, 174, 170, 240, 169, 238,
+  248, 241, 253, 252, 239, 230, 244, 250,
+  247, 251, 167, 175, 172, 171, 243, 168,
+  183, 181, 182, 199, 142, 143, 146, 128,
+  212, 144, 210, 211, 222, 214, 215, 216,
+  209, 165, 227, 224, 226, 229, 153, 158,
+  157, 235, 233, 234, 154, 237, 232, 225,
+  133, 160, 131, 198, 132, 134, 145, 135,
+  138, 130, 136, 137, 141, 161, 140, 139,
+  208, 164, 149, 162, 147, 228, 148, 246,
+  155, 151, 163, 150, 129, 236, 231, 152,
+};
+#endif
+
+static inline unsigned latin1_upcase (unsigned c)
+{
+  if (c - (unsigned char) 'a' <= (unsigned char) 'z' - (unsigned char) 'a'
+      || (c - (unsigned char) '`' <= (unsigned char) '~' - (unsigned char) '`'
+	  && c != (unsigned char) 'w'))
+    return c - (unsigned char) 'a' + (unsigned char) 'A';
+  else
+    return c;
+}
+
+static inline unsigned latin1_downcase (unsigned c)
+{
+  if (c - (unsigned char) 'A' <= (unsigned char) 'Z' - (unsigned char) 'A'
+      || (c - (unsigned char) '@' <= (unsigned char) '^' - (unsigned char) '@'
+	  && c != (unsigned char) 'W'))
+    return c + (unsigned char) 'a' - (unsigned char) 'A';
+  else
+    return c;
+}
+
+#if 0
+static inline unsigned latin1_to_cp850 (unsigned c)
+{
+  if ((signed) c - 128 >= 0)
+    return tb_latin1_to_cp850[c - 128];
+  else
+    return c;
+}
+#endif
+
+static inline unsigned cp850_to_latin1 (unsigned c)
+{
+  if ((signed) c - 128 >= 0)
+    return tb_cp850_to_latin1[c - 128];
+  else
+    return c;
+}
+
+unsigned hpfs_char_to_upper_linux (unsigned c)
+{
+  return latin1_upcase (cp850_to_latin1 (c));
+}
+
+unsigned linux_char_to_upper_linux (unsigned c)
+{
+  return latin1_upcase (c);
+}
+
+unsigned hpfs_char_to_lower_linux (unsigned c)
+{
+  return latin1_downcase (cp850_to_latin1 (c));
+}
+
+unsigned hpfs_char_to_linux (unsigned c)
+{
+  return cp850_to_latin1 (c);
+}
diff -u --recursive --new-file v1.1.88/linux/fs/hpfs/hpfs_caps.h linux/fs/hpfs/hpfs_caps.h
--- v1.1.88/linux/fs/hpfs/hpfs_caps.h	Thu Jan  1 02:00:00 1970
+++ linux/fs/hpfs/hpfs_caps.h	Sun Feb  5 14:44:32 1995
@@ -0,0 +1,4 @@
+unsigned hpfs_char_to_linux (unsigned c);
+unsigned hpfs_char_to_lower_linux (unsigned c);
+unsigned hpfs_char_to_upper_linux (unsigned c);
+unsigned linux_char_to_upper_linux (unsigned c);
diff -u --recursive --new-file v1.1.88/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- v1.1.88/linux/fs/hpfs/hpfs_fs.c	Wed Oct 19 10:23:18 1994
+++ linux/fs/hpfs/hpfs_fs.c	Sun Feb  5 14:44:32 1995
@@ -25,6 +25,7 @@
 #include <asm/segment.h>
 
 #include "hpfs.h"
+#include "hpfs_caps.h"
 
 /* 
  * HPFS is a mixture of 512-byte blocks and 2048-byte blocks.  The 2k blocks
@@ -1209,12 +1210,8 @@
 
 	if (n != 0)
 		do {
-			unsigned c1 = *s1++;
-			unsigned c2 = *s2++;
-			if (c1 - 'a' < 26)
-				c1 -= 040;
-			if (c2 - 'a' < 26)
-				c2 -= 040;
+			unsigned c1 = linux_char_to_upper_linux (*s1++);
+			unsigned c2 = hpfs_char_to_upper_linux (*s2++);
 			if ((t = c1 - c2) != 0)
 				return t;
 		} while (--n != 0);
@@ -1394,15 +1391,14 @@
 	put_fs_long(ino, &dirent->d_ino);
 	put_fs_word(namelen, &dirent->d_reclen);
 
-	if (lowercase)
-		for (n = namelen; n != 0;) {
-			unsigned t = name[--n];
-			if (t - 'A' < 26)
-				t += 040;
-			put_fs_byte(t, &dirent->d_name[n]);
-		}
-	else
-		memcpy_tofs(dirent->d_name, name, namelen);
+	for (n = namelen; n != 0;) {
+		unsigned t = name[--n];
+		if (lowercase)
+			t = hpfs_char_to_lower_linux (t);
+		else
+			t = hpfs_char_to_linux (t);
+		put_fs_byte(t, &dirent->d_name[n]);
+	}
 
 	put_fs_byte(0, &dirent->d_name[namelen]);
 }
diff -u --recursive --new-file v1.1.88/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v1.1.88/linux/fs/proc/inode.c	Thu Jan 26 07:49:08 1995
+++ linux/fs/proc/inode.c	Sun Feb  5 14:44:40 1995
@@ -139,7 +139,24 @@
 		return;
 	}
 
-	/* files within /proc/net */
+#ifdef CONFIG_IP_ACCT
+	/* be careful: /proc/net/ip_acct_0 resets IP accounting */
+	if (ino == PROC_NET_IPACCT0) {
+		inode->i_mode = S_IFREG | S_IRUSR;
+		inode->i_op = &proc_net_inode_operations;
+		return;
+	}
+#endif
+#ifdef CONFIG_IP_FIREWALL
+	/* /proc/net/ip_forward_0 and /proc/net/ip_block_0 reset counters */
+	if ((ino == PROC_NET_IPFWFWD0) || (ino == PROC_NET_IPFWBLK0)) {
+		inode->i_mode = S_IFREG | S_IRUSR;
+		inode->i_op = &proc_net_inode_operations;
+		return;
+	}
+#endif
+
+	/* other files within /proc/net */
 	if ((ino >= PROC_NET_UNIX) && (ino < PROC_NET_LAST)) {
 		inode->i_mode = S_IFREG | S_IRUGO;
 		inode->i_op = &proc_net_inode_operations;
diff -u --recursive --new-file v1.1.88/linux/fs/proc/net.c linux/fs/proc/net.c
--- v1.1.88/linux/fs/proc/net.c	Wed Feb  1 09:23:06 1995
+++ linux/fs/proc/net.c	Sun Feb  5 14:44:40 1995
@@ -58,9 +58,16 @@
 #if	defined(CONFIG_WAVELAN)
 extern int wavelan_get_info(char *, char **, off_t, int);
 #endif	/* defined(CONFIG_WAVELAN) */
+#ifdef CONFIG_IP_ACCT
 extern int ip_acct_procinfo(char *, char **, off_t, int);
+extern int ip_acct0_procinfo(char *, char **, off_t, int);
+#endif /* CONFIG_IP_ACCT */
+#ifdef CONFIG_IP_FIREWALL
 extern int ip_fw_blk_procinfo(char *, char **, off_t, int);
+extern int ip_fw_blk0_procinfo(char *, char **, off_t, int);
 extern int ip_fw_fwd_procinfo(char *, char **, off_t, int);
+extern int ip_fw_fwd0_procinfo(char *, char **, off_t, int);
+#endif /* CONFIG_IP_FIREWALL */
 extern int ip_msqhst_procinfo(char *, char **, off_t, int);
 extern int ip_mc_procinfo(char *, char **, off_t, int);
 #endif /* CONFIG_INET */
@@ -140,13 +147,16 @@
 #endif
 #ifdef CONFIG_IP_FIREWALL
 	{ PROC_NET_IPFWFWD,	10, "ip_forward"},
-	{ PROC_NET_IPBLFWD,	8,  "ip_block"},
+	{ PROC_NET_IPFWFWD0,	12, "ip_forward_0"},
+	{ PROC_NET_IPFWBLK,	8,  "ip_block"},
+	{ PROC_NET_IPFWBLK0,	10, "ip_block_0"},
 #endif
 #ifdef CONFIG_IP_MASQUERADE
 	{ PROC_NET_IPMSQHST,	13, "ip_masquerade"},
 #endif
 #ifdef CONFIG_IP_ACCT
 	{ PROC_NET_IPACCT,	7,  "ip_acct"},
+	{ PROC_NET_IPACCT0,	9,  "ip_acct_0"},
 #endif
 #if	defined(CONFIG_WAVELAN)
 	{ PROC_NET_WAVELAN,	7, "wavelan" },
@@ -292,13 +302,22 @@
 			case PROC_NET_IPFWFWD:
 				length = ip_fw_fwd_procinfo(page, &start, file->f_pos,thistime);
 				break;
-			case PROC_NET_IPBLFWD:
+			case PROC_NET_IPFWFWD0:
+				length = ip_fw_fwd0_procinfo(page, &start, file->f_pos,thistime);
+				break;
+			case PROC_NET_IPFWBLK:
 				length = ip_fw_blk_procinfo(page, &start, file->f_pos,thistime);
 				break;
+			case PROC_NET_IPFWBLK0:
+				length = ip_fw_blk0_procinfo(page, &start, file->f_pos,thistime);
+				break;
 #endif
 #ifdef CONFIG_IP_ACCT
 			case PROC_NET_IPACCT:
 				length = ip_acct_procinfo(page, &start, file->f_pos,thistime);
+				break;
+			case PROC_NET_IPACCT0:
+				length = ip_acct0_procinfo(page, &start, file->f_pos,thistime);
 				break;
 #endif
 #ifdef CONFIG_IP_MASQUERADE
diff -u --recursive --new-file v1.1.88/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v1.1.88/linux/include/asm-alpha/io.h	Mon Jan 16 14:18:24 1995
+++ linux/include/asm-alpha/io.h	Fri Feb  3 18:44:42 1995
@@ -1,234 +1,21 @@
 #ifndef __ALPHA_IO_H
 #define __ALPHA_IO_H
 
-/*
- * Defines for the AlphaPC EISA IO and memory address space.
- */
+#include <linux/config.h>
 
 #ifndef mb
 #define mb() __asm__ __volatile__("mb": : :"memory")
 #endif
 
 /*
- * NOTE! Currently it never uses the HAE register, so these work only
- * for the low 25 bits of EISA addressing.  That covers all of the IO
- * address space (16 bits), and most of the "normal" EISA memory space.
- * I'll fix it eventually, but I'll need to come up with a clean way
- * to handle races with interrupt services wanting to change HAE...
- */
-
-/*
- * NOTE 2! The memory operations do not set any memory barriers, as it's
- * not needed for cases like a frame buffer that is essentially memory-like.
- * You need to do them by hand if the operations depend on ordering.
- *
- * Similarly, the port IO operations do a "mb" only after a write operation:
- * if an mb is needed before (as in the case of doing memory mapped IO
- * first, and then a port IO operation to the same device), it needs to be
- * done by hand.
- *
- * After the above has bitten me 100 times, I'll give up and just do the
- * mb all the time, but right now I'm hoping this will work out.  Avoiding
- * mb's may potentially be a noticeable speed improvement, but I can't
- * honestly say I've tested it.
- *
- * Handling interrupts that need to do mb's to synchronize to non-interrupts
- * is another fun race area.  Don't do it (because if you do, I'll have to
- * do *everything* with interrupts disabled, ugh).
- */
-
-/*
- * Virtual -> physical identity mapping starts at this offset
- */
-#define IDENT_ADDR	(0xfffffc0000000000UL)
-
-/*
- * EISA Interrupt Acknowledge address
- */
-#define EISA_INTA		(IDENT_ADDR + 0x100000000UL)
-
-/*
- * FEPROM addresses
- */
-#define EISA_FEPROM0		(IDENT_ADDR + 0x180000000UL)
-#define EISA_FEPROM1		(IDENT_ADDR + 0x1A0000000UL)
-
-/*
- * VL82C106 base address
- */
-#define EISA_VL82C106		(IDENT_ADDR + 0x1C0000000UL)
-
-/*
- * EISA "Host Address Extension" address (bits 25-31 of the EISA address)
- */
-#define EISA_HAE		(IDENT_ADDR + 0x1D0000000UL)
-
-/*
- * "SYSCTL" register address
- */
-#define EISA_SYSCTL		(IDENT_ADDR + 0x1E0000000UL)
-
-/*
- * "spare" register address
- */
-#define EISA_SPARE		(IDENT_ADDR + 0x1F0000000UL)
-
-/*
- * EISA memory address offset
- */
-#define EISA_MEM		(IDENT_ADDR + 0x200000000UL)
-
-/*
- * EISA IO address offset
- */
-#define EISA_IO			(IDENT_ADDR + 0x300000000UL)
-
-/*
- * IO functions
- *
- * The "local" functions are those that don't go out to the EISA bus,
- * but instead act on the VL82C106 chip directly.. This is mainly the
- * keyboard, RTC,  printer and first two serial lines..
- *
- * The local stuff makes for some complications, but it seems to be
- * gone in the PCI version. I hope I can get DEC suckered^H^H^H^H^H^H^H^H
- * convinced that I need one of the newer machines.
- */
-extern inline unsigned int __local_inb(unsigned long addr)
-{
-	long result = *(volatile int *) ((addr << 9) + EISA_VL82C106);
-	return 0xffUL & result;
-}
-
-extern inline void __local_outb(unsigned char b, unsigned long addr)
-{
-	*(volatile unsigned int *) ((addr << 9) + EISA_VL82C106) = b;
-	mb();
-}
-
-extern inline unsigned int __inb(unsigned long addr)
-{
-	long result = *(volatile int *) ((addr << 7) + EISA_IO + 0x00);
-	result >>= (addr & 3) * 8;
-	return 0xffUL & result;
-}
-
-extern inline void __outb(unsigned char b, unsigned long addr)
-{
-	*(volatile unsigned int *) ((addr << 7) + EISA_IO + 0x00) = b * 0x01010101;
-	mb();
-}
-
-/*
- * This is a stupid one: I'll make it a bitmap soon, promise..
- *
- * On the other hand: this allows gcc to optimize. Hmm. I'll
- * have to use the __constant_p() stuff here.
- *
- * The PCI version just returns zero all the time, I do believe..
- */
-extern inline int __is_local(unsigned long addr)
-{
-	/* keyboard */
-	if (addr == 0x60 || addr == 0x64)
-		return 1;
-
-	/* RTC */
-	if (addr == 0x170 || addr == 0x171)
-		return 1;
-
-	/* motherboard COM2 */
-	if (addr >= 0x2f8 && addr <= 0x2ff)
-		return 1;
-
-	/* motherboard LPT1 */
-	if (addr >= 0x3bc && addr <= 0x3be)
-		return 1;
-
-	/* motherboard COM2 */
-	if (addr >= 0x3f8 && addr <= 0x3ff)
-		return 1;
-
-	return 0;
-}
-
-extern inline unsigned int inb(unsigned long addr)
-{
-	if (__is_local(addr))
-		return __local_inb(addr);
-	return __inb(addr);
-}
-
-extern inline void outb(unsigned char b, unsigned long addr)
-{
-	if (__is_local(addr))
-		__local_outb(b, addr);
-	else
-		__outb(b, addr);
-}
-
-extern inline unsigned int inw(unsigned long addr)
-{
-	long result = *(volatile int *) ((addr << 7) + EISA_IO + 0x20);
-	result >>= (addr & 3) * 8;
-	return 0xffffUL & result;
-}
-
-extern inline unsigned int inl(unsigned long addr)
-{
-	return *(volatile unsigned int *) ((addr << 7) + EISA_IO + 0x60);
-}
-
-extern inline void outw(unsigned short b, unsigned long addr)
-{
-	*(volatile unsigned int *) ((addr << 7) + EISA_IO + 0x20) = b * 0x00010001;
-	mb();
-}
-
-extern inline void outl(unsigned int b, unsigned long addr)
-{
-	*(volatile unsigned int *) ((addr << 7) + EISA_IO + 0x60) = b;
-	mb();
-}
-
-/*
- * Memory functions
- */
-extern inline unsigned long readb(unsigned long addr)
-{
-	long result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x00);
-	result >>= (addr & 3) * 8;
-	return 0xffUL & result;
-}
-
-extern inline unsigned long readw(unsigned long addr)
-{
-	long result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x20);
-	result >>= (addr & 3) * 8;
-	return 0xffffUL & result;
-}
-
-extern inline unsigned long readl(unsigned long addr)
-{
-	return *(volatile unsigned int *) ((addr << 7) + EISA_MEM + 0x60);
-}
-
-extern inline void writeb(unsigned short b, unsigned long addr)
-{
-	*(volatile unsigned int *) ((addr << 7) + EISA_MEM + 0x00) = b * 0x01010101;
-}
-
-extern inline void writew(unsigned short b, unsigned long addr)
-{
-	*(volatile unsigned int *) ((addr << 7) + EISA_MEM + 0x20) = b * 0x00010001;
-}
-
-extern inline void writel(unsigned int b, unsigned long addr)
-{
-	*(volatile unsigned int *) ((addr << 7) + EISA_MEM + 0x60) = b;
-}
-
-#define inb_p inb
-#define outb_p outb
+ * There are different version of the alpha motherboards: the
+ * "interesting" (read: slightly braindead) Jensen type hardware
+ * and the PCI version
+ */
+#ifdef CONFIG_PCI
+#include <asm/lca.h>		/* get chip-specific definitions */
+#else
+#include <asm/jensen.h>
+#endif
 
 #endif
diff -u --recursive --new-file v1.1.88/linux/include/asm-alpha/jensen.h linux/include/asm-alpha/jensen.h
--- v1.1.88/linux/include/asm-alpha/jensen.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/jensen.h	Fri Feb  3 18:55:02 1995
@@ -0,0 +1,239 @@
+#ifndef __ALPHA_JENSEN_H
+#define __ALPHA_JENSEN_H
+
+/*
+ * Defines for the AlphaPC EISA IO and memory address space.
+ */
+
+/*
+ * NOTE! Currently it never uses the HAE register, so these work only
+ * for the low 25 bits of EISA addressing.  That covers all of the IO
+ * address space (16 bits), and most of the "normal" EISA memory space.
+ * I'll fix it eventually, but I'll need to come up with a clean way
+ * to handle races with interrupt services wanting to change HAE...
+ */
+
+/*
+ * NOTE 2! The memory operations do not set any memory barriers, as it's
+ * not needed for cases like a frame buffer that is essentially memory-like.
+ * You need to do them by hand if the operations depend on ordering.
+ *
+ * Similarly, the port IO operations do a "mb" only after a write operation:
+ * if an mb is needed before (as in the case of doing memory mapped IO
+ * first, and then a port IO operation to the same device), it needs to be
+ * done by hand.
+ *
+ * After the above has bitten me 100 times, I'll give up and just do the
+ * mb all the time, but right now I'm hoping this will work out.  Avoiding
+ * mb's may potentially be a noticeable speed improvement, but I can't
+ * honestly say I've tested it.
+ *
+ * Handling interrupts that need to do mb's to synchronize to non-interrupts
+ * is another fun race area.  Don't do it (because if you do, I'll have to
+ * do *everything* with interrupts disabled, ugh).
+ */
+
+/*
+ * Virtual -> physical identity mapping starts at this offset
+ */
+#define IDENT_ADDR	(0xfffffc0000000000UL)
+
+/*
+ * EISA Interrupt Acknowledge address
+ */
+#define EISA_INTA		(IDENT_ADDR + 0x100000000UL)
+
+/*
+ * FEPROM addresses
+ */
+#define EISA_FEPROM0		(IDENT_ADDR + 0x180000000UL)
+#define EISA_FEPROM1		(IDENT_ADDR + 0x1A0000000UL)
+
+/*
+ * VL82C106 base address
+ */
+#define EISA_VL82C106		(IDENT_ADDR + 0x1C0000000UL)
+
+/*
+ * EISA "Host Address Extension" address (bits 25-31 of the EISA address)
+ */
+#define EISA_HAE		(IDENT_ADDR + 0x1D0000000UL)
+
+/*
+ * "SYSCTL" register address
+ */
+#define EISA_SYSCTL		(IDENT_ADDR + 0x1E0000000UL)
+
+/*
+ * "spare" register address
+ */
+#define EISA_SPARE		(IDENT_ADDR + 0x1F0000000UL)
+
+/*
+ * EISA memory address offset
+ */
+#define EISA_MEM		(IDENT_ADDR + 0x200000000UL)
+
+/*
+ * EISA IO address offset
+ */
+#define EISA_IO			(IDENT_ADDR + 0x300000000UL)
+
+/*
+ * IO functions
+ *
+ * The "local" functions are those that don't go out to the EISA bus,
+ * but instead act on the VL82C106 chip directly.. This is mainly the
+ * keyboard, RTC,  printer and first two serial lines..
+ *
+ * The local stuff makes for some complications, but it seems to be
+ * gone in the PCI version. I hope I can get DEC suckered^H^H^H^H^H^H^H^H
+ * convinced that I need one of the newer machines.
+ */
+extern inline unsigned int __local_inb(unsigned long addr)
+{
+	long result = *(volatile int *) ((addr << 9) + EISA_VL82C106);
+	return 0xffUL & result;
+}
+
+extern inline void __local_outb(unsigned char b, unsigned long addr)
+{
+	*(volatile unsigned int *) ((addr << 9) + EISA_VL82C106) = b;
+	mb();
+}
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+	long result = *(volatile int *) ((addr << 7) + EISA_IO + 0x00);
+	result >>= (addr & 3) * 8;
+	return 0xffUL & result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+	*(volatile unsigned int *) ((addr << 7) + EISA_IO + 0x00) = b * 0x01010101;
+	mb();
+}
+
+/*
+ * This is a stupid one: I'll make it a bitmap soon, promise..
+ *
+ * On the other hand: this allows gcc to optimize. Hmm. I'll
+ * have to use the __constant_p() stuff here.
+ */
+extern inline int __is_local(unsigned long addr)
+{
+	/* keyboard */
+	if (addr == 0x60 || addr == 0x64)
+		return 1;
+
+	/* RTC */
+	if (addr == 0x170 || addr == 0x171)
+		return 1;
+
+	/* motherboard COM2 */
+	if (addr >= 0x2f8 && addr <= 0x2ff)
+		return 1;
+
+	/* motherboard LPT1 */
+	if (addr >= 0x3bc && addr <= 0x3be)
+		return 1;
+
+	/* motherboard COM2 */
+	if (addr >= 0x3f8 && addr <= 0x3ff)
+		return 1;
+
+	return 0;
+}
+
+extern inline unsigned int inb(unsigned long addr)
+{
+	if (__is_local(addr))
+		return __local_inb(addr);
+	return __inb(addr);
+}
+
+extern inline void outb(unsigned char b, unsigned long addr)
+{
+	if (__is_local(addr))
+		__local_outb(b, addr);
+	else
+		__outb(b, addr);
+}
+
+extern inline unsigned int inw(unsigned long addr)
+{
+	long result = *(volatile int *) ((addr << 7) + EISA_IO + 0x20);
+	result >>= (addr & 3) * 8;
+	return 0xffffUL & result;
+}
+
+extern inline unsigned int inl(unsigned long addr)
+{
+	return *(volatile unsigned int *) ((addr << 7) + EISA_IO + 0x60);
+}
+
+extern inline void outw(unsigned short b, unsigned long addr)
+{
+	*(volatile unsigned int *) ((addr << 7) + EISA_IO + 0x20) = b * 0x00010001;
+	mb();
+}
+
+extern inline void outl(unsigned int b, unsigned long addr)
+{
+	*(volatile unsigned int *) ((addr << 7) + EISA_IO + 0x60) = b;
+	mb();
+}
+
+/*
+ * Memory functions
+ */
+extern inline unsigned long readb(unsigned long addr)
+{
+	long result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x00);
+	result >>= (addr & 3) * 8;
+	return 0xffUL & result;
+}
+
+extern inline unsigned long readw(unsigned long addr)
+{
+	long result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x20);
+	result >>= (addr & 3) * 8;
+	return 0xffffUL & result;
+}
+
+extern inline unsigned long readl(unsigned long addr)
+{
+	return *(volatile unsigned int *) ((addr << 7) + EISA_MEM + 0x60);
+}
+
+extern inline void writeb(unsigned short b, unsigned long addr)
+{
+	*(volatile unsigned int *) ((addr << 7) + EISA_MEM + 0x00) = b * 0x01010101;
+}
+
+extern inline void writew(unsigned short b, unsigned long addr)
+{
+	*(volatile unsigned int *) ((addr << 7) + EISA_MEM + 0x20) = b * 0x00010001;
+}
+
+extern inline void writel(unsigned int b, unsigned long addr)
+{
+	*(volatile unsigned int *) ((addr << 7) + EISA_MEM + 0x60) = b;
+}
+
+#define inb_p inb
+#define outb_p outb
+
+/*
+ * The Alpha Jensen hardware for some rather strange reason puts
+ * the RTC clock at 0x170 instead of 0x70. Probably due to some
+ * misguided idea about using 0x70 for NMI stuff.
+ *
+ * These defines will override the defaults when doing RTC queries
+ */
+#define RTC_PORT(x)	(0x170+(x))
+#define RTC_ADDR(x)	(x)
+#define RTC_ALWAYS_BCD	0
+
+#endif
diff -u --recursive --new-file v1.1.88/linux/include/asm-alpha/lca.h linux/include/asm-alpha/lca.h
--- v1.1.88/linux/include/asm-alpha/lca.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/lca.h	Fri Feb  3 18:42:16 1995
@@ -0,0 +1,207 @@
+#ifndef __ALPHA_LCA__H
+#define __ALPHA_LCA__H
+
+/*
+ * Low Cost Alpha (LCA) definitions (these apply to 21066 and 21068,
+ * for example).
+ *
+ * This file is based on:
+ *
+ *	DECchip 21066 and DECchip 21068 Alpha AXP Microprocessors
+ *	Hardware Reference Manual; Digital Equipment Corp.; May 1994;
+ *	Maynard, MA; Order Number: EC-N2681-71.
+ */
+
+/*
+ * NOTE! Currently, this never uses the HAE register, so it works only
+ * for the low 27 bits of the PCI sparse memory address space.  Dense
+ * memory space doesn't require the HAE, but is restricted to aligned
+ * 32 and 64 bit accesses.  Special Cycle and Interrupt Acknowledge
+ * cycles may also require the use of the HAE.  The LCA limits I/O
+ * address space to the bottom 24 bits of address space, but this
+ * easily covers the 16 bit ISA I/O address space.
+ */
+
+/*
+ * NOTE 2! The memory operations do not set any memory barriers, as
+ * it's not needed for cases like a frame buffer that is essentially
+ * memory-like.  You need to do them by hand if the operations depend
+ * on ordering.
+ *
+ * Similarly, the port I/O operations do a "mb" only after a write
+ * operation: if an mb is needed before (as in the case of doing
+ * memory mapped I/O first, and then a port I/O operation to the same
+ * device), it needs to be done by hand.
+ *
+ * After the above has bitten me 100 times, I'll give up and just do
+ * the mb all the time, but right now I'm hoping this will work out.
+ * Avoiding mb's may potentially be a noticeable speed improvement,
+ * but I can't honestly say I've tested it.
+ *
+ * Handling interrupts that need to do mb's to synchronize to
+ * non-interrupts is another fun race area.  Don't do it (because if
+ * you do, I'll have to do *everything* with interrupts disabled,
+ * ugh).
+ */
+
+/*
+ * Virtual -> physical identity mapping starts at this offset.
+ */
+#define IDENT_ADDR	(0xfffffc0000000000UL)
+
+/*
+ * I/O Controller registers:
+ */
+#define LCA_IOC_HAE		(IDENT_ADDR + 0x180000000UL)
+#define LCA_IOC_CONF		(IDENT_ADDR + 0x180000020UL)
+#define LCA_IOC_STAT0		(IDENT_ADDR + 0x180000040UL)
+#define LCA_IOC_STAT1		(IDENT_ADDR + 0x180000060UL)
+#define LCA_IOC_TBIA		(IDENT_ADDR + 0x180000080UL)
+#define LCA_IOC_TB_ENA		(IDENT_ADDR + 0x1800000a0UL)
+#define LCA_IOC_SFT_RST		(IDENT_ADDR + 0x1800000c0UL)
+#define LCA_IOC_PAR_DIS		(IDENT_ADDR + 0x1800000e0UL)
+#define LCA_IOC_W_BASE0		(IDENT_ADDR + 0x180000100UL)
+#define LCA_IOC_W_BASE1		(IDENT_ADDR + 0x180000120UL)
+#define LCA_IOC_W_MASK0		(IDENT_ADDR + 0x180000140UL)
+#define LCA_IOC_W_MASK1		(IDENT_ADDR + 0x180000160UL)
+#define LCA_IOC_T_BASE0		(IDENT_ADDR + 0x180000180UL)
+#define LCA_IOC_T_BASE1		(IDENT_ADDR + 0x1800001a0UL)
+#define LCA_IOC_TB_TAG0		(IDENT_ADDR + 0x188000000UL)
+#define LCA_IOC_TB_TAG1		(IDENT_ADDR + 0x188000020UL)
+#define LCA_IOC_TB_TAG2		(IDENT_ADDR + 0x188000040UL)
+#define LCA_IOC_TB_TAG3		(IDENT_ADDR + 0x188000060UL)
+#define LCA_IOC_TB_TAG4		(IDENT_ADDR + 0x188000070UL)
+#define LCA_IOC_TB_TAG5		(IDENT_ADDR + 0x1880000a0UL)
+#define LCA_IOC_TB_TAG6		(IDENT_ADDR + 0x1880000c0UL)
+#define LCA_IOC_TB_TAG7		(IDENT_ADDR + 0x1880000e0UL)
+
+/*
+ * Memory spaces:
+ */
+#define LCA_IACK_SC		(IDENT_ADDR + 0x1a0000000UL)
+#define LCA_CONF		(IDENT_ADDR + 0x1e0000000UL)
+#define LCA_IO			(IDENT_ADDR + 0x1c0000000UL)
+#define LCA_SPARSE_MEM		(IDENT_ADDR + 0x200000000UL)
+#define LCA_DENSE_MEM		(IDENT_ADDR + 0x300000000UL)
+
+/*
+ * Bit definitions for I/O Controller status register 0:
+ */
+#define LCA_IOC_STAT0_CMD		0xf
+#define LCA_IOC_STAT0_ERR		(1<<4)
+#define LCA_IOC_STAT0_LOST		(1<<5)
+#define LCA_IOC_STAT0_THIT		(1<<6)
+#define LCA_IOC_STAT0_TREF		(1<<7)
+#define LCA_IOC_STAT0_CODE_SHIFT	8
+#define LCA_IOC_STAT0_CODE_MASK		0x7
+#define LCA_IOC_STAT0_P_NBR_SHIFT	13
+#define LCA_IOC_STAT0_P_NBR_MASK	0x7ffff
+
+/*
+ * I/O functions:
+ *
+ * Unlike Jensen, the Noname machines have no concept of local
+ * I/O---everything goes over the PCI bus.
+ *
+ * There is plenty room for optimization here.  In particular,
+ * the Alpha's insb/insw/extb/extw should be useful in moving
+ * data to/from the right byte-lanes.
+ */
+
+extern inline unsigned int
+inb(unsigned long addr)
+{
+    long result = *(volatile int *) ((addr << 5) + LCA_IO + 0x00);
+    result >>= (addr & 3) * 8;
+    return 0xffUL & result;
+}
+
+extern inline unsigned int
+inw(unsigned long addr)
+{
+    long result = *(volatile int *) ((addr << 5) + LCA_IO + 0x08);
+    result >>= (addr & 3) * 8;
+    return 0xffffUL & result;
+}
+
+extern inline unsigned int
+inl(unsigned long addr)
+{
+    return *(volatile unsigned int *) ((addr << 5) + LCA_IO + 0x18);
+}
+
+extern inline void
+outb(unsigned char b, unsigned long addr)
+{
+    *(volatile unsigned int *) ((addr << 5) + LCA_IO + 0x00) = b * 0x01010101;
+    mb();
+}
+
+extern inline void
+outw(unsigned char b, unsigned long addr)
+{
+    *(volatile unsigned int *) ((addr << 5) + LCA_IO + 0x08) = b * 0x00010001;
+    mb();
+}
+
+extern inline void
+outl(unsigned char b, unsigned long addr)
+{
+    *(volatile unsigned int *) ((addr << 5) + LCA_IO + 0x18) = b;
+    mb();
+}
+
+
+/*
+ * Memory functions.  64-bit and 32-bit accesses are done through
+ * dense memory space, everything else through sparse space.
+ */
+
+extern inline unsigned long
+readb(unsigned long addr)
+{
+    long result = *(volatile int *) ((addr << 5) + LCA_SPARSE_MEM + 0x00);
+    result >>= (addr & 3) * 8;
+    return 0xffUL & result;
+}
+
+extern inline unsigned long
+readw(unsigned long addr)
+{
+    long result = *(volatile int *) ((addr << 5) + LCA_SPARSE_MEM + 0x08);
+    result >>= (addr & 3) * 8;
+    return 0xffffUL & result;
+}
+
+extern inline unsigned long
+readl(unsigned long addr)
+{
+    return *(volatile int *) (addr + LCA_DENSE_MEM);
+}
+
+extern inline void
+writeb(unsigned short b, unsigned long addr)
+{
+    *(volatile unsigned int *) ((addr << 5) + LCA_SPARSE_MEM + 0x00) =
+      b * 0x01010101;
+}
+
+extern inline void
+writew(unsigned short b, unsigned long addr)
+{
+    *(volatile unsigned int *) ((addr << 5) + LCA_SPARSE_MEM + 0x08) =
+      b * 0x00010001;
+}
+
+extern inline void
+writel(unsigned short b, unsigned long addr)
+{
+    *(volatile unsigned int *) (addr + LCA_DENSE_MEM) = b;
+}
+
+#define inb_local inb
+#define outb_local outb
+#define inb_p inb
+#define outb_p outb
+
+#endif
diff -u --recursive --new-file v1.1.88/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v1.1.88/linux/include/asm-alpha/pgtable.h	Wed Feb  1 09:23:07 1995
+++ linux/include/asm-alpha/pgtable.h	Wed Feb  1 09:19:36 1995
@@ -53,7 +53,7 @@
 
 /*
  * NOTE! The "accessed" bit isn't necessarily exact: it can be kept exactly
- * by software (use the KRE/URE/KWE/UWE bits appropritely), but I'll fake it.
+ * by software (use the KRE/URE/KWE/UWE bits appropriately), but I'll fake it.
  * Under Linux/AXP, the "accessed" bit just means "read", and I'll just use
  * the KRE/URE bits to watch for it. That way we don't need to overload the
  * KWE/UWE bits with both handling dirty and accessed.
diff -u --recursive --new-file v1.1.88/linux/include/asm-alpha/ptrace.h linux/include/asm-alpha/ptrace.h
--- v1.1.88/linux/include/asm-alpha/ptrace.h	Mon Jan 16 14:18:24 1995
+++ linux/include/asm-alpha/ptrace.h	Wed Feb  1 21:46:08 1995
@@ -46,6 +46,9 @@
 	unsigned long r18;
 };
 
+#ifdef __KERNEL__
 #define user_mode(regs) ((regs)->ps & 8)
+extern void show_regs(struct pt_regs *);
+#endif
 
 #endif
diff -u --recursive --new-file v1.1.88/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v1.1.88/linux/include/asm-alpha/system.h	Mon Jan 30 08:53:06 1995
+++ linux/include/asm-alpha/system.h	Wed Feb  1 21:46:08 1995
@@ -80,8 +80,9 @@
 extern unsigned long rdusp(void);
 
 #define halt() __asm__ __volatile__(".long 0");
-#define move_to_user_mode() halt()
-#define switch_to(x) halt()
+
+#define move_to_user_mode()	printk("Null move_to_user_mode\n")
+#define switch_to(x)		panic("switch_to() not yet done")
 
 #ifndef mb
 #define mb() __asm__ __volatile__("mb": : :"memory")
diff -u --recursive --new-file v1.1.88/linux/include/asm-i386/ptrace.h linux/include/asm-i386/ptrace.h
--- v1.1.88/linux/include/asm-i386/ptrace.h	Mon Jan  9 07:22:09 1995
+++ linux/include/asm-i386/ptrace.h	Wed Feb  1 21:46:08 1995
@@ -45,6 +45,7 @@
 
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->cs))
+extern void show_regs(struct pt_regs *);
 #endif
 
 #endif
diff -u --recursive --new-file v1.1.88/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v1.1.88/linux/include/asm-i386/system.h	Mon Jan  9 07:22:09 1995
+++ linux/include/asm-i386/system.h	Wed Feb  1 20:31:06 1995
@@ -249,4 +249,11 @@
  */
 extern struct desc_struct default_ldt;
 
+/*
+ * disable hlt during certain critical i/o operations
+ */
+#define HAVE_DISABLE_HLT
+void disable_hlt(void);
+void enable_hlt(void);
+
 #endif
diff -u --recursive --new-file v1.1.88/linux/include/asm-sparc/clock.h linux/include/asm-sparc/clock.h
--- v1.1.88/linux/include/asm-sparc/clock.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/clock.h	Thu Feb  2 08:42:35 1995
@@ -0,0 +1,51 @@
+/* clock.h:  Definitions for the clock/timer chips on the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* Clock timer structures. The interrupt timer has two properties which
+ * are the counter (which is handled in do_timer in sched.c) and the limit.
+ * This limit is where the timer's counter 'wraps' around. Oddly enough,
+ * the sun4c timer when it hits the limit wraps back to 1 and not zero
+ * thus when calculating the value at which it will fire a microsecond you
+ * must adjust by one.  Thanks SUN for designing such great hardware ;(
+ */
+
+/* Note that I am only going to use the timer that interrupts at
+ * Sparc IRQ 10.  There is another one available that can fire at
+ * IRQ 14. If I can think of some creative uses for it this may
+ * change. It might make a nice kernel/user profiler etc.
+ */
+
+struct sparc_timer_info {
+  unsigned int cur_count10;
+  unsigned int timer_limit10;
+  unsigned int cur_count14;
+  unsigned int timer_limit14;
+};
+
+struct sparc_clock_info {
+  unsigned char hsec;
+  unsigned char hr;
+  unsigned char min;
+  unsigned char sec;
+  unsigned char mon;
+  unsigned char day;
+  unsigned char yr;
+  unsigned char wkday;
+  unsigned char ram_hsec;
+  unsigned char ram_hr;
+  unsigned char ram_min;
+  unsigned char ram_sec;
+  unsigned char ram_mon;
+  unsigned char ram_day;
+  unsigned char ram_year;
+  unsigned char ram_wkday;
+  unsigned char intr_reg;
+  unsigned char cmd_reg;
+  unsigned char foo[14];
+};
+
+/* YUCK YUCK YUCK, grrr... */
+#define  TIMER_STRUCT  ((struct sparc_timer_info *)((struct sparc_clock_info *) TIMER_VADDR))
+
diff -u --recursive --new-file v1.1.88/linux/include/asm-sparc/cprefix.h linux/include/asm-sparc/cprefix.h
--- v1.1.88/linux/include/asm-sparc/cprefix.h	Wed Feb  1 09:23:07 1995
+++ linux/include/asm-sparc/cprefix.h	Thu Feb  2 08:42:35 1995
@@ -1,7 +1,7 @@
 /* cprefix.h:  This file is included by assembly source which needs
  *             to know what the c-label prefixes are. The newer versions
  *	       of cpp that come with gcc predefine such things to help
- *	       us out. The reason this stuff is needed is to make
+ *	       us out. The reason this stuff is neaded is to make
  *	       solaris compiles of the kernel work.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.1.88/linux/include/asm-sparc/head.h linux/include/asm-sparc/head.h
--- v1.1.88/linux/include/asm-sparc/head.h	Mon Jan  9 11:24:24 1995
+++ linux/include/asm-sparc/head.h	Thu Feb  2 08:42:35 1995
@@ -10,9 +10,11 @@
 #define SUN4C_SEGSZ     (1 << 18)
 #define USRSTACK        0x0         /* no joke, this is temporary, trust me */
 #define INT_ENABLE_REG_PHYSADR      0xf5000000
-#define INTS_ALL_ENAB   0x01
+#define INTS_ENAB   0x01
 
 #define WRITE_PAUSE     nop; nop; nop;
+
+#define PAGE_SIZE       4096
 
 /* Here are some trap goodies */
 
diff -u --recursive --new-file v1.1.88/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h
--- v1.1.88/linux/include/asm-sparc/io.h	Mon Jan  2 15:26:45 1995
+++ linux/include/asm-sparc/io.h	Thu Feb  2 08:42:35 1995
@@ -1,6 +1,8 @@
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
 
+#include <asm/page.h>      /* IO address mapping routines need this */
+
 /*
  * Defines for io operations on the Sparc. Whether a memory access is going
  * to i/o sparc is encoded in the pte. The type bits determine whether this
@@ -83,5 +85,16 @@
 
 #define inb_p inb
 #define outb_p outb
+
+extern inline void mapioaddr(unsigned long physaddr, unsigned long virt_addr)
+{
+  unsigned long page_entry;
+
+  page_entry = physaddr >> PAGE_SHIFT;
+  page_entry |= (PTE_V | PTE_ACC | PTE_W | PTE_P | PTE_IO);  /* kernel io addr */
+
+  put_pte(page_entry, virt_addr);
+  return;
+}
 
 #endif /* !(__SPARC_IO_H) */
diff -u --recursive --new-file v1.1.88/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v1.1.88/linux/include/asm-sparc/page.h	Thu Jan 26 07:49:15 1995
+++ linux/include/asm-sparc/page.h	Thu Feb  2 08:42:35 1995
@@ -10,60 +10,73 @@
 #include <asm/asi.h>        /* for get/set segmap/pte routines */
 #include <asm/contregs.h>   /* for switch_to_context */
 
-/* The current va context is global and known, so all that is needed to
- * do an invalidate is flush the VAC.
- */
-
-#define invalidate() flush_vac_context()  /* how conveeeiiiiinnnient :> */
-
-
 #define PAGE_SHIFT   12             /* This is the virtual page... */
-#define PGDIR_SHIFT  18             /* This is the virtual segment */
-#define PAGE_SIZE    4096
-#define PGDIR_SIZE   (1UL << PGDIR_SHIFT)
 
-#define PAGE_OFFSET    0
-#define MAP_NR(addr) (((addr)) >> PAGE_SHIFT)
-#define MAP_PAGE_RESERVED (1<<31)
+#ifndef __ASSEMBLY__
+#define PAGE_SIZE    (1UL << PAGE_SHIFT)
 
+/* to mask away the intra-page address bits */
+#define PAGE_MASK         (~(PAGE_SIZE-1))
 
+#ifdef __KERNEL__
 
-#define PAGE_PRESENT	0x001
-#define PAGE_RW		0x002
-#define PAGE_USER	0x004
-#define PAGE_ACCESSED	0x020
-#define PAGE_DIRTY	0x040
-#define PAGE_COW	0x200	/* implemented in software (one of the AVL bits) */
-
-#define PAGE_PRIVATE	(PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED | PAGE_COW)
-#define PAGE_SHARED	(PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED)
-#define PAGE_COPY	(PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED | PAGE_COW)
-#define PAGE_READONLY	(PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED)
-#define PAGE_EXECONLY	(PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED)
-#define PAGE_TABLE	(PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED)
+#define CONFIG_STRICT_MM_TYPECHECKS
 
-#define PAGE_CHG_MASK (PAGE_MASK | PAGE_ACCESSED | PAGE_DIRTY)
+#ifdef CONFIG_STRICT_MM_TYPECHECKS
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)	((x).pte)
+#define pmd_val(x)      ((x).pmd)
+#define pgd_val(x)	((x).pgd)
+#define pgprot_val(x)	((x).pgprot)
+
+#define __pte(x)	((pte_t) { (x) } )
+#define __pmd(x)        ((pmd_t) { (x) } )
+#define __pgd(x)	((pgd_t) { (x) } )
+#define __pgprot(x)	((pgprot_t) { (x) } )
 
-#ifdef __KERNEL__
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef unsigned long pte_t;
+typedef unsigned long pmd_t;
+typedef unsigned long pgd_t;
+typedef unsigned long pgprot_t;
+
+#define pte_val(x)	(x)
+#define pmd_val(x)      (x)
+#define pgd_val(x)	(x)
+#define pgprot_val(x)	(x)
+
+#define __pte(x)	(x)
+#define __pmd(x)        (x)
+#define __pgd(x)	(x)
+#define __pgprot(x)	(x)
 
-/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR      (8*sizeof(unsigned long))   /* better check this stuff */
+#endif
 
-/* to mask away the intra-page address bits */
-#define PAGE_MASK         (~(PAGE_SIZE-1))
+/* The current va context is global and known, so all that is needed to
+ * do an invalidate is flush the VAC.
+ */
 
-/* to mask away the intra-page address bits */
-#define PGDIR_MASK        (~(PGDIR_SIZE-1))
+#define invalidate() flush_vac_context()  /* how conveeeiiiiinnnient :> */
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)  (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-#define PGDIR_ALIGN(addr) (((addr)+PGDIR_SIZE-1)&PGDIR_MASK)
 
-/* to align the pointer to a pointer address */
-#define PTR_MASK          (~(sizeof(void*)-1))
+#define PAGE_OFFSET    0
+#define MAP_NR(addr) (((unsigned long)(addr)) >> PAGE_SHIFT)
+#define MAP_PAGE_RESERVED (1<<15)
 
 
-#define SIZEOF_PTR_LOG2   2
+#endif /* !(__ASSEMBLY__) */
 
 /* The rest is kind of funky because on the sparc, the offsets into the mmu 
  * entries are encoded in magic alternate address space tables. I will 
@@ -71,10 +84,6 @@
  * Much thought must go into this code.   (davem@caip.rutgers.edu)
  */
 
-#define PAGE_DIR_OFFSET(base, address)   ((unsigned long *) 0)
-#define PAGE_PTR(address)                ((unsigned long) 0)
-#define PTRS_PER_PAGE                    (64)  /* 64 pte's per phys_seg */
-
 /* Bitfields within a Sparc sun4c PTE (page table entry). */
 
 #define PTE_V     0x80000000   /* valid bit */
@@ -92,28 +101,6 @@
 #define PTE_RESV  0x00f80000   /* reserved bits */
 #define PTE_PHYPG 0x0007ffff   /* phys pg number, sun4c only uses 16bits */
 
-/* termed a 'page table' in the linux kernel, a segmap entry is obtained
- * with the following macro
- */
-
-#ifndef __ASSEMBLY__ /* for head.S */
-/*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern unsigned long __bad_page(void);
-extern unsigned long __bad_pagetable(void);
-extern unsigned long __zero_page(void);
-
-typedef unsigned int mem_map_t;
-
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE __zero_page()
-
 extern __inline__ unsigned long get_segmap(unsigned long addr)
 {
   register unsigned long entry;
@@ -172,16 +159,7 @@
   return ctx;
 }
 
-/* to set the page-dir
- *
- * On the Sparc this is a nop for now. It will set the proper segmap
- * in the real implementation.
- */
-
-#define SET_PAGE_DIR(tsk,pgdir)
-
-
-#endif /* !(__ASSEMBLY__) */
+typedef unsigned short mem_map_t;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v1.1.88/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v1.1.88/linux/include/asm-sparc/pgtable.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/pgtable.h	Thu Feb  2 08:42:35 1995
@@ -0,0 +1,317 @@
+#ifndef _SPARC_PGTABLE_H
+#define _SPARC_PGTABLE_H
+
+/*  asm-sparc/pgtable.h:  Defines and functions used to work
+ *                        with Sparc page tables.
+ *
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define PMD_SHIFT       22
+#define PMD_SIZE        (1UL << PMD_SHIFT)
+#define PMD_MASK        (~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT       22
+#define PGDIR_SIZE        (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK        (~(PGDIR_SIZE-1))
+#define PGDIR_ALIGN(addr) (((addr)+PGDIR_SIZE-1)&PGDIR_MASK)
+
+/*
+ * Just following the i386 lead, because it works on the Sparc sun4c
+ * machines.  Two-level, therefore there is no real PMD.
+ */
+
+#define PTRS_PER_PTE    1024
+#define PTRS_PER_PMD    1
+#define PTRS_PER_PGD    1024
+
+/* the no. of pointers that fit on a page: this will go away */
+#define PTRS_PER_PAGE   (PAGE_SIZE/sizeof(void*))
+
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET  (8*1024*1024)
+#define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) (TASK_SIZE + (unsigned long)(x))
+
+/*
+ * Sparc page table fields.
+ */
+
+#define _PAGE_VALID     0x80000000   /* valid page */
+#define _PAGE_WRITE     0x40000000   /* can be written to */
+#define _PAGE_PRIV      0x20000000   /* bit to signify privileged page */
+#define _PAGE_REF       0x02000000   /* Page had been accessed/referenced */
+#define _PAGE_DIRTY     0x01000000   /* Page has been modified, is dirty */
+#define _PAGE_COW       0x00800000   /* COW page, hardware ignores this bit (untested) */
+
+
+/* Sparc sun4c mmu has only a writable bit. Thus if a page is valid it can be
+ * read in a load, and executed as code automatically. Although, the memory fault
+ * hardware does make a distinction between date-read faults and insn-read faults
+ * which is determined by which trap happened plus magic sync/async fault register
+ * values which must be checked in the actual fault handler.
+ */
+
+/* We want the swapper not to swap out page tables, thus dirty and writable
+ * so that the kernel can change the entries as needed. Also valid for
+ * obvious reasons.
+ */
+#define _PAGE_TABLE     (_PAGE_VALID | _PAGE_WRITE | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_REF | _PAGE_DIRTY)
+
+#define PAGE_NONE       __pgprot(_PAGE_VALID | _PAGE_REF)
+#define PAGE_SHARED     __pgprot(_PAGE_VALID | _PAGE_WRITE | _PAGE_REF)
+#define PAGE_COPY       __pgprot(_PAGE_VALID | _PAGE_REF | _PAGE_COW)
+#define PAGE_READONLY   __pgprot(_PAGE_VALID | _PAGE_REF)
+#define PAGE_KERNEL     __pgprot(_PAGE_VALID | _PAGE_PRIV)
+
+#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | _PAGE_REF | (x))
+
+/* I define these like the i386 does because the check for text or data fault
+ * is done at trap time by the low level handler. Maybe I can set these bits
+ * then once determined. I leave them like this for now though.
+ */
+#define __P000  PAGE_NONE
+#define __P001  PAGE_READONLY
+#define __P010  PAGE_COPY
+#define __P011  PAGE_COPY
+#define __P100  PAGE_READONLY
+#define __P101  PAGE_READONLY
+#define __P110  PAGE_COPY
+#define __P111  PAGE_COPY
+
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED
+#define __S100	PAGE_READONLY
+#define __S101	PAGE_READONLY
+#define __S110	PAGE_SHARED
+#define __S111	PAGE_SHARED
+
+
+extern unsigned long pg0[1024];
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
+extern unsigned long __zero_page(void);
+
+
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE __zero_page()
+
+/* number of bits that fit into a memory pointer */
+#define BITS_PER_PTR      (8*sizeof(unsigned long))   /* better check this stuff */
+
+/* to align the pointer to a pointer address */
+#define PTR_MASK          (~(sizeof(void*)-1))
+
+
+#define SIZEOF_PTR_LOG2   2
+
+
+/* to set the page-dir
+ *
+ * On the Sparc the page segments hold 64 pte's which means 256k/segment.
+ * Therefore there is no global idea of 'the' page directory, although we
+ * make a virtual one in kernel memory so that we can keep the stats on
+ * all the pages since not all can be loaded at once in the mmu.
+ */
+
+#define SET_PAGE_DIR(tsk,pgdir)
+
+/* to find an entry in a page-table */
+#define PAGE_PTR(address) \
+((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+
+extern unsigned long high_memory;
+
+extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
+extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_VALID; }
+extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
+
+extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
+extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; }
+extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_VALID; }
+extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
+
+extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
+extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~PAGE_MASK) != _PAGE_TABLE || pgd_val(pgd) > high_memory; }
+extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_VALID; }
+extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+extern inline int pte_read(pte_t pte)		{ return pte_val(pte) & _PAGE_VALID; }
+extern inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_WRITE; }
+extern inline int pte_exec(pte_t pte)		{ return pte_val(pte) & _PAGE_VALID; }
+extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_REF; }
+extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_REF; }
+extern inline int pte_cow(pte_t pte)		{ return pte_val(pte) & _PAGE_COW; }
+
+extern inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_WRITE; return pte; }
+extern inline pte_t pte_rdprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_VALID; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_VALID; return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_PAGE_REF; return pte; }
+extern inline pte_t pte_uncow(pte_t pte)	{ pte_val(pte) &= ~_PAGE_COW; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _PAGE_WRITE; return pte; }
+extern inline pte_t pte_mkread(pte_t pte)	{ pte_val(pte) |= _PAGE_VALID; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte)	{ pte_val(pte) |= _PAGE_VALID; return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _PAGE_REF; return pte; }
+extern inline pte_t pte_mkcow(pte_t pte)	{ pte_val(pte) |= _PAGE_COW; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+extern inline unsigned long pte_page(pte_t pte)	{ return pte_val(pte) & PAGE_MASK; }
+
+extern inline unsigned long pmd_page(pmd_t pmd) { return pmd_val(pmd) & PAGE_MASK; }
+
+extern inline unsigned long pgd_page(pgd_t pgd)	{ return pgd_val(pgd) & PAGE_MASK; }
+
+extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
+{ pgd_val(*pgdp) = _PAGE_TABLE | (unsigned long) ptep; }
+
+/* to find an entry in a page-table-directory */
+#define PAGE_DIR_OFFSET(tsk,address) \
+((((unsigned long)(address)) >> 22) + (pgd_t *) (tsk)->tss.cr3)
+
+/* to find an entry in a page-table-directory */
+extern inline pgd_t * pgd_offset(struct task_struct * tsk, unsigned long address)
+{
+	return (pgd_t *) tsk->tss.cr3 + (address >> PGDIR_SHIFT);
+}
+
+/* Find an entry in the second-level page table.. */
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */ 
+extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+{
+	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+}
+
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any, and marks the page tables reserved.
+ */
+extern inline void pte_free_kernel(pte_t * pte)
+{
+	mem_map[MAP_NR(pte)] = 1;
+	free_page((unsigned long) pte);
+}
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+				return page + address;
+			}
+			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free_kernel(pmd_t * pmd)
+{
+}
+
+extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
+{
+	return (pmd_t *) pgd;
+}
+
+extern inline void pte_free(pte_t * pte)
+{
+	free_page((unsigned long) pte);
+}
+
+extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+				return page + address;
+			}
+			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free(pmd_t * pmd)
+{
+}
+
+extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+	return (pmd_t *) pgd;
+}
+
+extern pgd_t swapper_pg_dir[1024];
+
+#endif /* !(_SPARC_PGTABLE_H) */
diff -u --recursive --new-file v1.1.88/linux/include/asm-sparc/ptrace.h linux/include/asm-sparc/ptrace.h
--- v1.1.88/linux/include/asm-sparc/ptrace.h	Mon Jan  9 07:22:10 1995
+++ linux/include/asm-sparc/ptrace.h	Thu Feb  2 08:42:35 1995
@@ -24,6 +24,9 @@
 	unsigned long f_regs[64];    /* yuck yuck yuck */
 };
 
-#define user_mode(regs) (~((regs)->ps&0x1))  /* if previous supervisor is 0, came from user */
+#ifdef __KERNEL__
+#define user_mode(regs) (0x0)  /* if previous supervisor is 0, came from user */
+extern void show_regs(struct pt_regs *);
+#endif
 
 #endif
diff -u --recursive --new-file v1.1.88/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v1.1.88/linux/include/asm-sparc/system.h	Thu Jan 26 07:49:15 1995
+++ linux/include/asm-sparc/system.h	Thu Feb  2 08:42:35 1995
@@ -18,6 +18,7 @@
  */
 
 #include <asm/openprom.h>
+#include <asm/psr.h>
 
 #define INIT_PCB	0x00011fe0
 #define INIT_STACK	0x00013fe0
@@ -27,6 +28,10 @@
 #define EMPTY_PGE	0x00001000
 #define ZERO_PGE	0x00001000
 
+#define IRQ_ENA_ADR     0x2000        /* This is a bitmap of all activated IRQ's
+				       * which is mapped in head.S during boot.
+				       */
+
 #ifndef __ASSEMBLY__
 
 extern void wrent(void *, unsigned long);
@@ -46,18 +51,17 @@
  */
 
 #define swpipl(__new_ipl) \
-({ unsigned long __old_ipl, psr; \
+({ unsigned long psr, retval; \
 __asm__ __volatile__( \
-        "rd %%psr, %0\n\t" : "=&r" (__old_ipl)); \
+        "rd %%psr, %0\n\t" : "=&r" (psr)); \
+retval = psr; \
+psr = (psr & ~(PSR_PIL)); \
+psr |= ((__new_ipl << 8) & PSR_PIL); \
 __asm__ __volatile__( \
-	"and %1, 15, %0\n\t" \
-	"sll %0, 8, %0\n\t" \
-	"or  %0, %2, %0\n\t" \
 	"wr  %0, 0x0, %%psr\n\t" \
-	: "=&r" (psr) \
-	: "r" (__new_ipl), "r" (__old_ipl)); \
-__old_ipl = ((__old_ipl>>8)&15); \
-__old_ipl; })
+	: : "r" (psr)); \
+retval = ((retval>>8)&15); \
+retval; })
 
 #define cli()			swpipl(15)  /* 15 = no int's except nmi's */
 #define sti()			swpipl(0)   /* same as alpha */
@@ -82,6 +86,20 @@
 #define set_call_gate(a,addr) \
 	_set_gate(a,12,3,addr)
 
+
+extern inline unsigned int get_psr(void)
+{
+  unsigned int ret_val;
+  __asm__("rd %%psr, %0\n\t" :
+	  "=r" (ret_val));
+  return ret_val;
+}
+
+extern inline void put_psr(unsigned int new_psr)
+{
+  __asm__("wr %0, 0x0, %%psr\n\t" : :
+	  "r" (new_psr));
+}
 
 /* Must this be atomic? */
 
diff -u --recursive --new-file v1.1.88/linux/include/asm-sparc/vaddrs.h linux/include/asm-sparc/vaddrs.h
--- v1.1.88/linux/include/asm-sparc/vaddrs.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/vaddrs.h	Thu Feb  2 08:42:35 1995
@@ -0,0 +1,16 @@
+#ifndef _SPARC_VADDRS_H
+#define _SPARC_VADDRS_H
+
+/* asm-sparc/vaddrs.h:  Here will be define the virtual addresses at
+ *                      which important I/O addresses will be mapped.
+ *                      For instance the timer register virtual address
+ *                      is defined here.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#define  TIMER_VADDR    0x3000   /* Next page after where the interrupt enable
+				  * register gets mapped at boot.
+				  */
+
+#endif /* !(_SPARC_VADDRS_H) */
diff -u --recursive --new-file v1.1.88/linux/include/linux/aztcd.h linux/include/linux/aztcd.h
--- v1.1.88/linux/include/linux/aztcd.h	Wed Feb  1 09:23:07 1995
+++ linux/include/linux/aztcd.h	Fri Feb  3 15:15:09 1995
@@ -1,4 +1,4 @@
-/* $Id: aztcd.h,v 0.80 1995/01/21 19:55:04 root Exp $
+/* $Id: aztcd.h,v 0.90 1995/02/02 18:14:28 root Exp $
  * Definitions for a AztechCD268 CD-ROM interface
  *	Copyright (C) 1994, 1995  Werner Zimmermann
  *
@@ -70,13 +70,14 @@
 #define ACMD_GET_ERROR		0x40		/* get error code */
 #define ACMD_GET_STATUS		0x41		/* get status */
 #define ACMD_GET_Q_CHANNEL      0x50		/* read info from q channel */
-#define ACMD_EJECT		0x60		/* eject/open */
+#define ACMD_EJECT		0x60		/* eject/open tray */
+#define ACMD_CLOSE              0x61            /* close tray */
 #define ACMD_PAUSE		0x80		/* pause */
 #define ACMD_STOP		0x81		/* stop play */
 #define ACMD_PLAY_AUDIO		0x90		/* play audio track */
+#define ACMD_SET_VOLUME		0x93		/* set audio level */
 #define ACMD_GET_VERSION	0xA0		/* get firmware version */
 #define ACMD_SET_MODE		0xA1		/* set drive mode */
-#define ACMD_SET_VOLUME		0xAE		/* set audio level */
 
 #define SET_TIMER(func, jifs) \
         delay_timer.expires = jifs; \
diff -u --recursive --new-file v1.1.88/linux/include/linux/bios32.h linux/include/linux/bios32.h
--- v1.1.88/linux/include/linux/bios32.h	Mon Aug  8 14:46:14 1994
+++ linux/include/linux/bios32.h	Fri Feb  3 19:28:28 1995
@@ -22,7 +22,14 @@
 #ifndef BIOS32_H
 #define BIOS32_H
 
+extern int pcibios_present (void);
 unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end);
+
+#define PCIBIOS_SUCCESSFUL		0x00
+#define PCIBIOS_FUNC_NOT_SUPPORTED	0x81
+#define PCIBIOS_BAD_VENDOR_ID		0x83
+#define PCIBIOS_DEVICE_NOT_FOUND	0x86
+#define PCIBIOS_BAD_REGISTER_NUMBER	0x87
 
 extern int pcibios_find_class (unsigned long class_code, unsigned short index, 
     unsigned char *bus, unsigned char *device_fn);
diff -u --recursive --new-file v1.1.88/linux/include/linux/elf.h linux/include/linux/elf.h
--- v1.1.88/linux/include/linux/elf.h	Sun Dec  4 23:56:28 1994
+++ linux/include/linux/elf.h	Sun Feb  5 14:44:32 1995
@@ -206,6 +206,27 @@
   Elf32_Word	sh_entsize;
 } Elf32_Shdr;
 
+#define	EI_MAG0		0		/* e_ident[] indexes */
+#define	EI_MAG1		1
+#define	EI_MAG2		2
+#define	EI_MAG3		3
+#define	EI_CLASS	4
+#define	EI_DATA		5
+#define	EI_VERSION	6
+#define	EI_PAD		7
+
+#define	ELFMAG0		0x7f		/* EI_MAG */
+#define	ELFMAG1		'E'
+#define	ELFMAG2		'L'
+#define	ELFMAG3		'F'
+#define	ELFMAG		"\177ELF"
+#define	SELFMAG		4
+
+#define	ELFCLASSNONE	0		/* EI_CLASS */
+#define	ELFCLASS32	1
+#define	ELFCLASS64	2
+#define	ELFCLASSNUM	3
+
 #define ELF_START_MMAP 0x80000000
 
 #endif /* _LINUX_ELF_H */
diff -u --recursive --new-file v1.1.88/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v1.1.88/linux/include/linux/if_arp.h	Fri Oct 21 09:39:32 1994
+++ linux/include/linux/if_arp.h	Sun Feb  5 14:27:28 1995
@@ -39,6 +39,7 @@
 #define ARPHRD_RSRVD	260		/* Notional KISS type 		*/
 #define ARPHRD_ADAPT	264
 #define ARPHRD_PPP	512
+#define ARPHRD_TUNNEL	768		/* IPIP tunnel			*/
 
 /* ARP protocol opcodes. */
 #define	ARPOP_REQUEST	1		/* ARP request			*/
diff -u --recursive --new-file v1.1.88/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v1.1.88/linux/include/linux/if_ether.h	Mon Jan 30 06:41:58 1995
+++ linux/include/linux/if_ether.h	Wed Feb  1 20:03:29 1995
@@ -36,6 +36,7 @@
 #define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
 #define ETH_P_RARP      0x8035		/* Reverse Addr Res packet	*/
 #define ETH_P_X25	0x0805		/* CCITT X.25			*/
+#define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
 #define ETH_P_IPX	0x8137		/* IPX over DIX			*/
 #define ETH_P_802_3	0x0001		/* Dummy type for 802.3 frames  */
 #define ETH_P_AX25	0x0002		/* Dummy protocol id for AX.25  */
diff -u --recursive --new-file v1.1.88/linux/include/linux/in.h linux/include/linux/in.h
--- v1.1.88/linux/include/linux/in.h	Mon Jan  9 07:22:10 1995
+++ linux/include/linux/in.h	Fri Feb  3 15:28:32 1995
@@ -24,6 +24,7 @@
   IPPROTO_IP = 0,		/* Dummy protocol for TCP		*/
   IPPROTO_ICMP = 1,		/* Internet Control Message Protocol	*/
   IPPROTO_IGMP = 2,		/* Internet Gateway Management Protocol */
+  IPPROTO_IPIP = 4,		/* IPIP tunnels (older KA9Q tunnels use 94) */
   IPPROTO_TCP = 6,		/* Transmission Control Protocol	*/
   IPPROTO_EGP = 8,		/* Exterior Gateway Protocol		*/
   IPPROTO_PUP = 12,		/* PUP protocol				*/
diff -u --recursive --new-file v1.1.88/linux/include/linux/ip_fw.h linux/include/linux/ip_fw.h
--- v1.1.88/linux/include/linux/ip_fw.h	Mon Jan  9 07:22:10 1995
+++ linux/include/linux/ip_fw.h	Sun Feb  5 14:44:40 1995
@@ -82,21 +82,25 @@
  *	a raw socket for this. Instead we check rights in the calls.
  */     
 
-#define IP_FW_BASE_CTL	64
+#define IP_FW_BASE_CTL   64
 
-#define IP_FW_ADD_BLK (IP_FW_BASE_CTL)
-#define IP_FW_ADD_FWD (IP_FW_BASE_CTL+1)   
-#define IP_FW_CHK_BLK (IP_FW_BASE_CTL+2)
-#define IP_FW_CHK_FWD (IP_FW_BASE_CTL+3)
-#define IP_FW_DEL_BLK (IP_FW_BASE_CTL+4)
-#define IP_FW_DEL_FWD (IP_FW_BASE_CTL+5)
-#define IP_FW_FLUSH   (IP_FW_BASE_CTL+6)
-#define IP_FW_POLICY  (IP_FW_BASE_CTL+7) 
-
-#define IP_ACCT_ADD   (IP_FW_BASE_CTL+10)
-#define IP_ACCT_DEL   (IP_FW_BASE_CTL+11)
-#define IP_ACCT_FLUSH (IP_FW_BASE_CTL+12)
-#define IP_ACCT_ZERO  (IP_FW_BASE_CTL+13)
+#define IP_FW_ADD_BLK    (IP_FW_BASE_CTL)
+#define IP_FW_ADD_FWD    (IP_FW_BASE_CTL+1)   
+#define IP_FW_CHK_BLK    (IP_FW_BASE_CTL+2)
+#define IP_FW_CHK_FWD    (IP_FW_BASE_CTL+3)
+#define IP_FW_DEL_BLK    (IP_FW_BASE_CTL+4)
+#define IP_FW_DEL_FWD    (IP_FW_BASE_CTL+5)
+#define IP_FW_FLUSH_BLK  (IP_FW_BASE_CTL+6)
+#define IP_FW_FLUSH_FWD  (IP_FW_BASE_CTL+7)
+#define IP_FW_ZERO_BLK   (IP_FW_BASE_CTL+8)
+#define IP_FW_ZERO_FWD   (IP_FW_BASE_CTL+9)
+#define IP_FW_POLICY_BLK (IP_FW_BASE_CTL+10)
+#define IP_FW_POLICY_FWD (IP_FW_BASE_CTL+11)
+
+#define IP_ACCT_ADD      (IP_FW_BASE_CTL+16)
+#define IP_ACCT_DEL      (IP_FW_BASE_CTL+17)
+#define IP_ACCT_FLUSH    (IP_FW_BASE_CTL+18)
+#define IP_ACCT_ZERO     (IP_FW_BASE_CTL+19)
 
 
 /*
@@ -110,13 +114,14 @@
 #ifdef CONFIG_IP_FIREWALL
 extern struct ip_fw *ip_fw_blk_chain;
 extern struct ip_fw *ip_fw_fwd_chain;
-extern int ip_fw_policy;
-extern int ip_fw_chk(struct iphdr *, struct ip_fw *);
+extern int ip_fw_blk_policy;
+extern int ip_fw_fwd_policy;
+extern int ip_fw_chk(struct iphdr *, struct ip_fw *, int);
 extern int ip_fw_ctl(int, void *, int);
 #endif
 #ifdef CONFIG_IP_ACCT
 extern struct ip_fw *ip_acct_chain;
-extern void ip_acct_cnt(struct iphdr *, struct ip_fw *, int);
+extern void ip_acct_cnt(struct iphdr *, struct ip_fw *);
 extern int ip_acct_ctl(int, void *, int);
 #endif
 #endif /* KERNEL */
diff -u --recursive --new-file v1.1.88/linux/include/linux/mc146818rtc.h linux/include/linux/mc146818rtc.h
--- v1.1.88/linux/include/linux/mc146818rtc.h	Wed Feb  1 09:23:07 1995
+++ linux/include/linux/mc146818rtc.h	Fri Feb  3 18:55:02 1995
@@ -12,22 +12,10 @@
 #define _MC146818RTC_H
 #include <asm/io.h>
 
+#ifndef RTC_PORT
 #define RTC_PORT(x)	(0x70 + (x))
 #define RTC_ADDR(x)	(0x80 | (x))
 #define RTC_ALWAYS_BCD	1
-
-/*
- * The Alpha Jensen hardware for some rather strange reason puts
- * the RTC clock at 0x170 instead of 0x70. Probably due to some
- * misguided idea about using 0x70 for NMI stuff.
- */
-#ifdef __alpha__
-#undef RTC_PORT
-#undef RTC_ADDR
-#undef RTC_ALWAYS_BCD
-#define RTC_PORT(x)	(0x170+(x))
-#define RTC_ADDR(x)	(x)
-#define RTC_ALWAYS_BCD	0
 #endif
 
 #define CMOS_READ(addr) ({ \
diff -u --recursive --new-file v1.1.88/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.1.88/linux/include/linux/mm.h	Wed Feb  1 09:23:07 1995
+++ linux/include/linux/mm.h	Sun Feb  5 14:16:32 1995
@@ -10,6 +10,8 @@
 
 #include <asm/page.h>
 
+#ifdef __KERNEL__
+
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
 
@@ -123,8 +125,6 @@
 	struct wait_queue *wait;
 };
 /* end of planning stage */
-
-#ifdef __KERNEL__
 
 /*
  * Free area management
diff -u --recursive --new-file v1.1.88/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v1.1.88/linux/include/linux/netdevice.h	Mon Jan  9 07:22:10 1995
+++ linux/include/linux/netdevice.h	Sun Feb  5 13:48:05 1995
@@ -72,7 +72,7 @@
   unsigned long		  rmem_start;		/* shmem "recv" start	*/
   unsigned long		  mem_end;		/* sahared mem end	*/
   unsigned long		  mem_start;		/* shared mem start	*/
-  unsigned short	  base_addr;		/* device I/O address	*/
+  unsigned long		  base_addr;		/* device I/O address	*/
   unsigned char		  irq;			/* device IRQ number	*/
 
   /* Low-level status flags. */
diff -u --recursive --new-file v1.1.88/linux/include/linux/pci.h linux/include/linux/pci.h
--- v1.1.88/linux/include/linux/pci.h	Thu Jan 26 07:49:15 1995
+++ linux/include/linux/pci.h	Fri Feb  3 19:28:28 1995
@@ -489,38 +489,6 @@
 	{0x0	,0x0	,0x0	}  \
 }
 
+#include <linux/bios32.h>
 
-/* PCI BIOS */
-
-extern int pcibios_present (void);
-
-#define PCIBIOS_SUCCESSFUL		0x00
-#define PCIBIOS_FUNC_NOT_SUPPORTED	0x81
-#define PCIBIOS_BAD_VENDOR_ID		0x83
-#define PCIBIOS_DEVICE_NOT_FOUND	0x86
-#define PCIBIOS_BAD_REGISTER_NUMBER	0x87
-
-/*
- * The PCIBIOS calls all bit-field the device_function variable such that 
- * the bit fielding matches that of the bl register used in the actual
- * calls.
- */
-
-extern int pcibios_find_class (unsigned long class_code, unsigned short index, 
-    unsigned char *bus, unsigned char *device_fn);
-extern int pcibios_find_device (unsigned short vendor, unsigned short device_id, 
-    unsigned short index, unsigned char *bus, unsigned char *device_fn);
-extern int pcibios_read_config_byte (unsigned char bus,
-    unsigned char device_fn, unsigned char where, unsigned char *value);
-extern int pcibios_read_config_word (unsigned char bus,
-    unsigned char device_fn, unsigned char where, unsigned short *value);
-extern int pcibios_read_config_dword (unsigned char bus,
-    unsigned char device_fn, unsigned char where, unsigned long *value);
-extern char *pcibios_strerror (int error);
-extern int pcibios_write_config_byte (unsigned char bus,
-    unsigned char device_fn, unsigned char where, unsigned char value);
-extern int pcibios_write_config_word (unsigned char bus,
-    unsigned char device_fn, unsigned char where, unsigned short value);
-extern pcibios_write_config_dword (unsigned char bus,
-    unsigned char device_fn, unsigned char where, unsigned long value);
 #endif /* ndef PCI_H */
diff -u --recursive --new-file v1.1.88/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.1.88/linux/include/linux/proc_fs.h	Wed Feb  1 09:23:07 1995
+++ linux/include/linux/proc_fs.h	Sun Feb  5 14:44:40 1995
@@ -69,10 +69,13 @@
 #endif
 #ifdef CONFIG_IP_FIREWALL
 	PROC_NET_IPFWFWD,
-	PROC_NET_IPBLFWD,
+	PROC_NET_IPFWFWD0,
+	PROC_NET_IPFWBLK,
+	PROC_NET_IPFWBLK0,
 #endif
 #ifdef CONFIG_IP_ACCT
 	PROC_NET_IPACCT,
+	PROC_NET_IPACCT0,
 #endif
 #if	defined(CONFIG_WAVELAN)
 	PROC_NET_WAVELAN,
diff -u --recursive --new-file v1.1.88/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.1.88/linux/include/linux/sched.h	Mon Jan 30 06:41:58 1995
+++ linux/include/linux/sched.h	Wed Feb  1 09:19:36 1995
@@ -180,6 +180,7 @@
 	struct tty_struct *tty; /* NULL if no tty */
 /* ipc stuff */
 	struct sem_undo *semundo;
+	struct sem_queue *semsleeping;
 /* ldt for this task - used by Wine.  If NULL, default_ldt is used */
 	struct desc_struct *ldt;
 /* tss for this task */
@@ -232,7 +233,7 @@
 /* math */	0, \
 /* comm */	"swapper", \
 /* fs info */	0,NULL, \
-/* ipc */	NULL, \
+/* ipc */	NULL, NULL, \
 /* ldt */	NULL, \
 /* tss */	INIT_TSS, \
 /* fs */	{ INIT_FS }, \
diff -u --recursive --new-file v1.1.88/linux/include/linux/sem.h linux/include/linux/sem.h
--- v1.1.88/linux/include/linux/sem.h	Tue Nov  1 19:50:45 1994
+++ linux/include/linux/sem.h	Wed Feb  1 09:19:36 1995
@@ -3,7 +3,7 @@
 #include <linux/ipc.h>
 
 /* semop flags */
-#define SEM_UNDO        010000  /* undo the operation on exit */
+#define SEM_UNDO        0x1000  /* undo the operation on exit */
 
 /* semctl Command Definitions. */
 #define GETPID  11       /* get sempid */
@@ -16,14 +16,14 @@
 
 /* One semid data structure for each set of semaphores in the system. */
 struct semid_ds {
-  struct ipc_perm sem_perm;       /* permissions .. see ipc.h */
-  time_t          sem_otime;      /* last semop time */
-  time_t          sem_ctime;      /* last change time */
-  struct sem      *sem_base;      /* ptr to first semaphore in array */
-  struct wait_queue *eventn;
-  struct wait_queue *eventz;
-  struct sem_undo  *undo;	  /* undo requests on this array */
-  ushort          sem_nsems;      /* no. of semaphores in array */
+  struct ipc_perm sem_perm;            /* permissions .. see ipc.h */
+  time_t          sem_otime;           /* last semop time */
+  time_t          sem_ctime;           /* last change time */
+  struct sem      *sem_base;           /* ptr to first semaphore in array */
+  struct sem_queue *sem_pending;       /* pending operations to be processed */
+  struct sem_queue **sem_pending_last; /* last pending operation */
+  struct sem_undo *undo;	       /* undo requests on this array */
+  ushort          sem_nsems;           /* no. of semaphores in array */
 };
 
 /* semop system calls takes an array of these. */
@@ -43,16 +43,16 @@
 };
 
 struct  seminfo {
-    int semmap; 
-    int semmni; 
-    int semmns; 
-    int semmnu; 
-    int semmsl; 
-    int semopm; 
-    int semume; 
-    int semusz; 
-    int semvmx; 
-    int semaem; 
+    int semmap;
+    int semmni;
+    int semmns;
+    int semmnu;
+    int semmsl;
+    int semopm;
+    int semume;
+    int semusz;
+    int semvmx;
+    int semaem;
 };
 
 #define SEMMNI  128             /* ?  max # of semaphore identifiers */
@@ -66,31 +66,42 @@
 #define SEMMNU  SEMMNS          /* num of undo structures system wide */
 #define SEMAEM  (SEMVMX >> 1)   /* adjust on exit max value */
 #define SEMMAP  SEMMNS          /* # of entries in semaphore map */
-#define SEMUSZ  20		/* sizeof struct sem_undo */ 
+#define SEMUSZ  20		/* sizeof struct sem_undo */
 
 #ifdef __KERNEL__
 
 /* One semaphore structure for each semaphore in the system. */
 struct sem {
+  short   semval;         /* current value */
   short   sempid;         /* pid of last operation */
-  ushort  semval;         /* current value */
-  ushort  semncnt;        /* num procs awaiting increase in semval */
-  ushort  semzcnt;        /* num procs awaiting semval = 0 */
 };
 
 /* ipcs ctl cmds */
-#define SEM_STAT 18	
+#define SEM_STAT 18
 #define SEM_INFO 19
 
-/* per process undo requests */
-/* this gets linked into the task_struct */
+/* One queue for each semaphore set in the system. */
+struct sem_queue {
+    struct sem_queue *	next;	 /* next entry in the queue */
+    struct sem_queue **	prev;	 /* previous entry in the queue, *(q->prev) == q */
+    struct wait_queue *	sleeper; /* sleeping process */
+    struct sem_undo *	undo;	 /* undo structure */
+    int    		pid;	 /* process id of requesting process */
+    int    		status;	 /* completion status of operation */
+    struct semid_ds *	sma;	 /* semaphore array for operations */
+    struct sembuf *	sops;	 /* array of pending operations */
+    int			nsops;	 /* number of operations */
+};
+
+/* Each task has a list of undo requests. They are executed automatically
+ * when the process exits.
+ */
 struct sem_undo {
-    struct sem_undo *proc_next;
-    struct sem_undo *id_next;
-    int    semid;
-    short  semadj; 		/* semval adjusted by exit */
-    ushort sem_num; 		/* semaphore index in array semid */
-};      
+    struct sem_undo *  proc_next; /* next entry on this process */
+    struct sem_undo *  id_next;	  /* next entry on this semaphore set */
+    int		       semid;	  /* semaphore set identifier */
+    short *	       semadj;	  /* array of adjustments, one per semaphore */
+};
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v1.1.88/linux/include/linux/socket.h linux/include/linux/socket.h
--- v1.1.88/linux/include/linux/socket.h	Sun Jan  1 15:33:21 1995
+++ linux/include/linux/socket.h	Wed Feb  1 20:03:22 1995
@@ -56,6 +56,7 @@
 #define SOL_IP		0
 #define SOL_IPX		256
 #define SOL_AX25	257
+#define SOL_ATALK	258
 #define SOL_TCP		6
 #define SOL_UDP		17
 
diff -u --recursive --new-file v1.1.88/linux/include/linux/time.h linux/include/linux/time.h
--- v1.1.88/linux/include/linux/time.h	Mon Jan  2 09:06:25 1995
+++ linux/include/linux/time.h	Wed Feb  1 09:19:36 1995
@@ -14,6 +14,7 @@
 #define NFDBITS			__NFDBITS
 
 #ifdef __KERNEL__
+void do_gettimeofday(struct timeval *tv);
 #include <asm/bitops.h>
 #include <linux/string.h>
 #define FD_SETSIZE		__FD_SETSIZE
diff -u --recursive --new-file v1.1.88/linux/ipc/sem.c linux/ipc/sem.c
--- v1.1.88/linux/ipc/sem.c	Mon Dec 12 21:41:30 1994
+++ linux/ipc/sem.c	Wed Feb  1 09:19:36 1995
@@ -1,6 +1,34 @@
 /*
  * linux/ipc/sem.c
- * Copyright (C) 1992 Krishna Balasubramanian 
+ * Copyright (C) 1992 Krishna Balasubramanian
+ * Copyright (C) 1995 Eric Schenk, Bruno Haible
+ *
+ * IMPLEMENTATION NOTES ON CODE REWRITE (Eric Schenk, January 1995):
+ * This code underwent a massive rewrite in order to solve some problems
+ * with the original code. In particular the original code failed to
+ * wake up processes that were waiting for semval to go to 0 if the
+ * value went to 0 and was then incremented rapidly enough. In solving
+ * this problem I have also modified the implementation so that it
+ * processes pending operations in a FIFO manner, thus give a guarentee
+ * that processes waiting for a lock on the semaphore won't starve
+ * unless another locking process fails to unlock.
+ * In addition the following two changes in behavior have been introduced:
+ * - The original implementation of semop returned the value
+ *   last semaphore element examined on success. This does not
+ *   match the manual page specifications, and effectively
+ *   allows the user to read the semaphore even if they do not
+ *   have read permissions. The implementation now returns 0
+ *   on success as stated in the manual page.
+ * - There is some confusion over whether the set of undo adjustments
+ *   to be peformed at exit should be done in an atomic manner.
+ *   That is, if we are attempting to decrement the semval should we queue
+ *   up and wait until we can do so legally?
+ *   The original implementation attempted to do this.
+ *   The current implementation does not do so. This is because I don't
+ *   think it is the right thing (TM) to do, and because I couldn't
+ *   see a clean way to get the old behavior with the new design.
+ *   The POSIX standard and SVID should be consulted to determine
+ *   what behavior is mandated.
  */
 
 #include <linux/errno.h>
@@ -18,7 +46,7 @@
 static void freeary (int id);
 
 static struct semid_ds *semary[SEMMNI];
-static int used_sems = 0, used_semids = 0;                    
+static int used_sems = 0, used_semids = 0;
 static struct wait_queue *sem_lock = NULL;
 static int max_semid = 0;
 
@@ -27,7 +55,7 @@
 void sem_init (void)
 {
 	int i;
-	
+
 	sem_lock = NULL;
 	used_sems = used_semids = max_semid = sem_seq = 0;
 	for (i = 0; i < SEMMNI; i++)
@@ -39,9 +67,9 @@
 {
 	int id;
 	struct semid_ds *sma;
-	
+
 	for (id = 0; id <= max_semid; id++) {
-		while ((sma = semary[id]) == IPC_NOID) 
+		while ((sma = semary[id]) == IPC_NOID)
 			interruptible_sleep_on (&sem_lock);
 		if (sma == IPC_UNUSED)
 			continue;
@@ -62,7 +90,7 @@
 		return -EINVAL;
 	if (used_sems + nsems > SEMMNS)
 		return -ENOSPC;
-	for (id = 0; id < SEMMNI; id++) 
+	for (id = 0; id < SEMMNI; id++)
 		if (semary[id] == IPC_UNUSED) {
 			semary[id] = (struct semid_ds *) IPC_NOID;
 			goto found;
@@ -87,10 +115,12 @@
 	ipcp->cuid = ipcp->uid = current->euid;
 	ipcp->gid = ipcp->cgid = current->egid;
 	sma->sem_perm.seq = sem_seq;
-	sma->eventn = sma->eventz = NULL;
+	/* sma->sem_pending = NULL; */
+	sma->sem_pending_last = &sma->sem_pending;
+	/* sma->undo = NULL; */
 	sma->sem_nsems = nsems;
 	sma->sem_ctime = CURRENT_TIME;
-        if (id > max_semid)
+	if (id > max_semid)
 		max_semid = id;
 	used_semids++;
 	semary[id] = sma;
@@ -103,10 +133,10 @@
 {
 	int id;
 	struct semid_ds *sma;
-	
-	if (nsems < 0  || nsems > SEMMSL)
+
+	if (nsems < 0 || nsems > SEMMSL)
 		return -EINVAL;
-	if (key == IPC_PRIVATE) 
+	if (key == IPC_PRIVATE)
 		return newary(key, nsems, semflg);
 	if ((id = findkey (key)) == -1) {  /* key not used */
 		if (!(semflg & IPC_CREAT))
@@ -121,13 +151,188 @@
 	if (ipcperms(&sma->sem_perm, semflg))
 		return -EACCES;
 	return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
-} 
+}
+
+/* Manage the doubly linked list sma->sem_pending as a FIFO:
+ * insert new queue elements at the tail sma->sem_pending_last.
+ */
+static inline void insert_into_queue (struct semid_ds * sma, struct sem_queue * q)
+{
+	*(q->prev = sma->sem_pending_last) = q;
+	*(sma->sem_pending_last = &q->next) = NULL;
+}
+static inline void remove_from_queue (struct semid_ds * sma, struct sem_queue * q)
+{
+	*(q->prev) = q->next;
+	if (q->next)
+		q->next->prev = q->prev;
+	else /* sma->sem_pending_last == &q->next */
+		sma->sem_pending_last = q->prev;
+	q->prev = NULL; /* mark as removed */
+}
+
+/* Determine whether a sequence of semaphore operations would succeed
+ * all at once. Return 0 if yes, 1 if need to sleep, else return error code.
+ */
+static int try_semop (struct semid_ds * sma, struct sembuf * sops, int nsops)
+{
+	int result = 0;
+	int i = 0;
+
+	while (i < nsops) {
+		struct sembuf * sop = &sops[i];
+		struct sem * curr = &sma->sem_base[sop->sem_num];
+		if (sop->sem_op + curr->semval > SEMVMX) {
+			result = -ERANGE;
+			break;
+		}
+		if (!sop->sem_op && curr->semval) {
+			if (sop->sem_flg & IPC_NOWAIT)
+				result = -EAGAIN;
+			else
+				result = 1;
+			break;
+		}
+		i++;
+		curr->semval += sop->sem_op;
+		if (curr->semval < 0) {
+			if (sop->sem_flg & IPC_NOWAIT)
+				result = -EAGAIN;
+			else
+				result = 1;
+			break;
+		}
+	}
+	while (--i >= 0) {
+		struct sembuf * sop = &sops[i];
+		struct sem * curr = &sma->sem_base[sop->sem_num];
+		curr->semval -= sop->sem_op;
+	}
+	return result;
+}
+
+/* Actually perform a sequence of semaphore operations. Atomically. */
+/* This assumes that try_semop() already returned 0. */
+static int do_semop (struct semid_ds * sma, struct sembuf * sops, int nsops,
+		     struct sem_undo * un, int pid)
+{
+	int i;
+
+	for (i = 0; i < nsops; i++) {
+		struct sembuf * sop = &sops[i];
+		struct sem * curr = &sma->sem_base[sop->sem_num];
+		if (sop->sem_op + curr->semval > SEMVMX) {
+			printk("do_semop: race\n");
+			break;
+		}
+		if (!sop->sem_op) {
+			if (curr->semval) {
+				printk("do_semop: race\n");
+				break;
+			}
+		} else {
+			curr->semval += sop->sem_op;
+			if (curr->semval < 0) {
+				printk("do_semop: race\n");
+				break;
+			}
+			if (sop->sem_flg & SEM_UNDO)
+				un->semadj[sop->sem_num] -= sop->sem_op;
+		}
+		curr->sempid = pid;
+	}
+	sma->sem_otime = CURRENT_TIME;
+
+	/* Previous implementation returned the last semaphore's semval.
+	 * This is wrong because we may not have checked read permission,
+	 * only write permission.
+	 */
+	return 0;
+}
+
+/* Go through the pending queue for the indicated semaphore
+ * looking for tasks that can be completed. Keep cycling through
+ * the queue until a pass is made in which no process is woken up.
+ */
+static void update_queue (struct semid_ds * sma)
+{
+	int wokeup, error;
+	struct sem_queue * q;
+
+	do {
+		wokeup = 0;
+		for (q = sma->sem_pending; q; q = q->next) {
+			error = try_semop(sma, q->sops, q->nsops);
+			/* Does q->sleeper still need to sleep? */
+			if (error > 0)
+				continue;
+			/* Perform the operations the sleeper was waiting for */
+			if (!error)
+				error = do_semop(sma, q->sops, q->nsops, q->undo, q->pid);
+			q->status = error;
+			/* Remove it from the queue */
+			remove_from_queue(sma,q);
+			/* Wake it up */
+			wake_up_interruptible(&q->sleeper); /* doesn't sleep! */
+			wokeup++;
+		}
+	} while (wokeup);
+}
+
+/* The following counts are associated to each semaphore:
+ *   semncnt        number of tasks waiting on semval being nonzero
+ *   semzcnt        number of tasks waiting on semval being zero
+ * This model assumes that a task waits on exactly one semaphore.
+ * Since semaphore operations are to be performed atomically, tasks actually
+ * wait on a whole sequence of semaphores simultaneously.
+ * The counts we return here are a rough approximation, but still
+ * warrant that semncnt+semzcnt>0 if the task is on the pending queue.
+ */
+static int count_semncnt (struct semid_ds * sma, ushort semnum)
+{
+	int semncnt;
+	struct sem_queue * q;
+
+	semncnt = 0;
+	for (q = sma->sem_pending; q; q = q->next) {
+		struct sembuf * sops = q->sops;
+		int nsops = q->nsops;
+		int i;
+		for (i = 0; i < nsops; i++)
+			if (sops[i].sem_num == semnum
+			    && (sops[i].sem_op < 0)
+			    && !(sops[i].sem_flg & IPC_NOWAIT))
+				semncnt++;
+	}
+	return semncnt;
+}
+static int count_semzcnt (struct semid_ds * sma, ushort semnum)
+{
+	int semzcnt;
+	struct sem_queue * q;
+
+	semzcnt = 0;
+	for (q = sma->sem_pending; q; q = q->next) {
+		struct sembuf * sops = q->sops;
+		int nsops = q->nsops;
+		int i;
+		for (i = 0; i < nsops; i++)
+			if (sops[i].sem_num == semnum
+			    && (sops[i].sem_op == 0)
+			    && !(sops[i].sem_flg & IPC_NOWAIT))
+				semzcnt++;
+	}
+	return semzcnt;
+}
 
+/* Free a semaphore set. */
 static void freeary (int id)
 {
 	struct semid_ds *sma = semary[id];
 	struct sem_undo *un;
+	struct sem_queue *q;
 
+	/* Invalidate this semaphore set */
 	sma->sem_perm.seq++;
 	sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI); /* increment, but avoid overflow */
 	used_sems -= sma->sem_nsems;
@@ -135,17 +340,21 @@
 		while (max_semid && (semary[--max_semid] == IPC_UNUSED));
 	semary[id] = (struct semid_ds *) IPC_UNUSED;
 	used_semids--;
+
+	/* Invalidate the existing undo structures for this semaphore set.
+	 * (They will be freed without any further action in sem_exit().)
+	 */
 	for (un = sma->undo; un; un = un->id_next)
-	        un->semadj = 0;
-	while (sma->eventz || sma->eventn) {
-		if (sma->eventz)
-			wake_up (&sma->eventz);
-		if (sma->eventn)
-			wake_up (&sma->eventn);
-		schedule();
+		un->semid = -1;
+
+	/* Wake up all pending processes and let them fail with EIDRM. */
+	for (q = sma->sem_pending; q; q = q->next) {
+		q->status = -EIDRM;
+		q->prev = NULL;
+		wake_up_interruptible(&q->sleeper); /* doesn't sleep! */
 	}
+
 	kfree(sma);
-	return;
 }
 
 int sys_semctl (int semid, int semnum, int cmd, union semun arg)
@@ -165,8 +374,8 @@
 		return -EINVAL;
 
 	switch (cmd) {
-	case IPC_INFO: 
-	case SEM_INFO: 
+	case IPC_INFO:
+	case SEM_INFO:
 	{
 		struct seminfo seminfo, *tmp = arg.__buf;
 		seminfo.semmni = SEMMNI;
@@ -174,8 +383,8 @@
 		seminfo.semmsl = SEMMSL;
 		seminfo.semopm = SEMOPM;
 		seminfo.semvmx = SEMVMX;
-		seminfo.semmnu = SEMMNU; 
-		seminfo.semmap = SEMMAP; 
+		seminfo.semmnu = SEMMNU;
+		seminfo.semmap = SEMMAP;
 		seminfo.semume = SEMUME;
 		seminfo.semusz = SEMUSZ;
 		seminfo.semaem = SEMAEM;
@@ -241,10 +450,10 @@
 		if (ipcperms (ipcp, S_IRUGO))
 			return -EACCES;
 		switch (cmd) {
-		case GETVAL : return curr->semval; 
+		case GETVAL : return curr->semval;
 		case GETPID : return curr->sempid;
-		case GETNCNT: return curr->semncnt;
-		case GETZCNT: return curr->semzcnt;
+		case GETNCNT: return count_semncnt(sma,semnum);
+		case GETZCNT: return count_semzcnt(sma,semnum);
 		case GETALL:
 			array = arg.array;
 			i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
@@ -254,13 +463,12 @@
 		break;
 	case SETVAL:
 		val = arg.val;
-		if (val > SEMVMX || val < 0) 
+		if (val > SEMVMX || val < 0)
 			return -ERANGE;
 		break;
 	case IPC_RMID:
-		if (suser() || current->euid == ipcp->cuid || 
-		    current->euid == ipcp->uid) {
-			freeary (id); 
+		if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) {
+			freeary (id);
 			return 0;
 		}
 		return -EPERM;
@@ -285,12 +493,12 @@
 		memcpy_fromfs (&tbuf, buf, sizeof (*buf));
 		break;
 	}
-	
+
 	if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
 		return -EIDRM;
 	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
 		return -EIDRM;
-	
+
 	switch (cmd) {
 	case GETALL:
 		if (ipcperms (ipcp, S_IRUGO))
@@ -303,18 +511,14 @@
 		if (ipcperms (ipcp, S_IWUGO))
 			return -EACCES;
 		for (un = sma->undo; un; un = un->id_next)
-			if (semnum == un->sem_num)
-				un->semadj = 0;
-		sma->sem_ctime = CURRENT_TIME;
+			un->semadj[semnum] = 0;
 		curr->semval = val;
-		if (sma->eventn)
-			wake_up (&sma->eventn);
-		if (sma->eventz)
-			wake_up (&sma->eventz);
+		sma->sem_ctime = CURRENT_TIME;
+		/* maybe some queued-up processes were waiting for this */
+		update_queue(sma);
 		break;
 	case IPC_SET:
-		if (suser() || current->euid == ipcp->cuid || 
-		    current->euid == ipcp->uid) {
+		if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) {
 			ipcp->uid = tbuf.sem_perm.uid;
 			ipcp->gid = tbuf.sem_perm.gid;
 			ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
@@ -335,15 +539,14 @@
 	case SETALL:
 		if (ipcperms (ipcp, S_IWUGO))
 			return -EACCES;
-		for (i = 0; i < nsems; i++) 
+		for (i = 0; i < nsems; i++)
 			sma->sem_base[i].semval = sem_io[i];
 		for (un = sma->undo; un; un = un->id_next)
-			un->semadj = 0;
-		if (sma->eventn)
-			wake_up (&sma->eventn);
-		if (sma->eventz)
-			wake_up (&sma->eventz);
+			for (i = 0; i < nsems; i++)
+				un->semadj[i] = 0;
 		sma->sem_ctime = CURRENT_TIME;
+		/* maybe some queued-up processes were waiting for this */
+		update_queue(sma);
 		break;
 	default:
 		return -EINVAL;
@@ -353,170 +556,155 @@
 
 int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
 {
-	int i, id;
+	int i, id, size, error;
 	struct semid_ds *sma;
-	struct sem *curr = NULL;
 	struct sembuf sops[SEMOPM], *sop;
 	struct sem_undo *un;
-	int undos = 0, alter = 0, semncnt = 0, semzcnt = 0;
-	
+	int undos = 0, alter = 0;
+
 	if (nsops < 1 || semid < 0)
 		return -EINVAL;
 	if (nsops > SEMOPM)
 		return -E2BIG;
-	if (!tsops) 
+	if (!tsops)
 		return -EFAULT;
 	if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops))))
 		return i;
-	memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops));  
+	memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops));
 	id = (unsigned int) semid % SEMMNI;
 	if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
 		return -EINVAL;
-	for (i = 0; i < nsops; i++) { 
+	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
+		return -EIDRM;
+	for (i = 0; i < nsops; i++) {
 		sop = &sops[i];
-		if (sop->sem_num > sma->sem_nsems)
+		if (sop->sem_num >= sma->sem_nsems)
 			return -EFBIG;
 		if (sop->sem_flg & SEM_UNDO)
 			undos++;
-		if (sop->sem_op) {
+		if (sop->sem_op)
 			alter++;
-			if (sop->sem_op > 0)
-				semncnt ++;
-		}
 	}
 	if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
 		return -EACCES;
-	/* 
-	 * ensure every sop with undo gets an undo structure 
-	 */
+	error = try_semop(sma, sops, nsops);
+	if (error < 0)
+		return error;
 	if (undos) {
-		for (i = 0; i < nsops; i++) {
-			if (!(sops[i].sem_flg & SEM_UNDO))
-				continue;
-			for (un = current->semundo; un; un = un->proc_next) 
-				if ((un->semid == semid) && 
-				    (un->sem_num == sops[i].sem_num))
-					break;
-			if (un)
-				continue;
-			un = (struct sem_undo *) 
-				kmalloc (sizeof(*un), GFP_ATOMIC);
+		/* Make sure we have an undo structure
+		 * for this process and this semaphore set.
+		 */
+		for (un = current->semundo; un; un = un->proc_next)
+			if (un->semid == semid)
+				break;
+		if (!un) {
+			size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems;
+			un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);
 			if (!un)
-				return -ENOMEM; /* freed on exit */
+				return -ENOMEM;
+			memset(un, 0, size);
+			un->semadj = (short *) &un[1];
 			un->semid = semid;
-			un->semadj = 0;
-			un->sem_num = sops[i].sem_num;
 			un->proc_next = current->semundo;
 			current->semundo = un;
 			un->id_next = sma->undo;
 			sma->undo = un;
 		}
-	}
-	
- slept:
-	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) 
-		return -EIDRM;
-	for (i = 0; i < nsops; i++) {
-		sop = &sops[i];
-		curr = &sma->sem_base[sop->sem_num];
-		if (sop->sem_op + curr->semval > SEMVMX)
-			return -ERANGE;
-		if (!sop->sem_op && curr->semval) { 
-			if (sop->sem_flg & IPC_NOWAIT)
-				return -EAGAIN;
-			if (current->signal & ~current->blocked) 
-				return -EINTR;
-			curr->semzcnt++;
-			interruptible_sleep_on (&sma->eventz);
-			curr->semzcnt--;
-			goto slept;
-		}
-		if ((sop->sem_op + curr->semval < 0) ) { 
-			if (sop->sem_flg & IPC_NOWAIT)
-				return -EAGAIN;
-			if (current->signal & ~current->blocked)
-				return -EINTR;
-			curr->semncnt++;
-			interruptible_sleep_on (&sma->eventn);
-			curr->semncnt--;
-			goto slept;
-		}
-	}
-	
-	for (i = 0; i < nsops; i++) {
-		sop = &sops[i];
-		curr = &sma->sem_base[sop->sem_num];
-		curr->sempid = current->pid;
-		if (!(curr->semval += sop->sem_op))
-			semzcnt++;
-		if (!(sop->sem_flg & SEM_UNDO))
-			continue;
-		for (un = current->semundo; un; un = un->proc_next) 
-			if ((un->semid == semid) && 
-			    (un->sem_num == sop->sem_num))
-				break;
-		if (!un) {
-			printk ("semop : no undo for op %d\n", i);
-			continue;
+	} else
+		un = NULL;
+	if (error == 0) {
+		/* the operations go through immediately */
+		error = do_semop(sma, sops, nsops, un, current->pid);
+		/* maybe some queued-up processes were waiting for this */
+		update_queue(sma);
+		return error;
+	} else {
+		/* We need to sleep on this operation, so we put the current
+		 * task into the pending queue and go to sleep.
+		 */
+		struct sem_queue queue;
+
+		queue.sma = sma;
+		queue.sops = sops;
+		queue.nsops = nsops;
+		queue.undo = un;
+		queue.pid = current->pid;
+		queue.status = 0;
+		insert_into_queue(sma,&queue);
+		queue.sleeper = NULL;
+		current->semsleeping = &queue;
+		interruptible_sleep_on(&queue.sleeper);
+		current->semsleeping = NULL;
+		/* When we wake up, either the operation is finished,
+		 * or some kind of error happened.
+		 */
+		if (!queue.prev) {
+			/* operation is finished, update_queue() removed us */
+			return queue.status;
+		} else {
+			remove_from_queue(sma,&queue);
+			return -EINTR;
 		}
-		un->semadj -= sop->sem_op;
 	}
-	sma->sem_otime = CURRENT_TIME; 
-       	if (semncnt && sma->eventn)
-		wake_up(&sma->eventn);
-	if (semzcnt && sma->eventz)
-		wake_up(&sma->eventz);
-	return curr->semval;
 }
 
 /*
  * add semadj values to semaphores, free undo structures.
  * undo structures are not freed when semaphore arrays are destroyed
  * so some of them may be out of date.
+ * IMPLEMENTATION NOTE: There is some confusion over whether the
+ * set of adjustments that needs to be done should be done in an atomic
+ * manner or not. That is, if we are attempting to decrement the semval
+ * should we queue up and wait until we can do so legally?
+ * The original implementation attempted to do this (queue and wait).
+ * The current implementation does not do so. The POSIX standard
+ * and SVID should be consulted to determine what behavior is mandated.
  */
 void sem_exit (void)
 {
+	struct sem_queue *q;
 	struct sem_undo *u, *un = NULL, **up, **unp;
 	struct semid_ds *sma;
-	struct sem *sem = NULL;
-	
+	int nsems, i;
+
+	/* If the current process was sleeping for a semaphore,
+	 * remove it from the queue.
+	 */
+	if ((q = current->semsleeping)) {
+		if (q->prev)
+			remove_from_queue(q->sma,q);
+		current->semsleeping = NULL;
+	}
+
 	for (up = &current->semundo; (u = *up); *up = u->proc_next, kfree(u)) {
+		if (u->semid == -1)
+			continue;
 		sma = semary[(unsigned int) u->semid % SEMMNI];
-		if (sma == IPC_UNUSED || sma == IPC_NOID) 
+		if (sma == IPC_UNUSED || sma == IPC_NOID)
 			continue;
 		if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI)
 			continue;
+		/* remove u from the sma->undo list */
 		for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
-			if (u == un) 
+			if (u == un)
 				goto found;
 		}
 		printk ("sem_exit undo list error id=%d\n", u->semid);
 		break;
 found:
 		*unp = un->id_next;
-		if (!un->semadj)
-			continue;
-		while (1) {
-			if (sma->sem_perm.seq != (unsigned int) un->semid / SEMMNI)
-				break;
-			sem = &sma->sem_base[un->sem_num];
-			if (sem->semval + un->semadj >= 0) {
-				sem->semval += un->semadj;
-				sem->sempid = current->pid;
-				sma->sem_otime = CURRENT_TIME;
-				if (un->semadj > 0 && sma->eventn)
-					wake_up (&sma->eventn);
-				if (!sem->semval && sma->eventz)
-					wake_up (&sma->eventz);
-				break;
-			} 
-			if (current->signal & ~current->blocked)
-				break;
-			sem->semncnt++;
-			interruptible_sleep_on (&sma->eventn);
-			sem->semncnt--;
-		}
+		/* perform adjustments registered in u */
+		nsems = sma->sem_nsems;
+		for (i = 0; i < nsems; i++) {
+			struct sem * sem = &sma->sem_base[i];
+			sem->semval += u->semadj[i];
+			if (sem->semval < 0)
+				sem->semval = 0; /* shouldn't happen */
+			sem->sempid = current->pid;
+		}
+		sma->sem_otime = CURRENT_TIME;
+		/* maybe some queued-up processes were waiting for this */
+		update_queue(sma);
 	}
 	current->semundo = NULL;
-	return;
 }
diff -u --recursive --new-file v1.1.88/linux/kernel/exit.c linux/kernel/exit.c
--- v1.1.88/linux/kernel/exit.c	Sun Jan 22 21:39:45 1995
+++ linux/kernel/exit.c	Wed Feb  1 09:19:36 1995
@@ -380,8 +380,7 @@
 		intr_count = 0;
 	}
 fake_volatile:
-	if (current->semundo)
-		sem_exit();
+	sem_exit();
 	exit_mmap(current);
 	free_page_tables(current);
 	exit_files();
diff -u --recursive --new-file v1.1.88/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.88/linux/kernel/ksyms.c	Mon Jan 30 06:41:59 1995
+++ linux/kernel/ksyms.c	Fri Feb  3 15:28:32 1995
@@ -37,6 +37,8 @@
 #ifdef CONFIG_INET
 #include <linux/net.h>
 #include <linux/netdevice.h>
+#include <linux/ip.h>
+#include "../net/inet/protocol.h"
 #endif
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
@@ -202,6 +204,10 @@
 	/* dma handling */
 	X(request_dma),
 	X(free_dma),
+#ifdef HAVE_DISABLE_HLT
+	X(disable_hlt),
+	X(enable_hlt),
+#endif
 
 	/* IO port handling */
 	X(check_region),
@@ -247,10 +253,19 @@
 
 	/* Miscellaneous access points */
 	X(si_meminfo),
-
+#ifdef CONFIG_NET
 	/* socket layer registration */
 	X(sock_register),
 	X(sock_unregister),
+	/* Internet layer registration */
+#ifdef CONFIG_INET	
+	X(inet_add_protocol),
+	X(inet_del_protocol),
+#endif
+	/* Device callback registration */
+	X(register_netdevice_notifier),
+	X(unregister_netdevice_notifier),
+#endif
 
 #ifdef CONFIG_FTAPE
 	/* The next labels are needed for ftape driver.  */
@@ -275,6 +290,11 @@
 	X(dev_ioctl),
 	X(dev_queue_xmit),
 	X(dev_base),
+	X(dev_close),
+	X(n_tty_ioctl),
+	X(tty_register_ldisc),
+	X(kill_fasync),
+	X(tty_hung_up_p),
 #endif
 #ifdef CONFIG_SCSI
 	/* Supports loadable scsi drivers */
@@ -284,6 +304,7 @@
 	X(scsi_malloc),
 	X(scsi_register),
 	X(scsi_unregister),
+	X(scsicam_bios_param),
 #endif
 	/* Added to make file system as module */
 	X(set_writetime),
diff -u --recursive --new-file v1.1.88/linux/kernel/sched.c linux/kernel/sched.c
--- v1.1.88/linux/kernel/sched.c	Wed Feb  1 09:23:08 1995
+++ linux/kernel/sched.c	Wed Feb  1 21:46:08 1995
@@ -770,4 +770,7 @@
 	bh_base[IMMEDIATE_BH].routine = immediate_bh;
 	if (request_irq(TIMER_IRQ, do_timer, 0, "timer") != 0)
 		panic("Could not allocate timer IRQ!");
+	enable_bh(TIMER_BH);
+	enable_bh(TQUEUE_BH);
+	enable_bh(IMMEDIATE_BH);
 }
diff -u --recursive --new-file v1.1.88/linux/kernel/softirq.c linux/kernel/softirq.c
--- v1.1.88/linux/kernel/softirq.c	Thu Jan 26 07:49:16 1995
+++ linux/kernel/softirq.c	Wed Feb  1 21:46:08 1995
@@ -27,7 +27,7 @@
 unsigned long intr_count = 0;
 
 unsigned long bh_active = 0;
-unsigned long bh_mask = ~0UL;
+unsigned long bh_mask = 0;
 struct bh_struct bh_base[32];
 
 
diff -u --recursive --new-file v1.1.88/linux/kernel/time.c linux/kernel/time.c
--- v1.1.88/linux/kernel/time.c	Wed Feb  1 09:23:08 1995
+++ linux/kernel/time.c	Wed Feb  1 09:19:36 1995
@@ -202,18 +202,13 @@
 
 	save_flags(flags);
 	cli();
-#if defined (__i386__) || defined (__mips__)
 	*tv = xtime;
+#if defined (__i386__) || defined (__mips__)
 	tv->tv_usec += do_gettimeoffset();
 	if (tv->tv_usec >= 1000000) {
 		tv->tv_usec -= 1000000;
 		tv->tv_sec++;
 	}
-	sti();
-#else /* !defined (__i386__) && !defined (__mips__) */
-	cli();
-	*tv = xtime;
-	sti();
 #endif /* !defined (__i386__) && !defined (__mips__) */
 	restore_flags(flags);
 }
diff -u --recursive --new-file v1.1.88/linux/mm/kmalloc.c linux/mm/kmalloc.c
--- v1.1.88/linux/mm/kmalloc.c	Mon Jan  9 11:24:24 1995
+++ linux/mm/kmalloc.c	Sun Feb  5 13:13:21 1995
@@ -270,11 +270,13 @@
      * sizes[order].firstfree used to be NULL, otherwise we wouldn't be
      * here, but you never know.... 
      */
-    page->next = sizes[order].firstfree;
-    if (dma_flag)
+    if (dma_flag) {
+      page->next = sizes[order].dmafree;
       sizes[order].dmafree = page;
-    else
+    } else {
+      page->next = sizes[order].firstfree;
       sizes[order].firstfree = page;
+    }
     restore_flags(flags);
     }
 
diff -u --recursive --new-file v1.1.88/linux/net/inet/ip.c linux/net/inet/ip.c
--- v1.1.88/linux/net/inet/ip.c	Mon Jan 30 06:41:59 1995
+++ linux/net/inet/ip.c	Sun Feb  5 14:44:40 1995
@@ -1268,7 +1268,7 @@
 	 */
 
 #ifdef CONFIG_IP_FIREWALL
-	if(!ip_fw_chk(skb->h.iph, ip_fw_fwd_chain))
+	if(!ip_fw_chk(skb->h.iph, ip_fw_fwd_chain, ip_fw_fwd_policy))
 	{
 		return;
 	}
@@ -1425,7 +1425,7 @@
 			 *	Count mapping we shortcut
 			 */
 			 
-			ip_acct_cnt(iph,ip_acct_chain,1);
+			ip_acct_cnt(iph,ip_acct_chain);
 #endif			
 			
 			/*
@@ -1493,7 +1493,8 @@
 
 #ifdef	CONFIG_IP_FIREWALL
 	
-	if(!LOOPBACK(iph->daddr) && !ip_fw_chk(iph,ip_fw_blk_chain))
+	if(!LOOPBACK(iph->daddr) && !ip_fw_chk(iph,ip_fw_blk_chain,
+			ip_fw_blk_policy))
 	{
 		kfree_skb(skb, FREE_WRITE);
 		return 0;	
@@ -1608,7 +1609,7 @@
 	 */
 	 
 #ifdef CONFIG_IP_ACCT
-	ip_acct_cnt(iph,ip_acct_chain,1);
+	ip_acct_cnt(iph,ip_acct_chain);
 #endif	
 
 	/*
@@ -1905,7 +1906,7 @@
 	 
 	ip_statistics.IpOutRequests++;
 #ifdef CONFIG_IP_ACCT
-	ip_acct_cnt(iph,ip_acct_chain,1);
+	ip_acct_cnt(iph,ip_acct_chain);
 #endif	
 	
 #ifdef CONFIG_IP_MULTICAST	
@@ -2280,8 +2281,12 @@
 		case IP_FW_DEL_FWD:
 		case IP_FW_CHK_BLK:
 		case IP_FW_CHK_FWD:
-		case IP_FW_FLUSH:
-		case IP_FW_POLICY:
+		case IP_FW_FLUSH_BLK:
+		case IP_FW_FLUSH_FWD:
+		case IP_FW_ZERO_BLK:
+		case IP_FW_ZERO_FWD:
+		case IP_FW_POLICY_BLK:
+		case IP_FW_POLICY_FWD:
 			if(!suser())
 				return -EPERM;
 			if(optlen>sizeof(tmp_fw) || optlen<1)
diff -u --recursive --new-file v1.1.88/linux/net/inet/ip_fw.c linux/net/inet/ip_fw.c
--- v1.1.88/linux/net/inet/ip_fw.c	Mon Jan  9 07:22:13 1995
+++ linux/net/inet/ip_fw.c	Sun Feb  5 14:44:40 1995
@@ -55,12 +55,17 @@
 #ifdef CONFIG_IP_FIREWALL
 struct ip_fw *ip_fw_fwd_chain;
 struct ip_fw *ip_fw_blk_chain;
-static int ip_fw_policy=1;
+int ip_fw_blk_policy=1;
+int ip_fw_fwd_policy=1;
 #endif
 #ifdef CONFIG_IP_ACCT
 struct ip_fw *ip_acct_chain;
 #endif
 
+#define IP_INFO_BLK	0
+#define IP_INFO_FWD	1
+#define IP_INFO_ACCT	2
+
 
 extern inline void print_ip(unsigned long xaddr)
 {
@@ -106,7 +111,7 @@
 
 #ifdef CONFIG_IP_FIREWALL
 
-int ip_fw_chk(struct iphdr *ip, struct ip_fw *chain)
+int ip_fw_chk(struct iphdr *ip, struct ip_fw *chain, int policy)
 {
 	unsigned long src, dst;
 	char got_proto=0;
@@ -116,7 +121,7 @@
 	unsigned short *portptr=(unsigned short *)&(((u_int *)ip)[ip->ihl]);
 
 	if (!chain) 
-		return(1);     /* If no chain , always say Ok to packet */
+		return(policy);  /* If no chain, use your policy. */
 
 	src = ip->saddr;
 	dst = ip->daddr;
@@ -166,6 +171,8 @@
 #ifdef DEBUG_CONFIG_IP_FIREWALL
 				printf("universal frwl match\n");
 #endif
+				f->p_cnt++;
+				f->b_cnt+=ntohs(ip->tot_len);
 #ifdef CONFIG_IP_FIREWALL_VERBOSE
 				if (!(f->flags & IP_FW_F_ACCEPT))
 					goto bad_packet;
@@ -226,6 +233,9 @@
 					        port_match(&f->ports[f->n_src_p],f->n_dst_p,dst_port,
 						f->flags&IP_FW_F_DRNG))) 
 					{
+					/* We've got a match! */
+					f->p_cnt++;
+					f->b_cnt+=ntohs(ip->tot_len);
 #ifdef CONFIG_IP_FIREWALL_VERBOSE
 						if (!(f->flags & IP_FW_F_ACCEPT))
 							goto bad_packet;
@@ -246,11 +256,11 @@
 	 */
 
 #ifdef CONFIG_IP_FIREWALL_VERBOSE
-	if (!(ip_fw_policy))
+	if (!(policy))
 		goto bad_packet;
 	return 1;
 #else
-	return(ip_fw_policy);
+	return(policy);
 #endif
 
 #ifdef CONFIG_IP_FIREWALL_VERBOSE
@@ -302,7 +312,7 @@
 
 
 #ifdef CONFIG_IP_ACCT
-void ip_acct_cnt(struct iphdr *ip,struct ip_fw *chain,int nh_conv)
+void ip_acct_cnt(struct iphdr *ip,struct ip_fw *chain)
 {
 	unsigned long src, dst;
 	char got_proto=0,rev=0;
@@ -341,13 +351,10 @@
      			f->p_cnt++;	/*	Rise packet count */
 
 			/*
-			 *	Rise byte count, if need to convert from host to network byte order,do it.
+			 *	Rise byte count, convert from host to network byte order.
 		     	 */
 		     	 
-			if (nh_conv)		    
-				f->b_cnt+=ntohs(ip->tot_len);
-			else
-				f->b_cnt+=ip->tot_len;
+			f->b_cnt+=ntohs(ip->tot_len);
 		}
 		else
 		{
@@ -407,12 +414,9 @@
 				{
 					f->p_cnt++;                   /* Rise packet count */
 					/*
-					 * Rise byte count, if need to convert from host to network byte order,do it.
+					 * Rise byte count, convert from host to network byte order.
 					 */
-					if (nh_conv)		    
-						f->b_cnt+=ntohs(ip->tot_len);
-					else
-						f->b_cnt+=ip->tot_len;
+					f->b_cnt+=ntohs(ip->tot_len);
 				} /* Ports match */
 			} /* Proto matches */
 		}  /* ALL/Specific */
@@ -811,25 +815,44 @@
 #ifdef CONFIG_IP_FIREWALL
 int ip_fw_ctl(int stage, void *m, int len)
 {
-	if ( stage == IP_FW_FLUSH )
+	if ( stage == IP_FW_FLUSH_BLK )
 	{
 		free_fw_chain(&ip_fw_blk_chain);
+		return(0);
+	}  
+
+	if ( stage == IP_FW_FLUSH_FWD )
+	{
 		free_fw_chain(&ip_fw_fwd_chain);
 		return(0);
 	}  
 
-	if ( stage == IP_FW_POLICY )
+	if ( stage == IP_FW_ZERO_BLK )
+	{
+		zero_fw_chain(ip_fw_blk_chain);
+		return(0);
+	}  
+
+	if ( stage == IP_FW_ZERO_FWD )
+	{
+		zero_fw_chain(ip_fw_fwd_chain);
+		return(0);
+	}  
+
+	if ( stage == IP_FW_POLICY_BLK || stage == IP_FW_POLICY_FWD )
 	{
 		int *tmp_policy_ptr;
 		tmp_policy_ptr=(int *)m;
 		if ((*tmp_policy_ptr)!=1 && (*tmp_policy_ptr)!=0)
 			return (EINVAL);
-		ip_fw_policy=*tmp_policy_ptr;
+		if ( stage == IP_FW_POLICY_BLK )
+			ip_fw_blk_policy=*tmp_policy_ptr;
+		else
+			ip_fw_fwd_policy=*tmp_policy_ptr;
 		return 0;
 	}
 
-	if ( stage == IP_FW_CHK_BLK 
-		|| stage == IP_FW_CHK_FWD )
+	if ( stage == IP_FW_CHK_BLK || stage == IP_FW_CHK_FWD )
 	{
 		struct iphdr *ip;
 
@@ -855,7 +878,9 @@
 
 		if ( ip_fw_chk(ip,
 			stage == IP_FW_CHK_BLK ?
-	                ip_fw_blk_chain : ip_fw_fwd_chain )
+	                ip_fw_blk_chain : ip_fw_fwd_chain,
+			stage == IP_FW_CHK_BLK ?
+	                ip_fw_blk_policy : ip_fw_fwd_policy )
 		       ) 
 			return(0);
 	    	else	
@@ -906,20 +931,45 @@
 
 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
 
-static int ip_chain_procinfo(struct ip_fw *chain, char *buffer, char **start, off_t offset, int length)
+static int ip_chain_procinfo(int stage, char *buffer, char **start,
+		off_t offset, int length, int reset)
 {
 	off_t pos=0, begin=0;
 	struct ip_fw *i;
 	unsigned long flags;
-	int len=0;
-	
+	int len;
 	
-	len=sprintf(buffer,"Firewall Rules\n");  
+
+	switch(stage)
+	{
+#ifdef CONFIG_IP_FIREWALL
+		case IP_INFO_BLK:
+			i = ip_fw_blk_chain;
+			len=sprintf(buffer, "IP firewall block rules, policy = %d\n",
+				ip_fw_blk_policy);
+			break;
+		case IP_INFO_FWD:
+			i = ip_fw_fwd_chain;
+			len=sprintf(buffer, "IP firewall forward rules, policy = %d\n",
+				ip_fw_fwd_policy);
+			break;
+#endif
+#ifdef CONFIG_IP_ACCT
+		case IP_INFO_ACCT:
+			i = ip_acct_chain;
+			len=sprintf(buffer,"IP accounting rules\n");
+			break;
+#endif
+		default:
+			/* this should never be reached, but safety first... */
+			i = NULL;
+			len=0;
+			break;
+	}
+
 	save_flags(flags);
 	cli();
 	
-	i=chain;
-	
 	while(i!=NULL)
 	{
 		len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %X ",
@@ -938,6 +988,12 @@
 			len=0;
 			begin=pos;
 		}
+		else if(reset)
+		{
+			/* This needs to be done at this specific place! */
+			i->p_cnt=0L;
+			i->b_cnt=0L;
+		}
 		if(pos>offset+length)
 			break;
 		i=i->next;
@@ -955,7 +1011,12 @@
 
 int ip_acct_procinfo(char *buffer, char **start, off_t offset, int length)
 {
-	return ip_chain_procinfo(ip_acct_chain, buffer,start,offset,length);
+	return ip_chain_procinfo(IP_INFO_ACCT, buffer,start,offset,length,0);
+}
+
+int ip_acct0_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+	return ip_chain_procinfo(IP_INFO_ACCT, buffer,start,offset,length,1);
 }
 
 #endif
@@ -964,12 +1025,22 @@
 
 int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset, int length)
 {
-	return ip_chain_procinfo(ip_fw_blk_chain, buffer,start,offset,length);
+	return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,0);
+}
+
+int ip_fw_blk0_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+	return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,1);
 }
 
 int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, int length)
 {
-	return ip_chain_procinfo(ip_fw_fwd_chain, buffer,start,offset,length);
+	return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,0);
+}
+
+int ip_fw_fwd0_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+	return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,1);
 }
 
 #endif
diff -u --recursive --new-file v1.1.88/linux/net/inet/rarp.c linux/net/inet/rarp.c
--- v1.1.88/linux/net/inet/rarp.c	Thu Jan 26 07:49:17 1995
+++ linux/net/inet/rarp.c	Sun Feb  5 14:26:08 1995
@@ -202,13 +202,13 @@
 	memcpy(&tip,rarp_ptr,4);
 
 /*
- *	Process entry
+ *	Process entry. Use tha for table lookup according to RFC903.
  */
   
 	cli();
 	for (entry = rarp_tables; entry != NULL; entry = entry->next)
-	if (!memcmp(entry->ha, sha, rarp->ar_hln))
-		break;
+		if (!memcmp(entry->ha, tha, rarp->ar_hln))
+			break;
   
 	if (entry != NULL)
 	{
diff -u --recursive --new-file v1.1.88/linux/net/inet/sock.c linux/net/inet/sock.c
--- v1.1.88/linux/net/inet/sock.c	Mon Jan 16 14:18:33 1995
+++ linux/net/inet/sock.c	Thu Feb  2 16:57:55 1995
@@ -62,6 +62,8 @@
  *		Alan Cox	:	Split IP from generic code
  *		Alan Cox	:	New kfree_skbmem()
  *		Alan Cox	:	Make SO_DEBUG superuser only.
+ *		Alan Cox	:	Allow anyone to clear SO_DEBUG
+ *					(compatibility fix)
  *
  * To Fix:
  *
@@ -134,7 +136,7 @@
 		  	return(-ENOPROTOOPT);
 
 		case SO_DEBUG:	
-			if(!suser())
+			if(val && !suser())
 				return(-EPERM);
 			sk->debug=val?1:0;
 			return 0;
diff -u --recursive --new-file v1.1.88/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.88/linux/net/inet/tcp.c	Wed Feb  1 09:23:08 1995
+++ linux/net/inet/tcp.c	Thu Feb  2 08:41:11 1995
@@ -2642,11 +2642,18 @@
 
 /*
  *	Default sequence number picking algorithm.
+ *	As close as possible to RFC 793, which
+ *	suggests using a 250kHz clock.
+ *	Further reading shows this assumes 2MB/s networks.
+ *	For 10MB/s ethernet, a 1MHz clock is appropriate.
+ *	That's funny, Linux has one built in!  Use it!
  */
 
-extern inline long tcp_init_seq(void)
+extern inline unsigned long tcp_init_seq(void)
 {
-	return jiffies * SEQ_TICK - seq_offset; 
+	struct timeval tv;
+	do_gettimeofday(&tv);
+	return tv.tv_usec+tv.tv_sec*1000000;
 }
 
 /*
@@ -4276,7 +4283,7 @@
   
 	sk->inuse = 1;
 	sk->daddr = usin->sin_addr.s_addr;
-	sk->write_seq = jiffies * SEQ_TICK - seq_offset;
+	sk->write_seq = tcp_init_seq();
 	sk->window_seq = sk->write_seq;
 	sk->rcv_ack_seq = sk->write_seq -1;
 	sk->err = 0;
diff -u --recursive --new-file v1.1.88/linux/net/socket.c linux/net/socket.c
--- v1.1.88/linux/net/socket.c	Thu Jan 26 07:49:17 1995
+++ linux/net/socket.c	Wed Feb  1 21:46:08 1995
@@ -1370,6 +1370,7 @@
 	 */
 
 	bh_base[NET_BH].routine= net_bh;
+	enable_bh(NET_BH);
 #endif  
 }
 
