diff -u --recursive --new-file v2.0.23/linux/CREDITS linux/CREDITS
--- v2.0.23/linux/CREDITS	Tue Oct  8 21:20:07 1996
+++ linux/CREDITS	Tue Oct 29 15:17:25 1996
@@ -926,7 +926,7 @@
 S: USA
 
 N: William (Bill) Metzenthen
-E: billm@jacobi.maths.monash.edu.au
+E: billm@suburbia.net
 D: Author of the FPU emulator.
 D: Minor kernel hacker for other lost causes (Hercules mono, etc).
 S: 22 Parker Street
diff -u --recursive --new-file v2.0.23/linux/MAINTAINERS linux/MAINTAINERS
--- v2.0.23/linux/MAINTAINERS	Sun Sep 15 10:34:18 1996
+++ linux/MAINTAINERS	Tue Oct 29 15:17:25 1996
@@ -335,6 +335,12 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+FPU EMULATOR
+P:	Bill Metzenthen
+M:	billm@suburbia.net
+W:	http://suburbia.net/~billm/floating-point/emulator/
+S:	Maintained
+
 CREDITS FILE
 P:	John A. Martin
 M:	jam@acm.org
diff -u --recursive --new-file v2.0.23/linux/Makefile linux/Makefile
--- v2.0.23/linux/Makefile	Sat Oct 19 10:06:10 1996
+++ linux/Makefile	Sat Oct 19 10:06:36 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 23
+SUBLEVEL = 24
 
 ARCH = i386
 
diff -u --recursive --new-file v2.0.23/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.0.23/linux/arch/alpha/defconfig	Mon Aug  5 10:13:50 1996
+++ linux/arch/alpha/defconfig	Wed Oct 30 03:42:40 1996
@@ -162,6 +162,7 @@
 # CONFIG_DGRS is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_TR is not set
+# CONFIG_FDDI is not set
 # CONFIG_ARCNET is not set
 
 #
diff -u --recursive --new-file v2.0.23/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.0.23/linux/arch/i386/defconfig	Mon Aug  5 10:13:50 1996
+++ linux/arch/i386/defconfig	Wed Oct 30 03:42:40 1996
@@ -112,6 +112,7 @@
 # CONFIG_NET_EISA is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_TR is not set
+# CONFIG_FDDI is not set
 # CONFIG_ARCNET is not set
 
 #
diff -u --recursive --new-file v2.0.23/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.0.23/linux/arch/i386/kernel/process.c	Tue Oct  8 21:20:08 1996
+++ linux/arch/i386/kernel/process.c	Wed Oct 30 03:42:40 1996
@@ -183,44 +183,200 @@
  */
 static long no_idt[2] = {0, 0};
 static int reboot_mode = 0;
+static int reboot_thru_bios = 0;
 
 void reboot_setup(char *str, int *ints)
 {
-	int mode = 0;
+	while(1) {
+		switch (*str) {
+		case 'w': /* "warm" reboot (no memory testing etc) */
+			reboot_mode = 0x1234;
+			break;
+		case 'c': /* "cold" reboot (with memory testing etc) */
+			reboot_mode = 0x0;
+			break;
+		case 'b': /* "bios" reboot by jumping through the BIOS */
+			reboot_thru_bios = 1;
+			break;
+		case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
+			reboot_thru_bios = 0;
+			break;
+		}
+		if((str = strchr(str,',')) != NULL)
+			str++;
+		else
+			break;
+	}
+}
+
+
+/* The following code and data reboots the machine by switching to real
+   mode and jumping to the BIOS reset entry point, as if the CPU has
+   really been reset.  The previous version asked the keyboard
+   controller to pulse the CPU reset line, which is more thorough, but
+   doesn't work with at least one type of 486 motherboard.  It is easy
+   to stop this code working; hence the copious comments. */
 
-	/* "w" for "warm" reboot (no memory testing etc) */
-	if (str[0] == 'w')
-		mode = 0x1234;
-	reboot_mode = mode;
+unsigned long long
+real_mode_gdt_entries [3] =
+{
+	0x0000000000000000ULL,	/* Null descriptor */
+	0x00009a000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */
+	0x000092000100ffffULL		/* 16-bit real-mode 64k data at 0x00000100 */
+};
+
+struct
+{
+	unsigned short       size __attribute__ ((packed));
+	unsigned long long * base __attribute__ ((packed));
 }
+real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
+real_mode_idt = { 0x3ff, 0 };
+
+/* This is 16-bit protected mode code to disable paging and the cache,
+   switch to real mode and jump to the BIOS reset code.
+
+   The instruction that switches to real mode by writing to CR0 must be
+   followed immediately by a far jump instruction, which set CS to a
+   valid value for real mode, and flushes the prefetch queue to avoid
+   running instructions that have already been decoded in protected
+   mode.
+
+   Clears all the flags except ET, especially PG (paging), PE
+   (protected-mode enable) and TS (task switch for coprocessor state
+   save).  Flushes the TLB after paging has been disabled.  Sets CD and
+   NW, to disable the cache on a 486, and invalidates the cache.  This
+   is more like the state of a 486 after reset.  I don't know if
+   something else should be done for other chips.
+
+   More could be done here to set up the registers as if a CPU reset had
+   occurred; hopefully real BIOSes don't assume much. */
+
+unsigned char real_mode_switch [] =
+{
+	0x66, 0x0f, 0x20, 0xc0,			/*    movl  %cr0,%eax        */
+	0x66, 0x83, 0xe0, 0x11,			/*    andl  $0x00000011,%eax */
+	0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,		/*    orl   $0x60000000,%eax */
+	0x66, 0x0f, 0x22, 0xc0,			/*    movl  %eax,%cr0        */
+	0x66, 0x0f, 0x22, 0xd8,			/*    movl  %eax,%cr3        */
+	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */
+	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */
+	0x74, 0x02,					/*    jz    f                */
+	0x0f, 0x08,					/*    invd                   */
+	0x24, 0x10,					/* f: andb  $0x10,al         */
+	0x66, 0x0f, 0x22, 0xc0,			/*    movl  %eax,%cr0        */
+	0xea, 0x00, 0x00, 0xff, 0xff			/*    ljmp  $0xffff,$0x0000  */
+};
 
 static inline void kb_wait(void)
 {
 	int i;
-
 	for (i=0; i<0x10000; i++)
 		if ((inb_p(0x64) & 0x02) == 0)
 			break;
 }
 
-void hard_reset_now(void)
+void hard_reset_now (void)
 {
-	int i, j;
 
-	sti();
-/* rebooting needs to touch the page at absolute addr 0 */
-	pg0[0] = 7;
-	*((unsigned short *)0x472) = reboot_mode;
-	for (;;) {
-		for (i=0; i<100; i++) {
-			kb_wait();
-			for(j = 0; j < 100000 ; j++)
-				/* nothing */;
-			outb(0xfe,0x64);	 /* pulse reset low */
-			udelay(10);
+	if(!reboot_thru_bios) {
+		sti();
+		/* rebooting needs to touch the page at absolute addr 0 */
+		pg0[0] = 7;
+		*((unsigned short *)0x472) = reboot_mode;
+		for (;;) {
+			int i;
+			for (i=0; i<100; i++) {
+				int j;
+				kb_wait();
+				for(j = 0; j < 100000 ; j++)
+					/* nothing */;
+				outb(0xfe,0x64);         /* pulse reset low */
+				udelay(10);
+			}
+			__asm__ __volatile__("\tlidt %0": "=m" (no_idt));
 		}
-		__asm__ __volatile__("\tlidt %0": "=m" (no_idt));
 	}
+
+	cli ();
+
+	/* Write zero to CMOS register number 0x0f, which the BIOS POST
+	   routine will recognize as telling it to do a proper reboot.  (Well
+	   that's what this book in front of me says -- it may only apply to
+	   the Phoenix BIOS though, it's not clear).  At the same time,
+	   disable NMIs by setting the top bit in the CMOS address register,
+	   as we're about to do peculiar things to the CPU.  I'm not sure if
+	   `outb_p' is needed instead of just `outb'.  Use it to be on the
+	   safe side. */
+
+	outb_p (0x8f, 0x70);
+	outb_p (0x00, 0x71);
+
+	/* Remap the kernel at virtual address zero, as well as offset zero
+	   from the kernel segment.  This assumes the kernel segment starts at
+	   virtual address 0xc0000000. */
+
+	memcpy (swapper_pg_dir, swapper_pg_dir + 768,
+		sizeof (swapper_pg_dir [0]) * 256);
+
+	/* Make sure the first page is mapped to the start of physical memory.
+	   It is normally not mapped, to trap kernel NULL pointer dereferences. */
+
+	pg0 [0] = 7;
+
+	/* Use `swapper_pg_dir' as our page directory.  Don't bother with
+	   `SET_PAGE_DIR' because interrupts are disabled and we're rebooting.
+	   This instruction flushes the TLB. */
+
+	__asm__ __volatile__ ("movl %0,%%cr3" : : "a" (swapper_pg_dir) : "memory");
+
+	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
+	   this on booting to tell it to "Bypass memory test (also warm
+	   boot)".  This seems like a fairly standard thing that gets set by
+	   REBOOT.COM programs, and the previous reset routine did this
+	   too. */
+
+	*((unsigned short *)0x472) = reboot_mode;
+
+	/* For the switch to real mode, copy some code to low memory.  It has
+	   to be in the first 64k because it is running in 16-bit mode, and it
+	   has to have the same physical and virtual address, because it turns
+	   off paging.  Copy it near the end of the first page, out of the way
+	   of BIOS variables. */
+
+	memcpy ((void *) (0x1000 - sizeof (real_mode_switch)),
+		real_mode_switch, sizeof (real_mode_switch));
+
+	/* Set up the IDT for real mode. */
+
+	__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
+
+	/* Set up a GDT from which we can load segment descriptors for real
+	   mode.  The GDT is not used in real mode; it is just needed here to
+	   prepare the descriptors. */
+
+	__asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));
+
+	/* Load the data segment registers, and thus the descriptors ready for
+	   real mode.  The base address of each segment is 0x100, 16 times the
+	   selector value being loaded here.  This is so that the segment
+	   registers don't have to be reloaded after switching to real mode:
+	   the values are consistent for real mode operation already. */
+
+	__asm__ __volatile__ ("movw $0x0010,%%ax\n"
+				"\tmovw %%ax,%%ds\n"
+				"\tmovw %%ax,%%es\n"
+				"\tmovw %%ax,%%fs\n"
+				"\tmovw %%ax,%%gs\n"
+				"\tmovw %%ax,%%ss" : : : "eax");
+
+	/* Jump to the 16-bit code that we copied earlier.  It disables paging
+	   and the cache, switches to real mode, and jumps to the BIOS reset
+	   entry point. */
+
+	__asm__ __volatile__ ("ljmp $0x0008,%0"
+				:
+				: "i" ((void *) (0x1000 - sizeof (real_mode_switch))));
 }
 
 void show_regs(struct pt_regs * regs)
diff -u --recursive --new-file v2.0.23/linux/arch/i386/math-emu/README linux/arch/i386/math-emu/README
--- v2.0.23/linux/arch/i386/math-emu/README	Thu Oct  5 15:30:43 1995
+++ linux/arch/i386/math-emu/README	Tue Oct 29 15:17:25 1996
@@ -1,9 +1,9 @@
  +---------------------------------------------------------------------------+
  |  wm-FPU-emu   an FPU emulator for 80386 and 80486SX microprocessors.      |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1995                                         |
+ | Copyright (C) 1992,1993,1994,1995,1996                                    |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
+ |                       Australia.  E-mail billm@suburbia.net               |
  |                                                                           |
  |    This program is free software; you can redistribute it and/or modify   |
  |    it under the terms of the GNU General Public License version 2 as      |
@@ -42,11 +42,11 @@
 some differences.
 
 Please report bugs, etc to me at:
-       billm@jacobi.maths.monash.edu.au
+       billm@suburbia.net
 
 
 --Bill Metzenthen
-  October 1995
+  October 1996
 
 
 ----------------------- Internals of wm-FPU-emu -----------------------
diff -u --recursive --new-file v2.0.23/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.0.23/linux/drivers/block/ide.c	Tue Oct  8 21:20:10 1996
+++ linux/drivers/block/ide.c	Tue Oct 29 00:30:43 1996
@@ -2272,11 +2272,13 @@
 	unsigned long capacity, check;
 
 	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL);
-	ide_input_data(drive, id, SECTOR_WORDS);	/* read 512 bytes of id info */
+	ide_input_data(drive, id, SECTOR_WORDS);/* read 512 bytes of id info */
 	sti();
 
+#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO)
 	/*
-	 * EATA SCSI controllers do a hardware ATA emulation:  ignore them
+	 * EATA SCSI controllers do a hardware ATA emulation:  
+	 * Ignore them if there is a driver for them available.
 	 */
 	if ((id->model[0] == 'P' && id->model[1] == 'M')
 	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
@@ -2284,6 +2286,7 @@
 		drive->present = 0;
 		return;
 	}
+#endif
 
 	/*
 	 *  WIN_IDENTIFY returns little-endian info,
diff -u --recursive --new-file v2.0.23/linux/drivers/block/umc8672.c linux/drivers/block/umc8672.c
--- v2.0.23/linux/drivers/block/umc8672.c	Mon Aug  5 10:13:51 1996
+++ linux/drivers/block/umc8672.c	Tue Oct 29 15:28:53 1996
@@ -28,7 +28,7 @@
  * Germany
  *
  * To enable UMC8672 support there must a lilo line like
- * append="hd=umc8672"...
+ * append="ide0=umc8672"...
  * To set the speed according to the abilities of the hardware there must be a
  * line like
  * #define UMC_DRIVE0 11
diff -u --recursive --new-file v2.0.23/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c
--- v2.0.23/linux/drivers/cdrom/cdu31a.c	Sat Oct 19 10:06:10 1996
+++ linux/drivers/cdrom/cdu31a.c	Mon Oct 28 22:16:53 1996
@@ -1915,7 +1915,9 @@
    int num_tracks;
 
 
-   num_tracks = sony_toc.last_track_num - sony_toc.first_track_num + 1;
+   num_tracks = (  bcd_to_int(sony_toc.last_track_num)
+                 - bcd_to_int(sony_toc.first_track_num)
+		 + 1);
    for (i = 0; i < num_tracks; i++)
    {
       if (sony_toc.tracks[i].track == track)
@@ -2486,8 +2488,8 @@
          i=verify_area(VERIFY_WRITE, hdr, sizeof(*hdr));
          if(i<0)
          	return i;
-         loc_hdr.cdth_trk0 = sony_toc.first_track_num;
-         loc_hdr.cdth_trk1 = sony_toc.last_track_num;
+         loc_hdr.cdth_trk0 = bcd_to_int(sony_toc.first_track_num);
+         loc_hdr.cdth_trk1 = bcd_to_int(sony_toc.last_track_num);
          memcpy_tofs(hdr, &loc_hdr, sizeof(*hdr));
       }
       return 0;
@@ -2567,8 +2569,8 @@
          	return i;
          
          memcpy_fromfs(&ti, (char *) arg, sizeof(ti));
-         if (   (ti.cdti_trk0 < sony_toc.first_track_num)
-             || (ti.cdti_trk0 > sony_toc.last_track_num)
+         if (   (ti.cdti_trk0 < bcd_to_int(sony_toc.first_track_num))
+             || (ti.cdti_trk0 > bcd_to_int(sony_toc.last_track_num))
              || (ti.cdti_trk1 < ti.cdti_trk0))
          {
             return -EINVAL;
@@ -2587,7 +2589,7 @@
           * If we want to stop after the last track, use the lead-out
           * MSF to do that.
           */
-         if (ti.cdti_trk1 >= sony_toc.last_track_num)
+         if (ti.cdti_trk1 >= bcd_to_int(sony_toc.last_track_num))
          {
             log_to_msf(msf_to_log(sony_toc.lead_out_start_msf)-1,
                        &(params[4]));
diff -u --recursive --new-file v2.0.23/linux/drivers/char/selection.c linux/drivers/char/selection.c
--- v2.0.23/linux/drivers/char/selection.c	Thu Jun  6 13:42:16 1996
+++ linux/drivers/char/selection.c	Wed Oct 30 03:51:32 1996
@@ -289,9 +289,9 @@
 	if (!bp || !c)
 		return 0;
 	do_unblank_screen();
-	current->state = TASK_INTERRUPTIBLE;
 	add_wait_queue(&vt->paste_wait, &wait);
-	while (c) {
+	do {
+		current->state = TASK_INTERRUPTIBLE;
 		if (test_bit(TTY_THROTTLED, &tty->flags)) {
 			schedule();
 			continue;
@@ -300,7 +300,8 @@
 		tty->ldisc.receive_buf(tty, bp, 0, l);
 		c -= l;
 		bp += l;
-	}
+	} while (c);
+	remove_wait_queue(&vt->paste_wait, &wait);
 	current->state = TASK_RUNNING;
 	return 0;
 }
diff -u --recursive --new-file v2.0.23/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.0.23/linux/drivers/char/tty_io.c	Wed Sep 11 17:57:14 1996
+++ linux/drivers/char/tty_io.c	Tue Oct 29 00:40:58 1996
@@ -1696,7 +1696,7 @@
 		if (((*p)->tty == tty) ||
 		    ((session > 0) && ((*p)->session == session)))
 			send_sig(SIGKILL, *p, 1);
-		else {
+		else if ((*p)->files) {
 			for (i=0; i < NR_OPEN; i++) {
 				filp = (*p)->files->fd[i];
 				if (filp && (filp->f_op == &tty_fops) &&
diff -u --recursive --new-file v2.0.23/linux/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c
--- v2.0.23/linux/drivers/isdn/isdn_cards.c	Sun Apr 21 11:56:14 1996
+++ linux/drivers/isdn/isdn_cards.c	Wed Oct 30 03:42:40 1996
@@ -27,15 +27,15 @@
 #include <linux/config.h>
 
 #ifdef CONFIG_ISDN_DRV_ICN
-extern void icn_init(void);
+extern int icn_init(void);
 #endif
 
 #ifdef CONFIG_ISDN_DRV_TELES
-extern void teles_init(void);
+extern int teles_init(void);
 #endif
 
 #ifdef CONFIG_ISDN_DRV_PCBIT
-extern void pcbit_init(void);
+extern int pcbit_init(void);
 #endif
 
 void isdn_cards_init(void)
diff -u --recursive --new-file v2.0.23/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.0.23/linux/drivers/net/3c509.c	Fri Sep 20 17:00:34 1996
+++ linux/drivers/net/3c509.c	Wed Oct 30 03:42:40 1996
@@ -27,6 +27,10 @@
 	FIXES:
 		Alan Cox:       Removed the 'Unexpected interrupt' bug.
 		Michael Meskes:	Upgraded to Donald Becker's version 1.07.
+		Alan Cox:	Increased the eeprom delay. Regardless of 
+				what the docs say some people definitely
+				get problems with lower (but in card spec)
+				delays
 */
 
 static char *version = "3c509.c:1.07 6/15/95 becker@cesdis.gsfc.nasa.gov\n";
@@ -312,7 +316,7 @@
 {
 	outw(EEPROM_READ + index, ioaddr + 10);
 	/* Pause for at least 162 us. for the read to take place. */
-	udelay (300);
+	udelay (500);
 	return inw(ioaddr + 12);
 }
 
@@ -326,7 +330,7 @@
 	outb(EEPROM_READ + index, id_port);
 
 	/* Pause for at least 162 us. for the read to take place. */
-	udelay (300);
+	udelay (500);
 	
 	for (bit = 15; bit >= 0; bit--)
 		word = (word << 1) + (inb(id_port) & 0x01);
diff -u --recursive --new-file v2.0.23/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.0.23/linux/drivers/net/3c59x.c	Thu Jul 18 10:08:45 1996
+++ linux/drivers/net/3c59x.c	Tue Oct 29 16:24:57 1996
@@ -315,7 +315,7 @@
 
 	root_vortex_dev = NULL;
 	cards_found = vortex_scan(0);
-	return cards_found < 0 ? cards_found : 0;
+	return cards_found ? 0 : -ENODEV;
 }
 
 #else
diff -u --recursive --new-file v2.0.23/linux/drivers/net/CONFIG linux/drivers/net/CONFIG
--- v2.0.23/linux/drivers/net/CONFIG	Thu May 16 20:12:56 1996
+++ linux/drivers/net/CONFIG	Wed Oct 30 03:42:40 1996
@@ -62,6 +62,10 @@
 #     DE4X5_DO_MEMCPY   Forces the Intels to use memory copies into sk_buffs
 #	                rather than straight DMA.
 #
+#  DEFXX		The DIGITAL series of FDDI EISA (DEFEA) and PCI (DEFPA)
+#			controllers
+#       DEFXX_DEBUG	Set the desired debug level
+#
 #  TULIP		Tulip (dc21040/dc21041/ds21140) driver
 #	TULIP_PORT	specify default if_port
 #			0: 10TP
@@ -92,5 +96,6 @@
 DEPCA_OPTS	= 
 EWRK3_OPTS	= 
 DE4X5_OPTS	= -DDE4X5_AUTOSENSE=AUTO
+DEFXX_OPTS	=
 ELP_OPTS	=
 TULIP_OPTS	=
diff -u --recursive --new-file v2.0.23/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.0.23/linux/drivers/net/Config.in	Mon May 20 08:08:36 1996
+++ linux/drivers/net/Config.in	Wed Oct 30 03:42:40 1996
@@ -84,7 +84,7 @@
     tristate 'NE2000/NE1000 support' CONFIG_NE2000
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'NI5210 support' CONFIG_NI52
-      bool 'NI6510 support' CONFIG_NI65
+      tristate 'NI6510 support' CONFIG_NI65
     fi
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
@@ -115,6 +115,10 @@
 bool 'Token Ring driver support' CONFIG_TR
 if [ "$CONFIG_TR" = "y" ]; then
   tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR
+fi
+bool 'FDDI driver support' CONFIG_FDDI
+if [ "$CONFIG_FDDI" = "y" ]; then
+  bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
 fi
 tristate 'ARCnet support' CONFIG_ARCNET
 if [ "$CONFIG_ARCNET" != "n" ]; then
diff -u --recursive --new-file v2.0.23/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.0.23/linux/drivers/net/Makefile	Mon May  6 12:44:31 1996
+++ linux/drivers/net/Makefile	Wed Oct 30 03:42:40 1996
@@ -350,6 +350,10 @@
   endif
 endif
 
+ifeq ($(CONFIG_DEFXX),y)
+L_OBJS += defxx.o
+endif
+
 ifeq ($(CONFIG_NI52),y)
 L_OBJS += ni52.o
 else
@@ -360,6 +364,10 @@
 
 ifeq ($(CONFIG_NI65),y)
 L_OBJS += ni65.o
+else
+  ifeq ($(CONFIG_NI65),m)
+  M_OBJS += ni65.o
+  endif
 endif
 
 ifeq ($(CONFIG_ELPLUS),y)
@@ -525,6 +533,9 @@
 
 de4x5.o: de4x5.c CONFIG
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE4X5_OPTS) -c $<
+
+defxx.o: defxx.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFXX_OPTS) -c $<
 
 ewrk3.o: ewrk3.c CONFIG
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(EWRK3_OPTS) -c $<
diff -u --recursive --new-file v2.0.23/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.0.23/linux/drivers/net/Space.c	Mon Jun  3 12:42:41 1996
+++ linux/drivers/net/Space.c	Wed Oct 30 03:42:40 1996
@@ -13,7 +13,7 @@
  *		field of the 'device' structure to store the unit number...
  *		-FvK
  *
- * Version:	@(#)Space.c	1.0.7	08/12/93
+ * Version:	@(#)Space.c	1.0.8	07/31/96
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -381,6 +381,30 @@
 #   define	NEXT_DEV	(&ibmtr_dev0)
 
 #endif 
+
+#ifdef CONFIG_DEFXX
+	extern int dfx_probe(struct device *dev);
+	static struct device fddi7_dev =
+		{"fddi7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, dfx_probe};
+	static struct device fddi6_dev =
+		{"fddi6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, dfx_probe};
+	static struct device fddi5_dev =
+		{"fddi5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, dfx_probe};
+	static struct device fddi4_dev =
+		{"fddi4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, dfx_probe};
+	static struct device fddi3_dev =
+		{"fddi3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, dfx_probe};
+	static struct device fddi2_dev =
+		{"fddi2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, dfx_probe};
+	static struct device fddi1_dev =
+		{"fddi1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, dfx_probe};
+	static struct device fddi0_dev =
+		{"fddi0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, dfx_probe};
+
+#undef	NEXT_DEV
+#define	NEXT_DEV	(&fddi0_dev)
+#endif 
+
 #ifdef CONFIG_NET_IPIP
 #ifdef CONFIG_IP_FORWARD
 	extern int tunnel_init(struct device *);
diff -u --recursive --new-file v2.0.23/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v2.0.23/linux/drivers/net/arcnet.c	Sat Aug 10 10:03:14 1996
+++ linux/drivers/net/arcnet.c	Sat Oct 19 10:36:20 1996
@@ -17,6 +17,14 @@
          
 	**********************
 	
+	v2.56 (96/10/18)
+	  - Turned arc0e/arc0s startup messages back on by default, as most
+	    people will probably not notice the additional devices
+	    otherwise, and experience more protocol confusion than
+	    necessary.
+	  - Fixed a tiny but noticeable bug in the packet debugging routines
+	    (thanks Tomasz)
+
 	v2.55 (96/08/05)
 	  - A couple more messages moved to D_EXTRA.
 	  - SLOW_XMIT_COPY off by default.
@@ -202,7 +210,7 @@
 */
 
 static const char *version =
- "arcnet.c: v2.55 96/08/05 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.56 96/10/18 Avery Pennarun <apenwarr@foxnet.net>\n";
 
  
 
@@ -708,8 +716,7 @@
         {
 		if (i%16==0)
 			printk("\n" KERN_DEBUG "[%04X] ",i);
-		else
-                       	printk("%02X ",((u_char *)skb->data)[i]);
+               	printk("%02X ",((u_char *)skb->data)[i]);
 	}
         printk("\n");
         restore_flags(flags);
@@ -731,8 +738,7 @@
 	{
 		if (i%16==0)
 			printk("\n" KERN_DEBUG "[%04X] ",i);
-		else
-			printk("%02X ",buffer[i]);
+		printk("%02X ",buffer[i]);
 	}
 	printk("\n");
 	restore_flags(flags);
@@ -754,6 +760,8 @@
  * NOTE: the list of possible ports/shmems is static, so it is retained
  * across calls to arcnet_probe.  So, if more than one ARCnet probe is made,
  * values that were discarded once will not even be tried again.
+ *
+ * FIXME: grab all devices in one shot and eliminate the big static array.
  */
 int arcnet_probe(struct device *dev)
 {
@@ -775,9 +783,8 @@
 			ports[(count-0x200)/16] = count;
 		for (count=0xA0000; count<=0xFF800; count+=2048)
 			shmems[(count-0xA0000)/2048] = count;
-	}
-	else
 		init_once=1;
+	}
 
 	BUGLVL(D_NORMAL) printk(version);
 
@@ -1370,7 +1377,7 @@
 	
 	/* The RFC1201 driver is the default - just store */
 	lp->adev=dev;
-	BUGMSG(D_EXTRA,"ARCnet RFC1201 protocol initialized.\n");
+	BUGMSG(D_NORMAL,"ARCnet RFC1201 protocol initialized.\n");
 
 #ifdef CONFIG_ARCNET_ETH	
 	/* Initialize the ethernet-encap protocol driver */
@@ -1388,7 +1395,7 @@
 	lp->edev->init=arcnetE_init;
 	register_netdev(lp->edev);
 #else
-	BUGMSG(D_EXTRA,"Ethernet-Encap protocol not available (disabled).\n");
+	BUGMSG(D_NORMAL,"Ethernet-Encap protocol not available (disabled).\n");
 #endif
 
 #ifdef CONFIG_ARCNET_1051
@@ -1400,7 +1407,7 @@
 	lp->sdev->init=arcnetS_init;
 	register_netdev(lp->sdev);
 #else
-	BUGMSG(D_EXTRA,"RFC1051 protocol not available (disabled).\n");
+	BUGMSG(D_NORMAL,"RFC1051 protocol not available (disabled).\n");
 #endif
 
 	/* we're started */
@@ -2781,7 +2788,7 @@
 	dev->stop=arcnetE_open_close;
 	dev->hard_start_xmit=arcnetE_send_packet;
 
-	BUGMSG(D_EXTRA,"ARCnet Ethernet-Encap protocol initialized.\n");
+	BUGMSG(D_NORMAL,"ARCnet Ethernet-Encap protocol initialized.\n");
 			
 	return 0;
 }
@@ -2961,7 +2968,7 @@
 	dev->hard_start_xmit=arcnetS_send_packet;
 	dev->hard_header=arcnetS_header;
 	dev->rebuild_header=arcnetS_rebuild_header;
-	BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
+	BUGMSG(D_NORMAL,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
 
 	return 0;
 }
@@ -3241,10 +3248,10 @@
 	
 	
 static int io=0x0;	/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-static int irqnum=0;	/* or use the insmod io= irqnum= shmem= options */
+static int irqnum=0;	/* or use the insmod io= irq= shmem= options */
 static int irq=0;
 static int shmem=0;
-static char *device = NULL;
+static char *device = NULL;	/* use eg. device="arc1" to change name */
 
 int
 init_module(void)
@@ -3304,15 +3311,3 @@
 }
 
 #endif /* MODULE */
-
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c arcnet.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 8
- * End:
- */
-
diff -u --recursive --new-file v2.0.23/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.0.23/linux/drivers/net/defxx.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/defxx.c	Wed Oct 30 03:42:40 1996
@@ -0,0 +1,3421 @@
+/*
+ * File Name:
+ *   defxx.c
+ *
+ * Copyright Information:
+ *   Copyright Digital Equipment Corporation 1996.
+ *
+ *   This software may be used and distributed according to the terms of
+ *   the GNU Public License, incorporated herein by reference.
+ *
+ * Abstract:
+ *   A Linux device driver supporting the Digital Equipment Corporation
+ *   FDDI EISA and PCI controller families.  Supported adapters include:
+ *
+ *		DEC FDDIcontroller/EISA (DEFEA)
+ *		DEC FDDIcontroller/PCI  (DEFPA)
+ *
+ * Maintainers:
+ *   LVS	Lawrence V. Stefani
+ *
+ * Contact:
+ *	 The author may be reached at:
+ *
+ *		Inet: stefani@lkg.dec.com
+ *		Mail: Digital Equipment Corporation
+ *			  550 King Street
+ *			  M/S: LKG1-3/M07
+ *			  Littleton, MA  01460
+ *
+ * Credits:
+ *   I'd like to thank Patricia Cross for helping me get started with
+ *   Linux, David Davies for a lot of help upgrading and configuring
+ *   my development system and for answering many OS and driver
+ *   development questions, and Alan Cox for recommendations and
+ *   integration help on getting FDDI support into Linux.  LVS
+ *
+ * Driver Architecture:
+ *   The driver architecture is largely based on previous driver work
+ *   for other operating systems.  The upper edge interface and
+ *   functions were largely taken from existing Linux device drivers
+ *   such as David Davies' DE4X5.C driver and Donald Becker's TULIP.C
+ *   driver.
+ *
+ *   Adapter Probe -
+ *		The driver scans for supported EISA adapters by reading the
+ *		SLOT ID register for each EISA slot and making a match
+ *		against the expected value.  The supported PCI adapters are
+ *		discovered using successive calls to pcibios_find_device.
+ *		The first time the probe routine is called, all supported
+ *		devices are discovered and initialized.  The adapters aren't
+ *		brought up to an operational state until the open routine is
+ *		called.
+ *
+ *   Bus-Specific Initialization -
+ *		This driver currently supports both EISA and PCI controller
+ *		families.  While the custom DMA chip and FDDI logic is similar
+ *		or identical, the bus logic is very different.  After
+ *		initialization, the	only bus-specific differences is in how the
+ *		driver enables and disables interrupts.  Other than that, the
+ *		run-time critical code behaves the same on both families.
+ *		It's important to note that both adapter families are configured
+ *		to I/O map, rather than memory map, the adapter registers.
+ *
+ *   Driver Open/Close -
+ *		In the driver open routine, the driver ISR (interrupt service
+ *		routine) is registered and the adapter is brought to an
+ *		operational state.  In the driver close routine, the opposite
+ *		occurs; the driver ISR is deregistered and the adapter is
+ *		brought to a safe, but closed state.  Users may use consecutive
+ *		commands to bring the adapter up and down as in the following
+ *		example:
+ *					ifconfig fddi0 up
+ *					ifconfig fddi0 down
+ *					ifconfig fddi0 up
+ *
+ *   Driver Shutdown -
+ *		Apparently, there is no shutdown or halt routine support under
+ *		Linux.  This routine would be called during "reboot" or
+ *		"shutdown" to allow the driver to place the adapter in a safe
+ *		state before a warm reboot occurs.  To be really safe, the user
+ *		should close the adapter before shutdown (eg. ifconfig fddi0 down)
+ *		to ensure that the adapter DMA engine is taken off-line.  However,
+ *		the current driver code anticipates this problem and always issues
+ *		a soft reset of the adapter	at the beginning of driver initialization.
+ *		A future driver enhancement in this area may occur in 2.1.X where
+ *		Alan indicated that a shutdown handler may be implemented.
+ *
+ *   Interrupt Service Routine -
+ *		The driver supports shared interrupts, so the ISR is registered for
+ *		each board with the appropriate flag and the pointer to that board's
+ *		device structure.  This provides the context during interrupt
+ *		processing to support shared interrupts and multiple boards.
+ *
+ *		Interrupt enabling/disabling can occur at many levels.  At the host
+ *		end, you can disable system interrupts, or disable interrupts at the
+ *		PIC (on Intel systems).  Across the bus, both EISA and PCI adapters
+ *		have a bus-logic chip interrupt enable/disable as well as a DMA
+ *		controller interrupt enable/disable.
+ *
+ *		The driver currently enables and disables adapter interrupts at the
+ *		bus-logic chip and assumes that Linux will take care of clearing or
+ *		acknowledging any host-based interrupt chips.
+ *
+ *   Control Functions -
+ *		Control functions are those used to support functions such as adding
+ *		or deleting multicast addresses, enabling or disabling packet
+ *		reception filters, or other custom/proprietary commands.  Presently,
+ *		the driver supports the "get statistics", "set multicast list", and
+ *		"set mac address" functions defined by Linux.  A list of possible
+ *		enhancements include:
+ *
+ *				- Custom ioctl interface for executing port interface commands
+ *				- Custom ioctl interface for adding unicast addresses to
+ *				  adapter CAM (to support bridge functions).
+ *				- Custom ioctl interface for supporting firmware upgrades.
+ *
+ *   Hardware (port interface) Support Routines -
+ *		The driver function names that start with "dfx_hw_" represent
+ *		low-level port interface routines that are called frequently.  They
+ *		include issuing a DMA or port control command to the adapter,
+ *		resetting the adapter, or reading the adapter state.  Since the
+ *		driver initialization and run-time code must make calls into the
+ *		port interface, these routines were written to be as generic and
+ *		usable as possible.
+ *
+ *   Receive Path -
+ *		The adapter DMA engine supports a 256 entry receive descriptor block
+ *		of which up to 255 entries can be used at any given time.  The
+ *		architecture is a standard producer, consumer, completion model in
+ *		which the driver "produces" receive buffers to the adapter, the
+ *		adapter "consumes" the receive buffers by DMAing incoming packet data,
+ *		and the driver "completes" the receive buffers by servicing the
+ *		incoming packet, then "produces" a new buffer and starts the cycle
+ *		again.  Receive buffers can be fragmented in up to 16 fragments
+ *		(descriptor	entries).  For simplicity, this driver posts
+ *		single-fragment receive buffers of 4608 bytes, then allocates a
+ *		sk_buff, copies the data, then reposts the buffer.  To reduce CPU
+ *		utilization, a better approach would be to pass up the receive
+ *		buffer (no extra copy) then allocate and post a replacement buffer.
+ *		This is a performance enhancement that should be looked into at
+ *		some point.
+ *
+ *   Transmit Path -
+ *		Like the receive path, the adapter DMA engine supports a 256 entry
+ *		transmit descriptor block of which up to 255 entries can be used at
+ *		any	given time.  Transmit buffers can be fragmented	in up to 255
+ *		fragments (descriptor entries).  This driver always posts one
+ *		fragment per transmit packet request.
+ *
+ *		The fragment contains the entire packet from FC to end of data.
+ *		Before posting the buffer to the adapter, the driver sets a three-byte
+ *		packet request header (PRH) which is required by the Motorola MAC chip
+ *		used on the adapters.  The PRH tells the MAC the type of token to
+ *		receive/send, whether or not to generate and append the CRC, whether
+ *		synchronous or asynchronous framing is used, etc.  Since the PRH
+ *		definition is not necessarily consistent across all FDDI chipsets,
+ *		the driver, rather than the common FDDI packet handler routines,
+ *		sets these bytes.
+ *
+ *		To reduce the amount of descriptor fetches needed per transmit request,
+ *		the driver takes advantage of the fact that there are at least three
+ *		bytes available before the skb->data field on the outgoing transmit
+ *		request.  This is guaranteed by having fddi_setup() in net_init.c set
+ *		dev->hard_header_len to 24 bytes.  21 bytes accounts for the largest
+ *		header in an 802.2 SNAP frame.  The other 3 bytes are the extra "pad"
+ *		bytes which we'll use to store the PRH.
+ *
+ *		There's a subtle advantage to adding these pad bytes to the
+ *		hard_header_len, it ensures that the data portion of the packet for
+ *		an 802.2 SNAP frame is longword aligned.  Other FDDI driver
+ *		implementations may not need the extra padding and can start copying
+ *		or DMAing directly from the FC byte which starts at skb->data.  Should
+ *		another driver implementation need ADDITIONAL padding, the net_init.c
+ *		module should be updated and dev->hard_header_len should be increased.
+ *		NOTE: To maintain the alignment on the data portion of the packet,
+ *		dev->hard_header_len should always be evenly divisible by 4 and at
+ *		least 24 bytes in size.
+ *
+ * Modification History:
+ *		Date		Name	Description
+ *		16-Aug-96	LVS		Created.
+ *		20-Aug-96	LVS		Updated dfx_probe so that version information
+ *							string is only displayed if 1 or more cards are
+ *							found.  Changed dfx_rcv_queue_process to copy
+ *							3 NULL bytes before FC to ensure that data is
+ *							longword aligned in receive buffer.
+ *		09-Sep-96	LVS		Updated dfx_ctl_set_multicast_list to enable
+ *							LLC group promiscuous mode if multicast list
+ *							is too large.  LLC individual/group promiscuous
+ *							mode is now disabled if IFF_PROMISC flag not set.
+ *							dfx_xmt_queue_pkt no longer checks for NULL skb
+ *							on Alan Cox recommendation.  Added node address
+ *							override support.
+ *		12-Sep-96	LVS		Reset current address to factory address during
+ *							device open.  Updated transmit path to post a
+ *							single fragment which includes PRH->end of data.
+ */
+
+/* Version information string - should be updated prior to each new release!!! */
+
+static const char *version = "defxx.c:v1.04 09/16/96  Lawrence V. Stefani (stefani@lkg.dec.com)\n";
+
+/* Include files */
+
+#include <linux/module.h>
+
+#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>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+
+#include "defxx.h"
+
+/* Define global routines */
+
+int	dfx_probe(struct device *dev);
+
+/* Define module-wide (static) routines */
+
+static struct	device *dfx_alloc_device(struct device *dev, u16 iobase);
+
+static void		dfx_bus_init(struct device *dev);
+static void		dfx_bus_config_check(DFX_board_t *bp);
+
+static int		dfx_driver_init(struct device *dev);
+static int		dfx_adap_init(DFX_board_t *bp);
+
+static int		dfx_open(struct device *dev);
+static int		dfx_close(struct device *dev);
+
+static void		dfx_int_pr_halt_id(DFX_board_t *bp);
+static void		dfx_int_type_0_process(DFX_board_t *bp);
+static void		dfx_int_common(DFX_board_t *bp);
+static void		dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static struct	enet_statistics *dfx_ctl_get_stats(struct device *dev);
+static void		dfx_ctl_set_multicast_list(struct device *dev);
+static int		dfx_ctl_set_mac_address(struct device *dev, void *addr);
+static int		dfx_ctl_update_cam(DFX_board_t *bp);
+static int		dfx_ctl_update_filters(DFX_board_t *bp);
+
+static int		dfx_hw_dma_cmd_req(DFX_board_t *bp);
+static int		dfx_hw_port_ctrl_req(DFX_board_t *bp, PI_UINT32	command, PI_UINT32 data_a, PI_UINT32 data_b, PI_UINT32 *host_data);
+static void		dfx_hw_adap_reset(DFX_board_t *bp, PI_UINT32 type);
+static int		dfx_hw_adap_state_rd(DFX_board_t *bp);
+static int		dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type);
+
+static void		dfx_rcv_init(DFX_board_t *bp);
+static void		dfx_rcv_queue_process(DFX_board_t *bp);
+
+static int		dfx_xmt_queue_pkt(struct sk_buff *skb, struct device *dev);
+static void		dfx_xmt_done(DFX_board_t *bp);
+static void		dfx_xmt_flush(DFX_board_t *bp);
+
+/* Define module-wide (static) variables */
+
+static int		num_boards = 0;			/* total number of adapters configured */
+static int		already_probed = 0;		/* have we already entered dfx_probe? */
+
+
+/*
+ * =======================
+ * = dfx_port_write_byte =
+ * = dfx_port_read_byte	 =
+ * = dfx_port_write_long =
+ * = dfx_port_read_long  =
+ * =======================
+ *   
+ * Overview:
+ *   Routines for reading and writing values from/to adapter
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp     - pointer to board information
+ *   offset - register offset from base I/O address
+ *   data   - for dfx_port_write_byte and dfx_port_write_long, this
+ *			  is a value to write.
+ *			  for dfx_port_read_byte and dfx_port_read_byte, this
+ *			  is a pointer to store the read value.
+ *
+ * Functional Description:
+ *   These routines perform the correct operation to read or write
+ *   the adapter register.
+ *   
+ *   EISA port block base addresses are based on the slot number in which the
+ *   controller is installed.  For example, if the EISA controller is installed
+ *   in slot 4, the port block base address is 0x4000.  If the controller is
+ *   installed in slot 2, the port block base address is 0x2000, and so on.
+ *   This port block can be used to access PDQ, ESIC, and DEFEA on-board
+ *   registers using the register offsets defined in DEFXX.H.
+ *
+ *   PCI port block base addresses are assigned by the PCI BIOS or system
+ *	 firmware.  There is one 128 byte port block which can be accessed.  It
+ *   allows for I/O mapping of both PDQ and PFI registers using the register
+ *   offsets defined in DEFXX.H.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   bp->base_addr is a valid base I/O address for this adapter.
+ *   offset is a valid register offset for this adapter.
+ *
+ * Side Effects:
+ *   Rather than produce macros for these functions, these routines
+ *   are defined using "inline" to ensure that the compiler will
+ *   generate inline code and not waste a procedure call and return.
+ *   This provides all the benefits of macros, but with the
+ *   advantage of strict data type checking.
+ */
+
+static inline void dfx_port_write_byte(
+	DFX_board_t	*bp,
+	int			offset,
+	u8			data
+	)
+
+	{
+	u16 port = bp->base_addr + offset;
+
+	outb(data, port);
+	return;
+	}
+
+static inline void dfx_port_read_byte(
+	DFX_board_t	*bp,
+	int			offset,
+	u8			*data
+	)
+
+	{
+	u16 port = bp->base_addr + offset;
+
+	*data = inb(port);
+	return;
+	}
+
+static inline void dfx_port_write_long(
+	DFX_board_t	*bp,
+	int			offset,
+	u32			data
+	)
+
+	{
+	u16 port = bp->base_addr + offset;
+
+	outl(data, port);
+	return;
+	}
+
+static inline void dfx_port_read_long(
+	DFX_board_t	*bp,
+	int			offset,
+	u32			*data
+	)
+
+	{
+	u16 port = bp->base_addr + offset;
+
+	*data = inl(port);
+	return;
+	}
+
+
+/*
+ * =============
+ * = dfx_probe =
+ * =============
+ *   
+ * Overview:
+ *   Probes for supported FDDI EISA and PCI controllers
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This routine is called by the OS for each FDDI device name (fddi0,
+ *   fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c.  Since
+ *   the DEFXX.C driver currently does not support being loaded as a
+ *   module, dfx_probe() will initialize all devices the first time
+ *   it is called.
+ *
+ *   Let's say that dfx_probe() is getting called to initialize fddi0.
+ *   Furthermore, let's say there are three supported controllers in the
+ *   system.  Before dfx_probe() leaves, devices fddi0, fddi1, and fddi2
+ *   will be initialized and a global flag will be set to indicate that
+ *   dfx_probe() has already been called.
+ *
+ *   However...the OS doesn't know that we've already initialized
+ *   devices fddi1 and fddi2 so dfx_probe() gets called again and again
+ *   until it reaches the end of the device list for FDDI (presently,
+ *   fddi7).  It's important that the driver "pretend" to probe for
+ *   devices fddi1 and fddi2 and return success.  Devices fddi3
+ *   through fddi7 will return failure since they weren't initialized.
+ *
+ *   This algorithm seems to work for the time being.  As other FDDI
+ *   drivers are written for Linux, a more generic approach (perhaps
+ *   similar to the Ethernet card approach) may need to be implemented.
+ *   
+ * Return Codes:
+ *   0		 - This device (fddi0, fddi1, etc) configured successfully
+ *   -ENODEV - No devices present, or no Digital FDDI EISA or PCI device
+ *			   present for this device name
+ *
+ * Assumptions:
+ *   For the time being, DEFXX.C is the only FDDI driver under Linux.
+ *   As this assumption changes, this routine will likely be impacted.
+ *   Also, it is assumed that no more than eight (8) FDDI controllers
+ *   will be configured in the system (fddi0 through fddi7).  This
+ *   routine will not allocate new device structures.  If more than
+ *   eight FDDI controllers need to be configured, drivers/net/Space.c
+ *   should be updated as well as the DFX_MAX_NUM_BOARDS constant in
+ *   DEFXX.H.
+ *
+ * Side Effects:
+ *   Device structures for FDDI adapters (fddi0, fddi1, etc) are
+ *   initialized and the board resources are read and stored in
+ *   the device structure.
+ */
+
+int dfx_probe(
+	struct device *dev
+	)
+
+	{
+	int				i;				/* used in for loops */
+	int				version_disp;	/* was version info string already displayed? */
+	int				port_len;		/* length of port address range (in bytes) */
+	u8				pci_bus;		/* PCI bus number (0-255) */
+	u8				pci_dev_fun;	/* PCI device and function numbers (0-255) */
+	u16				port;			/* temporary I/O (port) address */
+	u16				command;		/* PCI Configuration space Command register val */
+	u32				slot_id;		/* EISA hardware (slot) ID read from adapter */
+	DFX_board_t		*bp;			/* board pointer */
+
+	DBG_printk("In dfx_probe...\n");
+
+	/*
+	 * Verify whether we're going through dfx_probe() again
+	 *
+	 * If so, see if we're going through for a subsequent fddi device that
+	 * we've already initialized.  If we are, return success (0).  If not,
+	 * return failure (-ENODEV).
+	 */
+
+	version_disp = 0;				/* default to version string not displayed */
+	if (already_probed)
+		{
+		DBG_printk("Already entered dfx_probe\n");
+		if (dev != NULL)
+			if ((strncmp(dev->name, "fddi", 4) == 0) && (dev->base_addr != 0))
+				{
+				DBG_printk("In dfx_probe for fddi adapter (%s) we've already initialized it, so return success\n", dev->name);
+				return(0);
+				}
+		return(-ENODEV);
+		}
+	already_probed = 1;			/* set global flag */
+
+	/* Scan for FDDI EISA controllers */
+
+	for (i=0; i < DFX_MAX_EISA_SLOTS; i++)		/* only scan for up to 16 EISA slots */
+		{
+		port = (i << 12) + PI_ESIC_K_SLOT_ID;	/* port = I/O address for reading slot ID */
+		slot_id = inl(port);					/* read EISA HW (slot) ID */
+		if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID)
+			{
+			if (!version_disp)					/* display version info if adapter is found */
+				{
+				version_disp = 1;				/* set display flag to TRUE so that */
+				printk(version);				/* we only display this string ONCE */
+				}
+				
+			port = (i << 12);					/* recalc base addr */
+
+			/* Verify port address range is not already being used */
+
+			port_len = PI_ESIC_K_CSR_IO_LEN;
+			if (check_region(port, port_len) == 0)
+				{
+				/* Allocate a new device structure for this adapter */
+
+				dev = dfx_alloc_device(dev, port);
+				if (dev != NULL)
+					{
+					/* Initialize board structure with bus-specific info */
+
+					bp = (DFX_board_t *) dev->priv;
+					bp->dev = dev;
+					bp->bus_type = DFX_BUS_TYPE_EISA;
+					if (dfx_driver_init(dev) == DFX_K_SUCCESS)
+						num_boards++;		/* only increment global board count on success */
+					else
+						dev->base_addr = 0;	/* clear port address field in device structure on failure */
+					}
+				}
+			else
+				printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
+			}
+		}
+
+	/* Scan for FDDI PCI controllers */
+
+	if (pcibios_present())						/* is PCI BIOS even present? */
+		for (i=0; i < DFX_MAX_NUM_BOARDS; i++)	/* scan for up to 8 PCI cards */
+			if (pcibios_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, i, &pci_bus, &pci_dev_fun) == 0)
+				{
+				if (!version_disp)					/* display version info if adapter is found */
+					{
+					version_disp = 1;				/* set display flag to TRUE so that */
+					printk(version);				/* we only display this string ONCE */
+					}
+
+				/* Verify that I/O enable bit is set (PCI slot is enabled) */
+
+				pcibios_read_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, &command);
+				if ((command & PCI_COMMAND_IO) == 0)
+					printk("I/O enable bit not set!  Verify that slot is enabled\n");
+				else
+					{
+					/* Turn off memory mapped space and enable mastering */
+
+					command |= PCI_COMMAND_MASTER;
+					command &= ~PCI_COMMAND_MEMORY;
+					pcibios_write_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, command);
+
+					/* Read I/O base address from PCI Configuration Space */
+				
+					pcibios_read_config_word(pci_bus, pci_dev_fun, PCI_BASE_ADDRESS_1, &port);
+					port &= PCI_BASE_ADDRESS_IO_MASK;		/* clear I/O bit (bit 0) */
+
+					/* Verify port address range is not already being used */
+
+					port_len = PFI_K_CSR_IO_LEN;
+					if (check_region(port, port_len) == 0)
+						{
+						/* Allocate a new device structure for this adapter */
+
+						dev = dfx_alloc_device(dev, port);
+						if (dev != NULL)
+							{
+							/* Initialize board structure with bus-specific info */
+
+							bp = (DFX_board_t *) dev->priv;
+							bp->dev = dev;
+							bp->bus_type = DFX_BUS_TYPE_PCI;
+							bp->pci_bus = pci_bus;
+							bp->pci_dev_fun = pci_dev_fun;
+							if (dfx_driver_init(dev) == DFX_K_SUCCESS)
+								num_boards++;		/* only increment global board count on success */
+							else
+								dev->base_addr = 0;	/* clear port address field in device structure on failure */
+							}
+						}
+					else
+						printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
+					}
+				}
+
+	/*
+	 * If we're at this point we're going through dfx_probe() for the first
+	 * time.  Return success (0) if we've initialized 1 or more boards.
+	 * Otherwise, return failure (-ENODEV).
+	 */
+
+	if (num_boards > 0)
+		return(0);
+	else
+		return(-ENODEV);
+	}
+
+
+/*
+ * ====================
+ * = dfx_alloc_device =
+ * ====================
+ *   
+ * Overview:
+ *   Allocate new device structure for adapter
+ *  
+ * Returns:
+ *   Pointer to device structure for this adapter or NULL if
+ *   none are available or could not allocate memory for
+ *   private board structure.
+ *       
+ * Arguments:
+ *   dev    - pointer to device information for last device
+ *   iobase - base I/O address of new adapter
+ *
+ * Functional Description:
+ *   The algorithm for allocating a new device structure is
+ *   fairly simple.  Since we're presently the only FDDI driver
+ *   under Linux, we'll find the first device structure with an
+ *   "fddi*" device name that's free.  If we run out of devices,
+ *   we'll fail on error.  This is simpler than trying to
+ *   allocate the memory for a new device structure, determine
+ *   the next free number (beyond 7) and link it into the chain
+ *   of devices.  A user can always modify drivers/net/Space.c
+ *   to add new FDDI device structures if necessary.
+ *
+ *   Beyond finding a free FDDI device structure, this routine
+ *   initializes most of the fields, resource tags, and dispatch
+ *   pointers in the device structure and calls the common
+ *   fddi_setup() routine to perform the rest of the device
+ *   structure initialization.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   If additional FDDI drivers are integrated into Linux,
+ *   we'll likely need to use a different approach to
+ *   allocate a device structure.  Perhaps one that is
+ *   similar to what the Ethernet drivers use.
+ *
+ * Side Effects:
+ *   None
+ */
+
+struct device *dfx_alloc_device(
+	struct device	*dev,
+	u16				iobase
+	)
+
+	{
+	struct device *tmp_dev;		/* pointer to a device structure */
+
+	DBG_printk("In dfx_alloc_device...\n");
+
+	/* Find next free fddi entry */
+
+	for (tmp_dev = dev; tmp_dev != NULL; tmp_dev = tmp_dev->next)
+		if ((strncmp(tmp_dev->name, "fddi", 4) == 0) && (tmp_dev->base_addr == 0))
+			break;
+	if (tmp_dev == NULL)
+		{
+		printk("Could not find free FDDI device structure for this adapter!\n");
+		return(NULL);
+		}
+	DBG_printk("Device entry free, device name = %s\n", tmp_dev->name);
+
+	/* Allocate space for private board structure */
+
+	tmp_dev->priv = (void *) kmalloc(sizeof(DFX_board_t), GFP_KERNEL);
+	if (tmp_dev->priv == NULL)
+		{
+		printk("Could not allocate memory for private board structure!\n");
+		return(NULL);
+		}
+	memset(tmp_dev->priv, 0, sizeof(DFX_board_t));	/* clear structure */
+
+	/* Initialize new device structure */
+
+	tmp_dev->rmem_end	= 0;		/* shared memory isn't used */
+	tmp_dev->rmem_start	= 0;		/* shared memory isn't used */
+	tmp_dev->mem_end	= 0;		/* shared memory isn't used */
+	tmp_dev->mem_start	= 0;		/* shared memory isn't used */
+	tmp_dev->base_addr	= iobase;	/* save port (I/O) base address */
+	tmp_dev->irq		= 0;		/* set in dfx_bus_init() */
+	tmp_dev->if_port	= 0;		/* not applicable to FDDI adapters */
+	tmp_dev->dma		= 0;		/* Bus Master DMA doesn't require channel */
+
+	tmp_dev->get_stats				= &dfx_ctl_get_stats;
+	tmp_dev->open					= &dfx_open;
+	tmp_dev->stop					= &dfx_close;
+	tmp_dev->hard_start_xmit		= &dfx_xmt_queue_pkt;
+	tmp_dev->hard_header			= NULL;		/* set in fddi_setup() */
+	tmp_dev->rebuild_header			= NULL;		/* set in fddi_setup() */
+	tmp_dev->set_multicast_list		= &dfx_ctl_set_multicast_list;
+	tmp_dev->set_mac_address		= &dfx_ctl_set_mac_address;
+	tmp_dev->do_ioctl				= NULL;		/* not supported for now &&& */
+	tmp_dev->set_config				= NULL;		/* not supported for now &&& */
+	tmp_dev->header_cache_bind		= NULL;		/* not supported */
+	tmp_dev->header_cache_update	= NULL;		/* not supported */
+	tmp_dev->change_mtu				= NULL;		/* set in fddi_setup() */
+
+	/* Initialize remaining device structure information */
+
+	fddi_setup(tmp_dev);
+	return(tmp_dev);
+	}
+
+
+/*
+ * ================
+ * = dfx_bus_init =
+ * ================
+ *   
+ * Overview:
+ *   Initializes EISA and PCI controller bus-specific logic.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   Determine and save adapter IRQ in device table,
+ *   then perform bus-specific logic initialization.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   dev->base_addr has already been set with the proper
+ *	 base I/O address for this device.
+ *
+ * Side Effects:
+ *   Interrupts are enabled at the adapter bus-specific logic.
+ *   Note:  Interrupts at the DMA engine (PDQ chip) are not
+ *   enabled yet.
+ */
+
+void dfx_bus_init(
+	struct device *dev
+	)
+
+	{
+	DFX_board_t *bp = (DFX_board_t *)dev->priv;
+	u8			val;	/* used for I/O read/writes */
+
+	DBG_printk("In dfx_bus_init...\n");
+
+	/*
+	 * Initialize base I/O address field in bp structure
+	 *
+	 * Note: bp->base_addr is the same as dev->base_addr.
+	 *		 It's useful because often we'll need to read
+	 *		 or write registers where we already have the
+	 *		 bp pointer instead of the dev pointer.  Having
+	 *		 the base address in the bp structure will
+	 *		 save a pointer dereference.
+	 *
+	 *		 IMPORTANT!! This field must be defined before
+	 *		 any of the dfx_port_* inline functions are
+	 *		 called.
+	 */
+
+	bp->base_addr = dev->base_addr;
+
+	/* Initialize adapter based on bus type */
+
+	if (bp->bus_type == DFX_BUS_TYPE_EISA)
+		{
+		/* Get the interrupt level from the ESIC chip */
+
+		dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
+		switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ)
+			{
+			case PI_CONFIG_STAT_0_IRQ_K_9:
+				dev->irq = 9;
+				break;
+
+			case PI_CONFIG_STAT_0_IRQ_K_10:
+				dev->irq = 10;
+				break;
+
+			case PI_CONFIG_STAT_0_IRQ_K_11:
+				dev->irq = 11;
+				break;
+
+			case PI_CONFIG_STAT_0_IRQ_K_15:
+				dev->irq = 15;
+				break;
+			}
+
+		/* Enable access to I/O on the board by writing 0x03 to Function Control Register */
+
+		dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB);
+
+		/* Set the I/O decode range of the board */
+
+		val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT);
+		dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val);
+		dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val);
+
+		/* Enable access to rest of module (including PDQ and packet memory) */
+
+		dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB);
+
+		/*
+		 * Map PDQ registers into I/O space.  This is done by clearing a bit
+		 * in Burst Holdoff register.
+		 */
+
+		dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val);
+		dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP));
+
+		/* Enable interrupts at EISA bus interface chip (ESIC) */
+
+		dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
+		dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB));
+		}
+	else
+		{
+		/* Get the interrupt level from the PCI Configuration Table */
+
+		pcibios_read_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_INTERRUPT_LINE, &val);
+		dev->irq = val;					/* save IRQ value in device table */
+
+		/* Check Latency Timer and set if less than minimal */
+
+		pcibios_read_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_LATENCY_TIMER, &val);
+		if (val < PFI_K_LAT_TIMER_MIN)	/* if less than min, override with default */
+			{
+			val = PFI_K_LAT_TIMER_DEF;
+			pcibios_write_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_LATENCY_TIMER, val);
+			}
+
+		/* Enable interrupts at PCI bus interface chip (PFI) */
+
+		dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB));
+		}
+	return;
+	}
+
+
+/*
+ * ========================
+ * = dfx_bus_config_check =
+ * ========================
+ *   
+ * Overview:
+ *   Checks the configuration (burst size, full-duplex, etc.)  If any parameters
+ *   are illegal, then this routine will set new defaults.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   For Revision 1 FDDI EISA, Revision 2 or later FDDI EISA with rev E or later
+ *   PDQ, and all FDDI PCI controllers, all values are legal.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   dfx_adap_init has NOT been called yet so burst size and other items have
+ *   not been set.
+ *
+ * Side Effects:
+ *   None
+ */
+
+void dfx_bus_config_check(
+	DFX_board_t *bp
+	)
+
+	{
+	int	status;				/* return code from adapter port control call */
+	u32	slot_id;			/* EISA-bus hardware id (DEC3001, DEC3002,...) */
+	u32	host_data;			/* LW data returned from port control call */
+
+	DBG_printk("In dfx_bus_config_check...\n");
+
+	/* Configuration check only valid for EISA adapter */
+
+	if (bp->bus_type == DFX_BUS_TYPE_EISA)
+		{
+		dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id);
+
+		/*
+		 * First check if revision 2 EISA controller.  Rev. 1 cards used
+		 * PDQ revision B, so no workaround needed in this case.  Rev. 3
+		 * cards used PDQ revision E, so no workaround needed in this
+		 * case, either.  Only Rev. 2 cards used either Rev. D or E
+		 * chips, so we must verify the chip revision on Rev. 2 cards.
+		 */
+
+		if (slot_id == DEFEA_PROD_ID_2)
+			{
+			/*
+			 * Revision 2 FDDI EISA controller found, so let's check PDQ
+			 * revision of adapter.
+			 */
+
+			status = dfx_hw_port_ctrl_req(bp,
+											PI_PCTRL_M_SUB_CMD,
+											PI_SUB_CMD_K_PDQ_REV_GET,
+											0,
+											&host_data);
+			if ((status != DFX_K_SUCCESS) || (host_data == 2))
+				{
+				/*
+				 * Either we couldn't determine the PDQ revision, or
+				 * we determined that it is at revision D.  In either case,
+				 * we need to implement the workaround.
+				 */
+
+				/* Ensure that the burst size is set to 8 longwords or less */
+
+				switch (bp->burst_size)
+					{
+					case PI_PDATA_B_DMA_BURST_SIZE_32:
+					case PI_PDATA_B_DMA_BURST_SIZE_16:
+						bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_8;
+						break;
+
+					default:
+						break;
+					}
+
+				/* Ensure that full-duplex mode is not enabled */
+
+				bp->full_duplex_enb = PI_SNMP_K_FALSE;
+				}
+			}
+		}
+	return;
+	}
+
+
+/*
+ * ===================
+ * = dfx_driver_init =
+ * ===================
+ *   
+ * Overview:
+ *   Initializes remaining adapter board structure information
+ *   and makes sure adapter is in a safe state prior to dfx_open().
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This function allocates additional resources such as the host memory
+ *   blocks needed by the adapter (eg. descriptor and consumer blocks).
+ *	 Remaining bus initialization steps are also completed.  The adapter
+ *   is also reset so that it is in the DMA_UNAVAILABLE state.  The OS
+ *   must call dfx_open() to open the adapter and bring it on-line.
+ *
+ * Return Codes:
+ *   DFX_K_SUCCESS	- initialization succeeded
+ *   DFX_K_FAILURE	- initialization failed - could not allocate memory
+ *						or read adapter MAC address
+ *
+ * Assumptions:
+ *   Memory allocated from kmalloc() call is physically contiguous, locked
+ *   memory whose physical address equals its virtual address.
+ *
+ * Side Effects:
+ *   Adapter is reset and should be in DMA_UNAVAILABLE state before
+ *   returning from this routine.
+ */
+
+int dfx_driver_init(
+	struct device *dev
+	)
+
+	{
+	DFX_board_t *bp = (DFX_board_t *)dev->priv;
+	int			alloc_size;			/* total buffer size needed */
+	char		*top_v, *curr_v;	/* virtual addrs into memory block */
+	u32			top_p, curr_p;		/* physical addrs into memory block */
+	u32			data;				/* host data register value */
+
+	DBG_printk("In dfx_driver_init...\n");
+
+	/* Initialize bus-specific hardware registers */
+
+	dfx_bus_init(dev);
+
+	/*
+	 * Initialize default values for configurable parameters
+	 *
+	 * Note: All of these parameters are ones that a user may
+	 *       want to customize.  It'd be nice to break these
+	 *		 out into Space.c or someplace else that's more
+	 *		 accessible/understandable than this file.
+	 */
+
+	bp->full_duplex_enb		= PI_SNMP_K_FALSE;
+	bp->req_ttrt			= 8 * 12500;		/* 8ms in 80 nanosec units */
+	bp->burst_size			= PI_PDATA_B_DMA_BURST_SIZE_DEF;
+	bp->rcv_bufs_to_post	= RCV_BUFS_DEF;
+
+	/*
+	 * Ensure that HW configuration is OK
+	 *
+	 * Note: Depending on the hardware revision, we may need to modify
+	 *       some of the configurable parameters to workaround hardware
+	 *       limitations.  We'll perform this configuration check AFTER
+	 *       setting the parameters to their default values.
+	 */
+
+	dfx_bus_config_check(bp);
+
+	/* Disable PDQ interrupts first */
+
+	dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
+
+	/* Place adapter in DMA_UNAVAILABLE state by resetting adapter */
+
+	(void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST);
+
+	/*  Read the factory MAC address from the adapter then save it */
+
+	if (dfx_hw_port_ctrl_req(bp,
+							PI_PCTRL_M_MLA,
+							PI_PDATA_A_MLA_K_LO,
+							0,
+							&data) != DFX_K_SUCCESS)
+		{
+		printk("%s: Could not read adapter factory MAC address!\n", dev->name);
+		return(DFX_K_FAILURE);
+		}
+	memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32));
+
+	if (dfx_hw_port_ctrl_req(bp,
+							PI_PCTRL_M_MLA,
+							PI_PDATA_A_MLA_K_HI,
+							0,
+							&data) != DFX_K_SUCCESS)
+		{
+		printk("%s: Could not read adapter factory MAC address!\n", dev->name);
+		return(DFX_K_FAILURE);
+		}
+	memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16));
+
+	/*
+	 * Set current address to factory address
+	 *
+	 * Note: Node address override support is handled through
+	 *       dfx_ctl_set_mac_address.
+	 */
+
+	memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN);
+	if (bp->bus_type == DFX_BUS_TYPE_EISA)
+		printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+				dev->name,
+				dev->base_addr,
+				dev->irq,
+				dev->dev_addr[0],
+				dev->dev_addr[1],
+				dev->dev_addr[2],
+				dev->dev_addr[3],
+				dev->dev_addr[4],
+				dev->dev_addr[5]);
+	else
+		printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+				dev->name,
+				dev->base_addr,
+				dev->irq,
+				dev->dev_addr[0],
+				dev->dev_addr[1],
+				dev->dev_addr[2],
+				dev->dev_addr[3],
+				dev->dev_addr[4],
+				dev->dev_addr[5]);
+
+	/*
+	 * Get memory for descriptor block, consumer block, and other buffers
+	 * that need to be DMA read or written to by the adapter.
+	 */
+
+	alloc_size = sizeof(PI_DESCR_BLOCK) +
+					PI_CMD_REQ_K_SIZE_MAX +
+					PI_CMD_RSP_K_SIZE_MAX +
+					(bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) +
+					sizeof(PI_CONSUMER_BLOCK) +
+					(PI_ALIGN_K_DESC_BLK - 1);
+	top_v = (char *) kmalloc(alloc_size, GFP_KERNEL);
+	if (top_v == NULL)
+		{
+		printk("%s: Could not allocate memory for host buffers and structures!\n", dev->name);
+		return(DFX_K_FAILURE);
+		}
+	memset(top_v, 0, alloc_size);	/* zero out memory before continuing */
+	top_p = virt_to_bus(top_v);		/* get physical address of buffer */
+
+	/*
+	 *  To guarantee the 8K alignment required for the descriptor block, 8K - 1
+	 *  plus the amount of memory needed was allocated.  The physical address
+	 *	is now 8K aligned.  By carving up the memory in a specific order,
+	 *  we'll guarantee the alignment requirements for all other structures.
+	 *
+	 *  Note: If the assumptions change regarding the non-paged, non-cached,
+	 *		  physically contiguous nature of the memory block or the address
+	 *		  alignments, then we'll need to implement a different algorithm
+	 *		  for allocating the needed memory.
+	 */
+
+	curr_p = (u32) (ALIGN(top_p, PI_ALIGN_K_DESC_BLK));
+	curr_v = top_v + (curr_p - top_p);
+
+	/* Reserve space for descriptor block */
+
+	bp->descr_block_virt = (PI_DESCR_BLOCK *) curr_v;
+	bp->descr_block_phys = curr_p;
+	curr_v += sizeof(PI_DESCR_BLOCK);
+	curr_p += sizeof(PI_DESCR_BLOCK);
+
+	/* Reserve space for command request buffer */
+
+	bp->cmd_req_virt = (PI_DMA_CMD_REQ *) curr_v;
+	bp->cmd_req_phys = curr_p;
+	curr_v += PI_CMD_REQ_K_SIZE_MAX;
+	curr_p += PI_CMD_REQ_K_SIZE_MAX;
+
+	/* Reserve space for command response buffer */
+
+	bp->cmd_rsp_virt = (PI_DMA_CMD_RSP *) curr_v;
+	bp->cmd_rsp_phys = curr_p;
+	curr_v += PI_CMD_RSP_K_SIZE_MAX;
+	curr_p += PI_CMD_RSP_K_SIZE_MAX;
+
+	/* Reserve space for the LLC host receive queue buffers */
+
+	bp->rcv_block_virt = curr_v;
+	bp->rcv_block_phys = curr_p;
+	curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
+	curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
+
+	/* Reserve space for the consumer block */
+
+	bp->cons_block_virt = (PI_CONSUMER_BLOCK *) curr_v;
+	bp->cons_block_phys = curr_p;
+
+	/* Display virtual and physical addresses if debug driver */
+
+	DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n",				dev->name, (long)bp->descr_block_virt,	bp->descr_block_phys);
+	DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n",			dev->name, (long)bp->cmd_req_virt,		bp->cmd_req_phys);
+	DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n",			dev->name, (long)bp->cmd_rsp_virt,		bp->cmd_rsp_phys);
+	DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n",			dev->name, (long)bp->rcv_block_virt,	bp->rcv_block_phys);
+	DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n",					dev->name, (long)bp->cons_block_virt,	bp->cons_block_phys);
+
+	return(DFX_K_SUCCESS);
+	}
+
+
+/*
+ * =================
+ * = dfx_adap_init =
+ * =================
+ *   
+ * Overview:
+ *   Brings the adapter to the link avail/link unavailable state.
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   Issues the low-level firmware/hardware calls necessary to bring
+ *   the adapter up, or to properly reset and restore adapter during
+ *   run-time.
+ *
+ * Return Codes:
+ *   DFX_K_SUCCESS - Adapter brought up successfully
+ *   DFX_K_FAILURE - Adapter initialization failed
+ *
+ * Assumptions:
+ *   bp->reset_type should be set to a valid reset type value before
+ *   calling this routine.
+ *
+ * Side Effects:
+ *   Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state
+ *   upon a successful return of this routine.
+ */
+
+int dfx_adap_init(
+	DFX_board_t *bp
+	)
+
+	{
+	DBG_printk("In dfx_adap_init...\n");
+
+	/* Disable PDQ interrupts first */
+
+	dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
+
+	/* Place adapter in DMA_UNAVAILABLE state by resetting adapter */
+
+	if (dfx_hw_dma_uninit(bp, bp->reset_type) != DFX_K_SUCCESS)
+		{
+		printk("%s: Could not uninitialize/reset adapter!\n", bp->dev->name);
+		return(DFX_K_FAILURE);
+		}
+
+	/*
+	 * When the PDQ is reset, some false Type 0 interrupts may be pending,
+	 * so we'll acknowledge all Type 0 interrupts now before continuing.
+	 */
+
+	dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, PI_HOST_INT_K_ACK_ALL_TYPE_0);
+
+	/*
+	 * Clear Type 1 and Type 2 registers before going to DMA_AVAILABLE state
+	 *
+	 * Note: We only need to clear host copies of these registers.  The PDQ reset
+	 *       takes care of the on-board register values.
+	 */
+
+	bp->cmd_req_reg.lword	= 0;
+	bp->cmd_rsp_reg.lword	= 0;
+	bp->rcv_xmt_reg.lword	= 0;
+
+	/* Clear consumer block before going to DMA_AVAILABLE state */
+
+	memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK));
+
+	/* Initialize the DMA Burst Size */
+
+	if (dfx_hw_port_ctrl_req(bp,
+							PI_PCTRL_M_SUB_CMD,
+							PI_SUB_CMD_K_BURST_SIZE_SET,
+							bp->burst_size,
+							NULL) != DFX_K_SUCCESS)
+		{
+		printk("%s: Could not set adapter burst size!\n", bp->dev->name);
+		return(DFX_K_FAILURE);
+		}
+
+	/*
+	 * Set base address of Consumer Block
+	 *
+	 * Assumption: 32-bit physical address of consumer block is 64 byte
+	 *			   aligned.  That is, bits 0-5 of the address must be zero.
+	 */
+
+	if (dfx_hw_port_ctrl_req(bp,
+							PI_PCTRL_M_CONS_BLOCK,
+							bp->cons_block_phys,
+							0,
+							NULL) != DFX_K_SUCCESS)
+		{
+		printk("%s: Could not set consumer block address!\n", bp->dev->name);
+		return(DFX_K_FAILURE);
+		}
+
+	/*
+	 * Set base address of Descriptor Block and bring adapter to DMA_AVAILABLE state
+	 *
+	 * Note: We also set the literal and data swapping requirements in this
+	 *	     command.  Since this driver presently runs on Intel platforms
+	 *		 which are Little Endian, we'll tell the adapter to byte swap
+	 *		 data only.  This code will need to change when we support
+	 *		 Big Endian systems (eg. PowerPC).
+	 *
+	 * Assumption: 32-bit physical address of descriptor block is 8Kbyte
+	 *             aligned.  That is, bits 0-12 of the address must be zero.
+	 */
+
+	if (dfx_hw_port_ctrl_req(bp,
+							PI_PCTRL_M_INIT,
+							(u32) (bp->descr_block_phys | PI_PDATA_A_INIT_M_BSWAP_DATA),
+							0,
+							NULL) != DFX_K_SUCCESS)
+		{
+		printk("%s: Could not set descriptor block address!\n", bp->dev->name);
+		return(DFX_K_FAILURE);
+		}
+
+	/* Set transmit flush timeout value */
+
+	bp->cmd_req_virt->cmd_type = PI_CMD_K_CHARS_SET;
+	bp->cmd_req_virt->char_set.item[0].item_code	= PI_ITEM_K_FLUSH_TIME;
+	bp->cmd_req_virt->char_set.item[0].value		= 3;	/* 3 seconds */
+	bp->cmd_req_virt->char_set.item[0].item_index	= 0;
+	bp->cmd_req_virt->char_set.item[1].item_code	= PI_ITEM_K_EOL;
+	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
+		{
+		printk("%s: DMA command request failed!\n", bp->dev->name);
+		return(DFX_K_FAILURE);
+		}
+
+	/* Set the initial values for eFDXEnable and MACTReq MIB objects */
+
+	bp->cmd_req_virt->cmd_type = PI_CMD_K_SNMP_SET;
+	bp->cmd_req_virt->snmp_set.item[0].item_code	= PI_ITEM_K_FDX_ENB_DIS;
+	bp->cmd_req_virt->snmp_set.item[0].value		= bp->full_duplex_enb;
+	bp->cmd_req_virt->snmp_set.item[0].item_index	= 0;
+	bp->cmd_req_virt->snmp_set.item[1].item_code	= PI_ITEM_K_MAC_T_REQ;
+	bp->cmd_req_virt->snmp_set.item[1].value		= bp->req_ttrt;
+	bp->cmd_req_virt->snmp_set.item[1].item_index	= 0;
+	bp->cmd_req_virt->snmp_set.item[2].item_code	= PI_ITEM_K_EOL;
+	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
+		{
+		printk("%s: DMA command request failed!\n", bp->dev->name);
+		return(DFX_K_FAILURE);
+		}
+
+	/* Initialize adapter CAM */
+
+	if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS)
+		{
+		printk("%s: Adapter CAM update failed!\n", bp->dev->name);
+		return(DFX_K_FAILURE);
+		}
+
+	/* Initialize adapter filters */
+
+	if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS)
+		{
+		printk("%s: Adapter filters update failed!\n", bp->dev->name);
+		return(DFX_K_FAILURE);
+		}
+
+	/* Initialize receive descriptor block and produce buffers */
+
+	dfx_rcv_init(bp);
+
+	/* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */
+
+	bp->cmd_req_virt->cmd_type = PI_CMD_K_START;
+	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
+		{
+		printk("%s: Start command failed\n", bp->dev->name);
+		return(DFX_K_FAILURE);
+		}
+
+	/* Initialization succeeded, reenable PDQ interrupts */
+
+	dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_ENABLE_DEF_INTS);
+	return(DFX_K_SUCCESS);
+	}
+
+
+/*
+ * ============
+ * = dfx_open =
+ * ============
+ *   
+ * Overview:
+ *   Opens the adapter
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This function brings the adapter to an operational state.
+ *
+ * Return Codes:
+ *   0		 - Adapter was successfully opened
+ *   -EAGAIN - Could not register IRQ or adapter initialization failed
+ *
+ * Assumptions:
+ *   This routine should only be called for a device that was
+ *   initialized successfully during the dfx_probe process.
+ *
+ * Side Effects:
+ *   Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state
+ *   if the open is successful.
+ */
+
+int dfx_open(
+	struct device *dev
+	)
+
+	{
+	DFX_board_t	*bp = (DFX_board_t *)dev->priv;
+
+	DBG_printk("In dfx_open...\n");
+
+	/* Register IRQ - support shared interrupts by passing device ptr */
+
+	if (request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev))
+		{
+		printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
+		return(-EAGAIN);
+		}
+
+	/*
+	 * Set current address to factory MAC address
+	 *
+	 * Note: We've already done this step in dfx_driver_init.
+	 *       However, it's possible that a user has set a node
+	 *		 address override, then closed and reopened the
+	 *		 adapter.  Unless we reset the device address field
+	 *		 now, we'll continue to use the existing modified
+	 *		 address.
+	 */
+
+	memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN);
+
+	/* Clear local unicast/multicast address tables and counts */
+
+	memset(bp->uc_table, 0, sizeof(bp->uc_table));
+	memset(bp->mc_table, 0, sizeof(bp->mc_table));
+	bp->uc_count = 0;
+	bp->mc_count = 0;
+
+	/* Disable promiscuous filter settings */
+
+	bp->ind_group_prom	= PI_FSTATE_K_BLOCK;
+	bp->group_prom		= PI_FSTATE_K_BLOCK;
+
+	/* Reset and initialize adapter */
+
+	bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST;	/* skip self-test */
+	if (dfx_adap_init(bp) != DFX_K_SUCCESS)
+		{
+		printk("%s: Adapter open failed!\n", dev->name);
+		return(-EAGAIN);
+		}
+
+	/* Set device structure info */
+
+	dev->tbusy			= 0;
+	dev->interrupt		= DFX_UNMASK_INTERRUPTS;
+	dev->start			= 1;
+	return(0);
+	}
+
+
+/*
+ * =============
+ * = dfx_close =
+ * =============
+ *   
+ * Overview:
+ *   Closes the device/module.
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This routine closes the adapter and brings it to a safe state.
+ *   The interrupt service routine is deregistered with the OS.
+ *   The adapter can be opened again with another call to dfx_open().
+ *
+ * Return Codes:
+ *   Always return 0.
+ *
+ * Assumptions:
+ *   No further requests for this adapter are made after this routine is
+ *   called.  dfx_open() can be called to reset and reinitialize the
+ *   adapter.
+ *
+ * Side Effects:
+ *   Adapter should be in DMA_UNAVAILABLE state upon completion of this
+ *   routine.
+ */
+
+int dfx_close(
+	struct device *dev
+	)
+
+	{
+	DFX_board_t	*bp = (DFX_board_t *)dev->priv;
+
+	DBG_printk("In dfx_close...\n");
+
+	/* Disable PDQ interrupts first */
+
+	dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
+
+	/* Place adapter in DMA_UNAVAILABLE state by resetting adapter */
+
+	(void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST);
+
+	/*
+	 * Flush any pending transmit buffers
+	 *
+	 * Note: It's important that we flush the transmit buffers
+	 *		 BEFORE we clear our copy of the Type 2 register.
+	 *		 Otherwise, we'll have no idea how many buffers
+	 *		 we need to free.
+	 */
+
+	dfx_xmt_flush(bp);
+
+	/*
+	 * Clear Type 1 and Type 2 registers after adapter reset
+	 *
+	 * Note: Even though we're closing the adapter, it's
+	 *       possible that an interrupt will occur after
+	 *		 dfx_close is called.  Without some assurance to
+	 *		 the contrary we want to make sure that we don't
+	 *		 process receive and transmit LLC frames and update
+	 *		 the Type 2 register with bad information.
+	 */
+
+	bp->cmd_req_reg.lword	= 0;
+	bp->cmd_rsp_reg.lword	= 0;
+	bp->rcv_xmt_reg.lword	= 0;
+
+	/* Clear consumer block for the same reason given above */
+
+	memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK));
+
+	/* Clear device structure flags */
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	/* Deregister (free) IRQ */
+
+	free_irq(dev->irq, dev);
+	return(0);
+	}
+
+
+/*
+ * ======================
+ * = dfx_int_pr_halt_id =
+ * ======================
+ *   
+ * Overview:
+ *   Displays halt id's in string form.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   Determine current halt id and display appropriate string.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   None
+ *
+ * Side Effects:
+ *   None
+ */
+
+void dfx_int_pr_halt_id(
+	DFX_board_t	*bp
+	)
+
+	{
+	PI_UINT32	port_status;			/* PDQ port status register value */
+	PI_UINT32	halt_id;				/* PDQ port status halt ID */
+
+	/* Read the latest port status */
+
+	dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status);
+
+	/* Display halt state transition information */
+
+	halt_id = (port_status & PI_PSTATUS_M_HALT_ID) >> PI_PSTATUS_V_HALT_ID;
+	switch (halt_id)
+		{
+		case PI_HALT_ID_K_SELFTEST_TIMEOUT:
+			printk("%s: Halt ID: Selftest Timeout\n", bp->dev->name);
+			break;
+
+		case PI_HALT_ID_K_PARITY_ERROR:
+			printk("%s: Halt ID: Host Bus Parity Error\n", bp->dev->name);
+			break;
+
+		case PI_HALT_ID_K_HOST_DIR_HALT:
+			printk("%s: Halt ID: Host-Directed Halt\n", bp->dev->name);
+			break;
+
+		case PI_HALT_ID_K_SW_FAULT:
+			printk("%s: Halt ID: Adapter Software Fault\n", bp->dev->name);
+			break;
+
+		case PI_HALT_ID_K_HW_FAULT:
+			printk("%s: Halt ID: Adapter Hardware Fault\n", bp->dev->name);
+			break;
+
+		case PI_HALT_ID_K_PC_TRACE:
+			printk("%s: Halt ID: FDDI Network PC Trace Path Test\n", bp->dev->name);
+			break;
+
+		case PI_HALT_ID_K_DMA_ERROR:
+			printk("%s: Halt ID: Adapter DMA Error\n", bp->dev->name);
+			break;
+
+		case PI_HALT_ID_K_IMAGE_CRC_ERROR:
+			printk("%s: Halt ID: Firmware Image CRC Error\n", bp->dev->name);
+			break;
+
+		case PI_HALT_ID_K_BUS_EXCEPTION:
+			printk("%s: Halt ID: 68000 Bus Exception\n", bp->dev->name);
+			break;
+
+		default:
+			printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id);
+			break;
+		}
+	return;
+	}
+
+
+/*
+ * ==========================
+ * = dfx_int_type_0_process =
+ * ==========================
+ *   
+ * Overview:
+ *   Processes Type 0 interrupts.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   Processes all enabled Type 0 interrupts.  If the reason for the interrupt
+ *   is a serious fault on the adapter, then an error message is displayed
+ *   and the adapter is reset.
+ *
+ *   One tricky potential timing window is the rapid succession of "link avail"
+ *   "link unavail" state change interrupts.  The acknowledgement of the Type 0
+ *   interrupt must be done before reading the state from the Port Status
+ *   register.  This is true because a state change could occur after reading
+ *   the data, but before acknowledging the interrupt.  If this state change
+ *   does happen, it would be lost because the driver is using the old state,
+ *   and it will never know about the new state because it subsequently
+ *   acknowledges the state change interrupt.
+ *
+ *          INCORRECT                                      CORRECT
+ *      read type 0 int reasons                   read type 0 int reasons
+ *      read adapter state                        ack type 0 interrupts
+ *      ack type 0 interrupts                     read adapter state
+ *      ... process interrupt ...                 ... process interrupt ...
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   None
+ *
+ * Side Effects:
+ *   An adapter reset may occur if the adapter has any Type 0 error interrupts
+ *   or if the port status indicates that the adapter is halted.  The driver
+ *   is responsible for reinitializing the adapter with the current CAM
+ *   contents and adapter filter settings.
+ */
+
+void dfx_int_type_0_process(
+	DFX_board_t	*bp
+	)
+
+	{
+	PI_UINT32	type_0_status;		/* Host Interrupt Type 0 register */
+	PI_UINT32	state;				/* current adap state (from port status) */
+
+	/*
+	 * Read host interrupt Type 0 register to determine which Type 0
+	 * interrupts are pending.  Immediately write it back out to clear
+	 * those interrupts.
+	 */
+
+	dfx_port_read_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, &type_0_status);
+	dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, type_0_status);
+
+	/* Check for Type 0 error interrupts */
+
+	if (type_0_status & (PI_TYPE_0_STAT_M_NXM |
+							PI_TYPE_0_STAT_M_PM_PAR_ERR |
+							PI_TYPE_0_STAT_M_BUS_PAR_ERR))
+		{
+		/* Check for Non-Existent Memory error */
+
+		if (type_0_status & PI_TYPE_0_STAT_M_NXM)
+			printk("%s: Non-Existent Memory Access Error\n", bp->dev->name);
+
+		/* Check for Packet Memory Parity error */
+
+		if (type_0_status & PI_TYPE_0_STAT_M_PM_PAR_ERR)
+			printk("%s: Packet Memory Parity Error\n", bp->dev->name);
+
+		/* Check for Host Bus Parity error */
+
+		if (type_0_status & PI_TYPE_0_STAT_M_BUS_PAR_ERR)
+			printk("%s: Host Bus Parity Error\n", bp->dev->name);
+
+		/* Reset adapter and bring it back on-line */
+
+		bp->link_available = PI_K_FALSE;	/* link is no longer available */
+		bp->reset_type = 0;					/* rerun on-board diagnostics */
+		printk("%s: Resetting adapter...\n", bp->dev->name);
+		if (dfx_adap_init(bp) != DFX_K_SUCCESS)
+			{
+			printk("%s: Adapter reset failed!  Disabling adapter interrupts.\n", bp->dev->name);
+			dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
+			return;
+			}
+		printk("%s: Adapter reset successful!\n", bp->dev->name);
+		return;
+		}
+
+	/* Check for transmit flush interrupt */
+
+	if (type_0_status & PI_TYPE_0_STAT_M_XMT_FLUSH)
+		{
+		/* Flush any pending xmt's and acknowledge the flush interrupt */
+
+		bp->link_available = PI_K_FALSE;		/* link is no longer available */
+		dfx_xmt_flush(bp);						/* flush any outstanding packets */
+		(void) dfx_hw_port_ctrl_req(bp,
+									PI_PCTRL_M_XMT_DATA_FLUSH_DONE,
+									0,
+									0,
+									NULL);
+		}
+
+	/* Check for adapter state change */
+
+	if (type_0_status & PI_TYPE_0_STAT_M_STATE_CHANGE)
+		{                     
+		/* Get latest adapter state */
+
+		state = dfx_hw_adap_state_rd(bp);	/* get adapter state */
+		if (state == PI_STATE_K_HALTED)
+			{
+			/*
+			 * Adapter has transitioned to HALTED state, try to reset
+			 * adapter to bring it back on-line.  If reset fails,
+			 * leave the adapter in the broken state.
+			 */
+
+			printk("%s: Controller has transitioned to HALTED state!\n", bp->dev->name);
+			dfx_int_pr_halt_id(bp);			/* display halt id as string */
+
+			/* Reset adapter and bring it back on-line */
+
+			bp->link_available = PI_K_FALSE;	/* link is no longer available */
+			bp->reset_type = 0;					/* rerun on-board diagnostics */
+			printk("%s: Resetting adapter...\n", bp->dev->name);
+			if (dfx_adap_init(bp) != DFX_K_SUCCESS)
+				{
+				printk("%s: Adapter reset failed!  Disabling adapter interrupts.\n", bp->dev->name);
+				dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
+				return;
+				}
+			printk("%s: Adapter reset successful!\n", bp->dev->name);
+			}
+		else if (state == PI_STATE_K_LINK_AVAIL)
+			{
+			bp->link_available = PI_K_TRUE;		/* set link available flag */
+			}
+		}
+	return;
+	}
+
+
+/*
+ * ==================
+ * = dfx_int_common =
+ * ==================
+ *   
+ * Overview:
+ *   Interrupt service routine (ISR)
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   This is the ISR which processes incoming adapter interrupts.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   This routine assumes PDQ interrupts have not been disabled.
+ *   When interrupts are disabled at the PDQ, the Port Status register
+ *   is automatically cleared.  This routine uses the Port Status
+ *   register value to determine whether a Type 0 interrupt occurred,
+ *   so it's important that adapter interrupts are not normally
+ *   enabled/disabled at the PDQ.
+ *
+ *   It's vital that this routine is NOT reentered for the
+ *   same board and that the OS is not in another section of
+ *   code (eg. dfx_xmt_queue_pkt) for the same board on a
+ *   different thread.
+ *
+ * Side Effects:
+ *   Pending interrupts are serviced.  Depending on the type of
+ *   interrupt, acknowledging and clearing the interrupt at the
+ *   PDQ involves writing a register to clear the interrupt bit
+ *   or updating completion indices.
+ */
+
+void dfx_int_common(
+	DFX_board_t	*bp
+	)
+
+	{
+	PI_UINT32	port_status;		/* Port Status register */
+
+	/* Process xmt interrupts - frequent case, so always call this routine */
+
+	dfx_xmt_done(bp);				/* free consumed xmt packets */
+
+	/* Process rcv interrupts - frequent case, so always call this routine */
+
+	dfx_rcv_queue_process(bp);		/* service received LLC frames */
+
+	/*
+	 * Transmit and receive producer and completion indices are updated on the
+	 * adapter by writing to the Type 2 Producer register.  Since the frequent
+	 * case is that we'll be processing either LLC transmit or receive buffers,
+	 * we'll optimize I/O writes by doing a single register write here.
+	 */
+
+	dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
+
+	/* Read PDQ Port Status register to find out which interrupts need processing */
+
+	dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status);
+
+	/* Process Type 0 interrupts (if any) - infrequent, so only call when needed */
+
+	if (port_status & PI_PSTATUS_M_TYPE_0_PENDING)
+		dfx_int_type_0_process(bp);	/* process Type 0 interrupts */
+	return;
+	}
+
+
+/*
+ * =================
+ * = dfx_interrupt =
+ * =================
+ *   
+ * Overview:
+ *   Interrupt processing routine
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   irq	- interrupt vector
+ *   dev_id	- pointer to device information
+ *	 regs	- pointer to registers structure
+ *
+ * Functional Description:
+ *   This routine calls the interrupt processing routine for this adapter.  It
+ *   disables and reenables adapter interrupts, as appropriate.  We can support
+ *   shared interrupts since the incoming dev_id pointer provides our device
+ *   structure context.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   The interrupt acknowledgement at the hardware level (eg. ACKing the PIC
+ *   on Intel-based systems) is done by the operating system outside this
+ *   routine.
+ *
+ *	 System interrupts are enabled through this call.
+ *
+ * Side Effects:
+ *   Interrupts are disabled, then reenabled at the adapter.
+ */
+
+void dfx_interrupt(
+	int				irq,
+	void			*dev_id,
+	struct pt_regs	*regs
+	)
+
+	{
+	struct device	*dev = (struct device *) dev_id;
+	DFX_board_t		*bp;	/* private board structure pointer */
+	u8				tmp;	/* used for disabling/enabling ints */
+
+	/* Get board pointer only if device structure is valid */
+
+	if (dev == NULL)
+		{
+		printk("dfx_interrupt(): irq %d for unknown device!\n", irq);
+		return;
+		}
+	bp = (DFX_board_t *) dev->priv;
+
+	/* See if we're already servicing an interrupt */
+
+	if (dev->interrupt)
+		printk("%s: Re-entering the interrupt handler!\n", dev->name);
+	dev->interrupt = DFX_MASK_INTERRUPTS;	/* ensure non reentrancy */
+
+	/* Service adapter interrupts */
+
+	if (bp->bus_type == DFX_BUS_TYPE_PCI)
+		{
+		/* Disable PDQ-PFI interrupts at PFI */
+
+		dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, PFI_MODE_M_DMA_ENB);
+
+		/* Call interrupt service routine for this adapter */
+
+		dfx_int_common(bp);
+
+		/* Clear PDQ interrupt status bit and reenable interrupts */
+
+		dfx_port_write_long(bp, PFI_K_REG_STATUS, PFI_STATUS_M_PDQ_INT);
+		dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL,
+					(PFI_MODE_M_PDQ_INT_ENB + PFI_MODE_M_DMA_ENB));
+		}
+	else
+		{
+		/* Disable interrupts at the ESIC */
+
+		dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp);
+		tmp &= ~PI_CONFIG_STAT_0_M_INT_ENB;
+		dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
+
+		/* Call interrupt service routine for this adapter */
+
+		dfx_int_common(bp);
+
+		/* Reenable interrupts at the ESIC */
+
+		dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp);
+		tmp |= PI_CONFIG_STAT_0_M_INT_ENB;
+		dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
+		}
+
+	dev->interrupt = DFX_UNMASK_INTERRUPTS;
+	return;
+	}
+
+
+/*
+ * =====================
+ * = dfx_ctl_get_stats =
+ * =====================
+ *   
+ * Overview:
+ *   Get statistics for FDDI adapter
+ *  
+ * Returns:
+ *   Pointer to FDDI statistics structure
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   Gets current MIB objects from adapter, then
+ *   returns FDDI statistics structure as defined
+ *   in if_fddi.h.
+ *
+ *   Note: Since the FDDI statistics structure is
+ *   still new and the device structure doesn't
+ *   have an FDDI-specific get statistics handler,
+ *   we'll return the FDDI statistics structure as
+ *   a pointer to an Ethernet statistics structure.
+ *   That way, at least the first part of the statistics
+ *   structure can be decoded properly, and it allows
+ *   "smart" applications to perform a second cast to
+ *   decode the FDDI-specific statistics.
+ *
+ *   We'll have to pay attention to this routine as the
+ *   device structure becomes more mature and LAN media
+ *   independent.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   None
+ *
+ * Side Effects:
+ *   None
+ */
+
+struct enet_statistics *dfx_ctl_get_stats(
+	struct device *dev
+	)
+
+	{
+	DFX_board_t	*bp = (DFX_board_t *)dev->priv;
+
+	/* Fill the bp->stats structure with driver-maintained counters */
+
+	bp->stats.rx_packets			= bp->rcv_total_frames;
+	bp->stats.tx_packets			= bp->xmt_total_frames;
+	bp->stats.rx_errors				= (u32)(bp->rcv_crc_errors + bp->rcv_frame_status_errors + bp->rcv_length_errors);
+	bp->stats.tx_errors				= bp->xmt_length_errors;
+	bp->stats.rx_dropped			= bp->rcv_discards;
+	bp->stats.tx_dropped			= bp->xmt_discards;
+	bp->stats.multicast				= bp->rcv_multicast_frames;
+	bp->stats.transmit_collision	= 0;	/* always zero (0) for FDDI */
+
+	/* Get FDDI SMT MIB objects */
+
+	bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET;
+	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
+		return((struct enet_statistics *) &bp->stats);
+
+	/* Fill the bp->stats structure with the SMT MIB object values */
+
+	memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id));
+	bp->stats.smt_op_version_id					= bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id;
+	bp->stats.smt_hi_version_id					= bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id;
+	bp->stats.smt_lo_version_id					= bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id;
+	memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data));
+	bp->stats.smt_mib_version_id				= bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id;
+	bp->stats.smt_mac_cts						= bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct;
+	bp->stats.smt_non_master_cts				= bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct;
+	bp->stats.smt_master_cts					= bp->cmd_rsp_virt->smt_mib_get.smt_master_ct;
+	bp->stats.smt_available_paths				= bp->cmd_rsp_virt->smt_mib_get.smt_available_paths;
+	bp->stats.smt_config_capabilities			= bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities;
+	bp->stats.smt_config_policy					= bp->cmd_rsp_virt->smt_mib_get.smt_config_policy;
+	bp->stats.smt_connection_policy				= bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy;
+	bp->stats.smt_t_notify						= bp->cmd_rsp_virt->smt_mib_get.smt_t_notify;
+	bp->stats.smt_stat_rpt_policy				= bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy;
+	bp->stats.smt_trace_max_expiration			= bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration;
+	bp->stats.smt_bypass_present				= bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present;
+	bp->stats.smt_ecm_state						= bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state;
+	bp->stats.smt_cf_state						= bp->cmd_rsp_virt->smt_mib_get.smt_cf_state;
+	bp->stats.smt_remote_disconnect_flag		= bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag;
+	bp->stats.smt_station_status				= bp->cmd_rsp_virt->smt_mib_get.smt_station_status;
+	bp->stats.smt_peer_wrap_flag				= bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag;
+	bp->stats.smt_time_stamp					= bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls;
+	bp->stats.smt_transition_time_stamp			= bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls;
+	bp->stats.mac_frame_status_functions		= bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions;
+	bp->stats.mac_t_max_capability				= bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability;
+	bp->stats.mac_tvx_capability				= bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability;
+	bp->stats.mac_available_paths				= bp->cmd_rsp_virt->smt_mib_get.mac_available_paths;
+	bp->stats.mac_current_path					= bp->cmd_rsp_virt->smt_mib_get.mac_current_path;
+	memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN);
+	memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN);
+	memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN);
+	memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN);
+	bp->stats.mac_dup_address_test				= bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test;
+	bp->stats.mac_requested_paths				= bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths;
+	bp->stats.mac_downstream_port_type			= bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type;
+	memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN);
+	bp->stats.mac_t_req							= bp->cmd_rsp_virt->smt_mib_get.mac_t_req;
+	bp->stats.mac_t_neg							= bp->cmd_rsp_virt->smt_mib_get.mac_t_neg;
+	bp->stats.mac_t_max							= bp->cmd_rsp_virt->smt_mib_get.mac_t_max;
+	bp->stats.mac_tvx_value						= bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value;
+	bp->stats.mac_frame_error_threshold			= bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold;
+	bp->stats.mac_frame_error_ratio				= bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio;
+	bp->stats.mac_rmt_state						= bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state;
+	bp->stats.mac_da_flag						= bp->cmd_rsp_virt->smt_mib_get.mac_da_flag;
+	bp->stats.mac_una_da_flag					= bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag;
+	bp->stats.mac_frame_error_flag				= bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag;
+	bp->stats.mac_ma_unitdata_available			= bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available;
+	bp->stats.mac_hardware_present				= bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present;
+	bp->stats.mac_ma_unitdata_enable			= bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable;
+	bp->stats.path_tvx_lower_bound				= bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound;
+	bp->stats.path_t_max_lower_bound			= bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound;
+	bp->stats.path_max_t_req					= bp->cmd_rsp_virt->smt_mib_get.path_max_t_req;
+	memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration));
+	bp->stats.port_my_type[0]					= bp->cmd_rsp_virt->smt_mib_get.port_my_type[0];
+	bp->stats.port_my_type[1]					= bp->cmd_rsp_virt->smt_mib_get.port_my_type[1];
+	bp->stats.port_neighbor_type[0]				= bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0];
+	bp->stats.port_neighbor_type[1]				= bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1];
+	bp->stats.port_connection_policies[0]		= bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0];
+	bp->stats.port_connection_policies[1]		= bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1];
+	bp->stats.port_mac_indicated[0]				= bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0];
+	bp->stats.port_mac_indicated[1]				= bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1];
+	bp->stats.port_current_path[0]				= bp->cmd_rsp_virt->smt_mib_get.port_current_path[0];
+	bp->stats.port_current_path[1]				= bp->cmd_rsp_virt->smt_mib_get.port_current_path[1];
+	memcpy(&bp->stats.port_requested_paths[0*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3);
+	memcpy(&bp->stats.port_requested_paths[1*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3);
+	bp->stats.port_mac_placement[0]				= bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0];
+	bp->stats.port_mac_placement[1]				= bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1];
+	bp->stats.port_available_paths[0]			= bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0];
+	bp->stats.port_available_paths[1]			= bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1];
+	bp->stats.port_pmd_class[0]					= bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0];
+	bp->stats.port_pmd_class[1]					= bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1];
+	bp->stats.port_connection_capabilities[0]	= bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0];
+	bp->stats.port_connection_capabilities[1]	= bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1];
+	bp->stats.port_bs_flag[0]					= bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0];
+	bp->stats.port_bs_flag[1]					= bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1];
+	bp->stats.port_ler_estimate[0]				= bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0];
+	bp->stats.port_ler_estimate[1]				= bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1];
+	bp->stats.port_ler_cutoff[0]				= bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0];
+	bp->stats.port_ler_cutoff[1]				= bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1];
+	bp->stats.port_ler_alarm[0]					= bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0];
+	bp->stats.port_ler_alarm[1]					= bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1];
+	bp->stats.port_connect_state[0]				= bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0];
+	bp->stats.port_connect_state[1]				= bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1];
+	bp->stats.port_pcm_state[0]					= bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0];
+	bp->stats.port_pcm_state[1]					= bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1];
+	bp->stats.port_pc_withhold[0]				= bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0];
+	bp->stats.port_pc_withhold[1]				= bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1];
+	bp->stats.port_ler_flag[0]					= bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0];
+	bp->stats.port_ler_flag[1]					= bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1];
+	bp->stats.port_hardware_present[0]			= bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0];
+	bp->stats.port_hardware_present[1]			= bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1];
+
+	/* Get FDDI counters */
+
+	bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET;
+	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
+		return((struct enet_statistics *) &bp->stats);
+
+	/* Fill the bp->stats structure with the FDDI counter values */
+
+	bp->stats.mac_frame_cts				= bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls;
+	bp->stats.mac_copied_cts			= bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls;
+	bp->stats.mac_transmit_cts			= bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls;
+	bp->stats.mac_error_cts				= bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls;
+	bp->stats.mac_lost_cts				= bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls;
+	bp->stats.port_lct_fail_cts[0]		= bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls;
+	bp->stats.port_lct_fail_cts[1]		= bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls;
+	bp->stats.port_lem_reject_cts[0]	= bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls;
+	bp->stats.port_lem_reject_cts[1]	= bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls;
+	bp->stats.port_lem_cts[0]			= bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls;
+	bp->stats.port_lem_cts[1]			= bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls;
+
+	return((struct enet_statistics *) &bp->stats);
+	}
+
+
+/*
+ * ==============================
+ * = dfx_ctl_set_multicast_list =
+ * ==============================
+ *   
+ * Overview:
+ *   Enable/Disable LLC frame promiscuous mode reception
+ *   on the adapter and/or update multicast address table.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This routine follows a fairly simple algorithm for setting the
+ *   adapter filters and CAM:
+ *
+ *		if IFF_PROMISC flag is set
+ *			enable LLC individual/group promiscuous mode
+ *		else
+ *			disable LLC individual/group promiscuous mode
+ *			if number of incoming multicast addresses >
+ *					(CAM max size - number of unicast addresses in CAM)
+ *				enable LLC group promiscuous mode
+ *				set driver-maintained multicast address count to zero
+ *			else
+ *				disable LLC group promiscuous mode
+ *				set driver-maintained multicast address count to incoming count
+ *			update adapter CAM
+ *		update adapter filters
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   Multicast addresses are presented in canonical (LSB) format.
+ *
+ * Side Effects:
+ *   On-board adapter CAM and filters are updated.
+ */
+
+void dfx_ctl_set_multicast_list(
+	struct device *dev
+	)
+
+	{
+	DFX_board_t			*bp = (DFX_board_t *)dev->priv;
+	int					i;			/* used as index in for loop */
+	struct dev_mc_list	*dmi;		/* ptr to multicast addr entry */
+
+	/* Enable LLC frame promiscuous mode, if necessary */
+
+	if (dev->flags & IFF_PROMISC)
+		bp->ind_group_prom = PI_FSTATE_K_PASS;		/* Enable LLC ind/group prom mode */
+
+	/* Else, update multicast address table */
+
+	else
+		{
+		bp->ind_group_prom = PI_FSTATE_K_BLOCK;		/* Disable LLC ind/group prom mode */
+		/*
+		 * Check whether incoming multicast address count exceeds table size
+		 *
+		 * Note: The adapters utilize an on-board 64 entry CAM for
+		 *       supporting perfect filtering of multicast packets
+		 *		 and bridge functions when adding unicast addresses.
+		 *		 There is no hash function available.  To support
+		 *		 additional multicast addresses, the all multicast
+		 *		 filter (LLC group promiscuous mode) must be enabled.
+		 *
+		 *		 The firmware reserves two CAM entries for SMT-related
+		 *		 multicast addresses, which leaves 62 entries available.
+		 *		 The following code ensures that we're not being asked
+		 *		 to add more than 62 addresses to the CAM.  If we are,
+		 *		 the driver will enable the all multicast filter.
+		 *		 Should the number of multicast addresses drop below
+		 *		 the high water mark, the filter will be disabled and
+		 *		 perfect filtering will be used.
+		 */
+
+		if (dev->mc_count > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count))
+			{
+			bp->group_prom	= PI_FSTATE_K_PASS;		/* Enable LLC group prom mode */
+			bp->mc_count	= 0;					/* Don't add mc addrs to CAM */
+			}
+		else
+			{
+			bp->group_prom	= PI_FSTATE_K_BLOCK;	/* Disable LLC group prom mode */
+			bp->mc_count	= dev->mc_count;		/* Add mc addrs to CAM */
+			}
+
+		/* Copy addresses to multicast address table, then update adapter CAM */
+
+		dmi = dev->mc_list;				/* point to first multicast addr */
+		for (i=0; i < bp->mc_count; i++)
+			{
+			memcpy(&bp->mc_table[i*FDDI_K_ALEN], dmi->dmi_addr, FDDI_K_ALEN);
+			dmi = dmi->next;			/* point to next multicast addr */
+			}
+		if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS)
+			{
+			DBG_printk("%s: Could not update multicast address table!\n", dev->name);
+			}
+		else
+			{
+			DBG_printk("%s: Multicast address table updated!  Added %d addresses.\n", dev->name, bp->mc_count);
+			}
+		}
+
+	/* Update adapter filters */
+
+	if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS)
+		{
+		DBG_printk("%s: Could not update adapter filters!\n", dev->name);
+		}
+	else
+		{
+		DBG_printk("%s: Adapter filters updated!\n", dev->name);
+		}
+	return;
+	}
+
+
+/*
+ * ===========================
+ * = dfx_ctl_set_mac_address =
+ * ===========================
+ *   
+ * Overview:
+ *   Add node address override (unicast address) to adapter
+ *   CAM and update dev_addr field in device table.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   dev  - pointer to device information
+ *   addr - pointer to sockaddr structure containing unicast address to add
+ *
+ * Functional Description:
+ *   The adapter supports node address overrides by adding one or more
+ *   unicast addresses to the adapter CAM.  This is similar to adding
+ *   multicast addresses.  In this routine we'll update the driver and
+ *   device structures with the new address, then update the adapter CAM
+ *   to ensure that the adapter will copy and strip frames destined and
+ *   sourced by that address.
+ *
+ * Return Codes:
+ *   Always returns zero.
+ *
+ * Assumptions:
+ *   The address pointed to by addr->sa_data is a valid unicast
+ *   address and is presented in canonical (LSB) format.
+ *
+ * Side Effects:
+ *   On-board adapter CAM is updated.  On-board adapter filters
+ *   may be updated.
+ */
+
+int dfx_ctl_set_mac_address(
+	struct device	*dev,
+	void			*addr
+	)
+
+	{
+	DFX_board_t		*bp = (DFX_board_t *)dev->priv;
+	struct sockaddr	*p_sockaddr = (struct sockaddr *)addr;
+
+	/* Copy unicast address to driver-maintained structs and update count */
+
+	memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN);	/* update device struct */
+	memcpy(&bp->uc_table[0], p_sockaddr->sa_data, FDDI_K_ALEN);	/* update driver struct */
+	bp->uc_count = 1;
+
+	/*
+	 * Verify we're not exceeding the CAM size by adding unicast address
+	 *
+	 * Note: It's possible that before entering this routine we've
+	 *       already filled the CAM with 62 multicast addresses.
+	 *		 Since we need to place the node address override into
+	 *		 the CAM, we have to check to see that we're not
+	 *		 exceeding the CAM size.  If we are, we have to enable
+	 *		 the LLC group (multicast) promiscuous mode filter as
+	 *		 in dfx_ctl_set_multicast_list.
+	 */
+
+	if ((bp->uc_count + bp->mc_count) > PI_CMD_ADDR_FILTER_K_SIZE)
+		{
+		bp->group_prom	= PI_FSTATE_K_PASS;		/* Enable LLC group prom mode */
+		bp->mc_count	= 0;					/* Don't add mc addrs to CAM */
+
+		/* Update adapter filters */
+
+		if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS)
+			{
+			DBG_printk("%s: Could not update adapter filters!\n", dev->name);
+			}
+		else
+			{
+			DBG_printk("%s: Adapter filters updated!\n", dev->name);
+			}
+		}
+
+	/* Update adapter CAM with new unicast address */
+
+	if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS)
+		{
+		DBG_printk("%s: Could not set new MAC address!\n", dev->name);
+		}
+	else
+		{
+		DBG_printk("%s: Adapter CAM updated with new MAC address\n", dev->name);
+		}
+	return(0);			/* always return zero */
+	}
+
+
+/*
+ * ======================
+ * = dfx_ctl_update_cam =
+ * ======================
+ *
+ * Overview:
+ *   Procedure to update adapter CAM (Content Addressable Memory)
+ *   with desired unicast and multicast address entries.
+ *
+ * Returns:
+ *   Condition code
+ *
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   Updates adapter CAM with current contents of board structure
+ *   unicast and multicast address tables.  Since there are only 62
+ *   free entries in CAM, this routine ensures that the command
+ *   request buffer is not overrun.
+ *
+ * Return Codes:
+ *   DFX_K_SUCCESS - Request succeeded
+ *   DFX_K_FAILURE - Request failed
+ *
+ * Assumptions:
+ *   All addresses being added (unicast and multicast) are in canonical
+ *   order.
+ *
+ * Side Effects:
+ *   On-board adapter CAM is updated.
+ */
+
+int dfx_ctl_update_cam(
+	DFX_board_t *bp
+	)
+
+	{
+	int			i;				/* used as index */
+	PI_LAN_ADDR	*p_addr;		/* pointer to CAM entry */
+
+	/*
+	 * Fill in command request information
+	 *
+	 * Note: Even though both the unicast and multicast address
+	 *       table entries are stored as contiguous 6 byte entries,
+	 *		 the firmware address filter set command expects each
+	 *		 entry to be two longwords (8 bytes total).  We must be
+	 *		 careful to only copy the six bytes of each unicast and
+	 *		 multicast table entry into each command entry.  This
+	 *		 is also why we must first clear the entire command
+	 *		 request buffer.
+	 */
+
+	memset(bp->cmd_req_virt, 0, PI_CMD_REQ_K_SIZE_MAX);	/* first clear buffer */
+	bp->cmd_req_virt->cmd_type = PI_CMD_K_ADDR_FILTER_SET;
+	p_addr = &bp->cmd_req_virt->addr_filter_set.entry[0];
+
+	/* Now add unicast addresses to command request buffer, if any */
+
+	for (i=0; i < (int)bp->uc_count; i++)
+		{
+		if (i < PI_CMD_ADDR_FILTER_K_SIZE)
+			{
+			memcpy(p_addr, &bp->uc_table[i*FDDI_K_ALEN], FDDI_K_ALEN);
+			p_addr++;			/* point to next command entry */
+			}
+		}
+
+	/* Now add multicast addresses to command request buffer, if any */
+
+	for (i=0; i < (int)bp->mc_count; i++)
+		{
+		if ((i + bp->uc_count) < PI_CMD_ADDR_FILTER_K_SIZE)
+			{
+			memcpy(p_addr, &bp->mc_table[i*FDDI_K_ALEN], FDDI_K_ALEN);
+			p_addr++;			/* point to next command entry */
+			}
+		}
+
+	/* Issue command to update adapter CAM, then return */
+
+	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
+		return(DFX_K_FAILURE);
+	return(DFX_K_SUCCESS);
+	}
+
+
+/*
+ * ==========================
+ * = dfx_ctl_update_filters =
+ * ==========================
+ *
+ * Overview:
+ *   Procedure to update adapter filters with desired
+ *   filter settings.
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   Enables or disables filter using current filter settings.
+ *
+ * Return Codes:
+ *   DFX_K_SUCCESS - Request succeeded.
+ *   DFX_K_FAILURE - Request failed.
+ *
+ * Assumptions:
+ *   We must always pass up packets destined to the broadcast
+ *   address (FF-FF-FF-FF-FF-FF), so we'll always keep the
+ *   broadcast filter enabled.
+ *
+ * Side Effects:
+ *   On-board adapter filters are updated.
+ */
+
+int dfx_ctl_update_filters(
+	DFX_board_t *bp
+	)
+
+	{
+	int	i = 0;					/* used as index */
+
+	/* Fill in command request information */
+
+	bp->cmd_req_virt->cmd_type = PI_CMD_K_FILTERS_SET;
+
+	/* Initialize Broadcast filter - * ALWAYS ENABLED * */
+
+	bp->cmd_req_virt->filter_set.item[i].item_code	= PI_ITEM_K_BROADCAST;
+	bp->cmd_req_virt->filter_set.item[i++].value	= PI_FSTATE_K_PASS;
+
+	/* Initialize LLC Individual/Group Promiscuous filter */
+
+	bp->cmd_req_virt->filter_set.item[i].item_code	= PI_ITEM_K_IND_GROUP_PROM;
+	bp->cmd_req_virt->filter_set.item[i++].value	= bp->ind_group_prom;
+
+	/* Initialize LLC Group Promiscuous filter */
+
+	bp->cmd_req_virt->filter_set.item[i].item_code	= PI_ITEM_K_GROUP_PROM;
+	bp->cmd_req_virt->filter_set.item[i++].value	= bp->group_prom;
+
+	/* Terminate the item code list */
+
+	bp->cmd_req_virt->filter_set.item[i].item_code	= PI_ITEM_K_EOL;
+
+	/* Issue command to update adapter filters, then return */
+
+	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
+		return(DFX_K_FAILURE);
+	return(DFX_K_SUCCESS);
+	}
+
+
+/*
+ * ======================
+ * = dfx_hw_dma_cmd_req =
+ * ======================
+ *   
+ * Overview:
+ *   Sends PDQ DMA command to adapter firmware
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   The command request and response buffers are posted to the adapter in the manner
+ *   described in the PDQ Port Specification:
+ *
+ *		1. Command Response Buffer is posted to adapter.
+ *		2. Command Request Buffer is posted to adapter.
+ *		3. Command Request consumer index is polled until it indicates that request
+ *         buffer has been DMA'd to adapter.
+ *		4. Command Response consumer index is polled until it indicates that response
+ *         buffer has been DMA'd from adapter.
+ *
+ *   This ordering ensures that a response buffer is already available for the firmware
+ *   to use once it's done processing the request buffer.
+ *
+ * Return Codes:
+ *   DFX_K_SUCCESS	  - DMA command succeeded
+ * 	 DFX_K_OUTSTATE   - Adapter is NOT in proper state
+ *   DFX_K_HW_TIMEOUT - DMA command timed out
+ *
+ * Assumptions:
+ *   Command request buffer has already been filled with desired DMA command.
+ *
+ * Side Effects:
+ *   None
+ */
+
+int dfx_hw_dma_cmd_req(
+	DFX_board_t *bp
+	)
+
+	{
+	int status;			/* adapter status */
+	int timeout_cnt;	/* used in for loops */
+	
+	/* Make sure the adapter is in a state that we can issue the DMA command in */
+	
+	status = dfx_hw_adap_state_rd(bp);
+	if ((status == PI_STATE_K_RESET)		||
+		(status == PI_STATE_K_HALTED)		||
+		(status == PI_STATE_K_DMA_UNAVAIL)	||
+		(status == PI_STATE_K_UPGRADE))
+		return(DFX_K_OUTSTATE);
+
+	/* Put response buffer on the command response queue */
+
+	bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
+			((PI_CMD_RSP_K_SIZE_MAX / PI_ALIGN_K_CMD_RSP_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
+	bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_1 = bp->cmd_rsp_phys;
+
+	/* Bump (and wrap) the producer index and write out to register */
+
+	bp->cmd_rsp_reg.index.prod += 1;
+	bp->cmd_rsp_reg.index.prod &= PI_CMD_RSP_K_NUM_ENTRIES-1;
+	dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword);
+
+	/* Put request buffer on the command request queue */
+	
+	bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_0 = (u32) (PI_XMT_DESCR_M_SOP |
+			PI_XMT_DESCR_M_EOP | (PI_CMD_REQ_K_SIZE_MAX << PI_XMT_DESCR_V_SEG_LEN));
+	bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_1 = bp->cmd_req_phys;
+
+	/* Bump (and wrap) the producer index and write out to register */
+
+	bp->cmd_req_reg.index.prod += 1;
+	bp->cmd_req_reg.index.prod &= PI_CMD_REQ_K_NUM_ENTRIES-1;
+	dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword);
+
+	/*
+	 * Here we wait for the command request consumer index to be equal
+	 * to the producer, indicating that the adapter has DMAed the request.
+	 */
+
+	for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--)
+		{
+		if (bp->cmd_req_reg.index.prod == (u8)(bp->cons_block_virt->cmd_req))
+			break;
+		udelay(100);			/* wait for 100 microseconds */
+		}
+	if (timeout_cnt == 0) 
+		return(DFX_K_HW_TIMEOUT);
+
+	/* Bump (and wrap) the completion index and write out to register */
+
+	bp->cmd_req_reg.index.comp += 1;
+	bp->cmd_req_reg.index.comp &= PI_CMD_REQ_K_NUM_ENTRIES-1;
+	dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword);
+
+	/*
+	 * Here we wait for the command response consumer index to be equal
+	 * to the producer, indicating that the adapter has DMAed the response.
+	 */
+
+	for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--)
+		{
+		if (bp->cmd_rsp_reg.index.prod == (u8)(bp->cons_block_virt->cmd_rsp))
+			break;
+		udelay(100);			/* wait for 100 microseconds */
+		}
+	if (timeout_cnt == 0) 
+		return(DFX_K_HW_TIMEOUT);
+
+	/* Bump (and wrap) the completion index and write out to register */
+
+	bp->cmd_rsp_reg.index.comp += 1;
+	bp->cmd_rsp_reg.index.comp &= PI_CMD_RSP_K_NUM_ENTRIES-1;
+	dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword);
+	return(DFX_K_SUCCESS);
+	}
+
+
+/*
+ * ========================
+ * = dfx_hw_port_ctrl_req =
+ * ========================
+ *   
+ * Overview:
+ *   Sends PDQ port control command to adapter firmware
+ *  
+ * Returns:
+ *   Host data register value in host_data if ptr is not NULL
+ *       
+ * Arguments:
+ *   bp			- pointer to board information
+ *	 command	- port control command
+ *	 data_a		- port data A register value
+ *	 data_b		- port data B register value
+ *	 host_data	- ptr to host data register value
+ *
+ * Functional Description:
+ *   Send generic port control command to adapter by writing
+ *   to various PDQ port registers, then polling for completion.
+ *
+ * Return Codes:
+ *   DFX_K_SUCCESS	  - port control command succeeded
+ *   DFX_K_HW_TIMEOUT - port control command timed out
+ *
+ * Assumptions:
+ *   None
+ *
+ * Side Effects:
+ *   None
+ */
+
+int dfx_hw_port_ctrl_req(
+	DFX_board_t	*bp,
+	PI_UINT32	command,
+	PI_UINT32	data_a,
+	PI_UINT32	data_b,
+	PI_UINT32	*host_data
+	)
+
+	{
+	PI_UINT32	port_cmd;		/* Port Control command register value */
+	int			timeout_cnt;	/* used in for loops */
+
+	/* Set Command Error bit in command longword */
+	
+	port_cmd = (PI_UINT32) (command | PI_PCTRL_M_CMD_ERROR);
+
+	/* Issue port command to the adapter */
+
+	dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, data_a);
+	dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_B, data_b);
+	dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_CTRL, port_cmd);
+
+	/* Now wait for command to complete */
+
+	if (command == PI_PCTRL_M_BLAST_FLASH)
+		timeout_cnt = 600000;	/* set command timeout count to 60 seconds */
+	else
+		timeout_cnt = 20000;	/* set command timeout count to 2 seconds */
+
+	for (; timeout_cnt > 0; timeout_cnt--)
+		{
+		dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_CTRL, &port_cmd);
+		if (!(port_cmd & PI_PCTRL_M_CMD_ERROR))
+			break;
+		udelay(100);			/* wait for 100 microseconds */
+		}
+	if (timeout_cnt == 0) 
+		return(DFX_K_HW_TIMEOUT);
+
+	/*
+	 * If the address of host_data is non-zero, assume caller has supplied a  
+	 * non NULL pointer, and return the contents of the HOST_DATA register in 
+	 * it.
+	 */
+
+	if (host_data != NULL)
+		dfx_port_read_long(bp, PI_PDQ_K_REG_HOST_DATA, host_data);
+	return(DFX_K_SUCCESS);
+	}
+
+
+/*
+ * =====================
+ * = dfx_hw_adap_reset =
+ * =====================
+ *   
+ * Overview:
+ *   Resets adapter
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp   - pointer to board information
+ *   type - type of reset to perform
+ *
+ * Functional Description:
+ *   Issue soft reset to adapter by writing to PDQ Port Reset
+ *   register.  Use incoming reset type to tell adapter what
+ *   kind of reset operation to perform.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   This routine merely issues a soft reset to the adapter.
+ *   It is expected that after this routine returns, the caller
+ *   will appropriately poll the Port Status register for the
+ *   adapter to enter the proper state.
+ *
+ * Side Effects:
+ *   Internal adapter registers are cleared.
+ */
+
+void dfx_hw_adap_reset(
+	DFX_board_t	*bp,
+	PI_UINT32	type
+	)
+
+	{
+	/* Set Reset type and assert reset */
+
+	dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, type);	/* tell adapter type of reset */
+	dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, PI_RESET_M_ASSERT_RESET);
+
+	/* Wait for at least 1 Microsecond according to the spec. We wait 20 just to be safe */
+
+	udelay(20);
+
+	/* Deassert reset */
+
+	dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0);
+	return;
+	}
+
+
+/*
+ * ========================
+ * = dfx_hw_adap_state_rd =
+ * ========================
+ *   
+ * Overview:
+ *   Returns current adapter state
+ *  
+ * Returns:
+ *   Adapter state per PDQ Port Specification
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   Reads PDQ Port Status register and returns adapter state.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   None
+ *
+ * Side Effects:
+ *   None
+ */
+
+int dfx_hw_adap_state_rd(
+	DFX_board_t *bp
+	)
+
+	{
+	PI_UINT32 port_status;		/* Port Status register value */
+
+	dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status);
+	return((port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE);
+	}
+
+
+/*
+ * =====================
+ * = dfx_hw_dma_uninit =
+ * =====================
+ *   
+ * Overview:
+ *   Brings adapter to DMA_UNAVAILABLE state
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   bp   - pointer to board information
+ *   type - type of reset to perform
+ *
+ * Functional Description:
+ *   Bring adapter to DMA_UNAVAILABLE state by performing the following:
+ *		1. Set reset type bit in Port Data A Register then reset adapter.
+ *		2. Check that adapter is in DMA_UNAVAILABLE state.
+ *
+ * Return Codes:
+ *   DFX_K_SUCCESS	  - adapter is in DMA_UNAVAILABLE state
+ *   DFX_K_HW_TIMEOUT - adapter did not reset properly
+ *
+ * Assumptions:
+ *   None
+ *
+ * Side Effects:
+ *   Internal adapter registers are cleared.
+ */
+
+int dfx_hw_dma_uninit(
+	DFX_board_t	*bp,
+	PI_UINT32	type
+	)
+
+	{
+	int timeout_cnt;	/* used in for loops */
+
+	/* Set reset type bit and reset adapter */
+
+	dfx_hw_adap_reset(bp, type);
+
+	/* Now wait for adapter to enter DMA_UNAVAILABLE state */
+
+	for (timeout_cnt = 100000; timeout_cnt > 0; timeout_cnt--)
+		{
+		if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_DMA_UNAVAIL)
+			break;
+		udelay(100);					/* wait for 100 microseconds */
+		}
+	if (timeout_cnt == 0) 
+		return(DFX_K_HW_TIMEOUT);
+	return(DFX_K_SUCCESS);
+	}
+
+
+/*
+ * ================
+ * = dfx_rcv_init =
+ * ================
+ *   
+ * Overview:
+ *   Produces buffers to adapter LLC Host receive descriptor block
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   This routine can be called during dfx_adap_init() or during an adapter
+ *	 reset.  It initializes the descriptor block and produces all allocated
+ *   LLC Host queue receive buffers.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   The PDQ has been reset and the adapter and driver maintained Type 2
+ *   register indices are cleared.
+ *
+ * Side Effects:
+ *   Receive buffers are posted to the adapter LLC queue and the adapter
+ *   is notified.
+ */
+
+void dfx_rcv_init(
+	DFX_board_t *bp
+	)
+
+	{
+	int	i, j;					/* used in for loop */
+
+	/*
+	 *  Since each receive buffer is a single fragment of same length, initialize
+	 *  first longword in each receive descriptor for entire LLC Host descriptor
+	 *  block.  Also initialize second longword in each receive descriptor with
+	 *  physical address of receive buffer.  We'll always allocate receive
+	 *  buffers in powers of 2 so that we can easily fill the 256 entry descriptor
+	 *  block and produce new receive buffers by simply updating the receive
+	 *  producer index.
+	 *
+	 * 	Assumptions:
+	 *		To support all shipping versions of PDQ, the receive buffer size
+	 *		must be mod 128 in length and the physical address must be 128 byte
+	 *		aligned.  In other words, bits 0-6 of the length and address must
+	 *		be zero for the following descriptor field entries to be correct on
+	 *		all PDQ-based boards.  We guaranteed both requirements during
+	 *		driver initialization when we allocated memory for the receive buffers.
+	 */
+
+	for (i=0; i < (int)(bp->rcv_bufs_to_post); i++)
+		for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
+			{
+			bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
+				((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
+			bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX));
+			bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX));
+			}
+
+	/* Update receive producer and Type 2 register */
+
+	bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post;
+	dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
+	return;
+	}
+
+
+/*
+ * =========================
+ * = dfx_rcv_queue_process =
+ * =========================
+ *   
+ * Overview:
+ *   Process received LLC frames.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   Received LLC frames are processed until there are no more consumed frames.
+ *   Once all frames are processed, the receive buffers are returned to the
+ *   adapter.  Note that this algorithm fixes the length of time that can be spent
+ *   in this routine, because there are a fixed number of receive buffers to
+ *   process and buffers are not produced until this routine exits and returns
+ *   to the ISR.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   None
+ *
+ * Side Effects:
+ *   None
+ */
+
+void dfx_rcv_queue_process(
+	DFX_board_t *bp
+	)
+
+	{
+	PI_TYPE_2_CONSUMER	*p_type_2_cons;		/* ptr to rcv/xmt consumer block register */
+	char				*p_buff;			/* ptr to start of packet receive buffer (FMC descriptor) */
+	u32					descr, pkt_len;		/* FMC descriptor field and packet length */
+	struct sk_buff		*skb;				/* pointer to a sk_buff to hold incoming packet data */
+
+	/* Service all consumed LLC receive frames */
+
+	p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data);
+	while (bp->rcv_xmt_reg.index.rcv_comp != p_type_2_cons->index.rcv_cons)
+		{
+		/* Process any errors */
+
+		p_buff = (char *) bp->p_rcv_buff_va[bp->rcv_xmt_reg.index.rcv_comp];
+		memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32));
+
+		if (descr & PI_FMC_DESCR_M_RCC_FLUSH)
+			{
+			if (descr & PI_FMC_DESCR_M_RCC_CRC)
+				bp->rcv_crc_errors++;
+			else
+				bp->rcv_frame_status_errors++;
+			}
+		else
+			{
+			/* The frame was received without errors - verify packet length */
+
+			pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN);
+			pkt_len -= 4;				/* subtract 4 byte CRC */
+			if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN))
+				bp->rcv_length_errors++;
+			else
+				{
+				skb = dev_alloc_skb(pkt_len+3);	/* alloc new buffer to pass up, add room for PRH */
+				if (skb == NULL)
+					{
+					printk("%s: Could not allocate receive buffer.  Dropping packet.\n", bp->dev->name);
+					bp->rcv_discards++;
+					}
+				else
+					{
+					/* Receive buffer allocated, pass receive packet up */
+
+					memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+					skb->data += 3;			/* adjust data field so that it points to FC byte */
+					skb->len = pkt_len;		/* pass up packet length, NOT including CRC */
+					skb->dev = bp->dev;		/* pass up device pointer */
+					skb->protocol = fddi_type_trans(skb, bp->dev);
+					netif_rx(skb);
+
+					/* Update the rcv counters */
+
+					bp->rcv_total_frames++;
+					if (*(p_buff + RCV_BUFF_K_DA) & 0x01)
+						bp->rcv_multicast_frames++;
+					}
+				}
+			}
+
+		/*
+		 * Advance the producer (for recycling) and advance the completion
+		 * (for servicing received frames).  Note that it is okay to
+		 * advance the producer without checking that it passes the
+		 * completion index because they are both advanced at the same
+		 * rate.
+		 */
+
+		bp->rcv_xmt_reg.index.rcv_prod += 1;
+		bp->rcv_xmt_reg.index.rcv_comp += 1;
+		}
+	return;
+	}
+
+
+/*
+ * =====================
+ * = dfx_xmt_queue_pkt =
+ * =====================
+ *   
+ * Overview:
+ *   Queues packets for transmission
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   skb - pointer to sk_buff to queue for transmission
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   Here we assume that an incoming skb transmit request
+ *   is contained in a single physically contiguous buffer
+ *   in which the virtual address of the start of packet
+ *   (skb->data) can be converted to a physical address
+ *   by using virt_to_bus().
+ *
+ *   Since the adapter architecture requires a three byte
+ *   packet request header to prepend the start of packet,
+ *   we'll write the three byte field immediately prior to
+ *   the FC byte.  This assumption is valid because we've
+ *   ensured that dev->hard_header_len includes three pad
+ *   bytes.  By posting a single fragment to the adapter,
+ *   we'll reduce the number of descriptor fetches and
+ *   bus traffic needed to send the request.
+ *
+ *   Also, we can't free the skb until after it's been DMA'd
+ *   out by the adapter, so we'll queue it in the driver and
+ *   return it in dfx_xmt_done.
+ *
+ * Return Codes:
+ *   0 - driver queued packet, link is unavailable, or skbuff was bad
+ *	 1 - caller should requeue the sk_buff for later transmission
+ *
+ * Assumptions:
+ *	 First and foremost, we assume the incoming skb pointer
+ *   is NOT NULL and is pointing to a valid sk_buff structure.
+ *
+ *   The outgoing packet is complete, starting with the
+ *   frame control byte including the last byte of data,
+ *   but NOT including the 4 byte CRC.  We'll let the
+ *   adapter hardware generate and append the CRC.
+ *
+ *   The entire packet is stored in one physically
+ *   contiguous buffer which is not cached and whose
+ *   32-bit physical address can be determined.
+ *
+ *   It's vital that this routine is NOT reentered for the
+ *   same board and that the OS is not in another section of
+ *   code (eg. dfx_int_common) for the same board on a
+ *   different thread.
+ *
+ * Side Effects:
+ *   None
+ */
+
+int dfx_xmt_queue_pkt(
+	struct sk_buff	*skb,
+	struct device	*dev
+	)
+
+	{
+	DFX_board_t			*bp = (DFX_board_t *) dev->priv;
+	u8					prod;				/* local transmit producer index */
+	PI_XMT_DESCR		*p_xmt_descr;		/* ptr to transmit descriptor block entry */
+	XMT_DRIVER_DESCR	*p_xmt_drv_descr;	/* ptr to transmit driver descriptor */
+
+	/*
+	 * Verify that incoming transmit request is OK
+	 *
+	 * Note: The packet size check is consistent with other
+	 *		 Linux device drivers, although the correct packet
+	 *		 size should be verified before calling the
+	 *		 transmit routine.
+	 */
+
+	if (!IN_RANGE(skb->len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN))
+		{
+		printk("%s: Invalid packet length - %lu bytes\n", dev->name, skb->len);
+		bp->xmt_length_errors++;	/* bump error counter */
+		dev_tint(dev);				/* dequeue packets from xmt queue and send them */
+		return(0);					/* return "success" */
+		}
+
+	/*
+	 * See if adapter link is available, if not, free buffer
+	 *
+	 * Note: If the link isn't available, free buffer and return 0
+	 *		 rather than tell the upper layer to requeue the packet.
+	 *		 The methodology here is that by the time the link
+	 *		 becomes available, the packet to be sent will be
+	 *		 fairly stale.  By simply dropping the packet, the
+	 *		 higher layer protocols will eventually time out
+	 *		 waiting for response packets which it won't receive.
+	 */
+
+	if (bp->link_available == PI_K_FALSE)
+		{
+		if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_LINK_AVAIL)	/* is link really available? */
+			bp->link_available = PI_K_TRUE;		/* if so, set flag and continue */
+		else
+			{
+			bp->xmt_discards++;					/* bump error counter */
+			dev_kfree_skb(skb, FREE_WRITE);		/* free sk_buff now */
+			return(0);							/* return "success" */
+			}
+		}
+
+	/* Get the current producer and the next free xmt data descriptor */
+
+	prod		= bp->rcv_xmt_reg.index.xmt_prod;
+	p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]);
+
+	/*
+	 * Get pointer to auxiliary queue entry to contain information for this packet.
+	 *
+	 * Note: The current xmt producer index will become the current xmt completion
+	 *       index when we complete this packet later on.  So, we'll get the
+	 *       pointer to the next auxiliary queue entry now before we bump the
+	 *		 producer index.
+	 */
+
+	p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]);	/* also bump producer index */
+
+	/* Write the three PRH bytes immediately before the FC byte */
+
+	*((char *)skb->data - 3) = DFX_PRH0_BYTE;	/* these byte values are defined */
+	*((char *)skb->data - 2) = DFX_PRH1_BYTE;	/* in the Motorola FDDI MAC chip */
+	*((char *)skb->data - 1) = DFX_PRH2_BYTE;	/* specification */
+
+	/*
+	 * Write the descriptor with buffer info and bump producer
+	 *
+	 * Note: Since we need to start DMA from the packet request
+	 *		 header, we'll add 3 bytes to the DMA buffer length,
+	 *		 and we'll determine the physical address of the
+	 *		 buffer from the PRH, not skb->data.
+	 *
+	 * Assumptions:
+	 *		 1. Packet starts with the frame control (FC) byte
+	 *		    at skb->data.
+	 *		 2. The 4-byte CRC is not appended to the buffer or
+	 *			included in the length.
+	 *		 3. Packet length (skb->len) is from FC to end of
+	 *			data, inclusive.
+	 *		 4. The packet length does not exceed the maximum
+	 *			FDDI LLC frame length of 4491 bytes.
+	 *		 5. The entire packet is contained in a physically
+	 *			contiguous, non-cached, locked memory space
+	 *			comprised of a single buffer pointed to by
+	 *			skb->data.
+	 *		 6. The physical address of the start of packet
+	 *			can be determined from the virtual address
+	 *			by using virt_to_bus() and is only 32-bits
+	 *			wide.
+	 */
+
+	p_xmt_descr->long_0	= (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len + 3) << PI_XMT_DESCR_V_SEG_LEN));
+	p_xmt_descr->long_1 = (u32) virt_to_bus(skb->data - 3);
+
+	/*
+	 * Verify that descriptor is actually available
+	 *
+	 * Note: If descriptor isn't available, return 1 which tells
+	 *		 the upper layer to requeue the packet for later
+	 *		 transmission.
+	 *
+	 *       We need to ensure that the producer never reaches the
+	 *		 completion, except to indicate that the queue is empty.
+	 */
+
+	if (prod == bp->rcv_xmt_reg.index.xmt_comp)
+		return(1);						/* requeue packet for later */
+
+	/*
+	 * Save info for this packet for xmt done indication routine
+	 *
+	 * Normally, we'd save the producer index in the p_xmt_drv_descr
+	 * structure so that we'd have it handy when we complete this
+	 * packet later (in dfx_xmt_done).  However, since the current
+	 * transmit architecture guarantees a single fragment for the
+	 * entire packet, we can simply bump the completion index by
+	 * one (1) for each completed packet.
+	 *
+	 * Note: If this assumption changes and we're presented with
+	 *		 an inconsistent number of transmit fragments for packet
+	 *		 data, we'll need to modify this code to save the current
+	 *		 transmit producer index.
+	 */
+
+	p_xmt_drv_descr->p_skb = skb;
+
+	/* Update Type 2 register */
+
+	bp->rcv_xmt_reg.index.xmt_prod = prod;
+	dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
+	return(0);							/* packet queued to adapter */
+	}
+
+
+/*
+ * ================
+ * = dfx_xmt_done =
+ * ================
+ *   
+ * Overview:
+ *   Processes all frames that have been transmitted.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   For all consumed transmit descriptors that have not
+ *   yet been completed, we'll free the skb we were holding
+ *   onto using dev_kfree_skb and bump the appropriate
+ *   counters.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   The Type 2 register is not updated in this routine.  It is
+ *   assumed that it will be updated in the ISR when dfx_xmt_done
+ *   returns.
+ *
+ * Side Effects:
+ *   None
+ */
+
+void dfx_xmt_done(
+	DFX_board_t *bp
+	)
+
+	{
+	XMT_DRIVER_DESCR	*p_xmt_drv_descr;	/* ptr to transmit driver descriptor */
+	PI_TYPE_2_CONSUMER	*p_type_2_cons;		/* ptr to rcv/xmt consumer block register */
+
+	/* Service all consumed transmit frames */
+
+	p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data);
+	while (bp->rcv_xmt_reg.index.xmt_comp != p_type_2_cons->index.xmt_cons)
+		{
+		/* Get pointer to the transmit driver descriptor block information */
+
+		p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]);
+
+		/* Return skb to operating system */
+
+		dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE);
+
+		/* Increment transmit counters */
+
+		bp->xmt_total_frames++;
+
+		/*
+		 * Move to start of next packet by updating completion index
+		 *
+		 * Here we assume that a transmit packet request is always
+		 * serviced by posting one fragment.  We can therefore
+		 * simplify the completion code by incrementing the
+		 * completion index by one.  This code will need to be
+		 * modified if this assumption changes.  See comments
+		 * in dfx_xmt_queue_pkt for more details.
+		 */
+
+		bp->rcv_xmt_reg.index.xmt_comp += 1;
+		}
+	return;
+	}
+
+
+/*
+ * =================
+ * = dfx_xmt_flush =
+ * =================
+ *   
+ * Overview:
+ *   Processes all frames whether they've been transmitted
+ *   or not.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   For all produced transmit descriptors that have not
+ *   yet been completed, we'll free the skb we were holding
+ *   onto using dev_kfree_skb and bump the appropriate
+ *   counters.  Of course, it's possible that some of
+ *   these transmit requests actually did go out, but we
+ *   won't make that distinction here.  Finally, we'll
+ *   update the consumer index to match the producer.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   This routine does NOT update the Type 2 register.  It
+ *   is assumed that this routine is being called during a
+ *   transmit flush interrupt, or a shutdown or close routine.
+ *
+ * Side Effects:
+ *   None
+ */
+
+void dfx_xmt_flush(
+	DFX_board_t *bp
+	)
+
+	{
+	u32					prod_cons;			/* rcv/xmt consumer block longword */
+	XMT_DRIVER_DESCR	*p_xmt_drv_descr;	/* ptr to transmit driver descriptor */
+
+	/* Flush all outstanding transmit frames */
+
+	while (bp->rcv_xmt_reg.index.xmt_comp != bp->rcv_xmt_reg.index.xmt_prod)
+		{
+		/* Get pointer to the transmit driver descriptor block information */
+
+		p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]);
+
+		/* Return skb to operating system */
+
+		dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE);
+
+		/* Increment transmit error counter */
+
+		bp->xmt_discards++;
+
+		/*
+		 * Move to start of next packet by updating completion index
+		 *
+		 * Here we assume that a transmit packet request is always
+		 * serviced by posting one fragment.  We can therefore
+		 * simplify the completion code by incrementing the
+		 * completion index by one.  This code will need to be
+		 * modified if this assumption changes.  See comments
+		 * in dfx_xmt_queue_pkt for more details.
+		 */
+
+		bp->rcv_xmt_reg.index.xmt_comp += 1;
+		}
+
+	/* Update the transmit consumer index in the consumer block */
+
+	prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX);
+	prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX);
+	bp->cons_block_virt->xmt_rcv_data = prod_cons;
+	return;
+	}
+
+
+/*
+ * Local variables:
+ * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 -c defxx.c"
+ * End:
+ */
diff -u --recursive --new-file v2.0.23/linux/drivers/net/defxx.h linux/drivers/net/defxx.h
--- v2.0.23/linux/drivers/net/defxx.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/defxx.h	Wed Oct 30 03:42:40 1996
@@ -0,0 +1,1780 @@
+/*
+ * File Name:
+ *   defxx.h
+ *
+ * Copyright Information:
+ *   Copyright Digital Equipment Corporation 1996.
+ *
+ *   This software may be used and distributed according to the terms of
+ *   the GNU Public License, incorporated herein by reference.
+ *
+ * Abstract:
+ *   Contains all definitions specified by port specification and required
+ *   by the defxx.c driver.
+ *
+ * Maintainers:
+ *   LVS	Lawrence V. Stefani
+ *
+ * Contact:
+ *	 The author may be reached at:
+ *
+ *		Inet: stefani@lkg.dec.com
+ *		Mail: Digital Equipment Corporation
+ *			  550 King Street
+ *			  M/S: LKG1-3/M07
+ *			  Littleton, MA  01460
+ *
+ * Modification History:
+ *		Date		Name	Description
+ *		16-Aug-96	LVS		Created.
+ *		09-Sep-96	LVS		Added group_prom field.  Moved read/write I/O
+ *							macros to DEFXX.C.
+ *		12-Sep-96	LVS		Removed packet request header pointers.
+ */
+
+#ifndef _DEFXX_H_
+#define _DEFXX_H_
+
+/* Define basic types for unsigned chars, shorts, longs */
+
+typedef u8	PI_UINT8;
+typedef u16	PI_UINT16;
+typedef u32	PI_UINT32;
+
+/* Define general structures */
+
+typedef struct							/* 64-bit counter */
+	{
+	PI_UINT32  ms;
+	PI_UINT32  ls;
+	} PI_CNTR;
+
+typedef struct							/* LAN address */
+	{										
+	PI_UINT32  lwrd_0;
+	PI_UINT32  lwrd_1;
+	} PI_LAN_ADDR;
+
+typedef struct							/* Station ID address */
+	{
+	PI_UINT32  octet_7_4;
+	PI_UINT32  octet_3_0;
+	} PI_STATION_ID;
+
+
+/* Define general constants */
+
+#define PI_ALIGN_K_DESC_BLK	  			8192	/* Descriptor block boundary		*/
+#define PI_ALIGN_K_CONS_BLK	  	 		64		/* Consumer block boundary		  	*/
+#define PI_ALIGN_K_CMD_REQ_BUFF  		128	 	/* Xmt Command que buffer alignment */
+#define PI_ALIGN_K_CMD_RSP_BUFF	 		128	 	/* Rcv Command que buffer alignment */
+#define PI_ALIGN_K_UNSOL_BUFF	 		128	 	/* Unsol que buffer alignment	   	*/
+#define PI_ALIGN_K_XMT_DATA_BUFF 		0	   	/* Xmt data que buffer alignment	*/
+#define PI_ALIGN_K_RCV_DATA_BUFF 		128	 	/* Rcv que buffer alignment			*/
+
+/* Define PHY index values */
+
+#define PI_PHY_K_S						0		/* Index to S phy */
+#define PI_PHY_K_A						0		/* Index to A phy */
+#define PI_PHY_K_B						1		/* Index to B phy */
+#define PI_PHY_K_MAX					2		/* Max number of phys */
+
+/* Define FMC descriptor fields */
+
+#define PI_FMC_DESCR_V_SOP				31
+#define PI_FMC_DESCR_V_EOP				30
+#define PI_FMC_DESCR_V_FSC				27
+#define PI_FMC_DESCR_V_FSB_ERROR		26
+#define PI_FMC_DESCR_V_FSB_ADDR_RECOG	25
+#define PI_FMC_DESCR_V_FSB_ADDR_COPIED	24
+#define PI_FMC_DESCR_V_FSB				22
+#define PI_FMC_DESCR_V_RCC_FLUSH		21
+#define PI_FMC_DESCR_V_RCC_CRC			20
+#define PI_FMC_DESCR_V_RCC_RRR			17
+#define PI_FMC_DESCR_V_RCC_DD			15
+#define PI_FMC_DESCR_V_RCC_SS			13
+#define PI_FMC_DESCR_V_RCC				13
+#define PI_FMC_DESCR_V_LEN				0
+
+#define PI_FMC_DESCR_M_SOP				0x80000000
+#define PI_FMC_DESCR_M_EOP				0x40000000
+#define PI_FMC_DESCR_M_FSC				0x38000000
+#define PI_FMC_DESCR_M_FSB_ERROR		0x04000000
+#define PI_FMC_DESCR_M_FSB_ADDR_RECOG	0x02000000
+#define PI_FMC_DESCR_M_FSB_ADDR_COPIED	0x01000000
+#define PI_FMC_DESCR_M_FSB				0x07C00000
+#define PI_FMC_DESCR_M_RCC_FLUSH		0x00200000
+#define PI_FMC_DESCR_M_RCC_CRC			0x00100000
+#define PI_FMC_DESCR_M_RCC_RRR			0x000E0000
+#define PI_FMC_DESCR_M_RCC_DD			0x00018000
+#define PI_FMC_DESCR_M_RCC_SS			0x00006000
+#define PI_FMC_DESCR_M_RCC				0x003FE000
+#define PI_FMC_DESCR_M_LEN				0x00001FFF
+
+#define PI_FMC_DESCR_K_RCC_FMC_INT_ERR	0x01AA
+
+#define PI_FMC_DESCR_K_RRR_SUCCESS		0x00
+#define PI_FMC_DESCR_K_RRR_SA_MATCH		0x01
+#define PI_FMC_DESCR_K_RRR_DA_MATCH		0x02
+#define PI_FMC_DESCR_K_RRR_FMC_ABORT	0x03
+#define PI_FMC_DESCR_K_RRR_LENGTH_BAD	0x04
+#define PI_FMC_DESCR_K_RRR_FRAGMENT		0x05
+#define PI_FMC_DESCR_K_RRR_FORMAT_ERR	0x06
+#define PI_FMC_DESCR_K_RRR_MAC_RESET	0x07
+
+#define PI_FMC_DESCR_K_DD_NO_MATCH		0x0
+#define PI_FMC_DESCR_K_DD_PROMISCUOUS	0x1
+#define PI_FMC_DESCR_K_DD_CAM_MATCH		0x2
+#define PI_FMC_DESCR_K_DD_LOCAL_MATCH	0x3
+
+#define PI_FMC_DESCR_K_SS_NO_MATCH		0x0
+#define PI_FMC_DESCR_K_SS_BRIDGE_MATCH	0x1
+#define PI_FMC_DESCR_K_SS_NOT_POSSIBLE	0x2
+#define PI_FMC_DESCR_K_SS_LOCAL_MATCH	0x3
+
+/* Define some max buffer sizes */
+
+#define PI_CMD_REQ_K_SIZE_MAX			512
+#define PI_CMD_RSP_K_SIZE_MAX			512
+#define PI_UNSOL_K_SIZE_MAX				512
+#define PI_SMT_HOST_K_SIZE_MAX			4608		/* 4 1/2 K */
+#define PI_RCV_DATA_K_SIZE_MAX			4608		/* 4 1/2 K */
+#define PI_XMT_DATA_K_SIZE_MAX			4608		/* 4 1/2 K */
+
+/* Define adapter states */
+
+#define PI_STATE_K_RESET				0
+#define PI_STATE_K_UPGRADE		  		1
+#define PI_STATE_K_DMA_UNAVAIL			2
+#define PI_STATE_K_DMA_AVAIL			3
+#define PI_STATE_K_LINK_AVAIL			4
+#define PI_STATE_K_LINK_UNAVAIL	 		5
+#define PI_STATE_K_HALTED		   		6
+#define PI_STATE_K_RING_MEMBER			7
+#define PI_STATE_K_NUMBER				8 
+
+/* Define codes for command type */
+
+#define PI_CMD_K_START					0x00
+#define PI_CMD_K_FILTERS_SET			0x01
+#define PI_CMD_K_FILTERS_GET			0x02
+#define PI_CMD_K_CHARS_SET				0x03
+#define PI_CMD_K_STATUS_CHARS_GET		0x04
+#define PI_CMD_K_CNTRS_GET				0x05
+#define PI_CMD_K_CNTRS_SET				0x06
+#define PI_CMD_K_ADDR_FILTER_SET		0x07
+#define PI_CMD_K_ADDR_FILTER_GET		0x08
+#define PI_CMD_K_ERROR_LOG_CLEAR		0x09
+#define PI_CMD_K_ERROR_LOG_GET			0x0A
+#define PI_CMD_K_FDDI_MIB_GET			0x0B
+#define PI_CMD_K_DEC_EXT_MIB_GET		0x0C
+#define PI_CMD_K_DEVICE_SPECIFIC_GET	0x0D
+#define PI_CMD_K_SNMP_SET				0x0E
+#define PI_CMD_K_UNSOL_TEST				0x0F
+#define PI_CMD_K_SMT_MIB_GET			0x10
+#define PI_CMD_K_SMT_MIB_SET			0x11
+#define PI_CMD_K_MAX					0x11	/* Must match last */
+
+/* Define item codes for Chars_Set and Filters_Set commands */
+
+#define PI_ITEM_K_EOL					0x00 	/* End-of-Item list 		  */
+#define PI_ITEM_K_T_REQ					0x01 	/* DECnet T_REQ 			  */
+#define PI_ITEM_K_TVX					0x02 	/* DECnet TVX 				  */
+#define PI_ITEM_K_RESTRICTED_TOKEN		0x03 	/* DECnet Restricted Token 	  */	 
+#define PI_ITEM_K_LEM_THRESHOLD			0x04 	/* DECnet LEM Threshold 	  */
+#define PI_ITEM_K_RING_PURGER			0x05 	/* DECnet Ring Purger Enable  */	
+#define PI_ITEM_K_CNTR_INTERVAL			0x06 	/* Chars_Set 				  */
+#define PI_ITEM_K_IND_GROUP_PROM		0x07 	/* Filters_Set 				  */
+#define PI_ITEM_K_GROUP_PROM			0x08 	/* Filters_Set 				  */
+#define PI_ITEM_K_BROADCAST				0x09 	/* Filters_Set 				  */
+#define PI_ITEM_K_SMT_PROM				0x0A 	/* Filters_Set				  */
+#define PI_ITEM_K_SMT_USER				0x0B 	/* Filters_Set 				  */
+#define PI_ITEM_K_RESERVED				0x0C 	/* Filters_Set 				  */
+#define PI_ITEM_K_IMPLEMENTOR			0x0D 	/* Filters_Set 				  */
+#define PI_ITEM_K_LOOPBACK_MODE			0x0E 	/* Chars_Set 				  */
+#define PI_ITEM_K_CONFIG_POLICY			0x10 	/* SMTConfigPolicy 			  */
+#define PI_ITEM_K_CON_POLICY			0x11 	/* SMTConnectionPolicy 		  */
+#define PI_ITEM_K_T_NOTIFY				0x12 	/* SMTTNotify 				  */
+#define PI_ITEM_K_STATION_ACTION		0x13 	/* SMTStationAction			  */
+#define PI_ITEM_K_MAC_PATHS_REQ	   		0x15 	/* MACPathsRequested 		  */
+#define PI_ITEM_K_MAC_ACTION			0x17 	/* MACAction 				  */
+#define PI_ITEM_K_CON_POLICIES			0x18 	/* PORTConnectionPolicies	  */
+#define PI_ITEM_K_PORT_PATHS_REQ		0x19 	/* PORTPathsRequested 		  */
+#define PI_ITEM_K_MAC_LOOP_TIME			0x1A 	/* PORTMACLoopTime 			  */
+#define PI_ITEM_K_TB_MAX				0x1B 	/* PORTTBMax 				  */
+#define PI_ITEM_K_LER_CUTOFF			0x1C 	/* PORTLerCutoff 			  */
+#define PI_ITEM_K_LER_ALARM				0x1D 	/* PORTLerAlarm 			  */
+#define PI_ITEM_K_PORT_ACTION			0x1E 	/* PORTAction 				  */
+#define PI_ITEM_K_FLUSH_TIME			0x20 	/* Chars_Set 				  */
+#define PI_ITEM_K_MAC_T_REQ				0x29 	/* MACTReq 					  */
+#define PI_ITEM_K_EMAC_RING_PURGER		0x2A 	/* eMACRingPurgerEnable		  */
+#define PI_ITEM_K_EMAC_RTOKEN_TIMEOUT	0x2B 	/* eMACRestrictedTokenTimeout */
+#define PI_ITEM_K_FDX_ENB_DIS			0x2C 	/* eFDXEnable				  */
+#define PI_ITEM_K_MAX					0x2C 	/* Must equal high item		  */
+
+/* Values for some of the items */
+
+#define PI_K_FALSE						0	   /* Generic false */
+#define PI_K_TRUE						1	   /* Generic true  */
+
+#define PI_SNMP_K_TRUE					1	   /* SNMP true/false values */
+#define PI_SNMP_K_FALSE					2
+
+#define PI_FSTATE_K_BLOCK				0	   /* Filter State */
+#define PI_FSTATE_K_PASS				1
+
+/* Define command return codes */
+
+#define PI_RSP_K_SUCCESS				0x00
+#define PI_RSP_K_FAILURE				0x01
+#define PI_RSP_K_WARNING				0x02
+#define PI_RSP_K_LOOP_MODE_BAD			0x03
+#define PI_RSP_K_ITEM_CODE_BAD			0x04
+#define PI_RSP_K_TVX_BAD				0x05
+#define PI_RSP_K_TREQ_BAD				0x06
+#define PI_RSP_K_TOKEN_BAD				0x07
+#define PI_RSP_K_NO_EOL					0x0C
+#define PI_RSP_K_FILTER_STATE_BAD		0x0D
+#define PI_RSP_K_CMD_TYPE_BAD			0x0E
+#define PI_RSP_K_ADAPTER_STATE_BAD		0x0F
+#define PI_RSP_K_RING_PURGER_BAD		0x10
+#define PI_RSP_K_LEM_THRESHOLD_BAD		0x11
+#define PI_RSP_K_LOOP_NOT_SUPPORTED		0x12
+#define PI_RSP_K_FLUSH_TIME_BAD			0x13
+#define PI_RSP_K_NOT_IMPLEMENTED		0x14
+#define PI_RSP_K_CONFIG_POLICY_BAD		0x15
+#define PI_RSP_K_STATION_ACTION_BAD		0x16
+#define PI_RSP_K_MAC_ACTION_BAD			0x17
+#define PI_RSP_K_CON_POLICIES_BAD		0x18
+#define PI_RSP_K_MAC_LOOP_TIME_BAD		0x19
+#define PI_RSP_K_TB_MAX_BAD				0x1A
+#define PI_RSP_K_LER_CUTOFF_BAD			0x1B
+#define PI_RSP_K_LER_ALARM_BAD			0x1C
+#define PI_RSP_K_MAC_PATHS_REQ_BAD		0x1D
+#define PI_RSP_K_MAC_T_REQ_BAD			0x1E
+#define PI_RSP_K_EMAC_RING_PURGER_BAD	0x1F
+#define PI_RSP_K_EMAC_RTOKEN_TIME_BAD	0x20
+#define PI_RSP_K_NO_SUCH_ENTRY			0x21
+#define PI_RSP_K_T_NOTIFY_BAD			0x22
+#define PI_RSP_K_TR_MAX_EXP_BAD			0x23
+#define PI_RSP_K_MAC_FRM_ERR_THR_BAD	0x24
+#define PI_RSP_K_MAX_T_REQ_BAD			0x25
+#define PI_RSP_K_FDX_ENB_DIS_BAD		0x26
+#define PI_RSP_K_ITEM_INDEX_BAD			0x27
+#define PI_RSP_K_PORT_ACTION_BAD		0x28
+
+/* Commonly used structures */
+
+typedef struct									/* Item list */
+	{
+	PI_UINT32  item_code;
+	PI_UINT32  value;
+	} PI_ITEM_LIST;
+
+typedef struct									/* Response header */
+	{
+	PI_UINT32  reserved;
+	PI_UINT32  cmd_type;
+	PI_UINT32  status;
+	} PI_RSP_HEADER;
+
+
+/* Start Command */
+
+typedef struct
+	{
+	PI_UINT32  cmd_type;
+	} PI_CMD_START_REQ;
+
+/* Start Response */
+
+typedef struct 
+	{
+	PI_RSP_HEADER   header;	
+	} PI_CMD_START_RSP;
+
+/* Filters_Set Request */
+
+#define PI_CMD_FILTERS_SET_K_ITEMS_MAX  63		/* Fits in a 512 byte buffer */
+
+typedef struct 
+	{
+	PI_UINT32		cmd_type;
+	PI_ITEM_LIST	item[PI_CMD_FILTERS_SET_K_ITEMS_MAX];
+	} PI_CMD_FILTERS_SET_REQ;
+
+/* Filters_Set Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;	
+	} PI_CMD_FILTERS_SET_RSP;
+
+/* Filters_Get Request */
+
+typedef struct
+	{
+	PI_UINT32		cmd_type;   
+	} PI_CMD_FILTERS_GET_REQ;
+
+/* Filters_Get Response */
+
+typedef struct 
+	{
+	PI_RSP_HEADER   header;	
+	PI_UINT32		ind_group_prom;
+	PI_UINT32		group_prom;
+	PI_UINT32		broadcast_all;
+	PI_UINT32		smt_all;
+	PI_UINT32		smt_user;
+	PI_UINT32		reserved_all;
+	PI_UINT32		implementor_all;
+	} PI_CMD_FILTERS_GET_RSP;
+
+
+/* Chars_Set Request */
+
+#define PI_CMD_CHARS_SET_K_ITEMS_MAX 42		/* Fits in a 512 byte buffer */
+
+typedef struct
+	{
+	PI_UINT32		cmd_type;
+	struct							  		/* Item list */
+		{
+		PI_UINT32	item_code;
+		PI_UINT32	value;
+		PI_UINT32	item_index;
+		} item[PI_CMD_CHARS_SET_K_ITEMS_MAX];	
+	} PI_CMD_CHARS_SET_REQ;
+
+/* Chars_Set Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;	
+	} PI_CMD_CHARS_SET_RSP;
+
+
+/* SNMP_Set Request */
+
+#define PI_CMD_SNMP_SET_K_ITEMS_MAX 42	   	/* Fits in a 512 byte buffer */
+
+typedef struct
+	{
+	PI_UINT32		cmd_type;
+	struct							   		/* Item list */
+		{
+		PI_UINT32	item_code;
+		PI_UINT32	value;
+		PI_UINT32	item_index;
+		} item[PI_CMD_SNMP_SET_K_ITEMS_MAX];	
+	} PI_CMD_SNMP_SET_REQ;
+
+/* SNMP_Set Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;	
+	} PI_CMD_SNMP_SET_RSP;
+
+
+/* SMT_MIB_Set Request */
+
+#define PI_CMD_SMT_MIB_SET_K_ITEMS_MAX 42	/* Max number of items */ 
+
+typedef struct
+	{
+	PI_UINT32	cmd_type;
+	struct
+		{
+		PI_UINT32	item_code;
+		PI_UINT32	value;
+		PI_UINT32	item_index;
+		} item[PI_CMD_SMT_MIB_SET_K_ITEMS_MAX];
+	} PI_CMD_SMT_MIB_SET_REQ;
+
+/* SMT_MIB_Set Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;	
+	} PI_CMD_SMT_MIB_SET_RSP;
+
+/* SMT_MIB_Get Request */
+
+typedef struct
+	{
+	PI_UINT32  cmd_type;
+	} PI_CMD_SMT_MIB_GET_REQ;
+
+/* SMT_MIB_Get Response */
+
+typedef struct						  /* Refer to ANSI FDDI SMT Rev. 7.3 */
+	{
+	PI_RSP_HEADER  header;
+	
+	/* SMT GROUP */														  
+
+	PI_STATION_ID  	smt_station_id;
+	PI_UINT32 		smt_op_version_id;
+	PI_UINT32	   	smt_hi_version_id;
+	PI_UINT32	   	smt_lo_version_id;
+	PI_UINT32	   	smt_user_data[8];
+	PI_UINT32	   	smt_mib_version_id;
+	PI_UINT32	   	smt_mac_ct;
+	PI_UINT32	   	smt_non_master_ct;
+	PI_UINT32	   	smt_master_ct;
+	PI_UINT32	   	smt_available_paths;
+	PI_UINT32	   	smt_config_capabilities;
+	PI_UINT32	   	smt_config_policy;
+	PI_UINT32	   	smt_connection_policy;
+	PI_UINT32	   	smt_t_notify;
+	PI_UINT32	   	smt_stat_rpt_policy;
+	PI_UINT32	   	smt_trace_max_expiration;
+	PI_UINT32	   	smt_bypass_present;
+	PI_UINT32	  	smt_ecm_state;
+	PI_UINT32	   	smt_cf_state;
+	PI_UINT32	   	smt_remote_disconnect_flag;
+	PI_UINT32	   	smt_station_status;
+	PI_UINT32	   	smt_peer_wrap_flag;
+	PI_CNTR	   		smt_msg_time_stamp;
+	PI_CNTR	  		smt_transition_time_stamp;
+
+	/* MAC GROUP */
+
+	PI_UINT32		mac_frame_status_functions;
+	PI_UINT32		mac_t_max_capability;
+	PI_UINT32		mac_tvx_capability;
+	PI_UINT32		mac_available_paths;
+	PI_UINT32		mac_current_path;
+	PI_LAN_ADDR		mac_upstream_nbr;
+	PI_LAN_ADDR		mac_downstream_nbr;
+	PI_LAN_ADDR		mac_old_upstream_nbr;
+	PI_LAN_ADDR		mac_old_downstream_nbr;
+	PI_UINT32	   	mac_dup_address_test;
+	PI_UINT32	   	mac_requested_paths;
+	PI_UINT32	   	mac_downstream_port_type;
+	PI_LAN_ADDR		mac_smt_address;
+	PI_UINT32		mac_t_req;
+	PI_UINT32		mac_t_neg;
+	PI_UINT32		mac_t_max;
+	PI_UINT32		mac_tvx_value;
+	PI_UINT32		mac_frame_error_threshold;
+	PI_UINT32		mac_frame_error_ratio;
+	PI_UINT32		mac_rmt_state;
+	PI_UINT32		mac_da_flag;
+	PI_UINT32		mac_unda_flag;
+	PI_UINT32		mac_frame_error_flag;
+	PI_UINT32		mac_ma_unitdata_available;
+	PI_UINT32		mac_hardware_present;
+	PI_UINT32		mac_ma_unitdata_enable;
+
+	/* PATH GROUP */
+
+	PI_UINT32		path_configuration[8];
+	PI_UINT32		path_tvx_lower_bound;
+	PI_UINT32		path_t_max_lower_bound;
+	PI_UINT32		path_max_t_req;
+
+	/* PORT GROUP */
+
+	PI_UINT32		port_my_type[PI_PHY_K_MAX];
+	PI_UINT32		port_neighbor_type[PI_PHY_K_MAX];
+	PI_UINT32		port_connection_policies[PI_PHY_K_MAX];
+	PI_UINT32		port_mac_indicated[PI_PHY_K_MAX];
+	PI_UINT32		port_current_path[PI_PHY_K_MAX];
+	PI_UINT32		port_requested_paths[PI_PHY_K_MAX];
+	PI_UINT32		port_mac_placement[PI_PHY_K_MAX];
+	PI_UINT32		port_available_paths[PI_PHY_K_MAX];
+	PI_UINT32		port_pmd_class[PI_PHY_K_MAX];
+	PI_UINT32		port_connection_capabilities[PI_PHY_K_MAX];
+	PI_UINT32		port_bs_flag[PI_PHY_K_MAX];
+	PI_UINT32		port_ler_estimate[PI_PHY_K_MAX];
+	PI_UINT32		port_ler_cutoff[PI_PHY_K_MAX];	
+	PI_UINT32		port_ler_alarm[PI_PHY_K_MAX];
+	PI_UINT32		port_connect_state[PI_PHY_K_MAX];
+	PI_UINT32		port_pcm_state[PI_PHY_K_MAX];
+	PI_UINT32		port_pc_withhold[PI_PHY_K_MAX];
+	PI_UINT32		port_ler_flag[PI_PHY_K_MAX];
+	PI_UINT32		port_hardware_present[PI_PHY_K_MAX];
+
+	/* GROUP for things that were added later, so must be at the end. */
+
+	PI_CNTR	   		path_ring_latency;
+
+	} PI_CMD_SMT_MIB_GET_RSP; 
+
+
+/*
+ *  Item and group code definitions for SMT 7.3 mandatory objects.  These
+ *  definitions are to be used as appropriate in SMT_MIB_SET commands and
+ *  certain host-sent SMT frames such as PMF Get and Set requests.  The
+ *  codes have been taken from the MIB summary section of ANSI SMT 7.3.
+ */
+	
+#define PI_GRP_K_SMT_STATION_ID			0x100A
+#define PI_ITEM_K_SMT_STATION_ID		0x100B
+#define PI_ITEM_K_SMT_OP_VERS_ID		0x100D
+#define PI_ITEM_K_SMT_HI_VERS_ID		0x100E
+#define PI_ITEM_K_SMT_LO_VERS_ID		0x100F
+#define PI_ITEM_K_SMT_USER_DATA			0x1011
+#define PI_ITEM_K_SMT_MIB_VERS_ID	  	0x1012
+
+#define PI_GRP_K_SMT_STATION_CONFIG		0x1014
+#define PI_ITEM_K_SMT_MAC_CT			0x1015
+#define PI_ITEM_K_SMT_NON_MASTER_CT		0x1016
+#define PI_ITEM_K_SMT_MASTER_CT			0x1017
+#define PI_ITEM_K_SMT_AVAIL_PATHS		0x1018
+#define PI_ITEM_K_SMT_CONFIG_CAPS		0x1019
+#define PI_ITEM_K_SMT_CONFIG_POL		0x101A
+#define PI_ITEM_K_SMT_CONN_POL			0x101B
+#define PI_ITEM_K_SMT_T_NOTIFY			0x101D
+#define PI_ITEM_K_SMT_STAT_POL			0x101E
+#define PI_ITEM_K_SMT_TR_MAX_EXP		0x101F
+#define PI_ITEM_K_SMT_PORT_INDEXES		0x1020
+#define PI_ITEM_K_SMT_MAC_INDEXES		0x1021
+#define PI_ITEM_K_SMT_BYPASS_PRESENT	0x1022
+
+#define PI_GRP_K_SMT_STATUS				0x1028
+#define PI_ITEM_K_SMT_ECM_STATE			0x1029
+#define PI_ITEM_K_SMT_CF_STATE		 	0x102A
+#define PI_ITEM_K_SMT_REM_DISC_FLAG		0x102C
+#define PI_ITEM_K_SMT_STATION_STATUS	0x102D
+#define PI_ITEM_K_SMT_PEER_WRAP_FLAG	0x102E
+	
+#define PI_GRP_K_SMT_MIB_OPERATION	 	0x1032
+#define PI_ITEM_K_SMT_MSG_TIME_STAMP 	0x1033
+#define PI_ITEM_K_SMT_TRN_TIME_STAMP 	0x1034
+
+#define PI_ITEM_K_SMT_STATION_ACT		0x103C
+
+#define PI_GRP_K_MAC_CAPABILITIES	  	0x200A
+#define PI_ITEM_K_MAC_FRM_STAT_FUNC		0x200B
+#define PI_ITEM_K_MAC_T_MAX_CAP			0x200D
+#define PI_ITEM_K_MAC_TVX_CAP		  	0x200E
+
+#define PI_GRP_K_MAC_CONFIG				0x2014
+#define PI_ITEM_K_MAC_AVAIL_PATHS	  	0x2016
+#define PI_ITEM_K_MAC_CURRENT_PATH	 	0x2017
+#define PI_ITEM_K_MAC_UP_NBR			0x2018
+#define PI_ITEM_K_MAC_DOWN_NBR			0x2019
+#define PI_ITEM_K_MAC_OLD_UP_NBR	 	0x201A
+#define PI_ITEM_K_MAC_OLD_DOWN_NBR	 	0x201B
+#define PI_ITEM_K_MAC_DUP_ADDR_TEST		0x201D
+#define PI_ITEM_K_MAC_REQ_PATHS			0x2020
+#define PI_ITEM_K_MAC_DOWN_PORT_TYPE   	0x2021
+#define PI_ITEM_K_MAC_INDEX				0x2022
+
+#define PI_GRP_K_MAC_ADDRESS			0x2028
+#define PI_ITEM_K_MAC_SMT_ADDRESS		0x2029
+
+#define PI_GRP_K_MAC_OPERATION			0x2032
+#define PI_ITEM_K_MAC_TREQ				0x2033
+#define PI_ITEM_K_MAC_TNEG				0x2034
+#define PI_ITEM_K_MAC_TMAX				0x2035
+#define PI_ITEM_K_MAC_TVX_VALUE			0x2036
+
+#define PI_GRP_K_MAC_COUNTERS			0x2046
+#define PI_ITEM_K_MAC_FRAME_CT			0x2047
+#define PI_ITEM_K_MAC_COPIED_CT			0x2048
+#define PI_ITEM_K_MAC_TRANSMIT_CT		0x2049
+#define PI_ITEM_K_MAC_ERROR_CT			0x2051
+#define PI_ITEM_K_MAC_LOST_CT			0x2052
+
+#define PI_GRP_K_MAC_FRM_ERR_COND		0x205A
+#define PI_ITEM_K_MAC_FRM_ERR_THR		0x205F
+#define PI_ITEM_K_MAC_FRM_ERR_RAT		0x2060
+
+#define PI_GRP_K_MAC_STATUS				0x206E
+#define PI_ITEM_K_MAC_RMT_STATE			0x206F
+#define PI_ITEM_K_MAC_DA_FLAG			0x2070
+#define PI_ITEM_K_MAC_UNDA_FLAG			0x2071
+#define PI_ITEM_K_MAC_FRM_ERR_FLAG		0x2072
+#define PI_ITEM_K_MAC_MA_UNIT_AVAIL		0x2074
+#define PI_ITEM_K_MAC_HW_PRESENT		0x2075
+#define PI_ITEM_K_MAC_MA_UNIT_ENAB		0x2076
+
+#define PI_GRP_K_PATH_CONFIG			0x320A
+#define PI_ITEM_K_PATH_INDEX			0x320B
+#define PI_ITEM_K_PATH_CONFIGURATION 	0x3212
+#define PI_ITEM_K_PATH_TVX_LB			0x3215
+#define PI_ITEM_K_PATH_T_MAX_LB			0x3216
+#define PI_ITEM_K_PATH_MAX_T_REQ		0x3217
+
+#define PI_GRP_K_PORT_CONFIG			0x400A
+#define PI_ITEM_K_PORT_MY_TYPE			0x400C
+#define PI_ITEM_K_PORT_NBR_TYPE			0x400D
+#define PI_ITEM_K_PORT_CONN_POLS		0x400E
+#define PI_ITEM_K_PORT_MAC_INDICATED  	0x400F
+#define PI_ITEM_K_PORT_CURRENT_PATH		0x4010
+#define PI_ITEM_K_PORT_REQ_PATHS		0x4011
+#define PI_ITEM_K_PORT_MAC_PLACEMENT 	0x4012
+#define PI_ITEM_K_PORT_AVAIL_PATHS		0x4013
+#define PI_ITEM_K_PORT_PMD_CLASS		0x4016
+#define PI_ITEM_K_PORT_CONN_CAPS		0x4017
+#define PI_ITEM_K_PORT_INDEX			0x401D
+
+#define PI_GRP_K_PORT_OPERATION			0x401E
+#define PI_ITEM_K_PORT_BS_FLAG		 	0x4021
+
+#define PI_GRP_K_PORT_ERR_CNTRS			0x4028
+#define PI_ITEM_K_PORT_LCT_FAIL_CT	 	0x402A
+
+#define PI_GRP_K_PORT_LER			  	0x4032
+#define PI_ITEM_K_PORT_LER_ESTIMATE		0x4033
+#define PI_ITEM_K_PORT_LEM_REJ_CT		0x4034
+#define PI_ITEM_K_PORT_LEM_CT			0x4035
+#define PI_ITEM_K_PORT_LER_CUTOFF		0x403A
+#define PI_ITEM_K_PORT_LER_ALARM		0x403B
+
+#define PI_GRP_K_PORT_STATUS			0x403C
+#define PI_ITEM_K_PORT_CONNECT_STATE	0x403D
+#define PI_ITEM_K_PORT_PCM_STATE		0x403E
+#define PI_ITEM_K_PORT_PC_WITHHOLD		0x403F
+#define PI_ITEM_K_PORT_LER_FLAG			0x4040
+#define PI_ITEM_K_PORT_HW_PRESENT		0x4041
+
+#define PI_ITEM_K_PORT_ACT				0x4046
+
+/* Addr_Filter_Set Request */
+
+#define PI_CMD_ADDR_FILTER_K_SIZE   62
+
+typedef struct
+	{
+	PI_UINT32	cmd_type;
+	PI_LAN_ADDR	entry[PI_CMD_ADDR_FILTER_K_SIZE];
+	} PI_CMD_ADDR_FILTER_SET_REQ;
+
+/* Addr_Filter_Set Response */
+
+typedef struct 
+	{
+	PI_RSP_HEADER   header;	
+	} PI_CMD_ADDR_FILTER_SET_RSP;
+
+/* Addr_Filter_Get Request */
+
+typedef struct
+	{
+	PI_UINT32	cmd_type;
+	} PI_CMD_ADDR_FILTER_GET_REQ;
+
+/* Addr_Filter_Get Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;	
+	PI_LAN_ADDR		entry[PI_CMD_ADDR_FILTER_K_SIZE];
+	} PI_CMD_ADDR_FILTER_GET_RSP;
+
+/* Status_Chars_Get Request */
+
+typedef struct
+	{
+	PI_UINT32  cmd_type;
+	} PI_CMD_STATUS_CHARS_GET_REQ;
+
+/* Status_Chars_Get Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;	
+	PI_STATION_ID   station_id;						/* Station */
+	PI_UINT32		station_type;
+	PI_UINT32		smt_ver_id;
+	PI_UINT32		smt_ver_id_max;
+	PI_UINT32		smt_ver_id_min;
+	PI_UINT32		station_state;
+	PI_LAN_ADDR		link_addr;						/* Link */
+	PI_UINT32		t_req;
+	PI_UINT32		tvx;
+	PI_UINT32		token_timeout;
+	PI_UINT32		purger_enb;
+	PI_UINT32		link_state;
+	PI_UINT32		tneg;
+	PI_UINT32		dup_addr_flag;
+	PI_LAN_ADDR		una;
+	PI_LAN_ADDR		una_old;
+	PI_UINT32		un_dup_addr_flag;
+	PI_LAN_ADDR		dna;
+	PI_LAN_ADDR		dna_old;
+	PI_UINT32		purger_state;
+	PI_UINT32		fci_mode;
+	PI_UINT32		error_reason;
+	PI_UINT32		loopback;
+	PI_UINT32		ring_latency;
+	PI_LAN_ADDR		last_dir_beacon_sa;
+	PI_LAN_ADDR		last_dir_beacon_una;
+	PI_UINT32		phy_type[PI_PHY_K_MAX];			/* Phy */
+	PI_UINT32		pmd_type[PI_PHY_K_MAX];
+	PI_UINT32		lem_threshold[PI_PHY_K_MAX];
+	PI_UINT32		phy_state[PI_PHY_K_MAX];
+	PI_UINT32		nbor_phy_type[PI_PHY_K_MAX];
+	PI_UINT32		link_error_est[PI_PHY_K_MAX];
+	PI_UINT32		broken_reason[PI_PHY_K_MAX];
+	PI_UINT32		reject_reason[PI_PHY_K_MAX];
+	PI_UINT32		cntr_interval;					/* Miscellaneous */
+	PI_UINT32		module_rev;
+	PI_UINT32		firmware_rev;
+	PI_UINT32		mop_device_type;
+	PI_UINT32		phy_led[PI_PHY_K_MAX];
+	PI_UINT32		flush_time;
+	} PI_CMD_STATUS_CHARS_GET_RSP;
+
+/* FDDI_MIB_Get Request */
+
+typedef struct
+	{
+	PI_UINT32  cmd_type;
+	} PI_CMD_FDDI_MIB_GET_REQ;
+
+/* FDDI_MIB_Get Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;		
+
+	/* SMT GROUP */
+
+	PI_STATION_ID   smt_station_id;			
+	PI_UINT32		smt_op_version_id;
+	PI_UINT32		smt_hi_version_id;
+	PI_UINT32		smt_lo_version_id;
+	PI_UINT32		smt_mac_ct;				
+	PI_UINT32		smt_non_master_ct;			
+	PI_UINT32		smt_master_ct;				
+	PI_UINT32		smt_paths_available;			
+	PI_UINT32		smt_config_capabilities;		
+	PI_UINT32		smt_config_policy;		
+	PI_UINT32		smt_connection_policy;		
+	PI_UINT32		smt_t_notify;	
+	PI_UINT32		smt_status_reporting;
+	PI_UINT32		smt_ecm_state;	
+	PI_UINT32		smt_cf_state;	
+	PI_UINT32		smt_hold_state;		
+	PI_UINT32		smt_remote_disconnect_flag;
+	PI_UINT32		smt_station_action;			
+
+	/* MAC GROUP */
+
+	PI_UINT32		mac_frame_status_capabilities;	
+	PI_UINT32		mac_t_max_greatest_lower_bound;
+	PI_UINT32		mac_tvx_greatest_lower_bound;
+	PI_UINT32		mac_paths_available;
+	PI_UINT32		mac_current_path;
+	PI_LAN_ADDR		mac_upstream_nbr;			
+	PI_LAN_ADDR		mac_old_upstream_nbr;		
+	PI_UINT32		mac_dup_addr_test;			
+	PI_UINT32		mac_paths_requested;
+	PI_UINT32		mac_downstream_port_type;
+	PI_LAN_ADDR		mac_smt_address;			
+	PI_UINT32		mac_t_req;				
+	PI_UINT32		mac_t_neg;
+	PI_UINT32		mac_t_max;				
+	PI_UINT32		mac_tvx_value;			
+	PI_UINT32		mac_t_min;				
+	PI_UINT32		mac_current_frame_status;
+	/*			  	mac_frame_cts 			*/
+	/* 				mac_error_cts 			*/
+	/* 		   		mac_lost_cts 			*/
+	PI_UINT32		mac_frame_error_threshold;		
+	PI_UINT32		mac_frame_error_ratio;		
+	PI_UINT32		mac_rmt_state;
+	PI_UINT32		mac_da_flag;
+	PI_UINT32		mac_una_da_flag;			
+	PI_UINT32		mac_frame_condition;
+	PI_UINT32		mac_chip_set;			
+	PI_UINT32		mac_action;				
+
+	/* PATH GROUP => Does not need to be implemented */
+
+	/* PORT GROUP */
+
+	PI_UINT32		port_pc_type[PI_PHY_K_MAX];			
+	PI_UINT32		port_pc_neighbor[PI_PHY_K_MAX];			
+	PI_UINT32		port_connection_policies[PI_PHY_K_MAX];
+	PI_UINT32		port_remote_mac_indicated[PI_PHY_K_MAX];
+	PI_UINT32		port_ce_state[PI_PHY_K_MAX];
+	PI_UINT32		port_paths_requested[PI_PHY_K_MAX];
+	PI_UINT32		port_mac_placement[PI_PHY_K_MAX];
+	PI_UINT32		port_available_paths[PI_PHY_K_MAX];
+	PI_UINT32		port_mac_loop_time[PI_PHY_K_MAX];
+	PI_UINT32		port_tb_max[PI_PHY_K_MAX];
+	PI_UINT32		port_bs_flag[PI_PHY_K_MAX];
+	/*				port_lct_fail_cts[PI_PHY_K_MAX];	*/
+	PI_UINT32		port_ler_estimate[PI_PHY_K_MAX];				
+	/*				port_lem_reject_cts[PI_PHY_K_MAX];	*/
+	/*				port_lem_cts[PI_PHY_K_MAX];		*/
+	PI_UINT32		port_ler_cutoff[PI_PHY_K_MAX];				
+	PI_UINT32		port_ler_alarm[PI_PHY_K_MAX];				
+	PI_UINT32		port_connect_state[PI_PHY_K_MAX];
+	PI_UINT32		port_pcm_state[PI_PHY_K_MAX];
+	PI_UINT32		port_pc_withhold[PI_PHY_K_MAX];
+	PI_UINT32		port_ler_condition[PI_PHY_K_MAX];				
+	PI_UINT32		port_chip_set[PI_PHY_K_MAX];				
+	PI_UINT32		port_action[PI_PHY_K_MAX];				
+
+	/* ATTACHMENT GROUP */
+
+	PI_UINT32		attachment_class;
+	PI_UINT32		attachment_ob_present;
+	PI_UINT32		attachment_imax_expiration;
+	PI_UINT32		attachment_inserted_status;
+	PI_UINT32		attachment_insert_policy;
+
+	/* CHIP SET GROUP => Does not need to be implemented */
+
+	} PI_CMD_FDDI_MIB_GET_RSP;
+
+/* DEC_Ext_MIB_Get Request */
+
+typedef struct
+	{
+	PI_UINT32  cmd_type;
+	} PI_CMD_DEC_EXT_MIB_GET_REQ;
+
+/* DEC_Ext_MIB_Get (efddi and efdx groups only) Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;		
+
+	/* SMT GROUP */
+
+	PI_UINT32		esmt_station_type;
+
+	/* MAC GROUP */
+
+	PI_UINT32		emac_link_state;			
+	PI_UINT32		emac_ring_purger_state;
+	PI_UINT32		emac_ring_purger_enable;
+	PI_UINT32		emac_frame_strip_mode;
+	PI_UINT32		emac_ring_error_reason;
+	PI_UINT32		emac_up_nbr_dup_addr_flag;
+	PI_UINT32		emac_restricted_token_timeout;
+
+	/* PORT GROUP */
+
+	PI_UINT32		eport_pmd_type[PI_PHY_K_MAX];
+	PI_UINT32		eport_phy_state[PI_PHY_K_MAX];
+	PI_UINT32		eport_reject_reason[PI_PHY_K_MAX];
+
+	/* FDX (Full-Duplex) GROUP */
+
+	PI_UINT32		efdx_enable;				/* Valid only in SMT 7.3 */
+	PI_UINT32		efdx_op;					/* Valid only in SMT 7.3 */
+	PI_UINT32		efdx_state;					/* Valid only in SMT 7.3 */
+
+	} PI_CMD_DEC_EXT_MIB_GET_RSP;
+
+typedef struct
+	{
+	PI_CNTR		traces_rcvd;					/* Station */
+	PI_CNTR		frame_cnt;						/* Link */
+	PI_CNTR		error_cnt;
+	PI_CNTR		lost_cnt;
+	PI_CNTR		octets_rcvd;
+	PI_CNTR		octets_sent;
+	PI_CNTR		pdus_rcvd;
+	PI_CNTR		pdus_sent;
+	PI_CNTR		mcast_octets_rcvd;
+	PI_CNTR		mcast_octets_sent;
+	PI_CNTR		mcast_pdus_rcvd;
+	PI_CNTR		mcast_pdus_sent;
+	PI_CNTR		xmt_underruns;
+	PI_CNTR		xmt_failures;
+	PI_CNTR		block_check_errors;
+	PI_CNTR		frame_status_errors;
+	PI_CNTR		pdu_length_errors;
+	PI_CNTR		rcv_overruns;
+	PI_CNTR		user_buff_unavailable;
+	PI_CNTR		inits_initiated;
+	PI_CNTR		inits_rcvd;
+	PI_CNTR		beacons_initiated;
+	PI_CNTR		dup_addrs;
+	PI_CNTR		dup_tokens;
+	PI_CNTR		purge_errors;
+	PI_CNTR		fci_strip_errors;
+	PI_CNTR		traces_initiated;
+	PI_CNTR		directed_beacons_rcvd;
+	PI_CNTR		emac_frame_alignment_errors;
+	PI_CNTR		ebuff_errors[PI_PHY_K_MAX];		/* Phy */
+	PI_CNTR		lct_rejects[PI_PHY_K_MAX];
+	PI_CNTR		lem_rejects[PI_PHY_K_MAX];
+	PI_CNTR		link_errors[PI_PHY_K_MAX];
+	PI_CNTR		connections[PI_PHY_K_MAX];
+	PI_CNTR		copied_cnt;			 			/* Valid only if using SMT 7.3 */
+	PI_CNTR		transmit_cnt;					/* Valid only if using SMT 7.3 */
+	PI_CNTR		tokens;
+	} PI_CNTR_BLK;
+
+/* Counters_Get Request */
+
+typedef struct
+	{
+	PI_UINT32  cmd_type;
+	} PI_CMD_CNTRS_GET_REQ;
+
+/* Counters_Get Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;	
+	PI_CNTR		time_since_reset;			
+	PI_CNTR_BLK		cntrs;				
+	} PI_CMD_CNTRS_GET_RSP;
+
+/* Counters_Set Request */
+
+typedef struct
+	{
+	PI_UINT32	cmd_type;
+	PI_CNTR_BLK	cntrs;				
+	} PI_CMD_CNTRS_SET_REQ;
+
+/* Counters_Set Response */
+
+typedef struct 
+	{
+	PI_RSP_HEADER   header;	
+	} PI_CMD_CNTRS_SET_RSP;
+
+/* Error_Log_Clear Request */
+
+typedef struct
+	{
+	PI_UINT32  cmd_type;
+	} PI_CMD_ERROR_LOG_CLEAR_REQ;
+
+/* Error_Log_Clear Response */
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;	
+	} PI_CMD_ERROR_LOG_CLEAR_RSP;
+
+/* Error_Log_Get Request */
+
+#define PI_LOG_ENTRY_K_INDEX_MIN	0		/* Minimum index for entry */
+
+typedef struct
+	{
+	PI_UINT32  cmd_type;
+	PI_UINT32  entry_index;
+	} PI_CMD_ERROR_LOG_GET_REQ;
+
+/* Error_Log_Get Response */
+
+#define PI_K_LOG_FW_SIZE			111		/* Max number of fw longwords */
+#define PI_K_LOG_DIAG_SIZE	 		6		/* Max number of diag longwords */
+
+typedef struct
+	{
+	struct 
+		{
+		PI_UINT32	fru_imp_mask;
+		PI_UINT32	test_id;
+		PI_UINT32	reserved[PI_K_LOG_DIAG_SIZE];
+		} diag;
+	PI_UINT32		fw[PI_K_LOG_FW_SIZE];
+	} PI_LOG_ENTRY;
+
+typedef struct
+	{
+	PI_RSP_HEADER   header;	
+	PI_UINT32		event_status;
+	PI_UINT32		caller_id;
+	PI_UINT32		timestamp_l;
+	PI_UINT32		timestamp_h;
+	PI_UINT32		write_count;
+	PI_LOG_ENTRY	entry_info;
+	} PI_CMD_ERROR_LOG_GET_RSP;
+
+/* Define error log related constants and types.					*/
+/*   Not all of the caller id's can occur.  The only ones currently */
+/*   implemented are: none, selftest, mfg, fw, console				*/
+
+#define PI_LOG_EVENT_STATUS_K_VALID		0	/* Valid Event Status 		*/
+#define PI_LOG_EVENT_STATUS_K_INVALID	1	/* Invalid Event Status 	*/
+#define PI_LOG_CALLER_ID_K_NONE		 	0	/* No caller 				*/
+#define PI_LOG_CALLER_ID_K_SELFTEST	 	1	/* Normal power-up selftest */			
+#define PI_LOG_CALLER_ID_K_MFG		 	2	/* Mfg power-up selftest 	*/
+#define PI_LOG_CALLER_ID_K_ONLINE		3	/* On-line diagnostics 		*/
+#define PI_LOG_CALLER_ID_K_HW			4	/* Hardware 				*/
+#define PI_LOG_CALLER_ID_K_FW			5	/* Firmware 				*/
+#define PI_LOG_CALLER_ID_K_CNS_HW		6	/* CNS firmware 			*/
+#define PI_LOG_CALLER_ID_K_CNS_FW		7	/* CNS hardware 			*/
+#define PI_LOG_CALLER_ID_K_CONSOLE	 	8   /* Console Caller Id 		*/
+
+/*
+ *  Place all DMA commands in the following request and response structures
+ *  to simplify code.
+ */
+
+typedef union
+	{
+	PI_UINT32					cmd_type;
+	PI_CMD_START_REQ			start;
+	PI_CMD_FILTERS_SET_REQ		filter_set;
+	PI_CMD_FILTERS_GET_REQ		filter_get;
+	PI_CMD_CHARS_SET_REQ		char_set;
+	PI_CMD_ADDR_FILTER_SET_REQ	addr_filter_set;
+	PI_CMD_ADDR_FILTER_GET_REQ	addr_filter_get;
+	PI_CMD_STATUS_CHARS_GET_REQ	stat_char_get;
+	PI_CMD_CNTRS_GET_REQ		cntrs_get;
+	PI_CMD_CNTRS_SET_REQ		cntrs_set;
+	PI_CMD_ERROR_LOG_CLEAR_REQ	error_log_clear;
+	PI_CMD_ERROR_LOG_GET_REQ	error_log_read;
+	PI_CMD_SNMP_SET_REQ			snmp_set;
+	PI_CMD_FDDI_MIB_GET_REQ		fddi_mib_get;
+	PI_CMD_DEC_EXT_MIB_GET_REQ	dec_mib_get;
+	PI_CMD_SMT_MIB_SET_REQ		smt_mib_set;
+	PI_CMD_SMT_MIB_GET_REQ		smt_mib_get;
+	char						pad[PI_CMD_REQ_K_SIZE_MAX]; 
+	} PI_DMA_CMD_REQ;
+
+typedef union
+	{
+	PI_RSP_HEADER				header;
+	PI_CMD_START_RSP			start;
+	PI_CMD_FILTERS_SET_RSP		filter_set;
+	PI_CMD_FILTERS_GET_RSP		filter_get;
+	PI_CMD_CHARS_SET_RSP		char_set;
+	PI_CMD_ADDR_FILTER_SET_RSP	addr_filter_set;
+	PI_CMD_ADDR_FILTER_GET_RSP	addr_filter_get;
+	PI_CMD_STATUS_CHARS_GET_RSP	stat_char_get;
+	PI_CMD_CNTRS_GET_RSP		cntrs_get;
+	PI_CMD_CNTRS_SET_RSP		cntrs_set;
+	PI_CMD_ERROR_LOG_CLEAR_RSP	error_log_clear;
+	PI_CMD_ERROR_LOG_GET_RSP	error_log_get;
+	PI_CMD_SNMP_SET_RSP			snmp_set;
+	PI_CMD_FDDI_MIB_GET_RSP		fddi_mib_get;
+	PI_CMD_DEC_EXT_MIB_GET_RSP	dec_mib_get;
+	PI_CMD_SMT_MIB_SET_RSP		smt_mib_set;
+	PI_CMD_SMT_MIB_GET_RSP		smt_mib_get;
+	char						pad[PI_CMD_RSP_K_SIZE_MAX]; 
+	} PI_DMA_CMD_RSP;
+
+typedef union
+	{
+	PI_DMA_CMD_REQ	request;
+	PI_DMA_CMD_RSP	response;
+	} PI_DMA_CMD_BUFFER;
+
+
+/* Define format of Consumer Block (resident in host memory) */
+
+typedef struct
+	{
+	volatile PI_UINT32	xmt_rcv_data;
+	volatile PI_UINT32	reserved_1;
+	volatile PI_UINT32	smt_host;
+	volatile PI_UINT32	reserved_2;
+	volatile PI_UINT32	unsol;
+	volatile PI_UINT32	reserved_3;
+	volatile PI_UINT32	cmd_rsp;
+	volatile PI_UINT32	reserved_4;
+	volatile PI_UINT32	cmd_req;
+	volatile PI_UINT32	reserved_5;
+	} PI_CONSUMER_BLOCK;
+
+#define PI_CONS_M_RCV_INDEX			0x000000FF
+#define PI_CONS_M_XMT_INDEX			0x00FF0000
+#define PI_CONS_V_RCV_INDEX			0
+#define PI_CONS_V_XMT_INDEX			16
+
+/* Offsets into consumer block */
+
+#define PI_CONS_BLK_K_XMT_RCV		0x00
+#define PI_CONS_BLK_K_SMT_HOST		0x08
+#define PI_CONS_BLK_K_UNSOL			0x10
+#define PI_CONS_BLK_K_CMD_RSP		0x18
+#define PI_CONS_BLK_K_CMD_REQ		0x20
+
+/* Offsets into descriptor block */
+
+#define PI_DESCR_BLK_K_RCV_DATA		0x0000
+#define PI_DESCR_BLK_K_XMT_DATA		0x0800
+#define PI_DESCR_BLK_K_SMT_HOST 	0x1000
+#define PI_DESCR_BLK_K_UNSOL		0x1200
+#define PI_DESCR_BLK_K_CMD_RSP		0x1280
+#define PI_DESCR_BLK_K_CMD_REQ		0x1300	
+
+/* Define format of a rcv descr (Rcv Data, Cmd Rsp, Unsolicited, SMT Host)   */
+/*   Note a field has been added for later versions of the PDQ to allow for  */
+/*   finer granularity of the rcv buffer alignment.  For backwards		 	 */
+/*   compatibility, the two bits (which allow the rcv buffer to be longword  */
+/*   aligned) have been added at the MBZ bits.  To support previous drivers, */
+/*   the MBZ definition is left intact.									  	 */
+
+typedef struct
+	{
+	PI_UINT32	long_0;
+	PI_UINT32	long_1;
+	} PI_RCV_DESCR;
+
+#define	PI_RCV_DESCR_M_SOP	  		0x80000000
+#define PI_RCV_DESCR_M_SEG_LEN_LO 	0x60000000 
+#define PI_RCV_DESCR_M_MBZ	  		0x60000000 
+#define PI_RCV_DESCR_M_SEG_LEN		0x1F800000
+#define PI_RCV_DESCR_M_SEG_LEN_HI	0x1FF00000	  
+#define PI_RCV_DESCR_M_SEG_CNT	  	0x000F0000
+#define PI_RCV_DESCR_M_BUFF_HI	  	0x0000FFFF
+
+#define	PI_RCV_DESCR_V_SOP	  		31
+#define PI_RCV_DESCR_V_SEG_LEN_LO 	29
+#define PI_RCV_DESCR_V_MBZ	  		29
+#define PI_RCV_DESCR_V_SEG_LEN	  	23
+#define PI_RCV_DESCR_V_SEG_LEN_HI 	20	  
+#define PI_RCV_DESCR_V_SEG_CNT	  	16
+#define PI_RCV_DESCR_V_BUFF_HI	 	0
+
+/* Define the format of a transmit descriptor (Xmt Data, Cmd Req) */
+
+typedef struct
+	{
+	PI_UINT32	long_0;
+	PI_UINT32	long_1;
+	} PI_XMT_DESCR;
+
+#define	PI_XMT_DESCR_M_SOP			0x80000000
+#define PI_XMT_DESCR_M_EOP			0x40000000
+#define PI_XMT_DESCR_M_MBZ			0x20000000 
+#define PI_XMT_DESCR_M_SEG_LEN		0x1FFF0000
+#define PI_XMT_DESCR_M_BUFF_HI		0x0000FFFF
+
+#define	PI_XMT_DESCR_V_SOP			31
+#define	PI_XMT_DESCR_V_EOP			30
+#define PI_XMT_DESCR_V_MBZ			29
+#define PI_XMT_DESCR_V_SEG_LEN		16
+#define PI_XMT_DESCR_V_BUFF_HI		0
+
+/* Define format of the Descriptor Block (resident in host memory) */
+
+#define PI_RCV_DATA_K_NUM_ENTRIES			256
+#define PI_XMT_DATA_K_NUM_ENTRIES			256
+#define PI_SMT_HOST_K_NUM_ENTRIES			64
+#define PI_UNSOL_K_NUM_ENTRIES				16
+#define PI_CMD_RSP_K_NUM_ENTRIES			16
+#define PI_CMD_REQ_K_NUM_ENTRIES			16
+
+typedef struct
+	{
+	PI_RCV_DESCR  rcv_data[PI_RCV_DATA_K_NUM_ENTRIES];
+	PI_XMT_DESCR  xmt_data[PI_XMT_DATA_K_NUM_ENTRIES];
+	PI_RCV_DESCR  smt_host[PI_SMT_HOST_K_NUM_ENTRIES];
+	PI_RCV_DESCR  unsol[PI_UNSOL_K_NUM_ENTRIES];
+	PI_RCV_DESCR  cmd_rsp[PI_CMD_RSP_K_NUM_ENTRIES];
+	PI_XMT_DESCR  cmd_req[PI_CMD_REQ_K_NUM_ENTRIES];
+	} PI_DESCR_BLOCK;
+
+/* Define Port Registers - offsets from PDQ Base address */
+
+#define PI_PDQ_K_REG_PORT_RESET			0x00000000
+#define PI_PDQ_K_REG_HOST_DATA			0x00000004
+#define PI_PDQ_K_REG_PORT_CTRL			0x00000008
+#define PI_PDQ_K_REG_PORT_DATA_A		0x0000000C
+#define PI_PDQ_K_REG_PORT_DATA_B		0x00000010
+#define PI_PDQ_K_REG_PORT_STATUS		0x00000014
+#define PI_PDQ_K_REG_TYPE_0_STATUS 		0x00000018
+#define PI_PDQ_K_REG_HOST_INT_ENB	  	0x0000001C
+#define PI_PDQ_K_REG_TYPE_2_PROD_NOINT 	0x00000020
+#define PI_PDQ_K_REG_TYPE_2_PROD		0x00000024
+#define PI_PDQ_K_REG_CMD_RSP_PROD		0x00000028
+#define PI_PDQ_K_REG_CMD_REQ_PROD		0x0000002C
+#define PI_PDQ_K_REG_SMT_HOST_PROD   	0x00000030
+#define PI_PDQ_K_REG_UNSOL_PROD			0x00000034
+
+/* Port Control Register - Command codes for primary commands */
+
+#define PI_PCTRL_M_CMD_ERROR			0x8000
+#define PI_PCTRL_M_BLAST_FLASH			0x4000
+#define PI_PCTRL_M_HALT					0x2000
+#define PI_PCTRL_M_COPY_DATA			0x1000
+#define PI_PCTRL_M_ERROR_LOG_START		0x0800
+#define PI_PCTRL_M_ERROR_LOG_READ		0x0400
+#define PI_PCTRL_M_XMT_DATA_FLUSH_DONE	0x0200
+#define PI_PCTRL_M_INIT					0x0100
+#define PI_PCTRL_M_INIT_START		    0x0080
+#define PI_PCTRL_M_CONS_BLOCK			0x0040
+#define PI_PCTRL_M_UNINIT				0x0020
+#define PI_PCTRL_M_RING_MEMBER			0x0010
+#define PI_PCTRL_M_MLA					0x0008		
+#define PI_PCTRL_M_FW_REV_READ			0x0004
+#define PI_PCTRL_M_DEV_SPECIFIC			0x0002
+#define PI_PCTRL_M_SUB_CMD				0x0001
+
+/* Define sub-commands accessed via the PI_PCTRL_M_SUB_CMD command */
+
+#define PI_SUB_CMD_K_LINK_UNINIT		0x0001
+#define PI_SUB_CMD_K_BURST_SIZE_SET		0x0002
+#define PI_SUB_CMD_K_PDQ_REV_GET		0x0004
+#define PI_SUB_CMD_K_HW_REV_GET			0x0008
+
+/* Define some Port Data B values */
+
+#define PI_PDATA_B_DMA_BURST_SIZE_4	 	0		/* valid values for command */
+#define PI_PDATA_B_DMA_BURST_SIZE_8	 	1
+#define PI_PDATA_B_DMA_BURST_SIZE_16	2
+#define PI_PDATA_B_DMA_BURST_SIZE_32	3		/* not supported on PCI */
+#define PI_PDATA_B_DMA_BURST_SIZE_DEF	PI_PDATA_B_DMA_BURST_SIZE_16
+
+/* Port Data A Reset state */
+
+#define PI_PDATA_A_RESET_M_UPGRADE		0x00000001
+#define PI_PDATA_A_RESET_M_SOFT_RESET	0x00000002
+#define PI_PDATA_A_RESET_M_SKIP_ST		0x00000004
+
+/* Read adapter MLA address port control command constants */
+
+#define PI_PDATA_A_MLA_K_LO				0
+#define PI_PDATA_A_MLA_K_HI				1
+
+/* Byte Swap values for init command */
+
+#define PI_PDATA_A_INIT_M_DESC_BLK_ADDR			0x0FFFFE000
+#define PI_PDATA_A_INIT_M_RESERVED				0x000001FFC
+#define PI_PDATA_A_INIT_M_BSWAP_DATA			0x000000002 
+#define PI_PDATA_A_INIT_M_BSWAP_LITERAL			0x000000001
+
+#define PI_PDATA_A_INIT_V_DESC_BLK_ADDR			13
+#define PI_PDATA_A_INIT_V_RESERVED				3
+#define PI_PDATA_A_INIT_V_BSWAP_DATA			1 
+#define PI_PDATA_A_INIT_V_BSWAP_LITERAL			0
+
+/* Port Reset Register */
+
+#define PI_RESET_M_ASSERT_RESET			1
+
+/* Port Status register */
+
+#define PI_PSTATUS_V_RCV_DATA_PENDING	31
+#define PI_PSTATUS_V_XMT_DATA_PENDING	30
+#define PI_PSTATUS_V_SMT_HOST_PENDING	29
+#define PI_PSTATUS_V_UNSOL_PENDING		28
+#define PI_PSTATUS_V_CMD_RSP_PENDING	27
+#define PI_PSTATUS_V_CMD_REQ_PENDING	26
+#define PI_PSTATUS_V_TYPE_0_PENDING		25
+#define PI_PSTATUS_V_RESERVED_1			16
+#define PI_PSTATUS_V_RESERVED_2			11
+#define PI_PSTATUS_V_STATE				8
+#define PI_PSTATUS_V_HALT_ID			0
+
+#define PI_PSTATUS_M_RCV_DATA_PENDING	0x80000000
+#define PI_PSTATUS_M_XMT_DATA_PENDING	0x40000000
+#define PI_PSTATUS_M_SMT_HOST_PENDING	0x20000000
+#define PI_PSTATUS_M_UNSOL_PENDING		0x10000000
+#define PI_PSTATUS_M_CMD_RSP_PENDING	0x08000000
+#define PI_PSTATUS_M_CMD_REQ_PENDING	0x04000000
+#define PI_PSTATUS_M_TYPE_0_PENDING		0x02000000
+#define PI_PSTATUS_M_RESERVED_1			0x01FF0000
+#define PI_PSTATUS_M_RESERVED_2			0x0000F800
+#define PI_PSTATUS_M_STATE				0x00000700
+#define PI_PSTATUS_M_HALT_ID			0x000000FF
+
+/* Define Halt Id's			 					*/
+/*   Do not insert into this list, only append. */
+
+#define PI_HALT_ID_K_SELFTEST_TIMEOUT	0
+#define PI_HALT_ID_K_PARITY_ERROR		1
+#define PI_HALT_ID_K_HOST_DIR_HALT		2
+#define PI_HALT_ID_K_SW_FAULT			3
+#define PI_HALT_ID_K_HW_FAULT			4
+#define PI_HALT_ID_K_PC_TRACE			5
+#define PI_HALT_ID_K_DMA_ERROR			6			/* Host Data has error reg */
+#define PI_HALT_ID_K_IMAGE_CRC_ERROR	7   		/* Image is bad, update it */
+#define PI_HALT_ID_K_BUS_EXCEPTION	 	8   		/* 68K bus exception	   */
+
+/* Host Interrupt Enable Register as seen by host */ 
+
+#define PI_HOST_INT_M_XMT_DATA_ENB		0x80000000	/* Type 2 Enables */
+#define PI_HOST_INT_M_RCV_DATA_ENB		0x40000000  
+#define PI_HOST_INT_M_SMT_HOST_ENB		0x10000000	/* Type 1 Enables */ 
+#define PI_HOST_INT_M_UNSOL_ENB			0x20000000
+#define PI_HOST_INT_M_CMD_RSP_ENB		0x08000000
+#define PI_HOST_INT_M_CMD_REQ_ENB		0x04000000
+#define	PI_HOST_INT_M_TYPE_1_RESERVED	0x00FF0000
+#define	PI_HOST_INT_M_TYPE_0_RESERVED	0x0000FF00	/* Type 0 Enables */
+#define PI_HOST_INT_M_1MS				0x00000080
+#define PI_HOST_INT_M_20MS				0x00000040
+#define PI_HOST_INT_M_CSR_CMD_DONE		0x00000020
+#define PI_HOST_INT_M_STATE_CHANGE		0x00000010
+#define PI_HOST_INT_M_XMT_FLUSH			0x00000008
+#define PI_HOST_INT_M_NXM				0x00000004
+#define PI_HOST_INT_M_PM_PAR_ERR		0x00000002
+#define PI_HOST_INT_M_BUS_PAR_ERR		0x00000001
+
+#define PI_HOST_INT_V_XMT_DATA_ENB		31			/* Type 2 Enables */
+#define PI_HOST_INT_V_RCV_DATA_ENB		30  
+#define PI_HOST_INT_V_SMT_HOST_ENB		29			/* Type 1 Enables */ 
+#define PI_HOST_INT_V_UNSOL_ENB			28
+#define PI_HOST_INT_V_CMD_RSP_ENB		27
+#define PI_HOST_INT_V_CMD_REQ_ENB		26
+#define	PI_HOST_INT_V_TYPE_1_RESERVED	16
+#define	PI_HOST_INT_V_TYPE_0_RESERVED   8			/* Type 0 Enables */
+#define PI_HOST_INT_V_1MS_ENB			7
+#define PI_HOST_INT_V_20MS_ENB			6
+#define PI_HOST_INT_V_CSR_CMD_DONE_ENB	5
+#define PI_HOST_INT_V_STATE_CHANGE_ENB	4
+#define PI_HOST_INT_V_XMT_FLUSH_ENB 	3
+#define PI_HOST_INT_V_NXM_ENB			2
+#define PI_HOST_INT_V_PM_PAR_ERR_ENB	1
+#define PI_HOST_INT_V_BUS_PAR_ERR_ENB	0
+
+#define PI_HOST_INT_K_ACK_ALL_TYPE_0	0x000000FF
+#define PI_HOST_INT_K_DISABLE_ALL_INTS	0x00000000
+#define PI_HOST_INT_K_ENABLE_ALL_INTS	0xFFFFFFFF
+#define PI_HOST_INT_K_ENABLE_DEF_INTS	0xC000001F
+
+/* Type 0 Interrupt Status Register */
+
+#define PI_TYPE_0_STAT_M_1MS			0x00000080
+#define PI_TYPE_0_STAT_M_20MS			0x00000040
+#define PI_TYPE_0_STAT_M_CSR_CMD_DONE	0x00000020
+#define PI_TYPE_0_STAT_M_STATE_CHANGE	0x00000010
+#define PI_TYPE_0_STAT_M_XMT_FLUSH		0x00000008
+#define PI_TYPE_0_STAT_M_NXM			0x00000004
+#define PI_TYPE_0_STAT_M_PM_PAR_ERR		0x00000002
+#define PI_TYPE_0_STAT_M_BUS_PAR_ERR	0x00000001
+
+#define PI_TYPE_0_STAT_V_1MS			7			
+#define PI_TYPE_0_STAT_V_20MS			6	
+#define PI_TYPE_0_STAT_V_CSR_CMD_DONE	5
+#define PI_TYPE_0_STAT_V_STATE_CHANGE	4
+#define PI_TYPE_0_STAT_V_XMT_FLUSH		3
+#define PI_TYPE_0_STAT_V_NXM			2
+#define PI_TYPE_0_STAT_V_PM_PAR_ERR		1
+#define PI_TYPE_0_STAT_V_BUS_PAR_ERR	0
+
+/* Register definition structures are defined for both big and little endian systems */
+
+#ifndef  BIG_ENDIAN
+
+/* Little endian format of Type 1 Producer register */
+
+typedef union
+	{
+	PI_UINT32	lword;
+	struct
+		{
+		PI_UINT8	prod;
+		PI_UINT8	comp;
+		PI_UINT8	mbz_1;
+		PI_UINT8	mbz_2;
+		} index;
+	} PI_TYPE_1_PROD_REG;
+
+/* Little endian format of Type 2 Producer register */
+
+typedef union
+	{
+	PI_UINT32	lword;
+	struct
+		{
+		PI_UINT8	rcv_prod;
+		PI_UINT8	xmt_prod;
+		PI_UINT8	rcv_comp;
+		PI_UINT8	xmt_comp;
+		} index;
+	} PI_TYPE_2_PROD_REG;
+
+/* Little endian format of Type 1 Consumer Block longword */
+
+typedef union
+	{
+	PI_UINT32	lword;
+	struct
+		{
+		PI_UINT8	cons;
+		PI_UINT8	res0;
+		PI_UINT8	res1;
+		PI_UINT8	res2;
+		} index;
+	} PI_TYPE_1_CONSUMER;
+
+/* Little endian format of Type 2 Consumer Block longword */
+
+typedef union
+	{
+	PI_UINT32	lword;
+	struct
+		{
+		PI_UINT8	rcv_cons;
+		PI_UINT8	res0;
+		PI_UINT8	xmt_cons;
+		PI_UINT8	res1;
+		} index;
+	} PI_TYPE_2_CONSUMER;
+
+#else
+
+/* Big endian format of Type 1 Producer register */
+
+typedef union
+	{
+	PI_UINT32	lword;
+	struct
+		{
+		PI_UINT8	mbz_2;
+		PI_UINT8	mbz_1;
+		PI_UINT8	comp;
+		PI_UINT8	prod;
+		} index;
+	} PI_TYPE_1_PROD_REG;
+
+/* Big endian format of Type 2 Producer register */
+
+typedef union
+	{
+	PI_UINT32	lword;
+	struct
+		{
+		PI_UINT8	xmt_comp;
+		PI_UINT8	rcv_comp;
+		PI_UINT8	xmt_prod;
+		PI_UINT8	rcv_prod;
+		} index;
+	} PI_TYPE_2_PROD_REG;
+
+/* Big endian format of Type 1 Consumer Block longword */
+
+typedef union
+	{
+	PI_UINT32	lword;
+	struct
+		{
+		PI_UINT8	res2;
+		PI_UINT8	res1;
+		PI_UINT8	res0;
+		PI_UINT8	cons;
+		} index;
+	} PI_TYPE_1_CONSUMER;
+
+/* Big endian format of Type 2 Consumer Block longword */
+
+typedef union
+	{
+	PI_UINT32	lword;
+	struct
+		{
+		PI_UINT8	res1;
+		PI_UINT8	xmt_cons;
+		PI_UINT8	res0;
+		PI_UINT8	rcv_cons;
+		} index;
+	} PI_TYPE_2_CONSUMER;
+
+#endif	/* #ifndef BIG_ENDIAN */
+
+/* Define EISA controller register offsets */
+
+#define PI_ESIC_K_BURST_HOLDOFF			0x040
+#define PI_ESIC_K_SLOT_ID            	0xC80
+#define PI_ESIC_K_SLOT_CNTRL			0xC84
+#define PI_ESIC_K_MEM_ADD_CMP_0     	0xC85
+#define PI_ESIC_K_MEM_ADD_CMP_1     	0xC86
+#define PI_ESIC_K_MEM_ADD_CMP_2     	0xC87
+#define PI_ESIC_K_MEM_ADD_HI_CMP_0  	0xC88
+#define PI_ESIC_K_MEM_ADD_HI_CMP_1  	0xC89
+#define PI_ESIC_K_MEM_ADD_HI_CMP_2  	0xC8A
+#define PI_ESIC_K_MEM_ADD_MASK_0     	0xC8B
+#define PI_ESIC_K_MEM_ADD_MASK_1     	0xC8C
+#define PI_ESIC_K_MEM_ADD_MASK_2     	0xC8D
+#define PI_ESIC_K_MEM_ADD_LO_CMP_0  	0xC8E
+#define PI_ESIC_K_MEM_ADD_LO_CMP_1  	0xC8F
+#define PI_ESIC_K_MEM_ADD_LO_CMP_2  	0xC90
+#define PI_ESIC_K_IO_CMP_0_0			0xC91
+#define PI_ESIC_K_IO_CMP_0_1			0xC92
+#define PI_ESIC_K_IO_CMP_1_0			0xC93
+#define PI_ESIC_K_IO_CMP_1_1			0xC94
+#define PI_ESIC_K_IO_CMP_2_0			0xC95
+#define PI_ESIC_K_IO_CMP_2_1			0xC96
+#define PI_ESIC_K_IO_CMP_3_0			0xC97
+#define PI_ESIC_K_IO_CMP_3_1			0xC98
+#define PI_ESIC_K_IO_ADD_MASK_0_0    	0xC99
+#define PI_ESIC_K_IO_ADD_MASK_0_1    	0xC9A
+#define PI_ESIC_K_IO_ADD_MASK_1_0    	0xC9B
+#define PI_ESIC_K_IO_ADD_MASK_1_1    	0xC9C
+#define PI_ESIC_K_IO_ADD_MASK_2_0    	0xC9D
+#define PI_ESIC_K_IO_ADD_MASK_2_1    	0xC9E
+#define PI_ESIC_K_IO_ADD_MASK_3_0    	0xC9F
+#define PI_ESIC_K_IO_ADD_MASK_3_1    	0xCA0
+#define PI_ESIC_K_MOD_CONFIG_1			0xCA1
+#define PI_ESIC_K_MOD_CONFIG_2			0xCA2
+#define PI_ESIC_K_MOD_CONFIG_3			0xCA3
+#define PI_ESIC_K_MOD_CONFIG_4			0xCA4
+#define PI_ESIC_K_MOD_CONFIG_5    		0xCA5
+#define PI_ESIC_K_MOD_CONFIG_6			0xCA6
+#define PI_ESIC_K_MOD_CONFIG_7			0xCA7
+#define PI_ESIC_K_DIP_SWITCH         	0xCA8
+#define PI_ESIC_K_IO_CONFIG_STAT_0   	0xCA9
+#define PI_ESIC_K_IO_CONFIG_STAT_1   	0xCAA
+#define PI_ESIC_K_DMA_CONFIG         	0xCAB
+#define PI_ESIC_K_INPUT_PORT         	0xCAC
+#define PI_ESIC_K_OUTPUT_PORT        	0xCAD
+#define PI_ESIC_K_FUNCTION_CNTRL		0xCAE
+#define PI_ESIC_K_CSR_IO_LEN			PI_ESIC_K_FUNCTION_CNTRL+1	/* always last reg + 1 */
+
+/* Define the value all drivers must write to the function control register. */
+
+#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB	0x03
+
+/* Define the bits in the slot control register. */
+
+#define PI_SLOT_CNTRL_M_RESET		0x04	/* Don't use.       */
+#define PI_SLOT_CNTRL_M_ERROR		0x02	/* Not implemented. */
+#define PI_SLOT_CNTRL_M_ENB			0x01	/* Must be set.     */
+
+/* Define the bits in the burst holdoff register. */
+
+#define PI_BURST_HOLDOFF_M_HOLDOFF	0xFC
+#define PI_BURST_HOLDOFF_M_RESERVED	0x02
+#define PI_BURST_HOLDOFF_M_MEM_MAP	0x01
+
+#define PI_BURST_HOLDOFF_V_HOLDOFF	2
+#define PI_BURST_HOLDOFF_V_RESERVED	1
+#define PI_BURST_HOLDOFF_V_MEM_MAP	0
+
+/*
+ * Define the fields in the IO Compare registers.
+ * The driver must initialize the slot field with the slot ID shifted by the
+ * amount shown below.
+ */
+
+#define PI_IO_CMP_V_SLOT		4
+
+/* Define the fields in the Interrupt Channel Configuration and Status reg */
+
+#define PI_CONFIG_STAT_0_M_PEND			0x80
+#define PI_CONFIG_STAT_0_M_RES_1		0x40
+#define PI_CONFIG_STAT_0_M_IREQ_OUT		0x20
+#define PI_CONFIG_STAT_0_M_IREQ_IN		0x10
+#define PI_CONFIG_STAT_0_M_INT_ENB		0x08
+#define PI_CONFIG_STAT_0_M_RES_0		0x04
+#define PI_CONFIG_STAT_0_M_IRQ			0x03
+
+#define PI_CONFIG_STAT_0_V_PEND			7
+#define PI_CONFIG_STAT_0_V_RES_1		6
+#define PI_CONFIG_STAT_0_V_IREQ_OUT		5
+#define PI_CONFIG_STAT_0_V_IREQ_IN		4
+#define PI_CONFIG_STAT_0_V_INT_ENB		3
+#define PI_CONFIG_STAT_0_V_RES_0		2
+#define PI_CONFIG_STAT_0_V_IRQ			0
+
+#define PI_CONFIG_STAT_0_IRQ_K_9		0
+#define PI_CONFIG_STAT_0_IRQ_K_10		1
+#define PI_CONFIG_STAT_0_IRQ_K_11		2
+#define PI_CONFIG_STAT_0_IRQ_K_15		3
+
+/* Define DEC FDDIcontroller/EISA (DEFEA) EISA hardware ID's */
+
+#define DEFEA_PRODUCT_ID	0x0030A310		/* DEC product 300 (no rev)	*/
+#define DEFEA_PROD_ID_1		0x0130A310		/* DEC product 300, rev 1	*/
+#define DEFEA_PROD_ID_2		0x0230A310		/* DEC product 300, rev 2	*/
+#define DEFEA_PROD_ID_3		0x0330A310		/* DEC product 300, rev 3	*/
+
+/**********************************************/
+/* Digital PFI Specification v1.0 Definitions */
+/**********************************************/
+
+/* PCI Configuration Space Constants */
+
+#define PFI_K_LAT_TIMER_DEF			0x88	/* def max master latency timer */
+#define PFI_K_LAT_TIMER_MIN			0x20	/* min max master latency timer */
+#define PFI_K_CSR_MEM_LEN			0x80	/* 128 bytes */
+#define PFI_K_CSR_IO_LEN			0x80	/* 128 bytes */
+#define PFI_K_PKT_MEM_LEN			0x10000	/* 64K bytes */
+
+/* PFI Register Offsets (starting at PDQ Register Base Address) */
+
+#define PFI_K_REG_RESERVED_0		 0X00000038
+#define PFI_K_REG_RESERVED_1		 0X0000003C
+#define PFI_K_REG_MODE_CTRL			 0X00000040
+#define PFI_K_REG_STATUS			 0X00000044
+#define PFI_K_REG_FIFO_WRITE		 0X00000048
+#define PFI_K_REG_FIFO_READ			 0X0000004C
+
+/* PFI Mode Control Register Constants */
+
+#define PFI_MODE_M_RESERVED			 0XFFFFFFF0
+#define PFI_MODE_M_TGT_ABORT_ENB	 0X00000008
+#define PFI_MODE_M_PDQ_INT_ENB		 0X00000004
+#define PFI_MODE_M_PFI_INT_ENB		 0X00000002
+#define PFI_MODE_M_DMA_ENB			 0X00000001
+
+#define PFI_MODE_V_RESERVED			 4
+#define PFI_MODE_V_TGT_ABORT_ENB	 3
+#define PFI_MODE_V_PDQ_INT_ENB		 2
+#define PFI_MODE_V_PFI_INT_ENB		 1
+#define PFI_MODE_V_DMA_ENB			 0
+
+#define PFI_MODE_K_ALL_DISABLE		 0X00000000
+
+/* PFI Status Register Constants */
+
+#define PFI_STATUS_M_RESERVED		 0XFFFFFFC0
+#define PFI_STATUS_M_PFI_ERROR		 0X00000020		/* only valid in rev 1 or later PFI */
+#define PFI_STATUS_M_PDQ_INT		 0X00000010
+#define PFI_STATUS_M_PDQ_DMA_ABORT	 0X00000008
+#define PFI_STATUS_M_FIFO_FULL		 0X00000004
+#define PFI_STATUS_M_FIFO_EMPTY		 0X00000002
+#define PFI_STATUS_M_DMA_IN_PROGRESS 0X00000001
+
+#define PFI_STATUS_V_RESERVED		 6
+#define PFI_STATUS_V_PFI_ERROR		 5				/* only valid in rev 1 or later PFI */
+#define PFI_STATUS_V_PDQ_INT		 4
+#define PFI_STATUS_V_PDQ_DMA_ABORT	 3
+#define PFI_STATUS_V_FIFO_FULL		 2
+#define PFI_STATUS_V_FIFO_EMPTY		 1
+#define PFI_STATUS_V_DMA_IN_PROGRESS 0
+
+#define DFX_MAX_EISA_SLOTS		16			/* maximum number of EISA slots to scan */
+#define DFX_MAX_NUM_BOARDS		8			/* maximum number of adapters supported */
+
+#define DFX_BUS_TYPE_PCI		0			/* type code for DEC FDDIcontroller/PCI */
+#define DFX_BUS_TYPE_EISA		1			/* type code for DEC FDDIcontroller/EISA */
+
+#define DFX_FC_PRH2_PRH1_PRH0	0x54003820	/* Packet Request Header bytes + FC */
+#define DFX_PRH0_BYTE			0x20		/* Packet Request Header byte 0 */
+#define DFX_PRH1_BYTE			0x38		/* Packet Request Header byte 1 */
+#define DFX_PRH2_BYTE			0x00		/* Packet Request Header byte 2 */
+
+/* Driver routine status (return) codes */
+
+#define DFX_K_SUCCESS			0			/* routine succeeded */
+#define DFX_K_FAILURE			1			/* routine failed */
+#define DFX_K_OUTSTATE			2			/* bad state for command */
+#define DFX_K_HW_TIMEOUT		3			/* command timed out */
+
+/* Define LLC host receive buffer min/max/default values */
+
+#define RCV_BUFS_MIN	2					/* minimum pre-allocated receive buffers */
+#define RCV_BUFS_MAX	32					/* maximum pre-allocated receive buffers */
+#define RCV_BUFS_DEF	8					/* default pre-allocated receive buffers */
+
+/* Define offsets into FDDI LLC or SMT receive frame buffers - used when indicating frames */
+
+#define RCV_BUFF_K_DESCR	0				/* four byte FMC descriptor */
+#define RCV_BUFF_K_PADDING	4				/* three null bytes */
+#define RCV_BUFF_K_FC		7				/* one byte frame control */
+#define RCV_BUFF_K_DA		8				/* six byte destination address */
+#define RCV_BUFF_K_SA		14				/* six byte source address */
+#define RCV_BUFF_K_DATA		20				/* offset to start of packet data */
+
+/* Define offsets into FDDI LLC transmit frame buffers - used when sending frames */
+
+#define XMT_BUFF_K_FC		0				/* one byte frame control */
+#define XMT_BUFF_K_DA		1				/* six byte destination address */
+#define XMT_BUFF_K_SA		7				/* six byte source address */
+#define XMT_BUFF_K_DATA		13				/* offset to start of packet data */
+
+/*
+ * Macro evaluates to "value" aligned to "size" bytes.  Make sure that
+ * "size" is greater than 0 bytes.
+ */
+
+#define ALIGN(value,size) ((value + (size - 1)) & ~(size - 1))
+
+/* Macro for checking a "value" is within a specific range */
+
+#define IN_RANGE(value,low,high) ((value >= low) && (value <= high))
+
+/* Only execute special print call when debug driver was built */
+
+#ifdef DEFXX_DEBUG
+#define DBG_printk(args...) printk(## args)
+#else
+#define DBG_printk(args...)
+#endif
+
+/* Define constants for masking/unmasking interrupts */
+
+#define DFX_MASK_INTERRUPTS		1
+#define DFX_UNMASK_INTERRUPTS	0
+
+/* Define structure for driver transmit descriptor block */
+
+typedef struct
+	{
+	struct sk_buff	*p_skb;					/* ptr to skb */
+	} XMT_DRIVER_DESCR;
+
+typedef struct DFX_board_tag
+	{
+	/* Keep virtual and physical pointers to locked, physically contiguous memory */
+
+	PI_DESCR_BLOCK			*descr_block_virt;				/* PDQ descriptor block virt address */
+	u32						descr_block_phys;				/* PDQ descriptor block phys address */
+	PI_DMA_CMD_REQ			*cmd_req_virt;					/* Command request buffer virt address */
+	u32						cmd_req_phys;					/* Command request buffer phys address */
+	PI_DMA_CMD_RSP			*cmd_rsp_virt;					/* Command response buffer virt address */
+	u32						cmd_rsp_phys;					/* Command response buffer phys address */
+	char					*rcv_block_virt;				/* LLC host receive queue buf blk virt */
+	u32						rcv_block_phys;					/* LLC host receive queue buf blk phys */
+	PI_CONSUMER_BLOCK		*cons_block_virt;				/* PDQ consumer block virt address */
+	u32						cons_block_phys;				/* PDQ consumer block phys address */
+
+	/* Keep local copies of Type 1 and Type 2 register data */
+
+	PI_TYPE_1_PROD_REG		cmd_req_reg;					/* Command Request register */
+	PI_TYPE_1_PROD_REG		cmd_rsp_reg;					/* Command Response register */
+	PI_TYPE_2_PROD_REG		rcv_xmt_reg;					/* Type 2 (RCV/XMT) register */
+
+	/* Storage for unicast and multicast address entries in adapter CAM */
+
+	u8						uc_table[1*FDDI_K_ALEN];
+	u32						uc_count;						/* number of unicast addresses */
+	u8						mc_table[PI_CMD_ADDR_FILTER_K_SIZE*FDDI_K_ALEN];
+	u32						mc_count;						/* number of multicast addresses */
+
+	/* Current packet filter settings */
+
+	u32						ind_group_prom;					/* LLC individual & group frame prom mode */
+	u32						group_prom;						/* LLC group (multicast) frame prom mode */
+
+	/* Link available flag needed to determine whether to drop outgoing packet requests */
+
+	u32						link_available;					/* is link available? */
+
+	/* Resources to indicate reset type when resetting adapter */
+
+	u32						reset_type;						/* skip or rerun diagnostics */
+
+	/* Store pointers to receive buffers for queue processing code */
+
+	char					*p_rcv_buff_va[PI_RCV_DATA_K_NUM_ENTRIES];
+
+	/* Store pointers to transmit buffers for transmit completion code */
+
+	XMT_DRIVER_DESCR		xmt_drv_descr_blk[PI_XMT_DATA_K_NUM_ENTRIES];
+
+	/* Store device, bus-specific, and parameter information for this adapter */
+
+	struct device			*dev;							/* pointer to device structure */
+	u32						bus_type;						/* bus type (0 == PCI, 1 == EISA) */
+	u16						base_addr;						/* base I/O address (same as dev->base_addr) */
+	u8						pci_bus;						/* PCI bus number */
+	u8						pci_dev_fun;					/* PCI device and function numbers */
+	u32						full_duplex_enb;				/* FDDI Full Duplex enable (1 == on, 2 == off) */
+	u32						req_ttrt;						/* requested TTRT value (in 80ns units) */
+	u32						burst_size;						/* adapter burst size (enumerated) */
+	u32						rcv_bufs_to_post;				/* receive buffers to post for LLC host queue */
+	u8						factory_mac_addr[FDDI_K_ALEN];	/* factory (on-board) MAC address */
+
+	/* Common FDDI statistics structure and private counters */
+
+	struct fddi_statistics	stats;
+
+	u32						rcv_discards;
+	u32						rcv_crc_errors;
+	u32						rcv_frame_status_errors;
+	u32						rcv_length_errors;
+	u32						rcv_total_frames;
+	u32						rcv_multicast_frames;
+	u32						xmt_discards;
+	u32						xmt_length_errors;
+	u32						xmt_total_frames;
+	} DFX_board_t;
+
+#endif	/* #ifndef _DEFXX_H_ */
diff -u --recursive --new-file v2.0.23/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.0.23/linux/drivers/net/net_init.c	Sat Jun 29 12:00:46 1996
+++ linux/drivers/net/net_init.c	Wed Oct 30 03:42:40 1996
@@ -21,7 +21,12 @@
 		
 	Changed 29/10/95, Alan Cox to pass sockaddr's around for mac addresses.
 	
-	14/06/96 - Paul Gortmaker:	Add generic eth_change_mtu() function. 
+	14/06/96 - Paul Gortmaker:	Add generic eth_change_mtu() function.
+
+	August 12, 1996 - Lawrence V. Stefani: Added fddi_change_mtu() and
+					  fddi_setup() functions.
+	Sept. 10, 1996  - Lawrence V. Stefani: Increased hard_header_len to
+					  include 3 pad bytes.
 */
 
 #include <linux/config.h>
@@ -34,6 +39,7 @@
 #include <linux/string.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/fddidevice.h>
 #include <linux/trdevice.h>
 #include <linux/if_arp.h>
 #ifdef CONFIG_NET_ALIAS
@@ -154,6 +160,18 @@
 	return 0;
 }
 
+#ifdef CONFIG_FDDI
+
+static int fddi_change_mtu(struct device *dev, int new_mtu)
+	{
+	if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN))
+		return(-EINVAL);
+	dev->mtu = new_mtu;
+	return(0);
+	}
+
+#endif
+
 void ether_setup(struct device *dev)
 {
 	int i;
@@ -228,6 +246,43 @@
 	dev->pa_mask	= 0;
 	dev->pa_alen	= 4;
 }
+
+#endif
+
+#ifdef CONFIG_FDDI
+
+void fddi_setup(struct device *dev)
+	{
+	int i;
+
+	/*
+	 * Fill in the fields of the device structure with FDDI-generic values.
+	 * This should be in a common file instead of per-driver.
+	 */
+	for (i=0; i < DEV_NUMBUFFS; i++)
+		skb_queue_head_init(&dev->buffs[i]);
+
+	dev->change_mtu			= fddi_change_mtu;
+	dev->hard_header		= fddi_header;
+	dev->rebuild_header		= fddi_rebuild_header;
+
+	dev->type				= ARPHRD_FDDI;
+	dev->hard_header_len	= FDDI_K_SNAP_HLEN+3;	/* Assume 802.2 SNAP hdr len + 3 pad bytes */
+	dev->mtu				= FDDI_K_SNAP_DLEN;		/* Assume max payload of 802.2 SNAP frame */
+	dev->addr_len			= FDDI_K_ALEN;
+	dev->tx_queue_len		= 100;	/* Long queues on FDDI */
+	
+	memset(dev->broadcast, 0xFF, FDDI_K_ALEN);
+
+	/* New-style flags */
+	dev->flags		= IFF_BROADCAST | IFF_MULTICAST;
+	dev->family		= AF_INET;
+	dev->pa_addr	= 0;
+	dev->pa_brdaddr = 0;
+	dev->pa_mask	= 0;
+	dev->pa_alen	= 4;
+	return;
+	}
 
 #endif
 
diff -u --recursive --new-file v2.0.23/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.0.23/linux/drivers/net/ni65.c	Fri Apr 12 09:49:38 1996
+++ linux/drivers/net/ni65.c	Wed Oct 30 03:42:41 1996
@@ -1,8 +1,15 @@
 /*
- * ni6510 (am7990 'lance' chip) driver for Linux-net-3 by MH
- * Alphacode v0.51 (96/02/20) for 1.3.66 (or later)
+ * ni6510 (am7990 'lance' chip) driver for Linux-net-3
+ * BETAcode v0.70 (96/04/07) for 1.3.66 (or later)
+ * copyrights (c) 1994,1995,1996 by M.Hipp
+ * 
+ * This driver can handle the old ni6510 board and the newer ni6510 
+ * EtherBlaster. (probably it also works with every full NE2100 
+ * compatible card)
  *
- * copyright (c) 1994,1995,1996 by M.Hipp
+ * To compile as module, type:
+ *     gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ -DMODULE -c ni65.c
+ * driver probes: io: 0x360,0x300,0x320,0x340 / dma: 3,5,6,7
  *
  * This is an extension to the Linux operating system, and is covered by the
  * same Gnu Public License that covers the Linux-kernel.
@@ -18,18 +25,27 @@
  * known problems:
  *   on some PCI boards (including my own) the card/board/ISA-bridge has
  *   problems with bus master DMA. This results in lotsa overruns.
- *   It may help to '#define RCV_PARANOIA_CHECK'
- *   or just play with your BIOS options to optimize ISA-DMA access.
+ *   It may help to '#define RCV_PARANOIA_CHECK' or try to #undef
+ *   the XMT and RCV_VIA_SKB option .. this reduces driver performance.
+ *   Or just play with your BIOS options to optimize ISA-DMA access.
+ *   Maybe you also wanna play with the LOW_PERFORAMCE and MID_PERFORMANCE
+ *   defines -> please report me your experience then
  *
  * credits:
  *   thanx to Jason Sullivan for sending me a ni6510 card!
  *
- * simple performance test:
- *   8.1 seconds for getting a 8MB file via FTP -> near 1MB/s
+ * simple performance test: (486DX-33/Ni6510-EB receives from 486DX4-100/Ni6510-EB)
+ *    average: FTP -> 8384421 bytes received in 8.5 seconds
+ *           (no RCV_VIA_SKB,no XMT_VIA_SKB,PARANOIA_CHECK,4 XMIT BUFS, 8 RCV_BUFFS)
+ *    peak: FTP -> 8384421 bytes received in 7.5 seconds 
+ *           (RCV_VIA_SKB,XMT_VIA_SKB,no PARANOIA_CHECK,1(!) XMIT BUF, 16 RCV BUFFS)
  */
 
 /*
- * 96.Feb.19: fixed a few bugs .. cleanups .. tested for 1.3.66
+ * 96.April.13: enhanced error handling .. more tests (MH)
+ * 96.April.5/6: a lot of performance tests .. got it stable now (hopefully) (MH)
+ * 96.April.1: (no joke ;) .. added EtherBlaster and Module support (MH)
+ * 96.Feb.19: fixed a few bugs .. cleanups .. tested for 1.3.66 (MH)
  *            hopefully no more 16MB limit
  *
  * 95.Nov.18: multicast tweaked (AC).
@@ -56,75 +72,121 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+#include <linux/version.h>
+#include <linux/module.h>
+
 #include "ni65.h"
 
 /*
- * the current setting allows max. performance
+ * the current setting allows an acceptable performance
  * for 'RCV_PARANOIA_CHECK' read the 'known problems' part in 
  * the header of this file
+ * 'invert' the defines for max. performance. This may cause DMA problems
+ * on some boards (e.g on my ASUS SP3G)
  */
-#define RCV_VIA_SKB
-#undef RCV_PARANOIA_CHECK
 #define XMT_VIA_SKB
+#define RCV_VIA_SKB
+#define RCV_PARANOIA_CHECK
+
+#define MID_PERFORMANCE
+
+#if   defined( LOW_PERFORMANCE )
+ static int isa0=7,isa1=7,csr80=0x0c10;
+#elif defined( MID_PERFORMANCE )
+ static int isa0=5,isa1=5,csr80=0x2810;
+#else	/* high performance */
+ static int isa0=4,isa1=4,csr80=0x0017;
+#endif
 
 /*
- * a few card specific defines
+ * a few card/vendor specific defines
  */
-#define NI65_TOTAL_SIZE    16
-#define NI65_ADDR0 0x02
-#define NI65_ADDR1 0x07
-#define NI65_ADDR2 0x01
-#define NI65_ID0   0x00
-#define NI65_ID1   0x55
+#define NI65_ID0    0x00
+#define NI65_ID1    0x55
+#define NI65_EB_ID0 0x52
+#define NI65_EB_ID1 0x44
+#define NE2100_ID0  0x57
+#define NE2100_ID1  0x57
 
-#define PORT dev->base_addr
+#define PORT p->cmdr_addr
 
 /*
  * buffer configuration
  */
+#if 1
+#define RMDNUM 16
+#define RMDNUMMASK 0x80000000 
+#else
 #define RMDNUM 8
 #define RMDNUMMASK 0x60000000 /* log2(RMDNUM)<<29 */
-#define TMDNUM 4
-#define TMDNUMMASK 0x40000000 /* log2(TMDNUM)<<29 */
+#endif
 
-#define R_BUF_SIZE 1536
-#define T_BUF_SIZE 1536
+#if 1
+#define TMDNUM 1
+#define TMDNUMMASK 0x00000000 /* log2(TMDNUM)<<29 */
+#else
+#define TMDNUM 2
+#define TMDNUMMASK 0x20000000 /* log2(TMDNUM)<<29 */
+#endif
+
+/* slightly oversized */
+#define R_BUF_SIZE 1544
+#define T_BUF_SIZE 1544
 
 /*
  * lance register defines
  */
 #define L_DATAREG 0x00
 #define L_ADDRREG 0x02
-
 #define L_RESET   0x04
 #define L_CONFIG  0x05
-#define L_EBASE   0x08
+#define L_BUSIF   0x06
 
 /* 
- * to access the am7990-regs, you have to write
+ * to access the lance/am7990-regs, you have to write
  * reg-number into L_ADDRREG, then you can access it using L_DATAREG
  */
-#define CSR0 0x00
-#define CSR1 0x01
-#define CSR2 0x02
-#define CSR3 0x03
+#define CSR0  0x00
+#define CSR1  0x01
+#define CSR2  0x02
+#define CSR3  0x03
+
+#define INIT_RING_BEFORE_START	0x1
+#define FULL_RESET_ON_ERROR	0x2
 
+#if 0
 #define writereg(val,reg) {outw(reg,PORT+L_ADDRREG);inw(PORT+L_ADDRREG); \
                            outw(val,PORT+L_DATAREG);inw(PORT+L_DATAREG);}
 #define readreg(reg) (outw(reg,PORT+L_ADDRREG),inw(PORT+L_ADDRREG),\
                        inw(PORT+L_DATAREG))
+#if 0
 #define writedatareg(val) {outw(val,PORT+L_DATAREG);inw(PORT+L_DATAREG);}
+#else
+#define writedatareg(val) {  writereg(val,CSR0); }
+#endif
+#else
+#define writereg(val,reg) {outw(reg,PORT+L_ADDRREG);outw(val,PORT+L_DATAREG);}
+#define readreg(reg) (outw(reg,PORT+L_ADDRREG),inw(PORT+L_DATAREG))
+#define writedatareg(val) { writereg(val,CSR0); }
+#endif
 
-static int  ni65_probe1(struct device **dev,int);
-static void ni65_interrupt(int irq, void * dev_id, struct pt_regs *regs);
-static void ni65_recv_intr(struct device *dev,int);
-static void ni65_xmit_intr(struct device *dev,int);
-static int  ni65_open(struct device *dev);
-static int  ni65_am7990_reinit(struct device *dev);
-static int  ni65_send_packet(struct sk_buff *skb, struct device *dev);
-static int  ni65_close(struct device *dev);
-static struct enet_statistics *ni65_get_stats(struct device *);
-static void set_multicast_list(struct device *dev);
+static unsigned char ni_vendor[] = { 0x02,0x07,0x01 };
+
+static struct card {
+	unsigned char id0,id1;
+	short id_offset;
+	short total_size;
+	short cmd_offset;
+	short addr_offset;
+	unsigned char *vendor_id;
+	char *cardname;
+	unsigned char config;
+} cards[] = {
+	{ NI65_ID0,NI65_ID1,0x0e,0x10,0x0,0x8,ni_vendor,"ni6510", 0x1 } ,
+	{ NI65_EB_ID0,NI65_EB_ID1,0x0e,0x18,0x10,0x0,ni_vendor,"ni6510 EtherBlaster", 0x2 } ,
+	{ NE2100_ID0,NE2100_ID1,0x0e,0x18,0x10,0x0,NULL,"generic NE2100", 0x0 }
+};
+#define NUM_CARDS 3
 
 struct priv 
 {
@@ -142,132 +204,267 @@
   struct sk_buff *tmd_skb[TMDNUM];
 #endif
   void *tmdbounce[TMDNUM];
+  int tmdbouncenum;
   int lock,xmit_queued;
   struct enet_statistics stats;
+  void *self;
+  int cmdr_addr;
+  int cardno;
+  int features;
 }; 
 
+static int  ni65_probe1(struct device *dev,int);
+static void ni65_interrupt(int irq, void * dev_id, struct pt_regs *regs);
+static void ni65_recv_intr(struct device *dev,int);
+static void ni65_xmit_intr(struct device *dev,int);
+static int  ni65_open(struct device *dev);
+static int  ni65_lance_reinit(struct device *dev);
+static void ni65_init_lance(struct priv *p,unsigned char*,int,int);
+static int  ni65_send_packet(struct sk_buff *skb, struct device *dev);
+static int  ni65_close(struct device *dev);
+static int  ni65_alloc_buffer(struct device *dev);
+static void ni65_free_buffer(struct priv *p);
+static struct enet_statistics *ni65_get_stats(struct device *);
+static void set_multicast_list(struct device *dev);
+
 static int irqtab[] = { 9,12,15,5 }; /* irq config-translate */
-static int dmatab[] = { 0,3,5,6 };   /* dma config-translate */
-static int debuglevel = 0;
+static int dmatab[] = { 0,3,5,6,7 }; /* dma config-translate and autodetect */
+
+static int debuglevel = 1;
 
 /*
- * open (most done by init) 
+ * set 'performance' registers .. we must STOP lance for that
+ */
+static void ni65_set_performance(struct priv *p)
+{
+  writereg(CSR0_STOP | CSR0_CLRALL,CSR0); /* STOP */
+
+  if(!test_bit(1,&cards[p->cardno].config))
+    return;
+ 
+  outw(80,PORT+L_ADDRREG);
+  if(inw(PORT+L_ADDRREG) != 80)
+    return;
+ 
+  writereg( (csr80 & 0x3fff) ,80); /* FIFO watermarks */
+  outw(0,PORT+L_ADDRREG);
+  outw((short)isa0,PORT+L_BUSIF); /* write ISA 0: DMA_R : isa0 * 50ns */
+  outw(1,PORT+L_ADDRREG);
+  outw((short)isa1,PORT+L_BUSIF); /* write ISA 1: DMA_W : isa1 * 50ns  */
+
+  outw(CSR0,PORT+L_ADDRREG);	/* switch back to CSR0 */
+}
+
+/*
+ * open interface (up)
  */
 static int ni65_open(struct device *dev)
 {
-  if(ni65_am7990_reinit(dev))
+  struct priv *p = (struct priv *) dev->priv;
+  int irqval = request_irq(dev->irq, &ni65_interrupt,0,
+                        cards[p->cardno].cardname,NULL);
+  if (irqval) {
+    printk ("%s: unable to get IRQ %d (irqval=%d).\n", 
+              dev->name,dev->irq, irqval);
+    return -EAGAIN;
+  }
+  irq2dev_map[dev->irq] = dev;
+
+  if(ni65_lance_reinit(dev))
   {
     dev->tbusy     = 0;
     dev->interrupt = 0;
     dev->start     = 1;
+    MOD_INC_USE_COUNT;
     return 0;
   }
   else
   {
+    irq2dev_map[dev->irq] = NULL;
+    free_irq(dev->irq,NULL);
     dev->start = 0;
     return -EAGAIN;
   }
 }
 
+/*
+ * close interface (down)
+ */
 static int ni65_close(struct device *dev)
 {
-  outw(0,PORT+L_RESET); /* that's the hard way */
+  struct priv *p = (struct priv *) dev->priv;
+
+  outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
+
+#ifdef XMT_VIA_SKB
+  {
+    int i;
+    for(i=0;i<TMDNUM;i++)
+    {
+      if(p->tmd_skb[i]) {
+        dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+        p->tmd_skb[i] = NULL;
+      }
+    }
+  }
+#endif
+  irq2dev_map[dev->irq] = NULL;
+  free_irq(dev->irq,NULL);
   dev->tbusy = 1;
   dev->start = 0;
+  MOD_DEC_USE_COUNT;
   return 0; 
 }
 
 /* 
  * Probe The Card (not the lance-chip) 
- * and set hardaddress
  */ 
+#ifdef MODULE
+static
+#endif
 int ni65_probe(struct device *dev)
 {
   int *port;
-  static int ports[] = {0x300,0x320,0x340,0x360, 0};
+  static int ports[] = {0x360,0x300,0x320,0x340, 0};
 
-  if(dev) {
-    int base_addr = dev->base_addr;
-    if (base_addr > 0x1ff)          /* Check a single specified location. */
-       return ni65_probe1(&dev, base_addr);
-    else if (base_addr > 0)         /* Don't probe at all. */
-       return -ENXIO;
-    dev->base_addr = base_addr;
-  }
+  if (dev->base_addr > 0x1ff)          /* Check a single specified location. */
+     return ni65_probe1(dev, dev->base_addr);
+  else if (dev->base_addr > 0)         /* Don't probe at all. */
+     return -ENXIO;
 
   for (port = ports; *port; port++) 
   {
-    int ioaddr = *port;
-
-    if (check_region(ioaddr, NI65_TOTAL_SIZE))
-       continue;
-    if( !(inb(ioaddr+L_EBASE+6) == NI65_ID0) || 
-        !(inb(ioaddr+L_EBASE+7) == NI65_ID1) )
-       continue;
-    if (ni65_probe1(&dev, ioaddr) == 0)
+    if (ni65_probe1(dev, *port) == 0)
        return 0;
   }
 
   return -ENODEV;
 }
 
-int ni65_init(void)
-{
-        ni65_probe(NULL);
-        return 0;
-}
-
-static int ni65_probe1(struct device **dev1,int ioaddr)
+/*
+ * this is the real card probe .. 
+ */
+static int ni65_probe1(struct device *dev,int ioaddr)
 {
-  int i;
-  unsigned char *ptr;
+  int i,j;
   struct priv *p; 
-  struct device *dev = *dev1;
-
-  if(inb(ioaddr+L_EBASE+0) != NI65_ADDR0 || inb(ioaddr+L_EBASE+1) != NI65_ADDR1 
-      || inb(ioaddr+L_EBASE+2) != NI65_ADDR2)
-  {
-    printk("%s: wrong Hardaddress \n",dev ? dev->name : "ni6510" );
-    return -ENODEV;
-  }
 
-  if(!dev) {
-    dev = init_etherdev(0,0);
-    *dev1 = dev;
+  for(i=0;i<NUM_CARDS;i++) {
+    if(check_region(ioaddr, cards[i].total_size))
+      continue;
+    if(cards[i].id_offset >= 0) {
+      if(inb(ioaddr+cards[i].id_offset+0) != cards[i].id0 ||
+         inb(ioaddr+cards[i].id_offset+1) != cards[i].id1) {
+         continue;
+      }
+    }
+    if(cards[i].vendor_id) {
+      for(j=0;j<3;j++)
+        if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j])
+          continue;
+    }
+    break;
   }
-  dev->base_addr = ioaddr;
+  if(i == NUM_CARDS)
+    return -ENODEV;
 
-  for(i=0;i<6;i++)
-    dev->dev_addr[i] = inb(PORT+L_EBASE+i);
+  for(j=0;j<6;j++)
+    dev->dev_addr[j] = inb(ioaddr+cards[i].addr_offset+j);
 
-  if(dev->irq == 0) 
-    dev->irq = irqtab[(inw(PORT+L_CONFIG)>>2)&3];
-  if(dev->dma == 0)  
-    dev->dma = dmatab[inw(PORT+L_CONFIG)&3];
-
-  printk("%s: %s found at %#3lx, IRQ %d DMA %d.\n", dev->name,
-           "ni6510", dev->base_addr, dev->irq,dev->dma);
-
-  {        
-    int irqval = request_irq(dev->irq, &ni65_interrupt,0,"ni6510",NULL);
-    if (irqval) {
-      printk ("%s: unable to get IRQ %d (irqval=%d).\n", 
-                dev->name,dev->irq, irqval);
-      return -EAGAIN;
+  if( (j=ni65_alloc_buffer(dev)) < 0)
+    return j;
+  p = (struct priv *) dev->priv;
+  p->cmdr_addr = ioaddr + cards[i].cmd_offset;
+  p->cardno = i;
+
+  printk("%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr);
+
+  outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
+  if( (j=readreg(CSR0)) != 0x4) {
+     printk(KERN_ERR "can't RESET card: %04x\n",j);
+     ni65_free_buffer(p);
+     return -EAGAIN;
+  }
+
+  outw(88,PORT+L_ADDRREG);
+  if(inw(PORT+L_ADDRREG) == 88) {
+    unsigned long v;
+    v = inw(PORT+L_DATAREG);
+    v <<= 16;
+    outw(89,PORT+L_ADDRREG);
+    v |= inw(PORT+L_DATAREG);
+    printk("Version %#08lx, ",v);
+    p->features = INIT_RING_BEFORE_START;
+  }
+  else {
+    printk("ancient LANCE, ");
+    p->features = 0x0;
+  }
+
+  if(test_bit(0,&cards[i].config)) {
+    dev->irq = irqtab[(inw(ioaddr+L_CONFIG)>>2)&3];
+    dev->dma = dmatab[inw(ioaddr+L_CONFIG)&3];
+    printk("IRQ %d (from card), DMA %d (from card).\n",dev->irq,dev->dma);
+  }
+  else {
+    if(dev->dma == 0) {
+		/* 'stuck test' from lance.c */
+      int dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0);
+      for(i=1;i<5;i++) {
+        int dma = dmatab[i];
+        if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))
+          continue;
+        disable_dma(dma);
+        set_dma_mode(dma,DMA_MODE_CASCADE);
+        enable_dma(dma);
+        ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */
+        disable_dma(dma);
+        free_dma(dma);
+        if(readreg(CSR0) & CSR0_IDON)
+          break;
+      }
+      if(i == 5) {
+        printk("Can't detect DMA channel!\n");
+        ni65_free_buffer(p);
+        return -EAGAIN;
+      }
+      dev->dma = dmatab[i];
+      printk("DMA %d (autodetected), ",dev->dma);
     }
-    if(request_dma(dev->dma, "ni6510") != 0)
+    else
+      printk("DMA %d (assigned), ",dev->dma);
+
+    if(dev->irq < 2)
     {
-      printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
-      free_irq(dev->irq,NULL);
-      return -EAGAIN;
+      ni65_init_lance(p,dev->dev_addr,0,0);
+      autoirq_setup(0);
+      writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */
+
+      if(!(dev->irq = autoirq_report(2)))
+      {
+        printk("Failed to detect IRQ line!\n");
+        ni65_free_buffer(p);
+        return -EAGAIN;
+      }
+      printk("IRQ %d (autodetected).\n",dev->irq);
     }
+    else
+      printk("IRQ %d (assigned).\n",dev->irq);
+  }
+
+  if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0)
+  {
+    printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
+    ni65_free_buffer(p);
+    return -EAGAIN;
   }
-  irq2dev_map[dev->irq] = dev;
 
   /* 
-   * Grab the region so we can find another board if autoIRQ fails. 
+   * Grab the region so we can find another board. 
    */
-  request_region(ioaddr,NI65_TOTAL_SIZE,"ni6510");
+  request_region(ioaddr,cards[p->cardno].total_size,cards[p->cardno].cardname);
+
+  dev->base_addr = ioaddr;
 
   dev->open               = ni65_open;
   dev->stop               = ni65_close;
@@ -281,75 +478,238 @@
   dev->tbusy          = 0;
   dev->start          = 0;
 
+  return 0; /* everything is OK */
+}
+
+/*
+ * set lance register and trigger init 
+ */
+static void ni65_init_lance(struct priv *p,unsigned char *daddr,int filter,int mode) 
+{
+  int i;
+
+  writereg(CSR0_CLRALL|CSR0_STOP,CSR0);
+
+  for(i=0;i<6;i++)
+    p->ib.eaddr[i] = daddr[i];
+
+  for(i=0;i<8;i++)
+    p->ib.filter[i] = filter;
+  p->ib.mode = mode;
+
+  p->ib.trp = (unsigned long) p->tmdhead | TMDNUMMASK;
+  p->ib.rrp = (unsigned long) p->rmdhead | RMDNUMMASK;
+  writereg(0,CSR3);  /* busmaster/no word-swap */
+  writereg((unsigned short) (((unsigned long) &(p->ib)) & 0xffff),CSR1);
+  writereg((unsigned short) (((unsigned long) &(p->ib))>>16),CSR2);
+
+  writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */
+
+  for(i=0;i<32;i++)
+  {
+    udelay(4000);
+    if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) )
+      break; /* init ok ? */
+  }
+}
+
+/*
+ * allocate memory area and check the 16MB border
+ */
+static void *ni65_alloc_mem(struct device *dev,char *what,int size,int type)
+{
+  struct sk_buff *skb=NULL;
+  unsigned char *ptr;
+  void *ret;
+
+  if(type) {
+    ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA);
+    if(!skb) {
+      printk("%s: unable to allocate %s memory.\n",dev->name,what);
+      return NULL;
+    }
+    skb->dev = dev;
+    skb_reserve(skb,2+16);
+    skb_put(skb,R_BUF_SIZE);   /* grab the whole space .. (not necessary) */
+    ptr = skb->data;
+  }
+  else {
+    ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA);
+    if(!ret) {
+      printk("%s: unable to allocate %s memory.\n",dev->name,what);
+      return NULL;
+    }
+  }
+  if( (unsigned long) (ptr+size) > 0x1000000) {
+    printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what);
+    if(type)
+      kfree_skb(skb,FREE_WRITE);
+    else
+      kfree(ptr);
+    return NULL;
+  }
+  return ret;
+}
+
+/*
+ * allocate all memory structures .. send/recv buffers etc ...
+ */
+static int ni65_alloc_buffer(struct device *dev)
+{
+  unsigned char *ptr;
+  struct priv *p;
+  int i;
+ 
   /* 
    * we need 8-aligned memory ..
    */
-  ptr = kmalloc(sizeof(struct priv)+8,GFP_KERNEL|GFP_DMA);
+  ptr = ni65_alloc_mem(dev,"BUFFER",sizeof(struct priv)+8,0);
   if(!ptr)
     return -ENOMEM;
-  ptr = (unsigned char *) (((unsigned long) ptr + 7) & ~0x7);
-  if( (unsigned long) ptr + sizeof(struct priv) > 0x1000000) {
-    printk("%s: Can't alloc buffer in lower 16MB!\n",dev->name);
-    return -EAGAIN;
-  }
-  p = dev->priv = (struct priv *) ptr;
+
+  p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7);
   memset((char *) dev->priv,0,sizeof(struct priv));
+  p->self = ptr;
 
   for(i=0;i<TMDNUM;i++)
   {
-    if( (ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA )) == NULL) {
-      printk("%s: Can't alloc Xmit-Mem.\n",dev->name);
+#ifdef XMT_VIA_SKB
+    p->tmd_skb[i] = NULL;
+#endif
+    p->tmdbounce[i] = ni65_alloc_mem(dev,"XMIT",T_BUF_SIZE,0);
+    if(!p->tmdbounce[i]) {
+      ni65_free_buffer(p);
+      return -ENOMEM;
+    }
+  }
+
+  for(i=0;i<RMDNUM;i++)
+  {
+#ifdef RCV_VIA_SKB
+    p->recv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1);
+    if(!p->recv_skb[i]) {
+      ni65_free_buffer(p);
       return -ENOMEM;
     }
-    if( (unsigned long) (ptr+T_BUF_SIZE) > 0x1000000) {
-      printk("%s: Can't alloc Xmit-Mem in lower 16MB!\n",dev->name);
-      return -EAGAIN;
+#else
+    p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0);
+    if(!p->recvbounce[i]) {
+      ni65_free_buffer(p);
+      return -ENOMEM;
     }
-    p->tmdbounce[i] = ptr;
+#endif
+  }
+
+  return 0; /* everything is OK */
+}
+
+/*
+ * free buffers and private struct 
+ */
+static void ni65_free_buffer(struct priv *p)
+{
+  int i;
+
+  if(!p)
+    return;
+
+  for(i=0;i<TMDNUM;i++) {
+    if(p->tmdbounce[i])
+      kfree(p->tmdbounce[i]);
 #ifdef XMT_VIA_SKB
-    p->tmd_skb[i] = NULL;
+    if(p->tmd_skb[i])
+      dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
 #endif
   }
 
+  for(i=0;i<RMDNUM;i++)
+  {
 #ifdef RCV_VIA_SKB
-   for(i=0;i<RMDNUM;i++)
-   {
-     struct sk_buff *skb;
-     if( !(skb = dev_alloc_skb(R_BUF_SIZE+2)) ) {
-       printk("%s: unable to alloc recv-mem\n",dev->name);
-       return -ENOMEM;
-     }
-     skb->dev = dev;
-     skb_reserve(skb,2);
-     skb_put(skb,R_BUF_SIZE);	/* grab the whole space .. (not necessary) */
-     if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000 ) {
-       printk("%s: unable to alloc receive-memory in lower 16MB!\n",dev->name);
-       return -EAGAIN;
-     }
-     p->recv_skb[i] = skb;
-   }
+    if(p->recv_skb[i])
+      dev_kfree_skb(p->recv_skb[i],FREE_WRITE);
 #else
-   for(i=0;i<RMDNUM;i++)
-   {
-     if( !(p->recvbounce[i] = kmalloc(R_BUF_SIZE,GFP_KERNEL | GFP_DMA )) ) {
-       printk("%s: unable to alloc recv-mem\n",dev->name);
-       return -ENOMEM;
-     }
-     if( (unsigned long) p->recvbounce[i] + R_BUF_SIZE > 0x1000000 ) {
-       printk("%s: unable to alloc receive-memory in lower 16MB!\n",dev->name);
-       return -EAGAIN;
-     }
-   }
+    if(p->recvbounce[i])
+      kfree(p->recvbounce[i]);
+#endif
+  }
+  if(p->self)
+    kfree(p->self);
+}
+
+
+/*
+ * stop and (re)start lance .. e.g after an error
+ */
+static void ni65_stop_start(struct device *dev,struct priv *p)
+{
+  int csr0 = CSR0_INEA;
+
+  writedatareg(CSR0_STOP);
+
+  if(debuglevel > 1)
+    printk("ni65_stop_start\n");
+
+  if(p->features & INIT_RING_BEFORE_START) {
+    int i;
+#ifdef XMT_VIA_SKB
+    struct sk_buff *skb_save[TMDNUM];
+#endif
+    unsigned long buffer[TMDNUM];
+    short blen[TMDNUM];
+
+    if(p->xmit_queued) {
+      while(1) {
+        if((p->tmdhead[p->tmdlast].u.s.status & XMIT_OWN))
+          break;
+        p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
+        if(p->tmdlast == p->tmdnum)
+          break;
+      }
+    }
+    
+    for(i=0;i<TMDNUM;i++) {
+      struct tmd *tmdp = p->tmdhead + i;
+#ifdef XMT_VIA_SKB
+      skb_save[i] = p->tmd_skb[i];
 #endif
+      buffer[i] = tmdp->u.buffer;
+      blen[i] = tmdp->blen;
+      tmdp->u.s.status = 0x0;
+    }
 
-  return 0; /* we've found everything */
+    for(i=0;i<RMDNUM;i++) {
+      struct rmd *rmdp = p->rmdhead + i;
+      rmdp->u.s.status = RCV_OWN;
+    }
+    p->tmdnum = p->xmit_queued = 0;
+    writedatareg(CSR0_STRT | csr0);
+
+    for(i=0;i<TMDNUM;i++) {
+      int num = (i + p->tmdlast) & (TMDNUM-1);
+      p->tmdhead[i].u.buffer = buffer[num]; /* status is part of buffer field */
+      p->tmdhead[i].blen = blen[num];
+      if(p->tmdhead[i].u.s.status & XMIT_OWN) {
+	 p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
+         p->xmit_queued = 1;
+	 writedatareg(CSR0_TDMD | CSR0_INEA | csr0);
+      }
+#ifdef XMT_VIA_SKB
+      p->tmd_skb[i] = skb_save[num];
+#endif
+    }
+    p->rmdnum = p->tmdlast = 0;
+    if(!p->lock)
+      dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1;
+    dev->trans_start = jiffies;
+  } 
+  else
+    writedatareg(CSR0_STRT | csr0);
 }
 
 /* 
  * init lance (write init-values .. init-buffers) (open-helper)
  */
-
-static int ni65_am7990_reinit(struct device *dev)
+static int ni65_lance_reinit(struct device *dev)
 {
    int i;
    struct priv *p = (struct priv *) dev->priv;
@@ -361,17 +721,16 @@
    set_dma_mode(dev->dma,DMA_MODE_CASCADE);
    enable_dma(dev->dma); 
 
-   outw(0,PORT+L_RESET); /* first: reset the card */
-   if(inw(PORT+L_DATAREG) != 0x4)
+   outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
+   if( (i=readreg(CSR0) ) != 0x4)
    {
-     printk(KERN_ERR "%s: can't RESET ni6510 card: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
+     printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name,
+              cards[p->cardno].cardname,(int) i);
      disable_dma(dev->dma);
-     free_dma(dev->dma);
-     free_irq(dev->irq, NULL);
      return 0;
    }
 
-   p->tmdnum = 0; p->tmdlast = 0;
+   p->rmdnum = p->tmdnum = p->tmdlast = p->tmdbouncenum = 0;
    for(i=0;i<TMDNUM;i++)
    {
      struct tmd *tmdp = p->tmdhead + i;
@@ -386,7 +745,6 @@
      tmdp->blen = tmdp->status2 = 0;
    }
 
-   p->rmdnum = 0;
    for(i=0;i<RMDNUM;i++)
    {
      struct rmd *rmdp = p->rmdhead + i;
@@ -400,52 +758,27 @@
      rmdp->u.s.status = RCV_OWN;
    }
    
-   for(i=0;i<6;i++)
-     p->ib.eaddr[i] = dev->dev_addr[i];
-
-   for(i=0;i<8;i++)
-     p->ib.filter[i] = 0x0;
-   p->ib.mode = 0x0;
-
-   if(dev->flags & IFF_PROMISC) {
-     p->ib.mode = M_PROM;
-   }
-   else if(dev->mc_count || dev->flags & IFF_ALLMULTI) {
-     for(i=0;i<8;i++)
-       p->ib.filter[i] = 0xff;
-   }
-
-   p->ib.trp = (unsigned long) p->tmdhead | TMDNUMMASK;
-   p->ib.rrp = (unsigned long) p->rmdhead | RMDNUMMASK;
-
-   writereg(0,CSR3);  /* busmaster/no word-swap */
-   writereg((unsigned short) (((unsigned long) &(p->ib)) & 0xffff),CSR1);
-   writereg((unsigned short) (((unsigned long) &(p->ib))>>16),CSR2);
-
-   writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */
+   if(dev->flags & IFF_PROMISC)
+     ni65_init_lance(p,dev->dev_addr,0x00,M_PROM);
+   else if(dev->mc_count || dev->flags & IFF_ALLMULTI)
+     ni65_init_lance(p,dev->dev_addr,0xff,0x0);
+   else 
+     ni65_init_lance(p,dev->dev_addr,0x00,0x00);
 
   /*
+   * ni65_set_lance_mem() sets L_ADDRREG to CSR0
    * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED 
    */
 
-    for(i=0;i<32;i++)
-    {
-      __delay((loops_per_sec>>8)); /* wait a while */
-      if(inw(PORT+L_DATAREG) & CSR0_IDON) 
-        break; /* init ok ? */
-    }
-    if(i == 32) 
-    {
-      printk(KERN_ERR "%s: can't init am7990/lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
-      disable_dma(dev->dma);
-      free_dma(dev->dma);
-      free_irq(dev->irq, NULL);
-      return 0; /* false */
-    } 
-
-    writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT); /* start lance , enable interrupts */
-
-    return 1; /* OK */
+   if(inw(PORT+L_DATAREG) & CSR0_IDON)  {
+     ni65_set_performance(p);
+           /* init OK: start lance , enable interrupts */
+     writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT);
+     return 1; /* ->OK */
+   }
+   printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
+   disable_dma(dev->dma);
+   return 0; /* ->Error */
 }
  
 /* 
@@ -455,6 +788,7 @@
 {
   int csr0;
   struct device *dev = (struct device *) irq2dev_map[irq];
+  struct priv *p;
   int bcnt = 32;
 
   if (dev == NULL) {
@@ -462,62 +796,104 @@
     return;
   }
 
-  dev->interrupt = 1;
+  if(set_bit(0,(int *) &dev->interrupt)) {
+    printk("ni65: oops .. interrupt while proceeding interrupt\n");
+    return;
+  }
+  p = (struct priv *) dev->priv;
 
   while(--bcnt) {
-
     csr0 = inw(PORT+L_DATAREG);
-    writedatareg(csr0 & CSR0_CLRALL); /* ack interrupts, disable int. */
+
+#if 0
+    writedatareg( (csr0 & CSR0_CLRALL) ); /* ack interrupts, disable int. */
+#else
+    writedatareg( (csr0 & CSR0_CLRALL) | CSR0_INEA ); /* ack interrupts, interrupts enabled */
+#endif
 
     if(!(csr0 & (CSR0_ERR | CSR0_RINT | CSR0_TINT)))
       break;
 
+    if(csr0 & CSR0_RINT) /* RECV-int? */
+      ni65_recv_intr(dev,csr0);
+    if(csr0 & CSR0_TINT) /* XMIT-int? */
+      ni65_xmit_intr(dev,csr0);
+
     if(csr0 & CSR0_ERR)
     {
       struct priv *p = (struct priv *) dev->priv;
-
+      if (debuglevel > 1)
+	printk("%s: general error: %04x.\n",dev->name,csr0);
       if(csr0 & CSR0_BABL)
         p->stats.tx_errors++;
-      if(csr0 & CSR0_MISS)
+      if(csr0 & CSR0_MISS) {
+        int i;
+        for(i=0;i<RMDNUM;i++)
+          printk("%02x ",p->rmdhead[i].u.s.status);
+        printk("\n");
         p->stats.rx_errors++;
+      }
       if(csr0 & CSR0_MERR) {
-        writedatareg(CSR0_STOP);
-        writedatareg(CSR0_STRT);
+	if (debuglevel > 1)
+	  printk("%s: Ooops .. memory error: %04x.\n",dev->name,csr0);
+        ni65_stop_start(dev,p);
       }
     }
-    if(csr0 & CSR0_RINT) /* RECV-int? */
-      ni65_recv_intr(dev,csr0);
-    if(csr0 & CSR0_TINT) /* XMIT-int? */
-      ni65_xmit_intr(dev,csr0);
   }
 
 #ifdef RCV_PARANOIA_CHECK
 {
+ int j;
+ for(j=0;j<RMDNUM;j++)
+ {
   struct priv *p = (struct priv *) dev->priv;
-  int i,f=0;
-  for(i=0;i<RMDNUM;i++) {
-     struct rmd *rmdp = p->rmdhead + ((p->rmdnum - i - 1) & (RMDNUM-1));
-     if(! (rmdp->u.s.status & RCV_OWN) )
-        f = 1;
-     else if(f)
+  int i,k,num1,num2;
+  for(i=RMDNUM-1;i>0;i--) {
+     num2 = (p->rmdnum + i) & (RMDNUM-1);
+     if(!(p->rmdhead[num2].u.s.status & RCV_OWN))
         break;
   }
 
-  if(i < RMDNUM) {
-    p->rmdnum = (p->rmdnum + 8 - i) & (RMDNUM - 1);
-    printk(KERN_ERR "%s: Ooops, receive ring corrupted\n",dev->name);
+  if(i) {
+    for(k=0;k<RMDNUM;k++) {
+      num1 = (p->rmdnum + k) & (RMDNUM-1);
+      if(!(p->rmdhead[num1].u.s.status & RCV_OWN))
+        break;
+    }
+    if(!k)
+      break;
+
+    if(debuglevel > 0)
+    {
+      char buf[256],*buf1;
+      int k;
+      buf1 = buf;
+      for(k=0;k<RMDNUM;k++) {
+        sprintf(buf1,"%02x ",(p->rmdhead[k].u.s.status)); /* & RCV_OWN) ); */
+        buf1 += 3;
+      }
+      *buf1 = 0;
+      printk(KERN_ERR "%s: Ooops, receive ring corrupted %2d %2d | %s\n",dev->name,p->rmdnum,i,buf);
+    }
 
+    p->rmdnum = num1;
     ni65_recv_intr(dev,csr0);
+    if((p->rmdhead[num2].u.s.status & RCV_OWN))
+      break;	/* ok, we are 'in sync' again */
   }
+  else
+    break;
+ }
 }
 #endif
 
   if(csr0 & (CSR0_RXON | CSR0_TXON) != (CSR0_RXON | CSR0_TXON) ) {
-    writedatareg(CSR0_STOP);
-    writedatareg(CSR0_STRT | CSR0_INEA);
+    printk("%s: RX or TX was offline -> restart\n",dev->name);
+    ni65_stop_start(dev,p);
   }
   else
     writedatareg(CSR0_INEA);
+
   dev->interrupt = 0;
 
   return;
@@ -539,13 +915,6 @@
     if(tmdstat & XMIT_OWN)
       break;
 
-#ifdef XMT_VIA_SKB
-    if(p->tmd_skb[p->tmdlast]) {
-       dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE);
-       p->tmd_skb[p->tmdlast] = NULL;
-    }
-#endif
-
     if(tmdstat & XMIT_ERR)
     {
 #if 0
@@ -558,20 +927,34 @@
       if(tmdp->status2 & XMIT_LCAR)
         p->stats.tx_carrier_errors++;
       if(tmdp->status2 & (XMIT_BUFF | XMIT_UFLO )) {
+		/* this stops the xmitter */
         p->stats.tx_fifo_errors++;
-        writedatareg(CSR0_STOP);
-        writedatareg(CSR0_STRT);
-        if(debuglevel > 1)
+        if(debuglevel > 0)
           printk(KERN_ERR "%s: Xmit FIFO/BUFF error\n",dev->name);
+        if(p->features & INIT_RING_BEFORE_START) {
+          tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;	/* test: resend this frame */
+          ni65_stop_start(dev,p);
+          break;	/* no more Xmit processing .. */
+        }
+        else
+         ni65_stop_start(dev,p);
       }
       if(debuglevel > 2)
         printk(KERN_ERR "%s: xmit-error: %04x %02x-%04x\n",dev->name,csr0,(int) tmdstat,(int) tmdp->status2);
-      p->stats.tx_errors++;
+      if(!(csr0 & CSR0_BABL)) /* don't count errors twice */
+        p->stats.tx_errors++;
       tmdp->status2 = 0;
     }
     else
       p->stats.tx_packets++;
 
+#ifdef XMT_VIA_SKB
+    if(p->tmd_skb[p->tmdlast]) {
+       dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE);
+       p->tmd_skb[p->tmdlast] = NULL;
+    }
+#endif
+
     p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
     if(p->tmdlast == p->tmdnum)
       p->xmit_queued = 0;
@@ -583,16 +966,17 @@
 /*
  * We have received a packet
  */
-
 static void ni65_recv_intr(struct device *dev,int csr0)
 {
   struct rmd *rmdp; 
   int rmdstat,len;
+  int cnt=0;
   struct priv *p = (struct priv *) dev->priv;
 
   rmdp = p->rmdhead + p->rmdnum;
   while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN))
   {
+    cnt++;
     if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */ 
     {
       if(!(rmdstat & RCV_ERR)) {
@@ -603,27 +987,27 @@
         }
       }
       else {
-        printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n",
-                dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) );
+        if(debuglevel > 2)
+          printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n",
+                  dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) );
         if(rmdstat & RCV_FRAM)
           p->stats.rx_frame_errors++;
         if(rmdstat & RCV_OFLO)
           p->stats.rx_over_errors++;
-        if(rmdstat & (RCV_OFLO | RCV_BUF_ERR) ) { 
-          writedatareg(CSR0_STOP);
-          writedatareg(CSR0_STRT);
-          if(debuglevel > 1)
-            printk(KERN_ERR "%s: Rcv FIFO/BUFF error.\n",dev->name);
-        }
-        if(rmdstat & RCV_CRC)  p->stats.rx_crc_errors++;
+        if(rmdstat & RCV_CRC) 
+          p->stats.rx_crc_errors++;
+        if(rmdstat & RCV_BUF_ERR)
+          p->stats.rx_fifo_errors++;
       }
-      rmdp->u.s.status = RCV_OWN; /* change owner */
-      p->stats.rx_errors++;
+      if(!(csr0 & CSR0_MISS)) /* don't count errors twice */
+        p->stats.rx_errors++;
     }
     else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60)
     {
 #ifdef RCV_VIA_SKB
-      struct sk_buff *skb = dev_alloc_skb(R_BUF_SIZE+2);
+      struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC);
+      if (skb)
+        skb_reserve(skb,16);
 #else
       struct sk_buff *skb = dev_alloc_skb(len+2);
 #endif
@@ -648,23 +1032,23 @@
         skb_put(skb,len);
         eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);
 #endif
-        rmdp->u.s.status = RCV_OWN;
         p->stats.rx_packets++;
         skb->protocol=eth_type_trans(skb,dev);
         netif_rx(skb);
       }
       else
       {
-        rmdp->u.s.status = RCV_OWN;
         printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name);
         p->stats.rx_dropped++;
       }
     }
     else {
-      rmdp->u.s.status = RCV_OWN;
       printk(KERN_INFO "%s: received runt packet\n",dev->name);
       p->stats.rx_errors++;
     }
+    rmdp->blen = -(R_BUF_SIZE-8);
+    rmdp->mlen = 0;
+    rmdp->u.s.status = RCV_OWN; /* change owner */
     p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1);
     rmdp = p->rmdhead + p->rmdnum;
   }
@@ -680,11 +1064,19 @@
   if(dev->tbusy)
   {
     int tickssofar = jiffies - dev->trans_start;
-    if (tickssofar < 5)
+    if (tickssofar < 50)
       return 1;
 
     printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
-    ni65_am7990_reinit(dev);
+#if 0
+{
+  int i;
+  for(i=0;i<TMDNUM;i++)
+    printk("%02x ",p->tmdhead[i].u.s.status);
+  printk("\n");
+}
+#endif
+    ni65_lance_reinit(dev);
     dev->tbusy=0;
     dev->trans_start = jiffies;
   }
@@ -708,28 +1100,37 @@
 
   {
     short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-    struct tmd *tmdp = p->tmdhead + p->tmdnum;
+    struct tmd *tmdp;
     long flags;
 
 #ifdef XMT_VIA_SKB
     if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
 #endif
-      tmdp->u.buffer = (unsigned long ) p->tmdbounce[p->tmdnum]; 
-      memcpy((char *) tmdp->u.buffer,(char *)skb->data,
+
+      memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data,
                (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len);
       dev_kfree_skb (skb, FREE_WRITE);
+
+      save_flags(flags);
+      cli();
+
+      tmdp = p->tmdhead + p->tmdnum;
+      tmdp->u.buffer = (unsigned long ) p->tmdbounce[p->tmdbouncenum];
+      p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1);
+
 #ifdef XMT_VIA_SKB
     }
     else {
+      save_flags(flags);
+      cli();
+ 
+      tmdp = p->tmdhead + p->tmdnum;
       tmdp->u.buffer = (unsigned long) skb->data;
       p->tmd_skb[p->tmdnum] = skb;
     }
 #endif
     tmdp->blen = -len;
 
-    save_flags(flags);
-    cli();
-
     tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;
     writedatareg(CSR0_TDMD | CSR0_INEA); /* enable xmit & interrupt */
 
@@ -748,17 +1149,75 @@
 
 static struct enet_statistics *ni65_get_stats(struct device *dev)
 {
+
+#if 0
+ int i;
+ struct priv *p = (struct priv *) dev->priv;
+ for(i=0;i<RMDNUM;i++) {
+   struct rmd *rmdp = p->rmdhead + ((p->rmdnum + i) & (RMDNUM-1));
+   printk("%02x ",rmdp->u.s.status);
+ }
+ printk("\n");
+#endif
+
   return &((struct priv *) dev->priv)->stats;
 }
 
 static void set_multicast_list(struct device *dev)
 {
-	if(!ni65_am7990_reinit(dev))
+	if(!ni65_lance_reinit(dev))
 		printk(KERN_ERR "%s: Can't switch card into MC mode!\n",dev->name);
 	dev->tbusy = 0;
 }
 
+#ifdef MODULE
+static struct device dev_ni65 = {
+  "        ",  /* "ni6510": device name inserted by net_init.c */
+  0, 0, 0, 0,
+  0x360, 9,   /* I/O address, IRQ */
+  0, 0, 0, NULL, ni65_probe };
+
+/* set: io,irq,dma or set it when calling insmod */
+int irq=0;
+int io=0;
+int dma=0;
+
+int init_module(void)
+{
+#if 0
+  if(io <= 0x0 || irq < 2) {
+    printk("ni65: Autoprobing not allowed for modules.\n");
+    printk("ni65: Set symbols 'io' 'irq' and 'dma'\n");
+    return -ENODEV;
+  }
+#endif
+  dev_ni65.irq = irq;
+  dev_ni65.dma = dma;
+  dev_ni65.base_addr = io;
+  if (register_netdev(&dev_ni65) != 0)
+    return -EIO;
+  return 0;
+}
+
+void cleanup_module(void)
+{
+  struct priv *p;
+  p = (struct priv *) dev_ni65.priv;
+  if(!p) {
+    printk("Ooops .. no privat struct\n");
+    return;
+  }
+  disable_dma(dev_ni65.dma);
+  free_dma(dev_ni65.dma);
+  release_region(dev_ni65.base_addr,cards[p->cardno].total_size);
+  ni65_free_buffer(p);
+  dev_ni65.priv = NULL;
+  unregister_netdev(&dev_ni65);
+}
+#endif /* MODULE */
+
 /*
  * END of ni65.c 
  */
+
 
diff -u --recursive --new-file v2.0.23/linux/drivers/net/ni65.h linux/drivers/net/ni65.h
--- v2.0.23/linux/drivers/net/ni65.h	Mon Feb 26 11:58:15 1996
+++ linux/drivers/net/ni65.h	Wed Oct 30 03:42:41 1996
@@ -108,7 +108,7 @@
       volatile unsigned char status; 
     } s;
   } u;
-  short blen;
+  volatile short blen;
   volatile unsigned short mlen;
 };
 
@@ -123,7 +123,7 @@
       volatile unsigned char status;
     } s;
   } u;
-  unsigned short blen;
+  volatile unsigned short blen;
   volatile unsigned short status2;
 };
 
diff -u --recursive --new-file v2.0.23/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- v2.0.23/linux/drivers/net/slhc.c	Tue Jun 25 12:03:29 1996
+++ linux/drivers/net/slhc.c	Wed Oct 30 03:42:41 1996
@@ -246,6 +246,14 @@
 	struct iphdr *ip;
 	struct tcphdr *th, *oth;
 
+
+	/*
+	 *	Don't play with runt packets.
+	 */
+	 
+	if(isize<sizeof(struct iphdr))
+		return isize;
+		
 	ip = (struct iphdr *) icp;
 
 	/* Bail if this packet isn't TCP, or is an IP fragment */
@@ -264,9 +272,10 @@
 	hlen = ip->ihl*4 + th->doff*4;
 
 	/*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
-	 *  some other control bit is set).
+	 *  some other control bit is set). Also uncompressible if
+	 *  its a runt.
 	 */
-	if(th->syn || th->fin || th->rst ||
+	if(hlen > isize || th->syn || th->fin || th->rst ||
 	    ! (th->ack)){
 		/* TCP connection stuff; send as regular IP */
 		comp->sls_o_tcp++;
diff -u --recursive --new-file v2.0.23/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.0.23/linux/drivers/net/tulip.c	Sat Oct 19 10:06:10 1996
+++ linux/drivers/net/tulip.c	Wed Oct 30 04:02:39 1996
@@ -1133,6 +1133,25 @@
 		} while (++i < 15);
 
 		/* Now add this frame to the Tx list. */
+		{
+			unsigned long flags;
+			unsigned int entry;
+			
+			save_flags(flags); cli();
+			entry = tp->cur_tx++ % TX_RING_SIZE;
+			tp->dirty_tx++;
+			restore_flags(flags);
+
+			tp->tx_skbuff[entry] = 0;
+			/* Put the setup frame on the Tx list. */
+			tp->tx_ring[entry].length = 192 |
+			      (entry == TX_RING_SIZE-1 ? 0x0a000000 : 0x08000);
+			tp->tx_ring[entry].buffer1 = virt_to_bus((char *)tp->setup_frame);
+			tp->tx_ring[entry].buffer2 = 0;
+			tp->tx_ring[entry].status = TRING_OWN;
+			/* Trigger an immediate transmit demand. */
+			tio_write(TPOLL_TRIGGER, CSR1);
+		}
 	}
 }
 
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c
--- v2.0.23/linux/drivers/scsi/AM53C974.c	Fri Apr 12 09:49:40 1996
+++ linux/drivers/scsi/AM53C974.c	Wed Oct 30 04:03:42 1996
@@ -1,3 +1,5 @@
+#include <linux/module.h>
+
 #include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/signal.h>
@@ -2241,3 +2243,10 @@
 cmd->scsi_done(cmd);
 return SCSI_ABORT_SUCCESS;
 }
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = AM53C974;
+
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v2.0.23/linux/drivers/scsi/BusLogic.c	Wed Jul 17 21:22:13 1996
+++ linux/drivers/scsi/BusLogic.c	Mon Oct 28 13:39:30 1996
@@ -25,7 +25,7 @@
 
 
 #define BusLogic_DriverVersion		"2.0.6"
-#define BusLogic_DriverDate		"17 July 1996"
+#define BusLogic_DriverDate		"19 October 1996"
 
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- v2.0.23/linux/drivers/scsi/BusLogic.h	Wed Jul 17 21:22:13 1996
+++ linux/drivers/scsi/BusLogic.h	Mon Oct 28 13:39:30 1996
@@ -1066,11 +1066,10 @@
 
 static inline void BusLogic_Delay(int Seconds)
 {
-  unsigned long TimeoutJiffies = jiffies + Seconds * HZ;
   unsigned long ProcessorFlags;
   save_flags(ProcessorFlags);
   sti();
-  while (jiffies < TimeoutJiffies) barrier();
+  while (--Seconds >= 0) udelay(1000000);
   restore_flags(ProcessorFlags);
 }
 
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.0.23/linux/drivers/scsi/Config.in	Sun Jul  7 11:18:51 1996
+++ linux/drivers/scsi/Config.in	Wed Oct 30 03:44:13 1996
@@ -21,12 +21,12 @@
 dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
-bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974
+dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
 dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
-dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
 dep_tristate 'EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
 dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
+dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
 dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
 dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
 if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.0.23/linux/drivers/scsi/Makefile	Sat Jul  6 12:06:37 1996
+++ linux/drivers/scsi/Makefile	Wed Oct 30 03:42:41 1996
@@ -179,6 +179,10 @@
 
 ifeq ($(CONFIG_SCSI_AM53C974),y)
 L_OBJS += AM53C974.o
+else
+  ifeq ($(CONFIG_SCSI_AM53C974),m)
+  M_OBJS += AM53C974.o
+  endif
 endif
 
 ifeq ($(CONFIG_SCSI_BUSLOGIC),y)
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v2.0.23/linux/drivers/scsi/NCR5380.c	Mon Apr 29 17:14:19 1996
+++ linux/drivers/scsi/NCR5380.c	Tue Oct 29 16:21:48 1996
@@ -734,7 +734,7 @@
  */
 
 static void NCR5380_print_status (struct Scsi_Host *instance) {
-   char pr_bfr[256];
+   static char pr_bfr[512];
    char *start;
    int len;
 
@@ -767,7 +767,7 @@
 */
 
 #undef SPRINTF
-#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+#define SPRINTF(args...) do { if(pos < buffer + length-80) pos += sprintf(pos, ## args); } while(0)
 static
 char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
 static
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.0.23/linux/drivers/scsi/aha152x.c	Wed Sep 11 17:57:14 1996
+++ linux/drivers/scsi/aha152x.c	Wed Oct 30 03:42:41 1996
@@ -404,7 +404,7 @@
 
 /* END OF DEFINES */
 
-extern long loops_per_sec;
+extern unsigned long loops_per_sec;
 
 #define DELAY_DEFAULT 100
 
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.0.23/linux/drivers/scsi/aic7xxx.c	Sat Oct 19 10:06:11 1996
+++ linux/drivers/scsi/aic7xxx.c	Tue Oct 29 00:21:33 1996
@@ -1,3 +1,5 @@
+#define EXPERIMENTAL_FLAGS 0
+
 /*+M*************************************************************************
  * Adaptec AIC7xxx device driver for Linux.
  *
@@ -4314,7 +4316,7 @@
   p->flags = config->flags;
   p->chan_num = config->chan_num;
   p->scb_link = &(p->scb_usage);
-#ifdef AIC7XXX_SHARE_SCBS
+#if defined(CONFIG_PCI) && defined(AIC7XXX_SHARE_SCBS)
   if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883)))
   {
     shared_3985_scbs = &(p->scb_usage);
@@ -4410,7 +4412,7 @@
     outb(config->scsi_id_b, SCSIID + base);
     scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
     outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if 1
+#if EXPERIMENTAL_FLAGS
     outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
 #else
     outb(ENSELTIMO, SIMODE1 + base);
@@ -4432,7 +4434,7 @@
   outb(config->scsi_id, SCSIID + base);
   scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
   outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if 1
+#if EXPERIMENTAL_FLAGS
   outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
 #else
   outb(ENSELTIMO, SIMODE1 + base);
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- v2.0.23/linux/drivers/scsi/eata_dma.c	Sat Aug 17 21:19:27 1996
+++ linux/drivers/scsi/eata_dma.c	Tue Oct 29 00:30:43 1996
@@ -58,7 +58,7 @@
  * Jagdis who did a lot of testing and found quite a number *
  * of bugs during the development.                          *
  ************************************************************
- *  last change: 96/08/13                 OS: Linux 2.0.12  *
+ *  last change: 96/10/21                 OS: Linux 2.0.23  *
  ************************************************************/
 
 /* Look in eata_dma.h for configuration and revision information */
@@ -295,12 +295,9 @@
            sp->EOC = FALSE; /* Clean out this flag */
 
            if (ccb->status == LOCKED || ccb->status == RESET) {
-               ccb->status = FREE;
-               eata_stat = inb(base + HA_RSTATUS);
-               printk("eata_dma: int_handler, reseted command returned,"
-                      " freeing reseted queueslot\n");
+               printk("eata_dma: int_handler, reseted command pid %ld returned"
+		      "\n", cmd->pid);
 	       DBG(DBG_INTR && DBG_DELAY, DELAY(1));
-	       break;
 	    }
 	    
 	    eata_stat = inb(base + HA_RSTATUS); 
@@ -467,23 +464,33 @@
     struct Scsi_Host *sh;
     struct eata_ccb *ccb;
     struct scatterlist *sl;
+
     
     save_flags(flags);
     cli();
+
+#if 0
+    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
+      if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
+            printk("eata_dma: scsi%d interrupt pending in eata_queue.\n"
+		   "          Calling interrupt handler.\n", sh->host_no);
+            eata_int_handler(sh->irq, 0, 0);
+      }
+    }
+#endif
     
     queue_counter++;
 
     hd = HD(cmd);
     sh = cmd->host;
     
-#if 1
     if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) {
         DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
 	cmd->result = DID_OK << 16;
 	done(cmd);
+
 	return(0);
     }
-#endif
 
     /* check for free slot */
     for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) { 
@@ -678,7 +685,6 @@
 			   " reason %x\n", cmd->pid, cmd->target, cmd->lun, 
 			   cmd->abort_reason));
 	
-    /* Some interrupt controllers seem to loose interrupts */
     for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
         if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
             printk("eata_dma: scsi%d interrupt pending in eata_reset.\n"
@@ -686,6 +692,7 @@
             eata_int_handler(sh->irq, 0, 0);
       }
     }
+
     if (HD(cmd)->state == RESET) {
 	printk("eata_reset: exit, already in reset.\n");
 	restore_flags(flags);
@@ -766,9 +773,9 @@
     restore_flags(flags);
     
     if (success) {
-	DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n"));
+	DBG(DBG_ABNORM, printk("eata_reset: exit, pending.\n"));
 	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
-	return (SCSI_RESET_SUCCESS);
+	return (SCSI_RESET_PENDING);
     } else {
 	DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));
 	DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
@@ -852,8 +859,9 @@
 		    device->queue_depth = (TYPE_OTHER_QUEUE * factor) / 10;
 		    break;
 		}
-	    } else /* ISA forces us to limit the QS because of bounce buffers*/
-	        device->queue_depth = 2; /* I know this is cruel */
+	    } else /* ISA forces us to limit the queue depth because of the 
+		    * bounce buffer memory overhead. I know this is cruel */
+	        device->queue_depth = 2; 
 
 	    /* 
 	     * It showed that we need to set an upper limit of commands 
@@ -863,6 +871,8 @@
 	     */
 	    if(device->queue_depth > UPPER_DEVICE_QUEUE_LIMIT)
 		device->queue_depth = UPPER_DEVICE_QUEUE_LIMIT;
+	    if(device->queue_depth == 0) 
+		device->queue_depth = 1;
 
 	    printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d "
 		   "set to %d\n", host->host_no, device->id, device->channel,
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h
--- v2.0.23/linux/drivers/scsi/eata_dma.h	Sat Aug 17 21:19:27 1996
+++ linux/drivers/scsi/eata_dma.h	Tue Oct 29 00:30:43 1996
@@ -4,7 +4,7 @@
 *             mike@i-Connect.Net                        *
 *             neuffer@mail.uni-mainz.de                 *
 *********************************************************
-* last change: 96/08/14                                 *
+* last change: 96/10/14                                 *
 ********************************************************/
 
 #ifndef _EATA_DMA_H
@@ -17,7 +17,7 @@
 
 #define VER_MAJOR 2
 #define VER_MINOR 5
-#define VER_SUB   "9a"
+#define VER_SUB   "9b"
 
 
 /************************************************************************
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/eata_generic.h linux/drivers/scsi/eata_generic.h
--- v2.0.23/linux/drivers/scsi/eata_generic.h	Sat Aug 17 21:19:27 1996
+++ linux/drivers/scsi/eata_generic.h	Tue Oct 29 00:30:43 1996
@@ -68,7 +68,7 @@
 #define SG_SIZE		 64 
 #define SG_SIZE_BIG	 252	       /* max. 8096 elements, 64k */
 
-#define UPPER_DEVICE_QUEUE_LIMIT 24    /* The limit we have to set for the 
+#define UPPER_DEVICE_QUEUE_LIMIT 64    /* The limit we have to set for the 
 					* device queue to keep the broken 
 					* midlevel SCSI code from producing
 					* bogus timeouts
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.0.23/linux/drivers/scsi/hosts.c	Sat Aug 10 10:03:15 1996
+++ linux/drivers/scsi/hosts.c	Tue Oct 29 00:30:43 1996
@@ -224,6 +224,12 @@
 #ifdef CONFIG_SCSI_ADVANSYS
 	ADVANSYS,
 #endif
+#ifdef CONFIG_SCSI_EATA_DMA
+    EATA_DMA,
+#endif
+#ifdef CONFIG_SCSI_EATA_PIO
+    EATA_PIO,
+#endif
 /* BusLogic must come before aha1542.c */
 #ifdef CONFIG_SCSI_BUSLOGIC
     BUSLOGIC,
@@ -281,12 +287,6 @@
 #endif
 #ifdef CONFIG_SCSI_NCR53C8XX
     NCR53C8XX,
-#endif
-#ifdef CONFIG_SCSI_EATA_DMA
-    EATA_DMA,
-#endif
-#ifdef CONFIG_SCSI_EATA_PIO
-    EATA_PIO,
 #endif
 #ifdef CONFIG_SCSI_7000FASST
     WD7000,
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.0.23/linux/drivers/scsi/scsi.c	Tue Oct  8 21:20:14 1996
+++ linux/drivers/scsi/scsi.c	Wed Oct 30 03:12:04 1996
@@ -17,8 +17,8 @@
  *  add scatter-gather, multiple outstanding request, and other
  *  enhancements.
  *
- *  Native multichannel and wide scsi support added 
- *  by Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
+ *  Native multichannel, wide scsi, /proc/scsi and hot plugging 
+ *  support added by Michael Neuffer <mike@i-connect.net>
  *
  *  Added request_module("scsi_hostadapter") for kerneld:
  *  (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
@@ -47,6 +47,7 @@
 #include <linux/stat.h>
 #include <linux/blk.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
@@ -275,6 +276,7 @@
  */
 {"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN},
 {"TEXEL","CD-ROM","1.06", BLIST_BORKEN},
+{"IOMEGA","Io20S         *F","*", BLIST_KEY},
 {"INSITE","Floptical   F*8I","*", BLIST_KEY},
 {"INSITE","I325VM","*", BLIST_KEY},
 {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},
@@ -1215,17 +1217,19 @@
      */
     timeout = host->last_reset + MIN_RESET_DELAY;
     if (jiffies < timeout) {
-        /*
-         * NOTE: This may be executed from within an interrupt
-         * handler!  This is bad, but for now, it'll do.  The irq
-         * level of the interrupt handler has been masked out by the
-         * platform dependent interrupt handling code already, so the
-         * sti() here will not cause another call to the SCSI host's
-         * interrupt handler (assuming there is one irq-level per
-         * host).
-         */
-        sti();
-        while (jiffies < timeout) barrier();
+	int ticks_remaining = timeout - jiffies;
+	/*
+	 * NOTE: This may be executed from within an interrupt
+	 * handler!  This is bad, but for now, it'll do.  The irq
+	 * level of the interrupt handler has been masked out by the
+	 * platform dependent interrupt handling code already, so the
+	 * sti() here will not cause another call to the SCSI host's
+	 * interrupt handler (assuming there is one irq-level per
+	 * host).
+	 */
+	sti();
+	while (--ticks_remaining >= 0) udelay(1000000/HZ);
+	host->last_reset = jiffies - MIN_RESET_DELAY;
     }
     restore_flags(flags);
     
@@ -1791,7 +1795,8 @@
 	if ((++SCpnt->retries) < SCpnt->allowed)
 	{
 	    if ((SCpnt->retries >= (SCpnt->allowed >> 1))
-		&& !(jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
+		&& !(SCpnt->host->last_reset > 0 &&
+		     jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
 		&& !(SCpnt->flags & WAS_RESET))
 	    {
 		printk("scsi%d channel %d : resetting for second half of retries.\n",
@@ -3062,7 +3067,11 @@
 	 */
 	
 	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-	    if(shpnt->hostt == tpnt) scan_scsis(shpnt,0,0,0,0);
+	    if(shpnt->hostt == tpnt) {
+	      scan_scsis(shpnt,0,0,0,0);
+	      if (shpnt->select_queue_depths != NULL)
+		  (shpnt->select_queue_depths)(shpnt, scsi_devices);
+	    }
 	
 	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
 	    if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.0.23/linux/drivers/scsi/sd.c	Fri Sep 20 17:00:34 1996
+++ linux/drivers/scsi/sd.c	Tue Oct 29 00:30:44 1996
@@ -512,7 +512,7 @@
 
 	if (flag++ == 0)
 	    SCpnt = allocate_device(&CURRENT,
-				    rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0); 
+			   rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0); 
 	else SCpnt = NULL;
 	
 	/*
@@ -537,7 +537,8 @@
 	    cli();
 	    req = CURRENT;
 	    while(req){
-		SCpnt = request_queueable(req, rscsi_disks[DEVICE_NR(req->rq_dev)].device);
+		SCpnt = request_queueable(req, 
+                                   rscsi_disks[DEVICE_NR(req->rq_dev)].device);
 		if(SCpnt) break;
 		req1 = req;
 		req = req->next;
diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.0.23/linux/drivers/scsi/st.c	Tue Oct  8 21:20:14 1996
+++ linux/drivers/scsi/st.c	Tue Oct 29 17:40:50 1996
@@ -2314,6 +2314,7 @@
       return (-EBUSY);
 
     STp->drv_block = (STp->mt_status)->mt_fileno = (-1);
+    STp->eof = ST_NOEOF;
     if ((STp->buffer)->last_result_fatal != 0) {
       result = (-EIO);
       if (STp->can_partitions &&
diff -u --recursive --new-file v2.0.23/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.0.23/linux/fs/proc/array.c	Thu Aug 29 19:15:14 1996
+++ linux/fs/proc/array.c	Wed Oct 30 03:42:41 1996
@@ -307,7 +307,7 @@
 
 static int get_version(char * buffer)
 {
-	extern char *linux_banner;
+	extern const char *linux_banner;
 
 	strcpy(buffer, linux_banner);
 	return strlen(buffer);
diff -u --recursive --new-file v2.0.23/linux/fs/super.c linux/fs/super.c
--- v2.0.23/linux/fs/super.c	Fri Sep 20 17:00:35 1996
+++ linux/fs/super.c	Wed Oct 30 01:58:59 1996
@@ -146,6 +146,8 @@
 		if (vfsmnttail->mnt_dev == dev)
 			vfsmnttail = lptr;
 	}
+	if (tofree == mru_vfsmnt)
+		mru_vfsmnt = NULL;
 	kfree(tofree->mnt_devname);
 	kfree(tofree->mnt_dirname);
 	kfree_s(tofree, sizeof(struct vfsmount));
diff -u --recursive --new-file v2.0.23/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.0.23/linux/include/asm-i386/pgtable.h	Sun Sep  8 19:50:21 1996
+++ linux/include/asm-i386/pgtable.h	Wed Oct 30 04:53:16 1996
@@ -88,7 +88,7 @@
 	__flush_tlb()
 
 
-#undef CLEVER_SMP_INVALIDATE
+#define CLEVER_SMP_INVALIDATE
 #ifdef CLEVER_SMP_INVALIDATE
 
 /*
@@ -97,9 +97,6 @@
  *
  *	These mean you can really definitely utterly forget about
  *	writing to user space from interrupts. (Its not allowed anyway).
- *
- *	Doesn't currently work as Linus makes flush tlb calls before
- *	stuff like current/current->mm are setup properly
  */
  
 static inline void flush_tlb_current_task(void)
diff -u --recursive --new-file v2.0.23/linux/include/linux/fddidevice.h linux/include/linux/fddidevice.h
--- v2.0.23/linux/include/linux/fddidevice.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/fddidevice.h	Wed Oct 30 03:42:41 1996
@@ -0,0 +1,42 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		Definitions for the FDDI handlers.
+ *
+ * Version:	@(#)fddidevice.h	1.0.0	08/12/96
+ *
+ * Author:	Lawrence V. Stefani, <stefani@lkg.dec.com>
+ *
+ *		fddidevice.h is based on previous trdevice.h work by
+ *			Ross Biro, <bir7@leland.Stanford.Edu>
+ *			Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *			Alan Cox, <gw4pts@gw4pts.ampr.org>
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_FDDIDEVICE_H
+#define _LINUX_FDDIDEVICE_H
+
+#include <linux/if_fddi.h>
+
+#ifdef __KERNEL__
+extern int				fddi_header(struct sk_buff *skb,
+									struct device *dev,
+									unsigned short type,
+									void *daddr,
+									void *saddr,
+									unsigned len);
+extern int				fddi_rebuild_header(void *buff,
+											struct device *dev,
+											unsigned long dest,
+											struct sk_buff *skb);
+extern unsigned short	fddi_type_trans(struct sk_buff *skb,
+										struct device *dev);
+#endif
+
+#endif	/* _LINUX_FDDIDEVICE_H */
diff -u --recursive --new-file v2.0.23/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.0.23/linux/include/linux/fs.h	Fri Sep 20 17:00:36 1996
+++ linux/include/linux/fs.h	Wed Oct 30 04:53:05 1996
@@ -16,8 +16,6 @@
 #include <linux/kdev_t.h>
 #include <linux/ioctl.h>
 
-#include <asm/semaphore.h>
-
 /*
  * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
  * that later. Anyway, now the file code is no longer dependent
@@ -121,6 +119,7 @@
 
 #ifdef __KERNEL__
 
+#include <asm/semaphore.h>
 #include <asm/bitops.h>
 
 extern void buffer_init(void);
diff -u --recursive --new-file v2.0.23/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v2.0.23/linux/include/linux/if_arp.h	Thu Jul 25 20:28:49 1996
+++ linux/include/linux/if_arp.h	Wed Oct 30 04:55:11 1996
@@ -5,14 +5,15 @@
  *
  *		Global definitions for the ARP (RFC 826) protocol.
  *
- * Version:	@(#)if_arp.h	1.0.1	04/16/93
+ * Version:	@(#)if_arp.h	1.0.2	08/12/96
  *
  * Authors:	Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
  *		Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source.
  *		Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Florian La Roche,
- *		Jonathan Layes <layes@loran.com>
+ *		Jonathan Layes, <layes@loran.com>
+ *		Lawrence V. Stefani, <stefani@lkg.dec.com>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -52,6 +53,7 @@
 #define ARPHRD_SKIP	771		/* SKIP vif			*/
 #define ARPHRD_LOOPBACK	772		/* Loopback device		*/
 #define ARPHRD_LOCALTLK 773		/* Localtalk device		*/
+#define ARPHRD_FDDI		774		/* Fiber Distributed Data Interface */
 
 /* ARP protocol opcodes. */
 #define	ARPOP_REQUEST	1		/* ARP request			*/
diff -u --recursive --new-file v2.0.23/linux/include/linux/if_fddi.h linux/include/linux/if_fddi.h
--- v2.0.23/linux/include/linux/if_fddi.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/if_fddi.h	Wed Oct 30 03:42:41 1996
@@ -0,0 +1,202 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		Global definitions for the ANSI FDDI interface.
+ *
+ * Version:	@(#)if_fddi.h	1.0.1	09/16/96
+ *
+ * Author:	Lawrence V. Stefani, <stefani@lkg.dec.com>
+ *
+ *		if_fddi.h is based on previous if_ether.h and if_tr.h work by
+ *			Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *			Donald Becker, <becker@super.org>
+ *			Alan Cox, <alan@cymru.net>
+ *			Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+ *			Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_FDDI_H
+#define _LINUX_IF_FDDI_H
+
+/*
+ *  Define max and min legal sizes.  The frame sizes do not include
+ *  4 byte FCS/CRC (frame check sequence).
+ */
+#define FDDI_K_ALEN			6		/* Octets in one FDDI address */
+#define FDDI_K_8022_HLEN	16		/* Total octets in 802.2 header */
+#define FDDI_K_SNAP_HLEN	21		/* Total octets in 802.2 SNAP header */
+#define FDDI_K_8022_ZLEN	16		/* Min octets in 802.2 frame sans FCS */
+#define FDDI_K_SNAP_ZLEN	21		/* Min octets in 802.2 SNAP frame sans FCS */
+#define FDDI_K_8022_DLEN	4475	/* Max octets in 802.2 payload */
+#define FDDI_K_SNAP_DLEN	4470	/* Max octets in 802.2 SNAP payload */
+#define FDDI_K_LLC_ZLEN		13		/* Min octets in LLC frame sans FCS */
+#define FDDI_K_LLC_LEN		4491	/* Max octets in LLC frame sans FCS */
+
+/* Define FDDI Frame Control (FC) Byte values */
+#define FDDI_FC_K_VOID					0x00	
+#define FDDI_FC_K_NON_RESTRICTED_TOKEN	0x80	
+#define FDDI_FC_K_RESTRICTED_TOKEN		0xC0	
+#define FDDI_FC_K_SMT_MIN				0x41
+#define FDDI_FC_K_SMT_MAX		   		0x4F
+#define FDDI_FC_K_MAC_MIN				0xC1
+#define FDDI_FC_K_MAC_MAX		  		0xCF	
+#define FDDI_FC_K_ASYNC_LLC_MIN			0x50
+#define FDDI_FC_K_ASYNC_LLC_DEF			0x54
+#define FDDI_FC_K_ASYNC_LLC_MAX			0x5F
+#define FDDI_FC_K_SYNC_LLC_MIN			0xD0
+#define FDDI_FC_K_SYNC_LLC_MAX			0xD7
+#define FDDI_FC_K_IMPLEMENTOR_MIN		0x60
+#define FDDI_FC_K_IMPLEMENTOR_MAX  		0x6F
+#define FDDI_FC_K_RESERVED_MIN			0x70
+#define FDDI_FC_K_RESERVED_MAX			0x7F
+
+/* Define LLC and SNAP constants */
+#define FDDI_EXTENDED_SAP	0xAA
+#define FDDI_UI_CMD			0x03
+
+/* Define 802.2 Type 1 header */
+struct fddi_8022_1_hdr
+	{
+	__u8	dsap;					/* destination service access point */
+	__u8	ssap;					/* source service access point */
+	__u8	ctrl;					/* control byte #1 */
+	} __attribute__ ((packed));
+
+/* Define 802.2 Type 2 header */
+struct fddi_8022_2_hdr
+	{
+	__u8	dsap;					/* destination service access point */
+	__u8	ssap;					/* source service access point */
+	__u8	ctrl_1;					/* control byte #1 */
+	__u8	ctrl_2;					/* control byte #2 */
+	} __attribute__ ((packed));
+
+/* Define 802.2 SNAP header */
+#define FDDI_K_OUI_LEN	3
+struct fddi_snap_hdr
+	{
+	__u8	dsap;					/* always 0xAA */
+	__u8	ssap;					/* always 0xAA */
+	__u8	ctrl;					/* always 0x03 */
+	__u8	oui[FDDI_K_OUI_LEN];	/* organizational universal id */
+	__u16	ethertype;				/* packet type ID field */
+	} __attribute__ ((packed));
+
+/* Define FDDI LLC frame header */
+struct fddihdr
+	{
+	__u8	fc;						/* frame control */
+	__u8	daddr[FDDI_K_ALEN];		/* destination address */
+	__u8	saddr[FDDI_K_ALEN];		/* source address */
+	union
+		{
+		struct fddi_8022_1_hdr		llc_8022_1;
+		struct fddi_8022_2_hdr		llc_8022_2;
+		struct fddi_snap_hdr		llc_snap;
+		} hdr;
+	} __attribute__ ((packed));
+
+/* Define FDDI statistics structure */
+struct fddi_statistics
+	{
+	__u32	rx_packets;				/* total packets received */
+	__u32	tx_packets;				/* total packets transmitted */
+	__u32	rx_errors;				/* bad packets received	*/
+	__u32	tx_errors;				/* packet transmit problems	*/
+	__u32	rx_dropped;				/* no space in linux buffers */
+	__u32	tx_dropped;				/* no space available in linux */
+	__u32	multicast;				/* multicast packets received */
+	__u32	transmit_collision;		/* always 0 for FDDI */
+
+	/* Detailed FDDI statistics.  Adopted from RFC 1512 */
+
+	__u8	smt_station_id[8];
+	__u32	smt_op_version_id;
+	__u32	smt_hi_version_id;
+	__u32	smt_lo_version_id;
+	__u8	smt_user_data[32];
+	__u32	smt_mib_version_id;
+	__u32	smt_mac_cts;
+	__u32	smt_non_master_cts;
+	__u32	smt_master_cts;
+	__u32	smt_available_paths;
+	__u32	smt_config_capabilities;
+	__u32	smt_config_policy;
+	__u32	smt_connection_policy;
+	__u32	smt_t_notify;
+	__u32	smt_stat_rpt_policy;
+	__u32	smt_trace_max_expiration;
+	__u32	smt_bypass_present;
+	__u32	smt_ecm_state;
+	__u32	smt_cf_state;
+	__u32	smt_remote_disconnect_flag;
+	__u32	smt_station_status;
+	__u32	smt_peer_wrap_flag;
+	__u32	smt_time_stamp;
+	__u32	smt_transition_time_stamp;
+	__u32	mac_frame_status_functions;
+	__u32	mac_t_max_capability;
+	__u32	mac_tvx_capability;
+	__u32	mac_available_paths;
+	__u32	mac_current_path;
+	__u8	mac_upstream_nbr[FDDI_K_ALEN];
+	__u8	mac_downstream_nbr[FDDI_K_ALEN];
+	__u8	mac_old_upstream_nbr[FDDI_K_ALEN];
+	__u8	mac_old_downstream_nbr[FDDI_K_ALEN];
+	__u32	mac_dup_address_test;
+	__u32	mac_requested_paths;
+	__u32	mac_downstream_port_type;
+	__u8	mac_smt_address[FDDI_K_ALEN];
+	__u32	mac_t_req;
+	__u32	mac_t_neg;
+	__u32	mac_t_max;
+	__u32	mac_tvx_value;
+	__u32	mac_frame_cts;
+	__u32	mac_copied_cts;
+	__u32	mac_transmit_cts;
+	__u32	mac_error_cts;
+	__u32	mac_lost_cts;
+	__u32	mac_frame_error_threshold;
+	__u32	mac_frame_error_ratio;
+	__u32	mac_rmt_state;
+	__u32	mac_da_flag;
+	__u32	mac_una_da_flag;
+	__u32	mac_frame_error_flag;
+	__u32	mac_ma_unitdata_available;
+	__u32	mac_hardware_present;
+	__u32	mac_ma_unitdata_enable;
+	__u32	path_tvx_lower_bound;
+	__u32	path_t_max_lower_bound;
+	__u32	path_max_t_req;
+	__u32	path_configuration[8];
+	__u32	port_my_type[2];
+	__u32	port_neighbor_type[2];
+	__u32	port_connection_policies[2];
+	__u32	port_mac_indicated[2];
+	__u32	port_current_path[2];
+	__u8	port_requested_paths[3*2];
+	__u32	port_mac_placement[2];
+	__u32	port_available_paths[2];
+	__u32	port_pmd_class[2];
+	__u32	port_connection_capabilities[2];
+	__u32	port_bs_flag[2];
+	__u32	port_lct_fail_cts[2];
+	__u32	port_ler_estimate[2];
+	__u32	port_lem_reject_cts[2];
+	__u32	port_lem_cts[2];
+	__u32	port_ler_cutoff[2];
+	__u32	port_ler_alarm[2];
+	__u32	port_connect_state[2];
+	__u32	port_pcm_state[2];
+	__u32	port_pc_withhold[2];
+	__u32	port_ler_flag[2];
+	__u32	port_hardware_present[2];
+	};
+
+#endif	/* _LINUX_IF_FDDI_H */
diff -u --recursive --new-file v2.0.23/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.0.23/linux/include/linux/netdevice.h	Mon Aug  5 10:13:54 1996
+++ linux/include/linux/netdevice.h	Wed Oct 30 04:55:08 1996
@@ -5,7 +5,7 @@
  *
  *		Definitions for the Interfaces handler.
  *
- * Version:	@(#)dev.h	1.0.10	08/12/93
+ * Version:	@(#)dev.h	1.0.11	07/31/96
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -13,6 +13,7 @@
  *		Donald J. Becker, <becker@super.org>
  *		Alan Cox, <A.Cox@swansea.ac.uk>
  *		Bjorn Ekwall. <bj0rn@blox.se>
+ *		Lawrence V. Stefani, <stefani@lkg.dec.com>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -20,6 +21,7 @@
  *		2 of the License, or (at your option) any later version.
  *
  *		Moved to /usr/include/linux for NET3
+ *		Added extern for fddi_setup()
  */
 #ifndef _LINUX_NETDEVICE_H
 #define _LINUX_NETDEVICE_H
@@ -286,6 +288,7 @@
 
 extern void		ether_setup(struct device *dev);
 extern void		tr_setup(struct device *dev);
+extern void		fddi_setup(struct device *dev);
 extern int		ether_config(struct device *dev, struct ifmap *map);
 /* Support for loadable net-drivers */
 extern int		register_netdev(struct device *dev);
diff -u --recursive --new-file v2.0.23/linux/include/linux/raid0.h linux/include/linux/raid0.h
--- v2.0.23/linux/include/linux/raid0.h	Mon Feb 26 13:51:46 1996
+++ linux/include/linux/raid0.h	Tue Oct 29 15:20:35 1996
@@ -1,32 +1,3 @@
-
-#ifndef _RAID0_H
-#define _RAID0_H
-
-struct strip_zone
-{
-  int zone_offset;		/* Zone offset in md_dev */
-  int dev_offset;		/* Zone offset in real dev */
-  int size;			/* Zone size */
-  int nb_dev;			/* Number of devices attached to the zone */
-  struct real_dev *dev[MAX_REAL]; /* Devices attached to the zone */
-};
-
-struct raid0_hash
-{
-  struct strip_zone *zone0, *zone1;
-};
-
-struct raid0_data
-{
-  struct raid0_hash *hash_table; /* Dynamically allocated */
-  struct strip_zone *strip_zone; /* This one too */
-  int nr_strip_zones;
-  struct strip_zone *smallest;
-  int nr_zones;
-};
-
-#endif
-
 #ifndef _RAID0_H
 #define _RAID0_H
 
diff -u --recursive --new-file v2.0.23/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.0.23/linux/include/linux/skbuff.h	Thu Jul 25 20:26:55 1996
+++ linux/include/linux/skbuff.h	Wed Oct 30 04:53:15 1996
@@ -102,7 +102,7 @@
 #define PACKET_OTHERHOST	3		/* To someone else 				*/
 	unsigned short	users;			/* User count - see datagram.c,tcp.c 		*/
 	unsigned short	protocol;		/* Packet protocol from driver. 		*/
-	unsigned short	truesize;		/* Buffer size 					*/
+	unsigned int	truesize;		/* Buffer size 					*/
 
 	atomic_t	count;			/* reference count				*/
 	struct sk_buff	*data_skb;		/* Link to the actual data skb			*/
diff -u --recursive --new-file v2.0.23/linux/include/net/sock.h linux/include/net/sock.h
--- v2.0.23/linux/include/net/sock.h	Thu Jul 25 20:28:50 1996
+++ linux/include/net/sock.h	Wed Oct 30 04:55:13 1996
@@ -169,6 +169,7 @@
 	__u32			fin_seq;
 	__u32			urg_seq;
 	__u32			urg_data;
+	__u32			syn_seq;
 	int			users;			/* user count */
   /*
    *	Not all are volatile, but some are, so we
@@ -216,7 +217,7 @@
 	volatile unsigned long  ato;            /* ack timeout */
 	volatile unsigned long  lrcvtime;       /* jiffies at last data rcv */
 	volatile unsigned long  idletime;       /* jiffies at last rcv */
-	unsigned short		bytes_rcv;
+	unsigned int		bytes_rcv;
 /*
  *	mss is min(mtu, max_window) 
  */
@@ -251,8 +252,8 @@
 	unsigned char		max_ack_backlog;
 	unsigned char		priority;
 	unsigned char		debug;
-	unsigned short		rcvbuf;
-	unsigned short		sndbuf;
+	unsigned int		rcvbuf;
+	unsigned int		sndbuf;
 	unsigned short		type;
 	unsigned char		localroute;	/* Route locally only */
 #ifdef CONFIG_AX25
diff -u --recursive --new-file v2.0.23/linux/init/main.c linux/init/main.c
--- v2.0.23/linux/init/main.c	Tue Oct  8 21:20:14 1996
+++ linux/init/main.c	Wed Oct 30 03:42:41 1996
@@ -50,7 +50,7 @@
 #endif
 
 extern char _stext, _etext;
-extern char *linux_banner;
+extern const char *linux_banner;
 
 static char printbuf[1024];
 
@@ -65,7 +65,7 @@
 extern long console_init(long, long);
 extern long kmalloc_init(long,long);
 extern void sock_init(void);
-extern long pci_init(long, long);
+extern unsigned long pci_init(unsigned long, unsigned long);
 extern void sysctl_init(void);
 
 extern void no_scroll(char *str, int *ints);
diff -u --recursive --new-file v2.0.23/linux/kernel/exit.c linux/kernel/exit.c
--- v2.0.23/linux/kernel/exit.c	Fri Jul  5 13:48:39 1996
+++ linux/kernel/exit.c	Wed Oct 30 03:42:42 1996
@@ -21,7 +21,7 @@
 #include <asm/pgtable.h>
 
 extern void sem_exit (void);
-extern void acct_process (long exitcode);
+extern int acct_process (long exitcode);
 extern void kerneld_exit(void);
 
 int getrusage(struct task_struct *, int, struct rusage *);
diff -u --recursive --new-file v2.0.23/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.0.23/linux/kernel/ksyms.c	Sun Sep 15 10:34:18 1996
+++ linux/kernel/ksyms.c	Wed Oct 30 03:42:42 1996
@@ -65,13 +65,13 @@
 #endif
 
 extern char *get_options(char *str, int *ints);
-extern void set_device_ro(int dev,int flag);
+extern void set_device_ro(kdev_t dev,int flag);
 extern struct file_operations * get_blkfops(unsigned int);
 extern void blkdev_release(struct inode * inode);
 
 extern void *sys_call_table;
 
-extern int sys_tz;
+extern struct timezone sys_tz;
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
 
diff -u --recursive --new-file v2.0.23/linux/net/802/Makefile linux/net/802/Makefile
--- v2.0.23/linux/net/802/Makefile	Tue Apr  9 14:36:31 1996
+++ linux/net/802/Makefile	Wed Oct 30 03:42:42 1996
@@ -14,6 +14,10 @@
 O_OBJS += tr.o
 endif
 
+ifdef CONFIG_FDDI
+O_OBJS += fddi.o
+endif
+
 ifdef CONFIG_IPX
 OX_OBJS += p8022.o psnap.o p8022tr.o
 endif
diff -u --recursive --new-file v2.0.23/linux/net/802/fddi.c linux/net/802/fddi.c
--- v2.0.23/linux/net/802/fddi.c	Thu Jan  1 02:00:00 1970
+++ linux/net/802/fddi.c	Wed Oct 30 04:36:35 1996
@@ -0,0 +1,162 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		FDDI-type device handling.
+ *
+ * Version:	@(#)fddi.c	1.0.0	08/12/96
+ *
+ * Authors:	Lawrence V. Stefani, <stefani@lkg.dec.com>
+ *
+ *		fddi.c is based on previous eth.c and tr.c work by
+ *			Ross Biro, <bir7@leland.Stanford.Edu>
+ *			Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *			Mark Evans, <evansmp@uhura.aston.ac.uk>
+ *			Florian La Roche, <rzsfl@rz.uni-sb.de>
+ *			Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * 
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <net/arp.h>
+#include <net/sock.h>
+
+/*
+ * Create the FDDI MAC header for an arbitrary protocol layer
+ *
+ * saddr=NULL	means use device source address
+ * daddr=NULL	means leave destination address (eg unresolved arp)
+ */
+
+int fddi_header(
+	struct sk_buff	*skb,
+	struct device	*dev,
+	unsigned short	type,
+	void			*daddr,
+	void			*saddr,
+	unsigned		len
+	)
+
+	{
+	struct fddihdr *fddi = (struct fddihdr *)skb_push(skb, FDDI_K_SNAP_HLEN);
+
+	/* Fill in frame header - assume 802.2 SNAP frames for now */
+
+	fddi->fc					 = FDDI_FC_K_ASYNC_LLC_DEF;
+	fddi->hdr.llc_snap.dsap		 = FDDI_EXTENDED_SAP;
+	fddi->hdr.llc_snap.ssap		 = FDDI_EXTENDED_SAP;
+	fddi->hdr.llc_snap.ctrl		 = FDDI_UI_CMD;
+	fddi->hdr.llc_snap.oui[0]	 = 0x00;
+	fddi->hdr.llc_snap.oui[1]	 = 0x00;
+	fddi->hdr.llc_snap.oui[2]	 = 0x00;
+	fddi->hdr.llc_snap.ethertype = htons(type);
+
+	/* Set the source and destination hardware addresses */
+	 
+	if (saddr != NULL)
+		memcpy(fddi->saddr, saddr, dev->addr_len);
+	else
+		memcpy(fddi->saddr, dev->dev_addr, dev->addr_len);
+
+	if (daddr != NULL)
+		{
+		memcpy(fddi->daddr, daddr, dev->addr_len);
+		return(FDDI_K_SNAP_HLEN);
+		}
+	return(-FDDI_K_SNAP_HLEN);
+	}
+
+
+/*
+ * Rebuild the FDDI MAC header. This is called after an ARP
+ * (or in future other address resolution) has completed on
+ * this sk_buff.  We now let ARP fill in the other fields.
+ */
+ 
+int fddi_rebuild_header(
+	void			*buff,
+	struct device	*dev,
+	unsigned long	dest,
+	struct sk_buff	*skb
+	)
+
+	{
+	struct fddihdr *fddi = (struct fddihdr *)buff;
+
+	/* Only ARP/IP is currently supported */
+	 
+	if (fddi->hdr.llc_snap.ethertype != htons(ETH_P_IP))
+		{
+		printk("fddi_rebuild_header: Don't know how to resolve type %04X addresses?\n", (unsigned int)htons(fddi->hdr.llc_snap.ethertype));
+		return(0);
+		}
+
+	/* Try to get ARP to resolve the header and fill destination address */
+
+	if (arp_find(fddi->daddr, dest, dev, dev->pa_addr, skb))
+		return(1);
+	else
+		return(0);
+	}
+
+
+/*
+ * Determine the packet's protocol ID and fill in skb fields.
+ * This routine is called before an incoming packet is passed
+ * up.  It's used to fill in specific skb fields and to set
+ * the proper pointer to the start of packet data (skb->data).
+ */
+ 
+unsigned short fddi_type_trans(
+	struct sk_buff	*skb,
+	struct device	*dev
+	)
+
+	{
+	struct fddihdr *fddi = (struct fddihdr *)skb->data;
+
+	/*
+	 * Set mac.raw field to point to FC byte, set data field to point
+	 * to start of packet data.  Assume 802.2 SNAP frames for now.
+	 */
+
+	skb->mac.raw = skb->data;			/* point to frame control (FC) */
+	skb_pull(skb, FDDI_K_SNAP_HLEN);	/* adjust for 21 byte header */
+
+	/* Set packet type based on destination address and flag settings */
+			
+	if (*fddi->daddr & 0x01)
+		{
+		if (memcmp(fddi->daddr, dev->broadcast, FDDI_K_ALEN) == 0)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+		}
+	
+	else if (dev->flags & IFF_PROMISC)
+		{
+		if (memcmp(fddi->daddr, dev->dev_addr, FDDI_K_ALEN))
+			skb->pkt_type = PACKET_OTHERHOST;
+		}
+
+	/* Assume 802.2 SNAP frames, for now */
+
+	return(fddi->hdr.llc_snap.ethertype);
+	}
diff -u --recursive --new-file v2.0.23/linux/net/core/dev.c linux/net/core/dev.c
--- v2.0.23/linux/net/core/dev.c	Mon Aug  5 10:13:55 1996
+++ linux/net/core/dev.c	Wed Oct 30 03:42:42 1996
@@ -47,6 +47,9 @@
  *					1 device.
  *	    Thomas Bogendoerfer :	Return ENODEV for dev_open, if there
  *					is no device open function.
+ *	    Lawrence V. Stefani	:	Changed set MTU ioctl to not assume
+ *					min MTU of 68 bytes for devices
+ *					that have change MTU functions.
  *
  */
 
@@ -1196,17 +1199,17 @@
 	
 		case SIOCSIFMTU:	/* Set the MTU of a device */
 		
-			/*
-			 *	MTU must be positive.
-			 */
-			 
-			if(ifr.ifr_mtu<68)
-				return -EINVAL;
-
 			if (dev->change_mtu)
 				ret = (*dev->change_mtu)(dev, ifr.ifr_mtu);
 			else
 			{
+				/*
+				 *	MTU must be positive.
+				 */
+			 
+				if(ifr.ifr_mtu<68)
+					return -EINVAL;
+
 				dev->mtu = ifr.ifr_mtu;
 				ret = 0;
 			}
@@ -1367,7 +1370,7 @@
 extern int ni65_init(void);
 extern int pi_init(void);
 extern void sdla_setup(void);
-extern void dlci_setup(void);
+extern int dlci_setup(void);
 
 int net_dev_init(void)
 {
diff -u --recursive --new-file v2.0.23/linux/net/core/sock.c linux/net/core/sock.c
--- v2.0.23/linux/net/core/sock.c	Wed Aug 21 09:18:10 1996
+++ linux/net/core/sock.c	Wed Oct 30 03:42:42 1996
@@ -443,7 +443,7 @@
 {
 	struct sk_buff *skb;
 	int err;
-
+	unsigned long mem;
 	do
 	{
 		if(sk->err!=0)
@@ -462,6 +462,9 @@
 			return NULL;
 		}
 		
+		
+		mem=sk->wmem_alloc;
+		
 		if(!fallback)
 			skb = sock_wmalloc(sk, size, 0, sk->allocation);
 		else
@@ -479,8 +482,6 @@
 		 
 		if(skb==NULL)
 		{
-			unsigned long tmp;
-
 			sk->socket->flags |= SO_NOSPACE;
 			if(noblock)
 			{
@@ -492,7 +493,6 @@
 				*errcode=-EPIPE;
 				return NULL;
 			}
-			tmp = sk->wmem_alloc;
 			cli();
 			if(sk->shutdown&SEND_SHUTDOWN)
 			{
@@ -501,19 +501,7 @@
 				return NULL;
 			}
 			
-#if 1
-			if( tmp <= sk->wmem_alloc)
-#else
-			/* ANK: Line above seems either incorrect
-			 *	or useless. sk->wmem_alloc has a tiny chance to change
-			 *	between tmp = sk->w... and cli(),
-			 *	but it might(?) change earlier. In real life
-			 *	it does not (I never seen the message).
-			 *	In any case I'd delete this check at all, or
-			 *	change it to:
-			 */
-			if (sk->wmem_alloc + size >= sk->sndbuf) 
-#endif
+			if (sk->wmem_alloc==mem)
 			{
 				sk->socket->flags &= ~SO_NOSPACE;
 				interruptible_sleep_on(sk->sleep);
diff -u --recursive --new-file v2.0.23/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.0.23/linux/net/ipv4/arp.c	Tue Oct  8 21:20:14 1996
+++ linux/net/ipv4/arp.c	Wed Oct 30 03:42:42 1996
@@ -60,6 +60,7 @@
  *		Mike Shaver	:	/proc/sys/net/ipv4/arp_* support
  *		Stuart Cheshire	:	Metricom and grat arp fixes
  *					*** FOR 2.1 clean this up ***
+ *		Lawrence V. Stefani: (08/12/96) Added FDDI support.
  */
 
 /* RFC1122 Status:
@@ -86,6 +87,7 @@
 #include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/fddidevice.h>
 #include <linux/if_arp.h>
 #include <linux/trdevice.h>
 #include <linux/skbuff.h>
@@ -1289,7 +1291,8 @@
 			return 1;
 #ifdef CONFIG_IP_MULTICAST
 		case IS_MULTICAST:
-			if(dev->type==ARPHRD_ETHER || dev->type==ARPHRD_IEEE802)
+			if(dev->type==ARPHRD_ETHER || dev->type==ARPHRD_IEEE802 
+				|| dev->type==ARPHRD_FDDI)
 			{
 				u32 taddr;
 				haddr[0]=0x01;
@@ -1702,11 +1705,23 @@
 	/*
 	 *	Fill the device header for the ARP frame
 	 */
-
 	dev->hard_header(skb,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len);
 
-	/* Fill out the arp protocol part. */
+	/*
+	 * Fill out the arp protocol part.
+	 *
+	 * The arp hardware type should match the device type, except for FDDI,
+	 * which (according to RFC 1390) should always equal 1 (Ethernet).
+	 */
+#ifdef CONFIG_FDDI
+	arp->ar_hrd = (dev->type == ARPHRD_FDDI) ? htons(ARPHRD_ETHER) : htons(dev->type);
+#else
 	arp->ar_hrd = htons(dev->type);
+#endif
+	/*
+	 *	Exceptions everywhere. AX.25 uses the AX.25 PID value not the
+	 *	DIX code for the protocol. Make these device structure fields.
+	 */
 #ifdef CONFIG_AX25
 #ifdef CONFIG_NETROM
 	arp->ar_pro = (dev->type == ARPHRD_AX25 || dev->type == ARPHRD_NETROM) ? htons(AX25_P_IP) : htons(ETH_P_IP);
@@ -1751,7 +1766,7 @@
 	unsigned char *arp_ptr= (unsigned char *)(arp+1);
 	unsigned char *sha,*tha;
 	u32 sip,tip;
-	
+
 /*
  *	The hardware length of the packet should match the hardware length
  *	of the device.  Similarly, the hardware types should match.  The
@@ -1759,16 +1774,44 @@
  *	is not from an IP number.  We can't currently handle this, so toss
  *	it. 
  */  
+#ifdef CONFIG_FDDI
+	if (dev->type == ARPHRD_FDDI)
+	{
+		/*
+		 * According to RFC 1390, FDDI devices should accept ARP hardware types
+		 * of 1 (Ethernet).  However, to be more robust, we'll accept hardware
+		 * types of either 1 (Ethernet) or 6 (IEEE 802.2).
+		 */
+		if (arp->ar_hln != dev->addr_len    || 
+			((ntohs(arp->ar_hrd) != ARPHRD_ETHER) && (ntohs(arp->ar_hrd) != ARPHRD_IEEE802)) ||
+			dev->flags & IFF_NOARP          ||
+			arp->ar_pln != 4)
+		{
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
+	}
+	else
+	{
+		if (arp->ar_hln != dev->addr_len    || 
+			dev->type != ntohs(arp->ar_hrd) ||
+			dev->flags & IFF_NOARP          ||
+			arp->ar_pln != 4)
+		{
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
+	}
+#else
 	if (arp->ar_hln != dev->addr_len    || 
-     		dev->type != ntohs(arp->ar_hrd) || 
+		dev->type != ntohs(arp->ar_hrd) ||
 		dev->flags & IFF_NOARP          ||
 		arp->ar_pln != 4)
 	{
 		kfree_skb(skb, FREE_READ);
 		return 0;
-		/* Should this be an error/printk?  Seems like something */
-		/* you'd want to know about. Unless it's just !IFF_NOARP. -- MS */
 	}
+#endif
 
 /*
  *	Another test.
@@ -1776,7 +1819,6 @@
  *	match the protocol the device speaks.  If it doesn't, there is a
  *	problem, so toss the packet.
  */
-/* Again, should this be an error/printk? -- MS */
 
   	switch (dev->type)
   	{
@@ -1801,14 +1843,8 @@
 		case ARPHRD_ETHER:
 		case ARPHRD_ARCNET:
 		case ARPHRD_METRICOM:
-			if(arp->ar_pro != htons(ETH_P_IP))
-			{
-				kfree_skb(skb, FREE_READ);
-				return 0;
-			}
-			break;
-
 		case ARPHRD_IEEE802:
+		case ARPHRD_FDDI:
 			if(arp->ar_pro != htons(ETH_P_IP))
 			{
 				kfree_skb(skb, FREE_READ);
diff -u --recursive --new-file v2.0.23/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.0.23/linux/net/ipv4/icmp.c	Tue Oct  8 21:20:14 1996
+++ linux/net/ipv4/icmp.c	Wed Oct 30 03:42:42 1996
@@ -282,11 +282,11 @@
   { ENONET,		1 },	/*	ICMP_HOST_ISOLATED	*/
   { ENETUNREACH,	1 },	/*	ICMP_NET_ANO		*/
   { EHOSTUNREACH,	1 },	/*	ICMP_HOST_ANO		*/
-  { EOPNOTSUPP,		0 },	/*	ICMP_NET_UNR_TOS	*/
-  { EOPNOTSUPP,		0 },	/*	ICMP_HOST_UNR_TOS	*/
-  { EOPNOTSUPP,		1 },	/*	ICMP_PKT_FILTERED	*/
-  { EOPNOTSUPP,		1 },	/*	ICMP_PREC_VIOLATION	*/
-  { EOPNOTSUPP,		1 }	/*	ICMP_PREC_CUTOFF	*/
+  { ENETUNREACH,	0 },	/*	ICMP_NET_UNR_TOS	*/
+  { EHOSTUNREACH,	0 },	/*	ICMP_HOST_UNR_TOS	*/
+  { EHOSTUNREACH,	1 },	/*	ICMP_PKT_FILTERED	*/
+  { EHOSTUNREACH,	1 },	/*	ICMP_PREC_VIOLATION	*/
+  { EHOSTUNREACH,	1 }	/*	ICMP_PREC_CUTOFF	*/
 };
 
 /*
@@ -1030,6 +1030,14 @@
 	int r;
 #endif
 	icmp_statistics.IcmpInMsgs++;
+	
+	if(len < sizeof(struct icmphdr))
+	{
+		icmp_statistics.IcmpInErrors++;
+		printk(KERN_INFO "ICMP: runt packet\n");
+		kfree_skb(skb, FREE_READ);
+		return 0;
+	}
 	
   	/*
 	 *	Validate the packet
diff -u --recursive --new-file v2.0.23/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v2.0.23/linux/net/ipv4/igmp.c	Wed Aug 21 09:18:10 1996
+++ linux/net/ipv4/igmp.c	Wed Oct 30 03:42:42 1996
@@ -248,7 +248,7 @@
 
 	if(skb==NULL)
 		return;
-	tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL,
+	tmp=ip_build_header(skb, dev->pa_addr, address, &dev, IPPROTO_IGMP, NULL,
 				28 , 0, 1, NULL);
 	if(tmp<0)
 	{
@@ -452,7 +452,7 @@
 	}
 	ih=(struct igmphdr *)skb->h.raw;
 
-	if(skb->len <sizeof(struct igmphdr) || skb->ip_hdr->ttl<1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr)))
+	if(len <sizeof(struct igmphdr) || skb->ip_hdr->ttl<1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr)))
 	{
 		kfree_skb(skb, FREE_READ);
 		return 0;
diff -u --recursive --new-file v2.0.23/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v2.0.23/linux/net/ipv4/ip_forward.c	Sat Oct 19 10:06:12 1996
+++ linux/net/ipv4/ip_forward.c	Wed Oct 30 03:42:42 1996
@@ -230,9 +230,10 @@
 
 		/* This is for ip encap. Anand, ernet.*/
 
-		if (is_frag&IPFWD_MULTITUNNEL) {
+		if (is_frag&IPFWD_MULTITUNNEL)
+		{
 			encap=20;
-				}
+		}
 	}
 	else
 	{
diff -u --recursive --new-file v2.0.23/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.0.23/linux/net/ipv4/ip_fragment.c	Sat Aug 10 10:03:16 1996
+++ linux/net/ipv4/ip_fragment.c	Wed Oct 30 03:42:42 1996
@@ -24,6 +24,7 @@
 #include <net/icmp.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#include <linux/inet.h>
 #include <linux/firewall.h>
 #include <linux/ip_fw.h>
 #include <net/checksum.h>
@@ -47,6 +48,8 @@
 
 atomic_t ip_frag_mem = 0;			/* Memory used for fragments */
 
+char *in_ntoa(unsigned long in);
+
 /*
  *	Memory Tracking Functions
  */
@@ -337,7 +340,15 @@
 	 *	Allocate a new buffer for the datagram.
 	 */
 	len = qp->ihlen + qp->len;
-
+	
+	if(len>65535)
+	{
+		printk("Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr));
+		ip_statistics.IpReasmFails++;
+		ip_free(qp);
+		return NULL;
+	}
+	
 	if ((skb = dev_alloc_skb(len)) == NULL)
 	{
 		ip_statistics.IpReasmFails++;
@@ -366,7 +377,7 @@
 		{
 			NETDEBUG(printk("Invalid fragment list: Fragment over size.\n"));
 			ip_free(qp);
-			frag_kfree_skb(skb,FREE_WRITE);
+			kfree_skb(skb,FREE_WRITE);
 			ip_statistics.IpReasmFails++;
 			return NULL;
 		}
@@ -424,7 +435,7 @@
 	if (((flags & IP_MF) == 0) && (offset == 0))
 	{
 		if (qp != NULL)
-			ip_free(qp);	/* Huh? How could this exist?? */
+			ip_free(qp);	/* Fragmented frame replaced by full unfragmented copy */
 		return(skb);
 	}
 
@@ -461,11 +472,24 @@
 		if ((qp = ip_create(skb, iph, dev)) == NULL)
 		{
 			skb->sk = NULL;
-			frag_kfree_skb(skb, FREE_READ);
+			kfree_skb(skb, FREE_READ);
 			ip_statistics.IpReasmFails++;
 			return NULL;
 		}
 	}
+	
+	/*
+	 *	Attempt to construct an oversize packet.
+	 */
+	 
+	if(ntohs(iph->tot_len)+(int)offset>65535)
+	{
+		skb->sk = NULL;
+		printk("Oversized packet received from %s\n",in_ntoa(iph->saddr));
+		frag_kfree_skb(skb, FREE_READ);
+		ip_statistics.IpReasmFails++;
+		return NULL;
+	}	
 
 	/*
 	 *	Determine the position of this fragment.
diff -u --recursive --new-file v2.0.23/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.0.23/linux/net/ipv4/ip_output.c	Tue Jul  9 14:28:32 1996
+++ linux/net/ipv4/ip_output.c	Wed Oct 30 03:42:42 1996
@@ -123,13 +123,13 @@
 	skb->dev = dev;
 	skb->arp = 1;
 	skb->protocol = htons(ETH_P_IP);
+	skb_reserve(skb,(dev->hard_header_len+15)&~15);	/* 16 byte aligned IP headers are always good */
 	if (dev->hard_header)
 	{
 		/*
 		 *	Build a hardware header. Source address is our mac, destination unknown
 		 *  	(rebuild header will sort this out)
 		 */
-		skb_reserve(skb,(dev->hard_header_len+15)&~15);	/* 16 byte aligned IP headers are good */
 		if (rt && dev == rt->rt_dev && rt->rt_hh)
 		{
 			memcpy(skb_push(skb,dev->hard_header_len),rt->rt_hh->hh_data,dev->hard_header_len);
diff -u --recursive --new-file v2.0.23/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.0.23/linux/net/ipv4/ipmr.c	Fri Jul 19 08:24:05 1996
+++ linux/net/ipv4/ipmr.c	Wed Oct 30 03:42:42 1996
@@ -17,6 +17,8 @@
  *	Malcolm Beattie		:	Buffer handling fixes.
  *	Alexey Kuznetsov	:	Double buffer free and other fixes.
  *	SVR Anand		:	Fixed several multicast bugs and problems.
+ *	Alexey Kuznetsov	:	Subset of bugfixes/changes pending for
+ *					2.1. Doesn't include Alexey's PIM support.
  *
  *	Status:
  *		Cache manager under test. Forwarding in vague test mode
@@ -60,8 +62,8 @@
 static struct vif_device vif_table[MAXVIFS];		/* Devices 		*/
 static unsigned long vifc_map;				/* Active device map	*/
 int mroute_do_pim = 0;					/* Set in PIM assert	*/
-static struct mfc_cache *mfc_cache_array[MFC_LINES];	/* Forwarding cache	*/
-static struct mfc_cache *cache_resolve_queue;		/* Unresolved cache	*/
+static struct mfc_cache *mfc_cache_array[MFC_LINES+1];	/* Forwarding cache	*/
+#define cache_resolve_queue (mfc_cache_array[MFC_LINES])/* Unresolved cache 	*/
 int cache_resolve_queue_len = 0;			/* Size of unresolved	*/
 
 /*
@@ -79,22 +81,6 @@
 }
 
 /*
- *	Find a vif
- */
- 
-static int ipmr_vifi_find(struct device *dev)
-{
-	struct vif_device *v=&vif_table[0];
-	int ct;
-	for(ct=0;ct<MAXVIFS;ct++,v++)
-	{
-		if(v->dev==dev)
-			return ct;
-	}
-	return -1;
-}
-
-/*
  *	Delete a multicast route cache entry
  */
  
@@ -388,6 +374,8 @@
 		 */
 
 		cache->mfc_flags|=MFC_RESOLVED;
+		cache->mfc_parent=mfc->mfcc_parent;
+		
 		memcpy(cache->mfc_ttls, mfc->mfcc_ttls,sizeof(cache->mfc_ttls));
 		 
 		/*
@@ -733,12 +721,7 @@
 	struct mfc_cache *cache;
 	struct sk_buff *skb2;
 	int psend = -1;
-	int vif=ipmr_vifi_find(skb->dev);
-	if(vif==-1)
-	{
-		kfree_skb(skb, FREE_WRITE);
-		return;
-	}
+ 	int vif,ct=0;
 
 	/*
 	 *	Without the following addition, skb->h.iph points to something
@@ -747,56 +730,63 @@
 	
 	skb->h.iph = skb->ip_hdr;  /* Anand, ernet.  */
 
-	vif_table[vif].pkt_in++;
-	vif_table[vif].bytes_in+=skb->len;
-	
 	cache=ipmr_cache_find(skb->ip_hdr->saddr,skb->ip_hdr->daddr);
-	
+
 	/*
 	 *	No usable cache entry
 	 */
 	 
 	if(cache==NULL || (cache->mfc_flags&MFC_QUEUED))
-		ipmr_cache_unresolved(cache,vif,skb, is_frag);
-	else
 	{
-		/*
-		 *	Forward the frame
-		 */
-		 int ct=0;
-		 while(ct<MAXVIFS)
-		 {
-		 	/*
-		 	 *	0 means don't do it. Silly idea, 255 as don't do it would be cleaner!
-		 	 */
-		 	if(skb->ip_hdr->ttl > cache->mfc_ttls[ct] && cache->mfc_ttls[ct]>0)
-		 	{
-		 		if(psend!=-1)
-		 		{
-		 			/*
-		 			 *	May get variant mac headers
-		 			 *	so must copy -- boo hoo.
-		 			 */
-		 			skb2=skb_copy(skb, GFP_ATOMIC);
-		 			if(skb2)
-		 			{
-		 				skb2->free=1;
-		 				ipmr_queue_xmit(skb2, &vif_table[psend], skb->dev, is_frag);
-		 			}
-				}
-				psend=ct;
+		ipmr_cache_unresolved(cache,ALL_VIFS,skb, is_frag);
+		return;
+	}
+
+	vif=cache->mfc_parent;
+	
+	if(vif>=MAXVIFS || !(vifc_map&(1<<vif)) ||
+		vif_table[vif].dev != skb->dev)
+	{
+		kfree_skb(skb, FREE_READ);
+		return;
+	}
+	
+	vif_table[vif].pkt_in++;
+	vif_table[vif].bytes_in+=skb->len;
+	
+	/*
+	 *	Forward the frame
+	 */
+
+	 while(ct<MAXVIFS)
+	 {
+	 	/*
+	 	 *	0 means don't do it. Silly idea, 255 as don't do it would be cleaner!
+	 	 */
+	 	if(skb->ip_hdr->ttl > cache->mfc_ttls[ct] && cache->mfc_ttls[ct]>0)
+	 	{
+	 		if(psend!=-1)
+	 		{
+	 			/*
+	 			 *	May get variant mac headers
+	 			 *	so must copy -- boo hoo.
+	 			 */
+	 			skb2=skb_copy(skb, GFP_ATOMIC);
+	 			if(skb2)
+	 			{
+	 				skb2->free=1;
+	 				ipmr_queue_xmit(skb2, &vif_table[psend], skb->dev, is_frag);
+	 			}
 			}
-			ct++;
-		}
-		if(psend==-1)
-			kfree_skb(skb, FREE_WRITE);
-		else
-		{
-			ipmr_queue_xmit(skb, &vif_table[psend], skb->dev, is_frag);
+			psend=ct;
 		}
-		/*
-		 *	Adjust the stats
-		 */
+		ct++;
+	}
+	if(psend==-1)
+		kfree_skb(skb, FREE_WRITE);
+	else
+	{
+		ipmr_queue_xmit(skb, &vif_table[psend], skb->dev, is_frag);
 	}
 }
 
@@ -855,40 +845,38 @@
 	int ct;
 
 	len += sprintf(buffer,
-		 "Group    Origin   SrcIface \n");
+		 "Group    Origin   SrcIface VifTtls\n");
 	pos=len;
   
-	for (ct=0;ct<MFC_LINES;ct++) 
+	for (ct=0;ct<MFC_LINES+1;ct++) 
 	{
 		cli();
 		mfc=mfc_cache_array[ct];
 		while(mfc!=NULL)
 		{
 			char *name="none";
-			char vifmap[MAXVIFS+1];
 			int n;
 			/*
 			 *	Device name
 			 */
-			if(vifc_map&(1<<mfc->mfc_parent))
+			if(mfc->mfc_parent < MAXVIFS && vifc_map&(1<<mfc->mfc_parent))
 				name=vif_table[mfc->mfc_parent].dev->name;
-			/*
-			 *	Interface forwarding map
-			 */
-			for(n=0;n<MAXVIFS;n++)
-				if(vifc_map&(1<<n) && mfc->mfc_ttls[ct])
-					vifmap[n]='X';
-				else
-					vifmap[n]='-';
-			vifmap[n]=0;
-			/*
-			 *	Now print it out
-			 */
-			size = sprintf(buffer+len, "%08lX %08lX %-8s %s\n",
+
+			size = sprintf(buffer+len, "%08lX %08lX %-8s",
 				(unsigned long)mfc->mfc_mcastgrp,
 				(unsigned long)mfc->mfc_origin,
-				name,
-				vifmap);
+				name);
+				
+			for(n=0;n<MAXVIFS;n++)
+			{
+				if(vifc_map&(1<<n))
+					size+=sprintf(buffer+len+size,
+						" %-3d", mfc->mfc_ttls[n]);
+				else
+					size+=sprintf(buffer+len+size,
+						" --- ");
+			}
+			size+=sprintf(buffer+len+size,"\n");
 			len+=size;
 			pos+=size;
 			if(pos<offset)
diff -u --recursive --new-file v2.0.23/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- v2.0.23/linux/net/ipv4/rarp.c	Mon Aug  5 10:13:55 1996
+++ linux/net/ipv4/rarp.c	Wed Oct 30 03:42:42 1996
@@ -28,7 +28,7 @@
  * Fixes
  *	Alan Cox	:	Rarp delete on device down needed as
  *				reported by Walter Wolfgang.
- *
+ *  Lawrence V. Stefani : Added FDDI support.
  */
 
 #include <linux/module.h>
@@ -204,13 +204,40 @@
 /*
  *	If this test doesn't pass, it's not IP, or we should ignore it anyway
  */
-
+#ifdef CONFIG_FDDI
+	if (dev->type == ARPHRD_FDDI)
+	{
+		/*
+		 * Since the dev->type for FDDI is "made up", compare the rarp->ar_hrd
+		 * field against ARPHRD_ETHER and ARPHRD_IEEE802.
+		 *
+		 * Ought to move to a device specifc 'arp_type_ok()'
+		 */
+		if (rarp->ar_hln != dev->addr_len
+			|| ((ntohs(rarp->ar_hrd) != ARPHRD_ETHER) && (ntohs(rarp->ar_hrd) != ARPHRD_IEEE802))
+			|| dev->flags&IFF_NOARP)
+		{
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
+	}
+	else
+	{
+		if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd) 
+			|| dev->flags&IFF_NOARP)
+			{
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
+	}
+#else
 	if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd) 
 		|| dev->flags&IFF_NOARP)
 	{
 		kfree_skb(skb, FREE_READ);
 		return 0;
 	}
+#endif
 
 /*
  *	If it's not a RARP request, delete it.
diff -u --recursive --new-file v2.0.23/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.0.23/linux/net/ipv4/tcp_input.c	Mon Sep  2 15:18:26 1996
+++ linux/net/ipv4/tcp_input.c	Wed Oct 30 04:13:01 1996
@@ -428,6 +428,8 @@
 			return;
 		}
 	}
+	
+	skb->when = jiffies;	/* For timeout */
 	skb_queue_head_init(&newsk->write_queue);
 	skb_queue_head_init(&newsk->receive_queue);
 	newsk->send_head = NULL;
@@ -470,6 +472,7 @@
 	newsk->delay_acks = 1;
 	newsk->copied_seq = skb->seq+1;
 	newsk->fin_seq = skb->seq;
+	newsk->syn_seq = skb->seq;
 	newsk->state = TCP_SYN_RECV;
 	newsk->timeout = 0;
 	newsk->ip_xmit_timeout = 0;
@@ -1587,6 +1590,9 @@
  *	moved inline now as tcp_urg is only called from one
  *	place. We handle URGent data wrong. We have to - as
  *	BSD still doesn't use the correction from RFC961.
+ *
+ *	For 1003.1g we should support a new option TCP_STDURG to permit
+ *	either form.
  */
  
 static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
@@ -1613,6 +1619,15 @@
 			kill_pg(-sk->proc, SIGURG, 1);
 		}
 	}
+	/*
+	 *	We may be adding urgent data when the last byte read was
+	 *	urgent. To do this requires some care. We cannot just ignore
+	 *	sk->copied_seq since we would read the last urgent byte again
+	 *	as data, nor can we alter copied_seq until this data arrives
+	 *	or we break the sematics of SIOCATMARK (and thus sockatmark())
+	 */
+	if (sk->urg_seq == sk->copied_seq)
+		sk->copied_seq++;	/* Move the copied sequence on correctly */
 	sk->urg_data = URG_NOTYET;
 	sk->urg_seq = ptr;
 }
@@ -1735,7 +1750,6 @@
 {
 	struct tcphdr *th;
 	struct sock *sk;
-	int syn_ok=0;
 	__u32 seq;
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	int r;
@@ -1959,7 +1973,6 @@
 				 *	Ok.. it's good. Set up sequence numbers and
 				 *	move to established.
 				 */
-				syn_ok=1;	/* Don't reset this connection for the syn */
 				sk->acked_seq = skb->seq+1;
 				sk->lastwin_seq = skb->seq+1;
 				sk->fin_seq = skb->seq;
@@ -2074,10 +2087,21 @@
 		return tcp_reset(sk,skb);
 	
 	/*
-	 *	!syn_ok is effectively the state test in RFC793.
+	 *	Check for a SYN, and ensure it matches the SYN we were
+	 *	first sent. We have to handle the rather unusual (but valid)
+	 *	sequence that KA9Q derived products may generate of
+	 *
+	 *	SYN
+	 *				SYN|ACK Data
+	 *	ACK	(lost)
+	 *				SYN|ACK Data + More Data
+	 *	.. we must ACK not RST...
+	 *
+	 *	We keep syn_seq as the sequence space occupied by the 
+	 *	original syn. 
 	 */
 	 
-	if(th->syn && !syn_ok)
+	if(th->syn && skb->seq!=sk->syn_seq)
 	{
 		tcp_send_reset(daddr,saddr,th, &tcp_prot, opt, dev, skb->ip_hdr->tos, 255);
 		return tcp_reset(sk,skb);	
diff -u --recursive --new-file v2.0.23/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.0.23/linux/scripts/Menuconfig	Fri Sep 20 17:00:36 1996
+++ linux/scripts/Menuconfig	Tue Oct 29 17:38:17 1996
@@ -860,11 +860,11 @@
 
 #
 # Load config options from a file.
-# Converts all "# OPTION is not set" lines to "OPTION=" lines
+# Converts all "# OPTION is not set" lines to "OPTION=n" lines
 #
 function load_config_file () {
 	awk '
-	  /# .* is not set.*/ { printf("%s=\n", $2) }
+	  /# .* is not set.*/ { printf("%s=n\n", $2) }
 	! /# .* is not set.*/ { print }
 	' $1 >.tmpconfig
 
@@ -1119,12 +1119,12 @@
 Please enter a hexadecimal value. \
 Use the <TAB> key to move from the input field to the buttons below it."
 
-backtitle="Linux Kernel Configuration"
-
 DIALOG="./scripts/lxdialog/lxdialog"
 
 kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}"
 
+backtitle="Linux Kernel v$kernel_version Configuration"
+
 trap "cleanup ; rm -f .menuconfig ; exit 1" 1 2 15
 
 
@@ -1146,7 +1146,7 @@
   echo "#"
   echo "# Using defaults found in" $DEFAULTS
   echo "#"
-  . $DEFAULTS
+  load_config_file $DEFAULTS
 else
   echo "#"
   echo "# No defaults found"
