diff -u --recursive --new-file v1.1.89/linux/CREDITS linux/CREDITS
--- v1.1.89/linux/CREDITS	Wed Feb  1 09:23:04 1995
+++ linux/CREDITS	Wed Feb  8 09:03:08 1995
@@ -719,8 +719,8 @@
 N: Hannu Savolainen
 E: hannu@voxware.pp.fi
 D: Kernel sound drivers
-S: Pallaksentie 4 A 2
-S: 00970 Helsinki
+S: Hiekkalaiturintie 3 A 8
+S: 00980 Helsinki
 S: Finland
 
 N: Peter De Schrijver
diff -u --recursive --new-file v1.1.89/linux/Makefile linux/Makefile
--- v1.1.89/linux/Makefile	Sun Feb  5 19:31:50 1995
+++ linux/Makefile	Tue Feb  7 11:46:04 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 89
+SUBLEVEL = 90
 
 ARCH = i386
 
@@ -217,7 +217,7 @@
 	\
 	ls *.o > .allmods; \
 	echo $$MODULES | tr ' ' '\n' | sort | comm -23 .allmods - > .misc; \
-	inst_mod .misc misc; \
+	if [ -s .misc ]; then inst_mod .misc misc; fi; \
 	rm -f .misc .allmods; \
 	)
 
diff -u --recursive --new-file v1.1.89/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.1.89/linux/arch/i386/config.in	Wed Feb  1 09:23:04 1995
+++ linux/arch/i386/config.in	Wed Feb  8 11:49:32 1995
@@ -210,7 +210,7 @@
 if [ "$CONFIG_INET" = "y" ]; then
 bool 'NFS filesystem support' CONFIG_NFS_FS y
 fi
-if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
+if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_AZTCD" = "y" ]; then
 	bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
 else
 	bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
diff -u --recursive --new-file v1.1.89/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v1.1.89/linux/arch/i386/kernel/ldt.c	Thu Jan 26 07:49:02 1995
+++ linux/arch/i386/kernel/ldt.c	Sun Feb  5 23:39:17 1995
@@ -66,6 +66,7 @@
 			if (task[i] == current) {
 				if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
 					return -ENOMEM;
+				memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
 				set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
 				load_ldt(i);
 			}
diff -u --recursive --new-file v1.1.89/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v1.1.89/linux/arch/i386/kernel/signal.c	Thu Jan 26 07:49:02 1995
+++ linux/arch/i386/kernel/signal.c	Tue Feb  7 11:56:41 1995
@@ -254,6 +254,7 @@
 	}
 	regs->esp = (unsigned long) frame;
 	regs->eip = eip;		/* "return" to the first handler */
+	regs->eflags &= ~TF_MASK;
 	current->tss.trap_no = current->tss.error_code = 0;
 	return 1;
 }
diff -u --recursive --new-file v1.1.89/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v1.1.89/linux/arch/i386/kernel/traps.c	Sun Feb  5 19:31:51 1995
+++ linux/arch/i386/kernel/traps.c	Wed Feb  8 13:54:00 1995
@@ -178,23 +178,14 @@
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
-	int signr = SIGSEGV;
-
 	if (regs->eflags & VM_MASK) {
 		handle_vm86_fault((struct vm86_regs *) regs, error_code);
 		return;
 	}
 	die_if_kernel("general protection",regs,error_code);
-	switch (get_seg_byte(regs->cs, (char *)regs->eip)) {
-		case 0xCD: /* INT */
-		case 0xF4: /* HLT */
-		case 0xFA: /* CLI */
-		case 0xFB: /* STI */
-			signr = SIGILL;
-	}
 	current->tss.error_code = error_code;
 	current->tss.trap_no = 13;
-	send_sig(signr, current, 1);	
+	send_sig(SIGSEGV, current, 1);	
 }
 
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
diff -u --recursive --new-file v1.1.89/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v1.1.89/linux/arch/sparc/kernel/ioport.c	Sun Feb  5 19:31:51 1995
+++ linux/arch/sparc/kernel/ioport.c	Mon Feb  6 20:42:52 1995
@@ -1,6 +1,6 @@
 /* ioport.c:  I/O access on the Sparc. Work in progress.. Most of the things
  *            in this file are for the sole purpose of getting the kernel
- *	      throught the compiler. :-)
+ *	      through the compiler. :-)
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
diff -u --recursive --new-file v1.1.89/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v1.1.89/linux/arch/sparc/mm/init.c	Sun Feb  5 19:31:51 1995
+++ linux/arch/sparc/mm/init.c	Mon Feb  6 20:42:52 1995
@@ -97,7 +97,7 @@
  * unmaps the bootup page table (as we're now in KSEG, so we don't need it).
  *
  * The bootup sequence put the virtual page table into high memory: that
- * means that we cah change the L1 page table by just using VL1p below.
+ * means that we can change the L1 page table by just using VL1p below.
  */
 
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
diff -u --recursive --new-file v1.1.89/linux/drivers/block/README.fd linux/drivers/block/README.fd
--- v1.1.89/linux/drivers/block/README.fd	Sun Jan 22 23:03:57 1995
+++ linux/drivers/block/README.fd	Wed Feb  8 09:11:25 1995
@@ -35,16 +35,70 @@
 	Sets the bitmask of allowed drives to <mask>. By default, only units
 	0 and 1 of each floppy controller are allowed. This is done because
 	certain non-standard hardware (ASUS PCI motherboards) mess up the
-	keyboard when accessing units 2 or 3.
+	keyboard when accessing units 2 or 3. This option is somewhat
+	obsoleted by the cmos option.
+
+ floppy=all_drives
+	Sets the bitmask of allowed drives to all drives. Use this if you have
+	more than two drives connected to a floppy controller.
+
+ floppy=asus_pci
+	Sets the bitmask to allow only units 0 and 1. (The default)
+
+ floppy=daring
+	Tells the floppy driver that you have a well behaved floppy controller.
+	This allows more efficient and smoother operation, but may fail on
+	certain controllers. This may speed up certain operations.
+
+ floppy=0,daring
+	Tells the floppy driver that your floppy controller should be used
+	with caution.
+
+ floppy=one_fdc
+	Tells the floppy driver that you have only floppy controller (default)
 
  floppy=two_fdc
+ floppy=<address>,two_fdc
 	Tells the floppy driver that you have two floppy controllers. The
-	second floppy controller is assumed to be at io address 0x370.
+	second floppy controller is assumed to be at <address>. If <address>
+	is not given, 0x370 is assumed.
 
  floppy=thinkpad
 	Tells the floppy driver that you have a Thinkpad. Thinkpads use an
 	inverted convention for the disk change line.
 
+ floppy=0,thinkpad
+	Tells the floppy driver that you don't have a Thinkpad.
+
+ floppy=<drive>,<type>,cmos
+	Sets the cmos type of <drive> to <type>. Additionnaly, this drive is
+	allowed in the bitmask. This is useful if you have more than two
+	floppy drives (only two can be described in the physical cmos), or if
+	your BIOS uses non-standard CMOS types. The CMOS types are:
+		0 - unknown or not installed
+		1 - 5 1/4 DD
+		2 - 5 1/4 HD
+		3 - 3 1/2 DD
+		4 - 3 1/2 HD
+		5 - 3 1/2 ED
+		6 - 3 1/2 ED
+	(Note: there are two valid types for ED drives. This is because 5 was
+	initially chosen to represent floppy *tapes*, and 6 for ED drives.
+	AMI ignored this, and used 5 for ED drives. That's why the floppy
+	driver handles both)
+	Setting the CMOS to 0 for the first two drives (default) makes the
+	floppy driver read the physical cmos for those drives.
+
+ floppy=unexpected_interrupts
+	Print a warning message when an unexpected interrupt is received 
+	(default behaviour)
+
+ floppy=no_unexpected_interrupts
+ floppy=L40SX
+	Don't print a message when an unexpected interrupt is received. This
+	is needed on IBM L40SX laptops in certain video modes. (There seems
+	to be an interaction between video and floppy. The unexpected interrupts
+	only affect performance, and can safely be ignored.)
 
 
 Supporting utilities and additional documentation:
diff -u --recursive --new-file v1.1.89/linux/drivers/block/aztcd.c linux/drivers/block/aztcd.c
--- v1.1.89/linux/drivers/block/aztcd.c	Sun Feb  5 19:31:51 1995
+++ linux/drivers/block/aztcd.c	Mon Feb  6 20:42:52 1995
@@ -638,7 +638,7 @@
 		break;
 	case CDROMVOLCTRL:   /* Volume control 
 	 * With my Aztech CD268-01A volume control does not work, I can only
-	   turn the cannels on (any value !=0) or off (value==0). Maybe it
+	   turn the channels on (any value !=0) or off (value==0). Maybe it
            works better with your drive */
                 st=verify_area(VERIFY_READ,(void *) arg, sizeof(volctrl));
                 if (st) return (st);
diff -u --recursive --new-file v1.1.89/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.89/linux/drivers/block/floppy.c	Sun Feb  5 19:31:52 1995
+++ linux/drivers/block/floppy.c	Wed Feb  8 09:11:25 1995
@@ -82,7 +82,6 @@
  */
 
 #define CONFIG_FLOPPY_SANITY
-#define  CONFIG_FLOPPY_2_FDC
 #undef  CONFIG_FLOPPY_SILENT_DCL_CLEAR
 
 #define REALLY_SLOW_IO
@@ -92,6 +91,9 @@
 
 #include <linux/config.h>
 
+/* do print messages for unexpected interupts */
+static int print_unex=1;
+
 #ifndef FD_MODULE
 /* the following is the mask of allowed drives. By default units 2 and
  * 3 of both floppy controllers are disabled, because switching on the
@@ -148,14 +150,8 @@
 #define FLOPPY1_TYPE 0
 #endif
 
-
-#ifdef CONFIG_FLOPPY_2_FDC
 #define N_FDC 2
 #define N_DRIVE 8
-#else
-#define N_FDC 1
-#define N_DRIVE 4
-#endif
 
 #define TYPE(x) ( ((x)>>2) & 0x1f )
 #define DRIVE(x) ( ((x)&0x03) | (((x)&0x80 ) >> 5))
@@ -179,16 +175,16 @@
 #define USETF(x) (set_bit(x##_BIT, &UDRS->flags))
 #define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))
 
-#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive);
+#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive)
 
 #define DPRINT1(x,x1) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1))
 
 #define DPRINT2(x,x1,x2) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2))
 
 #define DPRINT3(x,x1,x2,x3) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
 
 /* read/write */
 #define COMMAND raw_cmd.cmd[0]
@@ -348,11 +344,8 @@
 
 /* Auto-detection: Disk type used until the next media change occurs. */
 struct floppy_struct *current_type[N_DRIVE] = {
+	NULL, NULL, NULL, NULL,
 	NULL, NULL, NULL, NULL
-#ifdef CONFIG_FLOPPY_2_FDC
-	,
-	NULL, NULL, NULL, NULL
-#endif
 };
 
 /*
@@ -645,9 +638,7 @@
 		current_drive = drive;
 	}
 	set_dor(fdc,~0,8);
-#ifdef CONFIG_FLOPPY_2_FDC
 	set_dor(1-fdc, ~8, 0);
-#endif
 	if ( FDCS->rawcmd == 2 )
 		reset_fdc_info(1);
 	if( inb_p(FD_STATUS) != STATUS_READY )
@@ -713,14 +704,11 @@
 	{ NULL, NULL, 0, 0, motor_off_callback },
 	{ NULL, NULL, 0, 1, motor_off_callback },
 	{ NULL, NULL, 0, 2, motor_off_callback },
-	{ NULL, NULL, 0, 3, motor_off_callback }
-#ifdef CONFIG_FLOPPY_2_FDC
-	,
+	{ NULL, NULL, 0, 3, motor_off_callback },
 	{ NULL, NULL, 0, 4, motor_off_callback },
 	{ NULL, NULL, 0, 5, motor_off_callback },
 	{ NULL, NULL, 0, 6, motor_off_callback },
 	{ NULL, NULL, 0, 7, motor_off_callback }
-#endif
 };
 
 /* schedules motor off */
@@ -1438,18 +1426,22 @@
 	int i;
 	if ( initialising )
 		return;
-	DPRINT("unexpected interrupt\n");
-	if ( inr >= 0 )
-		for(i=0; i<inr; i++)
-			printk("%d %x\n", i, reply_buffer[i] );
+	if(print_unex){
+		DPRINT("unexpected interrupt\n");
+		if ( inr >= 0 )
+			for(i=0; i<inr; i++)
+				printk("%d %x\n", i, reply_buffer[i] );
+	}
 	while(1){
 		output_byte(FD_SENSEI);
 		inr=result();
 		if ( inr != 2 )
 			break;
-		printk("sensei\n");
-		for(i=0; i<inr; i++)
-			printk("%d %x\n", i, reply_buffer[i] );
+		if(print_unex){
+			printk("sensei\n");
+			for(i=0; i<inr; i++)
+				printk("%d %x\n", i, reply_buffer[i] );
+		}
 	}
 	FDCS->reset = 1;
 }
@@ -2829,9 +2821,7 @@
 			     cnt < (type << 2 ) + 4 ;
 			     cnt++)
 				floppy_sizes[cnt]=
-#ifdef CONFIG_FLOPPY_2_FDC
 					floppy_sizes[cnt+0x80]=
-#endif
 						floppy_type[type].size>>1;
 			process_fd_request();
 			for ( cnt = 0; cnt < N_DRIVE; cnt++){
@@ -2899,36 +2889,44 @@
 #undef IOCTL_ALLOWED
 }
 
-static void set_base_type(int drive,int code)
-{
-	if (code > 0 && code <= NUMBER(default_drive_params)) {
-		memcpy((char *) UDP,
-		       (char *) (&default_drive_params[code].params),
-		       sizeof( struct floppy_drive_params ));
-		printk("fd%d is %s", drive, default_drive_params[code].name);
-		return;
-	} else if (!code)
-		printk("fd%d is not installed", drive);
-	else
-		printk("fd%d is unknown type %d",drive,code);
-}
-
 static void config_types(void)
 {
+	int first=1;
 	int drive;
 
-	for (drive=0; drive<N_DRIVE ; drive++){
-		/* default type for unidentifiable drives */
-		memcpy((char *) UDP, (char *) (&default_drive_params->params),
-		       sizeof( struct floppy_drive_params ));
-	}
-	printk("Floppy drive(s): ");
-	set_base_type(0, FLOPPY0_TYPE);
-	if (FLOPPY1_TYPE) {
-		printk(", ");
-		set_base_type(1, FLOPPY1_TYPE);
+	/* read drive info out of physical cmos */
+	drive=0;
+	if (!UDP->cmos )
+		UDP->cmos= FLOPPY0_TYPE;
+	drive=1;
+	if (!UDP->cmos && FLOPPY1_TYPE)
+		UDP->cmos = FLOPPY1_TYPE;
+
+	/* XXX */
+	/* additional physical CMOS drive detection should go here */
+
+	for (drive=0; drive < N_DRIVE; drive++){
+		if (UDP->cmos >= 0 && UDP->cmos <= NUMBER(default_drive_params))
+			memcpy((char *) UDP,
+			       (char *) (&default_drive_params[(int)UDP->cmos].params),
+			       sizeof(struct floppy_drive_params));
+		if (UDP->cmos){
+			if (first)
+				printk("Floppy drive(s): ");
+			else
+				printk(", ");
+			first=0;
+			if (UDP->cmos > 0 ){
+				ALLOWED_DRIVE_MASK |= 1 << drive;
+				printk("fd%d is %s", drive,
+				       default_drive_params[(int)UDP->cmos].name);
+			} else
+				printk("fd%d is unknown type %d",drive,
+				       UDP->cmos);
+		}
 	}
-	printk("\n");
+	if(!first)
+		printk("\n");
 }
 
 static int floppy_read(struct inode * inode, struct file * filp,
@@ -3204,56 +3202,128 @@
 } /* get_fdc_version */
 
 /* lilo configuration */
-static void invert_dcl(int *ints)
+
+/* we make the invert_dcl function global. One day, somebody might
+want to centralize all thinkpad related options into one lilo option,
+there are just so many thinpad related quirks! */
+void floppy_invert_dcl(int *ints,int param)
 {
 	int i;
 	
-	for (i=0; i < ARRAY_SIZE(default_drive_params); i++)
-		default_drive_params[i].params.flags |= 0x80;
+	for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
+		if (param)
+			default_drive_params[i].params.flags |= 0x80;
+		else
+			default_drive_params[i].params.flags &= ~0x80;
+	}
 	DPRINT("Configuring drives for inverted dcl\n");
 }
 
-static void allow_drives(int *ints)
+static void daring(int *ints,int param)
 {
-	if (ints[1] >= 1 ){
-		ALLOWED_DRIVE_MASK=ints[1];
-		DPRINT1("setting allowed_drive_mask to 0x%x\n", ints[1]);
-	} else
-		DPRINT("allowed_drive_mask needs a parameter\n");
+	int i;
+
+	for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
+		if (param){
+			default_drive_params[i].params.select_delay = 0;
+			default_drive_params[i].params.flags |= FD_SILENT_DCL_CLEAR;
+		} else {
+			default_drive_params[i].params.select_delay = 2;
+			default_drive_params[i].params.flags &= ~FD_SILENT_DCL_CLEAR;
+		}
+	}
+	DPRINT1("Assuming %s floppy hardware\n", param ? "standard" : "broken");
 }
 
-#ifdef  CONFIG_FLOPPY_2_FDC
-static void twofdc(int *ints)
+static void allow_drives(int *ints, int param)
 {
-	FDC2 = 0x370;
-	DPRINT("enabling second fdc at address 0x370\n");
+	ALLOWED_DRIVE_MASK=param;
+	DPRINT1("setting allowed_drive_mask to 0x%x\n", param);
 }
-#endif
 
+static void fdc2_adr(int *ints, int param)
+{
+	FDC2 = param;
+	if(param)
+		DPRINT1("enabling second fdc at address 0x%3x\n", FDC2);
+	else
+		DPRINT("disabling second fdc\n");
+}
+
+static void unex(int *ints,int param)
+{
+	print_unex = param;
+	DPRINT1("%sprinting messages for unexpected interrupts\n",
+		param ? "" : "not ");
+}
+
+static void set_cmos(int *ints, int dummy)
+{
+	int current_drive=0;
+
+	if ( ints[0] != 2 ){
+		DPRINT("wrong number of parameter for cmos\n");
+		return;
+	}
+	current_drive = ints[1];
+	if (current_drive < 0 || current_drive >= 8 ){
+		DPRINT("bad drive for set_cmos\n");
+		return;
+	}
+	if(ints[2] <= 0 || ints[2] >= NUMBER(default_drive_params)){
+		DPRINT1("bad cmos code %d\n", ints[2]);
+		return;
+	}
+	DP->cmos = ints[2];
+	DPRINT1("setting cmos code to %d\n", ints[2]);
+}
+		
 static struct param_table {
 	char *name;
-	void (*fn)(int *ints);
+	void (*fn)(int *ints, int param);
+	int def_param;
 } config_params[]={
-{ "allowed_drive_mask", allow_drives },
-#ifdef  CONFIG_FLOPPY_2_FDC
-{ "two_fdc", twofdc },
-#endif
-{ "thinkpad", invert_dcl } };
+{ "allowed_drive_mask", allow_drives, 0xff },
+{ "all_drives", allow_drives, 0xff },
+{ "asus_pci", allow_drives, 0x33 },
+
+{ "daring", daring, 1},
+
+{ "two_fdc", fdc2_adr, 0x370 },
+{ "one_fdc", fdc2_adr, 0 },
+
+{ "thinkpad", floppy_invert_dcl, 1 },
 
+{ "cmos", set_cmos, 0 },
+
+{ "unexpected_interrupts", unex, 1 },
+{ "no_unexpected_interrupts", unex, 0 },
+{ "L40SX", unex, 0 } };
+
+#define FLOPPY_SETUP
 void floppy_setup(char *str, int *ints)
 {
 	int i;
+	int param;
 	if(!str)
 		return;
 	for(i=0; i< ARRAY_SIZE(config_params); i++){
 		if (strcmp(str,config_params[i].name) == 0 ){
-			config_params[i].fn(ints);
+			if (ints[0] )
+				param = ints[1];
+			else
+				param = config_params[i].def_param;
+			config_params[i].fn(ints,param);
 			return;
 		}
 	}
-	printk("unknown floppy parameter %s\n", str);
+	DPRINT1("unknown floppy option %s\n", str);
+	DPRINT("allowed options are:");
+	for(i=0; i< ARRAY_SIZE(config_params); i++)
+		printk(" %s",config_params[i].name);
+	printk("\n");
+	DPRINT("Read linux/drivers/block/README.fd\n");
 }
-#define FLOPPY_SETUP
 
 #ifdef FD_MODULE
 static
diff -u --recursive --new-file v1.1.89/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog
--- v1.1.89/linux/drivers/char/ChangeLog	Sun Feb  5 19:31:52 1995
+++ linux/drivers/char/ChangeLog	Wed Feb  8 12:25:17 1995
@@ -1,31 +1,3 @@
-Thu Jan 26 09:02:49 1995  Theodore Y. Ts'o  (tytso@rt-11)
-
-	* serial.c (rs_init, set_serial_info, get_serial_info, rs_close):
-		Support close_wait and close_wait2 in the serial driver.
-		This is helpful for slow devices (like serial plotters) so
-		that their outputs don't get flushed upon device close.
-		This has to be configurable because normally we don't want
-		ports to be hung up for long periods of time during a
-		close when they are not connected to a device, or the
-		device is powered off.
-
-		The default is to wait 30 seconds after shutting down the
-		receiver (to prevent echo wars).  This is done by setting
-		close_wait=ASYNC_CLOSE_WAIT_NONE, close_wait2 = 3000.  If
-		XON/XOFF handshaking is used, then the 30 second timeout
-		should happen before the receiver is shutdown; this is
-		done by reversing the values of close_wait and
-		close_wait2.  In the case of a very slow device, the
-		timeouts for close_wait or close_wait2 should be lengthened.
-		If either value is set to 0, the kernel will wait forever
-		for all of the data to be transmitted.  
-
-Thu Jan 17 01:17:20 1995  Theodore Y. Ts'o  (tytso@rt-11)
-
-	* serial.c (startup, change_speed, rs_init): Add support to detect
-		the StarTech 16650 chip.  Treat it as a 16450 for now,
-		because of its FIFO bugs.
-
 Thu Jan  5 21:21:57 1995  <dhinds@allegro.stanford.edu>
 
 	* serial.c: (receive_char): Added counter to prevent infinite loop
diff -u --recursive --new-file v1.1.89/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v1.1.89/linux/drivers/char/cyclades.c	Sun Feb  5 19:31:52 1995
+++ linux/drivers/char/cyclades.c	Wed Feb  8 12:25:17 1995
@@ -1909,7 +1909,7 @@
 	    ret_val = tty_check_change(tty);
 	    if (ret_val)
 		return ret_val;
-            wait_until_sent(tty,0);
+            tty_wait_until_sent(tty,0);
             if (!arg)
                 send_break(info, HZ/4); /* 1/4 second */
             break;
@@ -1917,7 +1917,7 @@
 	    ret_val = tty_check_change(tty);
 	    if (ret_val)
 		return ret_val;
-            wait_until_sent(tty,0);
+            tty_wait_until_sent(tty,0);
             send_break(info, arg ? arg*(HZ/10) : HZ/4);
             break;
         case TIOCMBIS:
@@ -2060,7 +2060,7 @@
     if (info->flags & ASYNC_CALLOUT_ACTIVE)
 	info->callout_termios = *tty->termios;
     if (info->flags & ASYNC_INITIALIZED)
-	wait_until_sent(tty, 3000); /* 30 seconds timeout */
+	tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
     shutdown(info);
     if (tty->driver.flush_buffer)
 	tty->driver.flush_buffer(tty);
diff -u --recursive --new-file v1.1.89/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v1.1.89/linux/drivers/char/keyboard.c	Sun Feb  5 19:31:52 1995
+++ linux/drivers/char/keyboard.c	Mon Feb  6 20:46:31 1995
@@ -164,9 +164,10 @@
 {
 	int i;
 
-	for (i=0; i<0x10000; i++)
+	for (i=0; i<0x100000; i++)
 		if ((inb_p(0x64) & 0x02) == 0)
-			break;
+			return;
+	printk("Keyboard timed out\n");
 }
 
 static inline void send_cmd(unsigned char c)
@@ -1164,15 +1165,14 @@
 	bh_base[KEYBOARD_BH].routine = kbd_bh;
 	request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard");
 #ifdef __alpha__
-	/* enable keyboard interrupts */
-	outb(0x60,0x64);
-	while (inb(0x64) & 2)
-		/* nothing */;
-	outb(0x1,0x60);
-	while (inb(0x64) & 2)
-		/* nothing */;
-	if (!send_data(0xf0) || !send_data(0x01))
-		printk("Scanmode 1 change failed\n");
+	/* enable keyboard interrupts, PC/AT mode */
+	kb_wait();
+	outb(0x60,0x64);	/* write PS/2 Mode Register */
+	kb_wait();
+	outb(0x41,0x60);	/* KCC | EKI */
+	kb_wait();
+	if (!send_data(0xf0) || !send_data(0x02))
+		printk("Scanmode 2 change failed\n");
 #endif
 	mark_bh(KEYBOARD_BH);
 	enable_bh(KEYBOARD_BH);
diff -u --recursive --new-file v1.1.89/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v1.1.89/linux/drivers/char/n_tty.c	Fri Nov  4 12:39:05 1994
+++ linux/drivers/char/n_tty.c	Wed Feb  8 12:25:17 1995
@@ -666,7 +666,7 @@
 
 static void n_tty_close(struct tty_struct *tty)
 {
-	wait_until_sent(tty, 0);
+	tty_wait_until_sent(tty, 0);
 	n_tty_flush_buffer(tty);
 	if (tty->read_buf) {
 		free_page((unsigned long) tty->read_buf);
diff -u --recursive --new-file v1.1.89/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.1.89/linux/drivers/char/serial.c	Sun Feb  5 19:31:52 1995
+++ linux/drivers/char/serial.c	Wed Feb  8 12:25:17 1995
@@ -877,15 +877,7 @@
 	 * Clear the FIFO buffers and disable them
 	 * (they will be reenabled in change_speed())
 	 */
-	if (info->type == PORT_16650) {
-		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
-					     UART_FCR_CLEAR_XMIT));
-#if 0
-		info->xmit_fifo_size = 32;
-#else
-		info->xmit_fifo_size = 1;
-#endif
-	} else if (info->type == PORT_16550A) {
+	if (info->type == PORT_16550A) {
 		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
 					     UART_FCR_CLEAR_XMIT));
 		info->xmit_fifo_size = 16;
@@ -1156,18 +1148,6 @@
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
 		else
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
-	} else if (info->type == PORT_16650) {
-		/*
-		 * On the 16650, we disable the FIFOs altogether
-		 * because of a design bug in how the implement
-		 * things.  We could support it by completely changing
-		 * how we handle the interrupt driver, but not today....
-		 *
-		 * N.B.  Because there's no way to set a FIFO trigger
-		 * at 1 char, we'd probably disable at speed below
-		 * 2400 baud anyway...
-		 */
-		fcr = 0;
 	} else
 		fcr = 0;
 	
@@ -1424,8 +1404,6 @@
 	tmp.flags = info->flags;
 	tmp.baud_base = info->baud_base;
 	tmp.close_delay = info->close_delay;
-	tmp.closing_wait = info->closing_wait;
-	tmp.closing_wait2 = info->closing_wait2;
 	tmp.custom_divisor = info->custom_divisor;
 	tmp.hub6 = info->hub6;
 	memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
@@ -1493,8 +1471,6 @@
 	info->custom_divisor = new_serial.custom_divisor;
 	info->type = new_serial.type;
 	info->close_delay = new_serial.close_delay;
-	info->closing_wait = new_serial.closing_wait;
-	info->closing_wait2 = new_serial.closing_wait2;
 
 	release_region(info->port,8);
 	if (change_port || change_irq) {
@@ -1722,7 +1698,7 @@
 			retval = tty_check_change(tty);
 			if (retval)
 				return retval;
-			wait_until_sent(tty, 0);
+			tty_wait_until_sent(tty, 0);
 			if (!arg)
 				send_break(info, HZ/4);	/* 1/4 second */
 			return 0;
@@ -1730,7 +1706,7 @@
 			retval = tty_check_change(tty);
 			if (retval)
 				return retval;
-			wait_until_sent(tty, 0);
+			tty_wait_until_sent(tty, 0);
 			send_break(info, arg ? arg*(HZ/10) : HZ/4);
 			return 0;
 		case TIOCGSOFTCAR:
@@ -1895,8 +1871,6 @@
 		info->normal_termios = *tty->termios;
 	if (info->flags & ASYNC_CALLOUT_ACTIVE)
 		info->callout_termios = *tty->termios;
-	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		wait_until_sent(tty, info->closing_wait);
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1907,7 +1881,7 @@
 	info->read_status_mask &= ~UART_LSR_DR;
 	if (info->flags & ASYNC_INITIALIZED) {
 		serial_out(info, UART_IER, info->IER);
-		wait_until_sent(tty, info->closing_wait2);
+		tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
 		 * has completely drained; this is especially
@@ -2355,10 +2329,6 @@
 	if (info->flags & ASYNC_AUTO_IRQ)
 		info->irq = do_auto_irq(info);
 		
-	scratch2 = serial_in(info, UART_LCR);
-	serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-	serial_outp(info, UART_EFR, 0);	/* EFR is the same as FCR */
-	serial_outp(info, UART_LCR, scratch2);
 	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 	scratch = serial_in(info, UART_IIR) >> 6;
 	info->xmit_fifo_size = 1;
@@ -2373,15 +2343,8 @@
 			info->type = PORT_16550;
 			break;
 		case 3:
-			serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
-			if (serial_in(info, UART_EFR) == 0) {
-				info->type = PORT_16650;
-				info->xmit_fifo_size = 32;
-			} else {
-				info->type = PORT_16550A;
-				info->xmit_fifo_size = 16;
-			}
-			serial_outp(info, UART_LCR, scratch2);
+			info->type = PORT_16550A;
+			info->xmit_fifo_size = 16;
 			break;
 	}
 	if (info->type == PORT_16450) {
@@ -2495,8 +2458,6 @@
 		info->type = PORT_UNKNOWN;
 		info->custom_divisor = 0;
 		info->close_delay = 50;
-		info->closing_wait = ASYNC_CLOSING_WAIT_NONE;
-		info->closing_wait2 = 3000;
 		info->x_char = 0;
 		info->event = 0;
 		info->count = 0;
@@ -2531,9 +2492,6 @@
 				break;
 			case PORT_16550A:
 				printk(" is a 16550A\n");
-				break;
-			case PORT_16650:
-				printk(" is a 16650\n");
 				break;
 			default:
 				printk("\n");
diff -u --recursive --new-file v1.1.89/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c
--- v1.1.89/linux/drivers/char/tty_ioctl.c	Thu Jan 26 07:49:05 1995
+++ linux/drivers/char/tty_ioctl.c	Wed Feb  8 12:25:17 1995
@@ -40,7 +40,7 @@
 #define TERMIOS_WAIT	2
 #define TERMIOS_TERMIO	4
 
-void wait_until_sent(struct tty_struct * tty, int timeout)
+void tty_wait_until_sent(struct tty_struct * tty, int timeout)
 {
 	struct wait_queue wait = { current, NULL };
 
@@ -132,7 +132,7 @@
 		tty->ldisc.flush_buffer(tty);
 
 	if (opt & TERMIOS_WAIT)
-		wait_until_sent(tty, 0);
+		tty_wait_until_sent(tty, 0);
 
 	cli();
 	*tty->termios = tmp_termios;
@@ -363,7 +363,7 @@
 			retval = tty_check_change(tty);
 			if (retval)
 				return retval;
-			wait_until_sent(tty, 0);
+			tty_wait_until_sent(tty, 0);
 			if (!tty->driver.ioctl)
 				return 0;
 			tty->driver.ioctl(tty, file, cmd, arg);
diff -u --recursive --new-file v1.1.89/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v1.1.89/linux/drivers/net/3c501.c	Wed Feb  1 09:23:05 1995
+++ linux/drivers/net/3c501.c	Wed Feb  8 09:39:38 1995
@@ -61,6 +61,12 @@
     in group 224.0.0.1 and you will therefore be listening to all multicasts.
     One nv conference running over that ethernet and you can give up.
     
+    2/8/95 (invid@msen.com)
+
+    Removed calls to init_etherdev since they are no longer needed, and
+    cleaned up modularization just a bit. The driver still allows only
+    the default address for cards when loaded as a module, but that's
+    really less braindead than anyone using a 3c501 board. :)
 */
 
 static char *version =
@@ -75,6 +81,9 @@
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
 #endif
 
 #include <linux/kernel.h>
@@ -95,9 +104,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-				    unsigned long *mem_startp);
-
 /* A zero-terminated list of I/O addresses to be probed.
    The 3c501 can be at many locations, but here are the popular ones. */
 static unsigned int netcard_portlist[] =
@@ -208,6 +214,8 @@
 static int
 el1_probe1(struct device *dev, int ioaddr)
 {
+    #ifndef MODULE
+
     char *mname;		/* Vendor name */
     unsigned char station_addr[6];
     int autoirq = 0;
@@ -232,9 +240,6 @@
     /* Grab the region so we can find the another board if autoIRQ fails. */
     request_region(ioaddr, EL1_IO_EXTENT,"3c501");
 
-    if (dev == NULL)
-	dev = init_etherdev(0, sizeof(struct net_local), 0);
-
     /* We auto-IRQ by shutting off the interrupt line and letting it float
        high. */
     if (dev->irq < 2) {
@@ -290,6 +295,7 @@
     /* Setup the generic properties */
     ether_setup(dev);
 
+#endif /* !MODULE */
     return 0;
 }
 
@@ -312,9 +318,7 @@
     dev->start = 1;
 
     outb(AX_RX, AX_CMD);	/* Aux control, irq and receive enabled */
-#ifdef MODULE
     MOD_INC_USE_COUNT;
-#endif       
     return 0;
 }
 
@@ -618,9 +622,7 @@
     outb(AX_RESET, AX_CMD);	/* Reset the chip */
     irq2dev_map[dev->irq] = 0;
 
-#ifdef MODULE
     MOD_DEC_USE_COUNT;
-#endif    
     return 0;
 }
 
diff -u --recursive --new-file v1.1.89/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.1.89/linux/drivers/net/Space.c	Wed Feb  1 09:23:05 1995
+++ linux/drivers/net/Space.c	Tue Feb  7 17:35:26 1995
@@ -115,7 +115,7 @@
 #ifdef CONFIG_EWRK3             /* DEC EtherWORKS 3 */
         && ewrk3_probe(dev)
 #endif
-#ifdef CONFIG_DE4X5             /* DEC DE425, DE434, DE435 adapters */
+#ifdef CONFIG_DE4x5             /* DEC DE425, DE434, DE435 adapters */
         && de4x5_probe(dev)
 #endif
 #ifdef CONFIG_APRICOT		/* Apricot I82596 */
diff -u --recursive --new-file v1.1.89/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v1.1.89/linux/drivers/net/de600.c	Thu Jan 26 07:49:05 1995
+++ linux/drivers/net/de600.c	Tue Feb  7 11:43:23 1995
@@ -686,10 +686,12 @@
 		return ENODEV;
 	}
 
+#if 0 /* Not yet */
 	if (check_region(DE600_IO, 3)) {
 		printk(", port 0x%x busy\n", DE600_IO);
 		return EBUSY;
 	}
+#endif
 	request_region(DE600_IO, 3, "de600");
 
 	printk(", Ethernet Address: %02X", dev->dev_addr[0]);
@@ -840,10 +842,7 @@
 void
 cleanup_module(void)
 {
-	if (MOD_IN_USE)
-		printk("de600: device busy, remove delayed\n");
-	else
-		unregister_netdev(&de600_dev);
+	unregister_netdev(&de600_dev);
 	release_region(DE600_IO, 3);
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.1.89/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v1.1.89/linux/drivers/net/de620.c	Thu Jan 26 07:49:05 1995
+++ linux/drivers/net/de620.c	Tue Feb  7 11:43:23 1995
@@ -824,10 +824,12 @@
 		return ENODEV;
 	}
 
+#if 0 /* Not yet */
 	if (check_region(DE620_IO, 3)) {
 		printk(", port 0x%x busy\n", DE620_IO);
 		return EBUSY;
 	}
+#endif
 	request_region(DE620_IO, 3, "de620");
 
 	/* else, got it! */
@@ -987,10 +989,7 @@
 void
 cleanup_module(void)
 {
-	if (MOD_IN_USE)
-		printk("de620: device busy, remove delayed\n");
-	else
-		unregister_netdev(&de620_dev);
+	unregister_netdev(&de620_dev);
 	release_region(DE620_IO, 3);
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.1.89/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v1.1.89/linux/drivers/net/ni52.c	Sun Feb  5 19:31:53 1995
+++ linux/drivers/net/ni52.c	Mon Feb  6 20:42:52 1995
@@ -11,7 +11,7 @@
  * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
  * 
  * If you find a bug, please report me:
- *   The kernelpanic output and any kmsg from the ni52 driver
+ *   The kernel panic output and any kmsg from the ni52 driver
  *   the ni5210-driver-version and the linux-kernel version 
  *   how many shared memory (memsize) on the netcard, 
  *   bootprom: yes/no, base_addr, mem_start
@@ -55,10 +55,10 @@
  *
  * 19.Sep.94: Added Multicast support (not tested yet) (MH)
  * 
- * 18.Sep.94: Workarround for 'EL-Bug'. Removed flexible RBD-handling. 
+ * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling. 
  *            Now, every RFD has exact one RBD. (MH)
  *
- * 14.Sep.94: added promiscous mode, a few cleanups (MH)
+ * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
  *
  * 19.Aug.94: changed request_irq() parameter (MH)
  * 
@@ -108,7 +108,7 @@
 
   * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
   * --------------- in a different (more stable?) mode. Only in this mode it's
-  *                 possbile to configure the driver with 'NO_NOPCOMMANDS'
+  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
 
 sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
 sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
@@ -272,7 +272,7 @@
     ni_attn586();
     DELAY(2);	/* wait a while... */
 
-    if(p->iscp->busy) /* i82586 clears 'busy' after succesful init */
+    if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
       return 0;
   }
   return 1;
@@ -611,7 +611,7 @@
       if(len < num_addrs)
       {
         num_addrs = len;
-        printk("%s: Sorry, can only apply %d MC-Addresse(s).\n",dev->name,num_addrs);
+        printk("%s: Sorry, can only apply %d MC-Address(es).\n",dev->name,num_addrs);
       }
       mc_cmd = (struct mcsetup_cmd_struct *) ptr;
       mc_cmd->cmd_status = 0;
@@ -845,7 +845,7 @@
   p->stats.rx_errors++;
 
   WAIT_4_SCB_CMD();    /* wait for the last cmd */
-  p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no ressource'-state .. abort it now. */
+  p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
   ni_attn586(); 
   WAIT_4_SCB_CMD();    /* wait for accept cmd. */
 
@@ -1081,7 +1081,7 @@
 {
   if(!dev->start && !num_addrs)
   {
-    printk("%s: Can't apply promiscous/multicastmode to a not running interface.\n",dev->name);
+    printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name);
     return;
   }
 
diff -u --recursive --new-file v1.1.89/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v1.1.89/linux/drivers/net/plip.c	Thu Jan 26 07:49:06 1995
+++ linux/drivers/net/plip.c	Wed Feb  8 11:52:02 1995
@@ -1,5 +1,5 @@
-/* $Id: plip.c,v 1.7 1994/12/16 06:20:02 gniibe Exp $ */
-/* plip.c: A parallel port "network" driver for linux. */
+/* $Id: plip.c,v 1.10 1995/02/08 05:47:12 gniibe Exp $ */
+/* PLIP: A parallel port "network" driver for Linux. */
 /* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
 /*
  * Authors:	Donald Becker,  <becker@super.org>
@@ -9,12 +9,8 @@
  *		Peter Bauer, <100136.3530@compuserve.com>
  *		Niibe Yutaka, <gniibe@mri.co.jp>
  *
- *		This is the all improved state based PLIP that Niibe Yutaka has contributed.
- *
- *		Modularization by Alan Cox. I also added the plipconfig program to tune the timeouts
- *		and ifmap support for funny serial port settings or setting odd values using the 
- *		modular plip. I also took the panic() calls out. I don't like panic - especially when
- *		it can be avoided.
+ *		Modularization and ifreq/ifmap support by Alan Cox.
+ *		Rewritten by Niibe Yutaka.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -25,14 +21,18 @@
 /*
  * Original version and the name 'PLIP' from Donald Becker <becker@super.org>
  * inspired by Russ Nelson's parallel port packet driver.
+ *
+ * NOTE:
+ *     Tanabe Hiroyasu had changed the protocol, and it was in Linux v1.0.
+ *     Because of the necessity to communicate to DOS machines with the
+ *     Crynwr packet driver, Peter Bauer changed the protocol again
+ *     back to original protocol.
+ *
+ *     This version follows original PLIP protocol. 
+ *     So, this PLIP can't communicate the PLIP of Linux v1.0.
  */
 
-static char *version =
-    "NET3 "
-#ifdef MODULE
-    "MODULAR "    
-#endif    
-    "PLIP $Revision: 1.7 $ gniibe@mri.co.jp\n";
+static char *version = "NET3 PLIP version 2.0 gniibe@mri.co.jp\n";
 
 /*
   Sources:
@@ -40,17 +40,19 @@
 	"parallel.asm" parallel port packet driver.
 
   The "Crynwr" parallel port standard specifies the following protocol:
-   send header nibble '8'
-   count-low octet
-   count-high octet
-   ... data octets
-   checksum octet
+    Trigger by sending '0x08' (this cause interrupt on other end)
+    count-low octet
+    count-high octet
+    ... data octets
+    checksum octet
   Each octet is sent as <wait for rx. '0x1?'> <send 0x10+(octet&0x0F)>
 			<wait for rx. '0x0?'> <send 0x00+((octet>>4)&0x0F)>
 
-The cable used is a de facto standard parallel null cable -- sold as
-a "LapLink" cable by various places.  You'll need a 10-conductor cable to
-make one yourself.  The wiring is:
+  The packet is encapsulated as if it were ethernet.
+
+  The cable used is a de facto standard parallel null cable -- sold as
+  a "LapLink" cable by various places.  You'll need a 12-conductor cable to
+  make one yourself.  The wiring is:
     SLCTIN	17 - 17
     GROUND	25 - 25
     D0->ERROR	2 - 15		15 - 2
@@ -67,6 +69,9 @@
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
 #endif
 
 #include <linux/kernel.h>
@@ -94,9 +99,9 @@
 #include <asm/bitops.h>
 #include <asm/irq.h>
 
-/* use 0 for production, 1 for verification, >2 for debug */
+/* Use 0 for production, 1 for verification, >2 for debug */
 #ifndef NET_DEBUG
-#define NET_DEBUG 3
+#define NET_DEBUG 1
 #endif
 static unsigned int net_debug = NET_DEBUG;
 
@@ -107,807 +112,903 @@
 #define PLIP_TRIGGER_WAIT	 500
 
 /* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */
-#define PLIP_NIBBLE_WAIT        5000
+#define PLIP_NIBBLE_WAIT        3000
 
+#define PAR_INTR_ON		(LP_PINITP|LP_PSELECP|LP_PINTEN)
+#define PAR_INTR_OFF		(LP_PINITP|LP_PSELECP)
 #define PAR_DATA(dev)		((dev)->base_addr+0)
 #define PAR_STATUS(dev)		((dev)->base_addr+1)
 #define PAR_CONTROL(dev)	((dev)->base_addr+2)
 
-/* Index to functions, as function prototypes. */
+/* Bottom halfs */
+static void plip_kick_bh(struct device *dev);
+static void plip_bh(struct device *dev);
+
+/* Interrupt handler */
+static void plip_interrupt(int irq, struct pt_regs *regs);
+
+/* Functions for DEV methods */
+static int plip_rebuild_header(void *buff, struct device *dev,
+			       unsigned long raddr, struct sk_buff *skb);
 static int plip_tx_packet(struct sk_buff *skb, struct device *dev);
 static int plip_open(struct device *dev);
 static int plip_close(struct device *dev);
 static struct enet_statistics *plip_get_stats(struct device *dev);
-static int plip_rebuild_header(void *buff, struct device *dev,
-			       unsigned long raddr, struct sk_buff *skb);
-static void plip_kick_bh(struct device *dev);
-static void plip_bh(struct device *dev);
+static int plip_config(struct device *dev, struct ifmap *map);
+static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 
 enum plip_connection_state {
-    PLIP_CN_NONE=0,
-    PLIP_CN_RECEIVE,
-    PLIP_CN_SEND,
-    PLIP_CN_CLOSING,
-    PLIP_CN_ERROR
+	PLIP_CN_NONE=0,
+	PLIP_CN_RECEIVE,
+	PLIP_CN_SEND,
+	PLIP_CN_CLOSING,
+	PLIP_CN_ERROR
 };
 
 enum plip_packet_state {
-    PLIP_PK_DONE=0,
-    PLIP_PK_TRIGGER,
-    PLIP_PK_LENGTH_LSB,
-    PLIP_PK_LENGTH_MSB,
-    PLIP_PK_DATA,
-    PLIP_PK_CHECKSUM
+	PLIP_PK_DONE=0,
+	PLIP_PK_TRIGGER,
+	PLIP_PK_LENGTH_LSB,
+	PLIP_PK_LENGTH_MSB,
+	PLIP_PK_DATA,
+	PLIP_PK_CHECKSUM
 };
 
 enum plip_nibble_state {
-    PLIP_NB_BEGIN,
-    PLIP_NB_1,
-    PLIP_NB_2,
+	PLIP_NB_BEGIN,
+	PLIP_NB_1,
+	PLIP_NB_2,
 };
 
-#define PLIP_STATE_STRING(x) \
-    (((x) == PLIP_PK_DONE)?"0":\
-     ((x) == PLIP_PK_TRIGGER)?"t":\
-     ((x) == PLIP_PK_LENGTH_LSB)?"l":\
-     ((x) == PLIP_PK_LENGTH_MSB)?"m":\
-     ((x) == PLIP_PK_DATA)?"d":\
-     ((x) == PLIP_PK_CHECKSUM)?"s":"B")
-
 struct plip_local {
-    enum plip_packet_state state;
-    enum plip_nibble_state nibble;
-    unsigned short length;
-    unsigned short byte;
-    unsigned char  checksum;
-    unsigned char  data;
-    struct sk_buff *skb;
+	enum plip_packet_state state;
+	enum plip_nibble_state nibble;
+	unsigned short length;
+	unsigned short byte;
+	unsigned char  checksum;
+	unsigned char  data;
+	struct sk_buff *skb;
 };
 
 struct net_local {
-    struct enet_statistics e;
-    struct tq_struct immediate;
-    struct tq_struct deferred;
-    struct plip_local snd_data;
-    struct plip_local rcv_data;
-    unsigned long  trigger_us;
-    unsigned long  nibble_us;
-    unsigned long  unit_us;
-    enum plip_connection_state connection;
-    unsigned short timeout_count;
+	struct enet_statistics enet_stats;
+	struct tq_struct immediate;
+	struct tq_struct deferred;
+	struct plip_local snd_data;
+	struct plip_local rcv_data;
+	unsigned long  trigger;
+	unsigned long  nibble;
+	unsigned long  unit;
+	enum plip_connection_state connection;
+	unsigned short timeout_count;
+	char is_deferred;
 };
-
-/* Routines used internally. */
-static void plip_device_clear(struct device *dev);
-static void plip_interrupt(int irq, struct pt_regs *regs);
-
-static int plip_error(struct device *dev);
-static int plip_receive_packet(struct device *dev);
-static int plip_send_packet(struct device *dev);
-static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static int plip_config(struct device *dev, struct ifmap *map);
 
+/* Entry point of PLIP driver.
+   Probe the hardware, and register/initialize the driver. */
 int
 plip_init(struct device *dev)
 {
-    struct net_local *nl;
+	struct net_local *nl;
 
-    /* Check that there is something at base_addr. */
-    outb(LP_PINITP, PAR_CONTROL(dev));
-    outb(0x00, PAR_DATA(dev));
-    if (inb(PAR_DATA(dev)) != 0x00)
-	return -ENODEV;
+	/* Check region before the probe */
+	if (check_region(PAR_DATA(dev), 3) < 0)
+		return -ENODEV;
+
+	/* Check that there is something at base_addr. */
+	outb(0, PAR_DATA(dev));
+	udelay(1000);
+	if (inb(PAR_DATA(dev)) != 0)
+		return -ENODEV;
 
-    /* Alpha testers must have the version number to report bugs. */
-    if (net_debug)
 	printk(version);
-
-    if (dev->irq) {
-	printk("%s: configured for parallel port at %#3x, IRQ %d.\n",
-	       dev->name, dev->base_addr, dev->irq);
-    } else {
-	printk("%s: configured for parallel port at %#3x",
-	       dev->name, dev->base_addr);
+	printk("%s: Parallel port at %#3lx, ", dev->name, dev->base_addr);
+	if (dev->irq) {
+		printk("using assigned IRQ %d.\n", dev->irq);
+	} else {
+		int irq = 0;
 #ifdef MODULE
-	/* autoirq doesn't work :(, but we can set it by ifconfig */
+		/* dev->irq==0 means autoprobe, but we don't try to do so
+		   with module.  We can change it by ifconfig */
 #else
-	autoirq_setup(0);
-	outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-	outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-	outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-	dev->irq = autoirq_report(1);
+		unsigned int irqs = probe_irq_on();
+
+		outb(0x00, PAR_CONTROL(dev));
+		udelay(1000);
+		outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+		outb(PAR_INTR_ON, PAR_CONTROL(dev));
+		outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+		udelay(1000);
+		irq = probe_irq_off(irqs);
 #endif
-	if (dev->irq)
-	    printk(", probed IRQ %d.\n", dev->irq);
-	else {
-	    printk(", failed to detect IRQ line.\n");
-	    return -ENODEV;
-	}
-    }
-
-    request_region(PAR_DATA(dev), 3,"plip");
-
-    /* Fill in the generic fields of the device structure. */
-    ether_setup(dev);
-
-    /* And, override parts of it */
-    dev->rebuild_header 	= plip_rebuild_header;
-    dev->hard_start_xmit	= plip_tx_packet;
-    dev->open			= plip_open;
-    dev->stop			= plip_close;
-    dev->get_stats 		= plip_get_stats;
-    dev->set_config		= plip_config;
-    dev->do_ioctl		= plip_ioctl;
-    dev->flags			= IFF_POINTOPOINT;
-
-    /* Set private structure */
-    dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
-    memset(dev->priv, 0, sizeof(struct net_local));
-    nl = (struct net_local *) dev->priv;
-    
-    /* initialize constants */
-    nl->trigger_us	= PLIP_TRIGGER_WAIT;
-    nl->nibble_us	= PLIP_NIBBLE_WAIT;
-    nl->unit_us		= PLIP_DELAY_UNIT;
-
-    /* initialize task queue structures */
-    nl->immediate.next = &tq_last;
-    nl->immediate.sync = 0;
-    nl->immediate.routine = (void *)(void *)plip_bh;
-    nl->immediate.data = dev;
-
-    nl->deferred.next = &tq_last;
-    nl->deferred.sync = 0;
-    nl->deferred.routine = (void *)(void *)plip_kick_bh;
-    nl->deferred.data = dev;
+		if (irq > 0) {
+			dev->irq = irq;
+			printk("using probed IRQ %d.\n", dev->irq);
+		} else
+			printk("failed to detect IRQ(%d) --"
+			       " Please set IRQ by ifconfig.\n", irq);
+	}
+
+	request_region(PAR_DATA(dev), 3, dev->name);
 
-    return 0;
+	/* Fill in the generic fields of the device structure. */
+	ether_setup(dev);
+
+	/* Then, override parts of it */
+	dev->rebuild_header 	= plip_rebuild_header;
+	dev->hard_start_xmit	= plip_tx_packet;
+	dev->open		= plip_open;
+	dev->stop		= plip_close;
+	dev->get_stats 		= plip_get_stats;
+	dev->set_config		= plip_config;
+	dev->do_ioctl		= plip_ioctl;
+	dev->flags	        = IFF_POINTOPOINT;
+
+	/* Set the private structure */
+	dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct net_local));
+	nl = (struct net_local *) dev->priv;
+
+	/* Initialize constants */
+	nl->trigger	= PLIP_TRIGGER_WAIT;
+	nl->nibble	= PLIP_NIBBLE_WAIT;
+	nl->unit	= PLIP_DELAY_UNIT;
+
+	/* Initialize task queue structures */
+	nl->immediate.next = &tq_last;
+	nl->immediate.sync = 0;
+	nl->immediate.routine = (void *)(void *)plip_bh;
+	nl->immediate.data = dev;
+
+	nl->deferred.next = &tq_last;
+	nl->deferred.sync = 0;
+	nl->deferred.routine = (void *)(void *)plip_kick_bh;
+	nl->deferred.data = dev;
+
+	return 0;
 }
 
+/* Bottom half handler for the delayed request.
+   This routine is kicked by do_timer().
+   Request `plip_bh' to be invoked. */
 static void
 plip_kick_bh(struct device *dev)
 {
-    struct net_local *nl = (struct net_local *)dev->priv;
+	struct net_local *nl = (struct net_local *)dev->priv;
 
-    if (nl->connection == PLIP_CN_NONE)
-	return;
-    queue_task(&nl->immediate, &tq_immediate);
-    mark_bh(IMMEDIATE_BH);
-    return;
+	if (nl->is_deferred) {
+		queue_task(&nl->immediate, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
 }
 
+/* Forward declarations of internal routines */
+static int plip_none(struct device *, struct net_local *,
+		     struct plip_local *, struct plip_local *);
+static int plip_receive_packet(struct device *, struct net_local *,
+			       struct plip_local *, struct plip_local *);
+static int plip_send_packet(struct device *, struct net_local *,
+			    struct plip_local *, struct plip_local *);
+static int plip_connection_close(struct device *, struct net_local *,
+				 struct plip_local *, struct plip_local *);
+static int plip_error(struct device *, struct net_local *,
+		      struct plip_local *, struct plip_local *);
+static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+				 struct plip_local *snd,
+				 struct plip_local *rcv,
+				 int error);
+
+#define OK        0
+#define TIMEOUT   1
+#define ERROR     2
+
+typedef int (*plip_func)(struct device *dev, struct net_local *nl,
+			 struct plip_local *snd, struct plip_local *rcv);
+
+static plip_func connection_state_table[] =
+{
+	plip_none,
+	plip_receive_packet,
+	plip_send_packet,
+	plip_connection_close,
+	plip_error
+};
+
+/* Bottom half handler of PLIP. */
 static void
 plip_bh(struct device *dev)
 {
-    struct net_local *nl = (struct net_local *)dev->priv;
-    struct enet_statistics *stats = (struct enet_statistics *) dev->priv;
-    struct plip_local *rcv = &nl->rcv_data;
-    struct plip_local *snd = &nl->snd_data;
-    int result, timeout=0;
-    unsigned char *s;
-    unsigned char c0;
-    struct sk_buff *skb;
-
-    while (!timeout) {
-	cli();
-	switch (nl->connection) {
-	case PLIP_CN_NONE:
-	    sti();
-	    return;
-
-	case PLIP_CN_RECEIVE:
-	    sti();
-	    disable_irq(dev->irq);
-	    outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-	    outb(0x01, PAR_DATA(dev));   /* send ACK */
-	    dev->interrupt = 0;
-	    result = plip_receive_packet(dev);
-	    if (result == 0) { /* success */
-		outb (0x00, PAR_DATA(dev));
-		skb = rcv->skb;
-		rcv->skb = NULL;
-		stats->rx_packets++;
-		netif_rx(skb);
-		if (snd->state != PLIP_PK_DONE) {
-		    nl->connection = PLIP_CN_SEND;
-		    outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-		    enable_irq(dev->irq);
-		} else {
-		    nl->connection = PLIP_CN_NONE;
-		    outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-		    enable_irq(dev->irq);
-		    return;
-		}
-	    } else if (result == -1) { /* failure */
-		outb(0x00, PAR_DATA(dev));
-		if (rcv->skb)
-		    dev_kfree_skb(rcv->skb, FREE_WRITE);
-		rcv->state = PLIP_PK_DONE;
-		rcv->skb = NULL;
-		if (snd->skb)
-		    dev_kfree_skb(snd->skb, FREE_WRITE);
-		snd->state = PLIP_PK_DONE;
-		snd->skb = NULL;
-		dev->tbusy = 1;
-		nl->connection = PLIP_CN_ERROR;
-	    } else
-		timeout = 1;
-	    break;
-
-	case PLIP_CN_SEND:
-	    sti();
-	    result = plip_send_packet(dev);
-	    if (result == -1) /* interrupted */
-		break;
-	    if (result == 0) { /* success */
-		outb (0x00, PAR_DATA(dev));
-		snd->state = PLIP_PK_DONE;
-		snd->skb = NULL;
-		nl->connection = PLIP_CN_CLOSING;
-		queue_task(&nl->deferred, &tq_timer);
-		outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-		enable_irq(dev->irq);
-		return;
-	    } else
-		timeout = 1;
-	    break;
-
-	case PLIP_CN_CLOSING:
-	    sti();
-	    nl->connection = PLIP_CN_NONE;
-	    mark_bh(NET_BH);
-	    dev->tbusy = 0;
-	    return;
-
-	case PLIP_CN_ERROR:
-	    sti();
-	    result = plip_error(dev);
-	    if (result == 0) {
-		nl->connection = PLIP_CN_NONE;
-		dev->tbusy = 0;
-		outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-		enable_irq(dev->irq);
-		return;
-	    } else {
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct plip_local *snd = &nl->snd_data;
+	struct plip_local *rcv = &nl->rcv_data;
+	plip_func f;
+	int r;
+
+	nl->is_deferred = 0;
+	f = connection_state_table[nl->connection];
+	if ((r = (*f)(dev, nl, snd, rcv)) != OK
+	    && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
+		nl->is_deferred = 1;
 		queue_task(&nl->deferred, &tq_timer);
-		return;
-	    }
-	    break;
 	}
-    }
+}
 
-    /* timeout */
-    if (++nl->timeout_count > 3) { /* cable problem? */
-	c0 = inb(PAR_STATUS(dev));
+static int
+plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+		      struct plip_local *snd, struct plip_local *rcv,
+		      int error)
+{
+	unsigned char c0;
 
+	cli();
 	if (nl->connection == PLIP_CN_SEND) {
-	    stats->tx_errors++;
-	    stats->tx_aborted_errors++;
-	    s =  PLIP_STATE_STRING(snd->state);
-	    if (net_debug > 1)
-		printk("%s: transmit timeout(%s,%02x)... reset interface.\n",
-		       dev->name, s, (unsigned int)c0);
-	    if (snd->skb)
-		dev_kfree_skb(snd->skb, FREE_WRITE);
+
+		if (error != ERROR) { /* Timeout */
+			nl->timeout_count++;
+			if ((snd->state == PLIP_PK_TRIGGER
+			     && nl->timeout_count <= 10)
+			    || nl->timeout_count <= 3) {
+				sti();
+				/* Try again later */
+				return TIMEOUT;
+			}
+			c0 = inb(PAR_STATUS(dev));
+			printk("%s: transmit timeout(%d,%02x)\n",
+			       dev->name, snd->state, c0);
+		}
+		nl->enet_stats.tx_errors++;
+		nl->enet_stats.tx_aborted_errors++;
 	} else if (nl->connection == PLIP_CN_RECEIVE) {
-	    stats->rx_dropped++;
-	    s =  PLIP_STATE_STRING(rcv->state);
-	    if (net_debug > 1)
-		printk("%s: receive timeout(%s,%02x)... reset interface.\n",
-		       dev->name, s, (unsigned int)c0);
-	    if (rcv->skb)
-		dev_kfree_skb(rcv->skb, FREE_WRITE);
+		if (rcv->state == PLIP_PK_TRIGGER) {
+			/* Transmission was interrupted. */
+			sti();
+			return OK;
+		}
+		if (error != ERROR) { /* Timeout */
+			if (++nl->timeout_count <= 3) {
+				sti();
+				/* Try again later */
+				return TIMEOUT;
+			}
+			c0 = inb(PAR_STATUS(dev));
+			printk("%s: receive timeout(%d,%02x)\n",
+			       dev->name, rcv->state, c0);
+		}
+		nl->enet_stats.rx_dropped++;
+	}
+	rcv->state = PLIP_PK_DONE;
+	if (rcv->skb) {
+		rcv->skb->free = 1;
+		kfree_skb(rcv->skb, FREE_READ);
+		rcv->skb = NULL;
+	}
+	snd->state = PLIP_PK_DONE;
+	if (snd->skb) {
+		dev_kfree_skb(snd->skb, FREE_WRITE);
+		snd->skb = NULL;
 	}
 	disable_irq(dev->irq);
-	outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
+	outb(PAR_INTR_OFF, PAR_CONTROL(dev));
 	dev->tbusy = 1;
 	nl->connection = PLIP_CN_ERROR;
 	outb(0x00, PAR_DATA(dev));
-    }
+	sti();
 
-    queue_task(&nl->deferred, &tq_timer);
-    return;
+	return TIMEOUT;
 }
 
 static int
-plip_tx_packet(struct sk_buff *skb, struct device *dev)
+plip_none(struct device *dev, struct net_local *nl,
+	  struct plip_local *snd, struct plip_local *rcv)
 {
-    struct net_local *nl = (struct net_local *)dev->priv;
-    struct plip_local *snd = &nl->snd_data;
+	return OK;
+}
 
-    if (dev->tbusy)
-	return 1;
+/* PLIP_RECEIVE --- receive a byte(two nibbles)
+   Returns OK on success, TIMEOUT on timeout */
+inline static int
+plip_receive(unsigned short nibble_timeout, unsigned short unit,
+	     unsigned short status_addr, unsigned short data_addr,
+	     enum plip_nibble_state *ns_p, unsigned char *data_p)
+{
+	unsigned char c0, c1;
+	unsigned int cx;
 
-    /* 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;
-    }
+	switch (*ns_p) {
+	case PLIP_NB_BEGIN:
+		cx = nibble_timeout;
+		while (1) {
+			c0 = inb(status_addr);
+			udelay(unit);
+			if ((c0 & 0x80) == 0) {
+				c1 = inb(status_addr);
+				if (c0 == c1)
+					break;
+			}
+			if (--cx == 0)
+				return TIMEOUT;
+		}
+		*data_p = (c0 >> 3) & 0x0f;
+		outb(0x10, data_addr); /* send ACK */
+		*ns_p = PLIP_NB_1;
+
+	case PLIP_NB_1:
+		cx = nibble_timeout;
+		while (1) {
+			c0 = inb(status_addr);
+			udelay(unit);
+			if (c0 & 0x80) {
+				c1 = inb(status_addr);
+				if (c0 == c1)
+					break;
+			}
+			if (--cx == 0)
+				return TIMEOUT;
+		}
+		*data_p |= (c0 << 1) & 0xf0;
+		outb(0x00, data_addr); /* send ACK */
+		*ns_p = PLIP_NB_BEGIN;
+		return OK;
 
-    if (set_bit(0, (void*)&dev->tbusy) != 0) {
-	printk("%s: Transmitter access conflict.\n", dev->name);
-	return 1;
-    }
+	case PLIP_NB_2:
+	}
+}
 
-    if (skb->len > dev->mtu) {
-	printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
-	dev->tbusy = 0;
-	return 0;
-    }
+/* PLIP_RECEIVE_PACKET --- receive a packet */
+static int
+plip_receive_packet(struct device *dev, struct net_local *nl,
+		    struct plip_local *snd, struct plip_local *rcv)
+{
+	unsigned short data_addr = PAR_DATA(dev),
+	               status_addr = PAR_STATUS(dev);
+	unsigned short nibble_timeout = nl->nibble, unit = nl->unit;
+	unsigned char *lbuf;
 
-    snd->state = PLIP_PK_TRIGGER;
-    dev->trans_start = jiffies;
+	switch (rcv->state) {
+	case PLIP_PK_TRIGGER:
+		disable_irq(dev->irq);
+		outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+		dev->interrupt = 0;
+		outb(0x01, PAR_DATA(dev)); /* send ACK */
+		if (net_debug > 2)
+			printk("%s: receive start\n", dev->name);
+		rcv->state = PLIP_PK_LENGTH_LSB;
+		rcv->nibble = PLIP_NB_BEGIN;
 
-    snd->skb = skb;
-    snd->length = skb->len;
+	case PLIP_PK_LENGTH_LSB:
+		if (snd->state != PLIP_PK_DONE) {
+			if (plip_receive(nl->trigger, unit,
+					 status_addr, data_addr, &rcv->nibble,
+					 (unsigned char *)&rcv->length)) {
+				/* collision, here dev->tbusy == 1 */
+				rcv->state = PLIP_PK_DONE;
+				nl->is_deferred = 1;
+				nl->connection = PLIP_CN_SEND;
+				queue_task(&nl->deferred, &tq_timer);
+				outb(PAR_INTR_ON, PAR_CONTROL(dev));
+				enable_irq(dev->irq);
+				return OK;
+			}
+		} else {
+			if (plip_receive(nibble_timeout, unit,
+					 status_addr, data_addr, &rcv->nibble,
+					 (unsigned char *)&rcv->length))
+				return TIMEOUT;
+		}
+		rcv->state = PLIP_PK_LENGTH_MSB;
 
-    cli();
-    if (nl->connection == PLIP_CN_NONE) {
-	nl->connection = PLIP_CN_SEND;
-	nl->timeout_count = 0;
-    }
-    sti();
-    queue_task(&nl->immediate, &tq_immediate);
-    mark_bh(IMMEDIATE_BH);
+	case PLIP_PK_LENGTH_MSB:
+		if (plip_receive(nibble_timeout, unit,
+				 status_addr, data_addr, &rcv->nibble,
+				 (unsigned char *)&rcv->length+1))
+			return TIMEOUT;
+		if (rcv->length > dev->mtu || rcv->length < 8) {
+			printk("%s: bogus packet size %d.\n", dev->name, rcv->length);
+			return ERROR;
+		}
+		/* Malloc up new buffer. */
+		rcv->skb = alloc_skb(rcv->length, GFP_ATOMIC);
+		if (rcv->skb == NULL) {
+			printk("%s: Memory squeeze.\n", dev->name);
+			return ERROR;
+		}
+		rcv->skb->len = rcv->length;
+		rcv->skb->dev = dev;
+		rcv->state = PLIP_PK_DATA;
+		rcv->byte = 0;
+		rcv->checksum = 0;
+
+	case PLIP_PK_DATA:
+		lbuf = rcv->skb->data;
+		do {
+			if (plip_receive(nibble_timeout, unit,
+					 status_addr, data_addr,
+					 &rcv->nibble, &lbuf[rcv->byte]))
+				return TIMEOUT;
+			rcv->checksum += lbuf[rcv->byte];
+		} while (++rcv->byte < rcv->length);
+		rcv->state = PLIP_PK_CHECKSUM;
+
+	case PLIP_PK_CHECKSUM:
+		if (plip_receive(nibble_timeout, unit, status_addr,
+				 data_addr, &rcv->nibble, &rcv->data))
+			return TIMEOUT;
+		if (rcv->data != rcv->checksum) {
+			nl->enet_stats.rx_crc_errors++;
+			if (net_debug)
+				printk("%s: checksum error\n", dev->name);
+			return ERROR;
+		}
+		rcv->state = PLIP_PK_DONE;
 
-    return 0;
-}
+	case PLIP_PK_DONE:
+		/* Inform the upper layer for the arrival of a packet. */
+		netif_rx(rcv->skb);
+		nl->enet_stats.rx_packets++;
+		rcv->skb = NULL;
+		if (net_debug > 2)
+			printk("%s: receive end\n", dev->name);
 
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
+		/* Close the connection. */
+		outb (0x00, PAR_DATA(dev));
+		cli();
+		if (snd->state != PLIP_PK_DONE) {
+			nl->connection = PLIP_CN_SEND;
+			sti();
+			queue_task(&nl->immediate, &tq_immediate);
+			outb(PAR_INTR_ON, PAR_CONTROL(dev));
+			enable_irq(dev->irq);
+			return OK;
+		} else {
+			nl->connection = PLIP_CN_NONE;
+			sti();
+			outb(PAR_INTR_ON, PAR_CONTROL(dev));
+			enable_irq(dev->irq);
+			return OK;
+		}
+	}
+	return OK;
+}
 
-   This routine gets exclusive access to the parallel port by allocating
-   its IRQ line.
- */
-static int
-plip_open(struct device *dev)
+/* PLIP_SEND --- send a byte (two nibbles) 
+   Returns OK on success, TIMEOUT when timeout    */
+inline static int
+plip_send(unsigned short nibble_timeout, unsigned short unit,
+	  unsigned short status_addr, unsigned short data_addr,
+	  enum plip_nibble_state *ns_p, unsigned char data)
 {
-    int i;
+	unsigned char c0;
+	unsigned int cx;
 
-    cli();
-    if (request_irq(dev->irq , plip_interrupt, 0, "plip") != 0) {
-	sti();
-	printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
-	return -EAGAIN;
-    }
-    irq2dev_map[dev->irq] = dev;
-    sti();
-    /* enable rx interrupt. */
-    outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-    plip_device_clear(dev);
-
-    /* Fill in the MAC-level header. */
-    for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
-	dev->dev_addr[i] = 0xfc;
-    memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(unsigned long));
+	switch (*ns_p) {
+	case PLIP_NB_BEGIN:
+		outb((data & 0x0f), data_addr);
+		*ns_p = PLIP_NB_1;
+
+	case PLIP_NB_1:
+		outb(0x10 | (data & 0x0f), data_addr);
+		cx = nibble_timeout;
+		while (1) {
+			c0 = inb(status_addr);
+			if ((c0 & 0x80) == 0) 
+				break;
+			if (--cx == 0)
+				return TIMEOUT;
+			udelay(unit);
+		}
+		outb(0x10 | (data >> 4), data_addr);
+		*ns_p = PLIP_NB_2;
 
-    dev->start = 1;
-#ifdef MODULE
-    MOD_INC_USE_COUNT;
-#endif        
-    return 0;
+	case PLIP_NB_2:
+		outb((data >> 4), data_addr);
+		cx = nibble_timeout;
+		while (1) {
+			c0 = inb(status_addr);
+			if (c0 & 0x80)
+				break;
+			if (--cx == 0)
+				return TIMEOUT;
+			udelay(unit);
+		}
+		*ns_p = PLIP_NB_BEGIN;
+		return OK;
+	}
 }
 
-/* The inverse routine to plip_open (). */
+/* PLIP_SEND_PACKET --- send a packet */
 static int
-plip_close(struct device *dev)
+plip_send_packet(struct device *dev, struct net_local *nl,
+		 struct plip_local *snd, struct plip_local *rcv)
 {
-    dev->tbusy = 1;
-    dev->start = 0;
-    cli();
-    free_irq(dev->irq);
-    irq2dev_map[dev->irq] = NULL;
-    sti();
-    outb(0x00, PAR_DATA(dev));
-    /* release the interrupt. */
-    outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-#ifdef MODULE
-    MOD_DEC_USE_COUNT;
-#endif        
-    return 0;
+	unsigned short data_addr = PAR_DATA(dev),
+		       status_addr = PAR_STATUS(dev);
+	unsigned short nibble_timeout = nl->nibble, unit = nl->unit;
+	unsigned char *lbuf;
+	unsigned char c0;
+	unsigned int cx;
+
+	if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
+		printk("%s: send skb lost\n", dev->name);
+		snd->state = PLIP_PK_DONE;
+		snd->skb = NULL;
+		return ERROR;
+	}
+
+	switch (snd->state) {
+	case PLIP_PK_TRIGGER:
+		/* Trigger remote rx interrupt. */
+		outb(0x08, PAR_DATA(dev));
+		cx = nl->trigger;
+		while (1) {
+			udelay(nl->unit);
+			cli();
+			if (nl->connection == PLIP_CN_RECEIVE) {
+				sti();
+				/* interrupted */
+				nl->enet_stats.collisions++;
+				if (net_debug > 1)
+					printk("%s: collision.\n", dev->name);
+				return OK;
+			}
+			c0 = inb(PAR_STATUS(dev));
+			if (c0 & 0x08) {
+				disable_irq(dev->irq);
+				outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+				if (net_debug > 2)
+					printk("%s: send start\n", dev->name);
+				snd->state = PLIP_PK_LENGTH_LSB;
+				snd->nibble = PLIP_NB_BEGIN;
+				nl->timeout_count = 0;
+				sti();
+				break;
+			}
+			sti();
+			if (--cx == 0) {
+				outb(0x00, PAR_DATA(dev));
+				return TIMEOUT;
+			}
+		}
+
+	case PLIP_PK_LENGTH_LSB:
+		if (plip_send(nibble_timeout, unit, status_addr, data_addr,
+			      &snd->nibble, snd->length & 0xff))
+			return TIMEOUT;
+		snd->state = PLIP_PK_LENGTH_MSB;
+
+	case PLIP_PK_LENGTH_MSB:
+		if (plip_send(nibble_timeout, unit, status_addr, data_addr,
+			      &snd->nibble, snd->length >> 8))
+			return TIMEOUT;
+		snd->state = PLIP_PK_DATA;
+		snd->byte = 0;
+		snd->checksum = 0;
+
+	case PLIP_PK_DATA:
+		do {
+			if (plip_send(nibble_timeout, unit,
+				      status_addr, data_addr,
+				      &snd->nibble, lbuf[snd->byte]))
+				return TIMEOUT;
+			snd->checksum += lbuf[snd->byte];
+		} while (++snd->byte < snd->length);
+		snd->state = PLIP_PK_CHECKSUM;
+
+	case PLIP_PK_CHECKSUM:
+		if (plip_send(nibble_timeout, unit, status_addr, data_addr,
+			      &snd->nibble, snd->checksum))
+			return TIMEOUT;
+
+		dev_kfree_skb(snd->skb, FREE_WRITE);
+		nl->enet_stats.tx_packets++;
+		snd->state = PLIP_PK_DONE;
+
+	case PLIP_PK_DONE:
+		/* Close the connection */
+		outb (0x00, PAR_DATA(dev));
+		snd->skb = NULL;
+		if (net_debug > 2)
+			printk("%s: send end\n", dev->name);
+		nl->connection = PLIP_CN_CLOSING;
+		nl->is_deferred = 1;
+		queue_task(&nl->deferred, &tq_timer);
+		outb(PAR_INTR_ON, PAR_CONTROL(dev));
+		enable_irq(dev->irq);
+		return OK;
+	}
+	return OK;
 }
 
-static struct enet_statistics *
-plip_get_stats(struct device *dev)
+static int
+plip_connection_close(struct device *dev, struct net_local *nl,
+		      struct plip_local *snd, struct plip_local *rcv)
 {
-    struct enet_statistics *localstats = (struct enet_statistics*)dev->priv;
-    return localstats;
+	cli();
+	if (nl->connection == PLIP_CN_CLOSING) {
+		nl->connection = PLIP_CN_NONE;
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+	sti();
+	return OK;
 }
 
-/* We don't need to send arp, for plip is point-to-point. */
+/* PLIP_ERROR --- wait till other end settled */
 static int
-plip_rebuild_header(void *buff, struct device *dev, unsigned long dst,
-		    struct sk_buff *skb)
+plip_error(struct device *dev, struct net_local *nl,
+	   struct plip_local *snd, struct plip_local *rcv)
 {
-    struct ethhdr *eth = (struct ethhdr *)buff;
-    int i;
+	unsigned char status;
 
-    if (eth->h_proto != htons(ETH_P_IP)) {
-	printk("plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
-	memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-	return 0;
-    }
+	status = inb(PAR_STATUS(dev));
+	if ((status & 0xf8) == 0x80) {
+		if (net_debug > 2)
+			printk("%s: reset interface.\n", dev->name);
+		nl->connection = PLIP_CN_NONE;
+		dev->tbusy = 0;
+		dev->interrupt = 0;
+		outb(PAR_INTR_ON, PAR_CONTROL(dev));
+		enable_irq(dev->irq);
+		mark_bh(NET_BH);
+	} else {
+		nl->is_deferred = 1;
+		queue_task(&nl->deferred, &tq_timer);
+	}
 
-    for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
-	eth->h_dest[i] = 0xfc;
-    memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
-    return 0;
+	return OK;
 }
 
+/* Handle the parallel port interrupts. */
 static void
-plip_device_clear(struct device *dev)
+plip_interrupt(int irq, struct pt_regs * regs)
 {
-    struct net_local *nl = (struct net_local *)dev->priv;
+	struct device *dev = (struct device *) irq2dev_map[irq];
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct plip_local *rcv = &nl->rcv_data;
+	unsigned char c0;
 
-    outb (0x00, PAR_DATA(dev));
-    nl->rcv_data.state = PLIP_PK_DONE;
-    nl->snd_data.state = PLIP_PK_DONE;
-    nl->rcv_data.skb = NULL;
-    nl->snd_data.skb = NULL;
-    nl->connection = PLIP_CN_NONE;
-    cli();
-    dev->tbusy = 0;
-    sti();
-    outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
-    enable_irq(dev->irq);
-}
+	if (dev == NULL) {
+		printk ("plip_interrupt: irq %d for unknown device.\n", irq);
+		return;
+	}
 
-/* PLIP_ERROR --- wait till other end settled */
-static int
-plip_error(struct device *dev)
-{
-    unsigned char status;
+	if (dev->interrupt)
+		return;
 
-    status = inb(PAR_STATUS(dev));
-    if ((status & 0xf8) == 0x80)
-	return 0;
-    return 1;
+	c0 = inb(PAR_STATUS(dev));
+	if ((c0 & 0xf8) != 0xc0) {
+		if (net_debug > 1)
+			printk("%s: spurious interrupt\n", dev->name);
+		return;
+	}
+	dev->interrupt = 1;
+	if (net_debug > 3)
+		printk("%s: interrupt.\n", dev->name);
+
+	cli();
+	switch (nl->connection) {
+	case PLIP_CN_CLOSING:
+		dev->tbusy = 0;
+	case PLIP_CN_NONE:
+	case PLIP_CN_SEND:
+		dev->last_rx = jiffies;
+		rcv->state = PLIP_PK_TRIGGER;
+		nl->connection = PLIP_CN_RECEIVE;
+		nl->timeout_count = 0;
+		queue_task(&nl->immediate, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		sti();
+		break;
+
+	case PLIP_CN_RECEIVE:
+		sti();
+		printk("%s: receive interrupt when receiving packet\n", dev->name);
+		break;
+
+	case PLIP_CN_ERROR:
+		sti();
+		printk("%s: receive interrupt in error state\n", dev->name);
+		break;
+	}
 }
 
-/* PLIP_RECEIVE --- receive a byte(two nibbles)
-   Returns 0 on success, 1 on failure          */
-inline static int
-plip_receive(unsigned short nibble_timeout, unsigned short unit_us,
-	     unsigned short status_addr, unsigned short data_addr,
-	     enum plip_nibble_state *ns_p, unsigned char *data_p)
+/* We don't need to send arp, for plip is point-to-point. */
+static int
+plip_rebuild_header(void *buff, struct device *dev, unsigned long dst,
+		    struct sk_buff *skb)
 {
-    unsigned char c0, c1;
-    unsigned int cx;
+	struct ethhdr *eth = (struct ethhdr *)buff;
+	int i;
 
-    switch (*ns_p) {
-    case PLIP_NB_BEGIN:
-	cx = nibble_timeout;
-	while (1) {
-	    c0 = inb(status_addr);
-	    udelay(unit_us);
-	    if ((c0 & 0x80) == 0) {
-		c1 = inb(status_addr);
-		if (c0 == c1)
-		    break;
-	    }
-	    if (--cx == 0)
-		return 1;
-	}
-	*data_p = (c0 >> 3) & 0x0f;
-	outb(0x10, data_addr); /* send ACK */
-	*ns_p = PLIP_NB_1;
-
-    case PLIP_NB_1:
-	cx = nibble_timeout;
-	while (1) {
-	    c0 = inb(status_addr);
-	    udelay(unit_us);
-	    if (c0 & 0x80) {
-		c1 = inb(status_addr);
-		if (c0 == c1)
-		    break;
-	    }
-	    if (--cx == 0)
-		return 1;
+	if (eth->h_proto != htons(ETH_P_IP)) {
+		printk("plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
+		memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+		return 0;
 	}
-	*data_p |= (c0 << 1) & 0xf0;
-	outb(0x00, data_addr); /* send ACK */
-	*ns_p = PLIP_NB_BEGIN;
-	return 0;
 
-    case PLIP_NB_2:
-    }
+	for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
+		eth->h_dest[i] = 0xfc;
+	memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
+	return 0;
 }
 
-/* PLIP_RECEIVE_PACKET --- receive a packet
-   Returns 0 on success, 1 when timeout, -1 on failure */
 static int
-plip_receive_packet(struct device *dev)
+plip_tx_packet(struct sk_buff *skb, struct device *dev)
 {
-    unsigned short data_addr = PAR_DATA(dev), status_addr = PAR_STATUS(dev);
-    struct net_local *nl = (struct net_local *)dev->priv;
-    unsigned short nibble_timeout = nl->nibble_us, unit_us = nl->unit_us;
-    struct plip_local *rcv = &nl->rcv_data;
-    unsigned char *lbuf;
-    struct enet_statistics *stats = (struct enet_statistics *) dev->priv;
-
-    switch (rcv->state) {
-    case PLIP_PK_TRIGGER:
-	rcv->state = PLIP_PK_LENGTH_LSB;
-	rcv->nibble = PLIP_NB_BEGIN;
-
-    case PLIP_PK_LENGTH_LSB:
-	if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
-			 &rcv->nibble, (unsigned char *)&rcv->length))
-	    return 1;
-	rcv->state = PLIP_PK_LENGTH_MSB;
-
-    case PLIP_PK_LENGTH_MSB:
-	if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
-			 &rcv->nibble, (unsigned char *)&rcv->length+1))
-	    return 1;
-	if (rcv->length > dev->mtu || rcv->length < 8) {
-	    printk("%s: bogus packet size %d.\n", dev->name, rcv->length);
-	    return -1;
-	}
-	/* Malloc up new buffer. */
-	rcv->skb = alloc_skb(rcv->length, GFP_ATOMIC);
-	if (rcv->skb == NULL) {
-	    printk("%s: Memory squeeze.\n", dev->name);
-	    return -1;
-	}
-	rcv->skb->len = rcv->length;
-	rcv->skb->dev = dev;
-	rcv->state = PLIP_PK_DATA;
-	rcv->byte = 0;
-	rcv->checksum = 0;
-
-    case PLIP_PK_DATA:
-	lbuf = rcv->skb->data;
-	do {
-	    if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
-			     &rcv->nibble, &lbuf[rcv->byte]))
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct plip_local *snd = &nl->snd_data;
+
+	if (dev->tbusy)
 		return 1;
-	    rcv->checksum += lbuf[rcv->byte];
-	} while (++rcv->byte < rcv->length);
-	rcv->state = PLIP_PK_CHECKSUM;
-
-    case PLIP_PK_CHECKSUM:
-	if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
-			 &rcv->nibble, &rcv->data))
-	    return 1;
-	if (rcv->data != rcv->checksum) {
-	    stats->rx_crc_errors++;
-	    if (net_debug)
-		printk("%s: checksum error\n", dev->name);
-	    return -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;
 	}
-	rcv->state = PLIP_PK_DONE;
 
-    case PLIP_PK_DONE:
-    }
-    return 0;
-}
+	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return 1;
+	}
 
-/* Handle the parallel port interrupts. */
-static void
-plip_interrupt(int irq, struct pt_regs * regs)
-{
-    struct device *dev = (struct device *) irq2dev_map[irq];
-    struct net_local *nl = (struct net_local *)dev->priv;
-    struct plip_local *rcv = &nl->rcv_data;
-    unsigned char c0;
-
-    if (dev == NULL) {
-	if (net_debug)
-	    printk ("plip_interrupt: irq %d for unknown device.\n", irq);
-	return;
-    }
+	if (skb->len > dev->mtu) {
+		printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
+		dev->tbusy = 0;
+		return 0;
+	}
 
-    if (dev->interrupt)
-	return;
+	if (net_debug > 2)
+		printk("%s: send request\n", dev->name);
 
-    c0 = inb(PAR_STATUS(dev));
-    if ((c0 & 0xf8) != 0xc0) {
-	if (net_debug > 3)
-	    printk("plip: spurious interrupt\n");
-	return;
-    }
-    dev->interrupt = 1;
-    if (net_debug > 3)
-	printk("%s: interrupt.\n", dev->name);
-
-    cli();
-    switch (nl->connection) {
-    case PLIP_CN_CLOSING:
-	dev->tbusy = 0;
-    case PLIP_CN_NONE:
-    case PLIP_CN_SEND:
-	sti();
-	dev->last_rx = jiffies;
-	rcv->state = PLIP_PK_TRIGGER;
-	nl->connection = PLIP_CN_RECEIVE;
-	nl->timeout_count = 0;
+	cli();
+	dev->trans_start = jiffies;
+	snd->skb = skb;
+	snd->length = skb->len;
+	snd->state = PLIP_PK_TRIGGER;
+	if (nl->connection == PLIP_CN_NONE) {
+		nl->connection = PLIP_CN_SEND;
+		nl->timeout_count = 0;
+	}
 	queue_task(&nl->immediate, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
-	break;
-
-    case PLIP_CN_RECEIVE:
 	sti();
-	printk("%s: receive interrupt when receiving packet\n", dev->name);
-	break;
 
-    case PLIP_CN_ERROR:
-	sti();
-	printk("%s: receive interrupt in error state\n", dev->name);
-	break;
-    }
+	return 0;
 }
-
-/* PLIP_SEND --- send a byte (two nibbles) 
-   Returns 0 on success, 1 on failure        */
-inline static int
-plip_send(unsigned short nibble_timeout, unsigned short unit_us,
-	  unsigned short status_addr, unsigned short data_addr,
-	  enum plip_nibble_state *ns_p, unsigned char data)
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine gets exclusive access to the parallel port by allocating
+   its IRQ line.
+ */
+static int
+plip_open(struct device *dev)
 {
-    unsigned char c0;
-    unsigned int cx;
+	struct net_local *nl = (struct net_local *)dev->priv;
+	int i;
 
-    switch (*ns_p) {
-    case PLIP_NB_BEGIN:
-	outb((data & 0x0f), data_addr);
-	*ns_p = PLIP_NB_1;
-
-    case PLIP_NB_1:
-	outb(0x10 | (data & 0x0f), data_addr);
-	cx = nibble_timeout;
-	while (1) {
-	    c0 = inb(status_addr);
-	    if ((c0 & 0x80) == 0) 
-		break;
-	    if (--cx == 0) /* time out */
-		return 1;
-	    udelay(unit_us);
+	if (dev->irq == 0) {
+		printk("%s: IRQ is not set.  Please set it by ifconfig.\n", dev->name);
+		return -EAGAIN;
 	}
-	outb(0x10 | (data >> 4), data_addr);
-	*ns_p = PLIP_NB_2;
-
-    case PLIP_NB_2:
-	outb((data >> 4), data_addr);
-	cx = nibble_timeout;
-	while (1) {
-	    c0 = inb(status_addr);
-	    if (c0 & 0x80)
-		break;
-	    if (--cx == 0) /* time out */
-		return 1;
-	    udelay(unit_us);
+	cli();
+	if (request_irq(dev->irq , plip_interrupt, 0, dev->name) != 0) {
+		sti();
+		printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
+		return -EAGAIN;
 	}
-	*ns_p = PLIP_NB_BEGIN;
+	irq2dev_map[dev->irq] = dev;
+	sti();
+
+	/* Clear the data port. */
+	outb (0x00, PAR_DATA(dev));
+
+	/* Enable rx interrupt. */
+	outb(PAR_INTR_ON, PAR_CONTROL(dev));
+
+	/* Initialize the state machine. */
+	nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
+	nl->rcv_data.skb = nl->snd_data.skb = NULL;
+	nl->connection = PLIP_CN_NONE;
+	nl->is_deferred = 0;
+
+	/* Fill in the MAC-level header. */
+	for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
+		dev->dev_addr[i] = 0xfc;
+	memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(unsigned long));
+
+	dev->interrupt = 0;
+	dev->start = 1;
+	dev->tbusy = 0;
+	MOD_INC_USE_COUNT;
 	return 0;
-    }
 }
 
-/* PLIP_SEND_PACKET --- send a packet
-   Returns 0 on success, 1 when timeout, -1 when interrupted  */
+/* The inverse routine to plip_open (). */
 static int
-plip_send_packet(struct device *dev)
+plip_close(struct device *dev)
 {
-    unsigned short data_addr = PAR_DATA(dev), status_addr = PAR_STATUS(dev);
-    struct net_local *nl = (struct net_local *)dev->priv;
-    unsigned short nibble_timeout = nl->nibble_us, unit_us = nl->unit_us;
-    struct plip_local *snd = &nl->snd_data;
-    unsigned char *lbuf = snd->skb->data;
-    unsigned char c0;
-    unsigned int cx;
-    struct enet_statistics *stats = (struct enet_statistics *) dev->priv;
-
-    switch (snd->state) {
-    case PLIP_PK_TRIGGER:
-	/* Trigger remote rx interrupt. */
-	outb(0x08, PAR_DATA(dev));
-	cx = nl->trigger_us;
-	while (1) {
-	    if (nl->connection == PLIP_CN_RECEIVE) { /* interrupted */
-		stats->collisions++;
-		if (net_debug > 3)
-		    printk("%s: collision.\n", dev->name);
-		return -1;
-	    }
-	    cli();
-	    c0 = inb(PAR_STATUS(dev));
-	    if (c0 & 0x08) {
-		disable_irq(dev->irq);
-		outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-		if (net_debug > 3)
-		    printk("+");
-		/* OK, connection established! */
-		snd->state = PLIP_PK_LENGTH_LSB;
-		snd->nibble = PLIP_NB_BEGIN;
-		nl->timeout_count = 0;
-		sti();
-		break;
-	    }
-	    sti();
-	    udelay(nl->unit_us);
-	    if (--cx == 0) {
-		outb(0x00, PAR_DATA(dev));
-		return 1;
-	    }
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct plip_local *snd = &nl->snd_data;
+	struct plip_local *rcv = &nl->rcv_data;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+	cli();
+	free_irq(dev->irq);
+	irq2dev_map[dev->irq] = NULL;
+	nl->is_deferred = 0;
+	nl->connection = PLIP_CN_NONE;
+	sti();
+	outb(0x00, PAR_DATA(dev));
+
+	snd->state = PLIP_PK_DONE;
+	if (snd->skb) {
+		dev_kfree_skb(snd->skb, FREE_WRITE);
+		snd->skb = NULL;
+	}
+	rcv->state = PLIP_PK_DONE;
+	if (rcv->skb) {
+		rcv->skb->free = 1;
+		kfree_skb(rcv->skb, FREE_READ);
+		rcv->skb = NULL;
 	}
 
-    case PLIP_PK_LENGTH_LSB:
-	if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
-		      &snd->nibble, snd->length & 0xff)) /* timeout */
-	    return 1;
-	snd->state = PLIP_PK_LENGTH_MSB;
-
-    case PLIP_PK_LENGTH_MSB:
-	if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
-		      &snd->nibble, snd->length >> 8)) /* timeout */
-	    return 1;
-	snd->state = PLIP_PK_DATA;
-	snd->byte = 0;
-	snd->checksum = 0;
-
-    case PLIP_PK_DATA:
-	do {
-	    if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
-			  &snd->nibble, lbuf[snd->byte])) /* timeout */
-		return 1;
-	    snd->checksum += lbuf[snd->byte];
-	} while (++snd->byte < snd->length);
-	snd->state = PLIP_PK_CHECKSUM;
-
-    case PLIP_PK_CHECKSUM:
-	if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
-		      &snd->nibble, snd->checksum)) /* timeout */
-	    return 1;
-
-	dev_kfree_skb(snd->skb, FREE_WRITE);
-	stats->tx_packets++;
-
-    case PLIP_PK_DONE:
-    }
-    return 0;
+	/* Reset. */
+	outb(0x00, PAR_CONTROL(dev));
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
-
-static int plip_config(struct device *dev, struct ifmap *map)
+
+static struct enet_statistics *
+plip_get_stats(struct device *dev)
+{
+	struct net_local *nl = (struct net_local *)dev->priv;
+	struct enet_statistics *r = &nl->enet_stats;
+
+	return r;
+}
+
+static int
+plip_config(struct device *dev, struct ifmap *map)
 {
-	if(dev->flags&IFF_UP)
+	if (dev->flags & IFF_UP)
 		return -EBUSY;
-/*
- *	We could probe this for verification, but since they told us
- *	to do it then they can suffer.
- */
-	if(map->base_addr!= (unsigned short)-1)
-		dev->base_addr=map->base_addr;
-	if(map->irq!= (unsigned char)-1)
-		dev->irq= map->irq;
+
+	if (map->base_addr != (unsigned long)-1
+	    && map->base_addr != dev->base_addr)
+		printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
+
+	if (map->irq != (unsigned char)-1)
+		dev->irq = map->irq;
 	return 0;
 }
 
-static int plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int
+plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
 	struct net_local *nl = (struct net_local *) dev->priv;
 	struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
 	
-	switch(pc->pcmd)
-	{
-		case PLIP_GET_TIMEOUT:
-			pc->trigger=nl->trigger_us;
-			pc->nibble=nl->nibble_us;
-			pc->unit=nl->unit_us;
-			break;
-		case PLIP_SET_TIMEOUT:
-			nl->trigger_us=pc->trigger;
-			nl->nibble_us=pc->nibble;
-			nl->unit_us=pc->unit;
-			break;
-		default:
-			return -EOPNOTSUPP;
+	switch(pc->pcmd) {
+	case PLIP_GET_TIMEOUT:
+		pc->trigger = nl->trigger;
+		pc->nibble  = nl->nibble;
+		pc->unit    = nl->unit;
+		break;
+	case PLIP_SET_TIMEOUT:
+		nl->trigger = pc->trigger;
+		nl->nibble  = pc->nibble;
+		nl->unit    = pc->unit;
+		break;
+	default:
+		return -EOPNOTSUPP;
 	}
 	return 0;
 }
-
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
@@ -939,56 +1040,45 @@
 int
 init_module(void)
 {
-    int devices=0;
+	int devices=0;
 
-    if (register_netdev(&dev_plip0) != 0)
-	devices++;
-    if (register_netdev(&dev_plip1) != 0)
-	devices++;
-    if (register_netdev(&dev_plip2) != 0)
-	devices++;
-    if (devices == 0)
-	return -EIO;
-    return 0;
+	if (register_netdev(&dev_plip0) != 0)
+		devices++;
+	if (register_netdev(&dev_plip1) != 0)
+		devices++;
+	if (register_netdev(&dev_plip2) != 0)
+		devices++;
+	if (devices == 0)
+		return -EIO;
+	return 0;
 }
 
 void
 cleanup_module(void)
 {
-    if (MOD_IN_USE)
-	printk("plip: device busy, remove delayed\n");
-    else {
 	if (dev_plip0.priv) {
-	    unregister_netdev(&dev_plip0);
-	    release_region(PAR_DATA(&dev_plip0), 3);
-	    kfree_s(dev_plip0.priv, sizeof(struct net_local));
-	    dev_plip0.priv = NULL;
+		unregister_netdev(&dev_plip0);
+		release_region(PAR_DATA(&dev_plip0), 3);
+		kfree_s(dev_plip0.priv, sizeof(struct net_local));
+		dev_plip0.priv = NULL;
 	}
 	if (dev_plip1.priv) {
-	    unregister_netdev(&dev_plip1);
-	    release_region(PAR_DATA(&dev_plip1), 3);
-	    kfree_s(dev_plip1.priv, sizeof(struct net_local));
-	    dev_plip1.priv = NULL;
+		unregister_netdev(&dev_plip1);
+		release_region(PAR_DATA(&dev_plip1), 3);
+		kfree_s(dev_plip1.priv, sizeof(struct net_local));
+		dev_plip1.priv = NULL;
 	}
 	if (dev_plip2.priv) {
-	    unregister_netdev(&dev_plip2);
-	    release_region(PAR_DATA(&dev_plip2), 3);
-	    kfree_s(dev_plip2.priv, sizeof(struct net_local));
-	    dev_plip2.priv = NULL;
+		unregister_netdev(&dev_plip2);
+		release_region(PAR_DATA(&dev_plip2), 3);
+		kfree_s(dev_plip2.priv, sizeof(struct net_local));
+		dev_plip2.priv = NULL;
 	}
-    }
 }
 #endif /* MODULE */
 
 /*
  * Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486 -I../../net/inet -c plip.c"
- * c-indent-level: 4
- * c-continued-statement-offset: 4
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * version-control: t
- * kept-new-versions: 10
+ * compile-command: "gcc -DMODULE -DCONFIG_MODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c plip.c"
  * End:
  */
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v1.1.89/linux/drivers/scsi/eata.c	Sun Feb  5 19:31:53 1995
+++ linux/drivers/scsi/eata.c	Wed Feb  8 13:14:08 1995
@@ -1,6 +1,10 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *       8 Feb 1995 rev. 1.15 for linux 1.1.89
+ *          Cleared target_time_out counter while preforming a reset.
+ *          All external symbols renamed to avoid possible name conflicts.
+ *
  *      28 Jan 1995 rev. 1.14 for linux 1.1.86
  *          Added module support.
  *          Log and do a retry when a disk drive returns a target status 
@@ -41,7 +45,7 @@
  *          This driver is based on the CAM (Common Access Method Committee)
  *          EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
  *
- *      Released by Dario Ballabio (Dario_Ballabio@milano.europe.dg.com)
+ *      Copyright (C) 1994, 1995 Dario Ballabio (dario@milano.europe.dg.com)
  *
  */
 
@@ -89,6 +93,7 @@
 
 #if defined(MODULE)
 #include <linux/module.h>
+#include <linux/version.h>
 #endif
 
 #include <linux/string.h>
@@ -288,7 +293,7 @@
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
-static void eata_interrupt_handler(int, struct pt_regs *);
+static void eata2x_interrupt_handler(int, struct pt_regs *);
 static int do_trace = FALSE;
 
 static inline unchar wait_on_busy(ushort iobase) {
@@ -411,7 +416,7 @@
 
    /* Board detected, allocate its IRQ if not already done */
    if ((irq >= MAX_IRQ) || ((irqlist[irq] == NO_IRQ) && request_irq
-       (irq, eata_interrupt_handler, SA_INTERRUPT, driver_name))) {
+       (irq, eata2x_interrupt_handler, SA_INTERRUPT, driver_name))) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
       return FALSE;
       }
@@ -461,12 +466,7 @@
    if (HD(j)->subversion == ESA)
       sh[j]->unchecked_isa_dma = FALSE;
    else {
-
-#if !defined(MODULE)
-      /* The module code does not checkin/checkout in the blocking list yet */
       sh[j]->block = sh[j];
-#endif
-
       sh[j]->unchecked_isa_dma = TRUE;
       disable_dma(dma_channel);
       clear_dma_ff(dma_channel);
@@ -507,7 +507,7 @@
    return TRUE;
 }
 
-int eata_detect (Scsi_Host_Template * tpnt) {
+int eata2x_detect (Scsi_Host_Template * tpnt) {
    unsigned int j = 0, k, flags;
 
    ushort io_port[] = { 
@@ -535,6 +535,9 @@
       port_base++;
       }
 
+   if (j > 0) 
+      printk("EATA/DMA 2.0x: Copyright (C) 1994, 1995 Dario Ballabio.\n");
+
    restore_flags(flags);
    return j;
 }
@@ -554,7 +557,7 @@
    cpp->data_len = htonl((SCpnt->use_sg * sizeof(struct sg_list)));
 }
 
-int eata_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+int eata2x_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    unsigned int i, j, k, flags;
    struct mscp *cpp;
    struct mssp *spp;
@@ -585,7 +588,7 @@
 
       if (HD(j)->in_reset) 
          printk("%s: qcomm, already in reset.\n", BN(j));
-      else if (eata_reset(SCpnt) == SCSI_RESET_SUCCESS) 
+      else if (eata2x_reset(SCpnt) == SCSI_RESET_SUCCESS) 
          panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
 
       SCpnt->result = DID_BUS_BUSY << 16; 
@@ -657,7 +660,7 @@
    return 0;
 }
 
-int eata_abort (Scsi_Cmnd *SCarg) {
+int eata2x_abort (Scsi_Cmnd *SCarg) {
    unsigned int i, j, flags;
 
    save_flags(flags);
@@ -715,7 +718,7 @@
       panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
 }
 
-int eata_reset (Scsi_Cmnd *SCarg) {
+int eata2x_reset (Scsi_Cmnd *SCarg) {
    unsigned int i, j, flags, time, k, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
@@ -743,6 +746,8 @@
 
    for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE;
 
+   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0;
+
    for (i = 0; i < sh[j]->can_queue; i++) {
 
       if (HD(j)->cp_stat[i] == FREE) continue;
@@ -784,7 +789,7 @@
    HD(j)->in_reset = TRUE;
    sti();
    time = jiffies;
-   while (jiffies < (time + 200) && limit++ < 100000000) sti();
+   while (jiffies < (time + 100) && limit++ < 100000000);
    cli();
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -821,7 +826,7 @@
       }
 }
 
-static void eata_interrupt_handler(int irq, struct pt_regs * regs) {
+static void eata2x_interrupt_handler(int irq, struct pt_regs * regs) {
    Scsi_Cmnd *SCpnt;
    unsigned int i, j, k, flags, status, tstatus, loops, total_loops = 0;
    struct mssp *spp;
@@ -928,8 +933,7 @@
                      status = DID_BUS_BUSY << 16;
 
                   else if (tstatus == CHECK_CONDITION
-                           && (SCpnt->device->type == TYPE_DISK
-                            || SCpnt->device->type == TYPE_ROM)
+                           && SCpnt->device->type == TYPE_DISK
                            && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION)
                      status = DID_ERROR << 16;
    
@@ -939,8 +943,7 @@
                   if (tstatus == GOOD)
                      HD(j)->target_reset[SCpnt->target] = FALSE;
    
-                  if (spp->target_status && (SCpnt->device->type == TYPE_DISK
-                                          || SCpnt->device->type == TYPE_ROM))
+                  if (spp->target_status && SCpnt->device->type == TYPE_DISK)
                      printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
                             "0x%x, sense key 0x%x.\n", BN(j), 
                             SCpnt->target, SCpnt->lun, SCpnt->pid,
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- v1.1.89/linux/drivers/scsi/eata.h	Sun Feb  5 19:31:53 1995
+++ linux/drivers/scsi/eata.h	Wed Feb  8 13:14:08 1995
@@ -7,24 +7,24 @@
 
 #include <linux/scsicam.h>
 
-#define EATA_VERSION "1.14.03"
+#define EATA_VERSION "1.15.00"
 
-int eata_detect(Scsi_Host_Template *);
-int eata_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int eata_abort(Scsi_Cmnd *);
-int eata_reset(Scsi_Cmnd *);
+int eata2x_detect(Scsi_Host_Template *);
+int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int eata2x_abort(Scsi_Cmnd *);
+int eata2x_reset(Scsi_Cmnd *);
 
-#define EATA {  NULL, /* Ptr for modules */                    \
+#define EATA {                                                 \
+                NULL, /* Ptr for modules */                    \
                 NULL, /* usage count for modules */	       \
-                "EATA/DMA 2.0 rev. " EATA_VERSION " by "       \
-                "Dario_Ballabio@milano.europe.dg.com.",        \
-                eata_detect,	        	               \
+                "EATA/DMA 2.0x rev. " EATA_VERSION " ",        \
+                eata2x_detect,	        	               \
                 NULL, /* Release */     	               \
 		NULL,	                                       \
 		NULL,    			       	       \
-		eata_queuecommand,			       \
-		eata_abort,				       \
-		eata_reset,				       \
+		eata2x_queuecommand,			       \
+		eata2x_abort,				       \
+		eata2x_reset,				       \
 	        NULL,		                               \
 		scsicam_bios_param,   			       \
 		0,   /* can_queue, reset by detect */          \
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h
--- v1.1.89/linux/drivers/scsi/eata_dma.h	Sun Feb  5 19:31:54 1995
+++ linux/drivers/scsi/eata_dma.h	Mon Feb  6 20:42:52 1995
@@ -137,7 +137,7 @@
 #define C_P_L_DIV          4  /* 1 <= C_P_L_DIV <= 8            
 			       * You can use this parameter to fine-tune
 			       * the driver. Depending on the number of 
-			       * devices and their ablilty to queue commands
+			       * devices and their ability to queue commands
 			       * you will get the best results with a value
 			       * ~= numdevices-(devices_unable_to_queue_commands/2)
 			       * The reason for this is that the disk driver tents 
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.1.89/linux/drivers/scsi/hosts.c	Sun Feb  5 19:31:54 1995
+++ linux/drivers/scsi/hosts.c	Wed Feb  8 13:38:52 1995
@@ -221,7 +221,7 @@
 	j = sh->extra_bytes;
 
 	if(scsi_hostlist == sh)
-		scsi_hostlist = NULL;
+		scsi_hostlist = sh->next;
 	else {
 		shpnt = scsi_hostlist;
 		while(shpnt->next != sh) shpnt = shpnt->next;
@@ -244,7 +244,8 @@
 	if(j > 0xffff) panic("Too many extra bytes requested\n");
 	retval->extra_bytes = j;
 	retval->loaded_as_module = scsi_loadable_module_flag;
-	retval->host_no = next_scsi_host++;
+	retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */
+	next_scsi_host++;
 	retval->host_queue = NULL;
 	retval->host_wait = NULL;
 	retval->last_reset = 0;
@@ -339,29 +340,7 @@
 	printk ("scsi : %d host%s.\n", next_scsi_host,
 		(next_scsi_host == 1) ? "" : "s");
 
-      {
-      int block_count = 0, index;
-      struct Scsi_Host * sh[128], * shpnt;
-
-         for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-            if (shpnt->block) sh[block_count++] = shpnt;
-      
-         if (block_count == 1) sh[0]->block = NULL;
-
-         else if (block_count > 1) {
-
-            for(index = 0; index < block_count - 1; index++) {
-               sh[index]->block = sh[index + 1];
-               printk("scsi%d : added to blocked host list.\n", 
-                      sh[index]->host_no);
-               }
-           
-            sh[block_count - 1]->block = sh[0];
-            printk("scsi%d : added to blocked host list.\n", 
-                   sh[index]->host_no);
-            }
-
-      }
+	scsi_make_blocked_list();
 
 	/* Now attach the high level drivers */
 #ifdef CONFIG_BLK_DEV_SD
@@ -377,7 +356,9 @@
 	scsi_register_device(&sg_template);
 #endif
 
+#if 0      
 	max_scsi_hosts = next_scsi_host;
+#endif
 	return 0;
 }
 
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/script_asm.pl linux/drivers/scsi/script_asm.pl
--- v1.1.89/linux/drivers/scsi/script_asm.pl	Fri Aug 19 08:54:05 1994
+++ linux/drivers/scsi/script_asm.pl	Mon Feb  6 20:45:15 1995
@@ -280,11 +280,11 @@
 	$conditional = $1;
 	print STDERR "$0 : parsed ATN\n" if ($debug);
     } elsif ($conditional =~ /^($phase)\s*(.*)/i) {
-	$1 = "\U$1\E";
-	$p = $scsi_phases{$1};
+	$phase_index = "\U$1\E";
+	$p = $scsi_phases{$phase_index};
 	$code[$address] |= $p | 0x00_02_00_00;
 	$conditional = $2;
-	print STDERR "$0 : parsed phase $1\n" if ($debug);
+	print STDERR "$0 : parsed phase $phase_index\n" if ($debug);
     } else {
 	$other = '';
 	$need_data = 1;
@@ -378,16 +378,17 @@
 	$rest = $2;
 	foreach $rest (split (/\s*,\s*/, $rest)) {
 	    if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
-		if ($symbol_values{$1} eq undef) {
-		    $symbol_values{$1} = eval $2;
-		    delete $forward{$1};
+	        local ($id, $cnst) = ($1, $2);
+		if ($symbol_values{$id} eq undef) {
+		    $symbol_values{$id} = eval $cnst;
+		    delete $forward{$id};
 		    if ($is_absolute =~ /ABSOLUTE/i) {
-			push (@absolute , $1);
+			push (@absolute , $id);
 		    } else {
-			push (@relative, $1);
+			push (@relative, $id);
 		    }
 		} else {
-		    die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
+		    die "$0 : redefinition of symbol $id in line $lineno : $_\n";
 		}
 	    } else {
 		die 
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.1.89/linux/drivers/scsi/scsi.c	Sun Feb  5 19:31:54 1995
+++ linux/drivers/scsi/scsi.c	Wed Feb  8 13:44:13 1995
@@ -1,18 +1,18 @@
 /*
- *	scsi.c Copyright (C) 1992 Drew Eckhardt 
+ *	scsi.c Copyright (C) 1992 Drew Eckhardt
  *	       Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
  *	generic mid-level SCSI driver
- *		Initial versions: Drew Eckhardt 
+ *		Initial versions: Drew Eckhardt
  *		Subsequent revisions: Eric Youngdale
  *
  *	<drew@colorado.edu>
  *
- *	Bug correction thanks go to : 
+ *	Bug correction thanks go to :
  *		Rik Faith <faith@cs.unc.edu>
  *		Tommy Thorn <tthorn>
  *		Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
- * 
+ *
  *       Modified by Eric Youngdale ericy@cais.com to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
@@ -48,10 +48,9 @@
 
 static int time_start;
 static int time_elapsed;
-static int scsi_maybe_deadlocked = 0;
-static int max_active = 0;
-static struct Scsi_Host * host_active = NULL;
-static struct Scsi_Host * host_next = NULL;
+static volatile struct Scsi_Host * host_active = NULL;
+#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
+		   || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
 
 #define MAX_SCSI_DEVICE_CODE 10
 const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
@@ -70,8 +69,8 @@
 
 
 /*
-	global variables : 
-	scsi_devices an array of these specifying the address for each 
+	global variables :
+	scsi_devices an array of these specifying the address for each
 	(host, id, LUN)
 */
 
@@ -86,21 +85,21 @@
 Scsi_Cmnd * last_cmnd = NULL;
 
 /*
- *	As the scsi do command functions are intelligent, and may need to 
- *	redo a command, we need to keep track of the last command 
+ *	As the scsi do command functions are intelligent, and may need to
+ *	redo a command, we need to keep track of the last command
  *	executed on each one.
  */
 
-#define WAS_RESET 	0x01
-#define WAS_TIMEDOUT 	0x02
+#define WAS_RESET	0x01
+#define WAS_TIMEDOUT	0x02
 #define WAS_SENSE	0x04
 #define IS_RESETTING	0x08
 #define IS_ABORTING	0x10
 #define ASKED_FOR_SENSE 0x20
 
 /*
- *	This is the number  of clock ticks we should wait before we time out 
- *	and abort the command.  This is for  where the scsi.c module generates 
+ *	This is the number  of clock ticks we should wait before we time out
+ *	and abort the command.  This is for  where the scsi.c module generates
  *	the command, not where it originates from a higher level, in which
  *	case the timeout is specified there.
  *
@@ -127,9 +126,13 @@
 	#define SENSE_TIMEOUT 50
 	#define RESET_TIMEOUT 50
 	#define ABORT_TIMEOUT 50
-	#define MIN_RESET_DELAY 100
 #endif
 
+#define MIN_RESET_DELAY 100
+
+/* Do not call reset on error if we just did a reset within 10 sec. */
+#define MIN_RESET_PERIOD 1000
+
 /* The following devices are known not to tolerate a lun != 0 scan for
    one reason or another.  Some will respond to all luns, others will
    lock up. */
@@ -140,7 +143,7 @@
        char * revision; /* Latest revision known to be bad.  Not used yet */
      };
 
-static struct blist blacklist[] = 
+static struct blist blacklist[] =
 {
    {"CHINON","CD-ROM CDS-431","H42"},  /* Locks up if polled for lun != 0 */
    {"CHINON","CD-ROM CDS-535","Q14"}, /* Lockup if polled for lun != 0 */
@@ -171,7 +174,7 @@
    {"HP", "C1750A", "3226"},    /* scanjet iic */
    {"HP", "C1790A", ""},	/* scanjet iip */
    {"HP", "C2500A", ""},	/* scanjet iicx */
-   {NULL, NULL, NULL}};	
+   {NULL, NULL, NULL}};
 
 static int blacklisted(unsigned char * response_data){
   int i = 0;
@@ -187,41 +190,89 @@
     if(memcmp(blacklist[i].model, pnt,
 	       strlen(blacklist[i].model))) continue;
     return 1;
-  };	
+  };
 };
 
 /*
- *	As the actual SCSI command runs in the background, we must set up a 
- *	flag that tells scan_scsis() when the result it has is valid.  
- *	scan_scsis can set the_result to -1, and watch for it to become the 
- *	actual return code for that call.  the scan_scsis_done function() is 
- *	our user specified completion function that is passed on to the  
+ *	As the actual SCSI command runs in the background, we must set up a
+ *	flag that tells scan_scsis() when the result it has is valid.
+ *	scan_scsis can set the_result to -1, and watch for it to become the
+ *	actual return code for that call.  the scan_scsis_done function() is
+ *	our user specified completion function that is passed on to the
  *	scsi_do_cmd() function.
  */
 
 volatile int in_scan_scsis = 0;
 static int the_result;
 
-static void restart_all(void) {
- /*
-  * If we might have deadlocked, get things started again. Only
-  * for block devices. Character devices should never deadlock.
-  */
-  struct Scsi_Device_Template * sdtpnt;
+void scsi_make_blocked_list(void)  {
+  int block_count = 0, index;
+  unsigned int flags;
+  struct Scsi_Host * sh[128], * shpnt;
 
-  for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+  /*
+   * Create a circular linked list from the scsi hosts which have
+   * the "block" field in the Scsi_Host structure set to any value
+   * different from NULL.
+   * If there is only one host such that host->block != NULL, the list is
+   * empty and host->block is reset to NULL.
+   * The blocked list should include all the scsi hosts using ISA DMA.
+   * In some systems, using two dma channels simultaneously causes
+   * unpredictable results.
+   * Among the scsi hosts in the blocked list, only one host at a time
+   * is allowed to have active commands queued. The transition from
+   * one active host to the next one is allowed only when host_busy == 0
+   * for the active host (which implies host_busy == 0 for all the hosts
+   * in the list). Moreover for block devices the transition to a new
+   * active host is allowed only when a request is completed, since a
+   * block device request can be divided into multiple scsi commands
+   * (when there are few sg lists or clustering is disabled).
+   *
+   * (DB, 4 Feb 1995)
+   */
 
-     if (sdtpnt->blk && blk_dev[sdtpnt->major].request_fn)
-        (*blk_dev[sdtpnt->major].request_fn)();
+  save_flags(flags);
+  cli();
+  host_active = NULL;
+
+  for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
+
+#if 0
+     /*
+      * Is this is a candidate for the blocked list?
+      * Useful to put into the blocked list all the hosts whose driver
+      * does not know about the host->block feature.
+      */
+     if (shpnt->unchecked_isa_dma) shpnt->block = shpnt;
+#endif
 
+     if (shpnt->block) sh[block_count++] = shpnt;
+     }
+
+  if (block_count == 1) sh[0]->block = NULL;
+
+  else if (block_count > 1) {
+
+     for(index = 0; index < block_count - 1; index++) {
+	sh[index]->block = sh[index + 1];
+	printk("scsi%d : added to blocked host list.\n",
+	       sh[index]->host_no);
+	}
+
+     sh[block_count - 1]->block = sh[0];
+     printk("scsi%d : added to blocked host list.\n",
+	    sh[index]->host_no);
+     }
+
+  restore_flags(flags);
   }
 
 static void scan_scsis_done (Scsi_Cmnd * SCpnt)
 	{
-	
+
 #ifdef DEBUG
 	printk ("scan_scsis_done(%d, %06x)\n", SCpnt->host, SCpnt->result);
-#endif	
+#endif
 	SCpnt->request.dev = 0xfffe;
 
 	if (SCpnt->request.sem != NULL)
@@ -235,17 +286,17 @@
 #endif
 
 void scsi_luns_setup(char *str, int *ints) {
-    if (ints[0] != 1) 
+    if (ints[0] != 1)
 	printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
     else
-        max_scsi_luns = ints[1];
+	max_scsi_luns = ints[1];
 }
 
 /*
- *	Detecting SCSI devices :	
- *	We scan all present host adapter's busses,  from ID 0 to ID 6.  
- *	We use the INQUIRY command, determine device type, and pass the ID / 
- *	lun address of all sequential devices to the tape driver, all random 
+ *	Detecting SCSI devices :
+ *	We scan all present host adapter's busses,  from ID 0 to ID 6.
+ *	We use the INQUIRY command, determine device type, and pass the ID /
+ *	lun address of all sequential devices to the tape driver, all random
  *	devices to the disk driver.
  */
 
@@ -258,7 +309,7 @@
   Scsi_Device * SDpnt, *SDtail;
   struct Scsi_Device_Template * sdtpnt;
   Scsi_Cmnd  SCmd;
-  
+
   ++in_scan_scsis;
   lun = 0;
   type = -1;
@@ -271,9 +322,9 @@
   }
 
   /* Make sure we have something that is valid for DMA purposes */
-  scsi_result = ((current == task[0]  || !shpnt->unchecked_isa_dma) 
+  scsi_result = ((current == task[0]  || !shpnt->unchecked_isa_dma)
 		 ?  &scsi_result0[0] : scsi_malloc(512));
-	    
+
 
   shpnt->host_queue = &SCmd;  /* We need this so that
 					 commands can time out */
@@ -292,16 +343,16 @@
 	  SDpnt->next = NULL;
 	  SDpnt->attached = 0;
 /*
- * Assume that the device will have handshaking problems, and then 
+ * Assume that the device will have handshaking problems, and then
  * fix this field later if it turns out it doesn't.
  */
 	  SDpnt->borken = 1;
-	  
+
 	  scsi_cmd[0] = TEST_UNIT_READY;
 	  scsi_cmd[1] = lun << 5;
 	  scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
 	  scsi_cmd[4] = 0;
-	  
+
 	  SCmd.host = shpnt;
 	  SCmd.target = dev;
 	  SCmd.lun = lun;
@@ -313,12 +364,12 @@
 	  SCmd.old_use_sg  = 0;
 	  SCmd.transfersize = 0;
 	  SCmd.underflow = 0;
-	  
+
 	  scsi_do_cmd (&SCmd,
-		       (void *)  scsi_cmd, (void *) 
-		       scsi_result, 256,  scan_scsis_done, 
+		       (void *)  scsi_cmd, (void *)
+		       scsi_result, 256,  scan_scsis_done,
 		       SCSI_TIMEOUT + 400, 5);
-	  
+
 	  /* Wait for command to finish.  Use simple wait if we are booting, else
 	     do it right and use a mutex */
 
@@ -338,8 +389,8 @@
 	  printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
 	  printk("scsi: return code %08x\n", SCmd.result);
 #endif
-	  
-	  
+
+
 	  if(SCmd.result) {
 	    if ((driver_byte(SCmd.result)  & DRIVER_SENSE) &&
 		((SCmd.sense_buffer[0] & 0x70) >> 4) == 7) {
@@ -352,30 +403,30 @@
 	    else
 	      break;
 	  };
-	  
+
 #if defined (DEBUG) || defined(DEBUG_INIT)
 	  printk("scsi: performing INQUIRY\n");
 #endif
-	  
+
 	  /*
-	   * Build an INQUIRY command block.  
+	   * Build an INQUIRY command block.
 	   */
-	  
+
 	  scsi_cmd[0] = INQUIRY;
 	  scsi_cmd[1] = (lun << 5) & 0xe0;
 	  scsi_cmd[2] = 0;
 	  scsi_cmd[3] = 0;
 	  scsi_cmd[4] = 255;
 	  scsi_cmd[5] = 0;
-	  
+
 	  SCmd.request.dev = 0xffff; /* Mark not busy */
 	  SCmd.cmd_len = 0;
-	  
+
 	  scsi_do_cmd (&SCmd,
-		       (void *)  scsi_cmd, (void *) 
-		       scsi_result, 256,  scan_scsis_done, 
+		       (void *)  scsi_cmd, (void *)
+		       scsi_result, 256,  scan_scsis_done,
 		       SCSI_TIMEOUT, 3);
-	  
+
 	  if (current == task[0]){
 	    while (SCmd.request.dev != 0xfffe);
 	  } else {
@@ -389,18 +440,18 @@
 	  }
 
 	  the_result = SCmd.result;
-	  
+
 #if defined(DEBUG) || defined(DEBUG_INIT)
 	  if (!the_result)
 	    printk("scsi: INQUIRY successful\n");
 	  else
 	    printk("scsi: INQUIRY failed with code %08x\n", the_result);
 #endif
-	  
-	  if(the_result) break; 
-	  
+
+	  if(the_result) break;
+
 	  /* skip other luns on this device */
-	  
+
 	  if (!the_result)
 	    {
 		/* It would seem some TOSHIBA CD-ROM gets things wrong */
@@ -411,32 +462,23 @@
 			scsi_result[1] |= 0x80;  /* removable */
 		}
 
-/*
- *     Unfortunately the Toshiba CD-ROM XM-3401TA doesn't
- *     understand the vendor specific mode select/sense
- *     commands which are used by the photo cd routines in 
- *     sr.c.
- */
-
 	      SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
 	      if (!strncmp(scsi_result+8,"NEC",3))
 		SDpnt->manufacturer = SCSI_MAN_NEC;
-	      if (!strncmp(scsi_result+8,"TOSHIBA",7) &&
-		  strncmp(scsi_result+16,"CD-ROM XM-3401TA",16) &&
-		  strncmp(scsi_result+32,"3593",4))
+	      if (!strncmp(scsi_result+8,"TOSHIBA",7))
 		SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
 
-	      SDpnt->removable = (0x80 & 
+	      SDpnt->removable = (0x80 &
 				  scsi_result[1]) >> 7;
 	      SDpnt->lockable = SDpnt->removable;
 	      SDpnt->changed = 0;
 	      SDpnt->access_count = 0;
 	      SDpnt->busy = 0;
-/* 
+/*
  *	Currently, all sequential devices are assumed to be tapes,
- *	all random devices disk, with the appropriate read only 
+ *	all random devices disk, with the appropriate read only
  *	flags set for ROM / WORM treated as RO.
- */ 
+ */
 
 	      switch (type = (scsi_result[0] & 0x1f))
 		{
@@ -460,12 +502,12 @@
 		  type = -1;
 #endif
 		}
-	      
-	      SDpnt->soft_reset = 
+
+	      SDpnt->soft_reset =
 		(scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
 	      SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
 	      SDpnt->type = (type & 0x1f);
-	      
+
 	      if (type != -1)
 		{
 		  print_inquiry(scsi_result);
@@ -479,19 +521,19 @@
 		      (SDpnt->scsi_level == 1 &&
 		       (scsi_result[3] & 0x0f) == 1))
 		    SDpnt->scsi_level++;
-/* 
+/*
  * Set the tagged_queue flag for SCSI-II devices that purport to support
  * tagged queuing in the INQUIRY data.
  */
-		  
+
 		  SDpnt->tagged_queue = 0;
-		  
+
 		  if ((SDpnt->scsi_level >= SCSI_2) &&
 		      (scsi_result[7] & 2)) {
 		    SDpnt->tagged_supported = 1;
 		    SDpnt->current_tag = 0;
 		  }
-		  
+
 /*
  * Accommodate drivers that want to sleep when they should be in a polling
  * loop.
@@ -502,14 +544,14 @@
 /*
  * Some revisions of the Texel CD ROM drives have handshaking
  * problems when used with the Seagate controllers.  Before we
- * know what type of device we're talking to, we assume it's 
+ * know what type of device we're talking to, we assume it's
  * borken and then change it here if it turns out that it isn't
  * a TEXEL drive.
  */
 
 		  if(strncmp("TEXEL", (char *) &scsi_result[8], 5) != 0 ||
-		     strncmp("CD-ROM", (char *) &scsi_result[16], 6) != 0 
-/* 
+		     strncmp("CD-ROM", (char *) &scsi_result[16], 6) != 0
+/*
  * XXX 1.06 has problems, some one should figure out the others too so
  * ALL TEXEL drives don't suffer in performance, especially when I finish
  * integrating my seagate patches which do multiple I_T_L nexuses.
@@ -520,8 +562,8 @@
 #endif
 				 )
 		    SDpnt->borken = 0;
-		  
-		  
+
+
 		  /* These devices need this "key" to unlock the device
 		     so we can use it */
 		  if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
@@ -535,15 +577,15 @@
 		    scsi_cmd[3] = 0;
 		    scsi_cmd[4] = 0x2a;
 		    scsi_cmd[5] = 0;
-		    
+
 		    SCmd.request.dev = 0xffff; /* Mark not busy */
 		    SCmd.cmd_len = 0;
-		    
+
 		    scsi_do_cmd (&SCmd,
-				 (void *)  scsi_cmd, (void *) 
-				 scsi_result, 0x2a,  scan_scsis_done, 
+				 (void *)  scsi_cmd, (void *)
+				 scsi_result, 0x2a,  scan_scsis_done,
 				 SCSI_TIMEOUT, 3);
-		    
+
 		    if (current == task[0]){
 		      while (SCmd.request.dev != 0xfffe);
 		    } else {
@@ -572,16 +614,16 @@
 		    break;
 		  /* Some scsi-1 peripherals do not handle lun != 0.
 		     I am assuming that scsi-2 peripherals do better */
-		  if((scsi_result[2] & 0x07) == 1 && 
+		  if((scsi_result[2] & 0x07) == 1 &&
 		     (scsi_result[3] & 0x0f) == 0) break;
 		}
 	    }       /* if result == DID_OK ends */
 	}       /* for lun ends */
   shpnt->host_queue = NULL;  /* No longer needed here */
-  
+
   /* Last device block does not exist.  Free memory. */
   scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
-  
+
 
   /* If we allocated a buffer so we could do DMA, free it now */
   if (scsi_result != &scsi_result0[0]) scsi_free(scsi_result, 512);
@@ -590,22 +632,22 @@
 }       /* scan_scsis  ends */
 
 /*
- *	Flag bits for the internal_timeout array 
+ *	Flag bits for the internal_timeout array
  */
 
 #define NORMAL_TIMEOUT 0
 #define IN_ABORT 1
 #define IN_RESET 2
 /*
-	This is our time out function, called when the timer expires for a 
-	given host adapter.  It will attempt to abort the currently executing 
+	This is our time out function, called when the timer expires for a
+	given host adapter.  It will attempt to abort the currently executing
 	command, that failing perform a kernel panic.
-*/ 
+*/
 
 static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
 	{
-	
- 	switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
+
+	switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
 		{
 		case NORMAL_TIMEOUT:
 			if (!in_scan_scsis) {
@@ -613,13 +655,13 @@
 			  scsi_dump_status();
 #endif
 			}
-			
+
 			if (!scsi_abort	(SCpnt, DID_TIME_OUT, pid))
-				return;				
+				return;
 		case IN_ABORT:
 			printk("SCSI host %d abort() timed out - resetting\n",
 				SCpnt->host->host_no);
-			if (!scsi_reset (SCpnt)) 
+			if (!scsi_reset (SCpnt))
 				return;
 		case IN_RESET:
 		case (IN_ABORT | IN_RESET):
@@ -633,7 +675,7 @@
 		default:
 			INTERNAL_ERROR;
 		}
-					
+
 	}
 
 
@@ -651,10 +693,10 @@
 
   if (!device)
     panic ("No device passed to request_queueable().\n");
-  
+
   if (req && req->dev <= 0)
     panic("Invalid device in request_queueable");
-  
+
   SCpnt =  device->host->host_queue;
     while(SCpnt){
       if(SCpnt->target == device->id &&
@@ -665,17 +707,7 @@
 
   if (!SCpnt) return NULL;
 
-  if (device->host->can_queue &&
-       ((device->host->block && host_active && device->host != host_active) || 
-        (device->host->block && host_next && device->host != host_next) ||
-        device->host->host_busy >= device->host->can_queue)) {
-
-     if (device->host->block && !host_next && host_active 
-                             && device->host != host_active) 
-        host_next = device->host;
-
-     return NULL;
-     }
+  if (SCSI_BLOCK(device->host)) return NULL;
 
   if (req) {
     memcpy(&SCpnt->request, req, sizeof(struct request));
@@ -706,7 +738,7 @@
     } else {
       req->dev = -1;
       wake_up(&wait_for_request);
-    };      
+    };
   } else {
     SCpnt->request.dev = 0xffff; /* Busy, but no request */
     SCpnt->request.sem = NULL;  /* And no one is waiting for the device either */
@@ -743,26 +775,15 @@
 
   if (!device)
     panic ("No device passed to allocate_device().\n");
-  
+
   if (reqp) req = *reqp;
 
     /* See if this request has already been queued by an interrupt routine */
   if (req && (dev = req->dev) <= 0) return NULL;
-  
-  host = device->host;
-  
-  if (intr_count && host->can_queue &&
-                      ((host->block && host_active && host != host_active) ||
-                       (host->block && host_next && host != host_next) ||
-                       host->host_busy >= host->can_queue)) {
 
-     scsi_maybe_deadlocked = 1;
-
-     if (host->block && !host_next && host_active && host != host_active) 
-        host_next = host;
+  host = device->host;
 
-     return NULL;
-     }
+  if (intr_count && SCSI_BLOCK(host)) return NULL;
 
   while (1==1){
     SCpnt = host->host_queue;
@@ -790,7 +811,7 @@
 		 device->id ,device->lun);
 	  panic("No device found in allocate_device\n");
 	};
-	SCSI_SLEEP(&device->device_wait, 
+	SCSI_SLEEP(&device->device_wait,
 		   (SCwait->request.dev > 0));
       } else {
 	if (req) {
@@ -819,7 +840,7 @@
 	    req->buffer = bh->b_data;
 	    SCpnt->request.sem = NULL; /* Wait until whole thing done */
 	  }
-	  else 
+	  else
 	    {
 	      req->dev = -1;
 	      *reqp = req->next;
@@ -845,12 +866,13 @@
 /*
 	This is inline because we have stack problemes if we recurse to deeply.
 */
-			 
+
 inline void internal_cmnd (Scsi_Cmnd * SCpnt)
 	{
 	int temp;
 	struct Scsi_Host * host;
-#ifdef DEBUG_DELAY	
+	unsigned int flags;
+#ifdef DEBUG_DELAY
 	int clock;
 #endif
 
@@ -860,27 +882,30 @@
 	host = SCpnt->host;
 
 /*
-	We will wait MIN_RESET_DELAY clock ticks after the last reset so 
+	We will wait MIN_RESET_DELAY clock ticks after the last reset so
 	we can avoid the drive not being ready.
-*/ 
-temp = host->last_reset;
+*/
+save_flags(flags);
+sti();
+temp = host->last_reset + MIN_RESET_DELAY;
 while (jiffies < temp);
+restore_flags(flags);
 
 update_timeout(SCpnt, SCpnt->timeout_per_command);
 
 /*
 	We will use a queued command if possible, otherwise we will emulate the
-	queuing and calling of completion function ourselves. 
+	queuing and calling of completion function ourselves.
 */
 #ifdef DEBUG
 	printk("internal_cmnd (host = %d, target = %d, command = %08x, buffer =  %08x, \n"
 		"bufflen = %d, done = %08x)\n", SCpnt->host->host_no, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
 #endif
 
-        if (host->can_queue)
+	if (host->can_queue)
 		{
 #ifdef DEBUG
-	printk("queuecommand : routine at %08x\n", 
+	printk("queuecommand : routine at %08x\n",
 		host->hostt->queuecommand);
 #endif
 		  /* This locking tries to prevent all sorts of races between
@@ -894,7 +919,7 @@
 		if(!intr_count && SCpnt->host->irq)
 		  disable_irq(SCpnt->host->irq);
 
-                host->hostt->queuecommand (SCpnt, scsi_done);
+		host->hostt->queuecommand (SCpnt, scsi_done);
 
 		if(!intr_count && SCpnt->host->irq)
 		  enable_irq(SCpnt->host->irq);
@@ -906,34 +931,34 @@
 	printk("command() :  routine at %08x\n", host->hostt->command);
 #endif
 		temp=host->hostt->command (SCpnt);
-	        SCpnt->result = temp;
+		SCpnt->result = temp;
 #ifdef DEBUG_DELAY
 	clock = jiffies + 400;
 	while (jiffies < clock);
 	printk("done(host = %d, result = %04x) : routine at %08x\n", host->host_no, temp, done);
 #endif
-	        scsi_done(SCpnt);
-		}	
+		scsi_done(SCpnt);
+		}
 #ifdef DEBUG
 	printk("leaving internal_cmnd()\n");
 #endif
-	}	
+	}
 
 static void scsi_request_sense (Scsi_Cmnd * SCpnt)
 	{
 	unsigned int flags;
-	
+
 	save_flags(flags);
 	cli();
 	SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
 	update_timeout(SCpnt, SENSE_TIMEOUT);
 	restore_flags(flags);
-	
+
 
 	memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
 		sizeof(generic_sense));
 
-	SCpnt->cmnd[1] = SCpnt->lun << 5;	
+	SCpnt->cmnd[1] = SCpnt->lun << 5;
 	SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
 
 	SCpnt->request_buffer = &SCpnt->sense_buffer;
@@ -946,96 +971,65 @@
 
 
 /*
-	scsi_do_cmd sends all the commands out to the low-level driver.  It 
-	handles the specifics required for each low level driver - ie queued 
-	or non queued.  It also prevents conflicts when different high level 
+	scsi_do_cmd sends all the commands out to the low-level driver.  It
+	handles the specifics required for each low level driver - ie queued
+	or non queued.  It also prevents conflicts when different high level
 	drivers go for the same host at the same time.
 */
 
-void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , 
+void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
 		  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
-		  int timeout, int retries 
+		  int timeout, int retries
 		   )
-        {
+	{
 	unsigned long flags;
 	struct Scsi_Host * host = SCpnt->host;
 
 #ifdef DEBUG
 	{
-	int i;	
+	int i;
 	int target = SCpnt->target;
 	printk ("scsi_do_cmd (host = %d, target = %d, buffer =%08x, "
 		"bufflen = %d, done = %08x, timeout = %d, retries = %d)\n"
 		"command : " , host->host_no, target, buffer, bufflen, done, timeout, retries);
 	for (i = 0; i < 10; ++i)
-		printk ("%02x  ", ((unsigned char *) cmnd)[i]); 
+		printk ("%02x  ", ((unsigned char *) cmnd)[i]);
 	printk("\n");
       };
 #endif
-	
+
 	if (!host)
 		{
 		panic ("Invalid or not present host.\n");
 		}
 
-	
+
 /*
-	We must prevent reentrancy to the lowlevel host driver.  This prevents 
-	it - we enter a loop until the host we want to talk to is not busy.   
+	We must prevent reentrancy to the lowlevel host driver.  This prevents
+	it - we enter a loop until the host we want to talk to is not busy.
 	Race conditions are prevented, as interrupts are disabled in between the
 	time we check for the host being not busy, and the time we mark it busy
 	ourselves.
 */
 
-	SCpnt->pid = scsi_pid++; 
+	save_flags(flags);
+	cli();
+	SCpnt->pid = scsi_pid++;
+
+	while (SCSI_BLOCK(host)) {
+	   restore_flags(flags);
+	   SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
+	   cli();
+	   }
 
-        for(;;) {
+	if (host->block) host_active = host;
 
-	  save_flags(flags);
-          cli();
+	host->host_busy++;
+	restore_flags(flags);
 
-	  if (host->can_queue &&
-                ((host->block && host_active && host != host_active) ||
-	         (host->block && host_next && host != host_next) ||
-	         host->host_busy >= host->can_queue)) {
-
-             if (intr_count) 
-                panic("scsi: queueing to inactive host while in interrupt.\n");
-
-             if (host->block && !host_next && host_active 
-                                           && host != host_active) 
-                host_next = host;
-
-	     restore_flags(flags);
-	     SCSI_SLEEP(&host->host_wait, 
-                       ((host->block && host_active && host != host_active) ||
-                        (host->block && host_next && host != host_next) ||
-	                host->host_busy >= host->can_queue));
-	     } 
-
-          else {
-	     host->host_busy++;
-
-	     if (host->block) {
-
-	        if (!host_active) {
-                   max_active = 0;
-                   host_active = host;
-                   host_next = NULL;
-                   }
-                else if (max_active > 7 && !host_next) 
-                   host_next = host->block;
-
-                max_active++;
-                }
-
-	     restore_flags(flags);
-	     break;
-	     }
-          }
 /*
-	Our own function scsi_done (which marks the host as not busy, disables 
-	the timeout counter, etc) will be called by us or by the 
+	Our own function scsi_done (which marks the host as not busy, disables
+	the timeout counter, etc) will be called by us or by the
 	scsi_hosts[host].queuecommand() function needs to also call
 	the completion function for the high level driver.
 
@@ -1054,7 +1048,7 @@
 	SCpnt->allowed=retries;
 	SCpnt->done = done;
 	SCpnt->timeout_per_command = timeout;
-				
+
 	memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 12);
 	/* Zero the sense buffer.  Some host adapters automatically request
 	   sense on error.  0 is not a valid sense code.  */
@@ -1075,13 +1069,13 @@
 #ifdef DEBUG
 	printk ("Leaving scsi_do_cmd()\n");
 #endif
-        }
+	}
 
 
 
 /*
-	The scsi_done() function disables the timeout timer for the scsi host, 
-	marks the host as not busy, and calls the user specified completion 
+	The scsi_done() function disables the timeout timer for the scsi host,
+	marks the host as not busy, and calls the user specified completion
 	function for that host's current command.
 */
 
@@ -1090,14 +1084,14 @@
 #ifdef DEBUG
 	printk("scsi: reset(%d)\n", SCpnt->host->host_no);
 #endif
-	
+
 	SCpnt->flags |= (WAS_RESET | IS_RESETTING);
 	scsi_reset(SCpnt);
-	
+
 #ifdef DEBUG
 	printk("performing request sense\n");
 #endif
-	
+
 #if 0  /* FIXME - remove this when done */
 	if(SCpnt->flags & NEEDS_JUMPSTART) {
 	  SCpnt->flags &= ~NEEDS_JUMPSTART;
@@ -1105,8 +1099,8 @@
 	};
 #endif
 }
-	
-	
+
+
 
 static int check_sense (Scsi_Cmnd * SCpnt)
 	{
@@ -1119,7 +1113,7 @@
     else
       return SUGGEST_RETRY;
       }
-  
+
   SCpnt->flags &= ~ASKED_FOR_SENSE;
 
 #ifdef DEBUG_INIT
@@ -1127,7 +1121,7 @@
 	print_sense("", SCpnt);
 	printk("\n");
 #endif
-	        if (SCpnt->sense_buffer[2] &0xe0)
+		if (SCpnt->sense_buffer[2] &0xe0)
 		  return SUGGEST_ABORT;
 
 		switch (SCpnt->sense_buffer[2] & 0xf)
@@ -1138,16 +1132,16 @@
 			return SUGGEST_IS_OK;
 
 		case ABORTED_COMMAND:
-			return SUGGEST_RETRY;	
+			return SUGGEST_RETRY;
 		case NOT_READY:
 		case UNIT_ATTENTION:
 			return SUGGEST_ABORT;
 
-		/* these three are not supported */	
+		/* these three are not supported */
 		case COPY_ABORTED:
 		case VOLUME_OVERFLOW:
 		case MISCOMPARE:
-	
+
 		case MEDIUM_ERROR:
 			return SUGGEST_REMAP;
 		case BLANK_CHECK:
@@ -1198,7 +1192,7 @@
 	/* If we requested an abort, (and we got it) then fix up the return
 	   status to say why */
 	if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
-	  SCpnt->result = result = (result & 0xff00ffff) | 
+	  SCpnt->result = result = (result & 0xff00ffff) |
 	    (SCpnt->abort_reason << 16);
 
 
@@ -1217,7 +1211,7 @@
 		SCpnt->cmd_len = SCpnt->old_cmd_len;
 	}
 
-	switch (host_byte(result))	
+	switch (host_byte(result))
 	{
 	case DID_OK:
 		if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
@@ -1228,7 +1222,7 @@
 
 			if (!(SCpnt->flags & WAS_RESET))
 				{
-				printk("scsi%d : target %d lun %d request sense failed, performing reset.\n", 
+				printk("scsi%d : target %d lun %d request sense failed, performing reset.\n",
 					SCpnt->host->host_no, SCpnt->target, SCpnt->lun);
 				reset(SCpnt);
 				return;
@@ -1253,11 +1247,11 @@
 
 					SCpnt->flags &= ~WAS_SENSE;
 					SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-	
+
 					switch (checked = check_sense(SCpnt))
 					{
 					case SUGGEST_SENSE:
-					case 0: 
+					case 0:
 #ifdef DEBUG
 	printk("NO SENSE.  status = REDO\n");
 #endif
@@ -1265,10 +1259,10 @@
 						update_timeout(SCpnt, oldto);
 						status = REDO;
 						break;
-      					case SUGGEST_IS_OK:
+					case SUGGEST_IS_OK:
 						break;
-					case SUGGEST_REMAP:			
-					case SUGGEST_RETRY: 
+					case SUGGEST_REMAP:
+					case SUGGEST_RETRY:
 #ifdef DEBUG
 	printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
 #endif
@@ -1285,10 +1279,10 @@
 						exit =  DRIVER_SENSE | SUGGEST_ABORT;
 						break;
 					default:
-						printk ("Internal error %s %d \n", __FILE__, 
+						printk ("Internal error %s %d \n", __FILE__,
 							__LINE__);
-					}			   
-					}	
+					}
+					}
 				else
 					{
 #ifdef DEBUG
@@ -1298,16 +1292,16 @@
 					exit =  DRIVER_OK;
 					status = FINISHED;
 					}
-				break;	
+				break;
 
 			case CHECK_CONDITION:
 				switch (check_sense(SCpnt))
 				  {
-				  case 0: 
+				  case 0:
 				    update_timeout(SCpnt, oldto);
 				    status = REDO;
 				    break;
-				  case SUGGEST_REMAP:			
+				  case SUGGEST_REMAP:
 				  case SUGGEST_RETRY:
 				    status = MAYREDO;
 				    exit = DRIVER_SENSE | SUGGEST_RETRY;
@@ -1319,22 +1313,22 @@
 				  case SUGGEST_SENSE:
 				scsi_request_sense (SCpnt);
 				status = PENDING;
-				break;       	
+				break;
 				  }
-				break;       	
-			
+				break;
+
 			case CONDITION_GOOD:
 			case INTERMEDIATE_GOOD:
 			case INTERMEDIATE_C_GOOD:
 				break;
-				
+
 			case BUSY:
 				update_timeout(SCpnt, oldto);
 				status = REDO;
 				break;
 
 			case RESERVATION_CONFLICT:
-				printk("scsi%d : RESERVATION CONFLICT performing reset.\n", 
+				printk("scsi%d : RESERVATION CONFLICT performing reset.\n",
 					SCpnt->host->host_no);
 				reset(SCpnt);
 				return;
@@ -1345,16 +1339,16 @@
 #endif
 			default:
 				printk ("Internal error %s %d \n"
-					"status byte = %d \n", __FILE__, 
+					"status byte = %d \n", __FILE__,
 					__LINE__, status_byte(result));
-				
+
 			}
 			break;
 			default:
-				panic("scsi: unsupported message byte %d received\n", msg_byte(result)); 
+				panic("scsi: unsupported message byte %d received\n", msg_byte(result));
 			}
 			break;
-	case DID_TIME_OUT:	
+	case DID_TIME_OUT:
 #ifdef DEBUG
 	printk("Host returned DID_TIME_OUT - ");
 #endif
@@ -1363,10 +1357,10 @@
 			{
 #ifdef DEBUG
 	printk("Aborting\n");
-#endif	
+#endif
 			exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
-			}		
-		else 
+			}
+		else
 			{
 #ifdef DEBUG
 			printk ("Retrying.\n");
@@ -1386,15 +1380,15 @@
 #endif
 		exit  = (DRIVER_HARD | SUGGEST_ABORT);
 		break;
-	case DID_ERROR:	
+	case DID_ERROR:
 		status = MAYREDO;
 		exit = (DRIVER_HARD | SUGGEST_ABORT);
 		break;
 	case DID_BAD_TARGET:
 	case DID_ABORT:
 		exit = (DRIVER_INVALID | SUGGEST_ABORT);
-		break;	
-        case DID_RESET:
+		break;
+	case DID_RESET:
 		if (SCpnt->flags & IS_RESETTING)
 			{
 			SCpnt->flags &= ~IS_RESETTING;
@@ -1402,14 +1396,14 @@
 			break;
 			}
 
-                if(msg_byte(result) == GOOD &&
-                      status_byte(result) == CHECK_CONDITION) {
+		if(msg_byte(result) == GOOD &&
+		      status_byte(result) == CHECK_CONDITION) {
 			switch (check_sense(SCpnt)) {
-			case 0: 
+			case 0:
 			    update_timeout(SCpnt, oldto);
 			    status = REDO;
 			    break;
-			case SUGGEST_REMAP:			
+			case SUGGEST_REMAP:
 			case SUGGEST_RETRY:
 			    status = MAYREDO;
 			    exit = DRIVER_SENSE | SUGGEST_RETRY;
@@ -1419,20 +1413,20 @@
 			    exit =  DRIVER_SENSE | SUGGEST_ABORT;
 			    break;
 			case SUGGEST_SENSE:
-                              scsi_request_sense (SCpnt);
-                              status = PENDING;
-                              break;
+			      scsi_request_sense (SCpnt);
+			      status = PENDING;
+			      break;
 			}
 		} else {
-                status=REDO;
-                exit = SUGGEST_RETRY;
+		status=REDO;
+		exit = SUGGEST_RETRY;
 		}
-                break;
-	default : 		
+		break;
+	default :
 		exit = (DRIVER_ERROR | SUGGEST_DIE);
 	}
 
-	switch (status) 
+	switch (status)
 		{
 		case FINISHED:
 		case PENDING:
@@ -1447,13 +1441,14 @@
 			if ((++SCpnt->retries) < SCpnt->allowed)
 			{
 			if ((SCpnt->retries >= (SCpnt->allowed >> 1))
+			    && !(jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
 			    && !(SCpnt->flags & WAS_RESET))
-			        {
+				{
 					printk("scsi%d : resetting for second half of retries.\n",
 						SCpnt->host->host_no);
 					reset(SCpnt);
 					break;
-			        }
+				}
 
 			}
 			else
@@ -1465,14 +1460,12 @@
 
 		case REDO:
 
-                        if (host->block) scsi_maybe_deadlocked = 1;
-
-			if (SCpnt->flags & WAS_SENSE)			
-				scsi_request_sense(SCpnt); 	
-			else	
+			if (SCpnt->flags & WAS_SENSE)
+				scsi_request_sense(SCpnt);
+			else
 			  {
 			    memcpy ((void *) SCpnt->cmnd,
-				    (void*) SCpnt->data_cmnd, 
+				    (void*) SCpnt->data_cmnd,
 				    sizeof(SCpnt->data_cmnd));
 			    SCpnt->request_buffer = SCpnt->buffer;
 			    SCpnt->request_bufflen = SCpnt->bufflen;
@@ -1480,8 +1473,8 @@
 			    SCpnt->cmd_len = SCpnt->old_cmd_len;
 			    internal_cmnd (SCpnt);
 			  };
-			break;	
-		default: 
+			break;
+		default:
 			INTERNAL_ERROR;
 		}
 
@@ -1493,30 +1486,24 @@
 	   host->host_busy--; /* Indicate that we are free */
 
 	   if (host->block && host->host_busy == 0) {
-              struct Scsi_Host * block;
-
-              block = host_next;
-              host_active = NULL;
+	      host_active = NULL;
 
-              if (block) wake_up(&block->host_wait);
+	      /* For block devices "wake_up" is done in end_scsi_request */
+	      if (MAJOR(SCpnt->request.dev) != SCSI_DISK_MAJOR &&
+			MAJOR(SCpnt->request.dev) != SCSI_CDROM_MAJOR) {
+		 struct Scsi_Host * next;
+
+		 for (next = host->block; next != host; next = next->block)
+		    wake_up(&next->host_wait);
+		 }
 
-              for (block = host->block; block != host; block = block->block)
-                 wake_up(&block->host_wait);
-
-              host_next = NULL;
-
-              if (scsi_maybe_deadlocked) {
-                 scsi_maybe_deadlocked = 0;
-                 restart_all();
-                 }
-
-              }
+	      }
 
-           wake_up(&host->host_wait);
+	   wake_up(&host->host_wait);
 	   SCpnt->result = result | ((exit & 0xff) << 24);
 	   SCpnt->use_sg = SCpnt->old_use_sg;
 	   SCpnt->cmd_len = SCpnt->old_cmd_len;
-   	   SCpnt->done (SCpnt);
+	   SCpnt->done (SCpnt);
 	   }
 
 #undef FINISHED
@@ -1527,13 +1514,13 @@
 
 /*
 	The scsi_abort function interfaces with the abort() function of the host
-	we are aborting, and causes the current command to not complete.  The 
-	caller should deal with any error messages or status returned on the 
+	we are aborting, and causes the current command to not complete.  The
+	caller should deal with any error messages or status returned on the
 	next call.
-	
+
 	This will not be called reentrantly for a given host.
 */
-	
+
 /*
 	Since we're nice guys and specified that abort() and reset()
 	can be non-reentrant.  The internal_timeout flags are used for
@@ -1546,8 +1533,8 @@
 	int oldto;
 	unsigned long flags;
 	struct Scsi_Host * host = SCpnt->host;
-	
-	while(1)	
+
+	while(1)
 		{
 		save_flags(flags);
 		cli();
@@ -1561,24 +1548,24 @@
 		  return 0;
 		}
 
-		if (SCpnt->internal_timeout & IN_ABORT) 
+		if (SCpnt->internal_timeout & IN_ABORT)
 			{
 			restore_flags(flags);
 			while (SCpnt->internal_timeout & IN_ABORT);
 			}
 		else
-			{	
+			{
 			SCpnt->internal_timeout |= IN_ABORT;
 			oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
 
-			if ((SCpnt->flags & IS_RESETTING) && 
+			if ((SCpnt->flags & IS_RESETTING) &&
 			    SCpnt->device->soft_reset) {
 			  /* OK, this command must have died when we did the
 			     reset.  The device itself must have lied. */
 			  printk("Stale command on %d:%d appears to have died when"
 				 " the bus was reset\n", SCpnt->target, SCpnt->lun);
 			}
-			
+
 			restore_flags(flags);
 			if (!host->host_busy) {
 			  SCpnt->internal_timeout &= ~IN_ABORT;
@@ -1586,7 +1573,7 @@
 			  return 0;
 			}
 			printk("scsi : aborting command due to timeout : pid %lu, scsi%d, id %d, lun %d ",
-			       SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->target, (int) 
+			       SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->target, (int)
 			       SCpnt->lun);
 			print_command (SCpnt->cmnd);
 			if (SCpnt->request.dev == -1 || pid != SCpnt->pid)
@@ -1638,16 +1625,16 @@
 			  return 1;
 			}
 		      }
-	      }	
+	      }
       }
-     
+
 int scsi_reset (Scsi_Cmnd * SCpnt)
 	{
 	int temp, oldto;
 	unsigned long flags;
 	Scsi_Cmnd * SCpnt1;
 	struct Scsi_Host * host = SCpnt->host;
-	
+
 #ifdef DEBUG
 	printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",host->host_no);
 #endif
@@ -1662,16 +1649,16 @@
 		else
 			{
 			SCpnt->internal_timeout |= IN_RESET;
-			oldto = update_timeout(SCpnt, RESET_TIMEOUT);	
-					
+			oldto = update_timeout(SCpnt, RESET_TIMEOUT);
+
 			if (host->host_busy)
-				{	
+				{
 				restore_flags(flags);
 				SCpnt1 = host->host_queue;
 				while(SCpnt1) {
 				  if (SCpnt1->request.dev > 0) {
-#if 0				  
-				    if (!(SCpnt1->flags & IS_RESETTING) && 
+#if 0
+				    if (!(SCpnt1->flags & IS_RESETTING) &&
 				      !(SCpnt1->internal_timeout & IN_ABORT))
 				    scsi_abort(SCpnt1, DID_RESET, SCpnt->pid);
 #endif
@@ -1680,31 +1667,20 @@
 				  SCpnt1 = SCpnt1->next;
 				};
 
-				temp = host->hostt->reset(SCpnt);	
-				}				
+				host->last_reset = jiffies;
+				temp = host->hostt->reset(SCpnt);
+				host->last_reset = jiffies;
+				}
 			else
 				{
-				host->host_busy++;
-
-                                if (host->block) {
-                                   host_active = host;
-                                   host_next = NULL;
-                                   }
-	
+				if (!host->block) host->host_busy++;
 				restore_flags(flags);
+				host->last_reset = jiffies;
 				temp = host->hostt->reset(SCpnt);
 				host->last_reset = jiffies;
-				host->host_busy--;
-
+				if (!host->block) host->host_busy--;
 				}
 
-                        if (host->block && host->host_busy == 0) {
-                           host_active = NULL;
-                           host_next = NULL;
-                           restart_all();
-                           }
-
-
 #ifdef DEBUG
 			printk("scsi reset function returned %d\n", temp);
 #endif
@@ -1723,7 +1699,7 @@
 			  SCpnt->internal_timeout &= ~IN_RESET;
 			  scsi_request_sense (SCpnt);
 			  return 0;
-			case SCSI_RESET_SNOOZE:			  
+			case SCSI_RESET_SNOOZE:
 			  /* In this case, we set the timeout field to 0
 			     so that this command does not time out any more,
 			     and we return 1 so that we get a message on the
@@ -1738,12 +1714,12 @@
 			default:
 			  return 1;
 			}
-	
-			return temp;	
+
+			return temp;
 			}
 		}
 	}
-			 
+
 
 static void scsi_main_timeout(void)
 	{
@@ -1756,7 +1732,7 @@
 	struct Scsi_Host * host;
 	Scsi_Cmnd * SCpnt = NULL;
 
-	do 	{	
+	do {
 		save_flags(flags);
 		cli();
 
@@ -1765,7 +1741,7 @@
 		Find all timers such that they have 0 or negative (shouldn't happen)
 		time remaining on them.
 	*/
-			
+
 		timed_out = 0;
 		for(host = scsi_hostlist; host; host = host->next) {
 		  for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
@@ -1775,23 +1751,23 @@
 			pid = SCpnt->pid;
 			restore_flags(flags);
 			scsi_times_out(SCpnt, pid);
-			++timed_out; 
+			++timed_out;
 			save_flags(flags);
 			cli();
 		      }
 		};
-	      } while (timed_out);	
+	      } while (timed_out);
 	restore_flags(flags);
       }
 
 /*
 	The strategy is to cause the timer code to call scsi_times_out()
-	when the soonest timeout is pending.  
+	when the soonest timeout is pending.
 	The arguments are used when we are queueing a new command, because
 	we do not want to subtract the time used from this time, but when we
 	set the timer, we want to take this value into account.
 */
-	
+
 static int update_timeout(Scsi_Cmnd * SCset, int timeout)
 	{
 	unsigned int least, used;
@@ -1803,18 +1779,18 @@
 	save_flags(flags);
 	cli();
 
-/* 
-	Figure out how much time has passed since the last time the timeouts 
-   	were updated 
+/*
+	Figure out how much time has passed since the last time the timeouts
+	were updated
 */
 	used = (time_start) ? (jiffies - time_start) : 0;
 
 /*
 	Find out what is due to timeout soonest, and adjust all timeouts for
-	the amount of time that has passed since the last time we called 
-	update_timeout. 
+	the amount of time that has passed since the last time we called
+	update_timeout.
 */
-	
+
 	oldto = 0;
 
 	if(SCset){
@@ -1834,24 +1810,24 @@
 	    };
 
 /*
-	If something is due to timeout again, then we will set the next timeout 
+	If something is due to timeout again, then we will set the next timeout
 	interrupt to occur.  Otherwise, timeouts are disabled.
 */
-	
+
 	if (least != 0xffffffff)
 		{
-		time_start = jiffies;	
-		timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;	
+		time_start = jiffies;
+		timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
 		timer_active |= 1 << SCSI_TIMER;
 		}
 	else
 		{
 		timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
 		timer_active &= ~(1 << SCSI_TIMER);
-		}	
+		}
 	restore_flags(flags);
 	return oldto;
-	}		
+	}
 
 
 static unsigned char * dma_malloc_freelist = NULL;
@@ -1872,12 +1848,12 @@
   int i, j;
   if((len & 0x1ff) || len > (1<<MALLOC_PAGEBITS))
     return NULL;
-  
+
   save_flags(flags);
   cli();
   nbits = len >> 9;
   mask = (1 << nbits) - 1;
-  
+
   for(i=0;i < (dma_sectors >> (MALLOC_PAGEBITS - 9)); i++)
     for(j=0; j<=(sizeof(*dma_malloc_freelist) * 8) - nbits; j++){
       if ((dma_malloc_freelist[i] & (mask << j)) == 0){
@@ -1906,13 +1882,13 @@
 
    offset = -1;
   for (page = 0; page < (dma_sectors >> 3); page++)
-  	if ((unsigned long) obj >= (unsigned long) dma_malloc_pages[page] &&
-  		(unsigned long) obj < (unsigned long) dma_malloc_pages[page] + (1 << MALLOC_PAGEBITS))
- 		{
- 			offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
-  			break;
- 		}
- 		 
+	if ((unsigned long) obj >= (unsigned long) dma_malloc_pages[page] &&
+		(unsigned long) obj < (unsigned long) dma_malloc_pages[page] + (1 << MALLOC_PAGEBITS))
+		{
+			offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
+			break;
+		}
+
   if (page == (dma_sectors >> 3)) panic("Bad offset");
   sector = offset >> 9;
   if(sector >= dma_sectors) panic ("Bad page");
@@ -1973,8 +1949,8 @@
 }
 
 /*
-	scsi_dev_init() is our initialization routine, which in turn calls host 
-	initialization, bus scanning, and sd/st initialization routines.  It 
+	scsi_dev_init() is our initialization routine, which in turn calls host
+	initialization, bus scanning, and sd/st initialization routines.  It
 	should be called from main().
 */
 
@@ -1988,7 +1964,7 @@
 	int i;
 #ifdef FOO_ON_YOU
 	return;
-#endif	
+#endif
 
 	/* Init a few things so we can "malloc" memory. */
 	scsi_loadable_module_flag = 0;
@@ -1999,8 +1975,8 @@
 	timer_table[SCSI_TIMER].expires = 0;
 
 	/* initialize all hosts */
-	scsi_init(); 
-				
+	scsi_init();
+
 	scsi_devices = (Scsi_Device *) NULL;
 
 	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
@@ -2012,7 +1988,7 @@
 	    printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
 	    (sdtpnt->dev_noticed != 1) ? "s" : "");
 	printk("total.\n");
-  
+
 	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
 	  if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
 
@@ -2034,8 +2010,8 @@
 	      SCpnt->old_use_sg = 0;
 	      SCpnt->old_cmd_len = 0;
 	      SCpnt->timeout = 0;
-              SCpnt->underflow = 0;
-              SCpnt->transfersize = 0;
+	      SCpnt->underflow = 0;
+	      SCpnt->transfersize = 0;
 	      SCpnt->host_scribble = NULL;
 	      host = SDpnt->host;
 	      if(host->host_queue)
@@ -2057,12 +2033,12 @@
 
 	for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
 	  host = SDpnt->host;
-	  
+
 	  if(SDpnt->type != TYPE_TAPE)
-	    dma_sectors += ((host->sg_tablesize * 
-			     sizeof(struct scatterlist) + 511) >> 9) * 
+	    dma_sectors += ((host->sg_tablesize *
+			     sizeof(struct scatterlist) + 511) >> 9) *
 			       host->cmd_per_lun;
-	  
+
 	  if(host->unchecked_isa_dma &&
 	     memory_end - 1 > ISA_DMA_THRESHOLD &&
 	     SDpnt->type != TYPE_TAPE) {
@@ -2075,17 +2051,17 @@
 	dma_sectors = (dma_sectors + 15) & 0xfff0;
 	dma_free_sectors = dma_sectors;  /* This must be a multiple of 16 */
 
-	dma_malloc_freelist = (unsigned char *) 
+	dma_malloc_freelist = (unsigned char *)
 	  scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
 	memset(dma_malloc_freelist, 0, dma_sectors >> 3);
 
- 	dma_malloc_pages = (unsigned char **) 
- 	  scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
- 	memset(dma_malloc_pages, 0, dma_sectors >> 1);
- 
- 	for(i=0; i< dma_sectors >> 3; i++)
- 	  dma_malloc_pages[i] = (unsigned char *) 
- 	    scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+	dma_malloc_pages = (unsigned char **)
+	  scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
+	memset(dma_malloc_pages, 0, dma_sectors >> 1);
+
+	for(i=0; i< dma_sectors >> 3; i++)
+	  dma_malloc_pages[i] = (unsigned char *)
+	    scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
 
 
 	/* OK, now we finish the initialization by doing spin-up, read
@@ -2093,41 +2069,41 @@
 	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
 	  if(sdtpnt->finish && sdtpnt->nr_dev)
 	    (*sdtpnt->finish)();
-	
+
 	scsi_loadable_module_flag = 1;
 	return scsi_init_memory_start;
 	}
 
 static void print_inquiry(unsigned char *data)
 {
-        int i;
+	int i;
 
 	printk("  Vendor: ");
 	for (i = 8; i < 16; i++)
-	        {
-	        if (data[i] >= 0x20 && i < data[4] + 5)
-		        printk("%c", data[i]);
-	        else
-		        printk(" ");
-	        }
+		{
+		if (data[i] >= 0x20 && i < data[4] + 5)
+			printk("%c", data[i]);
+		else
+			printk(" ");
+		}
 
 	printk("  Model: ");
 	for (i = 16; i < 32; i++)
-	        {
-	        if (data[i] >= 0x20 && i < data[4] + 5)
-		        printk("%c", data[i]);
-	        else
-		        printk(" ");
-	        }
+		{
+		if (data[i] >= 0x20 && i < data[4] + 5)
+			printk("%c", data[i]);
+		else
+			printk(" ");
+		}
 
 	printk("  Rev: ");
 	for (i = 32; i < 36; i++)
-	        {
-	        if (data[i] >= 0x20 && i < data[4] + 5)
-		        printk("%c", data[i]);
-	        else
-		        printk(" ");
-	        }
+		{
+		if (data[i] >= 0x20 && i < data[4] + 5)
+			printk("%c", data[i]);
+		else
+			printk(" ");
+		}
 
 	printk("\n");
 
@@ -2186,8 +2162,14 @@
 	    printk ("scsi%d : %s\n", /* And print a little message */
 		    shpnt->host_no, name);
 	  }
+
+      printk ("scsi : %d host%s.\n", next_scsi_host,
+		(next_scsi_host == 1) ? "" : "s");
+
+      scsi_make_blocked_list();
+
       /* The next step is to call scan_scsis here.  This generates the
-         Scsi_Devices entries */
+	 Scsi_Devices entries */
 
       for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
 	if(shpnt->hostt == tpnt) scan_scsis(shpnt);
@@ -2232,18 +2214,18 @@
 	  unsigned int new_dma_sectors = 0;
 	  unsigned int new_need_isa_buffer = 0;
 	  unsigned char ** new_dma_malloc_pages = NULL;
-	  
+
 	  if (scsi_devicelist)
 	    new_dma_sectors = 16;  /* Base value we use */
-	  
+
 	  for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
 	    host = SDpnt->host;
-	    
+
 	    if(SDpnt->type != TYPE_TAPE)
-	      new_dma_sectors += ((host->sg_tablesize * 
-				   sizeof(struct scatterlist) + 511) >> 9) * 
+	      new_dma_sectors += ((host->sg_tablesize *
+				   sizeof(struct scatterlist) + 511) >> 9) *
 				     host->cmd_per_lun;
-	    
+
 	    if(host->unchecked_isa_dma &&
 	       scsi_need_isa_bounce_buffers &&
 	       SDpnt->type != TYPE_TAPE) {
@@ -2252,21 +2234,21 @@
 	      new_need_isa_buffer++;
 	    };
 	  };
-	  
+
 	  new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
 
-	  new_dma_malloc_freelist = (unsigned char *) 
+	  new_dma_malloc_freelist = (unsigned char *)
 	    scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
 	  memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
-	  
-	  new_dma_malloc_pages = (unsigned char **) 
+
+	  new_dma_malloc_pages = (unsigned char **)
 	    scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
 	  memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
-	  
+
 	  for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++)
-	    new_dma_malloc_pages[i] = (unsigned char *) 
+	    new_dma_malloc_pages[i] = (unsigned char *)
 	      scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-	  
+
 
 	  /* When we dick with the actual DMA list, we need to protect things */
 
@@ -2275,21 +2257,22 @@
 	  memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
 	  scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
 	  dma_malloc_freelist = new_dma_malloc_freelist;
-	  
+
 	  memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
 	  scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
-	  
+
 	  dma_free_sectors += new_dma_sectors - dma_sectors;
 	  dma_malloc_pages = new_dma_malloc_pages;
 	  dma_sectors = new_dma_sectors;
 	  need_isa_buffer = new_need_isa_buffer;
 	  restore_flags(flags);
 
-	  
+
 	}
       /* This does any final handling that is required. */
       for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-	if(sdtpnt->finish) (*sdtpnt->finish)();
+	if(sdtpnt->finish && sdtpnt->nr_dev)
+	  (*sdtpnt->finish)();
     }
   return 0;
 }
@@ -2299,7 +2282,7 @@
  * is trying to remove a low level scsi driver from the system.
  */
 static void scsi_unregister_host(Scsi_Host_Template * tpnt)
-{  
+{
   Scsi_Host_Template * SHT, *SHTp;
   Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
   Scsi_Cmnd * SCpnt;
@@ -2344,7 +2327,7 @@
 	  return;
 	}
       }
-  
+
   /* Next we free up the Scsi_Cmnd structures for this host */
 
   for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
@@ -2355,7 +2338,7 @@
 	sdpnt->host->host_queue = SCpnt;
 	if (SCpnt) SCpnt->prev = NULL;
       }
-  
+
   /* Next free up the Scsi_Device structures for this host */
 
   sdppnt = NULL;
@@ -2376,7 +2359,7 @@
      that were detected */
 
   shpnt = scsi_hostlist;
-  while(shpnt) { 
+  while(shpnt) {
    sh1 = shpnt->next;
     if(shpnt->hostt == tpnt) {
       if(shpnt->loaded_as_module) {
@@ -2388,7 +2371,7 @@
 	     thing for most correctly written host adapters. */
 	  if (shpnt->irq) free_irq(shpnt->irq);
 	  if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel);
-	  if (shpnt->io_port && shpnt->n_io_port) 
+	  if (shpnt->io_port && shpnt->n_io_port)
 	    release_region(shpnt->io_port, shpnt->n_io_port);
 	}
 	if(pcount == next_scsi_host) scsi_unregister(shpnt);
@@ -2398,6 +2381,11 @@
     shpnt = sh1;
   }
 
+  printk ("scsi : %d host%s.\n", next_scsi_host,
+	  (next_scsi_host == 1) ? "" : "s");
+
+  scsi_make_blocked_list();
+
   /* There were some hosts that were loaded at boot time, so we cannot
      do any more than this */
   if (tpnt->present) return;
@@ -2452,7 +2440,7 @@
 }
 
 #ifdef DEBUG_TIMEOUT
-static void 
+static void
 scsi_dump_status(void)
 {
   int i;
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.1.89/linux/drivers/scsi/scsi.h	Sun Feb  5 19:31:54 1995
+++ linux/drivers/scsi/scsi.h	Wed Feb  8 13:14:09 1995
@@ -76,6 +76,7 @@
 #define MODE_SELECT_10		0x55
 #define MODE_SENSE_10		0x5a
 
+extern void scsi_make_blocked_list(void);
 extern volatile int in_scan_scsis;
 extern const unsigned char scsi_command_size[8];
 #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
@@ -528,6 +529,7 @@
 extern int max_scsi_hosts;
 
 #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
+#include "hosts.h"
 static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
 {
 	struct request * req;
@@ -566,6 +568,15 @@
 	if (req->sem != NULL) {
 		up(req->sem);
 	}
+
+        if (SCpnt->host->block) {
+           struct Scsi_Host * next;
+
+           for (next = SCpnt->host->block; next != SCpnt->host;
+                                                   next = next->block)
+              wake_up(&next->host_wait);
+           }
+
 	req->dev = -1;
 	wake_up(&wait_for_request);
 	wake_up(&SCpnt->device->device_wait);
@@ -595,11 +606,16 @@
 	if (CONDITION) {					\
 		struct wait_queue wait = { current, NULL};	\
 		add_wait_queue(QUEUE, &wait);			\
-sleep_repeat:							\
+        for(;;) {       					\
 		current->state = TASK_UNINTERRUPTIBLE;		\
 		if (CONDITION) {				\
-			schedule();				\
-			goto sleep_repeat;			\
+                   if (intr_count)                              \
+                      panic("scsi: trying to call schedule() in interrupt" \
+                            ", file %s, line %d.\n", __FILE__, __LINE__);  \
+		   schedule();				 	\
+		   }              			 	\
+	        else						\
+                   break;                            	        \
 		}						\
 		remove_wait_queue(QUEUE, &wait);		\
 		current->state = TASK_RUNNING;			\
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.1.89/linux/drivers/scsi/sr.c	Wed Feb  1 09:23:06 1995
+++ linux/drivers/scsi/sr.c	Tue Feb  7 11:43:23 1995
@@ -293,19 +293,11 @@
  *     
  *   - TOSHIBA: setting density is done here now, mounting PhotoCD's should
  *              work now without running the program "set_density"
- *              People reported that it is necessary to eject and reinsert
- *              the CD after the set-density call to get this working for
- *              old drives.
- *              And some very new drives don't need this call any more...
  *              Multisession CD's are supported too.
  *
- * Dec 1994: completely rewritten, uses kernel_scsi_ioctl() now
- *
  *   kraxel@cs.tu-berlin.de (Gerd Knorr)
  */
 
-#define DEBUG
-
 static void sr_photocd(struct inode *inode)
 {
   unsigned long   sector,min,sec,frame;
@@ -345,12 +337,14 @@
     if (rc != 0) {
       printk("sr_photocd: ioctl error (NEC): 0x%x\n",rc);
       sector = 0;
+      is_xa = 0;
     } else {
       min   = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;
       sec   = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;
       frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;
       /* if rec[14] isn't 0xb0, the drive does not support multisession CD's, use zero */
       sector = (0xb0 == rec[14]) ? min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame : 0;
+      is_xa = (rec[14] == 0xb0);
 #ifdef DEBUG
       printk("NEC: (%2x) %2li:%02li:%02li = %li\n",buf[8+14],min,sec,frame,sector);
       if (sector) {
@@ -377,6 +371,7 @@
     if (rc != 0) {
       printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
       sector = 0;
+      is_xa = 0;
       break; /* if the first ioctl fails, we don't call the second one */
     }
     is_xa  = (rec[0] == 0x20);
@@ -431,6 +426,8 @@
       if (rc != 0) {
 	printk("sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
       }
+      /* The set_density command may have changed the sector size or capacity. */
+      scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
     }
     break;
 
@@ -440,15 +437,13 @@
     printk("sr_photocd: unknown drive, no special multisession code\n");
 #endif
     sector = 0;
+    is_xa = 0;
     break; }
 
   scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
-  /* The code above may have changed the sector size or capacity. */
-  scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
+  scsi_CDs[MINOR(inode->i_rdev)].is_xa = is_xa;
   return;
 }
-
-#undef DEBUG
 
 static int sr_open(struct inode * inode, struct file * filp)
 {
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- v1.1.89/linux/drivers/scsi/sr.h	Thu Nov 24 14:18:34 1994
+++ linux/drivers/scsi/sr.h	Tue Feb  7 11:43:23 1995
@@ -25,6 +25,7 @@
 	unsigned 	sector_size;		/* size in bytes 			*/
 	Scsi_Device  	*device;		
 	unsigned long   mpcd_sector;            /* for reading multisession-CD's        */
+	char            is_xa;                  /* is it an XA-CD ?                     */
 	unsigned char	sector_bit_size;	/* sector size = 2^sector_bit_size	*/
 	unsigned char	sector_bit_shift;	/* sectors/FS block = 2^sector_bit_shift*/
 	unsigned 	needs_sector_size:1;   	/* needs to get sector size */
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v1.1.89/linux/drivers/scsi/sr_ioctl.c	Sun Feb  5 19:31:54 1995
+++ linux/drivers/scsi/sr_ioctl.c	Tue Feb  7 11:43:23 1995
@@ -408,11 +408,8 @@
 			    ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
 			  else return (-EINVAL);
 			
-			  if (scsi_CDs[target].mpcd_sector)
-			    ms_info.xa_flag=1; /* valid redirection address */
-			  else
-			    ms_info.xa_flag=0; /* invalid redirection address */
-			  
+			  ms_info.xa_flag=scsi_CDs[target].is_xa;
+			 			  
 			  err=verify_area(VERIFY_WRITE,(void *) arg,
 					  sizeof(struct cdrom_multisession));
 			  if (err) return (err);
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v1.1.89/linux/drivers/scsi/u14-34f.c	Sun Feb  5 19:31:54 1995
+++ linux/drivers/scsi/u14-34f.c	Wed Feb  8 13:14:09 1995
@@ -1,6 +1,9 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *       8 Feb 1995 rev. 1.15 for linux 1.1.89
+ *          Cleared target_time_out counter while preforming a reset.
+ *
  *      28 Jan 1995 rev. 1.14 for linux 1.1.86
  *          Added module support.
  *          Log and do a retry when a disk drive returns a target status
@@ -34,7 +37,7 @@
  * 
  *          Multiple U14F and/or U34F host adapters are supported.
  *
- *      Released by Dario Ballabio (Dario_Ballabio@milano.europe.dg.com)
+ *      Copyright (C) 1994, 1995 Dario Ballabio (dario@milano.europe.dg.com)
  *
  *      WARNING: if your 14F board has an old firmware revision (see below)
  *               you must change "#undef" into "#define" in the following
@@ -113,6 +116,7 @@
 
 #if defined(MODULE)
 #include <linux/module.h>
+#include <linux/version.h>
 #endif
 
 #include <linux/string.h>
@@ -295,7 +299,7 @@
 
    sti();
    time = jiffies;
-   while (jiffies < (time + 100) && limit++ < 100000000) sti();
+   while (jiffies < (time + 100) && limit++ < 100000000);
    cli();
 
    if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
@@ -424,11 +428,7 @@
       sprintf(BN(j), "U34F%d", j);
       }
    else {
-
-#if !defined(MODULE)
-      /* The module code does not checkin/checkout in the blocking list yet */
       sh[j]->block = sh[j];
-#endif
 
 #if defined (HAVE_OLD_U14F_FIRMWARE)
       sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
@@ -491,6 +491,9 @@
       port_base++;
       }
 
+   if (j > 0) 
+      printk("UltraStor 14F/34F: Copyright (C) 1994, 1995 Dario Ballabio.\n");
+
    restore_flags(flags);
    return j;
 }
@@ -691,6 +694,8 @@
 
    for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE;
 
+   for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0;
+
    for (i = 0; i < sh[j]->can_queue; i++) {
 
       if (HD(j)->cp_stat[i] == FREE) continue;
@@ -733,7 +738,7 @@
    HD(j)->in_reset = TRUE;
    sti();
    time = jiffies;
-   while (jiffies < (time + 200) && limit++ < 100000000) sti();
+   while (jiffies < (time + 100) && limit++ < 100000000);
    cli();
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -879,8 +884,7 @@
                   status = DID_BUS_BUSY << 16;
 
                else if (tstatus == CHECK_CONDITION
-                        && (SCpnt->device->type == TYPE_DISK
-                         || SCpnt->device->type == TYPE_ROM)
+                        && SCpnt->device->type == TYPE_DISK
                         && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION)
                   status = DID_ERROR << 16;
    
@@ -890,8 +894,7 @@
                if (tstatus == GOOD)
                   HD(j)->target_reset[SCpnt->target] = FALSE;
 
-               if (spp->target_status && (SCpnt->device->type == TYPE_DISK
-                                       || SCpnt->device->type == TYPE_ROM))
+               if (spp->target_status && SCpnt->device->type == TYPE_DISK)
                   printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
                          "0x%x, sense key 0x%x.\n", BN(j), 
                          SCpnt->target, SCpnt->lun, SCpnt->pid,
diff -u --recursive --new-file v1.1.89/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v1.1.89/linux/drivers/scsi/u14-34f.h	Sun Feb  5 19:31:54 1995
+++ linux/drivers/scsi/u14-34f.h	Wed Feb  8 13:14:09 1995
@@ -10,15 +10,14 @@
 int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_biosparam(Disk *, int, int *);
 
-#define U14_34F_VERSION "1.14.05"
+#define U14_34F_VERSION "1.15.00"
 
 #define ULTRASTOR_14_34F {                                            \
-                NULL,                                                 \
-                NULL,                                                 \
-                "UltraStor 14F/34F rev. " U14_34F_VERSION " by "      \
-                "Dario_Ballabio@milano.europe.dg.com.",               \
+                NULL, /* Ptr for modules */                           \
+                NULL, /* usage count for modules */	              \
+                "UltraStor 14F/34F rev. " U14_34F_VERSION " ",        \
                 u14_34f_detect,                                       \
-                NULL,                                                 \
+                NULL, /* Release */                                   \
                 NULL,		                                      \
                 NULL,                                                 \
                 u14_34f_queuecommand,                                 \
diff -u --recursive --new-file v1.1.89/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v1.1.89/linux/drivers/sound/Readme	Fri Aug 19 08:54:07 1994
+++ linux/drivers/sound/Readme	Wed Feb  8 09:00:29 1995
@@ -74,7 +74,13 @@
 hannu@voxware.pp.fi
 
 Snail mail:	Hannu Savolainen
-		Pallaksentie 4 A 2
-		00970 Helsinki
+		Hiekkalaiturintie 3 A 8
+		00980 Helsinki
 		Finland
-FAX:		+358 0 395 1968 (usually not connected)
+FAX:		+358 0 341 6272 (answers if I have my machine (mgetty) on).
+
+NOTE!	I propably don't answer to Snail mail or FAX messages. Sending answer
+	to each of them is simply too expensive and time consuming. However I
+	try to reply every email message I get (within a week). If you don't
+	get response, please check how your address is written in the message
+	header. I can't answer if I don't have a valid reply address.
diff -u --recursive --new-file v1.1.89/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v1.1.89/linux/fs/isofs/inode.c	Thu Jan 26 07:49:07 1995
+++ linux/fs/isofs/inode.c	Tue Feb  7 11:43:23 1995
@@ -145,6 +145,43 @@
 	return 1;
 }
 
+
+static unsigned int isofs_get_last_session(int dev)
+{
+  struct cdrom_multisession ms_info;
+  unsigned int vol_desc_start;
+  struct inode inode_fake;
+  extern struct file_operations * get_blkfops(unsigned int);
+  int i;
+
+  /*
+   * look if the driver can tell the multi session redirection value
+   * <emoenke@gwdg.de>
+   */
+  vol_desc_start=0;
+  if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
+    {
+      inode_fake.i_rdev=dev;
+      ms_info.addr_format=CDROM_LBA;
+      set_fs(KERNEL_DS);
+      i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+				       NULL,
+				       CDROMMULTISESSION,
+				       (unsigned long) &ms_info);
+      set_fs(USER_DS);
+#if 0 
+      printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+      if (i==0)
+	{
+	  printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
+	  printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
+	}
+#endif 0
+      if ((i==0)&&(ms_info.xa_flag)) vol_desc_start=ms_info.addr.lba;
+    }
+  return vol_desc_start;
+}
+
 struct super_block *isofs_read_super(struct super_block *s,void *data,
 				     int silent)
 {
@@ -153,11 +190,8 @@
 	unsigned int blocksize_bits;
 	int high_sierra;
 	int dev=s->s_dev;
-	int i;
-	struct cdrom_multisession ms_info;
 	unsigned int vol_desc_start;
-	struct inode inode_fake;
-	extern struct file_operations * get_blkfops(unsigned int);
+
 	struct iso_volume_descriptor *vdp;
 	struct hs_volume_descriptor *hdp;
 
@@ -200,34 +234,11 @@
 
 	s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
 
-	/*
-	 * look if the driver can tell the multi session redirection value
-	 * <emoenke@gwdg.de>
-	 */
-	vol_desc_start=0;
-	if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
-	  {
-	    inode_fake.i_rdev=dev;
-	    ms_info.addr_format=CDROM_LBA;
-	    set_fs(KERNEL_DS);
-	    i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
-					     NULL,
-					     CDROMMULTISESSION,
-					     (unsigned long) &ms_info);
-	    set_fs(USER_DS);
-#if 0
-	    printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
-	    if (i==0)
-	      {
-		printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
-		printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
-	      }
-#endif 0
-	    if ((i==0)&&(ms_info.xa_flag)) vol_desc_start=ms_info.addr.lba;
-	  }
+	vol_desc_start = isofs_get_last_session(dev);
+	
 	for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) {
 #if 0
-	printk("isofs.inode: iso_blknum=%d\n", iso_blknum);
+	        printk("isofs.inode: iso_blknum=%d\n", iso_blknum);
 #endif 0
 		if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), opt.blocksize))) {
 			s->s_dev=0;
diff -u --recursive --new-file v1.1.89/linux/fs/nfs/sock.c linux/fs/nfs/sock.c
--- v1.1.89/linux/fs/nfs/sock.c	Thu Jan 26 07:49:08 1995
+++ linux/fs/nfs/sock.c	Tue Feb  7 11:43:23 1995
@@ -37,9 +37,6 @@
  * ***FIXME*** should probably put this in nfs_fs.h */
 #define NFS_SLACK_SPACE 1024
 
-
-extern struct socket *socki_lookup(struct inode *inode);
-
 #define _S(nr) (1<<((nr)-1))
 
 /*
@@ -81,7 +78,7 @@
 	file = server->file;
 	inode = file->f_inode;
 	select = file->f_op->select;
-	sock = socki_lookup(inode);
+	sock = &inode->u.socket_i;
 	if (!sock) {
 		printk("nfs_rpc_call: socki_lookup failed\n");
 		return -EBADF;
diff -u --recursive --new-file v1.1.89/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v1.1.89/linux/include/asm-i386/bugs.h	Wed Dec 28 16:58:19 1994
+++ linux/include/asm-i386/bugs.h	Wed Feb  8 10:03:50 1995
@@ -94,7 +94,7 @@
 		return;
 
 	}
-	printk("Ok, FDIV bug i%c86 system\n", '0'+x86);
+	printk("Hmm, FDIV bug i%c86 system\n", '0'+x86);
 }
 
 static void check_hlt(void)
diff -u --recursive --new-file v1.1.89/linux/include/asm-sparc/cprefix.h linux/include/asm-sparc/cprefix.h
--- v1.1.89/linux/include/asm-sparc/cprefix.h	Sun Feb  5 19:31:55 1995
+++ linux/include/asm-sparc/cprefix.h	Mon Feb  6 20:42:52 1995
@@ -1,7 +1,7 @@
 /* cprefix.h:  This file is included by assembly source which needs
  *             to know what the c-label prefixes are. The newer versions
  *	       of cpp that come with gcc predefine such things to help
- *	       us out. The reason this stuff is neaded is to make
+ *	       us out. The reason this stuff is needed is to make
  *	       solaris compiles of the kernel work.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v1.1.89/linux/include/linux/pci.h linux/include/linux/pci.h
--- v1.1.89/linux/include/linux/pci.h	Sun Feb  5 19:31:55 1995
+++ linux/include/linux/pci.h	Mon Feb  6 20:42:52 1995
@@ -226,8 +226,10 @@
 #define PCI_DEVICE_ID_DEC_TULIP		0x0002
 #define PCI_DEVICE_ID_DEC_TULIP_FAST	0x0009
 #define PCI_DEVICE_ID_DEC_FDDI		0x000F
+#define PCI_DEVICE_ID_DEC_BRD		0x0001
 
 #define PCI_VENDOR_ID_MATROX		0x102B
+#define PCI_DEVICE_ID_MATROX_2plus	0x0518
 
 #define PCI_VENDOR_ID_INTEL		0x8086
 #define PCI_DEVICE_ID_INTEL_82378	0x0484
@@ -262,13 +264,13 @@
 #define PCI_DEVICE_ID_AI_M1435		0x1435
 
 #define PCI_VENDOR_ID_AL		0x10b9
-#define PCI_DEVICE_ID_AL_M1449		0x4449
+#define PCI_DEVICE_ID_AL_M1449		0x1449
 #define PCI_DEVICE_ID_AL_M1451		0x1451
 
 #define PCI_VENDOR_ID_TSENG		0x100c
 #define PCI_DEVICE_ID_TSENG_W32P_2	0x3202
 #define PCI_DEVICE_ID_TSENG_W32P_b	0x3205
-#define PCI_DEVICE_ID_TSENG_W32P_a	0x3207
+#define PCI_DEVICE_ID_TSENG_W32P_c	0x3207
 
 #define PCI_VENDOR_ID_CMD		0x1095
 #define PCI_DEVICE_ID_CMD_640		0x0640
@@ -290,6 +292,7 @@
 
 #define PCI_VENDOR_ID_TRIDENT		0x1023
 #define PCI_DEVICE_ID_TRIDENT_9420	0x9420
+#define PCI_DEVICE_ID_TRIDENT_9440	0x9440
 
 #define PCI_VENDOR_ID_CONTAQ		0x1080
 #define PCI_DEVICE_ID_CONTAQ_82C599	0x0600
@@ -300,19 +303,30 @@
 #define PCI_DEVICE_ID_VIA_82C505	0x0505
 
 #define PCI_VENDOR_ID_SI		0x1039
-#define PCI_DEVICE_ID_SI_MG1936		0x0406
-#define PCI_DEVICE_ID_SI_MG1938		0x0008
+#define PCI_DEVICE_ID_SI_496		0x0496
+#define PCI_DEVICE_ID_SI_501		0x0406
+#define PCI_DEVICE_ID_SI_503		0x0008
 
 #define PCI_VENDOR_ID_LEADTEK		0x107d
 #define PCI_DEVICE_ID_LEADTEK_805	0x0000
 
+#define PCI_VENDOR_ID_IMS		0x10e0
+#define PCI_DEVICE_ID_IMS_8849		0x8849
+
+#define PCI_VENDOR_ID_ZEINET		0x1193
+#define PCI_DEVICE_ID_ZEINET_1221	0x0001
+
+#define PCI_VENDOR_ID_EF		0x111a
+#define PCI_DEVICE_ID_EF_ATM		0x0000
+
+
 struct pci_vendor_type {
 	unsigned short vendor_id;
 	char *vendor_name;
 };
 
 
-#define PCI_VENDOR_NUM 30
+#define PCI_VENDOR_NUM 33
 #define PCI_VENDOR_TYPE { \
 	{PCI_VENDOR_ID_NCR,		"NCR"}, \
 	{PCI_VENDOR_ID_ADAPTEC,		"Adaptec"}, \
@@ -343,7 +357,10 @@
 	{PCI_VENDOR_ID_NS,		"NS"}, \
 	{PCI_VENDOR_ID_VIA,		"VIA Technologies"}, \
 	{PCI_VENDOR_ID_SI,		"Silicon Integrated"}, \
-	{PCI_VENDOR_ID_LEADTEK,		"Leadtek Research"} \
+	{PCI_VENDOR_ID_LEADTEK,		"Leadtek Research"}, \
+	{PCI_VENDOR_ID_IMS,		"IMS"}, \
+	{PCI_VENDOR_ID_ZEINET,		"ZeiNet"}, \
+	{PCI_VENDOR_ID_EF,		"Efficient Networks"} \
 }
 
 
@@ -362,7 +379,7 @@
 	char *device_name;
 };
 
-#define PCI_DEVICE_NUM 54
+#define PCI_DEVICE_NUM 61
 #define PCI_DEVICE_TYPE { \
 	{0xff,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	"53c810"}, \
 	{0xff,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C815,	"53c815"}, \
@@ -385,6 +402,8 @@
 	{0xff,	PCI_VENDOR_ID_DEC,	PCI_DEVICE_ID_DEC_TULIP,	"DC21040"}, \
 	{0xff,	PCI_VENDOR_ID_DEC,	PCI_DEVICE_ID_DEC_TULIP_FAST,	"DC21040"}, \
 	{0xff,	PCI_VENDOR_ID_DEC,	PCI_DEVICE_ID_DEC_FDDI,		"DEFPA"}, \
+	{0xff,	PCI_VENDOR_ID_DEC,	PCI_DEVICE_ID_DEC_BRD,		"DC21050"}, \
+	{0xff,	PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_2plus,	"MGA/2+"}, \
 	{0xff,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82378,	"82378IB"}, \
 	{0x00,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82424,	"82424ZX Saturn"}, \
 	{0xff,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82375,	"82375EB"}, \
@@ -405,7 +424,7 @@
 	{0xff,	PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M1451,		"M1451"}, \
 	{0xff,	PCI_VENDOR_ID_TSENG,	PCI_DEVICE_ID_TSENG_W32P_2,	"ET4000W32P"}, \
 	{0xff,	PCI_VENDOR_ID_TSENG,	PCI_DEVICE_ID_TSENG_W32P_b,	"ET4000W32P rev B"}, \
-	{0xff,	PCI_VENDOR_ID_TSENG,	PCI_DEVICE_ID_TSENG_W32P_a,	"ET4000W32P rev A"}, \
+	{0xff,	PCI_VENDOR_ID_TSENG,	PCI_DEVICE_ID_TSENG_W32P_c,	"ET4000W32P rev C"}, \
 	{0xff,	PCI_VENDOR_ID_CMD,	PCI_DEVICE_ID_CMD_640,		"640A"}, \
 	{0xff,	PCI_VENDOR_ID_VISION,	PCI_DEVICE_ID_VISION_QD8500,	"QD-8500PCI"}, \
 	{0xff,	PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_LANCE,	"79C970"}, \
@@ -413,11 +432,16 @@
 	{0xff,	PCI_VENDOR_ID_ADL,	PCI_DEVICE_ID_ADL_2301,		"2301"}, \
 	{0xff,	PCI_VENDOR_ID_SYMPHONY,	PCI_DEVICE_ID_SYMPHONY_101,	"82C101"}, \
 	{0xff,	PCI_VENDOR_ID_TRIDENT,	PCI_DEVICE_ID_TRIDENT_9420,	"TG 9420"}, \
+	{0xff,	PCI_VENDOR_ID_TRIDENT,	PCI_DEVICE_ID_TRIDENT_9440,	"TG 9440"}, \
 	{0xff,	PCI_VENDOR_ID_CONTAQ,	PCI_DEVICE_ID_CONTAQ_82C599,	"82C599"}, \
 	{0xff,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C505,	"VT 82C505"}, \
-	{0xff,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_MG1936,	"MG1936 ??"}, \
-	{0xff,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_MG1938,	"MG1938 ??"}, \
-	{0xff,	PCI_VENDOR_ID_LEADTEK,	PCI_DEVICE_ID_LEADTEK_805,	"S3 805"} \
+	{0xff,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		"85C496"}, \
+	{0xff,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_501,		"85C501"}, \
+	{0xff,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		"85C503"}, \
+	{0xff,	PCI_VENDOR_ID_LEADTEK,	PCI_DEVICE_ID_LEADTEK_805,	"S3 805"}, \
+	{0xff,	PCI_VENDOR_ID_IMS,	PCI_DEVICE_ID_IMS_8849,		"8849"}, \
+	{0xff,	PCI_VENDOR_ID_ZEINET,	PCI_DEVICE_ID_ZEINET_1221,	"1221"}, \
+	{0xff,	PCI_VENDOR_ID_EF,	PCI_DEVICE_ID_EF_ATM,		"155P-MF1"} \
 }
 
 /* An item of this structure has the following meaning	*/
diff -u --recursive --new-file v1.1.89/linux/include/linux/serial.h linux/include/linux/serial.h
--- v1.1.89/linux/include/linux/serial.h	Wed Feb  1 09:23:07 1995
+++ linux/include/linux/serial.h	Wed Feb  8 12:28:48 1995
@@ -22,19 +22,10 @@
 	unsigned short	close_delay;
 	char	reserved_char[2];
 	int	hub6;
-	unsigned short	closing_wait; /* time to wait before rcvr shutdown */
-	unsigned short	closing_wait2; /* time to wait after rcvr shutdown */
-	int	reserved[4];
+	int	reserved[5];
 };
 
 /*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define ASYNC_CLOSING_WAIT_INF	0
-#define ASYNC_CLOSING_WAIT_NONE	65535
-
-/*
  * These are the supported serial types.
  */
 #define PORT_UNKNOWN	0
@@ -42,9 +33,8 @@
 #define PORT_16450	2
 #define PORT_16550	3
 #define PORT_16550A	4
-#define PORT_CIRRUS     5	/* Hey!  Who put this there? */
-#define PORT_16650	6
-#define PORT_MAX	6
+#define PORT_CIRRUS     5
+#define PORT_MAX	5
 
 /*
  * Definitions for async_struct (and serial_struct) flags field
@@ -106,8 +96,6 @@
 	int			custom_divisor;
 	int			x_char;	/* xon/xoff character */
 	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
 	int			IER; 	/* Interrupt Enable Register */
 	int			MCR; 	/* Modem control register */
 	int			MCR_noint; /* MCR with interrupts off */
diff -u --recursive --new-file v1.1.89/linux/include/linux/serial_reg.h linux/include/linux/serial_reg.h
--- v1.1.89/linux/include/linux/serial_reg.h	Wed Feb  1 09:23:07 1995
+++ linux/include/linux/serial_reg.h	Wed Feb  8 12:28:48 1995
@@ -21,8 +21,6 @@
 #define UART_IER	1	/* Out: Interrupt Enable Register */
 #define UART_IIR	2	/* In:  Interrupt ID Register */
 #define UART_FCR	2	/* Out: FIFO Control Register */
-#define UART_EFR	2	/* I/O: Extended Features Register */
-				/* (DLAB=1, 16C660 only) */
 #define UART_LCR	3	/* Out: Line Control Register */
 #define UART_MCR	4	/* Out: Modem Control Register */
 #define UART_LSR	5	/* In:  Line Status Register */
@@ -31,7 +29,6 @@
 
 /*
  * These are the definitions for the FIFO Control Register
- * (16650 only)
  */
 #define UART_FCR_ENABLE_FIFO	0x01 /* Enable the FIFO */
 #define UART_FCR_CLEAR_RCVR	0x02 /* Clear the RCVR FIFO */
@@ -42,15 +39,6 @@
 #define UART_FCR_TRIGGER_4	0x40 /* Mask for trigger set at 4 */
 #define UART_FCR_TRIGGER_8	0x80 /* Mask for trigger set at 8 */
 #define UART_FCR_TRIGGER_14	0xC0 /* Mask for trigger set at 14 */
-/* 16650 redefinitions */
-#define UART_FCR6_R_TRIGGER_8	0x00 /* Mask for receive trigger set at 1 */
-#define UART_FCR6_R_TRIGGER_16	0x40 /* Mask for receive trigger set at 4 */
-#define UART_FCR6_R_TRIGGER_24  0x80 /* Mask for receive trigger set at 8 */
-#define UART_FCR6_R_TRIGGER_28	0xC0 /* Mask for receive trigger set at 14 */
-#define UART_FCR6_T_TRIGGER_16	0x00 /* Mask for transmit trigger set at 16 */
-#define UART_FCR6_T_TRIGGER_8	0x10 /* Mask for transmit trigger set at 8 */
-#define UART_FCR6_T_TRIGGER_24  0x20 /* Mask for transmit trigger set at 24 */
-#define UART_FCR6_T_TRIGGER_30	0x30 /* Mask for transmit trigger set at 30 */
 
 /*
  * These are the definitions for the Line Control Register
@@ -120,18 +108,6 @@
 #define UART_MSR_DDSR	0x02	/* Delta DSR */
 #define UART_MSR_DCTS	0x01	/* Delta CTS */
 #define UART_MSR_ANY_DELTA 0x0F	/* Any of the delta bits! */
-
-/*
- * These are the definitions for the Extended Features Register
- * (StarTech 16C660 only, when DLAB=1)
- */
-#define UART_EFR_CTS	0x80	/* CTS flow control */
-#define UART_EFR_RTS	0x40	/* RTS flow control */
-#define UART_EFR_SCD	0x20	/* Special character detect */
-#define UART_EFR_ENI	0x10	/* Enhanced Interrupt */
-/*
- * the low four bits control software flow control
- */
 
 #endif /* _LINUX_SERIAL_REG_H */
 
diff -u --recursive --new-file v1.1.89/linux/include/linux/tty.h linux/include/linux/tty.h
--- v1.1.89/linux/include/linux/tty.h	Mon Dec 12 21:19:00 1994
+++ linux/include/linux/tty.h	Mon Feb  6 20:43:11 1995
@@ -283,7 +283,7 @@
 			      const char *routine);
 extern char *_tty_name(struct tty_struct *tty, char *buf);
 extern char *tty_name(struct tty_struct *tty);
-extern void wait_until_sent(struct tty_struct * tty, int timeout);
+extern void tty_wait_until_sent(struct tty_struct * tty, int timeout);
 extern int tty_check_change(struct tty_struct * tty);
 extern void stop_tty(struct tty_struct * tty);
 extern void start_tty(struct tty_struct * tty);
diff -u --recursive --new-file v1.1.89/linux/ipc/sem.c linux/ipc/sem.c
--- v1.1.89/linux/ipc/sem.c	Sun Feb  5 19:31:55 1995
+++ linux/ipc/sem.c	Mon Feb  6 20:42:52 1995
@@ -9,7 +9,7 @@
  * wake up processes that were waiting for semval to go to 0 if the
  * value went to 0 and was then incremented rapidly enough. In solving
  * this problem I have also modified the implementation so that it
- * processes pending operations in a FIFO manner, thus give a guarentee
+ * processes pending operations in a FIFO manner, thus give a guarantee
  * that processes waiting for a lock on the semaphore won't starve
  * unless another locking process fails to unlock.
  * In addition the following two changes in behavior have been introduced:
@@ -20,7 +20,7 @@
  *   have read permissions. The implementation now returns 0
  *   on success as stated in the manual page.
  * - There is some confusion over whether the set of undo adjustments
- *   to be peformed at exit should be done in an atomic manner.
+ *   to be performed at exit should be done in an atomic manner.
  *   That is, if we are attempting to decrement the semval should we queue
  *   up and wait until we can do so legally?
  *   The original implementation attempted to do this.
diff -u --recursive --new-file v1.1.89/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.89/linux/kernel/ksyms.c	Sun Feb  5 19:31:55 1995
+++ linux/kernel/ksyms.c	Mon Feb  6 20:43:16 1995
@@ -173,6 +173,12 @@
 	X(register_serial),
 	X(unregister_serial),
 
+	/* tty routines */
+	X(tty_hangup),
+	X(tty_wait_until_sent),
+	X(tty_check_change),
+	X(tty_hung_up_p),
+
 	/* filesystem registration */
 	X(register_filesystem),
 	X(unregister_filesystem),
diff -u --recursive --new-file v1.1.89/linux/mm/memory.c linux/mm/memory.c
--- v1.1.89/linux/mm/memory.c	Wed Feb  1 09:23:08 1995
+++ linux/mm/memory.c	Mon Feb  6 20:46:31 1995
@@ -268,116 +268,149 @@
 	return 0;
 }
 
+static inline void forget_pte(pte_t page)
+{
+	if (pte_none(page))
+		return;
+	if (pte_present(page)) {
+		free_page(pte_page(page));
+		if (mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED)
+			return;
+		if (current->mm->rss <= 0)
+			return;
+		current->mm->rss--;
+		return;
+	}
+	swap_free(pte_val(page));
+}
+
+static inline void unmap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
+{
+	pte_t * pte;
+	unsigned long end;
+
+	if (pmd_none(*pmd))
+		return;
+	if (pmd_bad(*pmd)) {
+		printk("unmap_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
+		pmd_clear(pmd);
+		return;
+	}
+	pte = pte_offset(pmd, address);
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end >= PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		pte_t page = *pte;
+		pte_clear(pte);
+		forget_pte(page);
+		address += PAGE_SIZE;
+		pte++;
+	} while (address < end);
+}
+
+static inline void unmap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
+{
+	pmd_t * pmd;
+	unsigned long end;
+
+	if (pgd_none(*dir))
+		return;
+	if (pgd_bad(*dir)) {
+		printk("unmap_pmd_range: bad pgd (%08lx)\n", pgd_val(*dir));
+		pgd_clear(dir);
+		return;
+	}
+	pmd = pmd_offset(dir, address);
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	do {
+		unmap_pte_range(pmd, address, end - address);
+		address = (address + PMD_SIZE) & PMD_MASK; 
+		pmd++;
+	} while (address < end);
+}
+
 /*
  * a more complete version of free_page_tables which performs with page
  * granularity.
  */
-int unmap_page_range(unsigned long from, unsigned long size)
+int unmap_page_range(unsigned long address, unsigned long size)
 {
-	pgd_t page_dir, * dir;
-	pte_t page, * page_table;
-	unsigned long poff, pcnt, pc;
-
-	if (from & ~PAGE_MASK) {
-		printk("unmap_page_range called with wrong alignment\n");
-		return -EINVAL;
-	}
-	size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
-	dir = PAGE_DIR_OFFSET(current,from);
-	poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
-	if ((pcnt = PTRS_PER_PAGE - poff) > size)
-		pcnt = size;
-
-	for ( ; size > 0; ++dir, size -= pcnt,
-	     pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) {
-	     	page_dir = *dir;
-	     	if (pgd_none(page_dir)) {
-			poff = 0;
-			continue;
-		}
-		if (pgd_bad(page_dir)) {
-			printk("unmap_page_range: bad page directory.");
-			continue;
-		}
-		page_table = (pte_t *) pgd_page(page_dir);
-		if (poff) {
-			page_table += poff;
-			poff = 0;
-		}
-		for (pc = pcnt; pc--; page_table++) {
-			page = *page_table;
-			if (!pte_none(page)) {
-				pte_clear(page_table);
-				if (pte_present(page)) {
-					if (!(mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED))
-						if (current->mm->rss > 0)
-							--current->mm->rss;
-					free_page(pte_page(page));
-				} else
-					swap_free(pte_val(page));
-			}
-		}
-		if (pcnt == PTRS_PER_PAGE) {
-			pgd_clear(dir);
-			free_page(pgd_page(page_dir));
-		}
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	dir = pgd_offset(current, address);
+	while (address < end) {
+		unmap_pmd_range(dir, address, end - address);
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
 	}
 	invalidate();
 	return 0;
 }
 
-int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot)
+static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pte_t zero_pte)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		pte_t oldpage = *pte;
+		*pte = zero_pte;
+		forget_pte(oldpage);
+		address += PAGE_SIZE;
+		pte++;
+	} while (address < end);
+}
+
+static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size, pte_t zero_pte)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	do {
+		pte_t * pte = pte_alloc(pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		zeromap_pte_range(pte, address, end - address, zero_pte);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address < end);
+	return 0;
+}
+
+int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
 {
+	int error = 0;
 	pgd_t * dir;
-	pte_t * page_table;
-	unsigned long poff, pcnt;
+	unsigned long end = address + size;
 	pte_t zero_pte;
 
-	if (from & ~PAGE_MASK) {
-		printk("zeromap_page_range: from = %08lx\n",from);
-		return -EINVAL;
-	}
 	zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE, prot));
-	dir = PAGE_DIR_OFFSET(current,from);
-	size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
-	poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
-	if ((pcnt = PTRS_PER_PAGE - poff) > size)
-		pcnt = size;
-
-	while (size > 0) {
-		if (!pgd_present(*dir)) {
-			if (!(page_table = (pte_t *) get_free_page(GFP_KERNEL))) {
-				invalidate();
-				return -ENOMEM;
-			}
-			if (pgd_present(*dir)) {
-				free_page((unsigned long) page_table);
-				page_table = (pte_t *) pgd_page(*dir);
-			} else
-				pgd_set(dir, page_table);
-		} else
-			page_table = (pte_t *) pgd_page(*dir);
+	dir = pgd_offset(current, address);
+	while (address < end) {
+		pmd_t *pmd = pmd_alloc(dir, address);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		error = zeromap_pmd_range(pmd, address, end - address, zero_pte);
+		if (error)
+			break;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-		page_table += poff;
-		poff = 0;
-		for (size -= pcnt; pcnt-- ;) {
-			pte_t page = *page_table;
-			if (!pte_none(page)) {
-				pte_clear(page_table);
-				if (pte_present(page)) {
-					if (!(mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED))
-						if (current->mm->rss > 0)
-							--current->mm->rss;
-					free_page(pte_page(page));
-				} else
-					swap_free(pte_val(page));
-			}
-			*page_table++ = zero_pte;
-		}
-		pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size);
 	}
 	invalidate();
-	return 0;
+	return error;
 }
 
 /*
diff -u --recursive --new-file v1.1.89/linux/net/inet/icmp.c linux/net/inet/icmp.c
--- v1.1.89/linux/net/inet/icmp.c	Mon Jan 30 08:53:06 1995
+++ linux/net/inet/icmp.c	Tue Feb  7 18:03:51 1995
@@ -372,11 +372,14 @@
 			 *	Add better route to host.
 			 *	But first check that the redirect
 			 *	comes from the old gateway..
+			 *	And make sure it's an ok host address
+			 *	(not some confused thing sending our
+			 *	address)
 			 */
 			rt = ip_rt_route(ip, NULL, NULL);
 			if (!rt)
 				break;
-			if (rt->rt_gateway != source)
+			if (rt->rt_gateway != source || ip_chk_addr(icmph->un.gateway))
 				break;
 			printk("redirect from %s\n", in_ntoa(source));
 			ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
diff -u --recursive --new-file v1.1.89/linux/net/inet/ip_fw.c linux/net/inet/ip_fw.c
--- v1.1.89/linux/net/inet/ip_fw.c	Sun Feb  5 19:31:56 1995
+++ linux/net/inet/ip_fw.c	Sun Feb  5 23:26:45 1995
@@ -424,7 +424,7 @@
 } /* End of whole function */
 #endif /* CONFIG_IP_ACCT */
 
-#ifdef CONFIG_IP_ACCT
+#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 
 static void zero_fw_chain(struct ip_fw *chainptr)
 {
@@ -436,10 +436,6 @@
 		ctmp=ctmp->next;
 	}
 }
-
-#endif
-
-#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 
 static void free_fw_chain(struct ip_fw *volatile* chainptr)
 {
diff -u --recursive --new-file v1.1.89/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.89/linux/net/inet/tcp.c	Sun Feb  5 19:31:56 1995
+++ linux/net/inet/tcp.c	Tue Feb  7 18:18:10 1995
@@ -371,7 +371,9 @@
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) 
+	{
+		skb->sk->dead=1;
 		tcp_close(skb->sk, 0);
 		kfree_skb(skb, FREE_READ);
 	}
@@ -607,10 +609,11 @@
 	{
 		sk->err = ETIMEDOUT;
 		sk->error_report(sk);
+		del_timer(&sk->retransmit_timer);
 		/*
 		 *	Time wait the socket 
 		 */
-		if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING) 
+		if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING ) 
 		{
 			tcp_set_state(sk,TCP_TIME_WAIT);
 			reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
@@ -2850,6 +2853,8 @@
 	{
 		sk->err = -ENOMEM;
 		newsk->dead = 1;
+		newsk->state = TCP_CLOSE;
+		/* And this will destroy it */
 		release_sock(newsk);
 		kfree_skb(skb, FREE_READ);
 		tcp_statistics.TcpAttemptFails++;
@@ -2879,6 +2884,7 @@
 		buff->free = 1;
 		kfree_skb(buff,FREE_WRITE);
 		newsk->dead = 1;
+		newsk->state = TCP_CLOSE;
 		release_sock(newsk);
 		skb->sk = sk;
 		kfree_skb(skb, FREE_READ);
@@ -2917,8 +2923,6 @@
 
 	tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);
 	newsk->prot->queue_xmit(newsk, ndev, buff, 0);
-	reset_xmit_timer(newsk, TIME_WRITE, newsk->rto);
-
 	reset_xmit_timer(newsk, TIME_WRITE , TCP_TIMEOUT_INIT);
 	skb->sk = newsk;
 
