diff -u --recursive --new-file v1.3.40/linux/Makefile linux/Makefile
--- v1.3.40/linux/Makefile	Sat Nov 11 17:41:32 1995
+++ linux/Makefile	Sun Nov 12 09:15:51 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 40
+SUBLEVEL = 41
 
 ARCH = i386
 
@@ -323,5 +323,5 @@
 
 .hdepend: dummy
 	rm -f $@
-	$(AWK) -f scripts/depend.awk `find $(HPATH) -name \*.h -print` > .$@
+	$(AWK) -f scripts/depend.awk `find $(HPATH) -name \*.h ! -name modversions.h -print` > .$@
 	mv .$@ $@
diff -u --recursive --new-file v1.3.40/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v1.3.40/linux/arch/alpha/defconfig	Sun Oct 29 11:38:47 1995
+++ linux/arch/alpha/defconfig	Sat Nov 11 16:54:34 1995
@@ -6,10 +6,19 @@
 # General setup
 #
 CONFIG_NATIVE=y
+# CONFIG_ALPHA_AVANTI is not set
+# CONFIG_ALPHA_JENSEN is not set
+# CONFIG_ALPHA_NONAME is not set
 CONFIG_ALPHA_CABRIOLET=y
+# CONFIG_ALPHA_EB66 is not set
+# CONFIG_ALPHA_EB66P is not set
+# CONFIG_ALPHA_EB64 is not set
+# CONFIG_ALPHA_EB64P is not set
 # CONFIG_ALPHA_SRM is not set
 CONFIG_PCI=y
 CONFIG_ALPHA_APECS=y
+# CONFIG_SERIAL_ECHO is not set
+# CONFIG_TGA_CONSOLE is not set
 CONFIG_PCI_OPTIMIZE=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
@@ -31,8 +40,8 @@
 #
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_TRITON is not set
 # CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_TRITON is not set
 # CONFIG_BLK_DEV_XD is not set
 
 #
@@ -43,7 +52,6 @@
 # CONFIG_IP_FORWARD is not set
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ACCT is not set
-# CONFIG_NET_IPIP is not set
 
 #
 # (it is safe to leave these untouched)
@@ -120,6 +128,7 @@
 CONFIG_NET_EISA=y
 # CONFIG_APRICOT is not set
 CONFIG_DE4X5=y
+# CONFIG_ETH16 is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_TR is not set
diff -u --recursive --new-file v1.3.40/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v1.3.40/linux/arch/alpha/kernel/head.S	Wed Sep 13 12:45:29 1995
+++ linux/arch/alpha/kernel/head.S	Sat Nov 11 17:17:25 1995
@@ -9,7 +9,6 @@
 
 #define __ASSEMBLY__
 #include <asm/system.h>
-#include <linux/fd.h>
 
 #define halt .long PAL_halt
 
diff -u --recursive --new-file v1.3.40/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v1.3.40/linux/arch/alpha/kernel/setup.c	Wed Nov  8 07:11:29 1995
+++ linux/arch/alpha/kernel/setup.c	Mon Nov 13 08:06:10 1995
@@ -21,6 +21,7 @@
 #include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/delay.h>
+#include <linux/config.h>	/* CONFIG_ALPHA_LCA etc */
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -66,24 +67,6 @@
 	16			/* orig-video-points */
 };
 
-/*
- * Initialize Programmable Interval Timers with standard values.  Some
- * drivers depend on them being initialized (e.g., joystick driver).
- */
-static void init_pit (void)
-{
-    outb(0x54, 0x43);	/* counter 1: refresh timer */
-    outb(0x18, 0x41);
-
-    outb(0x36, 0x43);	/* counter 0: system timer */
-    outb(0x00, 0x40);
-    outb(0x00, 0x40);
-
-    outb(0xb6, 0x43);	/* counter 2: speaker */
-    outb(0x31, 0x42);
-    outb(0x13, 0x42);
-}
-
 static unsigned long find_end_memory(void)
 {
 	int i;
@@ -109,8 +92,6 @@
 	unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
 	extern int _end;
-
-	init_pit();
 
 	hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr);
 
diff -u --recursive --new-file v1.3.40/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v1.3.40/linux/arch/alpha/mm/fault.c	Thu Jun  1 13:22:06 1995
+++ linux/arch/alpha/mm/fault.c	Sat Nov 11 16:54:34 1995
@@ -4,7 +4,6 @@
  *  Copyright (C) 1995  Linus Torvalds
  */
 
-#include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/head.h>
diff -u --recursive --new-file v1.3.40/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.3.40/linux/drivers/block/floppy.c	Sat Nov 11 17:41:32 1995
+++ linux/drivers/block/floppy.c	Sun Nov 12 09:14:21 1995
@@ -3015,7 +3015,7 @@
 	CLEARSTRUCT(UDRWE);
 }
 
-static inline int set_geometry(int cmd, struct floppy_struct *g,
+static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
 			       int drive, int type, int device)
 {
 	int cnt;
@@ -3114,14 +3114,14 @@
 {
 	int i, orig_size, ocmd;
 
-	orig_size = IOC_SIZE(*cmd);
+	orig_size = _IOC_SIZE(*cmd);
 	ocmd = *cmd;
 	for (i=0; i < ARRAY_SIZE(translation_table); i++) {
 		if ((*cmd & 0xff3f) == (translation_table[i].newcmd & 0xff3f)){
 			*cmd = translation_table[i].newcmd;
-			if (!orig_size && IOC_SIZE(*cmd)) {
-				/* kernels 1.3.34 to 1.3.37 : */
-				*size = IOC_SIZE(*cmd); 
+			if (!orig_size && _IOC_SIZE(*cmd)) {
+				/* kernels 1.3.34 to 1.3.39 : */
+				*size = _IOC_SIZE(*cmd); 
 				DPRINT1("warning: obsolete ioctl 0x%x\n",ocmd);
 				DPRINT("please recompile your program\n");
 				/* these ioctls only existed
@@ -3132,7 +3132,7 @@
 				 */
 			} else {
 				*size = orig_size;
-				if (*size > IOC_SIZE(*cmd)) {
+				if (*size > _IOC_SIZE(*cmd)) {
 					printk("ioctl not yet supported\n");
 					return -EFAULT;
 				}
@@ -3261,7 +3261,7 @@
 
 		case FDGETDRVTYP:
 			outparam = drive_name(type,drive);
-			SUPBOUND(size,strlen(outparam));
+			SUPBOUND(size,strlen(outparam)+1);
 			break;
 
 		IN(FDSETDRVPRM, UDP, dp);
diff -u --recursive --new-file v1.3.40/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v1.3.40/linux/drivers/cdrom/mcd.c	Thu Nov  9 11:23:47 1995
+++ linux/drivers/cdrom/mcd.c	Mon Nov 13 08:54:55 1995
@@ -59,21 +59,26 @@
 	DOS DRIVERS .... Accuracy counts... speed is secondary ;)
 	17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
 	07 July 1995 Modifications by Andrew J. Kroll
-	
-	0.6
-        8 November 95 More Modifications By Andrew J. Kroll
-        Media change detect now works :) That means that SuperMount and
-        other programs that depend on this will now work!
-        You are welcome in advance!  You will notice, however that you don't 
-        always get the kernel message saying "VFS: Disk change detected on 
-        device", so I'm not sure that it's *PERFECT* but it does seem to
-        actually work! What else should I add?
-	                                                         
 
 */
 
+#include <linux/config.h>
+
+#ifdef MODULE
+# include <linux/module.h>
+#endif
+
+#include <linux/version.h>
 
-#include <linux/module.h>
+#ifdef MODULE
+# ifndef CONFIG_MODVERSIONS
+    char kernel_version[]= UTS_RELEASE;
+# endif
+#define mcd_init init_module
+#else
+# define MOD_INC_USE_COUNT
+# define MOD_DEC_USE_COUNT
+#endif
 
 #include <linux/errno.h>
 #include <linux/signal.h>
@@ -138,28 +143,30 @@
 #endif
 /* #define DOUBLE_QUICK_ONLY */
 
-#define CURRENT_VALID \
-  (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
-   && CURRENT -> sector != -1)
+#if LINUX_VERSION_CODE < 66338
+    #define CURRENT_VALID \
+    (CURRENT && MAJOR(CURRENT -> dev) == MAJOR_NR && CURRENT -> cmd == READ \
+    && CURRENT -> sector != -1)
+#else
+    #define CURRENT_VALID \
+    (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
+    && CURRENT -> sector != -1)
+#endif
 #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
 #define MCD_BUF_SIZ 16
 static volatile int mcd_transfer_is_active;
-
-/* Are you sleeping, Are you sleeping, Brother John, Brother John? ;) */
-static volatile int sleeping_for_status;
-
 static char mcd_buf[2048*MCD_BUF_SIZ];	/* buffer for block size conversion */
 static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
 static volatile int mcd_buf_in, mcd_buf_out = -1;
 static volatile int mcd_error;
 static int mcd_open_count;
 enum mcd_state_e {
-  MCD_S_IDLE,    /* 0 */
-  MCD_S_START,   /* 1 */
-  MCD_S_MODE,    /* 2 */
-  MCD_S_READ,    /* 3 */
-  MCD_S_DATA,    /* 4 */
-  MCD_S_STOP,    /* 5 */
+  MCD_S_IDLE,   /* 0 */
+  MCD_S_START,  /* 1 */
+  MCD_S_MODE, /* 2 */
+  MCD_S_READ,   /* 3 */
+  MCD_S_DATA,   /* 4 */
+  MCD_S_STOP,   /* 5 */
   MCD_S_STOPPING /* 6 */
 };
 static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
@@ -214,7 +221,35 @@
       mitsumi_bug_93_wait = ints[3];
 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
 }
+
  
+static int
+#if LINUX_VERSION_CODE < 66338
+check_mcd_change(dev_t full_dev)
+#else
+check_mcd_change(kdev_t full_dev)
+#endif
+{
+   int retval, target;
+
+
+#if 1	 /* the below is not reliable */
+   return 0;
+#endif  
+   target = MINOR(full_dev);
+
+   if (target > 0) {
+      printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
+      return 0;
+   }
+
+   retval = mcdDiskChanged;
+   mcdDiskChanged = 0;
+
+   return retval;
+}
+
+
 /*
  * Do a 'get status' command and get the result.  Only use from the top half
  * because it calls 'getMcdStatus' which sleeps.
@@ -237,69 +272,6 @@
 	return st;
 }
 
-/*
- *             This detects a media change on the CD ROM.
- *        We need to grab the status right off the drive in here.
- *     Before, it ALWAYS returned a value of 0, which was not right!
- */
- 
-static int
-check_mcd_change(dev_t full_dev)
-{
-   int retval, target, st, count;
-   st = -1;
-   target = MINOR(full_dev);
-
-   if (target > 0) 
-   	{
-   	printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
-   	return 0;
-   	}
-
-/* 
- * SOMETIMES it changes, sometimes not! Well, here we FIX that little nasty!
- * All we need to do is read the status from the drive without spamming the 
- * kernel! In other words, this routine CANNOT sleep! 
- * The kernel will automagically picks up on this now.
- * Devilishly sneaky it is! 8) -- AJK
- */
-if ((!mcd_transfer_is_active) && 
-    (!sleeping_for_status) &&
-    (mcd_state == MCD_S_IDLE)) /* YES I'm paraniod! :) */
-	{
-	outb(MCMD_GET_STATUS, MCDPORT(0)); 	/* send get-status cmd */
-	for (count = 0; count < 3000; count++) /* wait for the status */
-		{
-		if (!(inb(MCDPORT(1)) & MFL_STATUS))
-			break;
-		}
-	if (count >= 3000)	/* Did we time out? */
-		{
-		retval = mcdDiskChanged; /* We can just jump out of here */
-		mcdDiskChanged = 0; /* as it's not needed all the time. */
-		return retval;	/* So we pretend nothing happened here! ;) */
-		}
-	st=inb(MCDPORT(0)) & 0xFF ;	/* Read the status in... */
-       
-	/* okay... here's that magic part! Muhuhuhuh...*/
-
-	if (st & MST_DSK_CHG)      /* Devil made me do it! O];) */ 
-		{
-		mcdDiskChanged = 1;  /* Show a change. */
-		audioStatus = CDROM_AUDIO_NO_STATUS; /* just incase... */
-		tocUpToDate = 0; 	/* Frantic laughing continues... */
-		mcd_invalidate_buffers(); /* 666 wins! */
-      		}		/* Stupid comments are fun! */
-	
-	
-	}
- 
-   retval = mcdDiskChanged; /* Indicate status. */
-   mcdDiskChanged = 0;   /* Go, now. Enjoy a good beer! */
-
-   return retval; /* The End. */
-}
-
 
 /*
  * Send a 'Play' command and get the status.  Use only from the top half.
@@ -1217,7 +1189,7 @@
 {
 	int count;
 	unsigned char result[3];
-        sleeping_for_status = 0;
+
 	if (mcd_port <= 0 || mcd_irq <= 0) {
 	  printk("skip mcd_init\n");
           return -EIO;
@@ -1419,14 +1391,10 @@
 
 	McdTimeout = timeout;
 	SET_TIMER(mcdStatTimer, 1);
-        sleeping_for_status = 1;
-        sleep_on(&mcd_waitq);
+	sleep_on(&mcd_waitq);
 	if (McdTimeout <= 0)
-		{
-		sleeping_for_status = 0;
-	      	return -1;
-		}
-	sleeping_for_status = 0;
+		return -1;
+
 	st = inb(MCDPORT(0)) & 0xFF;
 	if (st == 0xFF)
 		return -1;
@@ -1662,13 +1630,11 @@
 }
 
 #ifdef MODULE
-int init_module(void)
-{
-	return mcd_init();
-}
-
 void cleanup_module(void)
-{
+{ if (MOD_IN_USE)
+     { printk("mcd module in use - can't remove it.\n");
+       return;    
+     }
   if ((unregister_blkdev(MAJOR_NR, "mcd") == -EINVAL))
      { printk("What's that: can't unregister mcd\n");
        return;    
diff -u --recursive --new-file v1.3.40/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- v1.3.40/linux/drivers/cdrom/mcdx.c	Thu Nov  9 11:23:47 1995
+++ linux/drivers/cdrom/mcdx.c	Mon Nov 13 08:54:55 1995
@@ -1,7 +1,7 @@
 /*
  * The Mitsumi CDROM interface
- * Copyright (C) 1995 Heiko Schlittermann
- * VERSION: 1.0a
+ * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
+ * VERSION: 1.3
  * 
  * 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
@@ -34,10 +34,26 @@
 
 #if RCS
 static const char *mcdx_c_version
-		= "mcdx.c,v 1.7 1995/08/27 01:46:41 heiko Exp";
+		= "mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp";
 #endif
 
+#include <linux/config.h>
+
+#ifdef MODULE
 #include <linux/module.h>
+#endif
+
+#include <linux/version.h>
+
+#ifdef MODULE
+#ifndef CONFIG_MODVERSIONS
+char kernel_version[] = UTS_RELEASE;
+#endif
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#define MOD_IN_USE 1
+#endif MODULE
 
 #include <linux/errno.h>
 #include <linux/signal.h>
@@ -56,9 +72,11 @@
 
 #include <linux/major.h>
 
-#ifndef MITSUMI_X_CDROM_MAJOR               /* old kernel (doesn't know about MCDX) */
+/* old kernel (doesn't know about MCDX) */
+#ifndef MITSUMI_X_CDROM_MAJOR
 #define MITSUMI_X_CDROM_MAJOR 20
-#define DEVICE_NAME "Mitsumi CD-ROM"
+#define DEVICE_NAME "mcdx"
+
 /* #define DEVICE_INTR do_mcdx */
 #define DEVICE_REQUEST do_mcdx_request
 #define DEVICE_NR(device) (MINOR(device))
@@ -68,13 +86,20 @@
 
 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
 #include <linux/blk.h>
-#define	mcdx_drive_map mcdx     /* for compatible parameter passing with "insmod" */
+
+/* for compatible parameter passing with "insmod" */ 
+#define	mcdx_drive_map mcdx    
 #include <linux/mcdx.h>
 
+#ifndef HZ 
+#error HZ not defined
+#endif
+
 /* CONSTANTS *******************************************************/
 
 const int REQUEST_SIZE = 200;
 const int DIRECT_SIZE = 200;
+const unsigned long ACLOSE_INHIBIT = 800;  /* 1/100 s of autoclose inhibit */
 
 enum drivemodes { TOC, DATA, RAW, COOKED };
 enum datamodes { MODE0, MODE1, MODE2 };
@@ -134,7 +159,9 @@
     volatile int introk;	/* status of last irq operation */
     volatile int busy;		/* drive performs an operation */
     volatile int lock;		/* exclusive usage */
-
+    int eject_sw;           /* 1 - eject on last close (default 0) */
+    int autoclose;          /* 1 - close the door on open (default 1) */
+    
 	/* cd infos */
 	struct s_diskinfo di;
 	struct s_multi multi;
@@ -166,10 +193,10 @@
     char playcmd;       /* play should always be single speed */
     unsigned long changed;	/* last jiff the media was changed */
     unsigned long xxx;      /* last jiff it was asked for media change */
+    unsigned long ejected;  /* time we called the eject function */
     int users;				/* keeps track of open/close */
     int lastsector;			/* last block accessible */
     int errno;				/* last operation's error */
-
 };
 
 
@@ -180,10 +207,18 @@
 	changed elsewhere. */
 
 /* declared in blk.h */
+#if LINUX_VERSION_CODE < 66338
+unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end);
+#else
 int mcdx_init(void);
+#endif
 void do_mcdx_request(void);
 
+#if LINUX_VERSION_CODE < 66338
+int check_mcdx_media_change(dev_t);
+#else
 int check_mcdx_media_change(kdev_t);
+#endif
 
 /* already declared in init/main */
 void mcdx_setup(char *, int *);
@@ -229,17 +264,17 @@
 static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);
 static int mcdx_getstatus(struct s_drive_stuff*, int);
 static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*);
-
 static int mcdx_talk(struct s_drive_stuff*, 
-		const unsigned char* cmd, size_t, void *buffer,
-		size_t size, unsigned int timeout, int);
+		const unsigned char* cmd, size_t, 
+        void *buffer, size_t size, 
+        unsigned int timeout, int);
 static int mcdx_readtoc(struct s_drive_stuff*);
 static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*);
 static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*);
+static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int);
 
 /* static variables ************************************************/
 
-static int dummy0;
 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
 static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
 static struct s_drive_stuff* mcdx_irq_map[16] =
@@ -301,7 +336,7 @@
 					|| (ti.cdti_trk1 < stuffp->di.n_first))
 				return -EINVAL;
 			if (ti.cdti_trk1 > stuffp->di.n_last) ti.cdti_trk1 = stuffp->di.n_last;
-            TRACE((IOCTL, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1));
+            TRACE((PLAYTRK, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1));
 
             return mcdx_playtrk(stuffp, &ti);
         }
@@ -388,20 +423,20 @@
 
 			if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) return -EIO;
 
-            TRACE((IOCTL, "audiostatus: %x\n", stuffp->audiostatus));
+            TRACE((SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus));
 			sub.cdsc_audiostatus = stuffp->audiostatus;
 			sub.cdsc_adr = q.control;
 			sub.cdsc_ctrl = q.control >> 4;
 			sub.cdsc_trk = bcd2uint(q.tno);
 			sub.cdsc_ind = bcd2uint(q.index);
 
-            TRACE((IOCTL, "trk %d, ind %d\n", 
+            TRACE((SUBCHNL, "trk %d, ind %d\n", 
                     sub.cdsc_trk, sub.cdsc_ind));
 
 			if (sub.cdsc_format == CDROM_LBA) {
 				sub.cdsc_absaddr.lba = msf2log(&q.dt);
 				sub.cdsc_reladdr.lba = msf2log(&q.tt);
-                TRACE((IOCTL, "lba: abs %d, rel %d\n",
+                TRACE((SUBCHNL, "lba: abs %d, rel %d\n",
                     sub.cdsc_absaddr.lba,
                     sub.cdsc_reladdr.lba));
 			} else if (sub.cdsc_format == CDROM_MSF) {
@@ -411,7 +446,7 @@
 				sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
 				sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
 				sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
-                TRACE((IOCTL,
+                TRACE((SUBCHNL,
                         "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
                         sub.cdsc_absaddr.msf.minute,
                         sub.cdsc_absaddr.msf.second,
@@ -438,7 +473,7 @@
 			toc.cdth_trk0 = stuffp->di.n_first;
 			toc.cdth_trk1 = stuffp->di.n_last;
 			memcpy_tofs((void*) arg, &toc, sizeof toc);
-			TRACE((IOCTL, "ioctl() track0 = %d, track1 = %d\n",
+			TRACE((TOCHDR, "ioctl() track0 = %d, track1 = %d\n",
 					stuffp->di.n_first, stuffp->di.n_last));
 			return 0;
 		}
@@ -447,10 +482,9 @@
 			TRACE((IOCTL, "ioctl() PAUSE\n"));
 			if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL;
 			if (-1 == mcdx_stop(stuffp, 1)) return -EIO;
+            stuffp->audiostatus = CDROM_AUDIO_PAUSED;
 			if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1))
 				return -EIO;
-            
-            stuffp->audiostatus = CDROM_AUDIO_PAUSED;
 			return 0;
 		}
 
@@ -479,7 +513,7 @@
 
 			memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
 			if (ms.addr_format == CDROM_MSF) 
-				TRACE((IOCTL, 
+				TRACE((MS, 
 						"ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n",
 						ms.xa_flag, 
 						ms.addr.msf.minute,
@@ -490,8 +524,7 @@
 						stuffp->multi.msf_last.frame));
 			else
 			  {
-			    dummy0=0;
-			    TRACE((IOCTL, 
+			    TRACE((MS, 
 					"ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
 					ms.xa_flag,
 					ms.addr.lba,
@@ -509,11 +542,26 @@
 			return 0;
 		}
 
-        case CDROMVOLCTRL: {
-            TRACE((IOCTL, "ioctl() volctrl\n"));
+        case CDROMEJECT_SW: {
+            stuffp->eject_sw = arg;
             return 0;
         }
 
+        case CDROMVOLCTRL: {
+            int ans;
+            struct cdrom_volctrl volctrl;
+
+            TRACE((IOCTL, "ioctl() VOLCTRL\n"));
+            if ((ans = verify_area(
+                    VERIFY_READ, 
+                    (void*) arg,
+                    sizeof(volctrl))))
+                return ans;
+
+            memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
+            return mcdx_setattentuator(stuffp, &volctrl, 1);
+        }
+
 		default:
 			WARN(("ioctl(): unknown request 0x%04x\n", cmd));
 	    	return -EINVAL;
@@ -529,20 +577,36 @@
 
 	TRACE((REQUEST, "do_request()\n"));
 
+#if LINUX_VERSION_CODE < 66338
+	if ((CURRENT == NULL) || (CURRENT->dev < 0))  {
+#else
 	if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE))  {
+#endif
 		TRACE((REQUEST, "do_request() done\n"));
 		return;
 	}
 
+#if LINUX_VERSION_CODE < 66338
+    stuffp = mcdx_stuffp[MINOR(CURRENT->dev)];
+#else
     stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)];
+#endif
 	TRACE((REQUEST, "do_request() stuffp = %p\n", stuffp));
 
     INIT_REQUEST;
+#if LINUX_VERSION_CODE < 66338
+    dev = MINOR(CURRENT->dev);
+#else
     dev = MINOR(CURRENT->rq_dev);
+#endif
 
 	if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp->present)) {
-		WARN(("do_request(): bad device: %s\n",
-		      kdevname(CURRENT->rq_dev)));
+#if LINUX_VERSION_CODE < 66338
+		WARN(("do_request(): bad device: 0x%04x\n", CURRENT->dev));
+#else
+		WARN(("do_request(): bad device: %s\n", 
+            kdevname(CURRENT->rq_dev)));
+#endif
 		end_request(0);
 		goto again;
     }
@@ -569,13 +633,13 @@
 				      CURRENT->buffer,
 				      CURRENT->sector,
 				      CURRENT->nr_sectors))) {
-          WARN(("do_request() read error\n"));
-		  if (stuffp->errno == MCDX_EOM) {
-		      CURRENT->sector += CURRENT->nr_sectors;
-		      CURRENT->nr_sectors = 0;
-		  }
-		  end_request(0);
-		  goto again;
+              WARN(("do_request() read error\n"));
+              if (stuffp->errno == MCDX_EOM) {
+                  CURRENT->sector += CURRENT->nr_sectors;
+                  CURRENT->nr_sectors = 0;
+              }
+              end_request(0);
+              goto again;
 	      }
 	      CURRENT->sector += i;
 	      CURRENT->nr_sectors -= i;
@@ -596,6 +660,8 @@
 
 static int 
 mcdx_open(struct inode *ip, struct file *fp)
+/*  actions done on open:
+ *  1)  get the drives status */
 {
     struct s_drive_stuff *stuffp;
 
@@ -603,14 +669,21 @@
     stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
     if (!stuffp->present) return -ENXIO;
 
+    /* this is only done to test if the drive talks with us */
     if (-1 == mcdx_getstatus(stuffp, 1)) return -EIO;
 
 	/* close the door, if necessary (get the door information
-    from the hardware status register) */
-	if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR)  
-		mcdx_closedoor(stuffp, 1);
+    from the hardware status register). 
+    If the last eject is too recent, an autoclose wouldn't probably
+    be what we want ..., if we can't read the CD after an autoclose
+    no further autclose's will be tried */
+	if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
+        if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) return -EIO;
+        if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
+        else return -EIO;
+    }
 
-	/* if the media changed we will have to little more */
+	/* if the media changed we will have to do a little more */
 	if (stuffp->xxx < stuffp->changed) {
 
 		TRACE((OPENCLOSE, "open() media changed\n"));
@@ -619,18 +692,23 @@
         talk() will detect a media change ... (I think, config()
         is the reason. */
 
-        /*
-        TRACE((OPENCLOSE, "open() hardware reset\n"));
-		if (-1 == mcdx_reset(stuffp, HARD, 1)) return -EIO;
-        */
-
         stuffp->audiostatus = CDROM_AUDIO_INVALID;
 
 		/* get the multisession information */
 		{
+            int ans;
+
 			TRACE((OPENCLOSE, "open() Request multisession info\n"));
-			if (-1 == mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
-				return -EIO;
+            ans = mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6);
+            if (ans == -1) {
+                stuffp->autoclose = 0;
+                mcdx_eject(stuffp, 1);
+                return -EIO;
+            }
+
+            /* we succeeded, so on next open(2) we could try auto close
+            again */
+            stuffp->autoclose = 1;
 		
 			if (stuffp->multi.multi > 2)
 				WARN(("open() unknown multisession value (%d)\n", stuffp->multi.multi));
@@ -743,23 +821,36 @@
 		/* invalidate_inodes(ip->i_rdev); */
 		invalidate_buffers(ip->i_rdev);
 
-		if (-1 == mcdx_lockdoor(stuffp, 0, 1))
-				printk(MCDX ": Cannot unlock the door\n");
+		if (-1 == mcdx_lockdoor(stuffp, 0, 3))
+				INFO(("close() Cannot unlock the door\n"));
+
+        /* eject if wished */
+        if (stuffp->eject_sw) mcdx_eject(stuffp, 1);
+
     }
     MOD_DEC_USE_COUNT;
 
     return;
 }
 
+#if LINUX_VERSION_CODE < 66338
+int check_mcdx_media_change(dev_t full_dev)
+#else
 int check_mcdx_media_change(kdev_t full_dev)
+#endif
 /*	Return: 1 if media changed since last call to 
 			  this function
 			0 else
 	Setting flag to 0 resets the changed state. */
 
 {
+#if LINUX_VERSION_CODE < 66338
+    INFO(("check_mcdx_media_change called for device %x\n",
+	  full_dev));
+#else
     INFO(("check_mcdx_media_change called for device %s\n",
 	  kdevname(full_dev)));
+#endif
     return 0;
 }
 
@@ -813,8 +904,8 @@
 
     stuffp = mcdx_irq_map[irq];
 
-    if (!stuffp->busy) {
-		INFO(("intr() unexpected interrupt @ irq %d\n", irq));
+    if (stuffp == NULL || !stuffp->busy) {
+		TRACE((IRQ, "intr() unexpected interrupt @ irq %d\n", irq));
 		return;
     }
 
@@ -825,8 +916,8 @@
 				irq, x, inb((unsigned int) stuffp->rreg_data)));
 	else
 	  {
-	    dummy0=0;
 	    TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, x));
+
 	  }
     stuffp->busy = 0;
     wake_up_interruptible(&stuffp->busyq);
@@ -841,12 +932,16 @@
 		unsigned int timeout, int tries)
 /* Send a command to the drive, wait for the result.
  * returns -1 on timeout, drive status otherwise
+ * If buffer is not zero, the result (length size) is stored there.
+ * If buffer is zero the size should be the number of bytes to read
+ * from the drive.  These bytes are discarded.
  */
 {
-	char c;
 	int st;
+    char c;
+    int disgard;
 
-	if (!buffer || size == 0) buffer = &c, size = 1;
+    if ((disgard = (buffer == NULL))) buffer = &c;
 
     while (stuffp->lock)
 		interruptible_sleep_on(&stuffp->lockq);
@@ -881,18 +976,20 @@
 
         /* get the status byte */
         if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
-            WARN(("talk() %02x timed out (status), %d tr%s left\n", 
+            INFO(("talk() %02x timed out (status), %d tr%s left\n", 
                     cmd[0], tries - 1, tries == 2 ? "y" : "ies"));
                 continue; 
         }
-        st = *bp++;
+        st = *bp;
         sz--;
+        if (!disgard) bp++;
 
         TRACE((TALK, "talk() got status 0x%02x\n", st));
 
         /* command error? */
         if (e_cmderr(st)) {
-            WARN(("command error %02x (%d)\n", cmd[0], cmdlen));
+            WARN(("command error cmd = %02x %s \n", 
+                    cmd[0], cmdlen > 1 ? "..." : ""));
             st = -1;
             continue;
         }
@@ -901,6 +998,9 @@
         if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
             stuffp->audiostatus = 
                     e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
+        else if (stuffp->audiostatus == CDROM_AUDIO_PLAY 
+                && e_audiobusy(st) == 0)
+            stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
 
         /* media change? */
         if (e_changed(st)) {
@@ -910,18 +1010,17 @@
 
         /* now actually get the data */
         while (sz--) {
-            if (-1 == mcdx_getval(stuffp, timeout, -1, bp++)) {
-                WARN(("talk() %02x timed out (data), %d tr%s left\n", 
+            if (-1 == mcdx_getval(stuffp, timeout, -1, bp)) {
+                INFO(("talk() %02x timed out (data), %d tr%s left\n", 
                         cmd[0], tries - 1, tries == 2 ? "y" : "ies"));
                 st = -1; break;
             }
+            if (!disgard) bp++;
             TRACE((TALK, "talk() got 0x%02x\n", *(bp - 1)));
         }
     }
 
-#if QUIET == 0
-    if (!tries && st == -1) INFO(("talk() giving up\n"));
-#endif
+    if (!tries && st == -1) WARN(("talk() giving up\n"));
 
     stuffp->lock = 0;
     wake_up_interruptible(&stuffp->lockq);
@@ -938,7 +1037,11 @@
 	int i;
 	int drives = 0;
 
+#if LINUX_VERSION_CODE < 66338
+	mcdx_init(0, 0);
+#else
 	mcdx_init();
+#endif
 	for (i = 0; i < MCDX_NDRIVES; i++)  {
 		if (mcdx_stuffp[i]) {
 		TRACE((INIT, "init_module() drive %d stuff @ %p\n",
@@ -950,6 +1053,7 @@
     if (!drives) 
 		return -EIO;
 
+    register_symtab(0);
     return 0;
 }
 
@@ -1009,12 +1113,18 @@
 }
 
 
+#if LINUX_VERSION_CODE < 66338
+unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end)
+#else
 int mcdx_init(void)
+#endif
 {
 	int drive;
 
-	INFO((": Version 1.0a "
-			"mcdx.c,v 1.7 1995/08/27 01:46:41 heiko Exp\n"));
+	WARN(("Version 1.3 "
+			"mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp\n"));
+	INFO((": Version 1.3 "
+			"mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp\n"));
 
 	/* zero the pointer array */
 	for (drive = 0; drive < MCDX_NDRIVES; drive++)
@@ -1030,16 +1140,24 @@
 		
 		TRACE((INIT, "init() try drive %d\n", drive));
 
+#if defined(MODULE) || LINUX_VERSION_CODE > 66338
+        TRACE((INIT, "kmalloc space for stuffpt's\n"));
 		TRACE((MALLOC, "init() malloc %d bytes\n", size));
 		if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
 			WARN(("init() malloc failed\n"));
 			break; 
 		}
+#else
+        TRACE((INIT, "adjust mem_start\n"));
+        stuffp = (struct s_drive_stuff *) mem_start;
+        mem_start += size;
+#endif
 
 		TRACE((INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp));
 
-		/* zero the stuff */
+		/* set default values */
 		memset(stuffp, 0, sizeof(*stuffp));
+        stuffp->autoclose = 1;      /* close the door on open(2) */
 
 		stuffp->present = 0;		/* this should be 0 already */
 		stuffp->toc = NULL;			/* this should be NULL already */
@@ -1165,7 +1283,11 @@
 		TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp));
 	}
 
+#if MODULE || LINUX_VERSION_CODE > 66338
 	return 0;
+#else
+	return mem_start;
+#endif
 }
 
 
@@ -1210,25 +1332,17 @@
 	    current->timeout = jiffies + 5*HZ;
 	    while (stuffp->busy) {
 			interruptible_sleep_on(&stuffp->busyq);
-			if ((sig = (current->signal && ~current->blocked))
-					|| (to = (current->timeout == 0))) {
-				break;
-			} 	
 		}
 
 	    current->timeout = 0;
 
 		/* test for possible errors */
 	    if (((stuffp->busy == 0) && !stuffp->introk)
-				|| sig
 				|| to) {
 			if ((stuffp->busy == 0) && !stuffp->introk)
                 WARN(("mcdx_transfer() failure in data request\n"));
 			else if (to)
                 WARN(("mcdx_transfer(): timeout\n"));
-			else if (sig)
-                WARN(("mcdx_transfer(): got signal 0x%lx\n", current->signal));
-
 			stuffp->lock = 0;
 			stuffp->busy = 0;
 			wake_up_interruptible(&stuffp->lockq);
@@ -1365,16 +1479,16 @@
 {
 
 	if (stuffp->toc) {
-		TRACE((IOCTL, "ioctl() toc already read\n"));
+		TRACE((READTOC, "ioctl() toc already read\n"));
 		return 0;
 	}
 
-	TRACE((IOCTL, "ioctl() readtoc for %d tracks\n",
+	TRACE((READTOC, "ioctl() readtoc for %d tracks\n",
 			stuffp->di.n_last - stuffp->di.n_first + 1));
 
     if (-1 == mcdx_hold(stuffp, 1)) return -1;
 
-	TRACE((IOCTL, "ioctl() tocmode\n"));
+	TRACE((READTOC, "ioctl() tocmode\n"));
 	if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO;
 
 	/* all seems to be ok so far ... malloc */
@@ -1417,7 +1531,7 @@
 					&& (q.tno == 0)
 					&& (stuffp->toc[idx - stuffp->di.n_first].index == 0)) {
 				stuffp->toc[idx - stuffp->di.n_first] = q;
-				TRACE((IOCTL, "ioctl() toc idx %d (trk %d)\n", idx, trk));
+				TRACE((READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk));
 				trk--;
 			}
 			if (trk == 0) break;
@@ -1429,16 +1543,16 @@
 	}
 
 	/* unset toc mode */
-	TRACE((IOCTL, "ioctl() undo toc mode\n"));
+	TRACE((READTOC, "ioctl() undo toc mode\n"));
 	if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
 		return -EIO;
 
-#if MCDX_DEBUG && IOCTL
+#if MCDX_DEBUG && READTOC
 	{ int trk;
 	for (trk = 0; 
 			trk < (stuffp->di.n_last - stuffp->di.n_first + 2); 
 			trk++)
-		TRACE((IOCTL, "ioctl() %d readtoc %02x %02x %02x"
+		TRACE((READTOC, "ioctl() %d readtoc %02x %02x %02x"
 				"  %02x:%02x.%02x  %02x:%02x.%02x\n",
 				trk + stuffp->di.n_first,
 				stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index,
@@ -1466,14 +1580,14 @@
     cmd[5] = msf->cdmsf_sec1;
     cmd[6] = msf->cdmsf_frame1;
 
-    TRACE((IOCTL, "ioctl(): play %x "
+    TRACE((PLAYMSF, "ioctl(): play %x "
             "%02x:%02x:%02x -- %02x:%02x:%02x\n",
             cmd[0], cmd[1], cmd[2], cmd[3],
             cmd[4], cmd[5], cmd[6])); 
 
     outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
 
-    if (-1 == mcdx_getval(stuffp, 1*HZ, 0, NULL)) {
+    if (-1 == mcdx_getval(stuffp, 3*HZ, 0, NULL)) {
         WARN(("playmsf() timeout\n")); 
         return -1;
     }
@@ -1516,26 +1630,26 @@
 mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
 {
 	if (stuffp->present & DOOR)
-		return mcdx_talk(stuffp, "\xf8", 1, NULL, 0, 5*HZ, tries);
+		return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5*HZ, tries);
 	else
 		return 0;
 }
 
 static int 
 mcdx_stop(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 0, 2*HZ, tries); }
+{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2*HZ, tries); }
 
 static int
 mcdx_hold(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x70", 1, NULL, 0, 2*HZ, tries); }
+{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2*HZ, tries); }
 
 static int
 mcdx_eject(struct s_drive_stuff *stuffp, int tries)
 {
-	if (stuffp->present & DOOR)
-		return mcdx_talk(stuffp, "\xf6", 1, NULL, 0, 5*HZ, tries);
-	else
-		return 0;
+	if (stuffp->present & DOOR) {
+        stuffp->ejected = jiffies;
+		return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5*HZ, tries);
+    } else return 0;
 }
 
 static int
@@ -1618,7 +1732,7 @@
 	  default: break;
 	}
 	cmd[0] = 0x50;
-	return mcdx_talk(stuffp, cmd, 2, NULL, 0, 5*HZ, tries);
+	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
 }
 
 
@@ -1633,7 +1747,7 @@
 	  case MODE2: cmd[1] = 0x02; break;
 	  default: return -EINVAL;
 	}
-	return mcdx_talk(stuffp, cmd, 2, NULL, 0, 5*HZ, tries);
+	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
 }
 
 static int
@@ -1648,13 +1762,13 @@
 	cmd[1] = 0x10;		/* irq enable */
 	cmd[2] = 0x05;		/* pre, err irq enable */
 
-	if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 0, 1*HZ, tries))
+	if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries))
 		return -1;
 
 	cmd[1] = 0x02;		/* dma select */
 	cmd[2] = 0x00;		/* no dma */
 
-	return mcdx_talk(stuffp, cmd, 3, NULL, 0, 1*HZ, tries);
+	return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries);
 }
 
 static int
@@ -1679,7 +1793,7 @@
 		outb(0, (unsigned int) stuffp->wreg_chn);		/* no dma, no irq -> hardware */
 		outb(0, (unsigned int) stuffp->wreg_reset);		/* hw reset */
 		return 0;
-	} else return mcdx_talk(stuffp, "\x60", 1, NULL, 0, 5*HZ, tries);
+	} else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5*HZ, tries);
 }
 
 static int
@@ -1688,14 +1802,14 @@
 	char cmd[2] = { 0xfe };
     if (stuffp->present & DOOR) {
         cmd[1] = lock ? 0x01 : 0x00;
-        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 0, 5*HZ, tries);
+        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5*HZ, tries);
     } else 
         return 0;
 }
 
 static int
 mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x40", 1, NULL, 0, 5*HZ, tries); }
+{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5*HZ, tries); }
 
 static int
 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
@@ -1714,3 +1828,20 @@
 
     return 0;
 }
+
+static int
+mcdx_setattentuator(
+        struct s_drive_stuff* stuffp, 
+        struct cdrom_volctrl* vol, 
+        int tries)
+{
+    char cmd[5];
+    cmd[0] = 0xae;
+    cmd[1] = vol->channel0;
+    cmd[2] = 0;
+    cmd[3] = vol->channel1;
+    cmd[4] = 0;
+
+    return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
+}
+
diff -u --recursive --new-file v1.3.40/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v1.3.40/linux/drivers/char/Config.in	Mon Oct 23 18:02:06 1995
+++ linux/drivers/char/Config.in	Sun Nov 12 09:13:19 1995
@@ -4,7 +4,7 @@
 mainmenu_option next_comment
 comment 'character devices'
 
-bool 'Cyclades async mux support' CONFIG_CYCLADES
+tristate 'Cyclades async mux support' CONFIG_CYCLADES
 bool 'Stallion multiport serial support' CONFIG_STALDRV
 if [ "$CONFIG_STALDRV" = "y" ]; then
   tristate '  Stallion EasyIO or EC8/32 support' CONFIG_STALLION
diff -u --recursive --new-file v1.3.40/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.40/linux/drivers/char/Makefile	Wed Nov  8 07:11:31 1995
+++ linux/drivers/char/Makefile	Sun Nov 12 09:13:19 1995
@@ -20,8 +20,12 @@
 	tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \
 	defkeymap.o consolemap.o selection.o
 
-ifdef CONFIG_CYCLADES
+ifeq ($(CONFIG_CYCLADES),y)
 L_OBJS += cyclades.o
+else
+  ifeq ($(CONFIG_CYCLADES),m)
+  M_OBJS += cyclades.o
+  endif
 endif
 
 ifeq ($(CONFIG_STALLION),y)
diff -u --recursive --new-file v1.3.40/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v1.3.40/linux/drivers/char/cyclades.c	Tue Oct 10 18:46:33 1995
+++ linux/drivers/char/cyclades.c	Sun Nov 12 09:13:20 1995
@@ -223,6 +223,8 @@
  *
  */
 
+#include <linux/module.h>
+
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -404,7 +406,6 @@
 static void cy_throttle(struct tty_struct *);
 static void cy_unthrottle(struct tty_struct *);
 static void config_setup(struct cyclades_port *);
-extern void console_print(const char *);
 #ifdef CYCLOM_SHOW_STATUS
 static void show_status(int);
 #endif
@@ -466,7 +467,6 @@
 void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */
 void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */
 
-
 /* This routine waits up to 1000 micro-seconds for the previous
    command to the Cirrus chip to complete and then issues the
    new command.  An error is returned if the previous command
@@ -583,6 +583,7 @@
 } /* cy_sched_event */
 
 
+static int probe_ready;
 
 /*
  * This interrupt routine is used
@@ -594,6 +595,9 @@
   int save_xir, save_car;
   int index = 0;	/* probing interrupts is only for ISA */
 
+    if (!probe_ready)
+        return;
+
     cy_irq_triggered = irq;
     cy_triggered |= 1 << irq;
 
@@ -1107,6 +1111,7 @@
 	base_addr[CyCAR<<index] = 0;
 	write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
 	base_addr[CySRER<<index] |= CyTxMpty;
+	probe_ready = 1;
     sti();
     
     timeout = jiffies+2;
@@ -1114,6 +1119,7 @@
 	if (cy_irq_triggered)
 	    break;
     }
+    probe_ready = 0;
     return(cy_irq_triggered);
 } /* get_auto_irq */
 
@@ -1132,6 +1138,8 @@
     /* Turn on interrupts (they may be off) */
     save_flags(flags); sti();
 
+	probe_ready = 0;
+
         cy_wild_int_mask = check_wild_interrupts();
 
 	irq_lines = grab_all_interrupts(cy_wild_int_mask);
@@ -2286,6 +2294,7 @@
 cy_close(struct tty_struct * tty, struct file * filp)
 {
   struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+  unsigned long flags;
 
 /* CP('C'); */
 #ifdef SERIAL_DEBUG_OTHER
@@ -2300,6 +2309,14 @@
     printk("cy_close ttyC%d, count = %d\n", info->line, info->count);
 #endif
 
+    save_flags(flags); cli();
+
+    /* If the TTY is being hung up, nothing to do */
+    if (tty_hung_up_p(filp)) {
+	restore_flags(flags);
+	return;
+    }
+	
     if ((tty->count == 1) && (info->count != 1)) {
 	/*
 	 * Uh, oh.  tty->count is 1, which means that the tty
@@ -2313,7 +2330,7 @@
 	info->count = 1;
     }
 #ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count - 1);
+    printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count - 1);
 #endif
     if (--info->count < 0) {
 #ifdef SERIAL_DEBUG_COUNT
@@ -2322,7 +2339,11 @@
 	info->count = 0;
     }
     if (info->count)
+    {
+        MOD_DEC_USE_COUNT;
+	restore_flags(flags);
 	return;
+    }
     info->flags |= ASYNC_CLOSING;
     /*
      * Save the termios structure, since this port may have
@@ -2341,14 +2362,6 @@
 	tty->ldisc.flush_buffer(tty);
     info->event = 0;
     info->tty = 0;
-    if (tty->ldisc.num != ldiscs[N_TTY].num) {
-	if (tty->ldisc.close)
-	    (tty->ldisc.close)(tty);
-	tty->ldisc = ldiscs[N_TTY];
-	tty->termios->c_line = N_TTY;
-	if (tty->ldisc.open)
-	    (tty->ldisc.open)(tty);
-    }
     if (info->blocked_open) {
 	if (info->close_delay) {
 	    current->state = TASK_INTERRUPTIBLE;
@@ -2365,6 +2378,8 @@
     printk("cy_close done\n");
 #endif
 
+    MOD_DEC_USE_COUNT;
+    restore_flags(flags);
     return;
 } /* cy_close */
 
@@ -2384,14 +2399,12 @@
 	return;
     
     shutdown(info);
-#if 0
     info->event = 0;
     info->count = 0;
 #ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d: setting count to 0\n", __LINE__);
+    printk("cyc: %d(%d): setting count to 0\n", __LINE__, current->pid);
 #endif
     info->tty = 0;
-#endif
     info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
     wake_up_interruptible(&info->open_wait);
 } /* cy_hangup */
@@ -2477,7 +2490,7 @@
 #endif
     info->count--;
 #ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
+    printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count);
 #endif
     info->blocked_open++;
 
@@ -2537,7 +2550,7 @@
     if (!tty_hung_up_p(filp)){
 	info->count++;
 #ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
+    printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
 #endif
     }
     info->blocked_open--;
@@ -2581,7 +2594,7 @@
 #endif
     info->count++;
 #ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
+    printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
 #endif
     tty->driver_data = info;
     info->tty = tty;
@@ -2622,6 +2635,7 @@
 #ifdef SERIAL_DEBUG_OPEN
     printk("cy_open done\n");/**/
 #endif
+    MOD_INC_USE_COUNT;
     return 0;
 } /* cy_open */
 
@@ -2736,7 +2750,6 @@
   struct cyclades_card *cinfo;
   int			board,port,i;
 
-scrn[1] = '\0';
     show_version();
 
     /* Initialize the tty_driver structure */
@@ -2876,6 +2889,33 @@
     return 0;
     
 } /* cy_init */
+
+#ifdef MODULE
+int
+init_module(void)
+{
+   return(cy_init());
+}
+
+void
+cleanup_module(void)
+{
+    int i;
+
+
+    if (tty_unregister_driver(&cy_callout_driver))
+	    printk("Couldn't unregister Cyclom callout driver\n");
+    if (tty_unregister_driver(&cy_serial_driver))
+	    printk("Couldn't unregister Cyclom serial driver\n");
+
+    for (i = 0; i < NR_CARDS; i++) {
+        if (cy_card[i].base_addr != 0)
+	{
+	    free_irq(cy_card[i].irq);
+	}
+    }
+}
+#endif
 
 /*
  * ---------------------------------------------------------------------
diff -u --recursive --new-file v1.3.40/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v1.3.40/linux/drivers/net/3c505.c	Thu Nov  9 11:23:49 1995
+++ linux/drivers/net/3c505.c	Mon Nov 13 08:10:57 1995
@@ -10,7 +10,7 @@
  *		be here without 3C505 technical reference provided by
  *		3Com.
  *
- * Version:	@(#)3c505.c	0.8.1	26-Jun-95
+ * Version:	@(#)3c505.c	0.8.3	12-Nov-95
  *
  * Authors:	Linux 3c505 device driver by
  *			Craig Southeren, <craigs@ineluki.apana.org.au>
@@ -103,7 +103,7 @@
  *  3 = messages when interrupts received
  */
 
-#define	ELP_VERSION	"0.8.1"
+#define	ELP_VERSION	"0.8.3"
 
 /*****************************************************************
  *
@@ -473,9 +473,13 @@
 adapter_hard_reset (struct device * dev)
 {
 	int timeout;
+	long flags;
 
 	CHECK_NULL(dev);
 
+	save_flags(flags);
+	sti();
+
 	if (elp_debug > 0)
 		printk("%s: Resetting the adapter, please wait (approx 20 s)\n",
 			dev->name);
@@ -507,6 +511,7 @@
 	for (timeout = jiffies + (100 * 15); jiffies <= timeout; ) 
 		if (GET_ASF(dev->base_addr) != ASF_PCB_END)
 			break;
+	restore_flags(flags);
 }
 
 /******************************************************
@@ -1272,6 +1277,7 @@
 	int timeout;
 	int addr=dev->base_addr;
 	const char *name=dev->name;
+	long flags;
 
 	byte orig_HCR=inb_control(addr),
 		orig_HSR=inb_status(addr);
@@ -1286,6 +1292,10 @@
 		return -1; /* It can't be 3c505 if HCR.DIR != HSR.DIR */
 	}
 
+	/* Enable interrupts - we need timers! */
+	save_flags(flags);
+	sti();
+
 	/* Wait for a while; the adapter may still be booting up */
 	if (elp_debug > 0)
 		printk(stilllooking_msg);
@@ -1299,6 +1309,7 @@
 		timeout = jiffies+30;
 		while (jiffies < timeout)
 			;
+		restore_flags(flags);
 		if (inb_status(addr) & DIR) {
 			outb_control(orig_HCR,addr);
 			if (elp_debug > 0)
@@ -1311,6 +1322,7 @@
 		timeout = jiffies+300;
 		while (jiffies < timeout)
 			;
+		restore_flags(flags);
 		if (!(inb_status(addr) & DIR)) {
 			outb_control(orig_HCR,addr);
 			if (elp_debug > 0)
@@ -1462,8 +1474,8 @@
 	0, 0,
 	0, 0, 0, NULL, elplus_probe };
 
-static int io = 0x300;
-static int irq = 0;
+int io = 0x300;
+int irq = 0;
 
 int init_module(void)
 {
diff -u --recursive --new-file v1.3.40/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v1.3.40/linux/drivers/net/arcnet.c	Thu Nov  9 11:23:49 1995
+++ linux/drivers/net/arcnet.c	Mon Nov 13 08:54:55 1995
@@ -1,6 +1,6 @@
 /* arcnet.c
-	Written 1994-95 by Avery Pennarun, derived from skeleton.c by
-        Donald Becker.
+	Written 1994-95 by Avery Pennarun, derived from skeleton.c by Donald
+	Becker.
 
 	Contact Avery at: apenwarr@foxnet.net or
 	RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
@@ -17,6 +17,38 @@
          
 	**********************
 
+	v2.20 ALPHA (95/11/12)
+	  - Added a bit of protocol confusion to the arc0 code to allow
+	    trxnet-compatible IPX support - and the use of all that new
+	    Linux-IPX stuff (including lwared).  Just tell the ipx_interface
+	    command that arc0 uses 802.3 (other protocols will probably also
+	    work).
+	  - Fixed lp->stats to update tx_packets on all devices, not just
+	    arc0.  Also, changed a lot of the error counting to make more
+	    sense.
+	  - rx_packets on arc0 was being updated for each completely received
+	    packet.  It now updates for each segment received, which makes
+	    more sense. 
+	  - Removed unneeded extra check of dev->start in arcnet_inthandler.
+	  - Included someone else's fixes from kernel 1.3.39.  Does it still
+	    work with kernel 1.2?
+	  - Added a new define to disable PRINTING (not checking) of RECON
+	    messages.
+	  - Separated the duplicated error checking code from the various
+	    arcnet??_send_packet routines into a new function.
+	  - Cleaned up lock variables and ping-pong buffers a bit.  This
+	    should mean more stability, fewer missing packets, and less ugly
+	    debug messages.  Assuming it works.
+	  - Changed the format of debug messages to always include the actual
+	    device name instead of just "arcnet:".  Used more macros to
+	    shorten debugging code even more.
+	  - Finally squashed the "startup NULL pointer" bug.  irq2dev_map
+	    wasn't being cleared to NULL when the driver was closed.
+	  - Improved RECON checking; if a certain number of RECON messages
+	    are received within one minute, a warning message is printed
+	    to the effect of "cabling problem."  One-log-message-per-recon
+	    now defaults to OFF.
+
 	v2.12 ALPHA (95/10/27)
 	  - Tried to improve skb handling and init code to fix problems with
 	    the latest 1.3.x kernels. (We no longer use ether_setup except
@@ -94,16 +126,17 @@
            if there aren't any ARCnet cards in the system.  And why shouldn't
            it work as a module again?
          - Rewrite autoprobe.
+         - Make sure RESET flag is cleared during an IRQ even if dev->start==0;
+           mainly a portability fix.  This will confuse autoprobe a bit, so
+           test that too.
          - What about cards with shared memory that can be "turned off?"
          - NFS mount freezes after several megabytes to SOSS for DOS. 
  	   unmount/remount fixes it.  Is this arcnet-specific?  I don't know.
-         - Some newer ARCnets support promiscuous mode, supposedly. 
-           If someone sends me information, I'll try to implement it.
-         - Find and remove excess lock variables that are probably not
-           necessary anymore due to the changes in Linux 1.2.9.
+         - Some newer ARCnets support promiscuous mode, supposedly.  If
+           someone sends me information, I'll try to implement it.
          - Dump Linux 1.2 support and its ugly #ifdefs.
          - Add support for the new 1.3.x IP header cache features.
-         - ATA protocol support??
+         - ATA protocol support?? 
          - Banyan VINES TCP/IP support??
 
            
@@ -123,11 +156,14 @@
 */
 
 static const char *version =
- "arcnet.c:v2.12 ALPHA 95/10/27 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.20 ALPHA 95/11/12 Avery Pennarun <apenwarr@foxnet.net>\n";
 
-#include <linux/module.h>
+ 
 
+#include <linux/module.h>
 #include <linux/config.h>
+#include <linux/version.h>
+
 /* are we Linux 1.2.x? */
 #if LINUX_VERSION_CODE < 0x10300
 #define LINUX12
@@ -152,7 +188,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#include <linux/config.h>	/* for CONFIG_INET */
+/*#include <linux/config.h>*/		/* For CONFIG_INET */
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -167,18 +203,34 @@
 
 /**************************************************************************/
 
-/* Define this if you want to detect network reconfigurations.
- * They may be a real nuisance on a larger ARCnet network: but if you are
- * a network administrator you probably would like to count them. 
- * Reconfigurations will be recorded in stats.tx_carrier_errors 
- * (the last field of the /proc/net/dev file).
- *
- * The card sends the reconfiguration signal when it loses the connection
- * to the rest of its network. It is a 'Hello, is anybody there?' cry.  This
+/* The card sends the reconfiguration signal when it loses the connection to
+ * the rest of its network. It is a 'Hello, is anybody there?' cry.  This
  * usually happens when a new computer on the network is powered on or when
  * the cable is broken.
+ *
+ * Define DETECT_RECONFIGS if you want to detect network reconfigurations. 
+ * They may be a real nuisance on a larger ARCnet network; if you are a
+ * network administrator you probably would like to count them. 
+ * Reconfigurations will be recorded in stats.tx_carrier_errors (the last
+ * field of the /proc/net/dev file).
+ *
+ * Define SHOW_RECONFIGS if you really want to see a log message whenever
+ * a RECON occurs.
  */
 #define DETECT_RECONFIGS
+#undef SHOW_RECONFIGS
+
+/* RECON_THRESHOLD is the maximum number of RECON messages to receive within
+ * one minute before printing a "cabling problem" warning.  You must have
+ * DETECT_RECONFIGS enabled if you want to use this.  The default value
+ * should be fine.
+ *
+ * After that, a "cabling restored" message will be printed on the next IRQ
+ * if no RECON messages have been received for 10 seconds.
+ *
+ * Do not define RECON_THRESHOLD at all if you want to disable this feature.
+ */
+#define RECON_THRESHOLD 30
 
 /* Define this if you want to make sure transmitted packets are "acknowledged"
  * by the destination host, as long as they're not to the broadcast address.
@@ -190,26 +242,33 @@
  */
 #define VERIFY_ACK
 
+/* Define this to the minimum "timeout" value.  If a transmit takes longer
+ * than TX_TIMEOUT jiffies, Linux will abort the TX and retry.  On a large
+ * network, or one with heavy network traffic, this timeout may need to be
+ * increased.
+ */
+#define TX_TIMEOUT 20
+
 /* Define this if you want to make it easier to use the "call trace" when
  * a kernel NULL pointer assignment occurs.  Hopefully unnecessary, most of
  * the time.  It will make all the function names (and other things) show
  * up as kernel symbols.  (especially handy when using arcnet as a module)
  */
-#define static
+#undef static
 
 /**************************************************************************/
 
-/* new debugging bitflags: each option can be enabled individually.
+/* New debugging bitflags: each option can be enabled individually.
  *
- * these can be set while the driver is running by typing:
+ * These can be set while the driver is running by typing:
  *	ifconfig arc0 down metric 1xxx HOSTNAME
  *		where 1xxx is 1000 + the debug level you want
  *		and HOSTNAME is your hostname/ip address
  * and then resetting your routes.
  *
  * Note: only debug flags included in the ARCNET_DEBUG_MAX define will
- *   actually be available.  GCC (at least 2.7.0) will notice lines
- *   using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize
+ *   actually be available.  GCC will (at least, GCC 2.7.0 will) notice
+ *   lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize
  *   them out.
  */
 #define D_NORMAL	1	/* D_NORMAL  normal operational info	*/
@@ -233,8 +292,9 @@
 #endif
 int arcnet_debug = ARCNET_DEBUG;
 
-/* macro to simplify debug checking */
+/* macros to simplify debug checking */
 #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
+#define BUGMSG(x,msg,args...) BUGLVL(x) printk("%6s: " msg, dev->name , ## args);
 
 #ifndef HAVE_AUTOIRQ
 /* From auto_irq.c, in ioport.h for later versions. */
@@ -257,16 +317,18 @@
 #define IF_TBUSY (lp->adev->tbusy \
 		|| lp->edev->tbusy \
 		|| lp->sdev->tbusy)
+
 #define INTERRUPT lp->adev->interrupt \
 		=lp->edev->interrupt \
 		=lp->sdev->interrupt
 #define IF_INTERRUPT (lp->adev->interrupt \
 		|| lp->edev->interrupt \
 		|| lp->sdev->interrupt)
+
 #define START lp->adev->start \
 		=lp->edev->start \
 		=lp->sdev->start
-
+		
 
 /* The number of low I/O ports used by the ethercard. */
 #define ARCNET_TOTAL_SIZE	16
@@ -330,20 +392,20 @@
 #define RESETclear      0x08            /* power-on-reset */
 #define CONFIGclear     0x10            /* system reconfigured */
 
-      /* flags for "load test flags" command */
+	/* flags for "load test flags" command */
 #define TESTload        0x08            /* test flag (diagnostic) */
 
-      /* byte deposited into first address of buffers on reset */
+	/* byte deposited into first address of buffers on reset */
 #define TESTvalue       0321		 /* that's octal for 0xD1 :) */
 
-      /* for "enable receiver" command */
+	/* for "enable receiver" command */
 #define RXbcasts        0x80            /* receive broadcasts */
 
-      /* flags for "define configuration" command */
+	/* flags for "define configuration" command */
 #define NORMALconf      0x00            /* 1-249 byte packets */
 #define EXTconf         0x08            /* 250-504 byte packets */
 
-	/* buffers (4 total) used for receive and xmit.
+	/* Starts receiving packets into recbuf.
 	 */
 #define EnableReceiver()	outb(RXcmd|(recbuf<<3)|RXbcasts,COMMAND)
 
@@ -361,7 +423,7 @@
 #define ARC_P_ETHER	0xE8
 
 	/* Unsupported/indirectly supported protocols */
-#define ARC_P_LANSOFT	251		/* 0xFB */
+#define ARC_P_LANSOFT	251		/* 0xFB - what is this? */
 #define ARC_P_ATALK	0xDD
 
 	/* the header required by the card itself */
@@ -460,6 +522,13 @@
 	      in_txhandler,	/* in TX_IRQ handler? */
 	      sending;		/* transmit in progress? */
 	short tx_left;		/* segments of split packet left to TX */
+
+#if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD)
+	time_t first_recon,	/* time of "first" RECON message to count */
+		last_recon;	/* time of most recent RECON */
+	int num_recons,		/* number of RECONs between first and last. */
+	    network_down;	/* do we think the network is down? */
+#endif
 	
 	struct timer_list timer; /* the timer interrupt struct */
 	struct Incoming incoming[256];	/* one from each address */
@@ -485,13 +554,14 @@
 static int arcnet_close(struct device *dev);
 static int arcnet_reset(struct device *dev);
 
+static int arcnet_send_packet_bad(struct sk_buff *skb,struct device *dev);
 static int arcnetA_send_packet(struct sk_buff *skb, struct device *dev);
 static int arcnetE_send_packet(struct sk_buff *skb, struct device *dev);
 static int arcnetS_send_packet(struct sk_buff *skb, struct device *dev);
 static void arcnetA_continue_tx(struct device *dev);
 static void arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
 		char *data,int length,int daddr,int exceptA);
-static void arcnetAS_go_tx(struct device *dev);
+static int arcnet_go_tx(struct device *dev,int enable_irq);
 
 static void arcnet_interrupt(int irq,struct pt_regs *regs);
 static void arcnet_inthandler(struct device *dev);
@@ -585,7 +655,7 @@
 	struct arcnet_local *lp;
 
 	printk(version);
-
+	
 #if 1
 	BUGLVL(D_NORMAL)
 	{
@@ -608,8 +678,7 @@
 	}
 #endif
 
-	BUGLVL(D_INIT)
-		printk("arcnet: given: base %lXh, IRQ %Xh, shmem %lXh\n",
+	BUGMSG(D_INIT,"given: base %lXh, IRQ %Xh, shmem %lXh\n",
 			dev->base_addr,dev->irq,dev->mem_start);
 
 #ifndef MODULE
@@ -622,8 +691,7 @@
 		int ioaddr = *port;
 		if (check_region(ioaddr, ARCNET_TOTAL_SIZE))
 		{
-			BUGLVL(D_INIT)
-				printk("arcnet: Skipping %Xh because of check_region...\n",
+			BUGMSG(D_INIT,"Skipping %Xh because of check_region...\n",
 					ioaddr);
 			continue;
 		}
@@ -637,13 +705,11 @@
 	/* ioprobe turned out okay.  Now give it a couple seconds to finish
 	 * initializing...
 	 */
-	BUGLVL(D_INIT)
-		printk("arcnet: ioprobe okay!  Waiting for reset...\n");
+	BUGMSG(D_INIT,"ioprobe okay!  Waiting for reset...\n");
 	JIFFER(100);
 
 	/* okay, now we have to find the shared memory area. */
-	BUGLVL(D_INIT)
-		printk("arcnet: starting memory probe, given %lXh\n",
+	BUGMSG(D_INIT,"starting memory probe, given %lXh\n",
 			dev->mem_start);
 	if (dev->mem_start)	/* value given - probe just that one */
 	{
@@ -663,9 +729,11 @@
 	if (!dev->base_addr || !dev->irq || !dev->mem_start 
 		|| !dev->rmem_start)
 	{
-		printk("arcnet: loadable modules can't autoprobe!\n");
-		printk("arcnet:  try using io=, irqnum=, and shmem= on the insmod line.\n");
-		printk("arcnet:  you may also need num= to change the device name. (ie. num=1 for arc1)\n");
+		printk("%6s: loadable modules can't autoprobe!\n",dev->name);
+		printk("%6s:  try using io=, irqnum=, and shmem= on the insmod line.\n",
+			dev->name);
+		printk("%6s:  you may also need num= to change the device name. (ie. num=1 for arc1)\n",
+			dev->name);
 		return ENODEV;
 	}
 #endif
@@ -674,7 +742,7 @@
 		int irqval = request_irq(dev->irq, &arcnet_interrupt, 0,
 			"arcnet");
 		if (irqval) {
-			printk("%s: unable to get IRQ %d (irqval=%d).\n",
+			printk("%6s: unable to get IRQ %d (irqval=%d).\n",
 				dev->name,dev->irq, irqval);
 			return EAGAIN;
 		 }
@@ -683,7 +751,7 @@
 	/* Grab the region so we can find another board if autoIRQ fails. */
 	request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet");
 	
-	printk("%s: ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n", 
+	printk("%6s: ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n", 
 		dev->name, dev->base_addr, dev->irq, dev->mem_start);
 
 	/* Initialize the device structure. */
@@ -709,24 +777,26 @@
 	/* And now fill particular fields with arcnet values */
 	dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
 	dev->hard_header_len=sizeof(struct ClientData);
-	BUGLVL(D_DURING)
-		printk("arcnet: ClientData header size is %d.\narcnet: HardHeader size is %d.\n",
-			sizeof(struct ClientData),sizeof(struct HardHeader));
+	BUGMSG(D_DURING,"ClientData header size is %d.\n",
+		sizeof(struct ClientData));
+	BUGMSG(D_DURING,"HardHeader size is %d.\n",
+		sizeof(struct HardHeader));
 
 		/* since we strip EXTRA_CLIENTDATA bytes off before sending,
 		 * we let Linux add that many bytes to the packet data...
 		 */
 	
-	BUGLVL(D_INIT) printk("arcnet: arcnet_probe: resetting card.\n");
+	BUGMSG(D_INIT,"arcnet_probe: resetting card.\n");
 	arcnet_reset(dev);
 	JIFFER(50);
-	BUGLVL(D_NORMAL)
-		printk("arcnet: We appear to be station %d (%02Xh)\n",
+	BUGMSG(D_NORMAL,"We appear to be station %d (%02Xh)\n",
 			lp->arcnum,lp->arcnum);
 	if (lp->arcnum==0)
-		printk("arcnet: WARNING!  Station address 0 is reserved for broadcasts!\n");
+		printk("%6s: WARNING!  Station address 0 is reserved for broadcasts!\n",
+			dev->name);
 	if (lp->arcnum==255)
-		printk("arcnet: WARNING!  Station address 255 may confuse DOS networking programs!\n");
+		printk("%6s: WARNING!  Station address 255 may confuse DOS networking programs!\n",
+			dev->name);
 	dev->dev_addr[0]=lp->arcnum;
 	lp->sequence=1;
 	lp->recbuf=0;
@@ -747,11 +817,8 @@
 {
 	int delayval,airq;
 
-	BUGLVL(D_INIT)
-	{
-		printk("arcnet: probing address %Xh\n",ioaddr);
-		printk("arcnet:  status1=%Xh\n",inb(STATUS));
-	}
+	BUGMSG(D_INIT,"probing address %Xh\n",ioaddr);
+	BUGMSG(D_INIT," status1=%Xh\n",inb(STATUS));
 
 		
 	/* very simple - all we have to do is reset the card, and if there's
@@ -766,8 +833,7 @@
 	/* if status port is FF, there's certainly no arcnet... give up. */
 	if (inb(STATUS)==0xFF)
 	{
-		BUGLVL(D_INIT)
-			printk("arcnet:  probe failed.  Status port empty.\n");
+		BUGMSG(D_INIT," probe failed.  Status port empty.\n");
 		return ENODEV;
 	}
 
@@ -787,22 +853,20 @@
 			
 		if (curval==initval)
 		{
-			printk("arcnet:  probe failed.  never-changing command port (%02Xh).\n",
+			BUGLVL(D_INIT," probe failed.  never-changing command port (%02Xh).\n",
 				initval);
 			return ENODEV;
 		}
 	}
 #endif
 
-	BUGLVL(D_INIT)
-		printk("arcnet:  status2=%Xh\n",inb(STATUS));
+	BUGMSG(D_INIT," status2=%Xh\n",inb(STATUS));
 
 	/* now we turn the reset bit off so we can IRQ next reset... */
 	outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
 	if (inb(STATUS) & RESETflag) /* reset flag STILL on */
 	{
-		BUGLVL(D_INIT)
-			printk("arcnet:  probe failed.  eternal reset flag1...(status=%Xh)\n",
+		BUGMSG(D_INIT," probe failed.  eternal reset flag1...(status=%Xh)\n",
 				inb(STATUS));
 		return ENODEV;
 	}
@@ -827,15 +891,14 @@
 
 	airq = autoirq_report(0);
 	BUGLVL(D_INIT) if (airq)
-		printk("arcnet:  autoirq is %d\n", airq);
+		printk("%6s:  autoirq is %d\n", dev->name, airq);
 
 	/* if there was no autoirq AND the user hasn't set any defaults,
 	 * give up.
 	 */
 	if (!airq && !(dev->base_addr && dev->irq))
 	{
-		BUGLVL(D_INIT)
-			printk("arcnet:  probe failed.  no autoirq...\n");
+		BUGMSG(D_INIT," probe failed.  no autoirq...\n");
 		return ENODEV;
 	}
 
@@ -849,8 +912,7 @@
 	
 	if (inb(STATUS) & RESETflag) /* reset flag STILL on */
 	{
-		BUGLVL(D_INIT)
-			printk("arcnet:  probe failed.  eternal reset flag...(status=%Xh)\n",
+		BUGMSG(D_INIT," probe failed.  eternal reset flag...(status=%Xh)\n",
 				inb(STATUS));
 		return ENODEV;
 	}
@@ -865,13 +927,11 @@
 	}
 	else if (dev->irq == 2)
 	{
-		BUGLVL(D_NORMAL)
-			printk("arcnet: IRQ2 == IRQ9, don't worry.\n");
+		BUGMSG(D_NORMAL,"IRQ2 == IRQ9, don't worry.\n");
 		dev->irq = 9;
 	}
 
-	BUGLVL(D_INIT)
-		printk("arcnet: irq and base address seem okay. (%lXh, IRQ %d)\n",
+	BUGMSG(D_INIT,"irq and base address seem okay. (%lXh, IRQ %d)\n",
 			dev->base_addr,dev->irq);
 	return 0;
 }
@@ -883,16 +943,14 @@
  */
 int arcnet_memprobe(struct device *dev,u_char *addr)
 {
-	BUGLVL(D_INIT)
-		printk("arcnet: probing memory at %lXh\n",(u_long)addr);
+	BUGMSG(D_INIT,"probing memory at %lXh\n",(u_long)addr);
 		
 	dev->mem_start=0;
 
 	/* ARCnet memory byte 0 is TESTvalue */
 	if (addr[0]!=TESTvalue)
 	{
-		BUGLVL(D_INIT)
-			printk("arcnet:  probe failed.  addr=%lXh, addr[0]=%Xh (not %Xh)\n",
+		BUGMSG(D_INIT," probe failed.  addr=%lXh, addr[0]=%Xh (not %Xh)\n",
 				(unsigned long)addr,addr[0],TESTvalue);
 		return ENODEV;
 	}
@@ -901,8 +959,7 @@
 	addr[0]=0x42;
 	if (addr[0]!=0x42)
 	{
-		BUGLVL(D_INIT)
-			printk("arcnet:  probe failed.  addr=%lXh, addr[0]=%Xh (not 42h)\n",
+		BUGMSG(D_INIT," probe failed.  addr=%lXh, addr[0]=%Xh (not 42h)\n",
 				(unsigned long)addr,addr[0]);
 	 	return ENODEV;
 	}
@@ -930,8 +987,7 @@
 	
 	outb(0,INTMASK);	/* no IRQ's, please! */
 	
-	BUGLVL(D_INIT)
-		printk("arcnet: Resetting %s (status=%Xh)\n",
+	BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
 			dev->name,inb(STATUS));
 
 	inb(RESET);		/* Reset by reading this port */
@@ -946,8 +1002,7 @@
 	cardmem = (u_char *) dev->mem_start;
 	if (cardmem[0] != TESTvalue)
 	{
-		BUGLVL(D_INIT)
-			printk("arcnet: reset failed: TESTvalue not present.\n");
+		BUGMSG(D_INIT,"reset failed: TESTvalue not present.\n");
 		return 1;
 	}
 	lp->arcnum=cardmem[1];  /* save address for later use */
@@ -1016,9 +1071,7 @@
 	dev->stop=NULL;
 	dev->hard_start_xmit=arcnetE_send_packet;
 
-	BUGLVL(D_EXTRA)
-		printk("%s: ARCnet Ethernet-Encap protocol initialized.\n",
-			dev->name);
+	BUGMSG(D_EXTRA,"ARCnet Ethernet-Encap protocol initialized.\n");
 			
 	return 0;
 }
@@ -1044,9 +1097,7 @@
 #ifdef LINUX12
 	dev->type_trans=arcnetS_type_trans;
 #endif
-	BUGLVL(D_EXTRA)
-		printk("%s: ARCnet RFC1051 (NetBsd, AmiTCP) protocol initialized.\n",
-			dev->name);
+	BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBsd, AmiTCP) protocol initialized.\n");
 
 	return 0;
 }
@@ -1071,11 +1122,11 @@
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
 	int ioaddr=dev->base_addr,delayval;
-
+	
 	if (dev->metric>=1000)
 	{
 		arcnet_debug=dev->metric-1000;
-		printk("arcnet: debug level set to %d\n",arcnet_debug);
+		printk("%6s: debug level set to %d\n",dev->name,arcnet_debug);
 		dev->metric=1;
 	}
 
@@ -1083,7 +1134,7 @@
 
 	irq2dev_map[dev->irq] = dev;
 
-	BUGLVL(D_EXTRA) printk("arcnet: arcnet_open: resetting card.\n");
+	BUGMSG(D_EXTRA,"arcnet_open: resetting card.\n");
 	
 	/* try to reset - twice if it fails the first time */
 	if (arcnet_reset(dev) && arcnet_reset(dev))
@@ -1096,9 +1147,7 @@
 	
 	/* The RFC1201 driver is the default - just store */
 	lp->adev=dev;
-	BUGLVL(D_EXTRA)
-		printk("%s:  ARCnet RFC1201 protocol initialized.\n",
-			lp->adev->name);
+	BUGMSG(D_EXTRA,"ARCnet RFC1201 protocol initialized.\n");
 	
 	/* Initialize the ethernet-encap protocol driver */
 	lp->edev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
@@ -1135,7 +1184,6 @@
 	outb(NORXflag|RECON_flag,INTMASK);
 	
 	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
@@ -1151,6 +1199,10 @@
 	TBUSY=1;
 	START=0;
 	
+	/* very important! */
+	irq2dev_map[dev->irq] = NULL;
+
+	
 	/* Flush TX and disable RX */
 	outb(0,INTMASK);	/* no IRQ's (except RESET, of course) */
 	outb(NOTXcmd,COMMAND);  /* stop transmit */
@@ -1178,10 +1230,9 @@
 	kfree(lp->sdev);
 	lp->sdev=NULL;
 
-	/* Update the statistics here. */
+	/* Update the statistics here. (not necessary in ARCnet) */
 
 	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
@@ -1193,25 +1244,28 @@
  *                                                                          *
  ****************************************************************************/
 
-
-/* Called by the kernel in order to transmit a packet.
+/* Generic error checking routine for arcnet??_send_packet
  */
 static int
-arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
+arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
 	int ioaddr=dev->base_addr;
-
-	lp->intx++;
 	
-	BUGLVL(D_DURING)
-		printk("arcnet: transmit requested (status=%Xh, inTX=%d)\n",
+	BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
 			inb(STATUS),lp->intx);
 			
 	if (lp->in_txhandler)
 	{
-		printk("arcnet: send_packet called while in txhandler!\n");
-		lp->intx--;
+		BUGMSG(D_NORMAL,"send_packet called while in txhandler!\n");
+		lp->stats.tx_dropped++;
+		return 1;
+	}
+
+	if (lp->intx>1)
+	{
+		BUGMSG(D_NORMAL,"send_packet called while intx!\n");
+		lp->stats.tx_dropped++;
 		return 1;
 	}
 
@@ -1220,34 +1274,37 @@
 		/* If we get here, some higher level has decided we are broken.
 		   There should really be a "kick me" function call instead. */
 		int tickssofar = jiffies - dev->trans_start;
-		int recbuf=lp->recbuf;
+		/*int recbuf=lp->recbuf;*/
 		int status=inb(STATUS);
 		
-		if (tickssofar < 5) 
+		if (tickssofar < TX_TIMEOUT) 
 		{
-			BUGLVL(D_DURING)
-				printk("arcnet: premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
+			BUGMSG(D_DURING,"premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
 					status,tickssofar,lp->outgoing.skb,
 					lp->outgoing.numsegs,
 					lp->outgoing.segnum);
-			lp->intx--;
 			return 1;
 		}
 
-		BUGLVL(D_EXTRA)
-			printk("arcnet: transmit timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
-				status,lp->intx,lp->in_txhandler,tickssofar);
-				
-		lp->stats.tx_errors++;
-
-		/* Try to restart the adaptor. */
-		/*arcnet_reset(dev);*/
-		
 		outb(0,INTMASK);
-		if (status&NORXflag) EnableReceiver();
-		if (!(status&TXFREEflag))
+
+		if (status&TXFREEflag)	/* transmit _DID_ finish */
+		{
+			BUGMSG(D_EXTRA,"tx timed out - missed IRQ? (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
+					status,lp->intx,
+					lp->in_txhandler,tickssofar);
+			lp->stats.tx_errors++;
+		}
+		else
+		{
+			BUGMSG(D_NORMAL,"tx timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
+					status,lp->intx,
+					lp->in_txhandler,tickssofar);
+			lp->stats.tx_errors++;
+			lp->stats.tx_aborted_errors++;
+
 			outb(NOTXcmd,COMMAND);
-		/*dev->trans_start = jiffies;*/
+		}
 
 		if (lp->outgoing.skb)
 		{
@@ -1257,12 +1314,8 @@
 		lp->outgoing.skb=NULL;
 		
 		TBUSY=0;
-		lp->intx--;
-		/*lp->intx=0;*/
-		/*lp->in_txhandler=0;*/
 		lp->txready=0;
 		lp->sending=0;
-		/*mark_bh(NET_BH);*/
 
 		outb(NORXflag|RECON_flag,INTMASK);
 
@@ -1273,23 +1326,22 @@
 	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
 	   itself. */
 	if (skb == NULL) {
-		printk("arcnet: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
-			inb(STATUS),lp->intx,jiffies-dev->trans_start);
+		printk("%6s: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
+			dev->name,inb(STATUS),lp->intx,jiffies-dev->trans_start);
+		lp->stats.tx_errors++;
 		dev_tint(dev);
-		lp->intx--;
 		return 0;
 	}
 	
 	if (lp->txready)	/* transmit already in progress! */
 	{
-		printk("arcnet: trying to start new packet while busy! (status=%Xh)\n",
-			inb(STATUS));
-		/*printk("arcnet: marking as not ready.\n");*/
+		printk("%6s: trying to start new packet while busy! (status=%Xh)\n",
+			dev->name,inb(STATUS));
 		outb(0,INTMASK);
 		outb(NOTXcmd,COMMAND); /* abort current send */
 		arcnet_inthandler(dev); /* fake an interrupt */
 		lp->stats.tx_errors++;
-		lp->intx--;
+		lp->stats.tx_fifo_errors++;
 		lp->txready=0;	/* we definitely need this line! */
 		
 		return 1;
@@ -1299,253 +1351,224 @@
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
         if (set_bit(0, (void*)&dev->tbusy) != 0)
         {
-            printk("arcnet: transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
-            		inb(STATUS),lp->intx,jiffies-dev->trans_start);
-            lp->intx--;
+            printk("%6s: transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
+            		dev->name,inb(STATUS),lp->intx,jiffies-dev->trans_start);
+            lp->stats.tx_errors++;
+            lp->stats.tx_fifo_errors++;
             return -EBUSY;
         }
-	else {
-		struct Outgoing *out=&(lp->outgoing);
-		
-		TBUSY=1;
+
+	return 0;
+}
+
+
+/* Called by the kernel in order to transmit a packet.
+ */
+static int
+arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	int ioaddr=dev->base_addr,bad;
+	struct Outgoing *out=&(lp->outgoing);
+
+	BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
+			inb(STATUS),lp->intx);
+
+	lp->intx++;
+	
+	bad=arcnet_send_packet_bad(skb,dev);
+	if (bad)
+	{
+		lp->intx--;
+		return bad;
+	}
+	
+	TBUSY=1;
 		
-		out->length = 1 < skb->len ? skb->len : 1;
-		out->hdr=(struct ClientData*)skb->data;
-		out->skb=skb;
+	out->length = 1 < skb->len ? skb->len : 1;
+	out->hdr=(struct ClientData*)skb->data;
+	out->skb=skb;
 		
-		BUGLVL(D_SKB)
+	BUGLVL(D_SKB)
+	{
+		short i;
+		for( i=0; i< skb->len; i++)
 		{
-			short i;
-			for( i=0; i< skb->len; i++)
-			{
-				if( i%16 == 0 ) printk("\n[%04hX] ",i);
-				printk("%02hX ",((unsigned char*)skb->data)[i]);
-			}
-			printk("\n");
+			if( i%16 == 0 ) printk("\n[%04hX] ",i);
+			printk("%02hX ",((unsigned char*)skb->data)[i]);
 		}
+		printk("\n");
+	}
 
-		out->hdr->sequence=(lp->sequence++);
-
-		if (lp->txready && inb(STATUS)&TXFREEflag)
-			arcnetAS_go_tx(dev);
-		
-		/* fits in one packet? */
-		if (out->length-EXTRA_CLIENTDATA<=XMTU)
-		{
-			BUGLVL(D_DURING)
-				printk("arcnet: not splitting %d-byte packet. (split_flag=%d)\n",
-					out->length,out->hdr->split_flag);
-			BUGLVL(D_EXTRA) if (out->hdr->split_flag)
-				printk("arcnet: short packet has split_flag set?! (split_flag=%d)\n",
-					out->hdr->split_flag);
-			out->numsegs=1;
-			out->segnum=1;
-			arcnetAS_prepare_tx(dev,
-				((char *)out->hdr)+EXTRA_CLIENTDATA,
-				sizeof(struct ClientData)-EXTRA_CLIENTDATA,
-				((char *)skb->data)+sizeof(struct ClientData),
-				out->length-sizeof(struct ClientData),
-				out->hdr->daddr,1);
+	out->hdr->sequence=(lp->sequence++);
+	
+	/*arcnet_go_tx(dev);*/	/* Make sure buffers are clear */
 
-			/* done right away */
-			dev_kfree_skb(out->skb,FREE_WRITE);
-			out->skb=NULL;
+	/* fits in one packet? */
+	if (out->length-EXTRA_CLIENTDATA<=XMTU)
+	{
+		BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n",
+				out->length,out->hdr->split_flag);
+		BUGLVL(D_EXTRA) if (out->hdr->split_flag)
+			printk("%6s: short packet has split_flag set?! (split_flag=%d)\n",
+				dev->name,out->hdr->split_flag);
+		out->numsegs=1;
+		out->segnum=1;
+		arcnetAS_prepare_tx(dev,
+			((char *)out->hdr)+EXTRA_CLIENTDATA,
+			sizeof(struct ClientData)-EXTRA_CLIENTDATA,
+			((char *)skb->data)+sizeof(struct ClientData),
+			out->length-sizeof(struct ClientData),
+			out->hdr->daddr,1);
+
+		/* done right away */
+		dev_kfree_skb(out->skb,FREE_WRITE);
+		out->skb=NULL;
 					
-			if (!lp->sending)
-			{
-				arcnetAS_go_tx(dev);
-				
-				/* inform upper layers */
-				TBUSY=0;
-				mark_bh(NET_BH);
-			}
-		}
-		else			/* too big for one - split it */
+		if (arcnet_go_tx(dev,1))
 		{
-			int maxsegsize=XMTU-4;
+			/* inform upper layers */
+			TBUSY=0;
+			mark_bh(NET_BH);
+		}
+	}
+	else			/* too big for one - split it */
+	{
+		int maxsegsize=XMTU-4;
 
-			out->data=(u_char *)skb->data
-					+ sizeof(struct ClientData);
-			out->dataleft=out->length-sizeof(struct ClientData);
-			out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize;
-				
-			out->segnum=0;
+		out->data=(u_char *)skb->data
+				+ sizeof(struct ClientData);
+		out->dataleft=out->length-sizeof(struct ClientData);
+		out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize;
 				
-			BUGLVL(D_TX) printk("arcnet: packet (%d bytes) split into %d fragments:\n",
-				out->length,out->numsegs);
+		out->segnum=0;
+			
+		BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n",
+			out->length,out->numsegs);
 
-			/* if a packet waiting, launch it */
-			if (lp->txready && inb(STATUS)&TXFREEflag)
-				arcnetAS_go_tx(dev);
+		/* if a packet waiting, launch it */
+		arcnet_go_tx(dev,1);
 
-			if (!lp->txready)
-			{
-				/* prepare a packet, launch it and prepare
-                                 * another.
-                                 */
-				arcnetA_continue_tx(dev);
-				if (!lp->sending)
-				{
-					arcnetAS_go_tx(dev);
-					arcnetA_continue_tx(dev);
-					if (!lp->sending)
-						arcnetAS_go_tx(dev);
-				}
-			}
-			
-			/* if segnum==numsegs, the transmission is finished;
-			 * free the skb right away.
+		if (!lp->txready)
+		{
+			/* prepare a packet, launch it and prepare
+			 * another.
 			 */
-			if (out->segnum==out->numsegs)
+			arcnetA_continue_tx(dev);
+			if (arcnet_go_tx(dev,1))
 			{
-				/* transmit completed */
-				out->segnum++;
-				if (out->skb)
-					dev_kfree_skb(out->skb,FREE_WRITE);
-				out->skb=NULL;
+				arcnetA_continue_tx(dev);
+				arcnet_go_tx(dev,1);
 			}
 		}
+		
+		/* if segnum==numsegs, the transmission is finished;
+		 * free the skb right away.
+		 */
+		if (out->segnum==out->numsegs)
+		{
+			/* transmit completed */
+			out->segnum++;
+			if (out->skb)
+				dev_kfree_skb(out->skb,FREE_WRITE);
+			out->skb=NULL;
+		}
 	}
 
-	lp->intx--;
-	lp->stats.tx_packets++;
 	dev->trans_start=jiffies;
+	lp->intx--;
 	return 0;
 }
 
-/* After an RFC1201 split packet has been set up, this function calls
- * arcnetAS_prepare_tx to load the next segment into the card.  This function
- * does NOT automatically call arcnetAS_go_tx to allow for easier double-
- * buffering.
+
+/* Called by the kernel in order to transmit an ethernet-type packet.
  */
-static void arcnetA_continue_tx(struct device *dev)
+static int
+arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int maxsegsize=XMTU-4;
-	struct Outgoing *out=&(lp->outgoing);
+	int bad;
+	union ArcPacket *arcpacket = 
+		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
+	u_char *arcsoft,daddr;
+	short offset,length=skb->len+1;
+
+	BUGMSG(D_DURING,"in arcnetE_send_packet (skb=%p)\n",skb);
+		
+	lp->intx++;
 	
-	if (lp->txready)
+	bad=arcnet_send_packet_bad(skb,dev);
+	if (bad)
 	{
-		printk("arcnet: continue_tx: called with packet in buffer!\n");
-		return;
+		lp->intx--;
+		return bad;
 	}
 
-	if (out->segnum>=out->numsegs)
+	TBUSY=1;
+		
+	if (length>XMTU)
 	{
-		printk("arcnet: continue_tx: building segment %d of %d!\n",
-			out->segnum+1,out->numsegs);
-	}
-
-	if (!out->segnum)	/* first packet */
-		out->hdr->split_flag=((out->numsegs-2)<<1)+1;
-	else
-		out->hdr->split_flag=out->segnum<<1;
-
-	out->seglen=maxsegsize;
-	if (out->seglen>out->dataleft) out->seglen=out->dataleft;
-			
-	BUGLVL(D_TX) printk("arcnet: building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
-		out->segnum+1,out->seglen,out->numsegs,
-		out->length,out->hdr->split_flag);
+		printk("%6s: MTU must be <= 493 for ethernet encap (length=%d).\n",
+			dev->name,length);
+		printk("%6s: transmit aborted.\n",dev->name);
 
-	arcnetAS_prepare_tx(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
-		sizeof(struct ClientData)-EXTRA_CLIENTDATA,
-		out->data,out->seglen,out->hdr->daddr,1);
+		dev_kfree_skb(skb,FREE_WRITE);
+		return 0;
+	}
 		
-	out->dataleft-=out->seglen;
-	out->data+=out->seglen;
-	out->segnum++;
-}
-
-
-/* Given an skb, copy a packet into the ARCnet buffers for later transmission
- * by arcnetAS_go_tx.
- */
-static void
-arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
-		char *data,int length,int daddr,int exceptA)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	struct ClientData *arcsoft;
-	union ArcPacket *arcpacket = 
-		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
-	int offset;
-	
-	lp->txbuf=lp->txbuf^1;	/* XOR with 1 to alternate between 2 and 3 */
-	
-	length+=hdrlen;
+	BUGMSG(D_DURING,"starting tx sequence...\n");
 
-	BUGLVL(D_TX)
-		printk("arcnet: arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
-			hdr,length,data);
+	lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
 
 	/* clean out the page to make debugging make more sense :) */
 	BUGLVL(D_DURING)
 		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
 
-	arcpacket->hardheader.destination=daddr;
+	/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
+	if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
+		daddr=arcpacket->hardheader.destination=0;
+	else
+		daddr=arcpacket->hardheader.destination=
+			((struct ethhdr*)(skb->data))->h_dest[5];
 
 	/* load packet into shared memory */
-	if (length<=MTU)	/* Normal (256-byte) Packet */
-	{
-		arcpacket->hardheader.offset1=offset=256-length;
-		arcsoft=(struct ClientData *)
-			(&arcpacket->raw[offset]);
-	}
-	else if (length>=MinTU)	/* Extended (512-byte) Packet */
-	{
-		arcpacket->hardheader.offset1=0;
-		arcpacket->hardheader.offset2=offset=512-length;
-		
-		arcsoft=(struct ClientData *)
-			(&arcpacket->raw[offset]);
-	}
-	else if (exceptA)		/* RFC1201 Exception Packet */
+	offset=512-length;
+	if (length>MTU)		/* long/exception packet */
 	{
+		if (length<MinTU) offset-=3;
 		arcpacket->hardheader.offset1=0;
-		arcpacket->hardheader.offset2=offset=512-length-4;
-		arcsoft=(struct ClientData *)
-			(&arcpacket->raw[offset+4]);
-		
-		/* exception-specific stuff - these four bytes
-		 * make the packet long enough to fit in a 512-byte
-		 * frame.
-		 */
-		arcpacket->raw[offset+0]=hdr[0];
-		arcpacket->raw[offset+1]=0xFF; /* FF flag */
-			arcpacket->raw[offset+2]=0xFF; /* FF padding */
-			arcpacket->raw[offset+3]=0xFF; /* FF padding */
+		arcpacket->hardheader.offset2=offset;
 	}
-	else				/* "other" Exception packet */
+	else			/* short packet */
 	{
-		/* RFC1051 - set 4 trailing bytes to 0 */
-		memset(&arcpacket->raw[508],0,4);
-
-		/* now round up to MinTU */
-		arcpacket->hardheader.offset1=0;
-		arcpacket->hardheader.offset2=offset=512-MinTU;
-		arcsoft=(struct ClientData *)(&arcpacket->raw[offset]);
+		arcpacket->hardheader.offset1=(offset-=256);
 	}
-
-
+	
+	BUGMSG(D_DURING," length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
+			length,offset,arcpacket->hardheader.offset1,
+			arcpacket->hardheader.offset2);
+	
+	arcsoft=&arcpacket->raw[offset];
+	arcsoft[0]=ARC_P_ETHER;
+	arcsoft++;
+		
 	/* copy the packet into ARCnet shmem
 	 *  - the first bytes of ClientData header are skipped
 	 */
-	memcpy((u_char*)arcsoft,
-		(u_char*)hdr,hdrlen);
-	memcpy((u_char*)arcsoft+hdrlen,
-		data,length-hdrlen);
+	BUGMSG(D_DURING,"ready to memcpy\n");
+	
+	memcpy(arcsoft,skb->data,skb->len);
 		
-	BUGLVL(D_DURING) printk("arcnet: transmitting packet to station %02Xh (%d bytes)\n",
+	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
 			daddr,length);
-			
+				
 	BUGLVL(D_TX)
 	{
 		int countx,county;
-		
-		printk("arcnet: packet dump [tx] follows:");
+			
+		printk("%6s: packet dump [tx] follows:",dev->name);
 
- 		for (county=0; county<16+(length>MTU)*16; county++)
+ 		for (county=0; county<16+(length>=240)*16; county++)
 		{
 			printk("\n[%04X] ",county*16);
 			for (countx=0; countx<16; countx++)
@@ -1560,347 +1583,288 @@
 	lp->outgoing.lastload_dest=daddr;
 #endif
 	lp->txready=lp->txbuf;	/* packet is ready for sending */
-}
 
-/* Actually start transmitting a packet that was placed in the card's
- * buffer by arcnetAS_prepare_tx.
- */
-static void
-arcnetAS_go_tx(struct device *dev)
-{
-	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr;
-
-	BUGLVL(D_DURING)
-		printk("arcnet: go_tx: status=%Xh\n",
-			inb(STATUS));
-	
-	if (!(inb(STATUS)&TXFREEflag) || !lp->txready) return;
-
-	/* start sending */
-	outb(TXcmd|(lp->txready<<3),COMMAND);
+	dev_kfree_skb(skb,FREE_WRITE);
 
-	outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
+	if (arcnet_go_tx(dev,1))
+	{
+		/* inform upper layers */
+		TBUSY=0;
+		mark_bh(NET_BH);
+	}
 
-	dev->trans_start = jiffies;
-	lp->txready=0;
-	lp->sending++;
-#ifdef VERIFY_ACK	
-	lp->outgoing.lasttrans_dest=lp->outgoing.lastload_dest;
-	lp->outgoing.lastload_dest=0;
-#endif
+	dev->trans_start=jiffies;
+	lp->intx--;
+	return 0;
 }
 
 
-/* Called by the kernel in order to transmit an ethernet-type packet.
+/* Called by the kernel in order to transmit an RFC1051-type packet.
  */
 static int
-arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
+arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	int ioaddr=dev->base_addr,bad,length;
+	struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
+
+	lp->intx++;
 	
-	BUGLVL(D_DURING)
-		printk("%s: in arcnetE_send_packet (skb=%p)\n",dev->name,skb);
+	BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
+			inb(STATUS),lp->intx);
 
-	if (IF_TBUSY)
+	bad=arcnet_send_packet_bad(skb,dev);
+	if (bad)
 	{
-		/* If we get here, some higher level has decided we are broken.
-		   There should really be a "kick me" function call instead. */
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 10)
-			return 1;
-		printk("%s: transmit timed out\n",dev->name);
-		
-		/* Try to restart the adaptor. */
-		TBUSY=0;
-		/*dev->trans_start = jiffies;*/
-		return 0;
+		lp->intx--;
+		return bad;
 	}
+	
+	TBUSY=1;
 
-	/* If some higher layer thinks we've missed an tx-done interrupt
-	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-	   itself. */
-	if (skb == NULL)
-	{
-		dev_tint(dev);
-		return 0;
-	}
+	length = 1 < skb->len ? skb->len : 1;
 
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
-		printk("%s: Transmitter access conflict.\n", dev->name);
-	else
+	BUGLVL(D_SKB)
 	{
-		union ArcPacket *arcpacket = 
-			(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
-		u_char *arcsoft,daddr;
-		short offset,length=skb->len+1;
-		
-		TBUSY=1;
-		
-		if (length>XMTU)
+		short i;
+		for(i=0; i<skb->len; i++)
 		{
-			printk("arcnet: MTU for %s and %s must be <= 493 for ethernet encap.\n",
-				lp->adev->name,lp->edev->name);
-			printk("arcnet: transmit aborted.\n");
-
-			dev_kfree_skb(skb,FREE_WRITE);
-			return 0;
+			if( i%16 == 0 ) printk("\n[%04hX] ",i);
+			printk("%02hX ",((unsigned char*)skb->data)[i]);
 		}
-		
-		BUGLVL(D_DURING)
-			printk("arcnet: starting tx sequence...\n");
-
-		lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
+		printk("\n");
+	}
 
-		/* clean out the page to make debugging make more sense :) */
-		BUGLVL(D_DURING)
-			memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
+	/*if (lp->txready && inb(STATUS)&TXFREEflag)
+		arcnet_go_tx(dev);*/
 
-		/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
-		if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
-			daddr=arcpacket->hardheader.destination=0;
-		else
-			daddr=arcpacket->hardheader.destination=
-				((struct ethhdr*)(skb->data))->h_dest[5];
+	/* fits in one packet? */
+	if (length-S_EXTRA_CLIENTDATA<=XMTU)
+	{
+		arcnetAS_prepare_tx(dev,
+			skb->data+S_EXTRA_CLIENTDATA,
+			sizeof(struct S_ClientData)-S_EXTRA_CLIENTDATA,
+			skb->data+sizeof(struct S_ClientData),
+			length-sizeof(struct S_ClientData),
+			hdr->daddr,0);
 
-		/* load packet into shared memory */
-		offset=512-length;
-		if (length>MTU)		/* long/exception packet */
-		{
-			if (length<MinTU) offset-=3;
-			arcpacket->hardheader.offset1=0;
-			arcpacket->hardheader.offset2=offset;
-		}
-		else			/* short packet */
-		{
-			arcpacket->hardheader.offset1=(offset-=256);
-		}
-		
-		BUGLVL(D_DURING)
-			printk("arcnet: length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
-				length,offset,arcpacket->hardheader.offset1,
-				arcpacket->hardheader.offset2);
-		
-		arcsoft=&arcpacket->raw[offset];
-		arcsoft[0]=ARC_P_ETHER;
-		arcsoft++;
-		
-		/* copy the packet into ARCnet shmem
-		 *  - the first bytes of ClientData header are skipped
-		 */
-		BUGLVL(D_DURING) printk("arcnet: ready to memcpy\n");
-		
-		memcpy(arcsoft,skb->data,skb->len);
-			
-		BUGLVL(D_DURING)
-			printk("arcnet: transmitting packet to station %02Xh (%d bytes)\n",
-				daddr,length);
+		/* done right away */
+		dev_kfree_skb(skb,FREE_WRITE);
 				
-		BUGLVL(D_TX)
+		if (arcnet_go_tx(dev,1))
 		{
-			int countx,county;
-			
-			printk("arcnet: packet dump [tx] follows:");
-
-	 		for (county=0; county<16+(length>=240)*16; county++)
-			{
-				printk("\n[%04X] ",county*16);
-				for (countx=0; countx<16; countx++)
-					printk("%02X ",
-						arcpacket->raw[county*16+countx]);
-			}
-			
-			printk("\n");
+			/* inform upper layers */
+			TBUSY=0;
+			mark_bh(NET_BH);
 		}
-
-	#ifdef VERIFY_ACK
-		lp->outgoing.lastload_dest=daddr;
-	#endif
-		lp->txready=lp->txbuf;	/* packet is ready for sending */
-
-		arcnetAS_go_tx(dev);
-		dev->trans_start = jiffies;
+	}
+	else			/* too big for one - not accepted */
+	{
+		printk("arcnetS: packet too long (length=%d)\n",
+			length);
+		dev_kfree_skb(skb,FREE_WRITE);
+		lp->stats.tx_dropped++;
+		TBUSY=0;
+		mark_bh(NET_BH);	
 	}
 
-	dev_kfree_skb(skb,FREE_WRITE);
-
+	dev->trans_start=jiffies;
+	lp->intx--;
 	return 0;
 }
 
 
-/* Called by the kernel in order to transmit an RFC1051-type packet.
+/* After an RFC1201 split packet has been set up, this function calls
+ * arcnetAS_prepare_tx to load the next segment into the card.  This function
+ * does NOT automatically call arcnet_go_tx.
  */
-static int
-arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
+static void arcnetA_continue_tx(struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr;
-
-	lp->intx++;
+	int maxsegsize=XMTU-4;
+	struct Outgoing *out=&(lp->outgoing);
 	
-	BUGLVL(D_DURING)
-		printk("arcnetS: transmit requested (status=%Xh, inTX=%d)\n",
-			inb(STATUS),lp->intx);
-			
-	if (lp->in_txhandler)
+	if (lp->txready)
 	{
-		printk("arcnetS: send_packet called while in txhandler!\n");
-		lp->intx--;
-		return 1;
+		printk("%6s: continue_tx: called with packet in buffer!\n",
+			dev->name);
+		return;
 	}
 
-	if (IF_TBUSY)
+	if (out->segnum>=out->numsegs)
 	{
-		/* If we get here, some higher level has decided we are broken.
-		   There should really be a "kick me" function call instead. */
-		int tickssofar = jiffies - dev->trans_start;
-		int recbuf=lp->recbuf;
-		int status=inb(STATUS);
-		
-		if (tickssofar < 5) 
-		{
-			BUGLVL(D_DURING)
-				printk("arcnetS: premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
-					status,tickssofar,lp->outgoing.skb,
-					lp->outgoing.numsegs,
-					lp->outgoing.segnum);
-			lp->intx--;
-			return 1;
-		}
+		printk("%6s: continue_tx: building segment %d of %d!\n",
+			dev->name,out->segnum+1,out->numsegs);
+	}
 
-		BUGLVL(D_EXTRA)
-			printk("arcnetS: transmit timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
-				status,lp->intx,lp->in_txhandler,tickssofar);
-				
-		lp->stats.tx_errors++;
+	if (!out->segnum)	/* first packet */
+		out->hdr->split_flag=((out->numsegs-2)<<1)+1;
+	else
+		out->hdr->split_flag=out->segnum<<1;
 
-		/* Try to restart the adaptor. */
-		/*arcnet_reset(dev);*/
+	out->seglen=maxsegsize;
+	if (out->seglen>out->dataleft) out->seglen=out->dataleft;
+			
+	BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
+		out->segnum+1,out->seglen,out->numsegs,
+		out->length,out->hdr->split_flag);
+
+	arcnetAS_prepare_tx(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
+		sizeof(struct ClientData)-EXTRA_CLIENTDATA,
+		out->data,out->seglen,out->hdr->daddr,1);
 		
-		outb(0,INTMASK);
-		if (status&NORXflag) EnableReceiver();
-		if (!(status&TXFREEflag)) outb(NOTXcmd,COMMAND);
-		/*dev->trans_start = jiffies;*/
+	out->dataleft-=out->seglen;
+	out->data+=out->seglen;
+	out->segnum++;
+}
 
-		if (lp->outgoing.skb)
-		{
-			dev_kfree_skb(lp->outgoing.skb,FREE_WRITE);
-			lp->stats.tx_dropped++;
-		}
-		lp->outgoing.skb=NULL;
 
-		TBUSY=0;
-		lp->intx--;
-		/*lp->intx=0;*/
-		/*lp->in_txhandler=0;*/
-		lp->txready=0;
-		lp->sending=0;
-		/*mark_bh(NET_BH);*/
+/* Given an skb, copy a packet into the ARCnet buffers for later transmission
+ * by arcnet_go_tx.
+ */
+static void
+arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
+		char *data,int length,int daddr,int exceptA)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	struct ClientData *arcsoft;
+	union ArcPacket *arcpacket = 
+		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
+	int offset;
+	
+	lp->txbuf=lp->txbuf^1;	/* XOR with 1 to alternate between 2 and 3 */
+	
+	length+=hdrlen;
 
-		outb(NORXflag|RECON_flag,INTMASK);
+	BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
+			hdr,length,data);
 
-		return 1;
-	}
+	/* clean out the page to make debugging make more sense :) */
+	BUGLVL(D_DURING)
+		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
 
-	/* If some higher layer thinks we've missed a tx-done interrupt
-	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-	   itself. */
-	if (skb == NULL) {
-		printk("arcnetS: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
-			inb(STATUS),lp->intx,jiffies-dev->trans_start);
-		dev_tint(dev);
-		lp->intx--;
-		return 0;
+	arcpacket->hardheader.destination=daddr;
+
+	/* load packet into shared memory */
+	if (length<=MTU)	/* Normal (256-byte) Packet */
+	{
+		arcpacket->hardheader.offset1=offset=256-length;
+		arcsoft=(struct ClientData *)
+			(&arcpacket->raw[offset]);
 	}
-	
-	if (lp->txready)	/* transmit already in progress! */
+	else if (length>=MinTU)	/* Extended (512-byte) Packet */
 	{
-		printk("arcnetS: trying to start new packet while busy! (status=%Xh)\n",
-			inb(STATUS));
-		/*printk("arcnetS: marking as not ready.\n");*/
-		outb(0,INTMASK);
-		outb(NOTXcmd,COMMAND); /* abort current send */
-		arcnet_inthandler(dev); /* fake an interrupt */
-		lp->stats.tx_errors++;
-		lp->intx--;
-		lp->txready=0;	/* we definitely need this line! */
+		arcpacket->hardheader.offset1=0;
+		arcpacket->hardheader.offset2=offset=512-length;
 		
-		return 1;
+		arcsoft=(struct ClientData *)
+			(&arcpacket->raw[offset]);
 	}
-
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-        if (set_bit(0, (void*)&dev->tbusy) != 0)
-        {
-            printk("arcnetS: transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
-            		inb(STATUS),lp->intx,jiffies-dev->trans_start);
-            lp->intx--;
-            return -EBUSY;
-        }
-	else {
-		int length;
-		struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
+	else if (exceptA)		/* RFC1201 Exception Packet */
+	{
+		arcpacket->hardheader.offset1=0;
+		arcpacket->hardheader.offset2=offset=512-length-4;
+		arcsoft=(struct ClientData *)
+			(&arcpacket->raw[offset+4]);
 		
-		TBUSY=1;
+		/* exception-specific stuff - these four bytes
+		 * make the packet long enough to fit in a 512-byte
+		 * frame.
+		 */
+		arcpacket->raw[offset+0]=hdr[0];
+		arcpacket->raw[offset+1]=0xFF; /* FF flag */
+			arcpacket->raw[offset+2]=0xFF; /* FF padding */
+			arcpacket->raw[offset+3]=0xFF; /* FF padding */
+	}
+	else				/* "other" Exception packet */
+	{
+		/* RFC1051 - set 4 trailing bytes to 0 */
+		memset(&arcpacket->raw[508],0,4);
+
+		/* now round up to MinTU */
+		arcpacket->hardheader.offset1=0;
+		arcpacket->hardheader.offset2=offset=512-MinTU;
+		arcsoft=(struct ClientData *)(&arcpacket->raw[offset]);
+	}
+
+
+	/* copy the packet into ARCnet shmem
+	 *  - the first bytes of ClientData header are skipped
+	 */
+	memcpy((u_char*)arcsoft,
+		(u_char*)hdr,hdrlen);
+	memcpy((u_char*)arcsoft+hdrlen,
+		data,length-hdrlen);
 		
-		length = 1 < skb->len ? skb->len : 1;
+	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
+			daddr,length);
+			
+	BUGLVL(D_TX)
+	{
+		int countx,county;
 		
-		BUGLVL(D_SKB)
+		printk("%6s: packet dump [tx] follows:",dev->name);
+
+ 		for (county=0; county<16+(length>MTU)*16; county++)
 		{
-			short i;
-			for(i=0; i<skb->len; i++)
-			{
-				if( i%16 == 0 ) printk("\n[%04hX] ",i);
-				printk("%02hX ",((unsigned char*)skb->data)[i]);
-			}
-			printk("\n");
+			printk("\n[%04X] ",county*16);
+			for (countx=0; countx<16; countx++)
+				printk("%02X ",
+					arcpacket->raw[county*16+countx]);
 		}
-
-		if (lp->txready && inb(STATUS)&TXFREEflag)
-			arcnetAS_go_tx(dev);
 		
-		/* fits in one packet? */
-		if (length-S_EXTRA_CLIENTDATA<=XMTU)
-		{
-			arcnetAS_prepare_tx(dev,
-				skb->data+S_EXTRA_CLIENTDATA,
-				sizeof(struct S_ClientData)-S_EXTRA_CLIENTDATA,
-				skb->data+sizeof(struct S_ClientData),
-				length-sizeof(struct S_ClientData),
-				hdr->daddr,0);
+		printk("\n");
+	}
 
-			/* done right away */
-			dev_kfree_skb(skb,FREE_WRITE);
-					
-			if (!lp->sending)
-			{
-				arcnetAS_go_tx(dev);
-				
-				/* inform upper layers */
-				TBUSY=0;
-				mark_bh(NET_BH);
-			}
-		}
-		else			/* too big for one - not accepted */
+#ifdef VERIFY_ACK
+	lp->outgoing.lastload_dest=daddr;
+#endif
+	lp->txready=lp->txbuf;	/* packet is ready for sending */
+}
+
+/* Actually start transmitting a packet that was placed in the card's
+ * buffer by arcnetAS_prepare_tx.  Returns 1 if a Tx is really started.
+ */
+static int
+arcnet_go_tx(struct device *dev,int enable_irq)
+{
+	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
+	int ioaddr=dev->base_addr;
+
+	BUGMSG(D_DURING,"go_tx: status=%Xh\n",
+			inb(STATUS));
+			
+	outb(0,INTMASK);
+
+	if (lp->sending || !lp->txready)
+	{
+		if (enable_irq)
 		{
-			printk("arcnetS: packet too long (length=%d)\n",
-				length);
-			dev_kfree_skb(skb,FREE_WRITE);
-			lp->stats.tx_dropped++;
-			TBUSY=0;
-			mark_bh(NET_BH);	
+			if (lp->sending)
+				outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
+			else
+				outb(NORXflag|RECON_flag,INTMASK);
 		}
+		return 0;
 	}
 
-	lp->intx--;
+	/* start sending */
+	outb(TXcmd|(lp->txready<<3),COMMAND);
+
 	lp->stats.tx_packets++;
-	dev->trans_start=jiffies;
-	return 0;
-}
+	lp->txready=0;
+	lp->sending++;
+
+#ifdef VERIFY_ACK	
+	lp->outgoing.lasttrans_dest=lp->outgoing.lastload_dest;
+	lp->outgoing.lastload_dest=0;
+#endif
 
+	if (enable_irq)
+		outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
 
+	return 1;
+}
 
 
 /****************************************************************************
@@ -1941,17 +1905,17 @@
 {	
 	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
 	int ioaddr=dev->base_addr, status, boguscount = 3, didsomething;
-	
+
 	if (IF_INTERRUPT)
 	{
-		printk("arcnet: DRIVER PROBLEM!  Nested arcnet interrupts!\n");
+		printk("%6s: DRIVER PROBLEM!  Nested arcnet interrupts!\n",
+			dev->name);
 		return;	/* don't even try. */
 	}
 	outb(0,INTMASK);
 	INTERRUPT = 1;
-	
-	BUGLVL(D_DURING)
-		printk("arcnet: in net_interrupt (status=%Xh)\n",inb(STATUS));
+
+	BUGMSG(D_DURING,"in net_interrupt (status=%Xh)\n",inb(STATUS));
 		
 #if 1 /* Whatever you do, don't set this to 0. */
 	do
@@ -1959,17 +1923,22 @@
 		status = inb(STATUS);
 		didsomething=0;
 	
+#if 0 /* no longer necessary - doing checking in arcnet_interrupt now */
 		if (!dev->start)
 		{
-			BUGLVL(D_DURING)
-				printk("arcnet: ARCnet not yet initialized.  irq ignored. (status=%Xh)\n",
+			BUGMSG(D_DURING,"ARCnet not yet initialized.  irq ignored. (status=%Xh)\n",
 					status);
 			if (!(status&NORXflag))
 				outb(NORXflag|RECON_flag,INTMASK);
 
+			/* using dev->interrupt here instead of INTERRUPT
+			 * because if dev->start is 0, the other devices
+			 * probably do not exist.
+			 */
 			dev->interrupt=0;
 			return;
 		}
+#endif
 	
 		/* RESET flag was enabled - card is resetting and if RX
 		 * is disabled, it's NOT because we just got a packet.
@@ -1977,28 +1946,89 @@
 		if (status & RESETflag)
 		{
 			outb(CFLAGScmd|RESETclear,COMMAND);
-			BUGLVL(D_INIT)
-				printk("arcnet: reset irq (status=%Xh)\n",
+			BUGMSG(D_INIT,"reset irq (status=%Xh)\n",
 					status);
 		}
 #ifdef DETECT_RECONFIGS
 		if (status & RECONflag)
 		{
 			outb(CFLAGScmd|CONFIGclear,COMMAND);
-			BUGLVL(D_EXTRA)
-				printk("arcnet: Network reconfiguration detected (status=%Xh)\n",
-					status);
 			lp->stats.tx_carrier_errors++;
+			
+			#ifdef SHOW_RECONFIGS
+			BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
+					status);
+			#endif /* SHOW_RECONFIGS */
+			
+			#ifdef RECON_THRESHOLD
+			/* is the RECON info empty or old? */
+			if (!lp->first_recon || !lp->last_recon || 
+				jiffies-lp->last_recon > HZ*10)
+			{
+				if (lp->network_down)
+					printk("%6s: reconfiguration detected: cabling restored?\n",
+						dev->name);
+				lp->first_recon=lp->last_recon=jiffies;
+				lp->num_recons=lp->network_down=0;
+				
+				BUGMSG(D_DURING,"recon: clearing counters.\n");
+			}
+			else /* add to current RECON counter */
+			{
+				lp->last_recon=jiffies;
+				lp->num_recons++;
+				
+				BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
+					lp->num_recons,
+					(lp->last_recon-lp->first_recon)/HZ,
+					lp->network_down);
+
+				/* if network is marked up;
+				 * and first_recon and last_recon are 60+ sec
+				 *   apart;
+				 * and the average no. of recons counted is
+				 *   > RECON_THRESHOLD/min;
+				 * then print a warning message.
+				 */
+				if (!lp->network_down
+				    && (lp->last_recon-lp->first_recon)<=HZ*60
+				    && lp->num_recons >= RECON_THRESHOLD)
+				{
+					lp->network_down=1;
+					printk("%6s: many reconfigurations detected: cabling problem?\n",
+						dev->name);
+				}
+				else if (!lp->network_down
+				    && lp->last_recon-lp->first_recon > HZ*60)
+				{
+					/* reset counters if we've gone for
+					 * over a minute.
+					 */
+					lp->first_recon=lp->last_recon;
+					lp->num_recons=1;
+				}
+			}
+			#endif
 		}
-#endif
+		#ifdef RECON_THRESHOLD
+		else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
+		{
+			if (lp->network_down)
+				printk("%6s: cabling restored?\n",dev->name);
+			lp->first_recon=lp->last_recon=0;
+			lp->num_recons=lp->network_down=0;
+			
+			BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
+		}
+		#endif
+#endif /* DETECT_RECONFIGS */
 
 		/* RX is inhibited - we must have received something. */
 		if (status & NORXflag)
 		{
 			int recbuf=lp->recbuf=!lp->recbuf;
 
-			BUGLVL(D_DURING)
-				printk("arcnet: receive irq (status=%Xh)\n",
+			BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
 					status);
 
 			/* enable receive of our next packet */
@@ -2017,8 +2047,7 @@
 			lp->in_txhandler++;
 			lp->sending--;
 			
-			BUGLVL(D_DURING)
-				printk("arcnet: TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
+			BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
 					status,out->numsegs,out->segnum,out->skb);
 					
 #ifdef VERIFY_ACK
@@ -2026,27 +2055,23 @@
 			{
 				if (lp->outgoing.lasttrans_dest != 0)
 				{
-					printk("arcnet: transmit was not acknowledged! (status=%Xh, dest=%d)\n",
-						status,
+					printk("%6s: transmit was not acknowledged! (status=%Xh, dest=%d)\n",
+						dev->name,status,
 						lp->outgoing.lasttrans_dest);
 					lp->stats.tx_errors++;
+					lp->stats.tx_carrier_errors++;
 				}
 				else
 				{
-					BUGLVL(D_DURING)
-						printk("arcnet: broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n",
+					BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n",
 							status,
 							lp->outgoing.lasttrans_dest);
 				}
 			}
 #endif
-					
 			/* send packet if there is one */
-			if (lp->txready)
-			{
-				arcnetAS_go_tx(dev);
-				didsomething++;
-			}
+			arcnet_go_tx(dev,0);
+			didsomething++;
 			
 			if (lp->intx)
 			{
@@ -2056,8 +2081,7 @@
 
 			if (!lp->outgoing.skb)
 			{
-				BUGLVL(D_DURING)
-					printk("arcnet: TX IRQ done: no split to continue.\n");
+				BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
 				
 				/* inform upper layers */
 				if (!lp->txready && IF_TBUSY)
@@ -2070,15 +2094,12 @@
 				continue;
 			}
 			
-			/*lp->stats.tx_packets++;*/
-			
 			/* if more than one segment, and not all segments
 			 * are done, then continue xmit.
 			 */
 			if (out->segnum<out->numsegs)
 				arcnetA_continue_tx(dev);
-			if (lp->txready && !lp->sending)
-				arcnetAS_go_tx(dev);
+			arcnet_go_tx(dev,0);
 
 			/* if segnum==numsegs, the transmission is finished;
 			 * free the skb.
@@ -2102,13 +2123,19 @@
 			
 			lp->in_txhandler--;
 		}
+		else if (lp->txready && !lp->sending && !lp->intx)
+		{
+			BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n",
+						status);
+			arcnet_go_tx(dev,0);
+			didsomething++;
+		}
 	} while (--boguscount && didsomething);
 
-	BUGLVL(D_DURING)
-		printk("arcnet: net_interrupt complete (status=%Xh, count=%d)\n\n",
+	BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n\n",
 			inb(STATUS),boguscount);
 
-	if (dev->start && lp->sending)
+	if (dev->start && (lp->sending || (lp->txready && !lp->intx)))
 		outb(NORXflag|TXFREEflag|RECON_flag,INTMASK);
 	else
 		outb(NORXflag|RECON_flag,INTMASK);
@@ -2145,6 +2172,8 @@
 	u_char *arcsoft;
 	short length,offset;
 	u_char daddr,saddr;
+	
+	lp->stats.rx_packets++;
 
 	saddr=arcpacket->hardheader.source;
 	daddr=arcpacket->hardheader.destination;
@@ -2152,8 +2181,8 @@
 	/* if source is 0, it's a "used" packet! */
 	if (saddr==0)
 	{
-		printk("arcnet: discarding old packet. (status=%Xh)\n",
-			inb(STATUS));
+		printk("%6s: discarding old packet. (status=%Xh)\n",
+			dev->name,inb(STATUS));
 		lp->stats.rx_errors++;
 		return;
 	}
@@ -2173,8 +2202,7 @@
 		length=512-offset;
 	}
 	
-       	BUGLVL(D_DURING)
-		printk("arcnet: received packet from %02Xh to %02Xh (%d bytes)\n",
+       	BUGMSG(D_DURING,"received packet from %02Xh to %02Xh (%d bytes)\n",
        			saddr,daddr,length);
 
 	/* call the right receiver for the protocol */
@@ -2194,8 +2222,10 @@
 		arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr);
 		break;
 	default:
-		printk("arcnet: received unknown protocol %d (%Xh)\n",
-			arcsoft[0],arcsoft[0]);
+		printk("%6s: received unknown protocol %d (%Xh)\n",
+			dev->name,arcsoft[0],arcsoft[0]);
+		lp->stats.rx_errors++;
+		lp->stats.rx_crc_errors++;
 		break;
 	}
 
@@ -2203,7 +2233,7 @@
 	{
         	int countx,county;
         	
-        	printk("arcnet: packet dump [rx] follows:");
+        	printk("%6s: packet dump [rx] follows:",dev->name);
 
        		for (county=0; county<16+(length>240)*16; county++)
        		{
@@ -2239,8 +2269,7 @@
 	struct sk_buff *skb;
 	struct ClientData *arcsoft,*soft;
 	
-	BUGLVL(D_DURING)
-		printk("arcnet: it's an RFC1201 packet (length=%d)\n",
+	BUGMSG(D_DURING,"it's an RFC1201 packet (length=%d)\n",
 			length);
 			
 	/* compensate for EXTRA_CLIENTDATA (which isn't actually in the
@@ -2251,8 +2280,7 @@
 
 	if (arcsoft->split_flag==0xFF)  /* Exception Packet */
 	{
-		BUGLVL(D_DURING)
-			printk("arcnet: compensating for exception packet\n");
+		BUGMSG(D_DURING,"compensating for exception packet\n");
 
 		/* skip over 4-byte junkola */
 		arcsoft=(struct ClientData *)
@@ -2264,17 +2292,17 @@
 	{
 		struct Incoming *in=&lp->incoming[saddr];
 
-		BUGLVL(D_RX) printk("arcnet: incoming is not split (splitflag=%d)\n",
+		BUGMSG(D_RX,"incoming is not split (splitflag=%d)\n",
 			arcsoft->split_flag);
 			
 		if (in->skb)	/* already assembling one! */
         	{
-        		BUGLVL(D_EXTRA) printk("arcnet: aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
+        		BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
         			in->sequence,arcsoft->split_flag,
         			arcsoft->sequence);
         		kfree_skb(in->skb,FREE_WRITE);
-			lp->stats.tx_dropped++;
-        		lp->stats.rx_errors++;
+			lp->stats.rx_errors++;
+        		lp->stats.rx_missed_errors++;
         		in->skb=NULL;
         	}
         	
@@ -2282,7 +2310,8 @@
 
          	skb = alloc_skb(length, GFP_ATOMIC);
          	if (skb == NULL) {
-         		printk("arcnet: Memory squeeze, dropping packet.\n");
+         		printk("%6s: Memory squeeze, dropping packet.\n",
+         			dev->name);
          		lp->stats.rx_dropped++;
          		return;
          	}
@@ -2314,22 +2343,23 @@
          			
          			if (!*cptr)	/* is saddr = 00? */
          			{
-         				BUGLVL(D_EXTRA)
-         					printk("arcnet: ARP source address was 00h, set to %02Xh.\n",
+         				BUGMSG(D_EXTRA,"ARP source address was 00h, set to %02Xh.\n",
          						saddr);
+         				lp->stats.rx_crc_errors++;
          				*cptr=saddr;
          			}
-         			else BUGLVL(D_DURING) 
+         			else
          			{
-         				printk("arcnet: ARP source address (%Xh) is fine.\n",
+         				BUGMSG(D_DURING,"ARP source address (%Xh) is fine.\n",
          					*cptr);
          			}
          		}
          		else
          		{
-         			printk("arcnet: funny-shaped ARP packet. (%Xh, %Xh)\n",
-         				arp->ar_hln,arp->ar_pln);
-         			lp->stats.rx_frame_errors++;
+         			printk("%6s: funny-shaped ARP packet. (%Xh, %Xh)\n",
+         				dev->name,arp->ar_hln,arp->ar_pln);
+         			lp->stats.rx_errors++;
+         			lp->stats.rx_crc_errors++;
          		}
          	}
          	
@@ -2349,7 +2379,6 @@
 		#endif
 
          	netif_rx(skb);
-         	lp->stats.rx_packets++;
          }
          else			/* split packet */
          {
@@ -2372,32 +2401,32 @@
 	          
 	        struct Incoming *in=&lp->incoming[saddr];
 	        
-	        BUGLVL(D_RX) printk("arcnet: packet is split (splitflag=%d, seq=%d)\n",
+	        BUGMSG(D_RX,"packet is split (splitflag=%d, seq=%d)\n",
 	        	arcsoft->split_flag,in->sequence);
 
 		if (in->skb && in->sequence!=arcsoft->sequence)
 		{
-			BUGLVL(D_EXTRA) printk("arcnet: wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n",	
+			BUGMSG(D_EXTRA,"wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n",	
 				in->sequence,arcsoft->sequence,
 				arcsoft->split_flag);
 	        	kfree_skb(in->skb,FREE_WRITE);
 	        	in->skb=NULL;
-			lp->stats.tx_dropped++;
-	        	lp->stats.rx_fifo_errors++;
+			lp->stats.rx_errors++;
+	        	lp->stats.rx_missed_errors++;
 	        	in->lastpacket=in->numpackets=0;
 	        }
 	          
 	        if (arcsoft->split_flag & 1)	/* first packet in split */
 	        {
-	        	BUGLVL(D_RX) printk("arcnet: brand new splitpacket (splitflag=%d)\n",
+	        	BUGMSG(D_RX,"brand new splitpacket (splitflag=%d)\n",
 	        		arcsoft->split_flag);
 	        	if (in->skb)	/* already assembling one! */
 	        	{
-	        		BUGLVL(D_EXTRA) printk("arcnet: aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
+	        		BUGMSG(D_EXTRA,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
 	        			in->sequence,arcsoft->split_flag,
 	        			arcsoft->sequence);
-				lp->stats.tx_dropped++;
-	        		lp->stats.rx_over_errors++;
+				lp->stats.rx_errors++;
+	        		lp->stats.rx_missed_errors++;
 	        		kfree_skb(in->skb,FREE_WRITE);
 	        	}
 
@@ -2407,9 +2436,10 @@
 	        	
 	        	if (in->numpackets>16)
 	        	{
-	        		BUGLVL(D_EXTRA) printk("arcnet: incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
+	        		BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
 	        			arcsoft->split_flag);
-	        		lp->stats.rx_dropped++;
+	        		lp->stats.rx_errors++;
+	        		lp->stats.rx_length_errors++;
 	        		return;
 	        	}
 	        
@@ -2417,7 +2447,7 @@
                 			+ sizeof(struct ClientData),
 	                		GFP_ATOMIC);
                 	if (skb == NULL) {
-                		printk("%s: (split) memory squeeze, dropping packet.\n", 
+                		printk("%6s: (split) memory squeeze, dropping packet.\n", 
                 			dev->name);
                 		lp->stats.rx_dropped++;
                 		return;
@@ -2447,9 +2477,10 @@
 			 */			
 			if (!in->skb)
 			{
-				BUGLVL(D_EXTRA) printk("arcnet: can't continue split without starting first! (splitflag=%d, seq=%d)\n",
+				BUGMSG(D_EXTRA,"can't continue split without starting first! (splitflag=%d, seq=%d)\n",
 					arcsoft->split_flag,arcsoft->sequence);
 				lp->stats.rx_errors++;
+				lp->stats.rx_missed_errors++;
 				return;
 			}
 
@@ -2459,19 +2490,21 @@
 				/* harmless duplicate? ignore. */
 				if (packetnum<=in->lastpacket-1)
 				{
-					BUGLVL(D_EXTRA) printk("arcnet: duplicate splitpacket ignored! (splitflag=%d)\n",
+					BUGMSG(D_EXTRA,"duplicate splitpacket ignored! (splitflag=%d)\n",
 						arcsoft->split_flag);
+					lp->stats.rx_errors++;
+					lp->stats.rx_frame_errors++;
 					return;
 				}
 				
 				/* "bad" duplicate, kill reassembly */
-				BUGLVL(D_EXTRA) printk("arcnet: out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",	
+				BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",	
 					in->sequence,arcsoft->split_flag,
 					arcsoft->sequence);
 	        		kfree_skb(in->skb,FREE_WRITE);
 	        		in->skb=NULL;
-				lp->stats.tx_dropped++;
-	        		lp->stats.rx_fifo_errors++;
+				lp->stats.rx_errors++;
+	        		lp->stats.rx_missed_errors++;
 	        		in->lastpacket=in->numpackets=0;
 	        		return;
 	        	}
@@ -2494,29 +2527,33 @@
          	if (in->lastpacket == in->numpackets)
          	{
          		if (!skb || !in->skb)
-         			printk("arcnet: ?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
-         				skb,in->skb);
-         		in->skb=NULL;
-         		in->lastpacket=in->numpackets=0;
+         		{
+         			printk("%6s: ?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
+         				dev->name,skb,in->skb);
+         		}
+         		else
+         		{
+	         		in->skb=NULL;
+        	 		in->lastpacket=in->numpackets=0;
 			
-			BUGLVL(D_SKB)
-			{
-	        	    short i;
-	        	       	for(i=0; i<skb->len; i++)
-               			{
-                	       		if( i%16 == 0 ) printk("\n[%04hX] ",i);
-                	       		printk("%02hX ",((unsigned char*)skb->data)[i]);
-               			}
-               			printk("\n");
-            		}
+				BUGLVL(D_SKB)
+				{
+		        	    short i;
+		        	       	for(i=0; i<skb->len; i++)
+               				{
+                		       		if( i%16 == 0 ) printk("\n[%04hX] ",i);
+                	       			printk("%02hX ",((unsigned char*)skb->data)[i]);
+	               			}
+        	       			printk("\n");
+	            		}
 
 			
-			#ifndef LINUX12
-			skb->protocol=arcnetA_type_trans(skb,dev);
-			#endif
+				#ifndef LINUX12
+				skb->protocol=arcnetA_type_trans(skb,dev);
+				#endif
 				
-	         	netif_rx(skb);
-        	 	lp->stats.rx_packets++;
+	         		netif_rx(skb);
+	         	}
         	}
          }
 }
@@ -2531,13 +2568,12 @@
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
 	struct sk_buff *skb;
 	
-	BUGLVL(D_DURING)
-		printk("arcnet: it's an ethernet-encap packet (length=%d)\n",
+	BUGMSG(D_DURING,"it's an ethernet-encap packet (length=%d)\n",
 			length);
 
        	skb = alloc_skb(length, GFP_ATOMIC);
        	if (skb == NULL) {
-       		printk("arcnet: Memory squeeze, dropping packet.\n");
+       		printk("%6s: Memory squeeze, dropping packet.\n",dev->name);
        		lp->stats.rx_dropped++;
        		return;
        	}
@@ -2550,7 +2586,7 @@
         BUGLVL(D_SKB)
         {
 		short i;
-		printk("arcnet: rx skb dump follows:\n");
+		printk("%6s: rx skb dump follows:\n",dev->name);
                 for(i=0; i<skb->len; i++)
                 {
 			if (i%16==0)
@@ -2566,7 +2602,6 @@
 	#endif
         
         netif_rx(skb);
-        lp->stats.rx_packets++;
 }
 
 /* Packet receiver for RFC1051 packets; 
@@ -2582,8 +2617,7 @@
 	arcsoft=(struct S_ClientData *)(buf-S_EXTRA_CLIENTDATA);
 	length+=S_EXTRA_CLIENTDATA;
 	
-	BUGLVL(D_DURING)
-		printk("arcnetS: it's an RFC1051 packet (length=%d)\n",
+	BUGMSG(D_DURING,"it's an RFC1051 packet (length=%d)\n",
 			length);
 			
 	
@@ -2625,7 +2659,6 @@
 		#endif
 
          	netif_rx(skb);
-         	lp->stats.rx_packets++;
          }
 }
 
@@ -2659,7 +2692,7 @@
 static void
 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
-#if 0	  /* no promiscuous mode at all on most ARCnet models */
+#if 0	  /* no promiscuous mode at all on most (all?) ARCnet models */
 	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
 
 	short ioaddr = dev->base_addr;
@@ -2690,10 +2723,9 @@
 #else
 		skb_push(skb,dev->hard_header_len);
 #endif
-/*	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);*/
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
 
-	BUGLVL(D_DURING)
-		printk("arcnetA: create header from %d to %d; protocol %d (%Xh); size %u.\n",
+	BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n",
 			saddr ? *(u_char*)saddr : -1,
 			daddr ? *(u_char*)daddr : -1,
 			type,type,len);
@@ -2711,14 +2743,18 @@
 		head->protocol_id=ARC_P_RARP;
 		break;
 	case ETH_P_IPX:
+	case ETH_P_802_3:
+	case ETH_P_802_2:
 		head->protocol_id=ARC_P_IPX;
 		break;
 	case ETH_P_ATALK:
 		head->protocol_id=ARC_P_ATALK;
 		break;
 	default:
-		printk("arcnet: I don't understand protocol %d (%Xh)\n",
-			type,type);
+		printk("%6s: I don't understand protocol %d (%Xh)\n",
+			dev->name,type,type);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
 		return 0;
 	}	
 
@@ -2771,24 +2807,24 @@
 #else
 		skb_push(skb,dev->hard_header_len);
 #endif
-/*	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);*/
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
 
 	/* set the protocol ID according to RFC1051 */
 	switch(type)
 	{
 	case ETH_P_IP:
 		head->protocol_id=ARC_P_IP_RFC1051;
-		BUGLVL(D_DURING)
-			printk("arcnetS: S_header: IP_RFC1051 packet.\n");
+		BUGMSG(D_DURING,"S_header: IP_RFC1051 packet.\n");
 		break;
 	case ETH_P_ARP:
 		head->protocol_id=ARC_P_ARP_RFC1051;
-		BUGLVL(D_DURING)
-			printk("arcnetS: S_header: ARP_RFC1051 packet.\n");
+		BUGMSG(D_DURING,"S_header: ARP_RFC1051 packet.\n");
 		break;
 	default:
 		printk("arcnetS: I don't understand protocol %d (%Xh)\n",
 			type,type);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
 		return 0;
 	}	
 
@@ -2827,6 +2863,7 @@
 		struct sk_buff *skb)
 {
 	struct ClientData *head = (struct ClientData *)buff;
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
 	int status;
 
 	/*
@@ -2835,8 +2872,10 @@
 	 
 	if(head->protocol_id != ARC_P_IP) 
 	{
-		printk("arcnet: I don't understand protocol type %d (%Xh) addresses!\n",
-			head->protocol_id,head->protocol_id);
+		printk("%6s: I don't understand protocol type %d (%Xh) addresses!\n",
+			dev->name,head->protocol_id,head->protocol_id);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
 		head->daddr=0;
 		/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
 		return 0;
@@ -2846,12 +2885,10 @@
 	 * Try and get ARP to resolve the header.
 	 */
 #ifdef CONFIG_INET	 
-	BUGLVL(D_DURING)
-		printk("arcnetA: rebuild header from %d to %d; protocol %Xh\n",
+	BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n",
 			head->saddr,head->daddr,head->protocol_id);
 	status=arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0;
-	BUGLVL(D_DURING)
-		printk("arcnetA:   rebuilt: from %d to %d; protocol %Xh\n",
+	BUGMSG(D_DURING," rebuilt: from %d to %d; protocol %Xh\n",
 			head->saddr,head->daddr,head->protocol_id);
 	return status;
 #else
@@ -2864,6 +2901,7 @@
 		struct sk_buff *skb)
 {
 	struct S_ClientData *head = (struct S_ClientData *)buff;
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
 
 	/*
 	 * Only ARP and IP are currently supported
@@ -2873,6 +2911,8 @@
 	{
 		printk("arcnetS: I don't understand protocol type %d (%Xh) addresses!\n",
 			head->protocol_id,head->protocol_id);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
 		head->daddr=0;
 		/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
 		return 0;
@@ -2922,14 +2962,14 @@
 	case ARC_P_IP:		return htons(ETH_P_IP);
 	case ARC_P_ARP:		return htons(ETH_P_ARP);
 	case ARC_P_RARP:	return htons(ETH_P_RARP);
-	case ARC_P_IPX:		return htons(ETH_P_IPX);
+	case ARC_P_IPX:		return htons(ETH_P_802_3);
 	case ARC_P_ATALK:   return htons(ETH_P_ATALK); /* untested appletalk */
 	case ARC_P_LANSOFT: /* don't understand.  fall through. */
 	default:
-		BUGLVL(D_EXTRA)
-			printk("arcnet: received packet of unknown protocol id %d (%Xh)\n",
+		BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n",
 				head->protocol_id,head->protocol_id);
-		lp->stats.rx_frame_errors++;
+		lp->stats.rx_errors++;
+		lp->stats.rx_crc_errors++;
 		return 0;
 	}
 
@@ -2943,7 +2983,7 @@
 	struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
 
 #ifdef LINUX12
-	head=(struct ClientData *)skb->data;
+	head=(struct S_ClientData *)skb->data;
 #else
 	/* Pull off the arcnet header. */
 	skb->mac.raw=skb->data;
@@ -2966,10 +3006,10 @@
 	case ARC_P_IP_RFC1051:	return htons(ETH_P_IP);
 	case ARC_P_ARP_RFC1051:	return htons(ETH_P_ARP);
 	default:
-		BUGLVL(D_EXTRA)
-			printk("arcnetS: received packet of unknown protocol id %d (%Xh)\n",
+		BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n",
 				head->protocol_id,head->protocol_id);
-		lp->stats.rx_frame_errors++;
+		lp->stats.rx_errors++;
+		lp->stats.rx_crc_errors++;
 		return 0;
 	}
 
diff -u --recursive --new-file v1.3.40/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v1.3.40/linux/drivers/net/eth16i.c	Sat Nov 11 17:41:33 1995
+++ linux/drivers/net/eth16i.c	Mon Nov 13 08:53:49 1995
@@ -1170,7 +1170,6 @@
 }
 
 #ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
 static char devicename[9] = { 0, };
 static struct device dev_eth16i = {
 	devicename,
diff -u --recursive --new-file v1.3.40/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v1.3.40/linux/drivers/pci/pci.c	Wed Nov  8 07:11:33 1995
+++ linux/drivers/pci/pci.c	Mon Nov 13 08:03:45 1995
@@ -168,8 +168,9 @@
 	DEVICE( ADAPTEC,	ADAPTEC_7870,	"AIC-7870"),
 	DEVICE( ADAPTEC,	ADAPTEC_7871,	"AIC-7871"),
 	DEVICE( ADAPTEC,	ADAPTEC_7872,	"AIC-7872"),
-	DEVICE( ADAPTEC,	ADAPTEC_7880,	"AIC-7880"),
-	DEVICE( ADAPTEC,	ADAPTEC_7881,	"AIC-7881"),
+	DEVICE( ADAPTEC,	ADAPTEC_7880,	"AIC-7880U"),
+	DEVICE( ADAPTEC,	ADAPTEC_7881,	"AIC-7881U"),
+	DEVICE( ADAPTEC,	ADAPTEC_7882,	"AIC-7882U"),
   	DEVICE( ATRONICS,	ATRONICS_2015,	"IDE-2015PL"),
 	DEVICE( HER,		HER_STING,	"Stingray"),
 	DEVICE( HER,		HER_STINGARK,	"Stingray ARK 2000PV")
diff -u --recursive --new-file v1.3.40/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v1.3.40/linux/drivers/scsi/aic7xxx.c	Wed Nov  8 07:11:34 1995
+++ linux/drivers/scsi/aic7xxx.c	Mon Nov 13 08:03:45 1995
@@ -41,7 +41,7 @@
  *
  *    -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 04/03/95
  *
- *  $Id: aic7xxx.c,v 2.5 1995/09/20 05:18:18 deang Exp $
+ *  $Id: aic7xxx.c,v 2.10 1995/11/10 10:49:14 deang Exp $
  *-M*************************************************************************/
 
 #ifdef MODULE
@@ -73,7 +73,7 @@
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 2.5 $"
+#define AIC7XXX_C_VERSION  "$Revision: 2.10 $"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        ((a < b) ? a : b)
@@ -163,7 +163,7 @@
  * Define this to use polling rather than using kernel support for waking
  * up a waiting process.
  */
-#undef AIC7XXX_POLL
+#define AIC7XXX_POLL
 
 /*
  * Controller type and options
@@ -172,9 +172,11 @@
   AIC_NONE,
   AIC_274x,    /* EISA aic7770 */
   AIC_284x,    /* VLB  aic7770 */
-  AIC_7870,    /* PCI  aic7870 */
+  AIC_7870,    /* PCI  aic7870/aic7871 motherboard or 294x */
   AIC_7850,    /* PCI  aic7850 */
-  AIC_7872     /* PCI  aic7870 on 394x */
+  AIC_7872,    /* PCI  aic7870 on 394x */
+  AIC_7880,    /* PCI  aic7880/aic7881 motherboard or 294x Ultra */
+  AIC_7882,    /* PCI  aic7870 on 394x Ultra */
 } aha_type;
 
 typedef enum {
@@ -247,6 +249,21 @@
 #define		ENAUTOATNP	0x02
 #define		SCSIRSTO	0x01
 
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+#define	SXFRCTL0(x)		((x) + 0xC01ul)
+#define		DFON		0x80
+#define		DFPEXP		0x40
+#define		ULTRAEN		0x20
+#define		CLRSTCNT	0x10
+#define		SPIOEN		0x08
+#define		SCAMEN		0x04
+#define		CLRCHN		0x02
+/*  UNUSED			0x01 */
+
 /*
  * SCSI Transfer Control 1 Register (pp. 3-14,15).
  * Controls the SCSI module data path.
@@ -395,28 +412,6 @@
 /*  UNUSED			0x07 */
 
 /*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device.  In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device.  When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM.  When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.  See aic7xxx_read_eprom for detailed information on
- * the protocol necessary to read the serial EEPROM.
- */
-#define SEECTL(x)		((x) + 0xC1Eul)
-#define		EXTARBACK	0x80
-#define		EXTARBREQ	0x40
-#define		SEEMS		0x20
-#define		SEERDY		0x10
-#define		SEECS		0x08
-#define		SEECK		0x04
-#define		SEEDO		0x02
-#define		SEEDI		0x01
-
-/*
  * SCSI Block Control (p. 3-32)
  * Controls Bus type and channel selection. In a twin channel configuration
  * addresses 0x00-0x1E are gated to the appropriate channel based on this
@@ -425,8 +420,11 @@
  */
 #define SBLKCTL(x)		((x) + 0xC1Ful)
 /*  UNUSED			0xC0 */
+#define		DIAGLEDEN	0x80
+#define		DIAGLEDON	0x40
 #define		AUTOFLUSHDIS	0x20		/* used for Rev C check */
 /*  UNUSED			0x10 */
+#define		SELBUS_MASK	0x0F
 #define		SELBUSB		0x08
 /*  UNUSED			0x04 */
 #define		SELWIDE		0x02
@@ -503,7 +501,7 @@
 #define		PAUSE		0x04
 #define		INTEN		0x02
 #define		CHIPRST		0x01
-#define		REQ_PAUSE	IRQMS | PAUSE | INTEN
+#define		REQ_PAUSE	IRQMS | INTEN | PAUSE
 #define		UNPAUSE_274X	IRQMS | INTEN
 #define		UNPAUSE_284X	INTEN
 #define		UNPAUSE_294X	IRQMS | INTEN
@@ -603,11 +601,64 @@
 
 /* ---------------- END AIC-7770 Register Definitions ----------------- */
 
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+#define SEECTL_2840(x)		((x) + 0xCC0ul)
+/*    UNUSED			0xF8 */
+#define		CS_2840		0x04
+#define		CK_2840		0x02
+#define		DO_2840		0x01
+
+#define STATUS_2840(x)		((x) + 0xCC1ul)
+#define		EEPROM_TF	0x80
+#define		BIOS_SEL	0x60
+#define		ADSEL		0x1E
+#define		DI_2840		0x01
+
 /* --------------------- AIC-7870-only definitions -------------------- */
 
 #define DSPCISTATUS(x)	 	((x) + 0xC86ul)
 #define 	DFTHRESH        0xC0
 
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  See aic7xxx_read_eprom for detailed information on
+ * the protocol necessary to read the serial EEPROM.
+ */
+#define SEECTL(x)		((x) + 0xC1Eul)
+#define		EXTARBACK	0x80
+#define		EXTARBREQ	0x40
+#define		SEEMS		0x20
+#define		SEERDY		0x10
+#define		SEECS		0x08
+#define		SEECK		0x04
+#define		SEEDO		0x02
+#define		SEEDI		0x01
+
+#define DEVREVID  		0x08ul
+
+#define	DEVSTATUS		0x40ul
+#define		MPORTMODE	0x04	/* aic7870 only */
+#define		RAMPSM		0x02	/* aic7870 only */
+#define		VOLSENSE	0x01
+
+#define	DEVCONFIG		0x41ul
+#define		SCBRAMSEL	0x80
+#define		MRDCEN		0x40
+#define		EXTSCBTIME	0x20	/* aic7870 only */
+#define		EXTSCBPEN	0x10	/* aic7870 only */
+#define		BERREN		0x08
+#define		DACEN		0x04
+#define		STPWLEVEL	0x02
+#define		DIFACTNEGEN	0x01	/* aic7870 only */
+
 /* Scratch RAM offset definitions */
 
 /* ---------------------- Scratch RAM Offsets ------------------------- */
@@ -726,9 +777,10 @@
 /*
  * Host Adapter Control Bits
  */
-/* UNUSED		0x0003 */
-#define CFWSTERM	0x0008		/* SCSI high byte termination (wide card) */
-#define CFSTERM		0x0004		/* SCSI low byte termination (non-wide cards) */
+/* UNUSED               0x0001 */
+#define CFULTRAEN       0x0002          /* Ultra SCSI speed enable (Ultra cards) */
+#define CFSTERM         0x0004          /* SCSI low byte termination (non-wide cards) */
+#define CFWSTERM        0x0008          /* SCSI high byte termination (wide card) */
 #define CFSPARITY	0x0010		/* SCSI parity */
 /* UNUSED		0x0020 */
 #define CFRESETB	0x0040		/* reset SCSI bus at IC initialization */
@@ -780,7 +832,7 @@
  */
 #define RESTART_SEQUENCER(p) \
   do {							\
-    outb(SEQRESET | FASTMODE, SEQCTL(p->base));	\
+    outb(SEQRESET | FASTMODE, SEQCTL(p->base));		\
   } while (inb(SEQADDR0(p->base)) != 0 &&		\
 	   inb(SEQADDR1(p->base)) != 0);		\
   UNPAUSE_SEQUENCER(p);
@@ -905,13 +957,13 @@
 	/*-----------------end of hardware supported fields----------------*/
 	struct aic7xxx_scb *next;	/* next ptr when in free list */
 	Scsi_Cmnd          *cmd;	/* Scsi_Cmnd for this scb */
-	int                 state;	/* current state of scb */
 #define SCB_FREE               0x00
 #define SCB_ACTIVE             0x01
 #define SCB_ABORTED            0x02
 #define SCB_DEVICE_RESET       0x04
 #define SCB_IMMED              0x08
 #define SCB_SENSE              0x10
+	int                 state;          /* current state of scb */
 	unsigned int        position;       /* Position in scb array */
 	struct scatterlist  sg;
 	struct scatterlist  sense_sg;
@@ -947,7 +999,7 @@
  * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
  * SEQUENCER CODE IF THIS IS MODIFIED!
  */
-#define AIC7XXX_MAXSCB	16
+#define AIC7XXX_MAXSCB	255
 
 /*
  * Define a structure used for each host adapter, only one per IRQ.
@@ -958,6 +1010,8 @@
   int                      numscb;           /* current number of scbs */
   int                      extended;         /* extended xlate? */
   aha_type                 type;             /* card type */
+  int                      ultra_enabled;    /* Ultra SCSI speed enabled */
+  int                      chan_num;         /* for 3940/3985, channel number */
   aha_bus_type             bus_type;         /* normal/twin/wide bus */
   unsigned char            a_scanned;        /* 0 not scanned, 1 scanned */
   unsigned char            b_scanned;        /* 0 not scanned, 1 scanned */
@@ -1010,7 +1064,10 @@
   int              scsi_id_b;  /* host SCSI ID B channel for twin cards */
   int              extended;   /* extended xlate? */
   int              busrtime;   /* bus release time */
+  int              walk_scbs;  /* external SCB RAM detected; walk the scb array */
   aha_type         type;       /* card type */
+  int              ultra_enabled;    /* Ultra SCSI speed enabled */
+  int              chan_num;   /* for 3940/3985, channel number */
   aha_bus_type     bus_type;   /* normal/twin/wide bus */
   aha_status_type  parity;     /* bus parity enabled/disabled */
   aha_status_type  low_term;   /* bus termination low byte */
@@ -1024,22 +1081,30 @@
  */
 static struct {
   short period;
+  /* Rates in Ultra mode have bit 8 of sxfr set */
+#define		ULTRA_SXFR 0x100
   short rate;
   const char *english;
 } aic7xxx_syncrates[] = {
-  { 100,   0,  "10.0" },
-  { 125,   1,  "8.0"  },
-  { 150,   2,  "6.67" },
-  { 175,   3,  "5.7"  },
-  { 200,   4,  "5.0"  },
-  { 225,   5,  "4.4"  },
-  { 250,   6,  "4.0"  },
-  { 275,   7,  "3.6"  }
+  {  50,  0x100,  "20.0" },
+  {  62,  0x110,  "16.0" },
+  {  75,  0x120,  "13.4" },
+  { 100,  0x140,  "10.0" },
+  { 100,  0x000,  "10.0" },
+  { 125,  0x010,  "8.0"  },
+  { 150,  0x020,  "6.67" },
+  { 175,  0x030,  "5.7"  },
+  { 200,  0x040,  "5.0"  },
+  { 225,  0x050,  "4.4"  },
+  { 250,  0x060,  "4.0"  },
+  { 275,  0x070,  "3.6"  }
 };
 
 static int num_aic7xxx_syncrates =
     sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
 
+static int number_of_3940s = 0;
+
 #ifdef AIC7XXX_DEBUG
 
 static void
@@ -1101,7 +1166,7 @@
       break;
 
     case AIC_7870:
-      printk("AIC7870%s (PCI-bus):\n", BUSW[p->bus_type]);
+      printk("AIC7870/7871%s (PCI-bus):\n", BUSW[p->bus_type]);
       break;
 
     case AIC_7850:
@@ -1112,6 +1177,14 @@
       printk("AIC7872%s (PCI-bus):\n", BUSW[p->bus_type]);
       break;
 
+    case AIC_7880:
+      printk("AIC7880/7881%s (PCI-bus):\n", BUSW[p->bus_type]);
+      break;
+
+    case AIC_7882:
+      printk("AIC7882%s (PCI-bus):\n", BUSW[p->bus_type]);
+      break;
+
     default:
       panic("aic7xxx debug_config: internal error\n");
   }
@@ -1160,6 +1233,7 @@
   }
 }
 
+#if 0
 static void
 debug_scb(struct aic7xxx_scb *scb)
 {
@@ -1183,6 +1257,7 @@
          (unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
          scb->position);
 }
+#endif
 
 #else
 #  define debug(fmt, args...)
@@ -1195,38 +1270,48 @@
  *       cards in the system. This should be fixed, but then,
  *       does anyone really have more than one in a machine?
  */
-static int aic7xxx_extended = 0;	/* extended translation on? */
-static int aic7xxx_no_reset = 0;	/* no resetting of SCSI bus */
+static unsigned int aic7xxx_extended = 0;    /* extended translation on? */
+static unsigned int aic7xxx_no_reset = 0;    /* no resetting of SCSI bus */
 
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_setup
  *
  * Description:
- *   Handle Linux boot parameters.
+ *   Handle Linux boot parameters. This routine allows for assigning a value
+ *   to a parameter with a ':' between the parameter and the value.
+ *   ie. aic7xxx=unpause:0x0A,extended
  *-F*************************************************************************/
 void
 aic7xxx_setup(char *s, int *dummy)
 {
-  int   i;
+  int   i, n;
   char *p;
 
   static struct {
     const char *name;
-    int *flag;
+    unsigned int *flag;
   } options[] = {
     { "extended",    &aic7xxx_extended },
     { "no_reset",    &aic7xxx_no_reset },
-    { NULL,          NULL}
+    { NULL,          NULL }
   };
 
   for (p = strtok(s, ","); p; p = strtok(NULL, ","))
   {
     for (i = 0; options[i].name; i++)
     {
-      if (!strcmp(options[i].name, p))
+      n = strlen(options[i].name);
+      if (!strncmp(options[i].name, p, n))
       {
-	*(options[i].flag) = !0;
+        if (p[n] == ':')
+        {
+          *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+        }
+        else
+        {
+          *(options[i].flag) = !0;
+        }
       }
     }
   }
@@ -1532,8 +1617,9 @@
  *   Look up the valid period to SCSIRATE conversion in our table
  *-F*************************************************************************/
 static void
-aic7xxx_scsirate(unsigned char *scsirate, unsigned char period,
-		 unsigned char offset, int target, char channel)
+aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
+                 unsigned char period, unsigned char offset,
+                 int target, char channel)
 {
   int i;
 
@@ -1541,8 +1627,38 @@
   {
     if ((aic7xxx_syncrates[i].period - period) >= 0)
     {
-      *scsirate = (aic7xxx_syncrates[i].rate << 4) | (offset & 0x0F);
-      printk("aic7xxx: target %d, channel %c, now synchronous at %sMb/s, "
+      /*
+       * Watch out for Ultra speeds when ultra is not enabled and
+       * vice-versa.
+       */
+      if (p->ultra_enabled)
+      {
+        if (! (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+        {
+          printk ("aic7xxx: target %d, channel %c, requests %sMB/s transfers, "
+                  "but adapter in Ultra mode can only sync at 10MB/s or "
+                  "above.\n", target, channel, aic7xxx_syncrates[i].english);
+          break;  /* Use asynchronous transfers. */
+        }
+      }
+      else
+      {
+        /*
+         * Check for an Ultra device trying to negotiate an Ultra rate
+         * on an adapter with Ultra mode disabled.
+         */
+        if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
+        {
+          /*
+           * This should only happen if the driver is the first to negotiate
+           * and chooses a high rate.  We'll just move down the table until
+           * we hit a non Ultra speed.
+           */
+           continue;
+        }
+      }
+      *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
+      printk("aic7xxx: target %d, channel %c, now synchronous at %sMB/s, "
              "offset = 0x%x\n",
 	     target, channel, aic7xxx_syncrates[i].english, offset);
       return;
@@ -2079,6 +2195,7 @@
     outb(sblkctl ^ SELBUSB, SBLKCTL(base));
     aic7xxx_reset_current_bus(base);
     outb(sblkctl, SBLKCTL(base));
+
     UNPAUSE_SEQUENCER(p);
   }
   /*
@@ -2280,7 +2397,7 @@
 	{
 	  max_offset = 0x0F;
 	}
-	aic7xxx_scsirate(&rate, transfer, MIN(offset, max_offset), scsi_id, channel);
+	aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset), scsi_id, channel);
 	/*
 	 * Preserve the wide transfer flag.
 	 */
@@ -3004,6 +3121,152 @@
 
 /*+F*************************************************************************
  * Function:
+ *   read_2840_seeprom
+ *
+ * Description:
+ *   Reads the 2840 serial EEPROM and returns 1 if successful and 0 if
+ *   not successful.
+ *
+ *   See read_seeprom (for the 2940) for the instruction set of the 93C46
+ *   chip.
+ *
+ *   The 2840 interface to the 93C46 serial EEPROM is through the
+ *   STATUS_2840 and SEECTL_2840 registers.  The CS_2840, CK_2840, and
+ *   DO_2840 bits of the SEECTL_2840 register are connected to the chip
+ *   select, clock, and data out lines respectively of the serial EEPROM.
+ *   The DI_2840 bit of the STATUS_2840 is connected to the data in line
+ *   of the serial EEPROM.  The EEPROM_TF bit of STATUS_2840 register is
+ *   useful in that it gives us an 800 nsec timer.  After a read from the
+ *   SEECTL_2840 register the timing flag is cleard and goes high 800 nsec
+ *   later.
+ *
+ *-F*************************************************************************/
+static int
+read_2840_seeprom(int base, struct seeprom_config *sc)
+{
+  int i = 0, k = 0;
+  unsigned char temp;
+  unsigned short checksum = 0;
+  unsigned short *seeprom = (unsigned short *) sc;
+  struct seeprom_cmd {
+    unsigned char len;
+    unsigned char bits[3];
+  };
+  struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
+
+#define CLOCK_PULSE(p) \
+  while ((inb(STATUS_2840(base)) & EEPROM_TF) == 0)	\
+  {						\
+    ;  /* Do nothing */				\
+  }						\
+  (void) inb(SEECTL_2840(base));
+
+  /*
+   * Read the first 32 registers of the seeprom.  For the 2840,
+   * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
+   * but only the first 32 are used by Adaptec BIOS.  The loop
+   * will range from 0 to 31.
+   */
+  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  {
+    /*
+     * Send chip select for one clock cycle.
+     */
+    outb(CK_2840 | CS_2840, SEECTL_2840(base));
+    CLOCK_PULSE(base);
+
+    /*
+     * Now we're ready to send the read command followed by the
+     * address of the 16-bit register we want to read.
+     */
+    for (i = 0; i < seeprom_read.len; i++)
+    {
+      temp = CS_2840 | seeprom_read.bits[i];
+      outb(temp, SEECTL_2840(base));
+      CLOCK_PULSE(base);
+      temp = temp ^ CK_2840;
+      outb(temp, SEECTL_2840(base));
+      CLOCK_PULSE(base);
+    }
+    /*
+     * Send the 6 bit address (MSB first, LSB last).
+     */
+    for (i = 5; i >= 0; i--)
+    {
+      temp = k;
+      temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
+      temp = CS_2840 | temp;
+      outb(temp, SEECTL_2840(base));
+      CLOCK_PULSE(base);
+      temp = temp ^ CK_2840;
+      outb(temp, SEECTL_2840(base));
+      CLOCK_PULSE(base);
+    }
+
+    /*
+     * Now read the 16 bit register.  An initial 0 precedes the
+     * register contents which begins with bit 15 (MSB) and ends
+     * with bit 0 (LSB).  The initial 0 will be shifted off the
+     * top of our word as we let the loop run from 0 to 16.
+     */
+    for (i = 0; i <= 16; i++)
+    {
+      temp = CS_2840;
+      outb(temp, SEECTL_2840(base));
+      CLOCK_PULSE(base);
+      temp = temp ^ CK_2840;
+      seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840(base)) & DI_2840);
+      outb(temp, SEECTL_2840(base));
+      CLOCK_PULSE(base);
+    }
+    /*
+     * The serial EEPROM has a checksum in the last word.  Keep a
+     * running checksum for all words read except for the last
+     * word.  We'll verify the checksum after all words have been
+     * read.
+     */
+    if (k < (sizeof(*sc) / 2) - 1)
+    {
+      checksum = checksum + seeprom[k];
+    }
+
+    /*
+     * Reset the chip select for the next command cycle.
+     */
+    outb(0, SEECTL_2840(base));
+    CLOCK_PULSE(base);
+    outb(CK_2840, SEECTL_2840(base));
+    CLOCK_PULSE(base);
+    outb(0, SEECTL_2840(base));
+    CLOCK_PULSE(base);
+  }
+
+#if 0
+  printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+  printk("Serial EEPROM:");
+  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  {
+    if (((k % 8) == 0) && (k != 0))
+    {
+      printk("\n              ");
+    }
+    printk(" 0x%x", seeprom[k]);
+  }
+  printk("\n");
+#endif
+
+  if (checksum != sc->checksum)
+  {
+    printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
+    return (0);
+  }
+
+  return (1);
+#undef CLOCK_PULSE
+}
+
+/*+F*************************************************************************
+ * Function:
  *   read_seeprom
  *
  * Description:
@@ -3052,9 +3315,9 @@
  *
  *-F*************************************************************************/
 static int
-read_seeprom(int base, struct seeprom_config *sc)
+read_seeprom(int base, int offset, struct seeprom_config *sc)
 {
-  int i = 0, k = 0;
+  int i = 0, k;
   unsigned long timeout;
   unsigned char temp;
   unsigned short checksum = 0;
@@ -3122,7 +3385,7 @@
      */
     for (i = 5; i >= 0; i--)
     {
-      temp = k;
+      temp = k + offset;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = SEEMS | SEECS | (temp << 1);
       outb(temp, SEECTL(base));
@@ -3197,6 +3460,7 @@
   }
 
   return (1);
+#undef CLOCK_PULSE
 }
 
 /*+F*************************************************************************
@@ -3207,10 +3471,10 @@
  *   Return the maximum number of SCB's allowed for a given controller.
  *-F*************************************************************************/
 static int
-detect_maxscb(aha_type type, int base)
+detect_maxscb(aha_type type, int base, int walk_scbs)
 {
-  unsigned char sblkctl_reg;
-  int maxscb = 0;
+  unsigned char sblkctl_reg, scb_byte;
+  int maxscb = 0, i;
 
   switch (type)
   {
@@ -3248,14 +3512,15 @@
       break;
 
     case AIC_7870:
+    case AIC_7880:
       maxscb = 16;
       break;
 
     case AIC_7872:
+    case AIC_7882:
       /*
-       * Really has 255, but we'll wait to verify that we access
-       * them the same way and do not have to set the card to
-       * use the memory port to access external SCB RAM.
+       * Is suppose to have 255 SCBs, but we'll walk the SCBs
+       * looking for more if external RAM is detected.
        */
       maxscb = 16;
       break;
@@ -3266,6 +3531,26 @@
        */
       break;
   }
+  if (walk_scbs)
+  {
+    /*
+     * This adapter has external SCB memory.
+     * Walk the SCBs to determine how many there are.
+     */
+    i = 0;
+    while (i < AIC7XXX_MAXSCB)
+    {
+      outb(i, SCBPTR(base));
+      scb_byte = ~(inb(SCBARRAY(base)));  /* complement the byte */
+      outb(scb_byte, SCBARRAY(base));     /* write it back out */
+      if (inb(SCBARRAY(base)) != scb_byte)
+      {
+        break;
+      }
+      i++;
+    }
+    maxscb = i;		
+  }
 
   return (maxscb);
 }
@@ -3278,41 +3563,35 @@
  *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
  *-F*************************************************************************/
 static int
-aic7xxx_register(Scsi_Host_Template *template, aha_type type,
-		 int base, unsigned char irq)
+aic7xxx_register(Scsi_Host_Template *template,
+                 struct aic7xxx_host_config *config)
 {
-  static const char * board_name[] = {"", "274x", "284x", "7870", "7850", "7872"};
+  static const char * board_name[] = {"", "274x", "284x", "7870", "7850",
+                                      "7872", "7881"};
   int i;
   unsigned char sblkctl;
   int max_targets;
-  int found = 1;
+  int found = 1, base;
   int bios_disabled = 0;
   unsigned char target_settings;
   unsigned char scsi_conf, host_conf;
   int have_seeprom = 0;
   struct Scsi_Host *host;
   struct aic7xxx_host *p;
-  struct aic7xxx_host_config config;
   struct seeprom_config sc;
 
-  config.type = type;
-  config.base = base;
-  config.irq = irq;
-  config.parity = AIC_UNKNOWN;
-  config.low_term = AIC_UNKNOWN;
-  config.high_term = AIC_UNKNOWN;
-  config.busrtime = 0;
+  base = config->base;
 
   /*
    * Lock out other contenders for our i/o space.
    */
   request_region(MINREG(base), MAXREG(base) - MINREG(base), "aic7xxx");
 
-  switch (type)
+  switch (config->type)
   {
     case AIC_274x:
 #if 0
-      printk("aha274x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
+      printk("aha274x: HCNTRL:0x%x\n", inb(HCNTRL(base)));
 #endif
       /*
        * For some 274x boards, we must clear the CHIPRST bit
@@ -3324,147 +3603,157 @@
        * trigger type (level or edge) and use this value
        * for pausing and unpausing the sequencer.
        */
-      config.unpause = (inb(HCNTRL(config.base)) & IRQMS) | INTEN;
-      config.pause = config.unpause | PAUSE;
-      config.extended = aic7xxx_extended;
+      config->unpause = (inb(HCNTRL(base)) & IRQMS) | INTEN;
+      config->pause = config->unpause | PAUSE;
+      config->extended = aic7xxx_extended;
 
-      /*
-       * I don't think we need to kick the reset again, the initial probe
-       * does a reset, it seems that this is kicking a dead horse here.
-       * So... I will try to just verify that the chip has come out of the
-       * reset state and continue the same as the 284x.
-       * In the Calgary version of the driver:
-       *   1) Chip Reset
-       *   2) Set unpause to IRQMS | INTEN
-       *   3) If an interrupt occured without any commands queued, the
-       *      unpause was set to just INTEN
-       * I changed the initial reset code to just mask in the CHIPRST bit
-       * and try to leave the other settings alone.
-       *
-       * I don't think we need the warning about chip reset not being clear.
-       * On both my test machines (2842 & 2940), they work just fine with a
-       * HCNTRL() of 0x5 (PAUSE | CHIPRST). Notice though, the 274x also
-       * adds the INTEN flag, where neither the 284x or 294x do.
-       */
-      outb(config.pause | CHIPRST, HCNTRL(config.base));
+      outb(config->pause | CHIPRST, HCNTRL(base));
       aic7xxx_delay(1);
-      if (inb(HCNTRL(config.base)) & CHIPRST)
+      if (inb(HCNTRL(base)) & CHIPRST)
       {
 	printk("aic7xxx_register: Chip reset not cleared; clearing manually.\n");
       }
-      outb(config.pause, HCNTRL(config.base));
+      outb(config->pause, HCNTRL(base));
 
       /*
        * Just to be on the safe side with the 274x, we will re-read the irq
        * since there was some issue about reseting the board.
        */
-      config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
+      config->irq = inb(HA_INTDEF(base)) & 0x0F;
       if ((inb(HA_274_BIOSCTRL(base)) & BIOSMODE) == BIOSDISABLED)
       {
         bios_disabled = 1;
       }
-      host_conf = inb(HA_HOSTCONF(config.base));
-      config.busrtime = host_conf & 0x3C;
+      host_conf = inb(HA_HOSTCONF(base));
+      config->busrtime = host_conf & 0x3C;
       /* XXX Is this valid for motherboard based controllers? */
       /* Setup the FIFO threshold and the bus off time */
-      outb(host_conf & DFTHRSH, BUSSPD(config.base));
-      outb((host_conf << 2) & BOFF, BUSTIME(config.base));
+      outb(host_conf & DFTHRSH, BUSSPD(base));
+      outb((host_conf << 2) & BOFF, BUSTIME(base));
 
       /*
        * A reminder until this can be detected automatically.
        */
-      printk("aha274x: extended translation %sabled\n",
-	     config.extended ? "en" : "dis");
+      printk("aha274x: Extended translation %sabled\n",
+	     config->extended ? "en" : "dis");
       break;
 
     case AIC_284x:
 #if 0
-      printk("aha284x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
+      printk("aha284x: HCNTRL:0x%x\n", inb(HCNTRL(base)));
 #endif
-      outb(CHIPRST, HCNTRL(config.base));
-      config.unpause = UNPAUSE_284X;
-      config.pause = REQ_PAUSE; /* DWG would like to be like the rest */
-      config.extended = aic7xxx_extended;
-      config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
+      outb(CHIPRST, HCNTRL(base));
+      config->unpause = UNPAUSE_284X;
+      config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
+      aic7xxx_delay(1);
+      outb(config->pause, HCNTRL(base));
+
+      config->extended = aic7xxx_extended;
+      config->irq = inb(HA_INTDEF(base)) & 0x0F;
       if ((inb(HA_274_BIOSCTRL(base)) & BIOSMODE) == BIOSDISABLED)
       {
         bios_disabled = 1;
       }
-      host_conf = inb(HA_HOSTCONF(config.base));
-      config.busrtime = host_conf & 0x3C;
+      host_conf = inb(HA_HOSTCONF(base));
+
+      printk("aha284x: Reading SEEPROM...");
+      have_seeprom = read_2840_seeprom(base, &sc);
+      if (!have_seeprom)
+      {
+	printk("aha284x: Unable to read SEEPROM\n");
+        config->busrtime = host_conf & 0x3C;
+      }
+      else
+      {
+	printk("done.\n");
+	config->extended = ((sc.bios_control & CFEXTEND) >> 7);
+	config->scsi_id = (sc.brtime_id & CFSCSIID);
+	config->parity = (sc.adapter_control & CFSPARITY) ?
+			 AIC_ENABLED : AIC_DISABLED;
+	config->low_term = (sc.adapter_control & CFSTERM) ?
+			      AIC_ENABLED : AIC_DISABLED;
+	config->high_term = (sc.adapter_control & CFWSTERM) ?
+			      AIC_ENABLED : AIC_DISABLED;
+	config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
+      }
       /* XXX Is this valid for motherboard based controllers? */
       /* Setup the FIFO threshold and the bus off time */
-      outb(host_conf & DFTHRSH, BUSSPD(config.base));
-      outb((host_conf << 2) & BOFF, BUSTIME(config.base));
+      outb(host_conf & DFTHRSH, BUSSPD(base));
+      outb((host_conf << 2) & BOFF, BUSTIME(base));
 
-      /*
-       * A reminder until this can be detected automatically.
-       */
-      printk("aha284x: extended translation %sabled\n",
-	     config.extended ? "en" : "dis");
+      printk("aha284x: Extended translation %sabled\n",
+	     config->extended ? "en" : "dis");
       break;
 
     case AIC_7850:
     case AIC_7870:
     case AIC_7872:
+    case AIC_7880:
+    case AIC_7882:
 #if 0
-      printk("aic%s hcntrl=0x%x\n", board_name[type], inb(HCNTRL(config.base)));
+      printk("aic%s HCNTRL:0x%x\n", board_name[config->type], inb(HCNTRL(base)));
 #endif
 
-      outb(CHIPRST, HCNTRL(config.base));
-      config.unpause = UNPAUSE_294X;
-      config.pause = config.unpause | PAUSE;
-      config.extended = aic7xxx_extended;
-      config.scsi_id = 7;
+      outb(CHIPRST, HCNTRL(base));
+      config->unpause = UNPAUSE_294X;
+      config->pause = config->unpause | PAUSE;
+      aic7xxx_delay(1);
+      outb(config->pause, HCNTRL(base));
 
-      printk("aic78xx: Reading SEEPROM... ");
-      have_seeprom = read_seeprom(base, &sc);
+      config->extended = aic7xxx_extended;
+      config->scsi_id = 7;
+
+      printk("aic78xx: Reading SEEPROM...");
+      have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2), &sc);
       if (!have_seeprom)
       {
-	printk("aic78xx: unable to read SEEPROM\n");
+	printk("aic78xx: Unable to read SEEPROM\n");
       }
       else
       {
-	printk("done\n");
-	config.extended = ((sc.bios_control & CFEXTEND) >> 7);
-	config.scsi_id = (sc.brtime_id & CFSCSIID);
-	config.parity = (sc.adapter_control & CFSPARITY) ?
+	printk("done.\n");
+	config->extended = ((sc.bios_control & CFEXTEND) >> 7);
+	config->scsi_id = (sc.brtime_id & CFSCSIID);
+	config->parity = (sc.adapter_control & CFSPARITY) ?
 			 AIC_ENABLED : AIC_DISABLED;
-	config.low_term = (sc.adapter_control & CFSTERM) ?
+	config->low_term = (sc.adapter_control & CFSTERM) ?
 			      AIC_ENABLED : AIC_DISABLED;
-	config.high_term = (sc.adapter_control & CFWSTERM) ?
+	config->high_term = (sc.adapter_control & CFWSTERM) ?
 			      AIC_ENABLED : AIC_DISABLED;
-	config.busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
+	config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
+        if (((config->type == AIC_7880) || (config->type == AIC_7882)) &&
+            (sc.adapter_control & CFULTRAEN))
+        {
+          printk ("aic7xxx: Enabling support for Ultra SCSI speed.\n");
+          config->ultra_enabled = TRUE;
+        }
       }
 
       /*
        * XXX - force data fifo threshold to 100%. Why does this
        *       need to be done?
        */
-      outb(inb(DSPCISTATUS(config.base)) | DFTHRESH, DSPCISTATUS(config.base));
-      outb(config.scsi_id | DFTHRESH, HA_SCSICONF(config.base));
+      outb(inb(DSPCISTATUS(base)) | DFTHRESH, DSPCISTATUS(base));
+      outb(config->scsi_id | DFTHRESH, HA_SCSICONF(base));
 
       /*
        * In case we are a wide card, place scsi ID in second conf byte.
        */
-      outb(config.scsi_id, (HA_SCSICONF(config.base) + 1));
+      outb(config->scsi_id, (HA_SCSICONF(base) + 1));
 
-      /*
-       * A reminder until this can be detected automatically.
-       */
-      printk("aic%s: extended translation %sabled\n", board_name[type],
-	     config.extended ? "en" : "dis");
+      printk("aic%s: Extended translation %sabled\n", board_name[config->type],
+	     config->extended ? "en" : "dis");
       break;
 
     default:
       panic("aic7xxx_register: internal error\n");
   }
 
-  config.maxscb = detect_maxscb(type, base);
+  config->maxscb = detect_maxscb(config->type, base, config->walk_scbs);
 
-  if ((config.type == AIC_274x) || (config.type == AIC_284x))
+  if ((config->type == AIC_274x) || (config->type == AIC_284x))
   {
-    if (config.pause & IRQMS)
+    if (config->pause & IRQMS)
     {
       printk("aic7xxx: Using Level Sensitive Interrupts\n");
     }
@@ -3478,35 +3767,35 @@
    * Read the bus type from the SBLKCTL register. Set the FLAGS
    * register in the sequencer for twin and wide bus cards.
    */
-  sblkctl = inb(SBLKCTL(base)) & 0x0F;  /* mask out upper two bits */
-  switch (sblkctl)
+  sblkctl = inb(SBLKCTL(base));
+  switch (sblkctl & SELBUS_MASK)
   {
     case SELSINGLE:     /* narrow/normal bus */
-      config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
-      config.bus_type = AIC_SINGLE;
+      config->scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+      config->bus_type = AIC_SINGLE;
       outb(SINGLE_BUS, HA_FLAGS(base));
       break;
 
     case SELWIDE:     /* Wide bus */
-      config.scsi_id = inb(HA_SCSICONF(base) + 1) & 0x0F;
-      config.bus_type = AIC_WIDE;
+      config->scsi_id = inb(HA_SCSICONF(base) + 1) & 0x0F;
+      config->bus_type = AIC_WIDE;
       printk("aic7xxx: Enabling wide channel of %s-Wide\n",
-	     board_name[config.type]);
+	     board_name[config->type]);
       outb(WIDE_BUS, HA_FLAGS(base));
       break;
 
     case SELBUSB:     /* Twin bus */
-      config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+      config->scsi_id = inb(HA_SCSICONF(base)) & 0x07;
 #ifdef AIC7XXX_TWIN_SUPPORT
-      config.scsi_id_b = inb(HA_SCSICONF(base) + 1) & 0x07;
-      config.bus_type = AIC_TWIN;
+      config->scsi_id_b = inb(HA_SCSICONF(base) + 1) & 0x07;
+      config->bus_type = AIC_TWIN;
       printk("aic7xxx: Enabled channel B of %s-Twin\n",
-	     board_name[config.type]);
+	     board_name[config->type]);
       outb(TWIN_BUS, HA_FLAGS(base));
 #else
-      config.bus_type = AIC_SINGLE;
+      config->bus_type = AIC_SINGLE;
       printk("aic7xxx: Channel B of %s-Twin will be ignored\n",
-	     board_name[config.type]);
+	     board_name[config->type]);
       outb(0, HA_FLAGS(base));
 #endif
       break;
@@ -3519,12 +3808,11 @@
   }
 
   /*
-   * Clear the upper two bits. For the 294x cards, clearing the
-   * upper two bits, will take the card out of diagnostic mode
-   * and make the host adatper LED follow bus activity (will not
-   * always be on).
+   * For the 294x cards, clearing DIAGLEDEN and DIAGLEDON, will
+   * take the card out of diagnostic mode and make the host adatper
+   * LED follow bus activity (will not always be on).
    */
-  outb(sblkctl, SBLKCTL(base));
+  outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL(base));
 
   /*
    * The IRQ level in i/o port 4 maps directly onto the real
@@ -3536,10 +3824,10 @@
    *
    * The 294x cards (PCI) get their interrupt from PCI BIOS.
    */
-  if (((config.type == AIC_274x) || (config.type == AIC_284x))
-      && (config.irq < 9 || config.irq > 15))
+  if (((config->type == AIC_274x) || (config->type == AIC_284x)) &&
+      (config->irq < 9 || config->irq > 15))
   {
-    printk("aic7xxx uses unsupported IRQ level, ignoring\n");
+    printk("aic7xxx uses unsupported IRQ level, ignoring.\n");
     return (0);
   }
 
@@ -3551,7 +3839,7 @@
    * proceed.
    */
 #ifndef AIC7XXX_SHARE_IRQS
-   if (aic7xxx_boards[config.irq] != NULL)
+   if (aic7xxx_boards[config->irq] != NULL)
    {
      printk("aic7xxx_register: Sharing of IRQs is not configured.\n");
      return (0);
@@ -3563,7 +3851,7 @@
    * the card - a lot of registers on it can't be read
    * when the sequencer is active.
    */
-  debug_config(&config);
+  debug_config(config);
 
   /*
    * Before registry, make sure that the offsets of the
@@ -3579,7 +3867,7 @@
     if (SG_STRUCT_CHECK(sg))
     {
       printk("aic7xxx warning: kernel scatter-gather "
-	     "structures changed, disabling it\n");
+	     "structures changed, disabling it.\n");
       template->sg_tablesize = SG_NONE;
     }
   }
@@ -3593,15 +3881,15 @@
    * information when an IRQ is triggered.
    */
   host = scsi_register(template, sizeof(struct aic7xxx_host));
-  host->can_queue = config.maxscb;
+  host->can_queue = config->maxscb;
   host->cmd_per_lun = AIC7XXX_CMDS_PER_LUN;
-  host->this_id = config.scsi_id;
-  host->irq = config.irq;
-  if (config.bus_type == AIC_WIDE)
+  host->this_id = config->scsi_id;
+  host->irq = config->irq;
+  if (config->bus_type == AIC_WIDE)
   {
     host->max_id = 16;
   }
-  if (config.bus_type == AIC_TWIN)
+  if (config->bus_type == AIC_TWIN)
   {
     host->max_channel = 1;
   }
@@ -3621,21 +3909,23 @@
   p->isr_count = 0;
   p->a_scanned = 0;
   p->b_scanned = 0;
-  p->base = config.base;
-  p->maxscb = config.maxscb;
+  p->base = base;
+  p->maxscb = config->maxscb;
   p->numscb = 0;
-  p->extended = config.extended;
-  p->type = config.type;
-  p->bus_type = config.bus_type;
+  p->extended = config->extended;
+  p->type = config->type;
+  p->ultra_enabled = config->ultra_enabled;
+  p->chan_num = config->chan_num;
+  p->bus_type = config->bus_type;
   p->have_seeprom = have_seeprom;
   p->seeprom = sc;
   p->free_scb = NULL;
   p->next = NULL;
 
-  p->unpause = config.unpause;
-  p->pause = config.pause;
+  p->unpause = config->unpause;
+  p->pause = config->pause;
 
-  if (aic7xxx_boards[config.irq] == NULL)
+  if (aic7xxx_boards[config->irq] == NULL)
   {
     /*
      * Warning! This must be done before requesting the irq.  It is
@@ -3644,15 +3934,15 @@
      * kernel, an interrupt is triggered immediately.  Therefore, we
      * must ensure the board data is correctly set before the request.
      */
-    aic7xxx_boards[config.irq] = host;
+    aic7xxx_boards[config->irq] = host;
 
     /*
      * Register IRQ with the kernel.
      */
-    if (request_irq(config.irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx"))
+    if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx"))
     {
-      printk("aic7xxx couldn't register irq %d, ignoring\n", config.irq);
-      aic7xxx_boards[config.irq] = NULL;
+      printk("aic7xxx couldn't register irq %d, ignoring\n", config->irq);
+      aic7xxx_boards[config->irq] = NULL;
       return (0);
     }
   }
@@ -3663,8 +3953,8 @@
      * registered host adapter. Add this host adapter's Scsi_Host
      * to the beginning of the linked list of hosts at the same IRQ.
      */
-    p->next = aic7xxx_boards[config.irq];
-    aic7xxx_boards[config.irq] = host;
+    p->next = aic7xxx_boards[config->irq];
+    aic7xxx_boards[config->irq] = host;
   }
 
   /*
@@ -3674,7 +3964,7 @@
    * but then your mailing address is dynamically assigned
    * so no one can find you anyway :-)
    */
-  printk("aic7xxx: Downloading sequencer code..");
+  printk("aic7xxx: Downloading sequencer code...");
   aic7xxx_loadseq(base);
 
   /*
@@ -3690,27 +3980,37 @@
   printk("done.\n");
 
   /*
-   * Set the SCSI Id, SXFRCTL1, and SIMODE1, for both channels
+   * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
    */
   if (p->bus_type == AIC_TWIN)
   {
     /*
-     * The device is gated to channel B after a chip reset,
-     * so set those values first.
+     * Select Channel B.
      */
-    outb(config.scsi_id_b, SCSIID(base));
+    outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL(base));
+
+    outb(config->scsi_id_b, SCSIID(base));
     scsi_conf = inb(HA_SCSICONF(base) + 1) & (ENSPCHK | STIMESEL);
     outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
     outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+    if (p->ultra_enabled)
+    {
+      outb(ULTRAEN, SXFRCTL0(base));
+    }
+
     /*
      * Select Channel A
      */
-    outb(SELSINGLE, SBLKCTL(base));
+    outb((sblkctl & ~SELBUS_MASK) | SELSINGLE, SBLKCTL(base));
   }
-  outb(config.scsi_id, SCSIID(base));
+  outb(config->scsi_id, SCSIID(base));
   scsi_conf = inb(HA_SCSICONF(base)) & (ENSPCHK | STIMESEL);
   outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
   outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+  if (p->ultra_enabled)
+  {
+    outb(ULTRAEN, SXFRCTL0(base));
+  }
 
   /*
    * Look at the information that board initialization or the board
@@ -3732,6 +4032,7 @@
   {
     max_targets = 16;
   }
+
   /*
    * Grab the disconnection disable table and invert it for our needs
    */
@@ -3743,13 +4044,14 @@
   {
     if (bios_disabled)
     {
-      printk("aic7xxx : Host Adapter Bios disabled.  Using default SCSI "
+      printk("aic7xxx : Host Adapter Bios disabled. Using default SCSI "
              "device parameters\n");
       p->discenable = 0xFFFF;
     }
     else
     {
-      p->discenable = ~(inw(HA_DISC_DSB(base)));
+      p->discenable = ~((inb(HA_DISC_DSB(base + 1)) << 8) |
+          inb(HA_DISC_DSB(base)));
     }
   }
 
@@ -3807,7 +4109,7 @@
    * Clear the control byte for every SCB so that the sequencer
    * doesn't get confused and think that one of them is valid
    */
-  for (i = 0; i < config.maxscb; i++)
+  for (i = 0; i < config->maxscb; i++)
   {
     outb(i, SCBPTR(base));
     outb(0, SCBARRAY(base));
@@ -3817,7 +4119,7 @@
    * For reconnecting targets, the sequencer code needs to
    * know how many SCBs it has to search through.
    */
-  outb(config.maxscb, HA_SCBCOUNT(base));
+  outb(config->maxscb, HA_SCBCOUNT(base));
 
   /*
    * Clear the active flags - no targets are busy.
@@ -3846,26 +4148,31 @@
 
   if (!aic7xxx_no_reset)
   {
-    printk("Resetting the SCSI bus...\n");
+    printk("aic7xxx: Resetting the SCSI bus...");
     if (p->bus_type == AIC_TWIN)
     {
       /*
-       * Select channel B.
+       * Select Channel B.
        */
-      outb(SELBUSB, SBLKCTL(base));
+      outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL(base));
+
       outb(SCSIRSTO, SCSISEQ(base));
       udelay(1000);
       outb(0, SCSISEQ(base));
+
       /*
-       * Select channel A.
+       * Select Channel A.
        */
-      outb(SELSINGLE, SBLKCTL(base));
+      outb((sblkctl & ~SELBUS_MASK) | SELSINGLE, SBLKCTL(base));
     }
 
     outb(SCSIRSTO, SCSISEQ(base));
     udelay(1000);
     outb(0, SCSISEQ(base));
+
     aic7xxx_delay(AIC7XXX_RESET_DELAY);
+
+    printk("done.\n");
   }
 
   /*
@@ -3891,8 +4198,10 @@
   int found = 0, slot, base;
   unsigned char irq = 0;
   int i;
+  struct aic7xxx_host_config config;
 
   template->proc_dir = &proc_scsi_aic7xxx;
+  config.chan_num = 0;
 
   /*
    * Since we may allow sharing of IRQs, it is imperative
@@ -3936,9 +4245,8 @@
       aic7xxx_spurious_count = 1;
 
 #if 0
-      printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
+      printk("aic7xxx: HCNTRL:0x%x\n", inb(HCNTRL(base)));
       outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
-      irq = inb(HA_INTDEF(base)) & 0x0F;
 #endif
 
       /*
@@ -3946,7 +4254,16 @@
        * signature and we can set it up and register
        * it with the kernel without incident.
        */
-      found += aic7xxx_register(template, type, base, irq);
+      config.type = type;
+      config.base = base;
+      config.irq = irq;
+      config.parity = AIC_UNKNOWN;
+      config.low_term = AIC_UNKNOWN;
+      config.high_term = AIC_UNKNOWN;
+      config.busrtime = 0;
+      config.walk_scbs = FALSE;
+      config.ultra_enabled = FALSE;
+      found += aic7xxx_register(template, &config);
 
       /*
        * Disallow spurious interrupts.
@@ -3957,11 +4274,6 @@
 
 #ifdef CONFIG_PCI
 
-#define DEVREVID  0x08
-#define DEVCONFIG 0x40
-#define DEVSTATUS 0x41
-#define RAMPSM    0x02
-
   /*
    * PCI-bus probe.
    */
@@ -4001,12 +4313,35 @@
 				  index, &pci_bus, &pci_device_fn))
 	  {
 	    type = AIC_7872;
+            config.chan_num = number_of_3940s & 0x1;
+            number_of_3940s++;
 	  }
 	  else
 	  {
-	    type = AIC_NONE;
-	    done = 1;
-	  }
+            if ((!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+                                     PCI_DEVICE_ID_ADAPTEC_7881,
+                                     index, &pci_bus, &pci_device_fn)) ||
+                (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+                                     PCI_DEVICE_ID_ADAPTEC_7880,
+                                     index, &pci_bus, &pci_device_fn)))
+	    {
+	      type = AIC_7880;
+	    }
+            else
+            {
+	      if (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+				      PCI_DEVICE_ID_ADAPTEC_7882,
+				      index, &pci_bus, &pci_device_fn))
+	      {
+	        type = AIC_7882;
+              }
+              else
+              {
+	        type = AIC_NONE;
+	        done = 1;
+              }
+            }
+          }
 	}
       }
 
@@ -4017,7 +4352,6 @@
 	 */
 	error = pcibios_read_config_dword(pci_bus, pci_device_fn,
 					  PCI_BASE_ADDRESS_0, &io_port);
-
 	if (error)
 	{
 	  panic("aic7xxx_detect: error 0x%x reading i/o port.\n", error);
@@ -4030,42 +4364,62 @@
 	  panic("aic7xxx_detect: error %d reading irq.\n", error);
 	}
 
-	/*
-	 * Make the base I/O register look like EISA and VL-bus.
-	 */
-	base = io_port - 0xC01;
-
-	/*
-	 * I don't think we need to bother with allowing
-	 * spurious interrupts for the 787x/7850, but what
-	 * the hey.
-	 */
-	aic7xxx_spurious_count = 1;
-
-#if 0
-	printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
-#endif
-	outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
-
 	error = pcibios_read_config_byte(pci_bus, pci_device_fn,
 					 DEVREVID, &devrevid);
+	if (error)
+	{
+	  panic("aic7xxx_detect: error %d reading device revision id.\n", error);
+	}
+
 	if (devrevid < 3)
 	{
 	  printk("aic7xxx_detect: AIC-7870 Rev %c\n", rev_id[devrevid]);
 	}
+
 	error = pcibios_read_config_byte(pci_bus, pci_device_fn,
 					 DEVCONFIG, &devconfig);
+	if (error)
+	{
+	  panic("aic7xxx_detect: error %d reading device configuration.\n", error);
+	}
+
 	error = pcibios_read_config_byte(pci_bus, pci_device_fn,
 					 DEVSTATUS, &devstatus);
+	if (error)
+	{
+	  panic("aic7xxx_detect: error %d reading device status.\n", error);
+	}
+
 	printk("aic7xxx_detect: devconfig 0x%x, devstatus 0x%x\n",
 	       devconfig, devstatus);
-	if (devstatus & RAMPSM)
+
+	/*
+	 * Make the base I/O register look like EISA and VL-bus.
+	 */
+	base = io_port - 0xC01;
+
+	/*
+	 * I don't think we need to bother with allowing
+	 * spurious interrupts for the 787x/7850, but what
+	 * the hey.
+	 */
+	aic7xxx_spurious_count = 1;
+
+        config.type = type;
+        config.base = base;
+        config.irq = irq;
+        config.parity = AIC_UNKNOWN;
+        config.low_term = AIC_UNKNOWN;
+        config.high_term = AIC_UNKNOWN;
+        config.busrtime = 0;
+        config.walk_scbs = FALSE;
+        config.ultra_enabled = FALSE;
+	if ((devstatus & RAMPSM) || (devconfig & SCBRAMSEL) ||
+            (type == AIC_7872))
 	{
-	  printk("aic7xxx_detect: detected external SCB RAM, "
-		 "mail deang@ims.com for test patch");
+          config.walk_scbs = TRUE;
 	}
-
-	found += aic7xxx_register(template, type, base, irq);
+	found += aic7xxx_register(template, &config);
 
 	/*
 	 * Disable spurious interrupts.
@@ -4530,8 +4884,24 @@
   save_flags(flags);
   cli();
 
-  aic7xxx_abort_scb(p, scb);
-
+  if (scb->state & SCB_ACTIVE)
+  {
+    if (scb->state & SCB_IMMED)
+    {
+      /*
+       * Don't know how set the number of retries to 0.
+       */
+      /* cmd->retries = 0; */
+      aic7xxx_done (p, scb);
+    }
+    else
+    {
+      /*
+       * Abort the operation.
+       */
+      aic7xxx_abort_scb(p, scb);
+    }
+  }
   restore_flags(flags);
   return (0);
 }
diff -u --recursive --new-file v1.3.40/linux/drivers/scsi/aic7xxx.seq linux/drivers/scsi/aic7xxx.seq
--- v1.3.40/linux/drivers/scsi/aic7xxx.seq	Mon Oct 23 18:02:08 1995
+++ linux/drivers/scsi/aic7xxx.seq	Mon Nov 13 08:03:45 1995
@@ -25,13 +25,14 @@
 # optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
 ##-M#########################################################################
 
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 2.1 1995/08/30 07:47:07 deang Exp $"
+VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 2.3 1995/11/10 10:51:22 deang Exp $"
 
 SCBMASK		= 0xff
 
 SCSISEQ		= 0x00
 ENRSELI		= 0x10
 SXFRCTL0	= 0x01
+ULTRAEN		= 0x20
 SXFRCTL1	= 0x02
 SCSISIGI	= 0x03
 SCSISIGO	= 0x03
@@ -229,7 +230,6 @@
 SAVED_TCL	= 0x56				# Temporary storage for the 
 						# target/channel/lun of a
 						# reconnecting target
-
 # After starting the selection hardware, we return to the "poll_for_work"
 # loop so that we can check for reconnecting targets as well as for our
 # selection to complete just in case the reselection wins bus arbitration.
@@ -444,6 +444,7 @@
 
 	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
 
+	mov	A		call scsisig
 	cmp	ALLZEROS,A	je p_dataout
 	cmp	A,0x40		je p_datain
 	cmp	A,0x80		je p_command
@@ -454,7 +455,6 @@
 	mvi	INTSTAT,BAD_PHASE		# unknown - signal driver
 
 p_dataout:
-	mvi	0		call scsisig	# !CDO|!IOO|!MSGO
 	mvi	DMAPARAMS,0x7d			# WIDEODD|SCSIEN|SDMAEN|HDMAEN|
 						#   DIRECTION|FIFORESET
 	jmp	data_phase_init
@@ -469,8 +469,7 @@
 # Reads should not use WIDEODD since it may make the last byte for a SG segment
 # go to the next segment.
 p_datain:
-	mvi	0x40		call scsisig	# !CDO|IOO|!MSGO
-	mvi	DMAPARAMS,0x39			# SCSIEN|SDMAEN|HDMAEN|
+	mvi	DMAPARAMS,0x79			# WIDEODD|SCSIEN|SDMAEN|HDMAEN|
 						#   !DIRECTION|FIFORESET
 data_phase_init:
 	call	assert
@@ -574,7 +573,6 @@
 #  so we can copy those three bytes directly into HCNT.
 #
 p_command:
-	mvi	0x80		call scsisig	# CDO|!IOO|!MSGO
 	call	assert
 
 # Load HADDR and HCNT.  We can do this in one bcopy since they are neighbors
@@ -592,7 +590,6 @@
 #  and store it into the SCB.
 #
 p_status:
-	mvi	0xc0		call scsisig	# CDO|IOO|!MSGO
 
 	mvi	SCBARRAY+14	call inb_first
 	jmp	mesgin_done
@@ -601,7 +598,6 @@
 #  took us into this phase anyway, build a no-op message and send it.
 #
 p_mesgout:
-	mvi	0xa0		call scsisig	# CDO|!IOO|MSGO
 	mvi	0x8		call mk_mesg	# build NOP message
 
 	clr     STCNT+2
@@ -661,7 +657,8 @@
 
 	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
 	cmp	A,0xa0		jne p_mesgout6
-	mvi	0x10		call scsisig	# ATNO - re-assert ATN
+	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
+	call	scsisig				# ATNO - re-assert ATN
 
 	jmp	ITloop
 
@@ -679,7 +676,6 @@
 #  to a data I/O phase.
 #
 p_mesgin:
-	mvi	0xe0		call scsisig	# CDO|IOO|MSGO
 	mvi	A		call inb_first	# read the 1st message byte
 	mvi	REJBYTE,A			# save it for the driver
 
@@ -742,11 +738,12 @@
 	mov	A,FUNCTION1
 	test	SCBARRAY+1,0x88 jz clear_a
 	xor	ACTIVE_B,A
-	jmp	complete
+	jmp	immediate
 
 clear_a:
 	xor	ACTIVE_A,A
 
+immediate:
 	test    SCBARRAY+11,0xff jnz complete  # Immediate message complete
 # Pause the sequencer until the driver gets around to handling the command
 # complete.  This is so that any action that might require carefull timing
@@ -1011,7 +1008,8 @@
 #  actually off first lest we get an ILLSADDR.
 #
 dma5:
-	clr	DFCNTRL				# disable DMA
+	and	DFCNTRL, 0x40, SINDEX		# disable DMA, but maintain
+						# WIDEODD
 dma6:
 	test	DFCNTRL,0x38	jnz dma6	# SCSIENACK|SDMAENACK|HDMAENACK
 
@@ -1044,7 +1042,7 @@
 #
 	clr	SIGSTATE 
 
-	mvi	SXFRCTL0,0x8a			# DFON|SPIOEN|CLRCHN
+	or	SXFRCTL0,0x8a			# DFON|SPIOEN|CLRCHN
 
 #  Make sure that the system knows we have not been through a DATA
 #  phase.
@@ -1205,7 +1203,8 @@
 	jmp	sdtr_to_rate_loop
 sdtr_to_rate_done:
 	shr	RETURN_1,0x2
-	add	RETURN_1,0x18	ret
-
+	add	RETURN_1,0x18
+	test	SXFRCTL0,ULTRAEN jz return
+	shr	RETURN_1,0x1
 return:
 	ret
diff -u --recursive --new-file v1.3.40/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.40/linux/drivers/scsi/scsi.c	Sat Nov 11 17:41:33 1995
+++ linux/drivers/scsi/scsi.c	Mon Nov 13 08:54:38 1995
@@ -796,6 +796,7 @@
 	 */
 	printk("Unable to reset scsi host %d - ", SCpnt->host->host_no);
 	printk("probably a SCSI bus hang.\n");
+	SCpnt->internal_timeout &= ~IN_RESET;
         scsi_reset (SCpnt, TRUE);
 	return;
 	
@@ -1834,6 +1835,26 @@
     }
 }
 
+
+/* Mark a single SCSI Device as having been reset. */
+
+static inline void scsi_mark_device_reset(Scsi_Device *Device)
+{
+  Device->was_reset = 1;
+  Device->expecting_cc_ua = 1;
+}
+
+
+/* Mark all SCSI Devices on a specific Host as having been reset. */
+
+void scsi_mark_host_bus_reset(struct Scsi_Host *Host)
+{
+  Scsi_Cmnd *SCpnt;
+  for(SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
+    scsi_mark_device_reset(SCpnt->device);
+}
+
+
 int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
 {
     int temp, oldto;
@@ -1934,28 +1955,21 @@
 #ifdef DEBUG
 	    printk("scsi reset function returned %d\n", temp);
 #endif
- 
-            if( temp & SCSI_RESET_BUS_RESET )
-            {
-                /*
-                 * The low level driver did a bus reset, so we should
-                 * go through and mark all of the devices on that bus
-                 * as having been reset.
-                 */
-                SCpnt1 = host->host_queue;
-                while(SCpnt1) {
-                    SCpnt1->device->was_reset = 1;
-                    SCpnt1->device->expecting_cc_ua = 1;
-                    SCpnt1 = SCpnt1->next;
-                }
-            }
             
             /*
              * Now figure out what we need to do, based upon
              * what the low level driver said that it did.
+	     * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
+	     * or SCSI_RESET_WAKEUP, then the low level driver did a
+	     * bus device reset or bus reset, so we should go through
+	     * and mark one or all of the devices on that bus
+	     * as having been reset.
              */
             switch(temp & SCSI_RESET_ACTION) {
 	    case SCSI_RESET_SUCCESS:
+	        if (temp & SCSI_RESET_BUS_RESET)
+		  scsi_mark_host_bus_reset(host);
+		else scsi_mark_device_reset(SCpnt->device);
 		save_flags(flags);
 		cli();
 		SCpnt->internal_timeout &= ~IN_RESET;
@@ -1963,12 +1977,18 @@
 		restore_flags(flags);
 		return 0;
 	    case SCSI_RESET_PENDING:
+	        if (temp & SCSI_RESET_BUS_RESET)
+		  scsi_mark_host_bus_reset(host);
+		else scsi_mark_device_reset(SCpnt->device);
 		return 0;
 	    case SCSI_RESET_PUNT:
                 SCpnt->internal_timeout &= ~IN_RESET;
                 scsi_request_sense (SCpnt);
                 return 0;
 	    case SCSI_RESET_WAKEUP:
+	        if (temp & SCSI_RESET_BUS_RESET)
+		  scsi_mark_host_bus_reset(host);
+		else scsi_mark_device_reset(SCpnt->device);
 		SCpnt->internal_timeout &= ~IN_RESET;
 		scsi_request_sense (SCpnt);
                 /*
diff -u --recursive --new-file v1.3.40/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.3.40/linux/drivers/scsi/scsi.h	Tue Oct 10 18:46:37 1995
+++ linux/drivers/scsi/scsi.h	Mon Nov 13 08:54:38 1995
@@ -449,6 +449,7 @@
 extern void print_command(unsigned char *);
 extern void print_sense(const char *, Scsi_Cmnd *);
 
+extern void scsi_mark_host_bus_reset(struct Scsi_Host *Host);
 
 #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
 #include "hosts.h"
diff -u --recursive --new-file v1.3.40/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.3.40/linux/drivers/scsi/sd.c	Thu Nov  9 11:23:50 1995
+++ linux/drivers/scsi/sd.c	Mon Nov 13 08:54:38 1995
@@ -1133,6 +1133,12 @@
 	
 	rscsi_disks[i].sector_size = (buffer[4] << 24) |
 	    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+
+	if (rscsi_disks[i].sector_size == 0) {
+	  rscsi_disks[i].sector_size = 512;
+	  printk("sd%c : sector size 0 reported, assuming 512.\n", 'a' + i);
+	}
+ 
 	
 	if (rscsi_disks[i].sector_size != 512 &&
 	    rscsi_disks[i].sector_size != 1024 &&
diff -u --recursive --new-file v1.3.40/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v1.3.40/linux/fs/ext2/super.c	Thu Nov  9 11:23:51 1995
+++ linux/fs/ext2/super.c	Mon Nov 13 08:24:02 1995
@@ -157,9 +157,9 @@
 				clear_opt (*mount_options, CHECK_NORMAL);
 				clear_opt (*mount_options, CHECK_STRICT);
 			}
-			else if (strcmp (value, "normal"))
+			else if (!strcmp (value, "normal"))
 				set_opt (*mount_options, CHECK_NORMAL);
-			else if (strcmp (value, "strict")) {
+			else if (!strcmp (value, "strict")) {
 				set_opt (*mount_options, CHECK_NORMAL);
 				set_opt (*mount_options, CHECK_STRICT);
 			}
diff -u --recursive --new-file v1.3.40/linux/fs/msdos/inode.c linux/fs/msdos/inode.c
--- v1.3.40/linux/fs/msdos/inode.c	Sat Nov 11 17:41:33 1995
+++ linux/fs/msdos/inode.c	Sun Nov 12 09:13:20 1995
@@ -81,7 +81,7 @@
 
 	*check = 'n';
 	*conversion = 'b';
-	*dotsOK =1;
+	*dotsOK =0;
 	*uid = current->uid;
 	*gid = current->gid;
 	*umask = current->fs->umask;
diff -u --recursive --new-file v1.3.40/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v1.3.40/linux/include/asm-alpha/system.h	Thu Nov  9 11:23:52 1995
+++ linux/include/asm-alpha/system.h	Mon Nov 13 08:06:10 1995
@@ -100,37 +100,39 @@
 /*
  * Give prototypes to shut up gcc.
  */
-extern inline unsigned long xchg_u32 (volatile int * m, unsigned long new_val);
-extern inline unsigned long xchg_u64 (volatile long * m, unsigned long new_val);
+extern inline unsigned long xchg_u32 (volatile int * m, unsigned long val);
+extern inline unsigned long xchg_u64 (volatile long * m, unsigned long val);
 
-extern inline unsigned long xchg_u32(volatile int * m, unsigned long new_val)
+extern inline unsigned long xchg_u32(volatile int * m, unsigned long val)
 {
-	unsigned long old_val;
+	unsigned long dummy, dummy2;
 
-	__asm__ __volatile__("\n1:\t"
-			     "ldl_l %0,%2\n\t"
-			     "bis %3,%3,$25\n\t"
-			     "stl_c $25,%1\n\t"
-			     "beq $25,1b\n"
-			     : "=r"(old_val), "=m"(*m)
-			     : "m"(*m), "r"(new_val)
-			     : "$25");
-	return old_val;
+	__asm__ __volatile__(
+		"\n1:\t"
+		"ldl_l %0,0(%1)\n\t"
+		"bis %2,%2,%3\n\t"
+		"stl_c %3,0(%1)\n\t"
+		"beq %3,1b\n"
+		: "=r" (val), "=r" (m), "=r" (dummy), "=r" (dummy2)
+		: "1" (m), "2" (val)
+		: "memory");
+	return val;
 }
 
-extern inline unsigned long xchg_u64(volatile long * m, unsigned long new_val)
+extern inline unsigned long xchg_u64(volatile long * m, unsigned long val)
 {
-	unsigned long old_val;
+	unsigned long dummy, dummy2;
 
-	__asm__ __volatile__("\n1:\t"
-			     "ldq_l %0,%2\n\t"
-			     "bis %3,%3,$25\n\t"
-			     "stq_c $25,%1\n\t"
-			     "beq $25,1b\n"
-			     : "=r"(old_val), "=m"(*m)
-			     : "m"(*m), "r"(new_val)
-			     : "$25");
-	return old_val;
+	__asm__ __volatile__(
+		"\n1:\t"
+		"ldq_l %0,0(%1)\n\t"
+		"bis %2,%2,%3\n\t"
+		"stq_c %3,0(%1)\n\t"
+		"beq %3,1b\n"
+		: "=r" (val), "=r" (m), "=r" (dummy), "=r" (dummy2)
+		: "1" (m), "2" (val)
+		: "memory");
+	return val;
 }
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
diff -u --recursive --new-file v1.3.40/linux/include/asm-i386/ioctl.h linux/include/asm-i386/ioctl.h
--- v1.3.40/linux/include/asm-i386/ioctl.h	Fri Oct  6 14:35:16 1995
+++ linux/include/asm-i386/ioctl.h	Sat Nov 11 17:44:36 1995
@@ -6,8 +6,6 @@
 #ifndef _ASMI386_IOCTL_H
 #define _ASMI386_IOCTL_H
 
-#include <asm/page.h>		/* for PAGE_SIZE */
-
 /* ioctl command encoding: 32 bits total, command in lower 16 bits,
  * size of the parameter structure in the lower 14 bits of the
  * upper 16 bits.
@@ -18,38 +16,6 @@
  * NOTE: This limits the max parameter size to 16kB -1 !
  */
 
-#define IOC_VOID	0x00000000	/* param in size field */
-#define IOC_IN		0x40000000	/* user --> kernel */
-#define IOC_OUT		0x80000000	/* kernel --> user */
-#define IOC_INOUT	(IOC_IN | IOC_OUT)	/* both */
-#define IOCSIZE_MASK	0x3fff0000	/* size (max 16k-1 bytes) */
-#define IOCSIZE_SHIFT	16		/* how to get the size */
-#define IOCSIZE_MAX	((PAGE_SIZE-1)&(IOCSIZE_MASK >> IOCSIZE_SHIFT))
-#define IOCCMD_MASK	0x0000ffff	/* command code */
-#define IOCCMD_SHIFT	0
-#define IOCPARM_MASK IOCCMD_MASK
-#define IOCPARM_SHIFT IOCCMD_SHIFT
-
-#define IOC_SIZE(cmd)	(((cmd) & IOCSIZE_MASK) >> IOCSIZE_SHIFT)
-#define IOCBASECMD(cmd)	((cmd) & ~IOCPARM_MASK)
-#define IOCGROUP(cmd)	(((cmd) >> 8) & 0xFF)
-
-/* _IO(magic, subcode); size field is zero and the 
- * subcode determines the command.
- */
-#define _IO(c,d)	(IOC_VOID | ((c)<<8) | (d)) /* param encoded */
-
-/* _IOXX(magic, subcode, arg_t); where arg_t is the type of the
- * (last) argument field in the ioctl call, if present.
- */
-#define _IOW(c,d,t)	(IOC_IN | ((sizeof(t)<<16) & IOCSIZE_MASK) | \
-				  ((c)<<8) | (d))
-#define _IOR(c,d,t)	(IOC_OUT | ((sizeof(t)<<16) & IOCSIZE_MASK) | \
-				   ((c)<<8) | (d))
-/* WR rather than RW to avoid conflict with stdio.h */
-#define _IOWR(c,d,t)	(IOC_INOUT | ((sizeof(t)<<16) & IOCSIZE_MASK) | \
-				     ((c)<<8) | (d))
-
 /*
  * The following is for compatibility across the various Linux
  * platforms.  The i386 ioctl numbering scheme doesn't really enforce
@@ -80,10 +46,30 @@
 #define _IOC_READ	1U
 #define _IOC_WRITE	2U
 
+#define _IOC(dir,type,nr,size) \
+	(((dir)  << _IOC_DIRSHIFT) | \
+	 ((type) << _IOC_TYPESHIFT) | \
+	 ((nr)   << _IOC_NRSHIFT) | \
+	 ((size) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+#define _IOWR(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+
 /* used to decode ioctl numbers.. */
 #define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
 #define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
 #define _IOC_NR(nr)		(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
 #define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the drivers/sound files... */
+
+#define IOC_IN		(_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT		(_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT	((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK	(_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT	(_IOC_SIZESHIFT)
 
 #endif /* _ASMI386_IOCTL_H */
diff -u --recursive --new-file v1.3.40/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- v1.3.40/linux/include/asm-i386/irq.h	Wed Nov  8 07:11:41 1995
+++ linux/include/asm-i386/irq.h	Sun Nov 12 09:06:28 1995
@@ -127,7 +127,7 @@
 #define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
 #define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
 
-#ifdef	___SMP__
+#ifdef	__SMP__
 
 #define GET_PROCESSOR_ID \
 	"movl "SYMBOL_NAME_STR(apic_reg)", %edx\n\t" \
diff -u --recursive --new-file v1.3.40/linux/include/linux/mcd.h linux/include/linux/mcd.h
--- v1.3.40/linux/include/linux/mcd.h	Sun Sep  3 16:12:49 1995
+++ linux/include/linux/mcd.h	Mon Nov 13 08:54:55 1995
@@ -110,8 +110,7 @@
 	struct msf	diskTime;
 };
 
-#if 0
 #ifndef I_WAS_HERE
-#error Please edit this file first.
-#endif
+#warning You have not edited mcd.h
+#warning Perhaps irq and i/o settings are wrong.
 #endif
diff -u --recursive --new-file v1.3.40/linux/include/linux/mcdx.h linux/include/linux/mcdx.h
--- v1.3.40/linux/include/linux/mcdx.h	Sun Sep  3 16:12:49 1995
+++ linux/include/linux/mcdx.h	Mon Nov 13 08:54:55 1995
@@ -1,7 +1,7 @@
 /*
  * Definitions for the Mitsumi CDROM interface
- * Copyright (C) 1995 Heiko Schlittermann
- * VERSION: 1.0a
+ * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
+ * VERSION: 1.3
  * 
  * 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
@@ -92,10 +92,16 @@
 #define INIT 		0
 #define MALLOC 		0
 #define IOCTL 		0
+#define PLAYTRK     0
+#define SUBCHNL     0
+#define TOCHDR      0
+#define MS          0
+#define PLAYMSF     0
+#define READTOC     0
 #define OPENCLOSE 	0
 #define HW		    0
 #define TALK		0
-#define IRQ 		0
+#define IRQ 		1
 #define TRANSFER 	0
 #define REQUEST	 	0
 #else
@@ -173,8 +179,7 @@
 #define MCDX_E		1			/* unspec error */
 #define MCDX_EOM	2			/* end of media */
 
-#if 0
 #ifndef I_WAS_HERE
-#error Please edit this file first.
-#endif
+#warning You have not edited mcdx.h
+#warning Perhaps irq and i/o settings are wrong.
 #endif
diff -u --recursive --new-file v1.3.40/linux/include/linux/pci.h linux/include/linux/pci.h
--- v1.3.40/linux/include/linux/pci.h	Wed Nov  8 07:11:42 1995
+++ linux/include/linux/pci.h	Mon Nov 13 08:03:45 1995
@@ -454,6 +454,7 @@
 #define PCI_DEVICE_ID_ADAPTEC_7872	0x7278
 #define PCI_DEVICE_ID_ADAPTEC_7880	0x8078
 #define PCI_DEVICE_ID_ADAPTEC_7881	0x8178
+#define PCI_DEVICE_ID_ADAPTEC_7882	0x8278
 
 #define PCI_VENDOR_ID_ATRONICS		0x907f
 #define PCI_DEVICE_ID_ATRONICS_2015	0x2015
diff -u --recursive --new-file v1.3.40/linux/include/linux/tty.h linux/include/linux/tty.h
--- v1.3.40/linux/include/linux/tty.h	Thu Nov  9 11:23:54 1995
+++ linux/include/linux/tty.h	Sun Nov 12 09:13:19 1995
@@ -328,6 +328,7 @@
 
 extern int con_open(struct tty_struct * tty, struct file * filp);
 extern void update_screen(int new_console);
+extern void console_print(const char *);
 
 /* vt.c */
 
diff -u --recursive --new-file v1.3.40/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.40/linux/kernel/ksyms.c	Thu Nov  9 11:23:56 1995
+++ linux/kernel/ksyms.c	Sun Nov 12 09:13:19 1995
@@ -266,6 +266,8 @@
 	X(tty_wait_until_sent),
 	X(tty_check_change),
 	X(tty_hung_up_p),
+	X(do_SAK),
+	X(console_print),
 
 	/* filesystem registration */
 	X(register_filesystem),
diff -u --recursive --new-file v1.3.40/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v1.3.40/linux/net/ipv4/proc.c	Wed Sep 13 12:45:35 1995
+++ linux/net/ipv4/proc.c	Mon Nov 13 08:53:12 1995
@@ -111,8 +111,8 @@
 			}
 			len += sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d %d\n",
 				i, src, srcp, dest, destp, sp->state, 
-				format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, 
-				format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
+				format==0?sp->write_seq-sp->rcv_ack_seq:sp->wmem_alloc, 
+				format==0?sp->acked_seq-sp->copied_seq:sp->rmem_alloc,
 				timer_active, timer_expires-jiffies, (unsigned) sp->retransmits,
 				(sp->socket&&SOCK_INODE(sp->socket))?SOCK_INODE(sp->socket)->i_uid:0,
 				timer_active?sp->timeout:0);
