diff -u --recursive --new-file v1.1.65/linux/Makefile linux/Makefile
--- v1.1.65/linux/Makefile	Tue Nov 22 15:41:10 1994
+++ linux/Makefile	Tue Nov 22 15:40:46 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 65
+SUBLEVEL = 66
 
 ARCH = i386
 
diff -u --recursive --new-file v1.1.65/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.1.65/linux/arch/i386/config.in	Fri Nov 18 15:22:09 1994
+++ linux/arch/i386/config.in	Fri Nov 25 14:00:12 1994
@@ -6,6 +6,7 @@
 comment 'General setup'
 
 bool 'Kernel math emulation' CONFIG_MATH_EMULATION n
+bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y
 bool 'Normal harddisk support' CONFIG_BLK_DEV_HD y
 bool 'XT harddisk support' CONFIG_BLK_DEV_XD n
 bool 'Networking support' CONFIG_NET y
@@ -57,8 +58,9 @@
 bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
 bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
 bool 'NCR53c7,8xx SCSI support'  CONFIG_SCSI_NCR53C7xx n
-#bool 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 n
+bool 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 n
 bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n
+bool 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC n
 bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n
 bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
 bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
@@ -116,6 +118,7 @@
 		bool 'NI6510 support' CONFIG_NI65 n
 	fi
 	bool 'HP PCLAN support' CONFIG_HPLAN n
+	bool 'HP PCLAN PLUS support' CONFIG_HPLAN_PLUS n
 	bool 'NE2000/NE1000 support' CONFIG_NE2000 y
 	bool 'SK_G16 support' CONFIG_SK_G16 n
 fi
@@ -163,7 +166,11 @@
 if [ "$CONFIG_INET" = "y" ]; then
 bool 'NFS filesystem support' CONFIG_NFS_FS y
 fi
-bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
+if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
+	bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
+else
+	bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
+fi
 bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
 bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
 
diff -u --recursive --new-file v1.1.65/linux/drivers/block/blk.h linux/drivers/block/blk.h
--- v1.1.65/linux/drivers/block/blk.h	Thu Oct  6 08:45:18 1994
+++ linux/drivers/block/blk.h	Fri Nov 25 10:43:58 1994
@@ -45,6 +45,13 @@
 #endif CONFIG_SBPCD
 extern void set_device_ro(int dev,int flag);
 
+extern void floppy_init(void);
+#ifdef FD_MODULE
+static
+#else
+extern
+#endif
+int new_floppy_init(void);
 extern void rd_load(void);
 extern long rd_init(long mem_start, int length);
 extern int ramdisk_size;
diff -u --recursive --new-file v1.1.65/linux/drivers/block/cdu31a.c linux/drivers/block/cdu31a.c
--- v1.1.65/linux/drivers/block/cdu31a.c	Tue Nov 22 15:41:10 1994
+++ linux/drivers/block/cdu31a.c	Tue Nov 22 15:40:13 1994
@@ -673,7 +673,7 @@
    *result_size = 2;
 
    /*
-    * 0x20 means an error occured.  Byte 2 will have the error code.
+    * 0x20 means an error occurred.  Byte 2 will have the error code.
     * Otherwise, the command succeeded, byte 2 will have the count of
     * how many more status bytes are coming.
     *
@@ -2781,7 +2781,7 @@
       }
       else
       {
-	 printk("CDU31A: Unknown interface type: %s\n", strings[3]);
+	 printk("CDU31A: Unknown interface type: %s\n", strings);
       }
    }
 }
diff -u --recursive --new-file v1.1.65/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.65/linux/drivers/block/floppy.c	Tue Nov 22 15:41:10 1994
+++ linux/drivers/block/floppy.c	Fri Nov 25 14:00:17 1994
@@ -4,34 +4,6 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1993, 1994  Alain Knaff
  */
-
-/* Configuration */
-/* The following does some extra sanity checks */
-#define SANITY
-
-/* the following is the mask of allowed drives. By default units 2 and
- * 3 of both floppy controllers are disabled, because switching on the
- * motor of these drives causes system hangs on some PCI computers. drive
- * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
- * a drive is allowed. */
-
-#define ALLOWED_DRIVE_MASK 0x33
-
-
-/* Undefine the following if you have to floppy disk controllers:
- * This works at least for me; if you get two controllers working, with
- * drives attached to both, please mail me: Alain.Knaff@imag.fr */
-/* #define HAVE_2_CONTROLLERS */
-
-
-/* Define the following if you don't like that your drives seek audibly
- * after a disk change (but it may not work correctly for everybody)
- */
-/* #define SILENT_DC_CLEAR */
-
-
-/* End of configuration */
-
 /*
  * 02.12.91 - Changed to static variables to indicate need for reset
  * and recalibrate. This makes some things easier (output_byte reset
@@ -109,13 +81,39 @@
  * errors to allow safe writing by specialized programs.
  */
 
+#define CONFIG_FLOPPY_SANITY
+#undef  CONFIG_FLOPPY_23
+#undef  CONFIG_FLOPPY_2_FDC
+#undef  CONFIG_FLOPPY_SILENT_DCL_CLEAR
+
 #define REALLY_SLOW_IO
-#define FLOPPY_IRQ 6
-#define FLOPPY_DMA 2
 
 #define DEBUGT 2
+#define DCL_DEBUG /* debug disk change line */
 
 #include <linux/config.h>
+
+#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
+ * motor of these drives causes system hangs on some PCI computers. drive
+ * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
+ * a drive is allowed. */
+#ifdef CONFIG_FLOPPY_23
+#define ALLOWED_DRIVE_MASK 0xff
+#else
+#define ALLOWED_DRIVE_MASK 0x33
+#endif
+
+#define FLOPPY_IRQ 6
+#define FLOPPY_DMA 2
+#define FDC1 0x3f0
+#define FDC2 0x370
+#endif
+
+#define MODULE_AWARE_DRIVER
+
+#ifdef CONFIG_BLK_DEV_FD
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -139,11 +137,11 @@
 #define MAJOR_NR FLOPPY_MAJOR
 #include "blk.h"
 
-static unsigned int changed_floppies = 0xff, fake_change = 0;
+static unsigned int fake_change = 0;
 static int initialising=1;
 
 
-#ifdef HAVE_2_CONTROLLERS
+#ifdef CONFIG_FLOPPY_2_FDC
 #define N_FDC 2
 #define N_DRIVE 8
 #else
@@ -161,11 +159,17 @@
 #define DRS (&drive_state[current_drive])
 #define DRWE (&write_errors[current_drive])
 #define FDCS (&fdc_state[fdc])
+#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags))
+#define SETF(x) (set_bit(x##_BIT, &DRS->flags))
+#define TESTF(x) (test_bit(x##_BIT, &DRS->flags))
 
 #define UDP (&drive_params[drive])
 #define UDRS (&drive_state[drive])
 #define UDRWE (&write_errors[drive])
 #define UFDCS (&fdc_state[FDC(drive)])
+#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags))
+#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);
 
@@ -200,8 +204,9 @@
 /*
  * Maximum disk size (in kilobytes). This default is used whenever the
  * current disk size is unknown.
+ * [Now it is rather a minimum]
  */
-#define MAX_DISK_SIZE 3984
+#define MAX_DISK_SIZE 2 /* 3984*/
 
 
 
@@ -280,8 +285,8 @@
 };
 
 static struct floppy_drive_params drive_params[N_DRIVE];
-static struct floppy_drive_struct volatile drive_state[N_DRIVE];
-static struct floppy_write_errors volatile write_errors[N_DRIVE];
+static struct floppy_drive_struct drive_state[N_DRIVE];
+static struct floppy_write_errors write_errors[N_DRIVE];
 static struct floppy_raw_cmd raw_cmd;
 
 /*
@@ -335,7 +340,7 @@
 /* Auto-detection: Disk type used until the next media change occurs. */
 struct floppy_struct *current_type[N_DRIVE] = {
 	NULL, NULL, NULL, NULL
-#ifdef HAVE_2_CONTROLLERS
+#ifdef CONFIG_FLOPPY_2_FDC
 	,
 	NULL, NULL, NULL, NULL
 #endif
@@ -367,6 +372,9 @@
 static struct wait_queue *fdc_wait = NULL, *command_done = NULL;
 #define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible)
 #define CALL(x) if( (x) == -EINTR) return -EINTR;
+#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
+#define WAIT(x) _WAIT((x),interruptible)
+#define IWAIT(x) _WAIT((x),1)
 
 /* Errors during formatting are counted here. */
 static int format_errors;
@@ -400,10 +408,10 @@
 done_f done; /* this is called to say if the operation has succeeded/failed */
 } *cont;
 
+static void floppy_ready(void);
 static void floppy_start(void);
-static void redo_fd_request(void);
+static void process_fd_request(void);
 static void recalibrate_floppy(void);
-static void seek_floppy(void);
 static void floppy_shutdown(void);
 
 static int floppy_grab_irq_and_dma(void);
@@ -427,7 +435,10 @@
 #define NO_TRACK -1
 #define NEED_1_RECAL -2
 #define NEED_2_RECAL -3
-#define PROVEN_ABSENT -4
+
+/* */
+static int usage_count = 0;
+
 
 /* buffer related variables */
 static int buffer_track = -1;
@@ -437,10 +448,10 @@
 
 /* fdc related variables, should end up in a struct */
 static struct floppy_fdc_state fdc_state[N_FDC];
-int fdc; /* current fdc */
+static int fdc; /* current fdc */
 
 static struct floppy_struct * floppy = floppy_type;
-static unsigned char current_drive = 255;
+static unsigned char current_drive = 0;
 static long current_count_sectors = 0;
 static char *current_addr = 0;
 static unsigned char sector_t; /* sector in track */
@@ -478,14 +489,17 @@
 
 /*
  * disk change.
- * This routine is responsible for maintaining the changed_floppies flag,
+ * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
  * and the last_checked date.
  *
  * last_checked is the date of the last check which showed 'no disk change'
- * changed_floppies is set under two conditions:
+ * FD_DISK_CHANGE is set under two conditions:
  * 1. The floppy has been changed after some i/o to that floppy already
  *    took place.
- * 2. No floppy disk is in the drive.
+ * 2. No floppy disk is in the drive. This is done in order to ensure that
+ *    requests are quickly flushed in case there is no disk in the drive. It
+ *    follows that FD_DISK_CHANGE can only be cleared if there is a disk in
+ *    the drive.
  *
  * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
  * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
@@ -500,62 +514,102 @@
 
 static int disk_change(int drive)
 {
-	if(jiffies < DP->select_delay + DRS->select_date)
-		udelay(20000);
+	int fdc=FDC(drive);
+#ifdef CONFIG_FLOPPY_SANITY
+	if(jiffies < UDP->select_delay + UDRS->select_date)
+		DPRINT("WARNING disk change called early\n");
+	if(! (FDCS->dor & (0x10 << UNIT(drive))) ||
+	   (FDCS->dor & 3) != UNIT(drive) ||
+	   fdc != FDC(drive)){
+		DPRINT("probing disk change on unselected drive\n");
+		DPRINT3("drive=%d fdc=%d dor=%x\n",drive, FDC(drive),
+			FDCS->dor);
+	}
+#endif
 
-	if(inb_p(FD_DIR) & 0x80){
-		UDRS->flags |= FD_VERIFY; /* verify write protection */
-		
-		if(UDRS->maxblock || /* disk change check */
-		   !(UDRS->flags & FD_DISK_NEWCHANGE)){/* disk presence check */
-			/* mark it changed or absent */
-			set_bit(drive,&changed_floppies);
+#ifdef DCL_DEBUG
+	if (UDP->flags & FD_DEBUG){
+		DPRINT1("checking disk change line for drive %d\n",drive);
+		DPRINT1("jiffies=%ld\n", jiffies);
+		DPRINT1("disk change line=%x\n",inb_p(FD_DIR)&0x80);
+		DPRINT1("flags=%x\n",UDRS->flags);
+	}
+#endif
+	if (UDP->flags & FD_BROKEN_DCL)
+		return UTESTF(FD_DISK_CHANGED);
+	if( (inb_p(FD_DIR) ^ UDP->flags) & 0x80){
+		USETF(FD_VERIFY); /* verify write protection */		
+		if(UDRS->maxblock){
+			/* mark it changed */
+			USETF(FD_DISK_CHANGED);
 
 			/* invalidate its geometry */
 			if (UDRS->keep_data >= 0) {
-				if ((DP->flags & FTD_MSG) &&
+				if ((UDP->flags & FTD_MSG) &&
 				    current_type[drive] != NULL)
 					DPRINT("Disk type is undefined after "
 					       "disk change\n");
 				current_type[drive] = NULL;
-				floppy_sizes[drive] = MAX_DISK_SIZE;
+				floppy_sizes[DRIVE(current_drive) + (FDC(current_drive) << 7)] = MAX_DISK_SIZE;
 			}
 		}
-		UDRS->flags |= FD_DISK_NEWCHANGE;
+		/*USETF(FD_DISK_NEWCHANGE);*/
 		return 1;
-	} else {
+	} else if(jiffies >= DRS->select_date+DP->select_delay){
 		UDRS->last_checked=jiffies;
-		UDRS->flags &= ~FD_DISK_NEWCHANGE;
-		return 0;
+		UCLEARF(FD_DISK_NEWCHANGE);
 	}
+	return 0;
+}
+
+static inline int is_selected(int dor, int unit)
+{
+	return ( (dor  & (0x10 << unit)) && (dor &3) == unit);
 }
 
-static int locked=0;
 static int set_dor(int fdc, char mask, char data)
 {
 	register unsigned char drive, unit, newdor,olddor;
 
-	locked=1;
+	if(FDCS->address == -1)
+		return -1;
+
 	olddor = FDCS->dor;
 	newdor =  (olddor & mask) | data;
 	if ( newdor != olddor ){
 		unit = olddor & 0x3;
-		drive = REVDRIVE(fdc,unit);
-		if ( olddor & ( 0x10 << unit ))
+		if(is_selected(olddor, unit) && !is_selected(newdor,unit)){
+			drive = REVDRIVE(fdc,unit);
+#ifdef DCL_DEBUG
+	if (UDP->flags & FD_DEBUG){
+		DPRINT("calling disk change from set_dor\n");
+	}
+#endif
 			disk_change(drive);
+		}
 		FDCS->dor = newdor;
-		outb_p( newdor, FD_DOR);
+		outb_p(newdor, FD_DOR);
+
+		unit = newdor & 0x3;
+		if(!is_selected(olddor, unit) && is_selected(newdor,unit)){
+			drive = REVDRIVE(fdc,unit);
+			UDRS->select_date = jiffies;
+		}
 	}
-	locked=0;
+	if ( newdor & 0xf0 )
+		floppy_grab_irq_and_dma();
+	if( olddor & 0xf0 )
+		floppy_release_irq_and_dma();
 	return olddor;
 }
 
 static void twaddle(void)
 {
-	cli();
+	if (DP->select_delay)
+		return;
 	outb_p(FDCS->dor & ~(0x10<<UNIT(current_drive)),FD_DOR);
 	outb_p(FDCS->dor, FD_DOR);
-	sti();
+	DRS->select_date = jiffies;
 }
 
 /* reset all driver information about the current fdc. This is needed after
@@ -570,7 +624,6 @@
 	FDCS->rawcmd = 0;
 	for ( drive = 0; drive < N_DRIVE; drive++)
 		if (FDC(drive) == fdc &&
-		    UDRS->track != PROVEN_ABSENT &&
 		    ( mode || UDRS->track != NEED_1_RECAL))
 			UDRS->track = NEED_2_RECAL;
 }
@@ -578,12 +631,12 @@
 /* selects the fdc and drive, and enables the fdc's input/dma. */
 static void set_fdc(int drive)
 {
-	if ( drive >= 0 ){
+	if (drive >= 0 && drive < N_DRIVE){
 		fdc = FDC(drive);
 		current_drive = drive;
 	}
 	set_dor(fdc,~0,8);
-#ifdef HAVE_2_CONTROLLERS
+#ifdef CONFIG_FLOPPY_2_FDC
 	set_dor(1-fdc, ~8, 0);
 #endif
 	if ( FDCS->rawcmd == 2 )
@@ -592,16 +645,16 @@
 		FDCS->reset = 1;
 }
 
-static int usage_count = 0;
 /* locks the driver */
 static int lock_fdc(int drive, int interruptible)
 {
-
 	if(!usage_count){
 		printk("trying to lock fdc while usage count=0\n");
 		return -1;
 	}
 	floppy_grab_irq_and_dma();
+	if (!current->pid)
+		run_task_queue(&tq_timer);
 	cli();
 	while (fdc_busy && NO_SIGNAL)
 		interruptible_sleep_on(&fdc_wait);
@@ -619,6 +672,10 @@
 #define LOCK_FDC(drive,interruptible) \
 if(lock_fdc(drive,interruptible)) return -EINTR;
 
+typedef void (*timeout_fn)(unsigned long);
+static struct timer_list fd_timeout ={ NULL, NULL, 0, 0, 
+					       (timeout_fn) floppy_shutdown };
+
 /* unlocks the driver */
 static inline void unlock_fdc(void)
 {
@@ -629,7 +686,7 @@
 		DPRINT1("device interrupt still active at FDC release: %p!\n",
 			DEVICE_INTR);
 	command_status = FD_COMMAND_NONE;
-	timer_active &= ~(1 << FLOPPY_TIMER);
+	del_timer(&fd_timeout);
 	fdc_busy = 0;
 	floppy_release_irq_and_dma();
 	wake_up(&fdc_wait);
@@ -640,10 +697,7 @@
 {
 	unsigned char mask = ~(0x10 << UNIT(nr));
 
-	if(locked)
-		floppy_off(nr);
-	else
-		set_dor( FDC(nr), mask, 0 );
+	set_dor( FDC(nr), mask, 0 );
 }
 
 static struct timer_list motor_off_timer[N_DRIVE] = {
@@ -651,7 +705,7 @@
 	{ NULL, NULL, 0, 1, motor_off_callback },
 	{ NULL, NULL, 0, 2, motor_off_callback },
 	{ NULL, NULL, 0, 3, motor_off_callback }
-#ifdef HAVE_2_CONTROLLERS
+#ifdef CONFIG_FLOPPY_2_FDC
 	,
 	{ NULL, NULL, 0, 4, motor_off_callback },
 	{ NULL, NULL, 0, 5, motor_off_callback },
@@ -661,26 +715,25 @@
 };
 
 /* schedules motor off */
-static void floppy_off(unsigned int nr)
+static void floppy_off(unsigned int drive)
 {
 	unsigned long volatile delta;
-	register int fdc=FDC(nr);
+	register int fdc=FDC(drive);
 
-	if( !(FDCS->dor & ( 0x10 << UNIT(nr))))
+	if( !(FDCS->dor & ( 0x10 << UNIT(drive))))
 		return;
 
-	del_timer(motor_off_timer+nr);
+	del_timer(motor_off_timer+drive);
 
 	/* make spindle stop in a position which minimizes spinup time
 	 * next time */
-	if ( drive_params[nr].rps ){
-		delta = jiffies - drive_state[nr].first_read_date + HZ -
-			drive_params[nr].spindown_offset;
-		delta = (( delta * drive_params[nr].rps) % HZ ) /
-			drive_params[nr].rps;
-		motor_off_timer[nr].expires = drive_params[nr].spindown - delta;
+	if (UDP->rps ){
+		delta = jiffies - UDRS->first_read_date + HZ -
+			UDP->spindown_offset;
+		delta = (( delta * UDP->rps) % HZ ) / UDP->rps;
+		motor_off_timer[drive].expires = UDP->spindown - delta;
 	}
-	add_timer(motor_off_timer+nr);
+	add_timer(motor_off_timer+drive);
 }
 
 /*
@@ -691,32 +744,37 @@
 static void scandrives(void)
 {
 	int i, drive, saved_drive;
+	
+	if (DP->select_delay)
+		return;
 
-	saved_drive = current_drive % N_DRIVE;
+	saved_drive = current_drive;
 	for(i=0; i< N_DRIVE; i++){
 		drive = (saved_drive + i + 1 ) % N_DRIVE;
-		if ( UDRS->fd_ref == 0 )
+		if ( UDRS->fd_ref == 0 || UDP->select_delay != 0)
 			continue; /* skip closed drives */
 		set_fdc(drive);
-		if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
-		    ((FDCS->dor & 0x3) != UNIT(drive)))
-			UDRS->select_date = jiffies;
 		if(! (set_dor( fdc, ~3, UNIT(drive) | ( 0x10 << UNIT(drive))) &
 		      (0x10 << UNIT(drive))))
 			/* switch the motor off again, if it was off to
 			 * begin with */
 			set_dor( fdc, ~( 0x10 << UNIT(drive) ), 0 );
 	}
-	current_drive = saved_drive;
+	set_fdc(saved_drive);
 }
 
-typedef void (*timeout_fn)(unsigned long);
 static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 };
 
 /* this function makes sure that the disk stays in the drive during the
  * transfer */
 static void fd_watchdog(void)
 {
+#ifdef DCL_DEBUG
+	if (DP->flags & FD_DEBUG){
+		DPRINT("calling disk change from watchdog\n");
+	}
+#endif
+
 	if ( disk_change(current_drive) ){
 		DPRINT("disk removed during i/o\n");
 		floppy_shutdown();
@@ -735,7 +793,7 @@
 }
 
 /* waits for a delay (spinup or select) to pass */
-static int wait_for_completion(int nr, int delay, timeout_fn function)
+static int wait_for_completion(int delay, timeout_fn function)
 {
 	if ( FDCS->reset ){
 		reset_fdc(); /* do the reset during sleep to win time
@@ -756,7 +814,7 @@
 
 static void setup_DMA(void)
 {
-#ifdef SANITY
+#ifdef CONFIG_FLOPPY_SANITY
 	if ((!CURRENT ||
 	     CURRENT->buffer != current_addr ||
 	     raw_cmd.length > 512 * CURRENT->nr_sectors) &&
@@ -998,11 +1056,11 @@
  * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
  * of the specify command (i.e. using the fdc_specify function).
  */
-static void fdc_dtr(void)
+static int fdc_dtr(void)
 {
 	/* If data rate not already set to desired value, set it. */
 	if ( raw_cmd.rate == FDCS->dtr)
-		return;
+		return 0;
 	
 	/* Set dtr */
 	outb_p(raw_cmd.rate, FD_DCR);
@@ -1010,10 +1068,11 @@
 	/* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
 	 * need a stabilization period of several milliseconds to be
 	 * enforced after data rate changes before R/W operations.
-	 * Pause 5 msec to avoid trouble.
+	 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
 	 */
-	udelay(5000);
 	FDCS->dtr = raw_cmd.rate;
+	return(wait_for_completion(jiffies+2,
+				   (timeout_fn) floppy_ready));
 } /* fdc_dtr */
 
 static void tell_sector(void)
@@ -1042,15 +1101,15 @@
 
 	/* check IC to find cause of interrupt */
 	switch ((ST0 & ST0_INTR)>>6) {
-		case 1:	/* error occured during command execution */
+		case 1:	/* error occurred during command execution */
 			bad = 1;
 			if (ST1 & ST1_WP) {
 				DPRINT("Drive is write protected\n");
-				DRS->flags &= ~FD_DISK_WRITABLE;
+				CLEARF(FD_DISK_WRITABLE);
 				cont->done(0);
 				bad = 2;
 			} else if (ST1 & ST1_ND) {
-				DRS->flags |= FD_NEED_TWADDLE;
+				SETF(FD_NEED_TWADDLE);
 			} else if (ST1 & ST1_OR) {
 				if (DP->flags & FTD_MSG )
 					DPRINT("Over/Underrun - retrying\n");
@@ -1126,7 +1185,7 @@
 			function = (timeout_fn) setup_rw_floppy;
 
 		/* wait until the floppy is spinning fast enough */
-		if (wait_for_completion(current_drive,ready_date,function))
+		if (wait_for_completion(ready_date,function))
 			return;
 	}
 	dflags = DRS->flags;
@@ -1156,9 +1215,7 @@
 		fd_watchdog();
 }
 
-#ifdef SILENT_DC_CLEAR
 static int blind_seek;
-#endif
 
 /*
  * This is the routine called after every seek (or recalibrate) interrupt
@@ -1169,9 +1226,6 @@
 #ifdef DEBUGT
 	debugt("seek interrupt:");
 #endif
-#ifdef SILENT_DC_CLEAR
-	set_dor(fdc, ~0,  (0x10 << UNIT(current_drive)));
-#endif
 	if (inr != 2 || (ST0 & 0xF8) != 0x20 ) {
 		DPRINT("seek failed\n");
 		DRS->track = NEED_2_RECAL;
@@ -1179,20 +1233,23 @@
 		cont->redo();
 		return;
 	}
-	if (DRS->track >= 0 && DRS->track != ST1    
-#ifdef SILENT_DC_CLEAR
-	    && !blind_seek
+	if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek){
+#ifdef DCL_DEBUG
+		if (DP->flags & FD_DEBUG){
+			DPRINT("clearing NEWCHANGE flag because of effective seek\n");
+			DPRINT1("jiffies=%ld\n", jiffies);
+		}
 #endif
-	    )
-		DRS->flags &= ~FD_DISK_NEWCHANGE; /* effective seek */
+		CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
+		DRS->select_date = jiffies;
+	}
 	DRS->track = ST1;
-	DRS->select_date = jiffies;
-	seek_floppy();
+	floppy_ready();
 }
 
 static void check_wp(void)
 {
-	if (DRS->flags & FD_VERIFY) {
+	if (TESTF(FD_VERIFY)) {
 		/* check write protection */
 		output_byte( FD_GETSTATUS );
 		output_byte( UNIT(current_drive) );
@@ -1200,10 +1257,18 @@
 			FDCS->reset = 1;
 			return;
 		}
-		DRS->flags &= ~(FD_VERIFY | FD_DISK_WRITABLE | FD_NEED_TWADDLE);
-
+		CLEARF(FD_VERIFY);
+		CLEARF(FD_NEED_TWADDLE);
+#ifdef DCL_DEBUG
+		if (DP->flags & FD_DEBUG){
+			DPRINT("checking whether disk is write protected\n");
+			DPRINT1("wp=%x\n",ST3 & 0x40);
+		}
+#endif
 		if (!( ST3  & 0x40))
-			DRS->flags |= FD_DISK_WRITABLE;
+			SETF(FD_DISK_WRITABLE);
+		else
+			CLEARF(FD_DISK_WRITABLE);
 	}
 }
 
@@ -1211,16 +1276,22 @@
 {
 	int track;
 
-#ifdef SILENT_DC_CLEAR
 	blind_seek=0;
+
+#ifdef DCL_DEBUG
+	if (DP->flags & FD_DEBUG){
+		DPRINT("calling disk change from seek\n");
+	}
 #endif
-	disk_change(current_drive);
-	if ((raw_cmd.flags & FD_RAW_NEED_DISK) &&
-	    test_bit(current_drive,&changed_floppies)){
+
+	if (!TESTF(FD_DISK_NEWCHANGE) &&
+	    disk_change(current_drive) &&
+	    (raw_cmd.flags & FD_RAW_NEED_DISK)){
 		/* the media changed flag should be cleared after the seek.
 		 * If it isn't, this means that there is really no disk in
 		 * the drive.
 		 */
+		SETF(FD_DISK_CHANGED);
 		cont->done(0);
 		cont->redo();
 		return;
@@ -1228,7 +1299,7 @@
 	if ( DRS->track <= NEED_1_RECAL ){
 		recalibrate_floppy();
 		return;
-	} else if ((DRS->flags & FD_DISK_NEWCHANGE) &&
+	} else if (TESTF(FD_DISK_NEWCHANGE) &&
 		   (raw_cmd.flags & FD_RAW_NEED_DISK) &&
 		   (DRS->track <= NO_TRACK || DRS->track == raw_cmd.track)) {
 		/* we seek to clear the media-changed condition. Does anybody
@@ -1236,15 +1307,17 @@
 		if ( raw_cmd.track )
 			track = raw_cmd.track - 1;
 		else {
-#ifdef SILENT_DC_CLEAR
-			set_dor(fdc, ~ (0x10 << UNIT(current_drive)), 0);
-			blind_seek = 1;
-#endif
+			if(DP->flags & FD_SILENT_DCL_CLEAR){
+				set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
+				blind_seek = 1;
+				raw_cmd.flags |= FD_RAW_NEED_SEEK;
+			}
 			track = 1;
 		}
 	} else {
 		check_wp();
-		if (raw_cmd.track != DRS->track)
+		if (raw_cmd.track != DRS->track &&
+		    (raw_cmd.flags & FD_RAW_NEED_SEEK))
 			track = raw_cmd.track;
 		else {
 			setup_rw_floppy();
@@ -1252,23 +1325,13 @@
 		}
 	}
 
-#ifndef SILENT_DC_CLEAR
-	if ( !track && DRS->track >= 0 && DRS->track < 80 ){
-		DRS->flags &= ~FD_DISK_NEWCHANGE;
-		/* if we go to track 0 anyways, we can just as well use
-		 * recalibrate */
-		recalibrate_floppy();
-	} else 
-#endif
-	{
-		SET_INTR(seek_interrupt);
-		output_byte(FD_SEEK);
-		output_byte(UNIT(current_drive));
-		LAST_OUT(track);
+	SET_INTR(seek_interrupt);
+	output_byte(FD_SEEK);
+	output_byte(UNIT(current_drive));
+	LAST_OUT(track);
 #ifdef DEBUGT
-		debugt("seek command:");
+	debugt("seek command:");
 #endif
-	}
 }
 
 static void recal_interrupt(void)
@@ -1280,11 +1343,6 @@
 		FDCS->reset = 1;
 	else if (ST0 & ST0_ECE) {
 	       	switch(DRS->track){
-		case PROVEN_ABSENT:
-#ifdef DEBUGT
-			debugt("recal interrupt proven absent:");
-#endif
-			/* fall through */
 	       	case NEED_1_RECAL:
 #ifdef DEBUGT
 			debugt("recal interrupt need 1 recal:");
@@ -1305,7 +1363,14 @@
 			 * not to move at recalibration is to be already at
 			 * track 0.) Clear the new change flag
 			 */
-			DRS->flags &= ~FD_DISK_NEWCHANGE;
+#ifdef DCL_DEBUG
+			if (DP->flags & FD_DEBUG){
+				DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
+			}
+#endif
+
+			CLEARF(FD_DISK_NEWCHANGE);
+			DRS->select_date = jiffies;
 			/* fall through */
 		default:
 #ifdef DEBUGT
@@ -1321,7 +1386,7 @@
 		}
 	} else
 		DRS->track = ST1;
-	seek_floppy();
+	floppy_ready();
 }
 
 /*
@@ -1358,8 +1423,11 @@
 	void (*handler)(void) = DEVICE_INTR;
 
 	CLEAR_INTR;
-	if ( fdc >= N_FDC ){ /* we don't even know which FDC is the culprit */
-		printk("floppy interrupt on bizarre fdc\n");
+	if ( fdc >= N_FDC || FDCS->address == -1){
+		/* we don't even know which FDC is the culprit */
+		printk("DOR0=%x\n", fdc_state[0].dor);
+		printk("floppy interrupt on bizarre fdc %d\n",fdc);
+		printk("handler=%p\n", handler);
 		return;
 	}
 	inr = result();
@@ -1444,9 +1512,9 @@
 		printk("floppy_tq.routine=%p\n", floppy_tq.routine);
 	if(fd_timer.prev)
 		printk("fd_timer.function=%p\n", fd_timer.function);
-	if( timer_active & (1 << FLOPPY_TIMER)){
-		printk("timer_table=%p\n",timer_table[FLOPPY_TIMER].fn);
-		printk("expires=%ld\n",timer_table[FLOPPY_TIMER].expires);
+	if(fd_timeout.prev){
+		printk("timer_table=%p\n",fd_timeout.function);
+		printk("expires=%ld\n",fd_timeout.expires);
 		printk("now=%ld\n",jiffies);
 	}
 	printk("cont=%p\n", cont);
@@ -1470,19 +1538,15 @@
 	cont->done(0);
 	cont->redo(); /* this will recall reset when needed */
 }
+/*typedef void (*timeout_fn)(unsigned long);*/
 
 /* start motor, check media-changed condition and write protection */
-static void start_motor(void)
+static int start_motor( void (*function)(void)  )
 {
 	int mask, data;
 
 	mask = 0xfc;
 	data = UNIT(current_drive);
-	if ( (FDCS->dor & 0x03) != UNIT(current_drive) ||
-	    !(FDCS->dor & ( 0x10 << UNIT(current_drive) ) ))
-		/* notes select time if floppy is not yet selected */
-		DRS->select_date = jiffies;
-
 	if (!(raw_cmd.flags & FD_RAW_NO_MOTOR)){
 		if(!(FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){
 			set_debugt();
@@ -1499,26 +1563,31 @@
 	/* starts motor and selects floppy */
 	del_timer(motor_off_timer + current_drive);
 	set_dor( fdc, mask, data);
-	if( raw_cmd.flags & FD_RAW_NO_MOTOR)
-		return;
-
-	disk_change(current_drive);
 
-	return;
+	/* wait_for_completion also schedules reset if needed. */
+	return(wait_for_completion(DRS->select_date+DP->select_delay,
+				   (timeout_fn) function));
 }
 
 static void floppy_ready(void)
 {
 	CHECK_RESET;
-	start_motor();
+	if(start_motor(floppy_ready)) return;
+	if(fdc_dtr()) return;
 
-	/* wait_for_completion also schedules reset if needed. */
-	if(wait_for_completion(current_drive,
-			       DRS->select_date+DP->select_delay,
-			       (timeout_fn) floppy_ready))
-		return;
-	fdc_dtr();
-	if ( raw_cmd.flags & FD_RAW_NEED_SEEK ){
+#ifdef DCL_DEBUG
+	if (DP->flags & FD_DEBUG){
+		DPRINT("calling disk change from floppy_ready\n");
+	}
+#endif
+
+	if(!(raw_cmd.flags & FD_RAW_NO_MOTOR) &&
+	   disk_change(current_drive) &&
+	   !DP->select_delay)
+		twaddle(); /* this clears the dcl on certain drive/controller
+			    * combinations */
+
+	if ( raw_cmd.flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){
 		perpendicular_mode();
 		fdc_specify(); /* must be done here because of hut, hlt ... */
 		seek_floppy();
@@ -1528,9 +1597,17 @@
 
 static void floppy_start(void)
 {
-	timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout;
-	timer_active |= 1 << FLOPPY_TIMER;
+	del_timer(&fd_timeout);
+	fd_timeout.expires = DP->timeout;
+	add_timer(&fd_timeout);
+
 	scandrives();
+#ifdef DCL_DEBUG
+		if (DP->flags & FD_DEBUG){
+			DPRINT("setting NEWCHANGE in floppy_start\n");
+		}
+#endif
+	SETF(FD_DISK_NEWCHANGE);
 	floppy_ready();
 }
 
@@ -1550,7 +1627,7 @@
 
 static void do_wakeup(void)
 {
-	timer_active &= ~(1 << FLOPPY_TIMER);
+	del_timer(&fd_timeout);
 	cont = 0;
 	command_status += 2;
 	wake_up(&command_done);
@@ -1582,7 +1659,7 @@
 	if(command_status < 2){
 		sti();
 		floppy_shutdown();
-		redo_fd_request();
+		process_fd_request();
 		return -EINTR;
 	}
 	sti();
@@ -1757,7 +1834,6 @@
 	raw_cmd.track = format_req.track << floppy->stretch;
 	buffer_track = -1;
 	setup_format_params();
-	clear_bit(current_drive, &changed_floppies);
 	floppy_start();
 #ifdef DEBUGT
 	debugt("queue format request");
@@ -1772,23 +1848,27 @@
 
 static int do_format(int device, struct format_descr *tmp_format_req)
 {
-	int okay;
+	int ret;
+	int drive=DRIVE(device);
 
-	LOCK_FDC(DRIVE(device),1);
+	LOCK_FDC(drive,1);
 	set_floppy(device);
 	if (!floppy ||
+	    floppy->track > DP->tracks ||
 	    tmp_format_req->track >= floppy->track ||
-	    tmp_format_req->head >= floppy->head){
-		redo_fd_request();
+	    tmp_format_req->head >= floppy->head ||
+	    (floppy->sect << 2) % (1 <<  FD_SIZECODE(floppy)) ||
+	    !floppy->fmt_gap) {
+		process_fd_request();
 		return -EINVAL;
 	}
 	format_req = *tmp_format_req;
 	format_errors = 0;
 	cont = &format_cont;
 	errors = &format_errors;
-	CALL(okay=wait_til_done(redo_format,1));
-	redo_fd_request();
-	return okay;
+	IWAIT(redo_format);
+	process_fd_request();
+	return ret;
 }
 
 /*
@@ -1803,7 +1883,7 @@
 	int block;
 
 	probing = 0;
-	timer_active &= ~(1 << FLOPPY_TIMER);
+	del_timer(&fd_timeout);
 
 	if (!CURRENT){
 		DPRINT("request list destroyed in floppy request done\n");
@@ -1867,7 +1947,7 @@
 		floppy->sect + ((R_SECTOR-SECTOR) <<  SIZECODE >> 2) -
 			(sector_t % floppy->sect) % ssize;
 
-#ifdef SANITY
+#ifdef CONFIG_FLOPPY_SANITY
 	if ( nr_sectors > current_count_sectors + ssize -
 	    (current_count_sectors + sector_t) % ssize +
 	    sector_t % ssize){
@@ -1940,7 +2020,7 @@
 	size = CURRENT->current_nr_sectors << 9;
 	bh = CURRENT->bh;
 
-	if(bh){
+	if (bh){
 		bh = bh->b_reqnext;
 		while ( bh && bh->b_data == base + size ){
 			size += bh->b_size;
@@ -1987,7 +2067,7 @@
 			current_count_sectors = CURRENT->nr_sectors;
 	}
 	remaining = current_count_sectors << 9;
-#ifdef SANITY
+#ifdef CONFIG_FLOPPY_SANITY
 	if ((remaining >> 9) > CURRENT->nr_sectors  && 
 	    CT(COMMAND) == FD_WRITE ){
 		DPRINT("in copy buffer\n");
@@ -2013,7 +2093,7 @@
 	while ( remaining > 0){
 		if ( size > remaining )
 			size = remaining;
-#ifdef SANITY
+#ifdef CONFIG_FLOPPY_SANITY
 		if (dma_buffer + size >
 		    floppy_track_buffer + (max_buffer_sectors << 10) ||
 		    dma_buffer < floppy_track_buffer ){
@@ -2042,7 +2122,7 @@
 
 		dma_buffer += size;
 		bh = bh->b_reqnext;
-#ifdef SANITY
+#ifdef CONFIG_FLOPPY_SANITY
 		if ( !bh){
 			DPRINT("bh=null in copy buffer after copy\n");
 			break;
@@ -2051,7 +2131,7 @@
 		size = bh->b_size;
 		buffer = bh->b_data;
 	}
-#ifdef SANITY
+#ifdef CONFIG_FLOPPY_SANITY
 	if ( remaining ){
 		if ( remaining > 0 )
 			max_sector -= remaining >> 9;
@@ -2075,7 +2155,7 @@
 	int aligned_sector_t;
 	int max_sector, max_size, tracksize, ssize;
 
-	current_drive = DRIVE(CURRENT->dev);
+	set_fdc(DRIVE(CURRENT->dev));
 
 	raw_cmd.flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
 		FD_RAW_NEED_SEEK;
@@ -2098,7 +2178,7 @@
 		return 0;
 	HEAD = sector_t / floppy->sect;
 
-	if ( (DRS->flags & FD_NEED_TWADDLE) && sector_t < floppy->sect )
+	if ( TESTF( FD_NEED_TWADDLE) && sector_t < floppy->sect )
 		max_sector = floppy->sect;
 
 	/* 2M disks have phantom sectors on the first track */
@@ -2189,7 +2269,7 @@
 		 */
 		if ((indirect - sector_t) * 2 > (direct - sector_t) * 3 &&
 		    *errors < DP->max_errors.read_track &&
-		    /*!(DRS->flags & FD_NEED_TWADDLE) &&*/
+		    /*!TESTF( FD_NEED_TWADDLE) &&*/
 		    ( ( !probing || (DP->read_track &
 			   (1 <<DRS->probed_format))))){
 			max_size = CURRENT->nr_sectors;
@@ -2223,7 +2303,7 @@
 		 * if we get here, we know that the write
 		 * is either aligned or the data already in the buffer
 		 * (buffer will be overwritten) */
-#ifdef SANITY
+#ifdef CONFIG_FLOPPY_SANITY
 		if (sector_t != aligned_sector_t && buffer_track == -1 )
 			DPRINT("internal error offset !=0 on write\n");
 #endif
@@ -2238,7 +2318,7 @@
 	raw_cmd.length = sector_t+current_count_sectors-aligned_sector_t;
 	raw_cmd.length = ((raw_cmd.length -1)|(ssize-1))+1;
 	raw_cmd.length <<= 9;
-#ifdef SANITY
+#ifdef CONFIG_FLOPPY_SANITY
 	if ((raw_cmd.length < current_count_sectors << 9) ||
 	    (current_addr != CURRENT->buffer &&
 	     CT(COMMAND) == FD_WRITE &&
@@ -2295,24 +2375,19 @@
 	return 2;
 }
 
-static struct cont_t rw_cont={
-	rw_interrupt,
-	redo_fd_request,
-	bad_flp_intr,
-	request_done };
-
 static void redo_fd_request(void)
 {
 #define REPEAT {request_done(0); continue; }
 	int device;
 	int tmp;
+	int error;
 
+	error = -1;
 	if (current_drive < N_DRIVE)
 		floppy_off(current_drive);
 
 	if (CURRENT && CURRENT->dev < 0) return;
 
-	cont = &rw_cont;	
 	while(1){
 		if (!CURRENT) {
 			CLEAR_INTR;
@@ -2323,20 +2398,29 @@
 			panic(DEVICE_NAME ": request list destroyed");
 		if (CURRENT->bh && !CURRENT->bh->b_lock)
 			panic(DEVICE_NAME ": block not locked");
-		
+#if 0
+		if (!CURRENT->bh->b_count && 
+		    (CURRENT->errors || error == CURRENT->dev)){
+			error=CURRENT->dev;
+			DPRINT("skipping read ahead buffer\n");
+			REPEAT;
+		}
+#endif
+		error=-1;
 		device = CURRENT->dev;
 		set_fdc( DRIVE(device));
 
-		timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout;
-		timer_active |= 1 << FLOPPY_TIMER;
-		raw_cmd.flags=0;
-		start_motor();
-		if(test_bit( DRIVE(device), &fake_change) ||
-		   test_bit( DRIVE(device), &changed_floppies)){
+		del_timer(&fd_timeout);
+		fd_timeout.expires = DP->timeout;
+		add_timer(&fd_timeout);
+
+		set_floppy(device);
+		if(start_motor(redo_fd_request)) return;
+		if(test_bit(current_drive, &fake_change) ||
+		   TESTF(FD_DISK_CHANGED)){
 			DPRINT("disk absent or changed during operation\n");
 			REPEAT;
 		}
-		set_floppy(device);
 		if (!floppy) { /* Autodetection */
 			if (!probing){
 				DRS->probed_format = 0;
@@ -2357,6 +2441,8 @@
 			continue;
 		}
 
+		if (TESTF(FD_NEED_TWADDLE))
+			twaddle();
 		floppy_tq.routine = (void *)(void *) floppy_start;
 		queue_task(&floppy_tq, &tq_timer);
 #ifdef DEBUGT
@@ -2367,7 +2453,22 @@
 #undef REPEAT
 }
 
-void do_fd_request(void)
+static struct cont_t rw_cont={
+	rw_interrupt,
+	redo_fd_request,
+	bad_flp_intr,
+	request_done };
+
+struct tq_struct request_tq = 
+{ 0, 0, (void *) (void *) redo_fd_request, 0 };
+
+static void process_fd_request(void)
+{
+	cont = &rw_cont;
+	queue_task(&request_tq, &tq_timer);
+}
+
+static void do_fd_request(void)
 {
 	if (fdc_busy)
 		/* fdc busy, this new request will be treated when the
@@ -2376,7 +2477,30 @@
 	/* fdc_busy cannot be set by an interrupt or a bh */
 	floppy_grab_irq_and_dma();
 	fdc_busy=1;
-	redo_fd_request();
+	process_fd_request();
+}
+
+static struct cont_t poll_cont={
+	success_and_wakeup,
+	floppy_ready,
+	generic_failure,
+	generic_done };
+
+static int poll_drive(int interruptible, int flag){
+	int ret;
+	/* no auto-sense, just clear dcl */
+	raw_cmd.flags= flag;
+	raw_cmd.track=0;
+	raw_cmd.cmd_count=0;
+	cont = &poll_cont;
+#ifdef DCL_DEBUG
+		if (DP->flags & FD_DEBUG){
+			DPRINT("setting NEWCHANGE in poll_drive\n");
+		}
+#endif
+	SETF(FD_DISK_NEWCHANGE);
+	WAIT(floppy_ready);
+	return ret;
 }
 
 /*
@@ -2397,29 +2521,23 @@
 
 static int user_reset_fdc(int drive, int arg, int interruptible)
 {
-	int result;
+	int ret;
 
-	result=0;
+	ret=0;
+	if(arg == FD_RESET_IF_NEEDED && !FDCS->reset)
+		return 0;
 	LOCK_FDC(drive,interruptible);
-	switch(arg){
-	case FD_RESET_ALWAYS:
+	if(arg == FD_RESET_ALWAYS)
 		FDCS->reset=1;
-		break;
-	case FD_RESET_IF_RAWCMD:
-		if(FDCS->rawcmd == 2 )
-			reset_fdc_info(1);
-		break;
-	}
 	if ( FDCS->reset ){
 		cont = &reset_cont;
-		timer_table[FLOPPY_TIMER].expires = jiffies + 5;
-		timer_active |= 1 << FLOPPY_TIMER;
-		CALL(result=wait_til_done(reset_fdc,interruptible));
-	}
-	if ( UDRS->track == PROVEN_ABSENT )
-		UDRS->track = NEED_2_RECAL;
-	redo_fd_request();
-	return result;
+		del_timer(&fd_timeout);
+		fd_timeout.expires = DP->timeout;
+		add_timer(&fd_timeout);
+		WAIT(reset_fdc);
+	}
+	process_fd_request();
+	return ret;
 }
 
 /*
@@ -2465,21 +2583,21 @@
 	generic_failure,
 	generic_done };
 
-static int raw_cmd_ioctl(int drive, void *param)
+static int raw_cmd_ioctl(void *param)
 {
-	int i, count, ret;
+	int i, drive, count, ret;
 
 	if ( FDCS->rawcmd <= 1 )
 		FDCS->rawcmd = 1;
-	for ( i= 0; i < N_DRIVE; i++){
-		if ( FDC(i) != fdc)
+	for ( drive= 0; drive < N_DRIVE; drive++){
+		if ( FDC(drive) != fdc)
 			continue;
-		if ( i == drive ){
-			if ( drive_state[i].fd_ref > 1 ){
+		if ( drive == current_drive ){
+			if ( UDRS->fd_ref > 1 ){
 				FDCS->rawcmd = 2;
 				break;
 			}
-		} else if ( drive_state[i].fd_ref ){
+		} else if ( UDRS->fd_ref ){
 			FDCS->rawcmd = 2;
 			break;
 		}
@@ -2505,13 +2623,18 @@
 
 	current_addr = floppy_track_buffer;
 	cont = &raw_cmd_cont;
-	CALL(ret=wait_til_done(floppy_start,1));
+	IWAIT(floppy_start);
+#ifdef DCL_DEBUG
+	if (DP->flags & FD_DEBUG){
+		DPRINT("calling disk change from raw_cmd ioctl\n");
+	}
+#endif
 	if( disk_change(current_drive) )
 		raw_cmd.flags |= FD_RAW_DISK_CHANGE;
 	else
 		raw_cmd.flags &= ~FD_RAW_DISK_CHANGE;
 	if(raw_cmd.flags & FD_RAW_NO_MOTOR_AFTER)
-		motor_off_callback(drive);	
+		motor_off_callback(current_drive);	
 
 	if ( !ret && !FDCS->reset ){
 		raw_cmd.reply_count = inr;
@@ -2538,7 +2661,7 @@
 {
 	/* invalidate the buffer track to force a reread */
 	set_bit( DRIVE(rdev), &fake_change);
-	redo_fd_request();
+	process_fd_request();
 	check_disk_change(rdev);
 	return 0;
 }
@@ -2547,6 +2670,7 @@
     unsigned long param)
 {
 #define IOCTL_MODE_BIT 8
+#define OPEN_WRITE_BIT 16
 #define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
 
 	struct floppy_struct newparams;
@@ -2584,7 +2708,9 @@
 			return -ENODEV;
 		return COPYOUT(this_floppy[0]);
 	case FDPOLLDRVSTAT:
-		check_disk_change(device);
+		LOCK_FDC(drive,1);
+		CALL(poll_drive(1, FD_RAW_NEED_DISK));
+		process_fd_request();
 		/* fall through */
 	case FDGETDRVSTAT:
 		return COPYOUT(*UDRS);
@@ -2611,14 +2737,12 @@
 			return -EINVAL;
 		LOCK_FDC(drive,1);
 		set_floppy(device);
-		CALL(i = raw_cmd_ioctl(drive, (void *) param));
-		redo_fd_request();
+		CALL(i = raw_cmd_ioctl((void *) param));
+		process_fd_request();
 		return i;
 	case FDFMTTRK:
 		if (UDRS->fd_ref != 1)
 			return -EBUSY;
-		if (UDRS->track == PROVEN_ABSENT)
-			return -ENXIO;
 		COPYIN(tmp_format_req);
 		return do_format(device, &tmp_format_req);
 	case FDSETMAXERRS:
@@ -2648,7 +2772,7 @@
 		if ( type){
 			if ( !suser() )
 				return -EPERM;
-			LOCK_FDC(-1,1);
+			LOCK_FDC(drive,1);
 			for ( cnt = 0; cnt < N_DRIVE; cnt++){
 				if (TYPE(drive_state[cnt].fd_device) == type &&
 				    drive_state[cnt].fd_ref)
@@ -2660,11 +2784,11 @@
 			     cnt < (type << 2 ) + 4 ;
 			     cnt++)
 				floppy_sizes[cnt]=
-#ifdef HAVE_2_CONTROLLERS
+#ifdef CONFIG_FLOPPY_2_FDC
 					floppy_sizes[cnt+0x80]=
 #endif
 						floppy_type[type].size>>1;
-			redo_fd_request();
+			process_fd_request();
 			for ( cnt = 0; cnt < N_DRIVE; cnt++){
 				if (TYPE(drive_state[cnt].fd_device) == type &&
 				    drive_state[cnt].fd_ref)
@@ -2675,12 +2799,10 @@
 		}
 
 		LOCK_FDC(drive,1);
-		if ( cmd != FDDEFPRM ){
+		if ( cmd != FDDEFPRM )
 			/* notice a disk change immediately, else
 			 * we loose our settings immediately*/
-			raw_cmd.flags = 0;
-			start_motor();
-		}
+			CALL(poll_drive(1,0));
 		user_params[drive] = newparams;
 		if (buffer_drive == drive &&
 		    buffer_max > user_params[drive].sect)
@@ -2701,7 +2823,7 @@
 		    DRS->maxtrack )
 			invalidate_drive(device);
 		else
-			redo_fd_request();
+			process_fd_request();
 		return 0;
 	case FDRESET:
 		return user_reset_fdc( drive, (int)param, 1);
@@ -2718,7 +2840,7 @@
 	case FDTWADDLE:
 		LOCK_FDC(drive,1);
 		twaddle();
-		redo_fd_request();
+		process_fd_request();
 	}
 	if ( ! suser() )
 		return -EPERM;
@@ -2769,35 +2891,48 @@
 	printk("\n");
 }
 
-int floppy_is_wp( int minor)
+static int floppy_read(struct inode * inode, struct file * filp,
+		       char * buf, int count)
 {
-	check_disk_change(minor + (MAJOR_NR << 8));
-	return ! ( drive_state[ DRIVE(minor) ].flags & FD_DISK_WRITABLE );
+	int drive = DRIVE(inode->i_rdev);
+
+	check_disk_change(inode->i_rdev);
+	if (UTESTF(FD_DISK_CHANGED))
+		return -ENXIO;
+	return block_read(inode, filp, buf, count);
 }
 
+static int floppy_write(struct inode * inode, struct file * filp,
+			char * buf, int count)
+{
+	int block;
+	int ret;
+	int drive = DRIVE(inode->i_rdev);
 
-#define WRAPPER(op) \
-static int floppy_##op(struct inode * inode, struct file * filp, \
-		     char * buf, int count) \
-{ \
-	check_disk_change(inode->i_rdev); \
-	if ( drive_state[DRIVE(inode->i_rdev)].track == PROVEN_ABSENT ) \
- 		return -ENXIO; \
-	if ( test_bit(DRIVE(inode->i_rdev),&changed_floppies)) \
-		return -ENXIO; \
-	return block_##op(inode, filp, buf, count); \
+	if(!UDRS->maxblock)
+		UDRS->maxblock=1;/* make change detectable */
+	check_disk_change(inode->i_rdev);
+	if (UTESTF(FD_DISK_CHANGED)) 
+		return -ENXIO;
+	if(!UTESTF(FD_DISK_WRITABLE))
+		return -EROFS;
+	block = (filp->f_pos + count) >> 9;
+	if(block > UDRS->maxblock)
+		UDRS->maxblock = block;
+	ret= block_write(inode, filp, buf, count);
+	return ret;
 }
 
-WRAPPER(read)
-WRAPPER(write)
-
 static void floppy_release(struct inode * inode, struct file * filp)
 {
 	int drive;
 	
 	drive = DRIVE(inode->i_rdev);
 
-	fsync_dev(inode->i_rdev);
+	if( !filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
+		/* if the file is mounted OR (writable now AND writable at
+		 * open time) Linus: Does this cover all cases? */
+		block_fsync(inode,filp);
 			
 	if (UDRS->fd_ref < 0)
 		UDRS->fd_ref=0;
@@ -2828,20 +2963,22 @@
 	}
 
 	drive = DRIVE(inode->i_rdev);
-	if ( drive >= N_DRIVE || !( ALLOWED_DRIVE_MASK & ( 1 << drive)) )
+	if (drive >= N_DRIVE || 
+	    !( ALLOWED_DRIVE_MASK & ( 1 << drive)) ||
+	    fdc_state[FDC(drive)].version == FDC_NONE)
 		return -ENXIO;
 
 	if (TYPE(inode->i_rdev) >= NUMBER(floppy_type))
 		return -ENXIO;
-
-	if ((filp->f_mode & 3)  &&
-	    UDRS->track == PROVEN_ABSENT )
-		return -ENXIO;
-
 	old_dev = UDRS->fd_device;
 	if (UDRS->fd_ref && old_dev != inode->i_rdev)
 		return -EBUSY;
 
+	if(!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){
+		USETF(FD_DISK_CHANGED);
+		USETF(FD_VERIFY);
+	}
+
 	if(UDRS->fd_ref == -1 ||
 	   (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
 		return -EBUSY;
@@ -2865,30 +3002,21 @@
 	/* Allow ioctls if we have write-permissions even if read-only open */
 	if ((filp->f_mode & 2) || permission(inode,2))
 		filp->f_mode |= IOCTL_MODE_BIT;
+	if (filp->f_mode & 2)
+		filp->f_mode |= OPEN_WRITE_BIT;
 
 	if (UFDCS->rawcmd == 1)
 	       UFDCS->rawcmd = 2;
 
 	if (filp->f_flags & O_NDELAY)
 		return 0;
-
-	if (filp->f_mode && UDRS->track == PROVEN_ABSENT )
-		RETERR(ENXIO);
-
-	if (user_reset_fdc(drive, FD_RESET_IF_NEEDED,0))
-		RETERR(EIO);
-
 	if (filp->f_mode & 3) {
 		UDRS->last_checked = 0;
 		check_disk_change(inode->i_rdev);
-		if (test_bit(drive,&changed_floppies))
+		if (UTESTF(FD_DISK_CHANGED))
 			RETERR(ENXIO);
 	}
-	
-	if (filp->f_mode && UDRS->track == PROVEN_ABSENT )
-		RETERR(ENXIO);
-
-	if ((filp->f_mode & 2) && !(UDRS->flags & FD_DISK_WRITABLE))
+	if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE)))
 		RETERR(EROFS);
 	return 0;
 #undef RETERR
@@ -2906,45 +3034,38 @@
 		return 0;
 	}
 
-	if(test_bit(drive, &changed_floppies))
+	if (UTESTF(FD_DISK_CHANGED))
 		return 1;
 
 	if(UDRS->last_checked + UDP->checkfreq < jiffies){
 		lock_fdc(drive,0);
-		start_motor();
-		redo_fd_request();
+		poll_drive(0,0);
+		process_fd_request();
 	}
 		
-	if(test_bit(drive, &changed_floppies))
-		return 1;
-	if(test_bit(drive, &fake_change))
+	if(UTESTF(FD_DISK_CHANGED) ||
+	   test_bit(drive, &fake_change) ||
+	   (!TYPE(dev) && !current_type[drive]))
 		return 1;
 	return 0;
 }
 
-static struct cont_t poll_cont={
-	success_and_wakeup,
-	floppy_ready,
-	generic_failure,
-	generic_done };
-
-
 /* revalidate the floppy disk, i.e. trigger format autodetection by reading
  * the bootblock (block 0). "Autodetection" is also needed to check whether
  * there is a disk in the drive at all... Thus we also do it for fixed
  * geometry formats */
 static int floppy_revalidate(dev_t dev)
 {
+#define NO_GEOM (!current_type[drive] && !TYPE(dev))
 	struct buffer_head * bh;
 	int drive=DRIVE(dev);
 	int cf;
 
-	cf = test_bit(drive, &changed_floppies);
-	if(cf || test_bit(drive, &fake_change)){
+	if(UTESTF(FD_DISK_CHANGED) || test_bit(drive, &fake_change) || NO_GEOM){
 		lock_fdc(drive,0);
-		cf = test_bit(drive, &changed_floppies);
-		if(! (cf || test_bit(drive, &fake_change))){
-			redo_fd_request(); /* already done by another thread */
+		cf = UTESTF(FD_DISK_CHANGED);
+		if(! (cf || test_bit(drive, &fake_change) || NO_GEOM)){
+			process_fd_request(); /*already done by another thread*/
 			return 0;
 		}
 		UDRS->maxblock = 0;
@@ -2952,34 +3073,28 @@
 		if ( buffer_drive == drive)
 			buffer_track = -1;
 		clear_bit(drive, &fake_change);
-		clear_bit(drive, &changed_floppies);
-		if(cf){
+		UCLEARF(FD_DISK_CHANGED);
+		if(cf)
 			UDRS->generation++;
-			if(!current_type[drive] && !TYPE(dev)){
-				/* auto-sensing */
-				int size = floppy_blocksizes[MINOR(dev)];
-				if (!size)
-					size = 1024;
-				if (!(bh = getblk(dev,0,size))){
-					redo_fd_request();
-					return 1;
-				}
-				if ( bh && ! bh->b_uptodate)
-					ll_rw_block(READ, 1, &bh);
-				redo_fd_request();
-				wait_on_buffer(bh);
-				brelse(bh);
-				return 0;
-			} else {
-				/* no auto-sense, just clear dcl */
-				raw_cmd.flags=FD_RAW_NEED_SEEK|FD_RAW_NEED_DISK;
-				raw_cmd.track=0;
-				raw_cmd.cmd_count=0;
-				cont = &poll_cont;
-				wait_til_done(floppy_ready,0);
+		if(NO_GEOM){
+			/* auto-sensing */
+			int size = floppy_blocksizes[MINOR(dev)];
+			if (!size)
+				size = 1024;
+			if (!(bh = getblk(dev,0,size))){
+				process_fd_request();
+				return 1;
 			}
-		}
-		redo_fd_request();
+			if ( bh && ! bh->b_uptodate)
+				ll_rw_block(READ, 1, &bh);
+			process_fd_request();
+			wait_on_buffer(bh);
+			brelse(bh);
+			return 0;
+		} 
+		if(cf)
+				poll_drive(0, FD_RAW_NEED_DISK);
+		process_fd_request();
 	}
 	return 0;
 }
@@ -3046,17 +3161,21 @@
 	}
 	printk("FDC %d is a post-1991 82077\n",fdc);
 	return FDC_82077;	/* Revised 82077AA passes all the tests */
-} /* fdc_init */
+} /* get_fdc_version */
 
-void floppy_init(void)
+#ifdef FD_MODULE
+static
+#endif
+int new_floppy_init(void)
 {
-	int i;
+	int i,drive;
+	int have_no_fdc=0;
 
 	sti();
 
 	if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
 		printk("Unable to get major %d for floppy\n",MAJOR_NR);
-		return;
+		return -EBUSY;
 	}
 
 	for(i=0; i<256; i++)
@@ -3068,42 +3187,48 @@
 	blk_size[MAJOR_NR] = floppy_sizes;
 	blksize_size[MAJOR_NR] = floppy_blocksizes;
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-	timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
-	timer_active &= ~(1 << FLOPPY_TIMER);
+	del_timer(&fd_timeout);
 	config_types();
 
-	fdc_state[0].address = 0x3f0;
+	fdc_state[0].address = FDC1;
+	fdc_state[0].dor = 0;
 #if N_FDC > 1
-	fdc_state[1].address = 0x370;
+	fdc_state[1].address = FDC2;
+	fdc_state[1].dor = 0;
 #endif
+
 	for (i = 0 ; i < N_FDC ; i++) {
 		fdc = i;
 		FDCS->dtr = -1;
-		FDCS->dor = 0;
+		FDCS->dor = 0x4;
 		FDCS->reset = 0;
 		FDCS->version = FDC_NONE;
-		set_dor(fdc, ~0, 0xc );
+	}
+
+	if(floppy_grab_irq_and_dma()){
+		unregister_blkdev(MAJOR_NR,"fd");
+		return -EBUSY;
 	}
 
 	/* initialise drive state */
-	for (i = 0; i < N_DRIVE ; i++) {
-		current_drive = i;
-		DRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE;
-		DRS->generation = 0;
-		DRS->keep_data = 0;
-		DRS->fd_ref = 0;
-		DRS->fd_device = 0;
-		DRWE->write_errors = 0;
-		DRWE->first_error_sector = 0;
-		DRWE->first_error_generation = 0;
-		DRWE->last_error_sector = 0;
-		DRWE->last_error_generation = 0;
-		DRWE->badness = 0;
+	for (drive = 0; drive < N_DRIVE ; drive++) {
+		UDRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE | FD_DISK_CHANGED;
+		UDRS->generation = 0;
+		UDRS->keep_data = 0;
+		UDRS->fd_ref = 0;
+		UDRS->fd_device = 0;
+		UDRWE->write_errors = 0;
+		UDRWE->first_error_sector = 0;
+		UDRWE->first_error_generation = 0;
+		UDRWE->last_error_sector = 0;
+		UDRWE->last_error_generation = 0;
+		UDRWE->badness = 0;
 	}
 
-	floppy_grab_irq_and_dma();
 	for (i = 0 ; i < N_FDC ; i++) {
 		fdc = i;
+		if (FDCS->address == -1 )
+			continue;
 		FDCS->rawcmd = 2;
 		if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0))
 			continue;
@@ -3112,6 +3237,7 @@
 		if (FDCS->version == FDC_NONE)
 			continue;
 
+		have_no_fdc = 0;
 		/* Not all FDCs seem to be able to handle the version command
 		 * properly, so force a reset for the standard FDC clones,
 		 * to avoid interrupt garbage.
@@ -3123,6 +3249,15 @@
 	current_drive = 0;
 	floppy_release_irq_and_dma();
 	initialising=0;
+	if(have_no_fdc)
+		unregister_blkdev(MAJOR_NR,"fd");
+	return have_no_fdc;
+}
+
+/* stupid compatibility hack... */
+void floppy_init(void)
+{
+	new_floppy_init();
 }
 
 static int floppy_grab_irq_and_dma(void)
@@ -3134,13 +3269,15 @@
 		return 0;
 	}
 	sti();
-
+#ifdef FD_MODULE
+	MOD_INC_USE_COUNT;
+#endif
 	for(i=0; i< N_FDC; i++){		
 		fdc = i;
 		reset_fdc_info(1);
-		outb_p( FDCS->dor, FD_DOR);
+		outb_p(FDCS->dor, FD_DOR);
 	}
-	set_dor(0, ~0, 8); /* avoid immediate interrupt */
+	set_dor(0, ~0, 8);  /* avoid immediate interrupt */
 
 	if (request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT, "floppy")) {
 		DPRINT1("Unable to grab IRQ%d for the floppy driver\n",
@@ -3153,25 +3290,50 @@
 		free_irq(FLOPPY_IRQ);
 		return -1;
 	}
+	for(fdc = 0; fdc < N_FDC ; fdc++)
+		if(FDCS->address != -1)
+			outb_p(FDCS->dor, FD_DOR);
+	fdc = 0;
 	enable_irq(FLOPPY_IRQ);
 	return 0;
 }
 
 static void floppy_release_irq_and_dma(void)
 {
+#ifdef CONFIG_FLOPPY_SANITY
+	int drive;
+#endif
 	cli();
 	if (--usage_count){
 		sti();
 		return;
 	}
 	sti();
+#ifdef FD_MODULE
+	MOD_DEC_USE_COUNT;
+#endif
 	disable_dma(FLOPPY_DMA);
 	free_dma(FLOPPY_DMA);
 	disable_irq(FLOPPY_IRQ);
 	free_irq(FLOPPY_IRQ);
+
 	set_dor(0, ~0, 8);
 #if N_FDC > 1
-	if(fdc.address != -1)
-		set_dor(1, ~8, 0);
+	set_dor(1, ~8, 0);
+#endif
+
+#ifdef CONFIG_FLOPPY_SANITY
+	for(drive=0; drive < N_FDC * 4; drive++)
+		if( motor_off_timer[drive].next )
+			printk("motor off timer %d still active\n", drive);
+	
+	if(fd_timeout.next)
+		printk("floppy timer still active\n");
+	if (fd_timer.next)
+		printk("auxiliary floppy timer still active\n");
+	if(floppy_tq.sync)
+		printk("task queue still active\n");
 #endif
 }
+
+#endif
diff -u --recursive --new-file v1.1.65/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v1.1.65/linux/drivers/block/hd.c	Mon Oct 24 08:39:01 1994
+++ linux/drivers/block/hd.c	Tue Nov 22 15:40:11 1994
@@ -260,40 +260,29 @@
 static unsigned int mult_count  [MAX_HD] = {0,}; /* currently enabled MultMode count */
 static struct request WCURRENT;
 
-static void fixstring(unsigned char *s, int n)
+static void fixstring (unsigned char *s, int bytecount)
 {
-	int i;
-	unsigned short *ss = (unsigned short *) s;
+	unsigned char *p, *end = &s[bytecount &= ~1];	/* bytecount must be even */
 
 	/* convert from big-endian to little-endian */
-	for (i = n ; (i -= 2) >= 0 ; ss++)
-		*ss = (*ss >> 8) | (*ss << 8);
-
-	/* "strnlen()" */
-	for (i = 0 ; i < n ; i++) {
-		if (!s[i]) {
-			n = i;
-			break;
-		}
+	for (p = end ; p != s;) {
+		unsigned short *pp = (unsigned short *) (p -= 2);
+		*pp = (*pp >> 8) | (*pp << 8);
 	}
 
-	/* wipe out trailing spaces */
-	while (n > 0) {
-		if (s[n-1] != ' ')
-			break;
-		n--;
-		s[n] = '\0';
+	/* strip leading blanks */
+	while (s != end && *s == ' ')
+		++s;
+
+	/* compress internal blanks and strip trailing blanks */
+	while (s != end && *s) {
+		if (*s++ != ' ' || (s != end && *s && *s != ' '))
+			*p++ = *(s-1);
 	}
 
-	/* wipe out leading spaces */
-	if (*s == ' ') {
-		unsigned char *t = s;
-		while (n-- && *++s == ' ');
-		while (n-- >= 0) {
-			*t++ = *s;
-			*s++ = '\0';
-		}
-	}
+	/* wipe out trailing garbage */
+	while (p != end)
+		*p++ = '\0';
 }
 
 static void identify_intr(void)
@@ -332,8 +321,8 @@
 		fixstring (id->model, sizeof(id->model));
 		printk ("  hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
 			dev+'a', id->model, id->cyls*id->heads*id->sectors/2048,
-			id->buf_size/2, hd_info[dev].cyl, hd_info[dev].head,
-			hd_info[dev].sect, id->max_multsect);
+			id->buf_size/2, bios_info[dev].cyl, bios_info[dev].head,
+			bios_info[dev].sect, id->max_multsect);
 		/*
 		 * Early model Quantum drives go weird at this point,
 		 *   but doing a recalibrate seems to "fix" them.
diff -u --recursive --new-file v1.1.65/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.1.65/linux/drivers/block/ll_rw_blk.c	Sun Oct 23 13:04:29 1994
+++ linux/drivers/block/ll_rw_blk.c	Fri Nov 25 10:43:58 1994
@@ -17,7 +17,7 @@
 #include <linux/locks.h>
 
 #include <asm/system.h>
-
+#include <asm/io.h>
 #include "blk.h"
 
 /*
@@ -506,6 +506,11 @@
 #endif
 #ifdef CONFIG_MCD
 	mem_start = mcd_init(mem_start,mem_end);
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+	floppy_init();
+#else
+	outb_p(0xc, 0x3f2);
 #endif
 #ifdef CONFIG_SBPCD
 	mem_start = sbpcd_init(mem_start, mem_end);
diff -u --recursive --new-file v1.1.65/linux/drivers/char/console.c linux/drivers/char/console.c
--- v1.1.65/linux/drivers/char/console.c	Tue Nov 15 15:35:39 1994
+++ linux/drivers/char/console.c	Wed Nov 23 13:14:57 1994
@@ -46,7 +46,8 @@
  * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
  *   Chars, and VT100 enhancements by Peter MacDonald.
  *
- * Copy and paste function by Andrew Haylett.
+ * Copy and paste function by Andrew Haylett,
+ *   some enhancements by Alessandro Rubini.
  *
  * User definable mapping table and font loading by Eugene G. Crosser,
  * <crosser@pccross.msk.su>
@@ -2337,6 +2338,8 @@
 		default:
 			return -EINVAL;
 	}
+	/* remove the pointer */
+	highlight_pointer(sel_cons,-1);
 	/* select to end of line if on trailing space */
 	if (new_sel_end > new_sel_start &&
 		!atedge(new_sel_end) && isspace(*(off + new_sel_end)))
diff -u --recursive --new-file v1.1.65/linux/drivers/net/8390.h linux/drivers/net/8390.h
--- v1.1.65/linux/drivers/net/8390.h	Sun Oct  9 19:28:48 1994
+++ linux/drivers/net/8390.h	Tue Nov 22 15:40:12 1994
@@ -146,7 +146,7 @@
 #define ENTSR_COL 0x04	/* The transmit collided at least once. */
 #define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
 #define ENTSR_CRS 0x10	/* The carrier sense was lost. */
-#define ENTSR_FU  0x20  /* A "FIFO underrun" occured during transmit. */
+#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
 #define ENTSR_CDH 0x40	/* The collision detect "heartbeat" signal was lost. */
 #define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
 
diff -u --recursive --new-file v1.1.65/linux/drivers/net/apricot.c linux/drivers/net/apricot.c
--- v1.1.65/linux/drivers/net/apricot.c	Tue Sep 13 03:18:34 1994
+++ linux/drivers/net/apricot.c	Wed Nov 23 17:46:54 1994
@@ -652,7 +652,8 @@
     int i;
     int checksum = 0;
     int ioaddr = 0x300;
-
+    char eth_addr[6];
+    
     /* this is easy the ethernet interface can only be at 0x300 */
     /* first check nothing is already registered here */
 
@@ -668,12 +669,21 @@
 
     if (checksum % 0x100) return mem_start;
 
-    dev = init_etherdev(0, (sizeof (struct i596_private) + 0xf), &mem_start);
 
+    for(i = 0; i < 6 ; i++)
+    	eth_addr[i] = inb(ioaddr +8 +i));
+    
+    /* Some other boards trip the checksum.. but then appear as ether
+       address 0. Trap these - AC */
+       
+    if(memcmp(eth_addr,"\x00\x00\x00\x00\x00\x00",6)==0)
+    	return mem_addr;
+
+    dev = init_etherdev(0, (sizeof (struct i596_private) + 0xf), &mem_start);
     printk("%s: Apricot 82596 at %#3x,", dev->name, ioaddr);
 
     for (i = 0; i < 6; i++)
-	printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr +8 + i));
+	printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
 
     dev->base_addr = ioaddr;
     dev->irq = 10;
diff -u --recursive --new-file v1.1.65/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v1.1.65/linux/drivers/net/ewrk3.c	Thu Nov  3 17:53:29 1994
+++ linux/drivers/net/ewrk3.c	Thu Nov 24 14:18:24 1994
@@ -291,7 +291,7 @@
 static int ewrk3_close(struct device *dev);
 static struct enet_statistics *ewrk3_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
-static int ewrk3_ioctl(struct device *dev, struct ifreq *rq);
+static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd);
 
 /*
 ** Private functions
@@ -1580,7 +1580,7 @@
 ** Perform IOCTL call functions here. Some are privileged operations and the
 ** effective uid is checked in those cases.
 */
-static int ewrk3_ioctl(struct device *dev, struct ifreq *rq)
+static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
   struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
   struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_data;
diff -u --recursive --new-file v1.1.65/linux/drivers/net/hp.c linux/drivers/net/hp.c
--- v1.1.65/linux/drivers/net/hp.c	Sun Oct  9 19:28:48 1994
+++ linux/drivers/net/hp.c	Tue Nov 22 15:40:12 1994
@@ -275,7 +275,7 @@
 	outb_p(0xff, nic_base + EN0_RSARLO);
 	outb_p(0x00, nic_base + EN0_RSARHI);
 	outb_p(E8390_RREAD+E8390_START, EN_CMD);
-	/* Make certain that the dummy read has occured. */
+	/* Make certain that the dummy read has occurred. */
 	inb_p(0x61);
 	inb_p(0x61);
 #endif
diff -u --recursive --new-file v1.1.65/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v1.1.65/linux/drivers/net/ne.c	Sun Oct  9 19:28:49 1994
+++ linux/drivers/net/ne.c	Tue Nov 22 15:40:12 1994
@@ -402,7 +402,7 @@
     outb_p(0x42, nic_base + EN0_RSARLO);
     outb_p(0x00, nic_base + EN0_RSARHI);
     outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
-    /* Make certain that the dummy read has occured. */
+    /* Make certain that the dummy read has occurred. */
     SLOW_DOWN_IO;
     SLOW_DOWN_IO;
     SLOW_DOWN_IO;
diff -u --recursive --new-file v1.1.65/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v1.1.65/linux/drivers/net/plip.c	Thu Oct  6 07:17:24 1994
+++ linux/drivers/net/plip.c	Thu Nov 24 14:18:17 1994
@@ -186,7 +186,7 @@
 static int plip_send(struct device *dev, enum plip_nibble_state *ns_p,
 		     unsigned char data);
 static void plip_send_packet(struct device *dev);
-static int plip_ioctl(struct device *dev, struct ifreq *ifr);
+static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 static int plip_config(struct device *dev, struct ifmap *map);
 
 
@@ -942,7 +942,7 @@
 	return 0;
 }
 
-static int plip_ioctl(struct device *dev, struct ifreq *rq)
+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;
diff -u --recursive --new-file v1.1.65/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.1.65/linux/drivers/net/ppp.c	Thu Aug 11 20:38:51 1994
+++ linux/drivers/net/ppp.c	Thu Nov 24 14:18:33 1994
@@ -94,7 +94,7 @@
 int ppp_init(struct device *);
 static void ppp_init_ctrl_blk(struct ppp *);
 static int ppp_dev_open(struct device *);
-static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr);
+static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 static int ppp_dev_close(struct device *);
 static void ppp_kick_tty(struct ppp *);
 
@@ -607,7 +607,7 @@
 }
 
 #ifndef NET02D
-static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr)
+static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 {
   struct ppp *ppp = &ppp_ctrl[dev->base_addr];
   int    error;
diff -u --recursive --new-file v1.1.65/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v1.1.65/linux/drivers/net/sk_g16.c	Wed Aug 10 20:00:12 1994
+++ linux/drivers/net/sk_g16.c	Tue Nov 22 15:40:12 1994
@@ -232,8 +232,8 @@
 #define SK_IORUN        0x20   
 
 /* 
- * LANCE interrupt: 0 = LANCE interrupt occured	
- *                  1 = no LANCE interrupt occured
+ * LANCE interrupt: 0 = LANCE interrupt occurred	
+ *                  1 = no LANCE interrupt occurred
  */
 #define SK_IRQ          0x10   
 			
@@ -1408,7 +1408,7 @@
      * We check status of transmitted packet.
      * see LANCE data-sheet for error explanation
      */
-    if (tmdstat & TX_ERR) /* Error occured */
+    if (tmdstat & TX_ERR) /* Error occurred */
     {
 	printk("%s: TX error: %04x %04x\n", dev->name, (int) tmdstat,
 		(int) tmdp->status2);
@@ -1440,7 +1440,7 @@
 
 	tmdp->status2 = 0;             /* Clear error flags */
     }
-    else if (tmdstat & TX_MORE)        /* Collisions occured ? */
+    else if (tmdstat & TX_MORE)        /* Collisions occurred ? */
     {
         /* 
          * Here I have a problem.
diff -u --recursive --new-file v1.1.65/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v1.1.65/linux/drivers/net/slip.c	Tue Nov 22 15:41:11 1994
+++ linux/drivers/net/slip.c	Tue Nov 22 08:28:43 1994
@@ -166,7 +166,7 @@
 	int omtu=sl->mtu;
 
 #ifdef CONFIG_AX25
-	sl->mtu=dev->mtu+73
+	sl->mtu=dev->mtu+73;
 #else
 	sl->mtu=dev->mtu;
 #endif	
@@ -572,7 +572,7 @@
   }
 
 #ifdef CONFIG_AX25
-  sl->mtu		= dev->mtu+73
+  sl->mtu		= dev->mtu+73;
 #else    
   sl->mtu		= dev->mtu;
 #endif  
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v1.1.65/linux/drivers/scsi/53c7,8xx.c	Wed Oct 12 15:42:04 1994
+++ linux/drivers/scsi/53c7,8xx.c	Tue Nov 22 15:40:14 1994
@@ -3466,7 +3466,7 @@
 
     if (dstat & DSTAT_OPC) {
     /* 
-     * Ascertain if this IID interrupts occured before or after a STO 
+     * Ascertain if this IID interrupts occurred before or after a STO 
      * interrupt.  Since the interrupt handling code now leaves 
      * DSP unmodified until _after_ all stacked interrupts have been
      * processed, reading the DSP returns the original DSP register.
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.1.65/linux/drivers/scsi/Makefile	Fri Nov 18 15:22:09 1994
+++ linux/drivers/scsi/Makefile	Wed Nov 23 08:47:34 1994
@@ -47,6 +47,11 @@
 SCSI_SRCS := $(SCSI_SRCS) sg.c
 endif
 
+ifdef CONFIG_SCSI_QLOGIC
+SCSI_OBJS := $(SCSI_OBJS) qlogic.o
+SCSI_SRCS := $(SCSI_SRCS) qlogic.c
+endif
+
 ifdef CONFIG_SCSI_AHA152X
 SCSI_OBJS := $(SCSI_OBJS) aha152x.o
 SCSI_SRCS := $(SCSI_SRCS) aha152x.c
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v1.1.65/linux/drivers/scsi/NCR5380.c	Sun Aug 21 15:52:02 1994
+++ linux/drivers/scsi/NCR5380.c	Tue Nov 22 15:40:13 1994
@@ -1647,7 +1647,7 @@
     NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
 #else
     /*
-     * Note : on my sample board, watch-dog timeouts occured when interrupts
+     * Note : on my sample board, watch-dog timeouts occurred when interrupts
      * were not disabled for the duration of a single DMA transfer, from 
      * before the setting of DMA mode to after transfer of the last byte.
      */
@@ -1971,7 +1971,7 @@
 		}
 
 		/*
-		 * The prefered transfer method is going to be 
+		 * The preferred transfer method is going to be 
 		 * PSEUDO-DMA for systems that are strictly PIO,
 		 * since we can let the hardware do the handshaking.
 		 *
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/NCR5380.h linux/drivers/scsi/NCR5380.h
--- v1.1.65/linux/drivers/scsi/NCR5380.h	Fri Aug 19 08:54:02 1994
+++ linux/drivers/scsi/NCR5380.h	Tue Nov 22 15:40:13 1994
@@ -56,7 +56,7 @@
 
 /* 
  * The contents of the OUTPUT DATA register are asserted on the bus when
- * either arbitration is occuring or the phase-indicating signals (
+ * either arbitration is occurring or the phase-indicating signals (
  * IO, CD, MSG) in the TARGET COMMAND register and the ASSERT DATA
  * bit in the INITIATOR COMMAND register is set.
  */
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/README.qlogic linux/drivers/scsi/README.qlogic
--- v1.1.65/linux/drivers/scsi/README.qlogic	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/README.qlogic	Wed Nov 23 08:17:37 1994
@@ -0,0 +1,65 @@
+
+RANDOM NOTES ON THE QLOGIC SCSI DRIVER
+
+This driver does NOT support the PCI version.  It is a different chip.
+
+It DOES support the ISA, VLB, and PCMCIA versions of the Qlogic FastSCSI!
+cards as well as any other card based on the chip (including the Control
+Concepts SCSI/IDE/SIO/PIO/FDC cards).
+
+PCMCIA SUPPORT
+
+This currently only works if the card is enabled first from DOS.  This means
+you will have to load your socket and card services, and QL41DOS.SYS and
+QL40ENBL.SYS.  These are a minimum, but loading the rest of the modules
+won't interfere with the operation.  The next thing to do is load the kernel
+without resetting the hardware, which can be a simple ctrl-alt-delete with
+a boot floppy, or by using loadlin with the kernel image accessable from
+DOS.  If you are using the Linux PCMCIA driver, you will have to adjust
+it or otherwise stop it from configuring the card.
+
+I am working with the PCMCIA group to make it more flexible, but that may
+take a while.
+
+ALL CARDS
+
+The top of the qlogic.c file has a number of defines that controls 
+configuration.  As shipped, it provides a balance between speed and
+function.  If there are any problems, try setting SLOW_CABLE to 1, and
+then try changing USE_IRQ and TURBO_PDMA to zero.  If you are familiar 
+with SCSI, there are other settings which can tune the bus.
+
+It may be a good idea to enable RESET_AT_START, especially if the devices
+may not have been just powered up, or if you are restarting after a crash,
+since they may be busy trying to complete the last command or something.
+It comes up faster if this is set to zero, and if you have reliable
+hardware and connections it may be more useful to not reset things.
+
+SOME TROUBLESHOOTING TIPS
+
+Make sure it works properly under DOS.  You should also do an inital FDISK
+on a new drive if you want partitions.
+
+Don't enable all the speedups first.  If anything is wrong, they will make
+any problem worse.
+
+IMPORTANT
+
+The best way to test if your cables, termination, etc. are good is to copy
+a very big file (e.g. a doublespace container file, or a very large executable
+or archive).  It should be at least 5 megabytes, but you can do multiple tests
+on smaller files.  Then do a COMP to verify that the file copied properly.
+(Turn off all caching when doing these tests, otherwise you will test your
+RAM and not the files).  Then do 10 COMPs, comparing the same file on the
+SCSI hard drive, i.e. "COMP realbig.doc realbig.doc".  Then do it after the
+computer gets warm.
+
+I noticed my system which seems to work 100% would fail this test if the
+computer was left on for a few hours.  It was worse with longer cables, and
+more devices on the SCSI bus.  What seems to happen is that it gets a false
+ACK causing an extra byte to be inserted into the stream (and this is not
+detected).  This can be caused by bad termination (the ACK can be reflected),
+or by noise when the chips work less well because of the heat, or when cables
+get too long for the speed.
+
+If it doesn't work under DOS, it won't work under Linux.
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v1.1.65/linux/drivers/scsi/aha152x.c	Tue Sep 13 03:18:35 1994
+++ linux/drivers/scsi/aha152x.c	Fri Nov 25 08:47:32 1994
@@ -20,10 +20,17 @@
  * General Public License for more details.
  
  *
- * $Id: aha152x.c,v 1.4 1994/09/12 11:33:01 root Exp $
+ * $Id: aha152x.c,v 1.6 1994/11/24 20:35:27 root Exp $
  *
 
  * $Log: aha152x.c,v $
+ * Revision 1.6  1994/11/24  20:35:27  root
+ * - problem with odd number of bytes in fifo fixed
+ *
+ * Revision 1.5  1994/10/30  14:39:56  root
+ * - abort code fixed
+ * - debugging improved
+ *
  * Revision 1.4  1994/09/12  11:33:01  root
  * - irqaction to request_irq
  * - abortion updated
@@ -243,15 +250,18 @@
 
 /* recently used for debugging */
 #if 0
-#define DEBUG_PHASES
-#define DEBUG_DATAI
 #endif
 
+#define DEBUG_QUEUE
+#define DEBUG_PHASES
+
 #endif
 
 #define DEBUG_RESET             /* resets should be rare */
 #define DEBUG_ABORT             /* aborts too */
 
+#define DEBUG_DEFAULT (debug_reset|debug_abort)
+
 /* END OF DEFINES */
 
 /* some additional "phases" for getphase() */
@@ -266,6 +276,10 @@
 static int can_doparity   = 0;
 static int commands       = 0;
 
+#ifdef DEBUG_AHA152X
+unsigned int aha152x_debug  = DEBUG_DEFAULT;
+#endif
+
 /* set by aha152x_setup according to the command line */
 static int setup_called    = 0;
 static int setup_portbase  = 0;
@@ -274,6 +288,10 @@
 static int setup_reconnect = 0;
 static int setup_doparity  = 0;
 
+#ifdef DEBUG_AHA152X
+static int setup_debug     = 0;
+#endif
+
 static char *setup_str = (char *)NULL;
 
 enum {
@@ -295,8 +313,7 @@
 static Scsi_Cmnd            *current_SC      = NULL;
 static Scsi_Cmnd            *disconnected_SC = NULL;
 
-static struct wait_queue    *abortion_complete;
-static int                  abort_result;
+static int aborting=0, abortion_complete=0, abort_result;
 
 void aha152x_intr( int irqno );
 void aha152x_done( int error );
@@ -328,7 +345,7 @@
   (void *) 0xf0000,
   (void *) 0xeb800,   /* VTech Platinum SMP */
 };
-#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
+#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( void * ))
 
 /* possible i/o addresses for the AIC-6260 */
 static unsigned short ports[] =
@@ -494,6 +511,9 @@
   setup_scsiid	  = ints[0] >= 3 ? ints[3] : 7;
   setup_reconnect = ints[0] >= 4 ? ints[4] : 1;
   setup_doparity  = ints[0] >= 5 ? ints[5] : 1;
+#ifdef DEBUG_AHA152X
+  setup_debug     = ints[0] >= 6 ? ints[6] : DEBUG_DEFAULT;
+#endif
 }
 
 /*
@@ -527,10 +547,18 @@
     {
       printk("aha152x: processing commandline: ");
    
+#ifdef DEBUG_AHA152X
+      if(setup_called>6)
+#else
       if(setup_called>5)
+#endif
         {
           printk("\naha152x: %s\n", setup_str );
+#ifdef DEBUG_AHA152X
+          printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>[,<DEBUG>]]]]]\n");
+#else
           printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>]]]]\n");
+#endif
           panic("aha152x panics in line %d", __LINE__);
         }
 
@@ -539,6 +567,9 @@
       this_host       = setup_scsiid;
       can_disconnect  = setup_reconnect;
       can_doparity    = setup_doparity;
+#ifdef DEBUG_AHA152X
+      aha152x_debug   = setup_debug;
+#endif
 
       for( i=0; i<PORT_COUNT && (port_base != ports[i]); i++)
         ;
@@ -720,19 +751,23 @@
   enter_driver("queue");
 #else
 #if defined(DEBUG_QUEUE)
-  printk("aha152x: queue(), ");
+  if(aha152x_debug & debug_queue)
+    printk("aha152x: queue(), ");
 #endif
 #endif
 
-
 #if defined(DEBUG_QUEUE)
-  printk( "SCpnt (target = %d lun = %d cmnd = 0x%02x pieces = %d size = %u), ",
-          SCpnt->target,
-          SCpnt->lun,
-          *(unsigned char *)SCpnt->cmnd,
-          SCpnt->use_sg,
-          SCpnt->request_bufflen );
-  disp_ports();
+  if(aha152x_debug & debug_queue)
+  {
+    printk( "SCpnt (target = %d lun = %d cmnd = ",
+            SCpnt->target,
+            SCpnt->lun);
+    print_command(SCpnt->cmnd);
+    printk( ", pieces = %d size = %u), ",
+            SCpnt->use_sg,
+            SCpnt->request_bufflen );
+    disp_ports();
+  }
 #endif
 
   SCpnt->scsi_done =       done;
@@ -771,7 +806,8 @@
     SETPORT( PORTA, 1 );
 
 #if defined(DEBUG_QUEUES)
-  printk("i+ (%d), ", commands );
+  if(aha152x_debug & debug_queues)
+    printk("i+ (%d), ", commands );
 #endif
   append_SC( &issue_SC, SCpnt);
   
@@ -810,11 +846,12 @@
   cli();
 
 #if defined(DEBUG_ABORT)
-  printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt );
-#endif
+  if(aha152x_debug & debug_abort)
+  { 
+    printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt );
 
-#if defined(DEBUG_ABORT)
-  show_queues();
+    show_queues();
+  }
 #endif
 
   /* look for command in issue queue */
@@ -838,24 +875,30 @@
       return SCSI_ABORT_SUCCESS;
     }
 
-  if (!current_SC && TESTLO(SSTAT1, BUSFREE))
-    printk("bus busy w/o current command, ");
+  /* if the bus is busy or a command is currently processed,
+     we can't do anything more */
+  if ( TESTLO(SSTAT1, BUSFREE) || (current_SC && current_SC!=SCpnt))
+    {
+      /* fail abortion, if bus is busy */
 
-  if (current_SC==SCpnt)
-    if( TESTLO(SSTAT1, BUSFREE) ) {
-      /* fail abortion, if current command is on the bus */
+      if(!current_SC)
+        printk("bus busy w/o current command, ");
+ 
       sti();
       return SCSI_ABORT_BUSY;
     }
-    else
-    { 
-      /* target entered bus free before COMMAND COMPLETE, nothing to abort */
-      sti();
-      current_SC->result = DID_ERROR << 16;
-      current_SC->done(current_SC);
-      current_SC = (Scsi_Cmnd *) NULL;
-      return SCSI_ABORT_SUCCESS;
-    }
+
+  /* bus is free */
+
+  if(current_SC)
+  { 
+    /* target entered bus free before COMMAND COMPLETE, nothing to abort */
+    sti();
+    current_SC->result = DID_ERROR << 16;
+    current_SC->done(current_SC);
+    current_SC = (Scsi_Cmnd *) NULL;
+    return SCSI_ABORT_SUCCESS;
+  }
 
   /* look for command in disconnected queue */
   for( ptr=disconnected_SC, prev=NULL;
@@ -864,40 +907,45 @@
     ;
 
   if(ptr)
-    if( TESTHI(SSTAT1, BUSFREE) )
-    {
-      /* dequeue */
-      if(prev)
-        prev->host_scribble = ptr->host_scribble;
-      else
-        disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
-
-      /* set command current and initiate selection,
-         let the interrupt routine take care of the abortion */
-      current_SC     = ptr;
-      ptr->SCp.phase = in_selection|aborted;
-      SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
-
-      /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
-      SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
-      SETPORT( SIMODE1, ENSELTIMO );
-
-      /* Enable SELECTION OUT sequence */
-      SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
-
-      SETBITS( DMACNTRL0, INTEN );
-      abort_result=SCSI_ABORT_SUCCESS;
-      sti();
-
-      /* sleep until the abortion is complete */
-      sleep_on( &abortion_complete );
-      return abort_result;
-    }
-  else {
-      /* fail abortion, if we can't abort the disconnected command */
-      sti();
-      return SCSI_ABORT_BUSY;
-    }
+    if(!aborting)
+      {
+        /* dequeue */
+        if(prev)
+          prev->host_scribble = ptr->host_scribble;
+        else
+          disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
+  
+        /* set command current and initiate selection,
+           let the interrupt routine take care of the abortion */
+        current_SC     = ptr;
+        ptr->SCp.phase = in_selection|aborted;
+        SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
+  
+        /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
+        SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
+        SETPORT( SIMODE1, ENSELTIMO );
+  
+        /* Enable SELECTION OUT sequence */
+        SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
+  
+        SETBITS( DMACNTRL0, INTEN );
+        abort_result=SCSI_ABORT_SUCCESS;
+        aborting++;
+        abortion_complete=0;
+        sti();
+  
+        /* sleep until the abortion is complete */
+        while(!abortion_complete)
+	  ;
+        aborting=0;
+        return abort_result;
+      }
+    else
+      {
+        /* we're already aborting a command */
+        sti();
+        return( SCSI_ABORT_BUSY );
+      }
 
   /* command wasn't found */
   printk("command not found\n");
@@ -954,12 +1002,12 @@
     {
        CLRBITS( DMACNTRL0, INTEN );
 
-#if defined( DEBUG_RESET )
+#if defined(DEBUG_RESET)
+  if(aha152x_debug & debug_reset)
+  {
        printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
-#endif
-
-#if defined( DEBUG_RESET )
        show_queues();
+  }
 #endif
 
        if(current_SC && !current_SC->device->soft_reset)
@@ -998,8 +1046,11 @@
        sti();
 
 #if defined( DEBUG_RESET )
-       printk("commands on targets w/ soft-resets:\n");
-       show_queues();
+       if(aha152x_debug & debug_reset)
+       {
+         printk("commands on targets w/ soft-resets:\n");
+         show_queues();
+       }
 #endif
 
        /* RESET OUT */
@@ -1023,8 +1074,10 @@
 int aha152x_biosparam(Scsi_Disk * disk, int dev, int *info_array )
 {
   int size = disk->capacity;
+
 #if defined(DEBUG_BIOSPARAM)
-  printk("aha152x_biosparam: dev=%x, size=%d, ", dev, size);
+  if(aha152x_debug & debug_biosparam)
+    printk("aha152x_biosparam: dev=%x, size=%d, ", dev, size);
 #endif
   
 /* I took this from other SCSI drivers, since it provides
@@ -1034,9 +1087,12 @@
   info_array[2]=size>>11;
 
 #if defined(DEBUG_BIOSPARAM)
-  printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
-         info_array[0], info_array[1], info_array[2]);
-  printk("WARNING: check, if the bios geometry is correct.\n");
+  if(aha152x_debug & debug_biosparam)
+  {
+    printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
+           info_array[0], info_array[1], info_array[2]);
+    printk("WARNING: check, if the bios geometry is correct.\n");
+  }
 #endif
 
   return 0;
@@ -1050,14 +1106,18 @@
   Scsi_Cmnd *done_SC;
 
 #if defined(DEBUG_DONE)
-  printk("\naha152x: done(), ");
-  disp_ports();
+  if(aha152x_debug & debug_done)
+  {
+    printk("\naha152x: done(), ");
+    disp_ports();
+  }
 #endif
 
   if (current_SC)
     {
 #if defined(DEBUG_DONE)
-      printk("done(%x), ", error);
+      if(aha152x_debug & debug_done)
+        printk("done(%x), ", error);
 #endif
 
       cli();
@@ -1071,7 +1131,8 @@
         SETPORT( PORTA, 0 );                                  /* turn led off */
 
 #if defined(DEBUG_QUEUES)
-      printk("ok (%d), ", commands);
+      if(aha152x_debug & debug_queues) 
+        printk("ok (%d), ", commands);
 #endif
       sti();
 
@@ -1079,23 +1140,27 @@
       SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
 
 #if defined(DEBUG_PHASES)
-      printk("BUS FREE loop, ");
+      if(aha152x_debug & debug_phases)
+        printk("BUS FREE loop, ");
 #endif
       while( TESTLO( SSTAT1, BUSFREE ) )
         ;
 #if defined(DEBUG_PHASES)
-      printk("BUS FREE\n");
+      if(aha152x_debug & debug_phases)
+        printk("BUS FREE\n");
 #endif
 
       done_SC->result = error;
       if(done_SC->scsi_done)
         {
 #if defined(DEBUG_DONE)
-          printk("calling scsi_done, ");
+          if(aha152x_debug & debug_done)
+            printk("calling scsi_done, ");
 #endif
           done_SC->scsi_done( done_SC );
 #if defined(DEBUG_DONE)
-          printk("done returned, ");
+          if(aha152x_debug & debug_done)
+            printk("done returned, ");
 #endif
         }
       else
@@ -1116,7 +1181,8 @@
   enter_driver("intr");
 #else
 #if defined(DEBUG_INTR)
-  printk("\naha152x: intr(), ");
+  if(aha152x_debug & debug_intr)
+    printk("\naha152x: intr(), ");
 #endif
 #endif
 
@@ -1143,6 +1209,7 @@
       if(current_SC)
         {
 #if defined(DEBUG_QUEUES)
+	  if(aha152x_debug & debug_queues)
           printk("i+, ");
 #endif
           cli();
@@ -1157,7 +1224,8 @@
       SETPORT( SSTAT1, CLRBUSFREE );
 
 #if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
-      printk("reselected, ");
+      if(aha152x_debug & (debug_queues|debug_phases))
+        printk("reselected, ");
 #endif
 
       i = GETPORT(SELID) & ~(1 << this_host);
@@ -1169,7 +1237,8 @@
         aha152x_panic("reconnecting target unknown");
 
 #if defined(DEBUG_QUEUES)
-      printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
+      if(aha152x_debug & debug_queues)
+        printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
 #endif
       SETPORT( SCSIID, (this_host << OID_) | target );
       SETPORT( SCSISEQ, ENRESELI );
@@ -1202,12 +1271,14 @@
       getphase();
 
 #if defined(DEBUG_QUEUES)
-      printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
+      if(aha152x_debug & debug_queues)
+        printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
 #endif
 
       cli();
 #if defined(DEBUG_QUEUES)
-      printk("d-, ");
+      if(aha152x_debug & debug_queues)
+        printk("d-, ");
 #endif
       current_SC = remove_SC( &disconnected_SC,
                               target,
@@ -1239,18 +1310,21 @@
         {
           cli();
 #if defined(DEBUG_QUEUES)
-          printk("i-, ");
+          if(aha152x_debug & debug_queues)
+            printk("i-, ");
 #endif
           current_SC = remove_first_SC( &issue_SC );
           sti();
 
 #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-          printk("issuing command, ");
+	  if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
+            printk("issuing command, ");
 #endif
           current_SC->SCp.phase = in_selection;
 
   #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-          printk("selecting %d, ", current_SC->target); 
+	  if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
+            printk("selecting %d, ", current_SC->target); 
   #endif
           SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
 
@@ -1279,7 +1353,8 @@
   /* the bus is busy with something */
 
 #if defined(DEBUG_INTR)
-  disp_ports();
+  if(aha152x_debug & debug_intr)
+    disp_ports();
 #endif
 
   /* we are waiting for the result of a selection attempt */
@@ -1311,21 +1386,22 @@
                 if(current_SC->SCp.phase & aborted)
                   {
                     abort_result=SCSI_ABORT_ERROR;
-                    wake_up( &abortion_complete );
+		    abortion_complete++;
                   }
 
                 aha152x_done( DID_NO_CONNECT << 16 );
                 return;
               }
 #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-            printk("SELDO (SELID=%x), ", GETPORT(SELID));
+	    if(aha152x_debug & (debug_selection|debug_phases))
+              printk("SELDO (SELID=%x), ", GETPORT(SELID));
 #endif
 
             /* selection was done */
             SETPORT( SSTAT0, CLRSELDO );
 
 #if defined(DEBUG_ABORT)
-            if(current_SC->SCp.phase & aborted)
+            if((aha152x_debug & debug_abort) && (current_SC->SCp.phase & aborted))
               printk("(ABORT) target selected, ");
 #endif
 
@@ -1348,6 +1424,7 @@
       else
         {
 #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
+	  if(aha152x_debug & (debug_selection|debug_phases))
           printk("SELTO, ");
 #endif
 	  /* end selection attempt */
@@ -1366,10 +1443,11 @@
           if(current_SC->SCp.phase & aborted)
             {
 #if defined(DEBUG_ABORT)
-              printk("(ABORT) selection timeout, ");
+	      if(aha152x_debug & debug_abort)
+                printk("(ABORT) selection timeout, ");
 #endif
               abort_result=SCSI_ABORT_ERROR;
-              wake_up( &abortion_complete );
+              abortion_complete++;
             }
 
           if( TESTLO( SSTAT0, SELINGO ) )
@@ -1398,13 +1476,15 @@
         unsigned char message;
 
 #if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
-        printk("MESSAGE OUT, ");
+        if(aha152x_debug & (debug_intr|debug_msgo|debug_phases))
+          printk("MESSAGE OUT, ");
 #endif
 
         if( current_SC->SCp.phase & aborted )
           {
 #if defined(DEBUG_MSGO) || defined(DEBUG_ABORT)
-            printk("ABORT, ");
+            if(aha152x_debug & (debug_msgo|debug_abort))
+              printk("ABORT, ");
 #endif
             message=ABORT;
           }
@@ -1416,15 +1496,17 @@
             {
               message=IDENTIFY(can_disconnect,current_SC->lun);
 #if defined(DEBUG_MSGO)
-              printk("IDENTIFY (reconnect=%s;lun=%d), ", 
-                      can_disconnect ? "enabled" : "disabled", current_SC->lun);
+              if(aha152x_debug & debug_msgo)
+                printk("IDENTIFY (reconnect=%s;lun=%d), ", 
+                        can_disconnect ? "enabled" : "disabled", current_SC->lun);
 #endif
             }
           else
             {
               message=MESSAGE_REJECT;
 #if defined(DEBUG_MSGO)
-              printk("REJECT, ");
+              if(aha152x_debug & debug_msgo)
+                printk("REJECT, ");
 #endif
             }
           
@@ -1455,7 +1537,7 @@
           {
             /* revive abort(); abort() enables interrupts */
             abort_result=SCSI_ABORT_SUCCESS;
-            wake_up( &abortion_complete );
+            abortion_complete++;
 
             current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
 
@@ -1472,7 +1554,8 @@
 
     case P_CMD:                                          /* COMMAND phase */
 #if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
-      printk("COMMAND, ");
+      if(aha152x_debug & (debug_intr|debug_cmd|debug_phases))
+        printk("COMMAND, ");
 #endif
       if( !(current_SC->SCp.sent_command) )
         {
@@ -1493,7 +1576,8 @@
           SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
   
 #if defined(DEBUG_CMD)
-          printk("waiting, ");
+          if(aha152x_debug & debug_cmd)
+            printk("waiting, ");
 #endif
           /* wait for FIFO to get empty */
           while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
@@ -1503,9 +1587,12 @@
             aha152x_panic("target left COMMAND phase");
 
 #if defined(DEBUG_CMD)
-          printk("DFIFOEMP, outsw (%d words), ",
-                 COMMAND_SIZE(current_SC->cmnd[0])>>1);
-          disp_ports();
+          if(aha152x_debug & debug_cmd)
+          {
+            printk("DFIFOEMP, outsw (%d words), ",
+                   COMMAND_SIZE(current_SC->cmnd[0])>>1);
+            disp_ports();
+          }
 #endif
   
           outsw( DATAPORT,
@@ -1513,8 +1600,11 @@
                  COMMAND_SIZE(current_SC->cmnd[0])>>1 );
 
 #if defined(DEBUG_CMD)
-          printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
-          disp_ports();
+	  if(aha152x_debug & debug_cmd)
+          {
+            printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
+            disp_ports();
+          }
 #endif
 
           /* wait for SCSI FIFO to get empty.
@@ -1530,8 +1620,9 @@
           CLRBITS(DMACNTRL0, ENDMA);
 
 #if defined(DEBUG_CMD) || defined(DEBUG_INTR)
-          printk("sent %d/%d command bytes, ", GETSTCNT(),
-                 COMMAND_SIZE(current_SC->cmnd[0]));
+          if(debug_cmd & debug_intr)
+            printk("sent %d/%d command bytes, ", GETSTCNT(),
+                   COMMAND_SIZE(current_SC->cmnd[0]));
 #endif
 
         }
@@ -1541,7 +1632,8 @@
 
     case P_MSGI:                                          /* MESSAGE IN phase */
 #if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-      printk("MESSAGE IN, ");
+      if(aha152x_debug & (debug_intr|debug_msgi|debug_phases))
+        printk("MESSAGE IN, ");
 #endif
       SETPORT( SXFRCTL0, CH1);
 
@@ -1555,7 +1647,8 @@
             {
             case DISCONNECT:
 #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-              printk("target disconnected, ");
+	      if(aha152x_debug & (debug_msgi|debug_phases))
+                printk("target disconnected, ");
 #endif
               current_SC->SCp.Message = 0;
               current_SC->SCp.phase   |= disconnected;
@@ -1565,20 +1658,23 @@
         
             case COMMAND_COMPLETE:
 #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-              printk("inbound message ( COMMAND COMPLETE ), ");
+	      if(aha152x_debug & (debug_msgi|debug_phases))
+                printk("inbound message ( COMMAND COMPLETE ), ");
 #endif
               done++;
               break;
 
             case MESSAGE_REJECT:
-#if defined(DEBUG_MSGI) || defined(DEBUG_TIMING)
-              printk("inbound message ( MESSAGE REJECT ), ");
+#if defined(DEBUG_MSGI)
+	      if(aha152x_debug & debug_msgi)
+                printk("inbound message ( MESSAGE REJECT ), ");
 #endif
               break;
 
             case SAVE_POINTERS:
 #if defined(DEBUG_MSGI)
-              printk("inbound message ( SAVE DATA POINTERS ), ");
+	      if(aha152x_debug & debug_msgi)
+                printk("inbound message ( SAVE DATA POINTERS ), ");
 #endif
               break;
 
@@ -1587,7 +1683,8 @@
                 int           i, code;
 
 #if defined(DEBUG_MSGI)
-                printk("inbound message ( EXTENDED MESSAGE ), ");
+	        if(aha152x_debug & debug_msgi)
+                  printk("inbound message ( EXTENDED MESSAGE ), ");
 #endif
                 make_acklow();
                 if(getphase()!=P_MSGI)
@@ -1596,11 +1693,8 @@
                 i=GETPORT(SCSIBUS);
 
 #if defined(DEBUG_MSGI)
-                printk("length (%d), ", i);
-#endif
-
-#if defined(DEBUG_MSGI)
-                printk("code ( ");
+	        if(aha152x_debug & debug_msgi)
+                  printk("length (%d), code ( ", i);
 #endif
 
                 make_acklow();
@@ -1613,50 +1707,58 @@
                   {
                   case 0x00:
 #if defined(DEBUG_MSGI)
-                    printk("MODIFY DATA POINTER ");
+	            if(aha152x_debug & debug_msgi)
+                      printk("MODIFY DATA POINTER ");
 #endif
                     SETPORT(SCSISIG, P_MSGI|ATNO);
                     break;
                   case 0x01:
 #if defined(DEBUG_MSGI)
-                    printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
+	            if(aha152x_debug & debug_msgi)
+                      printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
 #endif
                     SETPORT(SCSISIG, P_MSGI|ATNO);
                     break;
                   case 0x02:
 #if defined(DEBUG_MSGI)
-                    printk("EXTENDED IDENTIFY ");
+	            if(aha152x_debug & debug_msgi)
+                      printk("EXTENDED IDENTIFY ");
 #endif
                     break;
                   case 0x03:
 #if defined(DEBUG_MSGI)
-                    printk("WIDE DATA TRANSFER REQUEST ");
+	            if(aha152x_debug & debug_msgi)
+                      printk("WIDE DATA TRANSFER REQUEST ");
 #endif
                     SETPORT(SCSISIG, P_MSGI|ATNO);
                     break;
                   default:
 #if defined(DEBUG_MSGI)
-                    if( code & 0x80 )
-                      printk("reserved (%d) ", code );
-                    else
-                      printk("vendor specific (%d) ", code);
+	            if(aha152x_debug & debug_msgi)
+                      if( code & 0x80 )
+                        printk("reserved (%d) ", code );
+                      else
+                        printk("vendor specific (%d) ", code);
 #endif
                     SETPORT(SCSISIG, P_MSGI|ATNO);
                     break;
                   }
 #if defined(DEBUG_MSGI)
-                printk(" ), data ( ");
+	        if(aha152x_debug & debug_msgi)
+                  printk(" ), data ( ");
 #endif
                 while( --i && (make_acklow(), getphase()==P_MSGI))
                   {
 #if defined(DEBUG_MSGI)
-                    printk("%x ", GETPORT(SCSIBUS) );
+	            if(aha152x_debug & debug_msgi)
+                      printk("%x ", GETPORT(SCSIBUS) );
 #else
                     GETPORT(SCSIBUS);
 #endif
                   }
 #if defined(DEBUG_MSGI)
-                printk(" ), ");
+	        if(aha152x_debug & debug_msgi)
+                  printk(" ), ");
 #endif
                 /* We reject all extended messages. To do this
                    we just enter MSGO by asserting ATN. Since
@@ -1684,7 +1786,8 @@
         {
           cli();
 #if defined(DEBUG_QUEUES)
-          printk("d+, ");
+	  if(aha152x_debug & debug_queues)
+            printk("d+, ");
 #endif
           append_SC( &disconnected_SC, current_SC);
           current_SC = NULL;
@@ -1702,7 +1805,8 @@
 
     case P_STATUS:                                         /* STATUS IN phase */
 #if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-      printk("STATUS, ");
+      if(aha152x_debug & (debug_status|debug_intr|debug_phases))
+        printk("STATUS, ");
 #endif
       SETPORT( SXFRCTL0, CH1);
 
@@ -1717,9 +1821,12 @@
       getphase();
 
 #if defined(DEBUG_STATUS)
-      printk("inbound status ");
-      print_status( current_SC->SCp.Status );
-      printk(", ");
+      if(aha152x_debug & debug_status)
+      {
+        printk("inbound status ");
+        print_status( current_SC->SCp.Status );
+        printk(", ");
+      }
 #endif
       break;
 
@@ -1728,7 +1835,8 @@
         int fifodata, data_count, done;
 
 #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-        printk("DATA IN, ");
+        if(aha152x_debug & (debug_datai|debug_intr|debug_phases))
+          printk("DATA IN, ");
 #endif
 
         if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
@@ -1751,7 +1859,8 @@
         while ( !done ) 
           {
 #if defined(DEBUG_DATAI)
-            printk("expecting data, ");
+            if(aha152x_debug & debug_datai)
+              printk("expecting data, ");
 #endif
             /* wait for PHASEMIS or full FIFO */
             while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) )
@@ -1768,13 +1877,15 @@
                 /* rest of data in FIFO */
                 fifodata=GETPORT(FIFOSTAT);
 #if defined(DEBUG_DATAI)
-                printk("last transfer, ");
+                if(aha152x_debug & debug_datai)
+                  printk("last transfer, ");
 #endif
                 done=1;
               }
   
 #if defined(DEBUG_DATAI)
-            printk("fifodata=%d, ", fifodata);
+            if(aha152x_debug & debug_datai)
+              printk("fifodata=%d, ", fifodata);
 #endif
 
             while( fifodata && current_SC->SCp.this_residual )
@@ -1788,35 +1899,37 @@
                 fifodata -= data_count;
 
 #if defined(DEBUG_DATAI)
-                printk("data_count=%d, ", data_count);
+                if(aha152x_debug & debug_datai)
+                  printk("data_count=%d, ", data_count);
 #endif
   
-                if(data_count == 1)
+                if(data_count&1)
                   {
                     /* get a single byte in byte mode */
                     SETBITS(DMACNTRL0, _8BIT );
                     *current_SC->SCp.ptr++ = GETPORT( DATAPORT );
                     current_SC->SCp.this_residual--;
                   }
-                else
+                if(data_count>1)
                   {
                     CLRBITS(DMACNTRL0, _8BIT );
                     data_count >>= 1; /* Number of words */
                     insw( DATAPORT, current_SC->SCp.ptr, data_count );
 #if defined(DEBUG_DATAI)
+                    if(aha152x_debug & debug_datai)
 /* show what comes with the last transfer */
-                    if(done)
-                      {
-                        int           i;
-                        unsigned char *data;
-
-                        printk("data on last transfer (%d bytes: ",
-                               2*data_count);
-                        data = (unsigned char *) current_SC->SCp.ptr;
-                        for( i=0; i<2*data_count; i++)
-                          printk("%2x ", *data++);
-                        printk("), ");
-                      }
+                      if(done)
+                        {
+                          int           i;
+                          unsigned char *data;
+  
+                          printk("data on last transfer (%d bytes: ",
+                                 2*data_count);
+                          data = (unsigned char *) current_SC->SCp.ptr;
+                          for( i=0; i<2*data_count; i++)
+                            printk("%2x ", *data++);
+                          printk("), ");
+                        }
 #endif
                     current_SC->SCp.ptr           += 2 * data_count;
                     current_SC->SCp.this_residual -= 2 * data_count;
@@ -1851,15 +1964,16 @@
               }
 
 #if defined(DEBUG_DATAI)
-            if(!fifodata)
-              printk("fifo empty, ");
-            else
-              printk("something left in fifo, ");
+            if(aha152x_debug & debug_datai)
+              if(!fifodata)
+                printk("fifo empty, ");
+              else
+                printk("something left in fifo, ");
 #endif
           }
 
 #if defined(DEBUG_DATAI)
-        if(current_SC->SCp.buffers_residual || current_SC->SCp.this_residual)
+        if((aha152x_debug & debug_datai) && (current_SC->SCp.buffers_residual || current_SC->SCp.this_residual))
           printk("left buffers (buffers=%d, bytes=%d), ",
                  current_SC->SCp.buffers_residual, 
                  current_SC->SCp.this_residual);
@@ -1871,7 +1985,8 @@
         CLRBITS(DMACNTRL0, ENDMA );
 
 #if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
-        printk("got %d bytes, ", GETSTCNT());
+        if(aha152x_debug & (debug_datai|debug_intr))
+          printk("got %d bytes, ", GETSTCNT());
 #endif
 
         current_SC->SCp.have_data_in++;
@@ -1883,12 +1998,14 @@
         int data_count;
 
 #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-        printk("DATA OUT, ");
+        if(aha152x_debug & (debug_datao|debug_intr|debug_phases))
+          printk("DATA OUT, ");
 #endif
 #if defined(DEBUG_DATAO)
-        printk("got data to send (bytes=%d, buffers=%d), ",
-               current_SC->SCp.this_residual,
-               current_SC->SCp.buffers_residual );
+        if(aha152x_debug & debug_datao)
+          printk("got data to send (bytes=%d, buffers=%d), ",
+                 current_SC->SCp.this_residual,
+                 current_SC->SCp.buffers_residual );
 #endif
 
         if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) )
@@ -1913,26 +2030,28 @@
                   current_SC->SCp.buffers_residual) )
           {
 #if defined(DEBUG_DATAO)
-            printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
-                    current_SC->SCp.this_residual,
-                    current_SC->SCp.buffers_residual);
+            if(aha152x_debug & debug_datao)
+              printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
+                     current_SC->SCp.this_residual,
+                     current_SC->SCp.buffers_residual);
 #endif
             /* transfer rest of buffer, but max. 128 byte */
             data_count = current_SC->SCp.this_residual > 128 ?
                          128 : current_SC->SCp.this_residual ;
 
 #if defined(DEBUG_DATAO)
-            printk("data_count=%d, ", data_count);
+            if(aha152x_debug & debug_datao)
+              printk("data_count=%d, ", data_count);
 #endif
   
-            if(data_count == 1)
+            if(data_count&1)
               {
                 /* put a single byte in byte mode */
                 SETBITS(DMACNTRL0, _8BIT );
                 SETPORT(DATAPORT, *current_SC->SCp.ptr++);
                 current_SC->SCp.this_residual--;
               }
-            else
+            if(data_count>1)
               {
                 CLRBITS(DMACNTRL0, _8BIT );
                 data_count >>= 1; /* Number of words */
@@ -1946,8 +2065,9 @@
               ;
 
 #if defined(DEBUG_DATAO)
-            printk("fifo (%d bytes), transfered (%d bytes), ",
-                   GETPORT(FIFOSTAT), GETSTCNT() );
+            if(aha152x_debug & debug_datao)
+              printk("fifo (%d bytes), transfered (%d bytes), ",
+                     GETPORT(FIFOSTAT), GETSTCNT() );
 #endif
 
             /* if this buffer is empty and there are more buffers left */
@@ -1978,10 +2098,11 @@
             current_SC->SCp.ptr           -= data_count;
             current_SC->SCp.this_residual += data_count;
 #if defined(DEBUG_DATAO)
-            printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
-                   current_SC->SCp.this_residual,
-                   current_SC->SCp.buffers_residual,
-                   data_count );
+            if(aha152x_debug & debug_datao)
+              printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
+                     current_SC->SCp.this_residual,
+                     current_SC->SCp.buffers_residual,
+                     data_count );
 #endif
             SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
             CLRBITS(SXFRCTL0, SCSIEN|DMAEN );
@@ -1990,19 +2111,17 @@
         else
           {
 #if defined(DEBUG_DATAO)
-            printk("waiting for SCSI fifo to get empty, ");
+            if(aha152x_debug & debug_datao)
+              printk("waiting for SCSI fifo to get empty, ");
 #endif
             /* wait for SCSI fifo to get empty */
             while( TESTLO( SSTAT2, SEMPTY ) )
               ;
 #if defined(DEBUG_DATAO)
-            printk("ok, ");
-#endif
-
-#if defined(DEBUG_DATAO)
-            printk("left data (bytes=%d, buffers=%d) ",
-                   current_SC->SCp.this_residual,
-                   current_SC->SCp.buffers_residual);
+            if(aha152x_debug & debug_datao)
+              printk("ok, left data (bytes=%d, buffers=%d) ",
+                     current_SC->SCp.this_residual,
+                     current_SC->SCp.buffers_residual);
 #endif
             CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
 
@@ -2014,7 +2133,8 @@
           }
 
 #if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
-        printk("sent %d data bytes, ", GETSTCNT() );
+        if(aha152x_debug & (debug_datao|debug_intr))
+          printk("sent %d data bytes, ", GETSTCNT() );
 #endif
       }
       break;
@@ -2024,7 +2144,8 @@
       leave_driver("(BUSFREE) intr");
 #endif
 #if defined(DEBUG_PHASES)
-      printk("unexpected BUS FREE, ");
+      if(aha152x_debug & debug_phases)
+        printk("unexpected BUS FREE, ");
 #endif
       current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
 
@@ -2053,7 +2174,8 @@
   if(done)
     {
 #if defined(DEBUG_INTR)
-      printk("command done.\n");
+      if(aha152x_debug & debug_intr)
+        printk("command done.\n");
 #endif
 #if defined(DEBUG_RACE)
       leave_driver("(done) intr");
@@ -2082,7 +2204,8 @@
   SETPORT( SIMODE0, 0 );
   SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
 #if defined(DEBUG_INTR)
-  disp_enintr();
+  if(aha152x_debug & debug_intr)
+    disp_enintr();
 #endif
 #if defined(DEBUG_RACE)
   leave_driver("(PHASEEND) intr");
@@ -2107,9 +2230,12 @@
  */
 static void disp_ports(void)
 {
-#if !defined(SKIP_PORTS)
+#ifdef DEBUG_AHA152X
   int s;
 
+  if(aha152x_debug & debug_skipports)
+	return;
+
   printk("\n%s: ", current_SC ? "on bus" : "waiting");
 
   s=GETPORT(SCSISEQ);
@@ -2354,13 +2480,10 @@
  */
 static void show_command(Scsi_Cmnd *ptr)
 {
-  int i;
-
   printk("0x%08x: target=%d; lun=%d; cmnd=( ",
          (unsigned int) ptr, ptr->target, ptr->lun);
   
-  for(i=0; i<COMMAND_SIZE(ptr->cmnd[0]); i++)
-    printk("%02x ", ptr->cmnd[i]);
+  print_command(ptr->cmnd);
 
   printk("); residual=%d; buffers=%d; phase |",
          ptr->SCp.this_residual, ptr->SCp.buffers_residual);
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h
--- v1.1.65/linux/drivers/scsi/aha152x.h	Tue Sep 13 03:18:35 1994
+++ linux/drivers/scsi/aha152x.h	Fri Nov 25 08:47:32 1994
@@ -2,12 +2,13 @@
 #define _AHA152X_H
 
 /*
- * $Id: aha152x.h,v 1.4 1994/09/12 11:32:41 root Exp $
+ * $Id: aha152x.h,v 1.6 1994/11/24 21:35:38 root Exp root $
  */
 
+#if defined(__KERNEL__)
+
 #include "../block/blk.h"
 #include "scsi.h"
-#if defined(__KERNEL__)
 #include <asm/io.h>
 
 int        aha152x_detect(Scsi_Host_Template *);
@@ -22,7 +23,7 @@
    (unless we support more than 1 cmd_per_lun this should do) */
 #define AHA152X_MAXQUEUE	7		
 
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.4 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.6 $"
 
 /* Initial value of Scsi_Host entry */
 #define AHA152X       { /* next */		NULL,			    \
@@ -335,5 +336,26 @@
 
 #define TESTLO(PORT, BITS)	\
 	((inb(PORT) & (BITS)) == 0)
+
+#ifdef DEBUG_AHA152X
+enum {
+        debug_skipports =0x0001,
+        debug_queue     =0x0002,
+        debug_intr      =0x0004,
+        debug_selection =0x0008,
+        debug_msgo      =0x0010,
+        debug_msgi      =0x0020,
+        debug_status    =0x0040,
+        debug_cmd       =0x0080,
+        debug_datai     =0x0100,
+        debug_datao     =0x0200,
+        debug_abort     =0x0400,
+        debug_done      =0x0800,
+        debug_biosparam =0x1000,
+        debug_phases    =0x2000,
+        debug_queues    =0x4000,
+        debug_reset     =0x8000,
+};
+#endif
 
 #endif /* _AHA152X_H */
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v1.1.65/linux/drivers/scsi/eata.c	Tue Nov 22 15:41:12 1994
+++ linux/drivers/scsi/eata.c	Tue Nov 22 15:46:13 1994
@@ -413,7 +413,7 @@
       }
 
    if (k == sh[j]->can_queue) {
-      printk("%s: qcomm, no free mailbox, reseting.\n", BN(j));
+      printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
 
       if (HD(j)->in_reset) 
          printk("%s: qcomm, already in reset.\n", BN(j));
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v1.1.65/linux/drivers/scsi/fdomain.c	Wed Nov  9 14:56:34 1994
+++ linux/drivers/scsi/fdomain.c	Tue Nov 22 15:40:13 1994
@@ -150,7 +150,7 @@
  18C30 chip have a 2k cache).  When this many 512 byte blocks are filled by
  the SCSI device, an interrupt will be raised.  Therefore, this could be as
  low as 0, or as high as 16.  Note, however, that values which are too high
- or too low seem to prevent any interrupts from occuring, and thereby lock
+ or too low seem to prevent any interrupts from occurring, and thereby lock
  up the machine.  I have found that 2 is a good number, but throughput may
  be increased by changing this value to values which are close to 2.
  Please let me know if you try any different values.
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.1.65/linux/drivers/scsi/hosts.c	Fri Nov 18 15:22:09 1994
+++ linux/drivers/scsi/hosts.c	Wed Nov 23 08:47:34 1994
@@ -67,6 +67,10 @@
 #include "pas16.h"
 #endif
 
+#ifdef CONFIG_SCSI_QLOGIC
+#include "qlogic.h"
+#endif
+
 #ifdef CONFIG_SCSI_SEAGATE
 #include "seagate.h"
 #endif
@@ -158,6 +162,9 @@
 #endif
 #ifdef CONFIG_SCSI_GENERIC_NCR5380
         GENERIC_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_QLOGIC
+	QLOGIC,
 #endif
 #ifdef CONFIG_SCSI_PAS16
 	MV_PAS16,
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c
--- v1.1.65/linux/drivers/scsi/in2000.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/in2000.c	Wed Nov 23 08:08:12 1994
@@ -0,0 +1,678 @@
+/*
+ *  This file is in2000.c, written and
+ *  Copyright (C) 1993  Brad McLean
+ *	Last edit 07/19/94 WDE
+ * Disclaimer:
+ * Note:  This is ugly.  I know it, I wrote it, but my whole
+ * focus was on getting the damn thing up and out quickly.
+ * Future stuff that would be nice:  Command chaining, and
+ * a local queue of commands would speed stuff up considerably.
+ * Disconnection needs some supporting code.  All of this
+ * is beyond the scope of what I wanted to address, but if you
+ * have time and patience, more power to you.
+ * Also, there are some constants scattered throughout that
+ * should have defines, and I should have built functions to
+ * address the registers on the WD chip.
+ * Oh well, I'm out of time for this project.
+ * The one good thing to be said is that you can use the card.
+ */
+
+/*
+ * This module was updated by Shaun Savage first on 5-13-93
+ * At that time the write was fixed, irq detection, and some
+ * timing stuff.  since that time other problems were fixed.
+ * On 7-20-93 this file was updated for patch level 11
+ * There are still problems with it but it work on 95% of
+ * the machines.  There are still problems with it working with
+ * IDE drives, as swap drive and HD that support reselection.
+ * But for most people it will work.
+ */
+/* More changes by Bill Earnest, wde@aluxpo.att.com
+ * through 4/07/94. Includes rewrites of FIFO routines,
+ * length-limited commands to make swap partitions work.
+ * Merged the changes released by Larry Doolittle, based on input
+ * from Jon Luckey, Roger Sunshine, John Shifflett. The FAST_FIFO
+ * doesn't work for me. Scatter-gather code from Eric. The change to
+ * an IF stmt. in the interrupt routine finally made it stable.
+ * Limiting swap request size patch to ll_rw_blk.c not needed now.
+ * Please ignore the clutter of debug stmts., pretty can come later.
+ */
+/* Merged code from Matt Postiff improving the auto-sense validation
+ * for all I/O addresses. Some reports of problems still come in, but
+ * have been unable to reproduce or localize the cause. Some are from
+ * LUN > 0 problems, but that is not host specific. Now 6/6/94.
+ */
+/* Changes for 1.1.28 kernel made 7/19/94, code not affected. (WDE)
+ */
+
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <linux/sched.h>
+#include <asm/dma.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "sd.h"
+
+#include "in2000.h"
+
+/*#define FAST_FIFO_IO*/
+
+/*#define DEBUG*/
+#ifdef DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+/* These functions are based on include/asm/io.h */
+#ifndef inw
+inline static unsigned short inw( unsigned short port )
+{
+   unsigned short _v;
+   
+   __asm__ volatile ("inw %1,%0"
+		     :"=a" (_v):"d" ((unsigned short) port));
+   return _v;
+}
+#endif
+
+#ifndef outw
+inline static void outw( unsigned short value, unsigned short port )
+{
+   __asm__ volatile ("outw %0,%1"
+			: /* no outputs */
+			:"a" ((unsigned short) value),
+			"d" ((unsigned short) port));
+}
+#endif
+
+/* These functions are lifted from drivers/block/hd.c */
+
+#define port_read(port,buf,nr) \
+__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di")
+
+#define port_write(port,buf,nr) \
+__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si")
+
+static unsigned int base;
+static unsigned int ficmsk;
+static unsigned char irq_level;
+static int in2000_datalen;
+static unsigned int in2000_nsegment;
+static unsigned int in2000_current_segment;
+static unsigned short *in2000_dataptr;
+static char	in2000_datawrite;
+static struct scatterlist * in2000_scatter;
+static Scsi_Cmnd *in2000_SCptr = 0;
+
+static void (*in2000_done)(Scsi_Cmnd *);
+
+static int in2000_test_port(int index)
+{
+    static const int *bios_tab[] = {
+	(int *) 0xc8000, (int *) 0xd0000, (int *) 0xd8000 };
+    int	i;
+    char    tmp;
+
+    tmp = inb(INFLED);
+	/* First, see if the DIP switch values are valid */
+	/* The test of B7 may fail on some early boards, mine works. */
+    if (((~tmp & 0x3) != index ) || (tmp & 0x80) || !(tmp & 0x4) )
+    	return 0;
+    printk("IN-2000 probe got dip setting of %02X\n", tmp);
+    tmp = inb(INVERS);
+/* Add some extra sanity checks here */
+    for(i=0; i < 3; i++)
+	if(*(bios_tab[i]+0x04) == 0x41564f4e) {
+	  printk("IN-2000 probe found hdw. vers. %02x, BIOS at %06x\n",
+		tmp, (unsigned int)bios_tab[i]);
+		return 1;
+	}
+    printk("in2000 BIOS not found.\n");
+    return 0;
+}
+
+
+/*
+ * retreive the current transaction counter from the WD
+ */
+
+static unsigned in2000_txcnt(void)
+{
+    unsigned total=0;
+
+    if(inb(INSTAT) & 0x20) return 0xffffff;	/* not readable now */
+    outb(TXCNTH,INSTAT);	/* then autoincrement */
+    total =  (inb(INDATA) & 0xff) << 16;
+    outb(TXCNTM,INSTAT);
+    total += (inb(INDATA) & 0xff) << 8;
+    outb(TXCNTL,INSTAT);
+    total += (inb(INDATA) & 0xff);
+    return total;
+}
+
+/*
+ * Note: the FIFO is screwy, and has a counter granularity of 16 bytes, so
+ * we have to reconcile the FIFO counter, the transaction byte count from the
+ * WD chip, and of course, our desired transaction size.  It may look strange,
+ * and could probably use improvement, but it works, for now.
+ */
+
+static void in2000_fifo_out(void)	/* uses FIFOCNTR */
+{
+    unsigned count, infcnt, txcnt;
+
+    infcnt = inb(INFCNT)& 0xfe;	/* FIFO counter */
+    do {
+	txcnt = in2000_txcnt();
+/*DEB(printk("FIw:%d %02x %d\n", in2000_datalen, infcnt, txcnt));*/
+	count = (infcnt << 3) - 32;	/* dont fill completely */
+	if ( count > in2000_datalen )
+	    count = in2000_datalen;	/* limit to actual data on hand */
+	count >>= 1;		/* Words, not bytes */
+#ifdef FAST_FIFO_IO
+	if ( count ) {
+		port_write(INFIFO, in2000_dataptr, count);
+		in2000_datalen -= (count<<1);
+	}
+#else
+	while ( count-- )
+	    {
+		outw(*in2000_dataptr++, INFIFO);
+		in2000_datalen -= 2;
+	    }
+#endif
+    } while((in2000_datalen > 0) && ((infcnt = (inb(INFCNT)) & 0xfe) >= 0x20) );
+    /* If scatter-gather, go on to next segment */
+    if( !in2000_datalen && in2000_current_segment < in2000_nsegment)
+      {
+      in2000_scatter++;
+      in2000_current_segment++;
+      in2000_datalen = in2000_scatter->length;
+      in2000_dataptr = (unsigned short*)in2000_scatter->address;
+      }
+    if ( in2000_datalen <= 0 )
+    {
+	ficmsk = 0;
+	count = 32;	/* Always says to use this much flush */
+	while ( count-- )
+	    outw(0, INFIFO);
+	outb(2, ININTR); /* Mask FIFO Interrupts when done */
+    }
+}
+
+static void in2000_fifo_in(void)	/* uses FIFOCNTR */
+{
+    unsigned fic, count, count2;
+
+    count = inb(INFCNT) & 0xe1;
+    do{
+	count2 = count;
+	count = (fic = inb(INFCNT)) & 0xe1;
+    } while ( count != count2 );
+DEB(printk("FIir:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr));
+    do {
+	count2 = in2000_txcnt();	/* bytes yet to come over SCSI bus */
+DEB(printk("FIr:%d %02x %08x %08x\n", in2000_datalen,fic,count2,(unsigned int)in2000_dataptr));
+	if(count2 > 65536) count2 = 0;
+	if(fic > 128) count = 1024;
+	  else if(fic > 64) count = 512;
+	    else if (fic > 32) count = 256;
+	      else if ( count2 < in2000_datalen ) /* if drive has < what we want */
+	        count = in2000_datalen - count2;	/* FIFO has the rest */
+	if ( count > in2000_datalen )	/* count2 is lesser of FIFO & rqst */
+	    count2 = in2000_datalen >> 1;	/* converted to word count */
+	else
+	    count2 = count >> 1;
+	count >>= 1;		/* also to words */
+	count -= count2;	/* extra left over in FIFO */
+#ifdef FAST_FIFO_IO
+	if ( count2 ) {
+		port_read(INFIFO, in2000_dataptr, count2);
+		in2000_datalen -= (count2<<1);
+	}
+#else
+	while ( count2-- )
+	{
+	    *in2000_dataptr++ = inw(INFIFO);
+	    in2000_datalen -=2;
+	}
+#endif
+    } while((in2000_datalen > 0) && (fic = inb(INFCNT)) );
+DEB(printk("FIer:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr));
+/*    while ( count-- )
+    	inw(INFIFO);*/	/* Throw away some extra stuff */
+    if( !in2000_datalen && in2000_current_segment < in2000_nsegment)
+      {
+      in2000_scatter++;
+      in2000_current_segment++;
+      in2000_datalen = in2000_scatter->length;
+      in2000_dataptr = (unsigned short*)in2000_scatter->address;
+      }
+    if ( ! in2000_datalen ){
+	outb(2, ININTR); /* Mask FIFO Interrupts when done */
+	ficmsk = 0;}
+}
+
+static void in2000_intr_handle(int foo)
+{
+    int result=0;
+    unsigned int count,auxstatus,scsistatus,cmdphase,scsibyte;
+    int action=0;
+    Scsi_Cmnd *SCptr;
+
+  DEB(printk("INT:%d %02x %08x\n", in2000_datalen, inb(INFCNT),(unsigned int)in2000_dataptr));
+
+    if (( (ficmsk & (count = inb(INFCNT))) == 0xfe ) ||
+		( (inb(INSTAT) & 0x8c) == 0x80))
+	{	/* FIFO interrupt or WD interrupt */
+   	auxstatus = inb(INSTAT);	/* need to save now */
+   	outb(SCSIST,INSTAT);
+   	scsistatus = inb(INDATA); /* This clears the WD intrpt bit */
+   	outb(TARGETU,INSTAT);	/* then autoincrement */
+   	scsibyte = inb(INDATA);	/* Get the scsi status byte */
+   	outb(CMDPHAS,INSTAT);
+   	cmdphase = inb(INDATA);
+   	DEB(printk("(int2000:%02x %02x %02x %02x %02x)\n",count,auxstatus,
+		scsistatus,cmdphase,scsibyte));
+
+	/* Why do we assume that we need to send more data here??? ERY */
+   	if ( in2000_datalen && in2000_dataptr )	/* data xfer pending */
+   	    {
+   	    if ( in2000_datawrite )
+		in2000_fifo_out();
+	    else
+		in2000_fifo_in();
+   	    } else ficmsk = 0;
+	if ( (auxstatus & 0x8c) == 0x80 )
+	    {	/* There is a WD Chip interrupt & register read good */
+	    outb(2,ININTR);	/* Disable fifo interrupts */
+	    ficmsk = 0;
+	    result = DID_OK << 16;
+	    /* 16=Select & transfer complete, 85=got disconnect */
+	    if ((scsistatus != 0x16) && (scsistatus != 0x85)
+		&& (scsistatus != 0x42)){
+/*	   	printk("(WDi2000:%02x %02x %02x %02x %02x)\n",count,auxstatus,
+			scsistatus,cmdphase,scsibyte);*/
+/*		printk("QDAT:%d %08x %02x\n",
+		in2000_datalen,(unsigned int)in2000_dataptr,ficmsk);*/
+		;
+	    }
+		switch ( scsistatus & 0xf0 )
+		    {
+		    case	0x00:	/* Card Reset Completed */
+			action = 3;
+			break;
+		    case	0x10:	/* Successful Command Completion */
+			if ( scsistatus & 0x8 )
+		    	    action = 1;
+			break;
+		    case	0x20:	/* Command Paused or Aborted */
+			if ( (scsistatus & 0x8) )
+		    	    action = 1;
+			else if ( (scsistatus & 7) < 2 )
+		    		action = 2;
+			     else
+		    		result = DID_ABORT << 16;
+			break;
+		    case	0x40:	/* Terminated early */
+			if ( scsistatus & 0x8 )
+		     	    action = 1;
+			else if ( (scsistatus & 7) > 2 )
+		     		action = 2;
+			     else
+		    		result = DID_TIME_OUT << 16;
+			break;
+		    case	0x80:	/* Service Required from SCSI bus */
+			if ( scsistatus & 0x8 )
+			    action = 1;
+			else
+			    action = 2;
+			break;
+		    }		/* end switch(scsistatus) */
+		outb(0,INFLED);
+		switch ( action )
+		    {
+		    case	0x02:	/* Issue an abort */
+			outb(COMMAND,INSTAT);
+			outb(1,INDATA); 	/* ABORT COMMAND */
+			result = DID_ABORT << 16;
+		    case	0x00:	/* Basically all done */
+			if ( ! in2000_SCptr )
+			    return;
+			in2000_SCptr->result = result | scsibyte;
+			SCptr = in2000_SCptr;
+			in2000_SCptr = 0;
+			if ( in2000_done )
+		     	    (*in2000_done)(SCptr);
+			break;
+		    case	0x01:	/* We need to reissue a command */
+			outb(CMDPHAS,INSTAT);
+			switch ( scsistatus & 7 )
+			    {
+			    case	0:	/* Data out phase */
+		    	    case	1:	/* Data in phase */
+		    	    case	4:	/* Unspec info out phase */
+		    	    case	5:	/* Unspec info in phase */
+		    	    case	6:	/* Message in phase */
+		    	    case	7:	/* Message in phase */
+				outb(0x41,INDATA); /* rdy to disconn */
+				break;
+		    	    case	2:	/* command phase */
+				outb(0x30,INDATA); /* rdy to send cmd bytes */
+				break;
+		    	    case	3:	/* status phase */
+				outb(0x45,INDATA); /* To go to status phase,*/
+				outb(TXCNTH,INSTAT); /* elim. data, autoinc */
+				outb(0,INDATA);
+				outb(0,INDATA);
+				outb(0,INDATA);
+				in2000_datalen = 0;
+				in2000_dataptr = 0;
+				break;
+			    }	/* end switch(scsistatus) */
+			outb(COMMAND,INSTAT);
+			outb(8,INDATA);	 /* RESTART THE COMMAND */
+			break;
+		    case	0x03:	/* Finish up a Card Reset */
+			outb(TIMEOUT,INSTAT);	/* I got these values */
+						/* by reverse Engineering */
+			outb(IN2000_TMOUT,INDATA); /* the Always' bios. */
+			outb(CONTROL,INSTAT);
+			outb(0,INDATA);
+			outb(SYNCTXR,INSTAT);
+			outb(0x40,INDATA);	/* async, 4 cyc xfer per. */
+			break;
+		    }		/* end switch(action) */
+	    }			/* end if auxstatus for WD int */
+	}			/* end while intrpt active */
+}
+
+static int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+{
+    unchar direction;
+    unchar *cmd = (unchar *) SCpnt->cmnd;
+    unchar target = SCpnt->target;
+    void *buff = SCpnt->request_buffer;
+    int bufflen = SCpnt->request_bufflen;
+    int timeout, size, loop;
+    int i;
+
+    /*
+     * This SCSI command has no data phase, but unfortunately the mid-level
+     * SCSI drivers ask for 256 bytes of data xfer.  Our card hangs if you
+     * do this, so we protect against it here.  It would be nice if the mid-
+     * level could be changed, but who knows if that would break other host
+     * adapter drivers.
+     */
+    if ( *cmd == TEST_UNIT_READY )
+	bufflen = 0;
+
+    /*
+     * What it looks like.  Boy did I get tired of reading it's output.
+     */
+    if (*cmd == READ_10 || *cmd == WRITE_10) {
+	i = xscsi2int((cmd+1));
+    } else if (*cmd == READ_6 || *cmd == WRITE_6) {
+	i = scsi2int((cmd+1));
+    } else {
+	i = -1;
+    }
+#ifdef DEBUG
+    printk("in2000qcmd: pos %d len %d ", i, bufflen);
+    printk("scsi cmd:");
+    for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
+    printk("\n");
+#endif
+    direction = 1;	/* assume for most commands */
+    if (*cmd == WRITE_10 || *cmd == WRITE_6)
+	direction = 0;
+    size = SCpnt->cmd_len;	/* CDB length */ 
+    /*
+     * Setup our current pointers
+     * This is where you would allocate a control structure in a queue,
+     * If you were going to upgrade this to do multiple issue.
+     * Note that datalen and dataptr exist because we can change the
+     * values during the course of the operation, while managing the
+     * FIFO.
+     * Note the nasty little first clause.  In theory, the mid-level
+     * drivers should never hand us more than one command at a time,
+     * but just in case someone gets cute in configuring the driver,
+     * we'll protect them, although not very politely.
+     */
+    if ( in2000_SCptr )
+    {
+	printk("in2000_queue_command waiting for free command block!\n");
+	while ( in2000_SCptr );
+    }
+    for ( timeout = jiffies + 5; timeout > jiffies; )
+    {
+	if ( ! ( inb(INSTAT) & 0xb0 ) )
+	{
+	    timeout = 0;
+	    break;
+	}
+	else
+	{
+	    inb(INSTAT);
+	    outb(SCSIST,INSTAT);
+	    inb(INDATA);
+	    outb(TARGETU,INSTAT); 	/* then autoinc */
+	    inb(INDATA);
+	    inb(INDATA);
+	}
+    }
+    if ( timeout )
+    {
+	printk("in2000_queue_command timeout!\n");
+	SCpnt->result = DID_TIME_OUT << 16;
+	(*done)(SCpnt);
+	return 1;
+    }
+    /* Added for scatter-gather support */
+    in2000_nsegment = SCpnt->use_sg;
+    in2000_current_segment = 0;
+    if(SCpnt->use_sg){
+      in2000_scatter = (struct scatterlist *) buff;
+      in2000_datalen = in2000_scatter->length;
+      in2000_dataptr = (unsigned short*)in2000_scatter->address;
+    } else {
+      in2000_scatter = NULL;
+      in2000_datalen = bufflen;
+      in2000_dataptr = (unsigned short*) buff;
+    };
+    in2000_done = done;
+    in2000_SCptr = SCpnt;
+    /*
+     * Write the CDB to the card, then the LUN, the length, and the target.
+     */
+    outb(TOTSECT, INSTAT);	/* start here then autoincrement */
+    for ( loop=0; loop < size; loop++ )
+	outb(cmd[loop],INDATA);
+    outb(TARGETU,INSTAT);
+    outb(SCpnt->lun & 7,INDATA);
+    SCpnt->host_scribble = NULL;
+    outb(TXCNTH,INSTAT);	/* then autoincrement */
+    outb(bufflen>>16,INDATA);
+    outb(bufflen>>8,INDATA);
+    outb(bufflen,INDATA);
+    outb(target&7,INDATA);
+    /*
+     * Set up the FIFO
+     */
+    cli();		/* so FIFO init waits till WD set */
+    outb(0,INFRST);
+    if ( direction == 1 )
+    {
+	in2000_datawrite = 0;
+	outb(0,INFWRT);
+    }
+    else
+    {
+	in2000_datawrite = 1;
+	for ( loop=16; --loop; ) /* preload the outgoing fifo */
+	    {
+		outw(*in2000_dataptr++,INFIFO);
+		if(in2000_datalen > 0) in2000_datalen-=2;
+	    }
+    }
+    ficmsk = 0xff;
+    /*
+     * Start it up
+     */
+    outb(CONTROL,INSTAT);	/* WD BUS Mode */
+    outb(0x4C,INDATA);
+    if ( in2000_datalen )		/* if data xfer cmd */
+        outb(0,ININTR);		/* Enable FIFO intrpt some boards? */
+    outb(COMMAND,INSTAT);
+    outb(0,INNLED);
+    outb(8,INDATA);		/* Select w/ATN & Transfer */
+    sti();			/* let the intrpt rip */
+    return 0;
+}
+
+static volatile int internal_done_flag = 0;
+static volatile int internal_done_errcode = 0;
+
+static void internal_done(Scsi_Cmnd * SCpnt)
+{
+    internal_done_errcode = SCpnt->result;
+    ++internal_done_flag;
+}
+
+static int in2000_command(Scsi_Cmnd * SCpnt)
+{
+    in2000_queuecommand(SCpnt, internal_done);
+
+    while (!internal_done_flag);
+    internal_done_flag = 0;
+    return internal_done_errcode;
+}
+
+static int in2000_detect(Scsi_Host_Template * tpnt)
+{
+/* Order chosen to reduce conflicts with some multi-port serial boards */
+    int base_tab[] = { 0x220,0x200,0x110,0x100 };
+    int int_tab[] = { 15,14,11,10 };
+    struct Scsi_Host * shpnt;
+    int loop, tmp;
+
+    DEB(printk("in2000_detect: \n"));
+    
+    for ( loop=0; loop < 4; loop++ )
+    {
+	base = base_tab[loop];
+	if ( in2000_test_port(loop))  break;
+    }
+    if ( loop == 4 )
+	return 0;
+
+  /* Read the dip switch values again for miscellaneous checking and
+     informative messages */
+  tmp = inb(INFLED);
+
+  /* Bit 2 tells us if interrupts are disabled */
+  if ( (tmp & 0x4) == 0 ) {
+    printk("The IN-2000 is not configured for interrupt operation\n");
+    printk("Change the DIP switch settings to enable interrupt operation\n");
+  }
+
+  /* Bit 6 tells us about floppy controller */
+  printk("IN-2000 probe found floppy controller on IN-2000 ");
+  if ( (tmp & 0x40) == 0)
+    printk("enabled\n");
+  else
+    printk("disabled\n");
+
+  /* Bit 5 tells us about synch/asynch mode */
+  printk("IN-2000 probe found IN-2000 in ");
+  if ( (tmp & 0x20) == 0)
+    printk("synchronous mode\n");
+  else
+    printk("asynchronous mode\n");
+
+    irq_level = int_tab [ ((~inb(INFLED)>>3)&0x3) ];
+
+    printk("Configuring IN2000 at IO:%x, IRQ %d"
+#ifdef FAST_FIFO_IO
+		" (using fast FIFO I/O code)"
+#endif
+		"\n",base, irq_level);
+
+    outb(2,ININTR);	/* Shut off the FIFO first, so it won't ask for data.*/
+    if (request_irq(irq_level,in2000_intr_handle, 0, "in2000"))
+    {
+	printk("in2000_detect: Unable to allocate IRQ.\n");
+	return 0;
+    }
+    outb(0,INFWRT);	/* read mode so WD can intrpt */
+    outb(SCSIST,INSTAT);
+    inb(INDATA);	/* free status reg, clear WD intrpt */
+    outb(OWNID,INSTAT);
+    outb(0x7,INDATA);	/* we use addr 7 */
+    outb(COMMAND,INSTAT);
+    outb(0,INDATA);	/* do chip reset */
+    shpnt = scsi_register(tpnt, 0);
+    /* Set these up so that we can unload the driver properly. */
+    shpnt->io_port = base;
+    shpnt->n_io_port = 12;
+    shpnt->irq = irq_level;
+    snarf_region(base, 12);  /* Prevent other drivers from using this space */
+    return 1;
+}
+
+static int in2000_abort(Scsi_Cmnd * SCpnt)
+{
+    DEB(printk("in2000_abort\n"));
+    /*
+     * Ask no stupid questions, just order the abort.
+     */
+    outb(COMMAND,INSTAT);
+    outb(1,INDATA);	/* Abort Command */
+    return 0;
+}
+
+static inline void delay( unsigned how_long )
+{
+    unsigned long time = jiffies + how_long;
+    while (jiffies < time) ;
+}
+
+static int in2000_reset(Scsi_Cmnd * SCpnt)
+{
+    DEB(printk("in2000_reset called\n"));
+    /*
+     * Note: this is finished off by an incoming interrupt
+     */
+    outb(0,INFWRT);	/* read mode so WD can intrpt */
+    outb(SCSIST,INSTAT);
+    inb(INDATA);
+    outb(OWNID,INSTAT);
+    outb(0x7,INDATA);	/* ID=7,noadv, no parity, clk div=2 (8-10Mhz clk) */
+    outb(COMMAND,INSTAT);
+    outb(0,INDATA);	/* reset WD chip */
+    delay(2);
+#ifdef SCSI_RESET_PENDING
+    return SCSI_RESET_PENDING;
+#else
+    if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
+    return 0;
+#endif
+}
+
+static int in2000_biosparam(Disk * disk, int dev, int* iinfo)
+	{
+	  int size = disk->capacity;
+    DEB(printk("in2000_biosparam\n"));
+    iinfo[0] = 64;
+    iinfo[1] = 32;
+    iinfo[2] = size >> 11;
+    return 0;
+    }
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h
--- v1.1.65/linux/drivers/scsi/in2000.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/in2000.h	Wed Nov 23 08:08:12 1994
@@ -0,0 +1,124 @@
+#ifndef _IN2000_H
+
+/* $Id: in2000.h,v 1.1 1994/03/14 06:27:38 root Exp root $
+ *
+ * Header file for the Always IN 2000 driver for Linux
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/ioport.h>
+
+/* The IN-2000 is based on a WD33C93 */
+
+#define	INSTAT	(base + 0x0)	/* R: Auxiliary Status; W: register select */
+#define	INDATA	(base + 0x1)	/* R/W: Data port */
+#define	INFIFO	(base + 0x2)	/* R/W FIFO, Word access only */
+#define	INREST	(base + 0x3)	/* W: Reset everything */
+#define	INFCNT	(base + 0x4)	/* R: FIFO byte count */
+#define	INFRST	(base + 0x5)	/* W: Reset Fifo count and to write */
+#define	INFWRT	(base + 0x7)	/* W: Set FIFO to read */
+#define	INFLED	(base + 0x8)	/* W: Set LED; R: Dip Switch settings */
+#define	INNLED	(base + 0x9)	/* W: reset LED */
+#define	INVERS	(base + 0xa)	/* R: Read hw version, end-reset */
+#define	ININTR	(base + 0xc)	/* W: Interrupt Mask Port */
+#define G2CNTRL_HRDY	0x20		/* Sets HOST ready */
+
+/* WD33C93 defines */
+#define	OWNID	0
+#define	CONTROL	1
+#define	TIMEOUT	2
+#define	TOTSECT	3
+#define	TOTHEAD	4
+#define	TOTCYLH 5
+#define	TOTCYLL	6
+#define	LADRSHH	7
+#define	LADRSHL	8
+#define	LADRSLH	9
+#define	LADRSLL	10
+#define	SECTNUM	11
+#define	HEADNUM	12
+#define	CYLNUMH	13
+#define	CYLNUML	14
+#define	TARGETU	15
+#define	CMDPHAS	16
+#define	SYNCTXR	17
+#define	TXCNTH	18
+#define	TXCNTM	19
+#define TXCNTL	20
+#define DESTID	21
+#define	SRCID	22
+#define	SCSIST	23
+#define	COMMAND	24
+#define	WDDATA	25
+#define	AUXSTAT	31
+
+/* OWNID Register Bits */
+#define	OWN_EAF	0x08
+#define	OWN_EHP	0x10
+#define	OWN_FS0	0x40
+#define	OWN_FS1	0x80
+/* AUX Register Bits */
+#define	AUX_DBR	0
+#define	AUX_PE	1
+#define	AUX_CIP	0x10
+#define	AUX_BSY	0x20
+#define	AUX_LCI	0x40
+#define	AUX_INT	0x80
+
+/* Select timeout const, 1 count = 8ms */
+#define IN2000_TMOUT 0x1f
+
+#if 0
+/* This is used with scatter-gather */
+struct in2000_chain {
+  ulong  dataptr;		/* Location of data */
+  ulong  datalen;		/* Size of this part of chain */
+};
+#endif
+
+/* These belong in scsi.h also */
+#define any2scsi(up, p)				\
+(up)[0] = (((unsigned long)(p)) >> 16);		\
+(up)[1] = (((unsigned long)(p)) >> 8);		\
+(up)[2] = ((unsigned long)(p));
+
+#define scsi2int(up) ( ((((long)*(up))&0x1f) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) )
+
+#define xany2scsi(up, p)	\
+(up)[0] = ((long)(p)) >> 24;	\
+(up)[1] = ((long)(p)) >> 16;	\
+(up)[2] = ((long)(p)) >> 8;	\
+(up)[3] = ((long)(p));
+
+#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \
+		      + (((long)(up)[2]) <<  8) +  ((long)(up)[3]) )
+
+#define MAX_CDB 12
+#define MAX_SENSE 14
+#define MAX_STATUS 32
+
+static int in2000_detect(Scsi_Host_Template *);
+static int in2000_command(Scsi_Cmnd *);
+static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int in2000_abort(Scsi_Cmnd *);
+static int in2000_reset(Scsi_Cmnd *);
+static int in2000_biosparam(Disk *, int, int*);
+
+
+#ifndef NULL
+	#define NULL 0
+#endif
+
+/* next may be "SG_NONE" or "SG_ALL" or nr. of (1k) blocks per R/W Cmd. */
+#define IN2000_SG SG_ALL
+#define IN2000 {NULL, "Always IN2000", in2000_detect, NULL,	\
+		NULL, in2000_command,		\
+		in2000_queuecommand,		\
+		in2000_abort,			\
+		in2000_reset,			\
+	        NULL,		                \
+		in2000_biosparam,               \
+		1, 7, IN2000_SG, 1, 0, 0}
+
+#endif
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/qlogic.c linux/drivers/scsi/qlogic.c
--- v1.1.65/linux/drivers/scsi/qlogic.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogic.c	Wed Nov 23 08:47:34 1994
@@ -0,0 +1,564 @@
+/*----------------------------------------------------------------*/
+/*
+   Qlogic linux driver - work in progress. No Warranty express or implied.
+   Use at your own risk.  Support Tort Reform so you won't have to read all
+   these silly disclaimers.
+
+   Copyright 1994, Tom Zerucha.
+   zerucha@shell.portal.com
+
+   Additional Code, and much appreciated help by
+   Michael A. Griffith
+   grif@cs.ucr.edu
+
+   Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
+   (you can reference it, but it is incomplete and inaccurate in places)
+
+   Version 0.37
+   Redistributable under terms of the GNU Public License
+
+*/
+/*----------------------------------------------------------------*/
+/* Configuration */
+
+/* Set the following to 1 to enable the use of interrupts.  Note that 0 tends
+   to be more stable, but slower (or ties up the system more) */
+#define QL_USE_IRQ 1
+
+/* Set the following to max out the speed of the PIO PseudoDMA transfers,
+   again, 0 tends to be slower, but more stable */
+#define QL_TURBO_PDMA 1
+
+/* This will reset all devices when the driver is initialized (during bootup).
+   The other linux drivers don't do this, but the DOS drivers do, and after
+   using DOS or some kind of crash or lockup this will bring things back */
+#define QL_RESET_AT_START 1
+
+/* This will set fast (10Mhz) synchronous timing, FASTCLK must also be 1*/
+#define FASTSCSI  0
+
+/* This will set a faster sync transfer rate */
+#define FASTCLK   0
+
+/* This bit needs to be set to 1 if your cabling is long or noisy */
+#define SLOWCABLE 0
+
+/* This is the sync transfer divisor, 40Mhz/X will be the data rate
+	The power on default is 5, the maximum normal value is 5 */
+#define SYNCXFRPD 4
+
+/* This is the count of how many synchronous transfers can take place
+	i.e. how many reqs can occur before an ack is given.
+	The maximum value for this is 15, the upper bits can modify
+	REQ/ACK assertion and deassertion during synchronous transfers
+	If this is 0, the bus will only transfer asynchronously */
+#define SYNCOFFST 0
+/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
+	of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
+	cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
+	the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
+
+/*----------------------------------------------------------------*/
+
+#include <linux/config.h>
+#include "../block/blk.h"	/* to get disk capacity */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <unistd.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include "sd.h"
+#include "hosts.h"
+#include "qlogic.h"
+
+/*----------------------------------------------------------------*/
+/* driver state info, local to driver */
+static int	    qbase;	/* Port */
+static int	    qinitid;	/* initiator ID */
+static int	    qabort;	/* Flag to cause an abort */
+static int	    qlirq;	/* IRQ being used */
+static char	    qinfo[80];	/* description */
+static Scsi_Cmnd   *qlcmd;	/* current command being processed */
+
+/*----------------------------------------------------------------*/
+
+#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
+#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb6 , qbase + 0xd ))
+
+/* following is watchdog timeout - 0 is longest possible */
+#define WATCHDOG 5000000
+
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+   where something crashed or gets stuck at and as a simple profiler) */
+
+#if 0
+#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
+#else
+#define rtrc(i) {}
+#endif
+
+/*----------------------------------------------------------------*/
+/* local functions */
+/*----------------------------------------------------------------*/
+static void	ql_zap(void);
+/* error recovery - reset everything */
+void	ql_zap()
+{
+int	x;
+	cli();
+	x = inb(qbase + 0xd);
+	REG0;
+	outb(3, qbase + 3);				/* reset SCSI */
+	outb(2, qbase + 3);				/* reset chip */
+	if (x & 0x80)
+		REG1;
+	sti();
+}
+
+/*----------------------------------------------------------------*/
+/* do pseudo-dma */
+static int	ql_pdma(int phase, char *request, int reqlen)
+{
+int	j;
+	j = 0;
+	if (phase & 1) {	/* in */
+#if QL_TURBO_PDMA
+		/* empty fifo in large chunks */
+		if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) { /* full */
+			insl( qbase + 4, request, 32 );
+			reqlen -= 128;
+			request += 128;
+		}
+		while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */
+			if( (j=inb( qbase + 8 )) & 4 ) {
+				insl( qbase + 4, request, 21 );
+				reqlen -= 84;
+				request += 84;
+			}
+		if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) {	/* 1/3 */
+			insl( qbase + 4, request, 11 );
+			reqlen -= 44;
+			request += 44;
+		}
+#endif
+		/* until both empty and int (or until reclen is 0) */
+		j = 0;
+		while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) {
+			/* while bytes to receive and not empty */
+			j &= 0xc0;
+			while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) {
+				*request++ = inb(qbase + 4);
+				reqlen--;
+			}
+			if( j & 0x10 )
+				j = inb(qbase+8);
+
+		}
+	}
+	else {	/* out */
+#if QL_TURBO_PDMA
+		if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) { /* empty */
+			outsl(qbase + 4, request, 32 );
+			reqlen -= 128;
+			request += 128;
+		}
+		while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */
+			if( !((j=inb( qbase + 8 )) & 8) ) {
+				outsl( qbase + 4, request, 21 );
+				reqlen -= 84;
+				request += 84;
+			}
+		if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) { /* 2/3 */
+			outsl( qbase + 4, request, 10 );
+			reqlen -= 40;
+			request += 40;
+		}
+#endif
+		/* until full and int (or until reclen is 0) */
+		j = 0;
+		while( reqlen && !( (j & 2) && (j & 0xc0) ) ) {
+			/* while bytes to send and not full */
+			while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) {
+				outb(*request++, qbase + 4);
+				reqlen--;
+			}
+			if( j & 2 )
+				j = inb(qbase+8);
+		}
+	}
+/* maybe return reqlen */
+	return inb( qbase + 8 ) & 0xc0;
+}
+
+/*----------------------------------------------------------------*/
+/* wait for interrupt flag (polled - not real hardware interrupt) */
+static int	ql_wai(void)
+{
+int	i,k;
+	i = WATCHDOG;
+	while (--i && !qabort && !((k = inb(qbase + 4)) & 0xe0));
+	if (!i)
+		return (DID_TIME_OUT);
+	if (qabort)
+		return (qabort == 1 ? DID_ABORT : DID_RESET);
+	if (k & 0x60)
+		ql_zap();
+	if (k & 0x20)
+		return (DID_PARITY);
+	if (k & 0x40)
+		return (DID_ERROR);
+	return 0;
+}
+
+/*----------------------------------------------------------------*/
+/* initate scsi command - queueing handler */
+static void	ql_icmd(Scsi_Cmnd * cmd)
+{
+unsigned int	    i;
+	qabort = 0;
+
+	cli();
+	REG0;
+/* clearing of interrupts and the fifo is needed */
+	inb(qbase + 5); 			/* clear interrupts */
+	if (inb(qbase + 5))			/* if still interrupting */
+		outb(2, qbase + 3);		/* reset chip */
+	else if (inb(qbase + 7) & 0x1f)
+		outb(1, qbase + 3);		/* clear fifo */
+	while (inb(qbase + 5)); 		/* clear ints */
+	REG1;
+	outb(1, qbase + 8);			/* set for PIO pseudo DMA */
+	outb(0, qbase + 0xb);			/* disable ints */
+	inb(qbase + 8); 			/* clear int bits */
+	REG0;
+	outb(0x40, qbase + 0xb);		/* enable features */
+
+/* configurables */
+#if FASTSCSI
+#if FASTCLK
+	outb(0x18, qbase + 0xc);
+#else
+	outb(0x10, qbase + 0xc);
+#endif
+#else
+#if FASTCLK
+	outb(8, qbase + 0xc);
+#endif
+#endif
+
+#if SLOWCABLE
+	outb(0xd0 | qinitid, qbase + 8);	/* (initiator) bus id */
+#else
+	outb(0x50 | qinitid, qbase + 8);	/* (initiator) bus id */
+#endif
+	outb( SYNCOFFST , qbase + 7 );
+	outb( SYNCXFRPD , qbase + 6 );
+/**/
+	outb(0x99, qbase + 5);	/* timer */
+	outb(cmd->target, qbase + 4);
+
+	for (i = 0; i < COMMAND_SIZE(cmd->cmnd[0]); i++)
+		outb(cmd->cmnd[i], qbase + 2);
+	qlcmd = cmd;
+	outb(0x41, qbase + 3);	/* select and send command */
+	sti();
+}
+/*----------------------------------------------------------------*/
+/* process scsi command - usually after interrupt */
+static unsigned int	ql_pcmd(Scsi_Cmnd * cmd)
+{
+unsigned int	i, j, k;
+unsigned int	result; 		/* ultimate return result */
+unsigned int	status; 		/* scsi returned status */
+unsigned int	message;		/* scsi returned message */
+unsigned int	phase;			/* recorded scsi phase */
+unsigned int	reqlen; 		/* total length of transfer */
+struct scatterlist	*sglist;	/* scatter-gather list pointer */
+unsigned int	sgcount;		/* sg counter */
+
+	j = inb(qbase + 6);
+	i = inb(qbase + 5);
+	if (i == 0x20) {
+		return (DID_NO_CONNECT << 16);
+	}
+	i |= inb(qbase + 5);	/* the 0x10 bit can be set after the 0x08 */
+	if (i != 0x18) {
+		printk("Ql:Bad Interrupt status:%02x\n", i);
+		ql_zap();
+		return (DID_BAD_INTR << 16);
+	}
+	j &= 7; /* j = inb( qbase + 7 ) >> 5; */
+/* correct status is supposed to be step 4 */
+/* it sometimes returns step 3 but with 0 bytes left to send */
+	if (j != 4 && (j != 3 || inb(qbase + 7) & 0x1f)) {
+		printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f );
+		ql_zap();
+		return (DID_ERROR << 16);
+	}
+	result = DID_OK;
+	if (inb(qbase + 7) & 0x1f)	/* if some bytes in fifo */
+		outb(1, qbase + 3);		/* clear fifo */
+/* note that request_bufflen is the total xfer size when sg is used */
+	reqlen = cmd->request_bufflen;
+/* note that it won't work if transfers > 16M are requested */
+	if (reqlen && !((phase = inb(qbase + 4)) & 6)) {	/* data phase */
+rtrc(1)
+		outb(reqlen, qbase);			/* low-mid xfer cnt */
+		outb(reqlen >> 8, qbase+1);			/* low-mid xfer cnt */
+		outb(reqlen >> 16, qbase + 0xe);	/* high xfer cnt */
+		outb(0x90, qbase + 3);			/* command do xfer */
+/* PIO pseudo DMA to buffer or sglist */
+		REG1;
+		if (!cmd->use_sg)
+			ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen);
+		else {
+			sgcount = cmd->use_sg;
+			sglist = cmd->request_buffer;
+			while (sgcount--) {
+				if (qabort) {
+					REG0;
+					return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+				}
+				if (ql_pdma(phase, sglist->address, sglist->length))
+					break;
+				sglist++;
+			}
+		}
+		REG0;
+rtrc(2)
+/* wait for irq (split into second state of irq handler if this can take time) */
+		if ((k = ql_wai()))
+			return (k << 16);
+		k = inb(qbase + 5);	/* should be 0x10, bus service */
+	}
+/*** Enter Status (and Message In) Phase ***/
+	k = WATCHDOG;
+rtrc(4)
+	while (--k && !qabort && !(inb(qbase + 4) & 6));	/* wait for status phase */
+	if (!k) {
+		ql_zap();
+		return (DID_TIME_OUT << 16);
+	}
+	while (inb(qbase + 5)); 				/* clear pending ints */
+	if (qabort)
+		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+	outb(0x11, qbase + 3);					/* get status and message */
+	if ((k = ql_wai()))
+		return (k << 16);
+	i = inb(qbase + 5);					/* get chip irq stat */
+	j = inb(qbase + 7) & 0x1f;				/* and bytes rec'd */
+	status = inb(qbase + 2);
+	message = inb(qbase + 2);
+/* should get function complete int if Status and message, else bus serv if only status */
+	if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
+		printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
+		result = DID_ERROR;
+	}
+	outb(0x12, qbase + 3);	/* done, disconnect */
+rtrc(3)
+	if ((k = ql_wai()))
+		return (k << 16);
+/* should get bus service interrupt and disconnect interrupt */
+	i = inb(qbase + 5);	/* should be bus service */
+	while (!qabort && ((i & 0x20) != 0x20))
+		i |= inb(qbase + 5);
+rtrc(0)
+	if (qabort)
+		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+	return (result << 16) | (message << 8) | (status & STATUS_MASK);
+}
+
+#if QL_USE_IRQ
+/*----------------------------------------------------------------*/
+/* interrupt handler */
+static void		    ql_ihandl(int irq)
+{
+Scsi_Cmnd	   *icmd;
+	REG0;
+	if (!(inb(qbase + 4) & 0x80))	/* false alarm? */
+		return;
+	if (qlcmd == NULL) {		/* no command to process? */
+		while (inb(qbase + 5)); /* maybe also ql_zap() */
+		return;
+	}
+	icmd = qlcmd;
+	icmd->result = ql_pcmd(icmd);
+	qlcmd = NULL;
+/* if result is CHECK CONDITION done calls qcommand to request sense */
+	(icmd->scsi_done) (icmd);
+}
+#endif
+
+/*----------------------------------------------------------------*/
+/* global functions */
+/*----------------------------------------------------------------*/
+/* non queued command */
+#if QL_USE_IRQ
+static void	qlidone(Scsi_Cmnd * cmd) {};		/* null function */
+#endif
+
+/* command process */
+int	qlogic_command(Scsi_Cmnd * cmd)
+{
+int	k;
+#if QL_USE_IRQ
+	if (qlirq >= 0) {
+		qlogic_queuecommand(cmd, qlidone);
+		while (qlcmd != NULL);
+		return cmd->result;
+	}
+#endif
+/* non-irq version */
+	if (cmd->target == qinitid)
+		return (DID_BAD_TARGET << 16);
+	ql_icmd(cmd);
+	if ((k = ql_wai()))
+		return (k << 16);
+	return ql_pcmd(cmd);
+
+}
+
+#if QL_USE_IRQ
+/*----------------------------------------------------------------*/
+/* queued command */
+int	qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+	if(cmd->target == qinitid) {
+		cmd->result = DID_BAD_TARGET << 16;
+		done(cmd);
+		return 0;
+	}
+
+	cmd->scsi_done = done;
+/* wait for the last command's interrupt to finish */
+	while (qlcmd != NULL);
+	ql_icmd(cmd);
+	return 0;
+}
+#else
+int	qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+	return 1;
+}
+#endif
+
+/*----------------------------------------------------------------*/
+/* look for qlogic card and init if found */
+int	qlogic_detect(Scsi_Host_Template * host)
+{
+int	i, j;			/* these are only used by IRQ detect */
+int	qltyp;			/* type of chip */
+struct	Scsi_Host	*hreg;	/* registered host structure */
+
+/* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the
+   address - I check 230 first since MIDI cards are typically at 330
+   Note that this will not work for 2 Qlogic cards in 1 system.  The
+   easiest way to do that is to create 2 versions of this file, one for
+   230 and one for 330.
+
+   Alternately, the Scsi_Host structure now stores the i/o port and can
+   be used to set the port (go through and replace qbase with
+   (struct Scsi_Cmnd *) cmd->host->io_port, or for efficiency, set a local
+   copy of qbase.  There will also need to be something similar within the
+   IRQ handlers to sort out which board it came from and thus which port.
+*/
+
+	for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
+		REG1;
+		if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
+		  && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
+			break;
+	}
+	if (qbase == 0x430)
+		return 0;
+
+	qltyp = inb(qbase + 0xe) & 0xf8;
+	qinitid = host->this_id;
+	if (qinitid < 0)
+		qinitid = 7;			/* if no ID, use 7 */
+	outb(1, qbase + 8);			/* set for PIO pseudo DMA */
+	REG0;
+	outb(0xd0 | qinitid, qbase + 8);	/* (ini) bus id, disable scsi rst */
+	outb(0x99, qbase + 5);			/* select timer */
+	qlirq = -1;
+#if QL_RESET_AT_START
+	outb( 3 , qbase + 3 );
+	REG1;
+	while( inb( qbase + 0xf ) & 4 );
+	REG0;
+#endif
+#if QL_USE_IRQ
+/* IRQ probe - toggle pin and check request pending */
+	cli();
+	i = 0xffff;
+	j = 3;
+	outb(0x90, qbase + 3);	/* illegal command - cause interrupt */
+	REG1;
+	outb(10, 0x20); /* access pending interrupt map */
+	outb(10, 0xa0);
+	while (j--) {
+		outb(0xb2, qbase + 0xd);		/* int pin off */
+		i &= ~(inb(0x20) | (inb(0xa0) << 8));	/* find IRQ off */
+		outb(0xb6, qbase + 0xd);		/* int pin on */
+		i &= inb(0x20) | (inb(0xa0) << 8);	/* find IRQ on */
+	}
+	REG0;
+	while (inb(qbase + 5)); 			/* purge int */
+	while (i)					/* find on bit */
+		i >>= 1, qlirq++;	/* should check for exactly 1 on */
+	if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogic"))
+		host->can_queue = 1;
+	sti();
+#endif
+	hreg = scsi_register( host , 0 );	/* no host data */
+	hreg->io_port = qbase;
+	hreg->irq = qlirq;
+
+	sprintf(qinfo, "Qlogic Driver version 0.36, chip %02X at %03X, IRQ %d", qltyp, qbase, qlirq);
+	host->name = qinfo;
+	return 1;
+}
+
+/*----------------------------------------------------------------*/
+/* return bios parameters */
+int	qlogic_biosparam(Disk * disk, int dev, int ip[])
+{
+/* This should mimmic the DOS Qlogic driver's behavior exactly */
+	ip[0] = 0x40;
+	ip[1] = 0x20;
+	ip[2] = disk->capacity / (ip[0] * ip[1]);
+	if (ip[2] > 1024) {
+		ip[0] = 0xff;
+		ip[1] = 0x3f;
+		ip[2] = disk->capacity / (ip[0] * ip[1]);
+		if (ip[2] > 1023)
+			ip[2] = 1023;
+	}
+	return 0;
+}
+
+/*----------------------------------------------------------------*/
+/* abort command in progress */
+int	qlogic_abort(Scsi_Cmnd * cmd)
+{
+	qabort = 1;
+	ql_zap();
+	return 0;
+}
+
+/*----------------------------------------------------------------*/
+/* reset SCSI bus */
+int	qlogic_reset(Scsi_Cmnd * cmd)
+{
+	qabort = 2;
+	ql_zap();
+	return 1;
+}
+
+/*----------------------------------------------------------------*/
+/* return info string */
+const char	*qlogic_info()
+{
+	return qinfo;
+}
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/qlogic.h linux/drivers/scsi/qlogic.h
--- v1.1.65/linux/drivers/scsi/qlogic.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogic.h	Wed Nov 23 08:47:34 1994
@@ -0,0 +1,37 @@
+#ifndef _QLOGIC_H
+#define _QLOGIC_H
+
+int qlogic_detect(Scsi_Host_Template * );
+const char * qlogic_info(void);
+int qlogic_command(Scsi_Cmnd *);
+int qlogic_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+int qlogic_abort(Scsi_Cmnd *);
+int qlogic_reset(Scsi_Cmnd *);
+int qlogic_biosparam(Disk *,int,int[]);
+
+#ifndef NULL
+#define NULL (0)
+#endif
+
+#define QLOGIC {		\
+	NULL,			\
+	NULL,			\
+	qlogic_detect,		\
+	NULL,			\
+	qlogic_info,		\
+	qlogic_command, 	\
+	qlogic_queuecommand,	\
+	qlogic_abort,		\
+	qlogic_reset,		\
+	NULL,			\
+	qlogic_biosparam,	\
+	0,			\
+	-1,			\
+	SG_ALL,			\
+	1,			\
+	0,			\
+	0,			\
+	DISABLE_CLUSTERING	\
+}
+
+#endif /* _QLOGIC_H */
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.1.65/linux/drivers/scsi/scsi.c	Tue Nov 15 15:35:40 1994
+++ linux/drivers/scsi/scsi.c	Thu Nov 24 14:18:33 1994
@@ -346,6 +346,13 @@
 			scsi_result[0] = TYPE_ROM;
 			scsi_result[1] |= 0x80;  /* removable */
 		}
+
+	      SDpnt->manufactor = SCSI_MAN_UNKNOWN;
+	      if (!strncmp(scsi_result+8,"NEC",3))
+		SDpnt->manufactor = SCSI_MAN_NEC;
+	      if (!strncmp(scsi_result+8,"TOSHIBA",7))
+		SDpnt->manufactor = SCSI_MAN_TOSHIBA;
+
 	      SDpnt->removable = (0x80 & 
 				  scsi_result[1]) >> 7;
 	      SDpnt->lockable = SDpnt->removable;
@@ -532,7 +539,7 @@
 			if (!scsi_abort	(SCpnt, DID_TIME_OUT))
 				return;				
 		case IN_ABORT:
-			printk("SCSI host %d abort() timed out - reseting\n",
+			printk("SCSI host %d abort() timed out - resetting\n",
 				SCpnt->host->host_no);
 			if (!scsi_reset (SCpnt)) 
 				return;
@@ -1297,7 +1304,7 @@
 			if ((SCpnt->retries >= (SCpnt->allowed >> 1))
 			    && !(SCpnt->flags & WAS_RESET))
 			        {
-					printk("scsi%d : reseting for second half of retries.\n",
+					printk("scsi%d : resetting for second half of retries.\n",
 						SCpnt->host->host_no);
 					reset(SCpnt);
 					break;
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.1.65/linux/drivers/scsi/scsi.h	Wed Oct 12 14:57:29 1994
+++ linux/drivers/scsi/scsi.h	Thu Nov 24 14:18:33 1994
@@ -183,7 +183,7 @@
 #define DRIVER_OK		0x00
 
 /*
-	These indicate the error that occured, and what is available.
+	These indicate the error that occurred, and what is available.
 */
 
 #define DRIVER_BUSY		0x01
@@ -259,6 +259,13 @@
 	as the LUN.
 */
 
+/*
+        Manufactors list
+*/
+
+#define SCSI_MAN_UNKNOWN     0
+#define SCSI_MAN_NEC         1
+#define SCSI_MAN_TOSHIBA     2
 
 /*
 	The scsi_device struct contains what we know about each given scsi
@@ -268,6 +275,7 @@
 typedef struct scsi_device {
         struct scsi_device * next; /* Used for linked list */
 	unsigned char id, lun;
+	unsigned int manufactor; /* Manufactor of device, for using vendor-specific cmd's */
 	int attached;          /* # of high level drivers attached to this */
 	int access_count;	/* Count of open channels/mounts */
 	struct wait_queue * device_wait;  /* Used to wait if device is busy */
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.1.65/linux/drivers/scsi/sr.c	Wed Oct 12 14:57:30 1994
+++ linux/drivers/scsi/sr.c	Thu Nov 24 14:18:33 1994
@@ -271,6 +271,122 @@
   }
 }
 
+/*
+ * Here I tried to implement better support for PhotoCD's.
+ * 
+ * Much of this has do be done with vendor-specific SCSI-commands.
+ * So I have to complete it step by step. Useful information is welcome.
+ *
+ * Actually works: (should work ;-)
+ *   - NEC:     Detection and support of multisession CD's. Special handling
+ *              for XA-disks is not nessesary.
+ *     
+ *   - TOSHIBA: setting density is done here now, mounting PhotoCD's should
+ *              work now without running the program "set_density"
+ *              multisession-CD's are supported too.
+ *
+ *   Gerd Knorr  (mailto:kraxel@cs.tu-berlin.de,
+ *                http://www.cs.tu-berlin.de/~kraxel/)
+ */
+
+static void sr_photocd_done(Scsi_Cmnd *SCpnt)
+{
+  SCpnt->request.dev = 0xfffe;
+}
+
+static void sr_photocd(struct inode *inode)
+{
+  unsigned long   sector,min,sec,frame;
+  Scsi_Cmnd       *SCpnt;
+  unsigned char   scsi_cmd[10];
+  unsigned char   *buffer;
+  int             rc;
+
+  switch(scsi_CDs[MINOR(inode->i_rdev)].device->manufactor) {
+
+  case SCSI_MAN_NEC:
+    printk("sr_photocd: use NEC code\n");
+    SCpnt = allocate_device(NULL, scsi_CDs[MINOR(inode->i_rdev)].device,1);
+    memset(scsi_cmd,0,10);
+    scsi_cmd[0] = 0xde;
+    scsi_cmd[1] = ((scsi_CDs[MINOR(inode->i_rdev)].device->lun) << 5) | 0x03;
+    scsi_cmd[2] = 0xb0;
+    buffer = (unsigned char*) scsi_malloc(512);
+    scsi_do_cmd(SCpnt, scsi_cmd, buffer, 0x16,
+		sr_photocd_done, SR_TIMEOUT, MAX_RETRIES);
+    while (SCpnt->request.dev != 0xfffe);
+    rc = SCpnt->result;
+    if (driver_byte(rc) != 0) {
+      printk("sr_photocd: oops, CD-ROM reports an error.\n");
+      sector = 0; }
+    else {
+      min   = (unsigned long)buffer[15]/16*10 + (unsigned long)buffer[15]%16;
+      sec   = (unsigned long)buffer[16]/16*10 + (unsigned long)buffer[16]%16;
+      frame = (unsigned long)buffer[17]/16*10 + (unsigned long)buffer[17]%16;
+      sector = min*60*75 + sec*75 + frame;
+      if (sector) {
+	printk("sr_photocd: multisession PhotoCD detected\n"); }}
+    scsi_free(buffer,512);
+    SCpnt->request.dev = -1;
+    break;
+
+  case SCSI_MAN_TOSHIBA:
+    printk("sr_photocd: use TOSHIBA code\n");
+
+    /* first I do a set_density-call (for reading XA-sectors) ... */
+    SCpnt = allocate_device(NULL, scsi_CDs[MINOR(inode->i_rdev)].device,1);
+    memset(scsi_cmd,0,10);
+    scsi_cmd[0] = 0x15;
+    scsi_cmd[1] = ((scsi_CDs[MINOR(inode->i_rdev)].device->lun) << 5)|(1 << 4);
+    scsi_cmd[4] = 12;
+    buffer = (unsigned char*) scsi_malloc(512);
+    memset(buffer,0,512);
+    buffer[ 3] = 0x08;
+    buffer[ 4] = 0x83;
+    buffer[10] = 0x08;
+    scsi_do_cmd(SCpnt, scsi_cmd, buffer, 12,
+                sr_photocd_done, SR_TIMEOUT, MAX_RETRIES);
+    while (SCpnt->request.dev != 0xfffe);
+    rc = SCpnt->result;
+    if (driver_byte(rc) != 0) {
+      printk("sr_photocd: oops, CD-ROM reports an error.\n"); }
+    scsi_free(buffer,512);
+    SCpnt->request.dev = -1;
+
+    /* ... and then I ask, if there is a multisession-Disk */
+    SCpnt = allocate_device(NULL, scsi_CDs[MINOR(inode->i_rdev)].device,1);
+    memset(scsi_cmd,0,10);
+    scsi_cmd[0] = 0xc7;
+    scsi_cmd[1] = ((scsi_CDs[MINOR(inode->i_rdev)].device->lun) << 5) | 3;
+    buffer = (unsigned char*) scsi_malloc(512);
+    memset(buffer,0,512);
+    scsi_do_cmd(SCpnt, scsi_cmd, buffer, 4,
+                sr_photocd_done, SR_TIMEOUT, MAX_RETRIES);
+    while (SCpnt->request.dev != 0xfffe);
+    rc = SCpnt->result;
+    if (driver_byte(rc) != 0) {
+      printk("sr_photocd: oops, CD-ROM reports an error.\n");
+      sector = 0; }
+    else {
+      min   = (unsigned long)buffer[1]/16*10 + (unsigned long)buffer[1]%16;
+      sec   = (unsigned long)buffer[2]/16*10 + (unsigned long)buffer[2]%16;
+      frame = (unsigned long)buffer[3]/16*10 + (unsigned long)buffer[3]%16;
+      sector = min*60*75 + sec*75 + frame;
+      if (sector) {
+        printk("sr_photocd: multisession PhotoCD detected: %lu\n",sector); }}
+    scsi_free(buffer,512);
+    SCpnt->request.dev = -1;
+    break;
+  case SCSI_MAN_UNKNOWN:
+  default:
+    printk("sr_photocd: there is no special photocd-code for this drive\n");
+    sector = 0;
+    break; }
+
+  scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
+  return;
+}
+
 static int sr_open(struct inode * inode, struct file * filp)
 {
 	if(MINOR(inode->i_rdev) >= sr_template.nr_dev || 
@@ -292,6 +408,8 @@
 	if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)
 	  get_sectorsize(MINOR(inode->i_rdev));
 
+	sr_photocd(inode);
+
 	return 0;
 }
 
@@ -436,6 +554,10 @@
 work around the fact that the buffer cache has a block size of 1024,
 and we have 2048 byte sectors.  This code should work for buffers that
 are any multiple of 512 bytes long.  */
+
+	/* this is for support of multisession-CD's */ 
+	if (block >= 64 && block < 68) {
+	  block += scsi_CDs[dev].mpcd_sector*4; }
 
 	SCpnt->use_sg = 0;
 
diff -u --recursive --new-file v1.1.65/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- v1.1.65/linux/drivers/scsi/sr.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/sr.h	Thu Nov 24 14:18:34 1994
@@ -24,6 +24,7 @@
 	unsigned 	capacity;		/* size in blocks 			*/
 	unsigned 	sector_size;		/* size in bytes 			*/
 	Scsi_Device  	*device;		
+	unsigned long   mpcd_sector;            /* for reading multisession-CD's        */
 	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.65/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v1.1.65/linux/drivers/scsi/u14-34f.c	Fri Nov 18 15:22:09 1994
+++ linux/drivers/scsi/u14-34f.c	Tue Nov 22 15:46:13 1994
@@ -463,7 +463,7 @@
       }
 
    if (k == sh[j]->can_queue) {
-      printk("%s: qcomm, no free mailbox, reseting.\n", BN(j));
+      printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
 
       if (HD(j)->in_reset) 
          printk("%s: qcomm, already in reset.\n", BN(j));
diff -u --recursive --new-file v1.1.65/linux/fs/isofs/file.c linux/fs/isofs/file.c
--- v1.1.65/linux/fs/isofs/file.c	Tue Nov 15 15:35:40 1994
+++ linux/fs/isofs/file.c	Wed Nov 23 08:47:34 1994
@@ -119,7 +119,7 @@
 static int isofs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
 {
 	int read,left,chars;
-	int block, blocks, offset;
+	int block, blocks, offset, total_blocks;
 	int bhrequest;
 	int ra_blocks, max_block, nextblock;
 	struct buffer_head ** bhb, ** bhe;
@@ -153,6 +153,17 @@
 
 	ra_blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 	if(ra_blocks > blocks) blocks = ra_blocks;
+
+	/*
+	 * this is for stopping read ahead at EOF. It's  important for
+	 * reading PhotoCD's, becauce they have many small data tracks instead
+	 * of one big. And between two data-tracks are some unreadable sectors.
+	 * A read ahead after a EOF may try to read such an unreadable sector.
+	 *    kraxel@cs.tu-berlin.de (Gerd Knorr)
+	 */
+	total_blocks = inode->i_size >> ISOFS_BUFFER_BITS(inode);
+	if (inode->i_size & (ISOFS_BUFFER_BITS(inode)-1)) total_blocks++;
+	while (block + blocks > total_blocks) blocks--;
 
 	max_block = (inode->i_size + BLOCK_SIZE - 1)/BLOCK_SIZE;
 	nextblock = -1;
diff -u --recursive --new-file v1.1.65/linux/fs/super.c linux/fs/super.c
--- v1.1.65/linux/fs/super.c	Thu Oct  6 08:45:21 1994
+++ linux/fs/super.c	Fri Nov 25 10:43:58 1994
@@ -641,10 +641,12 @@
 
 	memset(super_blocks, 0, sizeof(super_blocks));
 	fcntl_init_locks();
+#ifdef CONFIG_BLK_DEV_FD
 	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
 		printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
 		wait_for_keypress();
 	}
+#endif
 
 	memset(&filp, 0, sizeof(filp));
 	memset(&d_inode, 0, sizeof(d_inode));
diff -u --recursive --new-file v1.1.65/linux/ibcs/binfmt_coff.c linux/ibcs/binfmt_coff.c
--- v1.1.65/linux/ibcs/binfmt_coff.c	Tue Aug  9 09:33:00 1994
+++ linux/ibcs/binfmt_coff.c	Tue Nov 22 15:40:12 1994
@@ -546,7 +546,7 @@
 	    }
 	}
 /*
- *   Generate any needed trap for this process. If an error occured then
+ *   Generate any needed trap for this process. If an error occurred then
  *   generate a segmentation violation. If the process is being debugged
  *   then generate the load trap. (Note: If this is a library load then
  *   do not generate the trap here. Pass the error to the caller who
diff -u --recursive --new-file v1.1.65/linux/include/asm-alpha/delay.h linux/include/asm-alpha/delay.h
--- v1.1.65/linux/include/asm-alpha/delay.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/delay.h	Wed Nov 23 08:32:09 1994
@@ -0,0 +1,38 @@
+#ifndef __ALPHA_DELAY_H
+#define __ALPHA_DELAY_H
+
+extern unsigned long loops_per_sec;
+
+/*
+ * Copyright (C) 1993 Linus Torvalds
+ *
+ * Delay routines, using a pre-computed "loops_per_second" value.
+ */
+
+extern __inline__ void __delay(unsigned long loops)
+{
+	__asm__ __volatile__(".align 3\n"
+		"1:\tsubq %0,1,%0\n\t"
+		"bge %0,1b": "=r" (loops) : "0" (loops));
+}
+
+/*
+ * division by multiplication: you don't have to worry about
+ * loss of precision.
+ *
+ * Use only for very small delays ( < 1 msec).  Should probably use a
+ * lookup table, really, as the multiplications take much too long with
+ * short delays.  This is a "reasonable" implementation, though (and the
+ * first constant multiplications gets optimized away if the delay is
+ * a constant)
+ */
+extern __inline__ void udelay(unsigned long usecs)
+{
+	usecs *= 0x000010c6f7a0b5edUL;		/* 2**64 / 1000000 */
+	__asm__("umulh %1,%2,%0"
+		:"=r" (usecs)
+		:"r" (usecs),"r" (loops_per_sec));
+	__delay(usecs);
+}
+
+#endif /* defined(__ALPHA_DELAY_H) */
diff -u --recursive --new-file v1.1.65/linux/include/linux/fd.h linux/include/linux/fd.h
--- v1.1.65/linux/include/linux/fd.h	Thu Oct  6 08:45:21 1994
+++ linux/include/linux/fd.h	Fri Nov 25 10:43:58 1994
@@ -25,19 +25,15 @@
 #define FDGETDRVPRM 21 /* get drive parameters */
 #define FDGETDRVSTAT 22 /* get drive state */
 #define FDPOLLDRVSTAT 23 /* get drive state */
-#define FDGETFDCSTAT 25 /* get fdc state */
-#define FDWERRORCLR  27 /* clear write error and badness information */
-#define FDWERRORGET  28 /* get write error and badness information */
-
 #define FDRESET 24 /* reset FDC */
+
 #define FD_RESET_IF_NEEDED 0
 #define FD_RESET_IF_RAWCMD 1
 #define FD_RESET_ALWAYS 2
 
-#define FDBAILOUT 26 /* release all fdc locks */
-#define FD_CLEAR_RESET 0
-#define FD_COMPLETE_FORMAT 1
-#define FD_UNLOCK_FDC 2
+#define FDGETFDCSTAT 25 /* get fdc state */
+#define FDWERRORCLR  27 /* clear write error and badness information */
+#define FDWERRORGET  28 /* get write error and badness information */
 
 #define FDRAWCMD 30 /* send a raw command to the fdc */
 
@@ -59,6 +55,7 @@
 #define FD_PERP 0x40
 
 #ifndef ASSEMBLER
+/* the following structure is used by FDSETPRM, FDDEFPRM and FDGETPRM */
 struct floppy_struct {
 	unsigned int	size,		/* nr of sectors total */
 			sect,		/* sectors per track */
@@ -94,6 +91,7 @@
 
 };
 
+/* the following structure is used by FDSETDRVPRM and FDGETDRVPRM */
 struct floppy_drive_params {
   char cmos;			/* cmos type */
 
@@ -124,7 +122,11 @@
  * disk changes.
  * Also used to enable/disable printing of overrun warnings.
  */
+
 #define FTD_MSG 0x10
+#define FD_BROKEN_DCL 0x20
+#define FD_DEBUG 0x02
+#define FD_SILENT_DCL_CLEAR 0x4
 
   char read_track;		/* use readtrack during probing? */
 
@@ -139,21 +141,30 @@
   int native_format; /* native format of this drive */
 };
 
-struct floppy_drive_struct {
-  signed char flags;
+enum {
+FD_NEED_TWADDLE_BIT, /* more magic */
+FD_VERIFY_BIT, /* inquire for write protection */
+FD_DISK_NEWCHANGE_BIT, /* change detected, and no action undertaken yet to
+			  clear media change status */
+FD_UNUSED_BIT,
+FD_DISK_CHANGED_BIT, /* disk has been changed since last i/o */
+FD_DISK_WRITABLE_BIT /* disk is writable */
+};
 
 /* values for these flags */
-#define FD_NEED_TWADDLE 1 /* more magic */
-#define FD_VERIFY 2 /* this is set at bootup to force an initial drive status
-		   inquiry*/
-#define FD_DISK_NEWCHANGE 4 /* change detected, and no action undertaken yet to
-			    clear media change status */
-#define FD_DRIVE_PRESENT 8
-#define FD_DISK_WRITABLE 32
-
-  unsigned long volatile spinup_date;
-  unsigned long volatile select_date;
-  unsigned long volatile first_read_date;
+#define FD_NEED_TWADDLE (1 << FD_NEED_TWADDLE_BIT)
+#define FD_VERIFY (1 << FD_VERIFY_BIT)
+#define FD_DISK_NEWCHANGE (1 << FD_DISK_NEWCHANGE_BIT)
+#define FD_DISK_CHANGED (1 << FD_DISK_CHANGED_BIT)
+#define FD_DISK_WRITABLE (1 << FD_DISK_WRITABLE_BIT)
+
+#define FD_DRIVE_PRESENT 0 /* keep fdpatch utils compiling */
+
+struct floppy_drive_struct {
+  signed char flags;
+  unsigned long spinup_date;
+  unsigned long select_date;
+  unsigned long first_read_date;
   short probed_format;
   short track; /* current track */
   short maxblock; /* id of highest block read */
diff -u --recursive --new-file v1.1.65/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v1.1.65/linux/include/linux/netdevice.h	Tue Nov 22 15:41:14 1994
+++ linux/include/linux/netdevice.h	Thu Nov 24 14:17:45 1994
@@ -139,7 +139,7 @@
 #define HAVE_SET_MAC_ADDR  		 
   int			  (*set_mac_address)(struct device *dev, void *addr);
 #define HAVE_PRIVATE_IOCTL
-  int			  (*do_ioctl)(struct device *dev, struct ifreq *ifr);
+  int			  (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd);
 #define HAVE_SET_CONFIG
   int			  (*set_config)(struct device *dev, struct ifmap *map);
   
diff -u --recursive --new-file v1.1.65/linux/init/main.c linux/init/main.c
--- v1.1.65/linux/init/main.c	Tue Nov 22 15:41:14 1994
+++ linux/init/main.c	Fri Nov 25 10:43:58 1994
@@ -75,7 +75,6 @@
 extern long kmalloc_init(long,long);
 extern long blk_dev_init(long,long);
 extern long chr_dev_init(long,long);
-extern void floppy_init(void);
 extern void sock_init(void);
 extern long rd_init(long mem_start, int length);
 unsigned long net_dev_init(unsigned long, unsigned long);
@@ -406,6 +405,82 @@
 	outb_p(0,0xf0);
 }
 
+static void check_fpu(void)
+{
+	static double x = 4195835.0;
+	static double y = 3145727.0;
+	unsigned short control_word;
+	int i;
+
+	if (!hard_math) {
+#ifndef CONFIG_MATH_EMULATION
+		printk("No coprocessor found and no math emulation present.\n");
+		printk("Giving up.\n");
+		for (;;) ;
+#endif
+		return;
+	}
+	/*
+	 * check if exception 16 works correctly.. This is truly evil
+	 * code: it disables the high 8 interrupts to make sure that
+	 * the irq13 doesn't happen. But as this will lead to a lockup
+	 * if no exception16 arrives, it depends on the fact that the
+	 * high 8 interrupts will be re-enabled by the next timer tick.
+	 * So the irq13 will happen eventually, but the exception 16
+	 * should get there first..
+	 */
+	printk("Checking 386/387 coupling... ");
+	timer_table[COPRO_TIMER].expires = jiffies+50;
+	timer_table[COPRO_TIMER].fn = copro_timeout;
+	timer_active |= 1<<COPRO_TIMER;
+	__asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
+	control_word &= 0xffc0;
+	__asm__("fldcw %0 ; fwait": :"m" (*&control_word));
+	outb_p(inb_p(0x21) | (1 << 2), 0x21);
+	__asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
+	timer_active &= ~(1<<COPRO_TIMER);
+	if (fpu_error)
+		return;
+	if (!ignore_irq13) {
+		printk("Ok, fpu using old IRQ13 error reporting\n");
+		return;
+	}
+	__asm__("fninit\n\t"
+		"fldl %1\n\t"
+		"fdivl %2\n\t"
+		"fmull %2\n\t"
+		"fldl %1\n\t"
+		"fsubp %%st,%%st(1)\n\t"
+		"fistpl %0\n\t"
+		"fwait\n\t"
+		"fninit"
+		: "=m" (*&i)
+		: "m" (*&x), "m" (*&y));
+	if (!i) {
+		printk("Ok, fpu using exception 16 error reporting.\n");
+		return;
+
+	}
+	printk("Ok, FDIV bug i%c86 system\n", '0'+x86);
+}
+
+static void check_hlt(void)
+{
+	printk("Checking 'hlt' instruction... ");
+	if (!hlt_works_ok) {
+		printk("disabled\n");
+		return;
+	}
+	__asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
+	printk("Ok.\n");
+}
+
+static void check_bugs(void)
+{
+	check_fpu();
+	check_hlt();
+}
+
 asmlinkage void start_kernel(void)
 {
 /*
@@ -468,51 +543,12 @@
 	mem_init(low_memory_start,memory_start,memory_end);
 	buffer_init();
 	time_init();
-	floppy_init();
 	sock_init();
 #ifdef CONFIG_SYSVIPC
 	ipc_init();
 #endif
 	sti();
-
-	/*
-	 * check if exception 16 works correctly.. This is truly evil
-	 * code: it disables the high 8 interrupts to make sure that
-	 * the irq13 doesn't happen. But as this will lead to a lockup
-	 * if no exception16 arrives, it depends on the fact that the
-	 * high 8 interrupts will be re-enabled by the next timer tick.
-	 * So the irq13 will happen eventually, but the exception 16
-	 * should get there first..
-	 */
-	if (hard_math) {
-		unsigned short control_word;
-
-		printk("Checking 386/387 coupling... ");
-		timer_table[COPRO_TIMER].expires = jiffies+50;
-		timer_table[COPRO_TIMER].fn = copro_timeout;
-		timer_active |= 1<<COPRO_TIMER;
-		__asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
-		control_word &= 0xffc0;
-		__asm__("fldcw %0 ; fwait": :"m" (*&control_word));
-		outb_p(inb_p(0x21) | (1 << 2), 0x21);
-		__asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
-		timer_active &= ~(1<<COPRO_TIMER);
-		if (!fpu_error)
-			printk("Ok, fpu using %s error reporting.\n",
-				ignore_irq13?"exception 16":"irq13");
-	}
-#ifndef CONFIG_MATH_EMULATION
-	else {
-		printk("No coprocessor found and no math emulation present.\n");
-		printk("Giving up.\n");
-		for (;;) ;
-	}
-#endif
-	if (hlt_works_ok) {
-		printk("Checking 'hlt' instruction... ");
-		__asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
-		printk("Ok.\n");
-	}
+	check_bugs();
 
 	system_utsname.machine[1] = '0' + x86;
 	printk(linux_banner);
diff -u --recursive --new-file v1.1.65/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.65/linux/kernel/ksyms.c	Tue Nov 15 15:35:41 1994
+++ linux/kernel/ksyms.c	Fri Nov 25 10:43:58 1994
@@ -36,6 +36,10 @@
 #endif
 
 #include <asm/irq.h>
+extern char floppy_track_buffer[];
+extern void set_device_ro(int dev,int flag);
+#include <linux/delay.h>
+#include <linux/locks.h>
   
 extern void *sys_call_table;
 
@@ -91,6 +95,10 @@
 	X(namei),
 	X(lnamei),
 	X(open_namei),
+	X(check_disk_change),
+	X(invalidate_buffers),
+	X(fsync_dev),
+	X(permission),
 	X(inode_setattr),
 	X(inode_change_ok),
 	X(generic_mmap),
@@ -116,7 +124,10 @@
 	X(block_fsync),
 	X(wait_for_request),
 	X(blksize_size),
+	X(blk_size),
 	X(blk_dev),
+	X(is_read_only),
+	X(set_device_ro),
 	
 	/* Module creation of serial units */
 	X(register_serial),
@@ -144,7 +155,11 @@
 	X(bh_mask),
 	X(add_timer),
 	X(del_timer),
+	X(tq_timer),
 	X(tq_immediate),
+	X(tq_last),
+	X(timer_active),
+	X(timer_table),
 
 	/* dma handling */
 	X(request_dma),
diff -u --recursive --new-file v1.1.65/linux/net/inet/af_inet.c linux/net/inet/af_inet.c
--- v1.1.65/linux/net/inet/af_inet.c	Thu Nov  3 17:53:30 1994
+++ linux/net/inet/af_inet.c	Thu Nov 24 14:17:59 1994
@@ -1245,12 +1245,15 @@
 		case OLD_SIOCGIFHWADDR:
 		case SIOCSIFMAP:
 		case SIOCGIFMAP:
-		case SIOCDEVPRIVATE:
 		case SIOCSIFSLAVE:
 		case SIOCGIFSLAVE:
 			return(dev_ioctl(cmd,(void *) arg));
 
 		default:
+			if ((cmd >= SIOCDEVPRIVATE) &&
+			   (cmd <= (SIOCDEVPRIVATE + 15)))
+				return(dev_ioctl(cmd,(void *) arg));
+
 			if (sk->prot->ioctl==NULL) 
 				return(-EINVAL);
 			return(sk->prot->ioctl(sk, cmd, arg));
@@ -1304,6 +1307,12 @@
 				continue;
 			score++;
 		}
+		/*
+		 * strange but true: udp sockets don't care that much
+		 * about the remote address.
+		 */
+		if (prot == &udp_prot)
+			return s;
 		/* remote address matches? */
 		if (s->daddr) {
 			if (s->daddr != raddr)
diff -u --recursive --new-file v1.1.65/linux/net/inet/dev.c linux/net/inet/dev.c
--- v1.1.65/linux/net/inet/dev.c	Fri Oct 21 09:39:34 1994
+++ linux/net/inet/dev.c	Thu Nov 24 14:18:09 1994
@@ -1268,13 +1268,6 @@
 				return -EINVAL;
 			ret=dev->set_mac_address(dev,ifr.ifr_hwaddr.sa_data);
 			break;
-		
-		case SIOCDEVPRIVATE:
-			if(dev->do_ioctl==NULL)
-				return -EOPNOTSUPP;
-			ret=dev->do_ioctl(dev, &ifr);
-			memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
-			break;
 			
 		case SIOCGIFMAP:
 			ifr.ifr_map.mem_start=dev->mem_start;
@@ -1348,10 +1341,19 @@
 		break;
 #endif			
 		/*
-		 *	Unknown ioctl
+		 *	Unknown or private ioctl
 		 */
 
 		default:
+			if((getset >= SIOCDEVPRIVATE) &&
+			   (getset <= (SIOCDEVPRIVATE + 15))) {
+				if(dev->do_ioctl==NULL)
+					return -EOPNOTSUPP;
+				ret=dev->do_ioctl(dev, &ifr, getset);
+				memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
+				break;
+			}
+			
 			ret = -EINVAL;
 	}
 	return(ret);
@@ -1404,7 +1406,6 @@
 		case SIOCSIFMEM:
 		case SIOCSIFMAP:
 		case SIOCSIFSLAVE:
-		case SIOCDEVPRIVATE:
 			if (!suser())
 				return -EPERM;
 			return dev_ifsioc(arg, cmd);
@@ -1413,10 +1414,16 @@
 			return -EINVAL;
 
 		/*
-		 *	Unknown ioctl.
+		 *	Unknown or private ioctl.
 		 */	
 		 
 		default:
+			if((cmd >= SIOCDEVPRIVATE) &&
+			   (cmd <= (SIOCDEVPRIVATE + 15))) {
+				if (!suser())
+					return -EPERM;
+				return dev_ifsioc(arg, cmd);
+			}
 			return -EINVAL;
 	}
 }
diff -u --recursive --new-file v1.1.65/linux/net/inet/devinet.c linux/net/inet/devinet.c
--- v1.1.65/linux/net/inet/devinet.c	Tue Nov 22 15:41:14 1994
+++ linux/net/inet/devinet.c	Thu Nov 24 11:08:11 1994
@@ -151,7 +151,7 @@
 				return IS_BROADCAST;
 		}
 	}
-	if(IN_MULTICAST(addr))
+	if(IN_MULTICAST(ntohl(addr)))
 		return IS_MULTICAST;
 	return 0;		/* no match at all */
 }
diff -u --recursive --new-file v1.1.65/linux/net/inet/ip.c linux/net/inet/ip.c
--- v1.1.65/linux/net/inet/ip.c	Tue Nov 22 15:41:14 1994
+++ linux/net/inet/ip.c	Tue Nov 22 15:40:12 1994
@@ -1851,7 +1851,7 @@
 			 *	If the packet is still being sent by the device/protocol
 			 *	below then don't retransmit. This is both needed, and good -
 			 *	especially with connected mode AX.25 where it stops resends
-			 *	occuring of an as yet unsent anyway frame!
+			 *	occurring of an as yet unsent anyway frame!
 			 *	We still add up the counts as the round trip time wants
 			 *	adjusting.
 			 */
diff -u --recursive --new-file v1.1.65/linux/net/inet/packet.c linux/net/inet/packet.c
--- v1.1.65/linux/net/inet/packet.c	Wed Aug 10 19:26:50 1994
+++ linux/net/inet/packet.c	Tue Nov 22 15:40:12 1994
@@ -295,7 +295,7 @@
 	skb=skb_recv_datagram(sk,flags,noblock,&err);
 	
 	/*
-	 *	An error occured so return it. Because skb_recv_datagram() 
+	 *	An error occurred so return it. Because skb_recv_datagram() 
 	 *	handles the blocking we don't see and worry about blocking
 	 *	retries.
 	 */
diff -u --recursive --new-file v1.1.65/linux/net/inet/route.c linux/net/inet/route.c
--- v1.1.65/linux/net/inet/route.c	Thu Nov  3 17:53:30 1994
+++ linux/net/inet/route.c	Wed Nov 23 09:24:08 1994
@@ -113,8 +113,8 @@
 	unsigned long flags;
 
 	rp = &rt_base;
-	cli();
 	save_flags(flags);
+	cli();
 	while ((r = *rp) != NULL) {
 		if (r->rt_dev != dev) {
 			rp = &r->rt_next;
diff -u --recursive --new-file v1.1.65/linux/net/inet/sock.c linux/net/inet/sock.c
--- v1.1.65/linux/net/inet/sock.c	Tue Nov 22 15:41:15 1994
+++ linux/net/inet/sock.c	Wed Nov 23 08:47:34 1994
@@ -43,7 +43,7 @@
  *		Alan Cox	:	for new sk_buff allocations wmalloc/rmalloc now call alloc_skb
  *		Alan Cox	:	kfree_s calls now are kfree_skbmem so we can track skb resources
  *		Alan Cox	:	Supports socket option broadcast now as does udp. Packet and raw need fixing.
- *		Alan Cox	:	Added RCVBUF,SNDBUF size setting. It suddenly occured to me how easy it was so...
+ *		Alan Cox	:	Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so...
  *		Rick Sladkey	:	Relaxed UDP rules for matching packets.
  *		C.E.Hawkins	:	IFF_PROMISC/SIOCGHWADDR support
  *	Pauline Middelink	:	Pidentd support
@@ -497,14 +497,29 @@
 void release_sock(struct sock *sk)
 {
 	struct sk_buff *skb;
+	unsigned long flags;
 
 	if (!sk->prot)
 		return;
+	/*
+	 *	Make the backlog atomic. If we don't do this there is a tiny
+	 *	window where a packet may arrive between the sk->blog being 
+	 *	tested and then set with sk->inuse stil 0 causing an extra 
+	 *	unwanted re-entry into release_sock().
+	 */
+
+	save_flags(flags);
+	cli();
 	if (sk->blog) 
+	{
+		restore_flags(flags);
 		return;
+	}
+	sk->blog=1;
+	sk->inuse = 1;
+	restore_flags(flags);
 #ifdef CONFIG_INET
 	/* See if we have any packets built up. */
-	sk->inuse = 1;
 	while((skb = skb_dequeue(&sk->back_log)) != NULL) 
 	{
 		sk->blog = 1;
diff -u --recursive --new-file v1.1.65/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.65/linux/net/inet/tcp.c	Tue Nov 22 15:41:15 1994
+++ linux/net/inet/tcp.c	Wed Nov 23 08:47:34 1994
@@ -101,6 +101,10 @@
  *					a sensible code size.
  *		Alan Cox	:	Self connect lockup fix.
  *		Alan Cox	:	No connect to multicast.
+ *		Ross Biro	:	Close unaccepted children on master
+ *					socket close.
+ *		Alan Cox	:	Reset tracing code.
+ *		Alan Cox	:	Spurious resets on shutdown.
  *
  *
  * To Fix:
@@ -178,6 +182,8 @@
 unsigned long seq_offset;
 struct tcp_mib	tcp_statistics;
 
+static void tcp_close(struct sock *sk, int timeout);
+
 #ifdef TCP_FASTPATH
 unsigned long tcp_rx_miss=0, tcp_rx_hit1=0, tcp_rx_hit2=0;
 #endif
@@ -260,6 +266,42 @@
 	return NULL;
 }
 
+
+/* 
+ *	This routine closes sockets which have been at least partially
+ *	opened, but not yet accepted. Currently it is only called by
+ *	tcp_close, and timeout mirrors the value there. 
+ */
+
+static void tcp_close_pending (struct sock *sk, int timeout) 
+{
+	unsigned long flags;
+	struct sk_buff *p, *old_p;
+
+	save_flags(flags);
+	cli(); 
+	p=skb_peek(&sk->receive_queue);
+
+	if(p==NULL) 
+	{
+		restore_flags(flags);
+		return;
+	}
+
+	do
+	{
+		tcp_close (p->sk, timeout);
+		skb_unlink (p);
+		old_p = p;
+		p=p->next;
+		kfree_skb(old_p, FREE_READ);
+	}
+	while(p!=skb_peek(&sk->receive_queue));
+
+	restore_flags(flags);
+	return;
+}
+
 static struct sk_buff *tcp_dequeue_established(struct sock *s)
 {
 	struct sk_buff *skb;
@@ -1979,6 +2021,8 @@
 	}
 	else 
 	{
+		if(sk->debug)
+			printk("Reset on %p: Connect on dead socket.\n",sk);
 		tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl);
 		tcp_statistics.TcpAttemptFails++;
 		kfree_skb(skb, FREE_READ);
@@ -2309,6 +2353,9 @@
 			release_sock(sk);
 			return;
 		case TCP_LISTEN:
+			/* we need to drop any sockets which have been connected,
+			   but have not yet been accepted. */
+			tcp_close_pending(sk, timeout);
 			tcp_set_state(sk,TCP_CLOSE);
 			release_sock(sk);
 			return;
@@ -2918,7 +2965,7 @@
 		if (sk->rcv_ack_seq == sk->write_seq && sk->acked_seq == sk->fin_seq) 
 		{
 			flag |= 1;
-			tcp_set_state(sk,TCP_CLOSE);
+			tcp_time_wait(sk);
 			sk->shutdown = SHUTDOWN_MASK;
 		}
 	}
@@ -2939,7 +2986,7 @@
 		{
 			flag |= 1;
 			sk->shutdown |= SEND_SHUTDOWN;
-			tcp_set_state(sk,TCP_FIN_WAIT2);
+			tcp_set_state(sk, TCP_FIN_WAIT2);
 		}
 	}
 
@@ -3015,6 +3062,8 @@
 	struct tcphdr *th;
 	int dup_dumped=0;
 	unsigned long new_seq;
+	struct sk_buff *tail;
+	unsigned long shut_seq;
 
 	th = skb->h.th;
 	skb->len = len -(th->doff*4);
@@ -3044,11 +3093,37 @@
 	{
 		new_seq= th->seq + skb->len + th->syn;	/* Right edge of _data_ part of frame */
 		
-		if(after(new_seq,sk->acked_seq+1))	/* If the right edge of this frame is after the last copied byte
-							   then it contains data we will never touch. We send an RST to 
-							   ensure the far end knows it never got to the application */
+		/*
+		 *	This is subtle and not nice. When we shut down we can
+		 *	have data in the queue and acked_seq therefore not
+		 *	pointing to the last byte that will be read. Thus
+		 *	the naive implementation:
+		 *		after(new_seq,sk->acked_seq+1)
+		 *	will cause bogus resets IFF a resend of a frame that has
+		 *	been queued but not yet read after a shutdown has been done
+		 *	occured.What we do now is a bit more complex but works as
+		 *	follows. If the queue is empty copied_seq+1 is right (+1 for FIN)
+		 *	if the queue has data the shutdown occurs at the right edge of
+		 *	the last packet queued +1
+		 *
+		 *	We can't simply ack data beyond this point as it has
+		 *	and will never be received by an application.
+		 */
+		tail=skb_peek(&sk->receive_queue);
+		if(tail!=NULL)
+		{
+			tail=sk->receive_queue.prev;
+			shut_seq=tail->h.th->seq+tail->len+1;
+		}
+		else
+			shut_seq=sk->copied_seq+1;
+		
+		if(after(new_seq,shut_seq))
 		{
 			sk->acked_seq = new_seq + th->fin;
+			if(sk->debug)
+				printk("Data arrived on %p after close [Data right edge %lX, Socket shut on %lX] %d\n",
+					sk, new_seq, shut_seq, sk->blog);
 			tcp_reset(sk->saddr, sk->daddr, skb->h.th,
 				sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl);
 			tcp_statistics.TcpEstabResets++;
@@ -3802,7 +3877,7 @@
 		cli();
 		if (sk->inuse) 
 		{
-			skb_queue_head(&sk->back_log, skb);
+			skb_queue_tail(&sk->back_log, skb);
 			sti();
 			return(0);
 		}
@@ -3998,7 +4073,8 @@
 				sk->err = ECONNRESET;
 				tcp_set_state(sk,TCP_CLOSE);
 				sk->shutdown = SHUTDOWN_MASK;
-				tcp_reset(daddr, saddr,  th, sk->prot, opt,dev, sk->ip_tos,sk->ip_ttl);
+				if(sk->debug)
+					printk("Socket %p reset by SYN while established.\n", sk);
 				if (!sk->dead) {
 					sk->state_change(sk);
 				}
@@ -4012,9 +4088,10 @@
 				 *	old connection.
 				 *
 				 */
+				 
 				if(st==TCP_TIME_WAIT && th->seq > sk->acked_seq && sk->dead)
 				{
-					release_sock(sk);
+					struct sock *psk=sk;
 					/*
 					 *	Find the listening socket.
 					 */
@@ -4023,19 +4100,22 @@
 					{
 						sk->inuse=1;
 						tcp_conn_request(sk, skb, daddr, saddr,opt, dev,seq+128000);
-						release_sock(sk);
+						release_sock(psk);
 						/* Fall through in case people are
 						   also using the piggy backed SYN + data 
 						   protocol violation */
 					}
 					else
 					{
+						tcp_reset(daddr, saddr,  th, psk->prot, opt,dev, psk->ip_tos,psk->ip_ttl);
+						release_sock(psk);
 						kfree_skb(skb, FREE_READ);
 						return 0;
 					}			
 				}
 				else
 				{
+					tcp_reset(daddr, saddr,  th, sk->prot, opt,dev, sk->ip_tos,sk->ip_ttl);
 					kfree_skb(skb, FREE_READ);
 					release_sock(sk);
 					return(0);
@@ -4080,6 +4160,7 @@
 			if (!th->rst) {
 				if (!th->ack)
 					th->ack_seq = 0;
+				if(sk->debug) printk("Reset on closed socket %s.\n",sk->blog);
 				tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
 			}
 			kfree_skb(skb, FREE_READ);
@@ -4093,6 +4174,7 @@
 				return(0);
 			}
 			if (th->ack) {
+				printk("Reset on listening socket %d.\n",sk->blog);
 				tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
 				kfree_skb(skb, FREE_READ);
 				release_sock(sk);
