diff -u --recursive --new-file v2.0.20/linux/CREDITS linux/CREDITS
--- v2.0.20/linux/CREDITS	Sun Sep 15 10:34:17 1996
+++ linux/CREDITS	Tue Sep 17 23:19:53 1996
@@ -53,7 +53,8 @@
 S: Calgary, Alberta, Canada
 
 N: Ralf Baechle
-E: ralf@waldorf-gmbh.de
+E: ralf@gnu.ai.mit.edu
+P: 1024/AF7B30C1 CF 97 C2 CC 6D AE A7 FE  C8 BA 9C FC 88 DE 32 C3
 D: Linux/MIPS port
 D: Linux/68k hacker
 S: Hauptstrasse 19
@@ -802,10 +803,10 @@
 S: Canada K2H 6S3
 
 N: Warner Losh
-E: imp@boulder.parcplace.com
-D: Provided OI/OB for Linux, general hacker
-S: 4909 Pearl East Circle, Suite 200
-S: Boulder, Colorado 80303
+E: imp@village.org
+D: Linux/MIPS Deskstation support, Provided OI/OB for Linux
+S: 8786 Niwot Rd
+S: Niwot, CO 80503
 S: USA
 
 N: H.J. Lu
@@ -1407,6 +1408,10 @@
 N: Jeffrey A. Uphoff
 E: juphoff@nrao.edu
 E: jeff.uphoff@linux.org
+P: 1024/9ED505C5 D7 BB CA AA 10 45 40 1B  16 19 0A C0 38 A0 3E CB
+D: Linux Security/Alert mailing lists' moderator/maintainer.
+D: NSM (rpc.statd) developer.
+D: PAM S/Key module developer.
 D: 'dip' contributor.
 D: AIPS port, astronomical community support.
 S: National Radio Astronomy Observatory
diff -u --recursive --new-file v2.0.20/linux/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd
--- v2.0.20/linux/Documentation/cdrom/ide-cd	Mon Jul  8 13:01:29 1996
+++ linux/Documentation/cdrom/ide-cd	Wed Sep 18 11:13:52 1996
@@ -182,6 +182,10 @@
   If this is set, the driver will never attempt to lock the door of
   the drive.
 
+CDROM_NBLOCKS_BUFFER
+  This sets the size of the buffer to be used for a CDROMREADAUDIO
+  ioctl.  The default is 8.
+
 TEST
   This presently enables an additional ioctl which enables a user-mode
   program to execute an arbitrary packet command.  See the source for
@@ -366,6 +370,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <linux/cdrom.h>
+#include <linux/ucdrom.h>
 
 
 int
@@ -396,10 +401,10 @@
 	}
 
 	/* load */ 
-	status = ioctl (fd, CDROMLOADFROMSLOT, x_slot);
+	status = ioctl (fd, CDROM_SELECT_DISC, x_slot);
 	if (status != 0) {
 		fprintf (stderr,
-			 "%s: CDROMLOADFROMSLOT ioctl failed for `%s': %s\n",
+			 "%s: CDROM_SELECT_DISC ioctl failed for `%s': %s\n",
 			 program, device, strerror (errno));
 		exit (1);
 	}
diff -u --recursive --new-file v2.0.20/linux/Documentation/digiboard.txt linux/Documentation/digiboard.txt
--- v2.0.20/linux/Documentation/digiboard.txt	Mon Aug  5 10:13:50 1996
+++ linux/Documentation/digiboard.txt	Mon Sep 16 13:05:28 1996
@@ -60,7 +60,7 @@
   for c in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15;
   do
 	name=`expr $boardnum \* 16 + $c`
-	mknod /dev/cud$name c $DIGI_CUMAJOR $name
+	mknod /dev/cud$name c $DIGICU_MAJOR $name
 	mknod /dev/ttyD$name c $DIGI_MAJOR $name
   done
   boardnum=`expr $boardnum + 1`
diff -u --recursive --new-file v2.0.20/linux/Makefile linux/Makefile
--- v2.0.20/linux/Makefile	Sun Sep 15 10:34:18 1996
+++ linux/Makefile	Fri Sep 20 16:08:47 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 20
+SUBLEVEL = 21
 
 ARCH = i386
 
@@ -24,9 +24,10 @@
 TOPDIR	:= $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
 
 HPATH   	= $(TOPDIR)/include
+FINDHPATH	= $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net
 
 HOSTCC  	=gcc -I$(HPATH)
-HOSTCFLAGS	=
+HOSTCFLAGS	=-O2 -fomit-frame-pointer
 
 CROSS_COMPILE 	=
 
@@ -38,7 +39,6 @@
 NM	=$(CROSS_COMPILE)nm
 STRIP	=$(CROSS_COMPILE)strip
 MAKE	=make
-AWK	=gawk
 
 all:	do-it-all
 
@@ -327,7 +327,7 @@
 	rm -f .menuconfig .menuconfig.log
 	rm -f include/asm
 	rm -f .depend `find . -name .depend -print`
-	rm -f .hdepend
+	rm -f .hdepend scripts/mkdep
 	rm -f $(TOPDIR)/include/linux/modversions.h
 	rm -f $(TOPDIR)/include/linux/modules/*
 
@@ -344,8 +344,9 @@
 sums:
 	find . -type f -print | sort | xargs sum > .SUMS
 
-dep-files: archdep .hdepend include/linux/version.h
-	$(AWK) -f scripts/depend.awk init/*.c > .tmpdepend
+dep-files: scripts/mkdep archdep include/linux/version.h
+	scripts/mkdep init/*.c > .tmpdepend
+	scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend
 	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep; done
 	mv .tmpdepend .depend
 
@@ -383,7 +384,5 @@
 # This generates dependencies for the .h files.
 #
 
-.hdepend: dummy
-	rm -f $@
-	$(AWK) -f scripts/depend.awk `find $(HPATH) -name \*.h ! -name modversions.h -print` > .$@
-	mv .$@ $@
+scripts/mkdep: scripts/mkdep.c
+	$(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c
diff -u --recursive --new-file v2.0.20/linux/Rules.make linux/Rules.make
--- v2.0.20/linux/Rules.make	Fri Jun  7 16:28:45 1996
+++ linux/Rules.make	Sun Sep 15 13:21:20 1996
@@ -83,7 +83,7 @@
 #
 fastdep: dummy
 	if [ -n "$(wildcard *.[chS])" ]; then \
-	$(AWK) -f $(TOPDIR)/scripts/depend.awk *.[chS] > .depend; fi
+	$(TOPDIR)/scripts/mkdep *.[chS] > .depend; fi
 ifdef ALL_SUB_DIRS
 	set -e; for i in $(ALL_SUB_DIRS); do $(MAKE) -C $$i fastdep; done
 endif
diff -u --recursive --new-file v2.0.20/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.0.20/linux/arch/i386/kernel/setup.c	Wed May  8 07:42:33 1996
+++ linux/arch/i386/kernel/setup.c	Fri Sep 20 13:17:18 1996
@@ -327,8 +327,8 @@
                         }
                         len += sprintf(buffer+len,
                                        "\nbogomips\t: %lu.%02lu\n",
-                                       CD(loops_per_sec)/500000,
-                                       (CD(loops_per_sec)/5000) % 100);
+                                       CD(loops_per_sec+2500)/500000,
+                                       (CD(loops_per_sec+2500)/5000) % 100);
 #ifdef __SMP__
                 }
         }
diff -u --recursive --new-file v2.0.20/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.0.20/linux/drivers/block/ide-cd.c	Mon Aug  5 10:13:51 1996
+++ linux/drivers/block/ide-cd.c	Wed Sep 18 11:13:53 1996
@@ -106,6 +106,8 @@
  *                        <jeffml@netcom.com>
  * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
  * 3.16  Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
+ * 3.17  Sep 17, 1996 -- Tweak audio reads for some drives.
+ *                       Start changing CDROMLOADFROMSLOT to CDROM_SELECT_DISC.
  *
  * NOTE: Direct audio reads will only work on some types of drive.
  * So far, i've received reports of success for Sony and Toshiba drives.
@@ -132,6 +134,7 @@
 #include <linux/errno.h>
 #include <linux/hdreg.h>
 #include <linux/cdrom.h>
+#include <linux/ucdrom.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
@@ -168,6 +171,13 @@
 #endif
 
 
+/* Size of buffer to allocate, in blocks, for audio reads. */
+
+#ifndef CDROM_NBLOCKS_BUFFER
+#define CDROM_NBLOCKS_BUFFER 8
+#endif
+
+
 /************************************************************************/
 
 #define SECTOR_SIZE 512
@@ -1918,7 +1928,7 @@
 
 
 static int
-cdrom_read_block (ide_drive_t *drive, int format, int lba,
+cdrom_read_block (ide_drive_t *drive, int format, int lba, int nblocks,
 		  char *buf, int buflen,
 		  struct atapi_request_sense *reqbuf)
 {
@@ -1944,8 +1954,13 @@
 
 	pc.c[1] = (format << 2);
 	put_unaligned(htonl(lba), (unsigned int *) &pc.c[2]);
-	pc.c[8] = 1;  /* one block */
-	pc.c[9] = 0x10;
+	pc.c[8] = (nblocks & 0xff);
+	pc.c[7] = ((nblocks>>8) & 0xff);
+	pc.c[6] = ((nblocks>>16) & 0xff);
+	if (format <= 1)
+		pc.c[9] = 0xf0;
+	else
+		pc.c[9] = 0x10;
 
 	stat = cdrom_queue_packet_command (drive, &pc);
 
@@ -1959,8 +1974,8 @@
 			"trying opcode 0xd4\n",
 			drive->name);
 		CDROM_CONFIG_FLAGS (drive)->old_readcd = 1;
-		return cdrom_read_block (drive, format, lba, buf, buflen,
-					 reqbuf);
+		return cdrom_read_block (drive, format, lba, nblocks,
+					 buf, buflen, reqbuf);
 	}
 #endif  /* not STANDARD_ATAPI */
 
@@ -2343,19 +2358,25 @@
 		if (lba < 0 || lba >= toc->capacity)
 			return -EINVAL;
 
-		buf = (char *) kmalloc (CD_FRAMESIZE_RAW, GFP_KERNEL);
+		buf = (char *) kmalloc (CDROM_NBLOCKS_BUFFER*CD_FRAMESIZE_RAW,
+					GFP_KERNEL);
 		if (buf == NULL)
 			return -ENOMEM;
 
 		while (ra.nframes > 0) {
-			stat = cdrom_read_block (drive, 1, lba, buf,
-						 CD_FRAMESIZE_RAW, NULL);
+			int this_nblocks = ra.nframes;
+			if (this_nblocks > CDROM_NBLOCKS_BUFFER)
+				this_nblocks = CDROM_NBLOCKS_BUFFER;
+			stat = cdrom_read_block
+				(drive, 1, lba, this_nblocks,
+				 buf, this_nblocks * CD_FRAMESIZE_RAW, NULL);
 			if (stat) break;
 
-			memcpy_tofs (ra.buf, buf, CD_FRAMESIZE_RAW);
-			ra.buf += CD_FRAMESIZE_RAW;
-			--ra.nframes;
-			++lba;
+			memcpy_tofs (ra.buf, buf,
+				     this_nblocks * CD_FRAMESIZE_RAW);
+			ra.buf += this_nblocks * CD_FRAMESIZE_RAW;
+			ra.nframes -= this_nblocks;
+			lba += this_nblocks;
 		}
 
 		kfree (buf);
@@ -2399,7 +2420,7 @@
 		if (buf == NULL)
 			return -ENOMEM;
 
-		stat = cdrom_read_block (drive, format, lba, buf, blocksize,
+		stat = cdrom_read_block (drive, format, lba, 1, buf, blocksize,
 					 NULL);
 		if (stat == 0)
 			memcpy_tofs ((char *)arg, buf, blocksize);
@@ -2432,7 +2453,12 @@
 		return stat;
 	}
 
-	case CDROMLOADFROMSLOT: {
+	case CDROMLOADFROMSLOT:
+		printk ("%s: Use CDROM_SELECT_DISC "
+			" instead of CDROMLOADFROMSLOT.\n", drive->name);
+		/* Fall through. */
+
+	case CDROM_SELECT_DISC: {
 		struct atapi_request_sense my_reqbuf;
 		int stat;
 
diff -u --recursive --new-file v2.0.20/linux/drivers/block/ide_modes.h linux/drivers/block/ide_modes.h
--- v2.0.20/linux/drivers/block/ide_modes.h	Mon Aug  5 10:13:51 1996
+++ linux/drivers/block/ide_modes.h	Fri Sep 20 15:21:40 1996
@@ -6,6 +6,8 @@
  *  Copyright (C) 1996  Linus Torvalds, Igor Abramov, and Mark Lord
  */
 
+#include <linux/config.h>
+
 /*
  * Shared data/functions for determining best PIO mode for an IDE drive.
  * Most of this stuff originally lived in cmd640.c, and changes to the
diff -u --recursive --new-file v2.0.20/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.0.20/linux/drivers/block/ll_rw_blk.c	Sat Aug 17 21:19:26 1996
+++ linux/drivers/block/ll_rw_blk.c	Fri Sep 20 12:50:55 1996
@@ -349,6 +349,10 @@
 	}
 
 /* look for a free request. */
+       /* Loop uses two requests, 1 for loop and 1 for the real device.
+        * Cut max_req in half to avoid running out and deadlocking. */
+        if (major == LOOP_MAJOR)
+	     max_req >>= 1;
 
 	/*
 	 * Try to coalesce the new request with old requests
@@ -508,7 +512,6 @@
 	for (i = 0; i < nr; i++) {
 		if (bh[i]) {
 			set_bit(BH_Req, &bh[i]->b_state);
-
 			make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]);
 		}
 	}
@@ -528,6 +531,7 @@
 {
 	int i, j;
 	int buffersize;
+	int max_req;
 	unsigned long rsector;
 	kdev_t rdev;
 	struct request * req[8];
@@ -539,10 +543,12 @@
                                    " nonexistent block-device\n");
 		return;
 	}
+	max_req = NR_REQUEST;
 	switch (rw) {
 		case READ:
 			break;
 		case WRITE:
+			max_req = (NR_REQUEST * 2) / 3;
 			if (is_read_only(dev)) {
 				printk(KERN_NOTICE
                                        "Can't swap to read-only device %s\n",
@@ -555,6 +561,8 @@
 	}
 	buffersize = PAGE_SIZE / nb;
 
+	if (major == LOOP_MAJOR)
+	     max_req >>= 1;
 	for (j=0, i=0; i<nb;)
 	{
 		for (; j < 8 && i < nb; j++, i++, buf += buffersize)
@@ -572,10 +580,10 @@
 #endif
 			
 			if (j == 0) {
-				req[j] = get_request_wait(NR_REQUEST, rdev);
+				req[j] = get_request_wait(max_req, rdev);
 			} else {
 				cli();
-				req[j] = get_request(NR_REQUEST, rdev);
+				req[j] = get_request(max_req, rdev);
 				sti();
 				if (req[j] == NULL)
 					break;
diff -u --recursive --new-file v2.0.20/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.0.20/linux/drivers/char/mem.c	Thu Aug 29 19:15:14 1996
+++ linux/drivers/char/mem.c	Fri Sep 20 13:17:18 1996
@@ -196,6 +196,7 @@
 
 static int read_full(struct inode * node, struct file * file, char * buf,int count)
 {
+	file->f_pos += count;
 	return count;
 }
 
diff -u --recursive --new-file v2.0.20/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.0.20/linux/drivers/char/random.c	Tue Jul  2 19:08:42 1996
+++ linux/drivers/char/random.c	Fri Sep 20 13:17:18 1996
@@ -1002,6 +1002,8 @@
 		nbytes -= i;
 		buf += i;
 		add_timer_randomness(r, &extract_timer_state, nbytes);
+		if (to_user && need_resched)
+			schedule();
 	}
 
 	/* Wipe data from memory */
@@ -1229,7 +1231,7 @@
 			return -EINVAL;
 		size = get_user(p++);
 		retval = random_write(0, file, (const char *) p, size);
-		if (retval)
+		if (retval < 0)
 			return retval;
 		/*
 		 * Add ent_count to entropy_count, limiting the result to be
diff -u --recursive --new-file v2.0.20/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.0.20/linux/drivers/net/3c509.c	Wed Aug 21 09:18:08 1996
+++ linux/drivers/net/3c509.c	Fri Sep 20 09:11:44 1996
@@ -312,7 +312,7 @@
 {
 	outw(EEPROM_READ + index, ioaddr + 10);
 	/* Pause for at least 162 us. for the read to take place. */
-	udelay (200);
+	udelay (300);
 	return inw(ioaddr + 12);
 }
 
@@ -326,7 +326,7 @@
 	outb(EEPROM_READ + index, id_port);
 
 	/* Pause for at least 162 us. for the read to take place. */
-	udelay (200);
+	udelay (300);
 	
 	for (bit = 15; bit >= 0; bit--)
 		word = (word << 1) + (inb(id_port) & 0x01);
diff -u --recursive --new-file v2.0.20/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx
--- v2.0.20/linux/drivers/scsi/README.ncr53c8xx	Thu Jul 11 08:19:59 1996
+++ linux/drivers/scsi/README.ncr53c8xx	Sat Sep 14 11:11:11 1996
@@ -10,7 +10,7 @@
 1.  Introduction
 2.  Supported chips and SCSI features
 3.  Summary of other supported features
-4.  Memory mapped IO versus normal IO
+4.  Memory mapped I/O versus normal I/O
 5.  Tagged command queueing
 6.  Parity checking
 7.  Profiling information
@@ -39,7 +39,7 @@
 maintained by:
           Gerard Roudier              <groudier@club-internet.fr>
 
-The original driver has been written for 386bsd and FreeBSD by
+The original driver has been written for 386bsd and FreeBSD by:
           Wolfgang Stanglmeier        <wolf@cologne.de>
           Stefan Esser                <se@mi.Uni-Koeln.de>
 
@@ -50,14 +50,14 @@
           http://www.symbios.com
 
 This short documentation only describes the features of the NCR53C8XX driver, 
-configuration parameters and control commands available through the proc scsi 
+configuration parameters and control commands available through the proc SCSI
 file system read / write operations.
 
-This driver has been tested ok with linux/i386  and is currently untested
+This driver has been tested OK with linux/i386  and is currently untested
 under linux/Alpha. If you intend to use this driver under linux/Alpha, just 
 try it first with read-only or mounted read-only devices.
 
-I am not a native speaker of English and there is probably lots of 
+I am not a native speaker of English and there are probably lots of 
 mistakes in this README file. Any help will be welcome.
 
 
@@ -68,14 +68,14 @@
 	Synchronous negotiation
 	Disconnection
 	Tagged command queuing
-	Scsi parity checking
+	SCSI parity checking
 	Master parity checking
 
 "Wide negotiation" is supported for chips that allow it.
 The following table shows some characteristics of NCR 8xx family chips:
 
        On board                        Supported by    Tested with
-Chip   SDMS BIOS   Wide   Ultra Scsi   the driver      the driver
+Chip   SDMS BIOS   Wide   Ultra SCSI   the driver      the driver
 ----   ---------   ----   ----------   ------------    -----------
 810        N         N        N            Y             Y
 810A       N         N        N            Y             Y
@@ -84,73 +84,73 @@
 825A       Y         Y        N            Y             Not yet
 875        Y         Y        Y(1)         Y             Not yet
 
-(1) Ultra scsi extensions will be supported in a future release of the 
+(1) Ultra SCSI extensions will be supported in a future release of the 
     driver.
 
 
 3. Summary of other supported features.
 
         Module:                allow to load the driver
-        Memory mapped IO:      increase performances
-        Profiling information: read operations from the proc scsi file system
-        Control commands:      write operations to the proc scsi file system
+        Memory mapped I/O:     increases performance
+        Profiling information: read operations from the proc SCSI file system
+        Control commands:      write operations to the proc SCSI file system
         Debugging information: written to syslog (expert only)
 	Scatter / gather
 	Shared interrupt
 
 
-4. Memory mapped IO versus normal IO
+4. Memory mapped I/O versus normal I/O
 
-Memory mapped IO have less latency than normal IO.
-Since linux-1.3.x, memory mapped IO is used rather than normal IO.
-Memory mapped IO seems to works fine on most hardware configuration, but some 
-bad designed motherboards may break this feature.
-
-During initialisation phase, the driver first tries to use memory mapped io.
-If nothing seems wrong, it will use memory mapped io.
-If a flaw is detected,  it will use normal io.
+Memory mapped I/O has less latency than normal I/O.
+Since linux-1.3.x, memory mapped I/O is used rather than normal I/O.
+Memory mapped I/O seems to work fine on most hardware configurations, but some 
+poorly designed motherboards may break this feature.
+
+During the initialization phase, the driver first tries to use memory mapped
+I/O.  If nothing seems wrong, it will use memory mapped I/O.
+If a flaw is detected, it will use normal I/O.
 
-However, it's possible that memory mapped io does not work properly and the 
+However, it's possible that memory mapped I/O does not work properly and the 
 driver has not detected the problem.
 
-The configuration option CONFIG_SCSI_NCR53C8XX_IOMAPPED allow to force the 
-driver to use normal io in all cases.
+The configuration option CONFIG_SCSI_NCR53C8XX_IOMAPPED forces the 
+driver to use normal I/O in all cases.
 
 
 5. Tagged command queueing
 
-Some scsi devices donnot support properly tagged command queuing.
-A safe configuration can be to not enable tagged command queuing support at 
+Some SCSI devices do not properly support tagged command queuing.
+A safe configuration is to not enable tagged command queuing support at 
 boot-up, and to enable support of it with the control command "settags" 
 described further in this text.
 
-Once you are sure that all your devices support properly tagged command queuing,
+Once you are sure that all your devices properly support tagged command queuing,
 you can enable it by default with the CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE 
 configuration option.
 
 
 6. Parity checking
 
-The driver supports scsi parity checking and PCI bus master parity checking.
+The driver supports SCSI parity checking and PCI bus master parity checking.
 These features must be enabled in order to ensure safe data transfers.
 However, some flawed devices or mother boards will have problems with 
 parity. You can disable parity by choosing first "CONFIG_EXPERIMENTAL".
 Then, "make config" will allow to set the following configuration options:
 
-   CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK  (disable scsi parity checking)
+   CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK  (disable SCSI parity checking)
    CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK (disable master parity checking)
 
 
 7. Profiling information
 
-Profiling information are available through the proc scsi file system.
+Profiling information is available through the proc SCSI file system.
 The device associated with a host has the following pathname:
           /proc/scsi/ncr53c8xx/N     (N=0,1,2 ....)
 
-Generally, only 1 board is used on hardware configuration, and the device is:
+Generally, only 1 board is used on hardware configuration, and that device is:
           /proc/scsi/ncr53c8xx/0
 
-However, if the driver has been made as module, the number of the host is 
+However, if the driver has been made as module, the number of the hosts is 
 incremented each time the driver is loaded.
 
 In order to display profiling information, just enter:
@@ -175,8 +175,8 @@
   ms_post      = 1320
 -------------------------------------------------------
 
-General information is easy to understand. The device id and the 
-revision id identify the scsi chip as follows:
+General information is easy to understand. The device ID and the 
+revision ID identify the SCSI chip as follows:
 
 Chip    Device id     Revision Id
 ----    ---------     -----------
@@ -188,11 +188,11 @@
 825A      0x3            >= 0x10
 875       0xf
 
-The profiling information is updated upon completion of scsi commands.
-The data structure is allocated and zeroed when the host adapter is 
+The profiling information is updated upon completion of SCSI commands.
+A data structure is allocated and zeroed when the host adapter is 
 attached. So, if the driver is a module, the profile counters are cleared each 
 time the driver is loaded.
-The "clearprof" command allow to clear these counters at any time.
+The "clearprof" command allows you to clear these counters at any time.
 
 The following counters are available:
 ("num" prefix means "number of", "ms" means milli-seconds)
@@ -206,8 +206,8 @@
 	Example above: 671 MB transferred
 
 num_disc
-	Number of scsi disconnections
-	Example above: 25763 scsi disconnections
+	Number of SCSI disconnections
+	Example above: 25763 SCSI disconnections
 
 num_break
 	number of script interruptions (phase mismatch)
@@ -222,7 +222,7 @@
 	Example above: 18038 interruptions "on the fly"
 
 ms_setup
-	Elapsed time for scsi commands setups
+	Elapsed time for SCSI commands setups
 	Example above: 4.94 seconds
 
 ms_data
@@ -230,12 +230,12 @@
 	Example above: 369.94 seconds spent for data transfer
 
 ms_disc
-	Elapsed time for scsi disconnections
+	Elapsed time for SCSI disconnections
 	Example above: 183.09 seconds spent disconnected
 
 ms_post
 	Elapsed time for command post processing
-	(time from scsi status get to command completion call)
+	(time from SCSI status get to command completion call)
 	Example above: 1.32 seconds spent for post processing
 
 Due to the 1/100 second tick of the system clock, "ms_post" time may be 
@@ -243,13 +243,13 @@
 
 In the example above, we got 18038 interrupts "on the fly" and only 1673 script 
 breaks probably due to disconnections inside a segment of the scatter list. 
-It is an excellent result due to the fact that the driver tries to use small 
+This is an excellent result due to the fact that the driver tries to use small 
 data segments (512) for the scatter list. The CPU load of this rescatter process 
-is acceptable. Unlike other scsi processors, NCR53C8XX controllers do not need  
-large data chunks in order to get better performances, and it seems that it 
-is the opposite.
-The scatter/gather algorithm of the middle scsi driver is not optimal for 
-NCR scsi processors and should be tunable according to host type.
+is acceptable. Unlike other SCSI processors, NCR53C8XX controllers do not need  
+large data chunks in order to get better performance, and it seems that it 
+is just the opposite.
+The scatter/gather algorithm of the middle SCSI driver is not optimal for 
+NCR SCSI processors and should be tunable according to host type.
 
 You can tune the "wished" segment size for the scatterlist by changing the 
 following "define" in the file ncr53c8xx.h.
@@ -261,7 +261,7 @@
 8. Control commands
 
 Control commands can be sent to the driver with write operations to the 
-proc scsi file system. The generic command syntax is the following:
+proc SCSI file system. The generic command syntax is the following:
 
       echo "<verb> <parameters>" >/proc/scsi/ncr53c8xx/0
       (assumes controller number is 0)
@@ -311,14 +311,14 @@
     setdebug <list of debug flags>
 
     Available debug flags:
-        alloc:   print infos about memory allocations (ccb, lcb)
-        queue:   print infos about insertions into the command start queue
+        alloc:   print info about memory allocations (ccb, lcb)
+        queue:   print info about insertions into the command start queue
         result:  print sense data on CHECK CONDITION status
-        scatter: print infos about the scatter process
-        scripts: print infos about the script binding process
+        scatter: print info about the scatter process
+        scripts: print info about the script binding process
 	tiny:    print minimal debugging information
-	timing:  print timing information of the ncr chip.
-	nego:    print information about scsi negotiations
+	timing:  print timing information of the NCR chip
+	nego:    print information about SCSI negotiations
 	phase:   print information on script interruptions
 
 
@@ -327,38 +327,38 @@
     clearprof
 
     The profile counters are automatically cleared when the amount of data 
-    transfered reach 1000 GB in order to avoid overflow.
-    The "clearprof" command allow to clear these counters at any time.
+    transfered reaches 1000 GB in order to avoid overflow.
+    The "clearprof" command allows you to clear these counters at any time.
 
 
 9. Configuration parameters
 
 If the firmware of all your devices is perfect enough, all the features 
 supported by the driver can be enabled at start-up.
-However, if only one has a flaw for some scsi feature, you can disable the 
+However, if only one has a flaw for some SCSI feature, you can disable the 
 support by the driver of this feature at linux start-up and enable this 
 feature after boot-up only for devices that support it safely.
 
 CONFIG_SCSI_NCR53C8XX_IOMAPPED       (default answer: n)
-    Answer "y" if you suspect your mother board to not allow memory mapped IO.
-    May slow down a little performances.
+    Answer "y" if you suspect your mother board to not allow memory mapped I/O.
+    May slow down performance a little.
 
 CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE    (default answer: n)
-    Answer "y" if you are sure that all your scsi devices that are able to 
+    Answer "y" if you are sure that all your SCSI devices that are able to 
     accept tagged commands will proceed safely.
 
 CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS (default answer: n)
-    This option allow to force asynchronous transfer mode for all scsi devices. 
+    This option forces asynchronous transfer mode for all SCSI devices. 
  
 CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO (default answer: n)
-    Force synchronous negotiation for all scsi-2 devices.
-    Some scsi-2 devices do not report this feature in byte 7 of inquiry 
-    response and however support it properly (TAMARACK scanners for example).
+    Force synchronous negotiation for all SCSI-2 devices.
+    Some SCSI-2 devices do not report this feature in byte 7 of inquiry 
+    response but do support it properly (TAMARACK scanners for example).
 
 CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT   (default and only reasonnable answer: n)
-    If you suspect a device of yours to not support properly disconnections,
-    you can answer "y". Then, all scsi devices will never disconnect the bus 
-    even while long scsi operations.
+    If you suspect a device of yours does not properly support disconnections,
+    you can answer "y". Then, all SCSI devices will never disconnect the bus 
+    even while performing long SCSI operations.
 
 
 10. Some constants and flags of the ncr53c8xx.h header files
@@ -368,17 +368,17 @@
 Do that only if you know what you are doing.
 
 SCSI_NCR_IOMAPPED		(default: not defined)
-	If defined, normal IO is forced.
+	If defined, normal I/O is forced.
 
 SCSI_NCR_SHARE_IRQ		(default: defined)
-	If defined, request shared irq.
+	If defined, request shared IRQ.
 	
 SCSI_NCR_MAX_TAGS		(default: 4)
 	Maximum number of simultaneous tagged commands to a device.
 	Can be changed by "settags <target> <maxtags>"
 
 SCSI_NCR_ALWAYS_SIMPLE_TAG	(default: defined)
-	Use SIMPLE TAG for read and write commands
+	Use SIMPLE TAG for read and write commands.
 	Can be changed by "setorder <ordered|simple|default>"
 
 SCSI_NCR_TAGGED_QUEUE_DISABLED	(default: defined)
@@ -389,38 +389,38 @@
 	If defined, targets are not allowed to disconnect.
 
 SCSI_NCR_FORCE_SYNC_NEGO	(default: not defined)
-	If defined, synchronous negotiation is tried for all scsi-2 devices.
+	If defined, synchronous negotiation is tried for all SCSI-2 devices.
 	Can be changed by "setsync <target> <period>"
 
 SCSI_NCR_DISABLE_MPARITY_CHECK	(default: not defined)
 	If defined, master parity checking is disabled.
 
 SCSI_NCR_DISABLE_PARITY_CHECK	(default: not defined)
-	If defined, scsi parity checking is disabled.
+	If defined, SCSI parity checking is disabled.
 
 SCSI_NCR_PROFILE		(default: defined)
-	If defined, profile information are gathered
+	If defined, profiling information is gathered.
 
 SCSI_NCR_MAX_SCATTER		(default: 128)
 	Scatter list size of the driver ccb.
 
 SCSI_NCR_SEGMENT_SIZE		(default: 512)
-	If defined, the driver try to use scatter segments of this size.
+	If defined, the driver will try to use scatter segments of this size.
 	If not defined, the Linux scatter list is used as is.
 
 SCSI_NCR_MAX_TARGET		(default: 16)
-	Max number of target per host.
+	Max number of targets per host.
 
 SCSI_NCR_MAX_HOST		(default: 2)
 	Max number of host controllers.
 
 SCSI_NCR_SETTLE_TIME		(default: 2)
-	Number of seconds the driver wait after reset.
+	Number of seconds the driver will wait after reset.
 
 SCSI_NCR_TIMEOUT_ALERT		(default: 3)
 	If a pending command will time out after this amount of seconds,
 	an ordered tag is used for the next command.
-	Avoid timeouts for unordered tagged commands.
+	Avoids timeouts for unordered tagged commands.
 
 SCSI_NCR_CAN_QUEUE		(default: 7*SCSI_NCR_MAX_TAGS)
 	Max number of commands that can be queued to a host.
@@ -432,7 +432,7 @@
 	Max size of the Linux scatter/gather list.
 
 SCSI_NCR_MAX_LUN	(default: 8)
-	Max number of luns per target
+	Max number of LUNs per target.
 
 
 11. Provided files
@@ -474,9 +474,9 @@
 
 This install script only supports linux-1.2.13 and linux-1.3.45 to 1.3.100.
 
-This procedure just move the standard driver files to SAVE_53 sub-directory 
+This procedure just moves the standard driver files to SAVE_53 sub-directory 
 of linux/drivers/scsi, copies the drivers file to that directory and patches 
-the scsi Makefile.
+the SCSI Makefile.
 The standard driver can be restored with Uninstall.ncr53c8xx
 
 	If your linux directory is at the standard location
@@ -497,7 +497,7 @@
 		Since release 1.3.90, additionnal configuation parameters 
 		have been added for the standard NCR driver.
 		Just reply Y or N as you want to these questions;
-		The NCR53C8XX driver ignore those parameters.
+		The NCR53C8XX driver ignores those parameters.
 
 	If you prefer the standard NCR driver of Linux:
 	just enter:
@@ -509,9 +509,9 @@
 
 13. Installation procedure for Linux version 2
 
-This procedure add the driver to the kernel tree.
+This procedure adds the driver to the kernel tree.
 Using "make config" you can choose between the standard driver and the BSD one.
-It is possible to configure the both drivers as module and to switch from one 
+It is possible to configure both drivers as modules and to switch from one 
 to the other at run time.
 Take care to unload the current driver module before loading the other one.
 
@@ -532,9 +532,9 @@
 
 14. Control commands under linux-1.2.13
 
-Profile data and control commands using the proc scsi file system are not 
+Profiling data and control commands using the proc SCSI file system are not 
 available for linux-1.2.13.
-The only control command available is "scsitag" which allows to enable 
+The only control command available is "scsitag" which allows you to enable
 tagged command queuing support after linux boot-up.
 
 Tagged command queueing is disabled by default at system startup.
@@ -549,19 +549,19 @@
 
 15.1 Tagged commands with Iomega Jaz device
 
-I never tried such devices, however it has been reported to me the following:
+I have not tried this device, however it has been reported to me the following:
 This device is capable of Tagged command queuing. However while spinning up,
-it rejects Tagged commands. This behaviour is conforms to 6.8.2 of scsi-2 
+it rejects Tagged commands. This behaviour is conforms to 6.8.2 of SCSI-2 
 specifications. The current behaviour of the driver in that situation is not 
 satisfying. So do not enable Tagged command queuing for devices that are able 
 to spin down.
-The other problems that may appear are timeouts. The only way to avoid timeouts 
+The other problem that may appear is timeouts. The only way to avoid timeouts 
 seems to edit linux/drivers/scsi/sd.c and to increase the current timeout 
 values.
 
 15.2 Tagged command queuing cannot be disabled at run time
 
-Once Tagged command queuing has been enabled, the driver will not allow to 
+Once Tagged command queuing has been enabled, the driver will not allow you to 
 disable this feature ("settags <target> 0" is not supported).
 This problem is due to some limitations of the code added to the Linux version 
 of the driver.
diff -u --recursive --new-file v2.0.20/linux/drivers/scsi/g_NCR5380.h linux/drivers/scsi/g_NCR5380.h
--- v2.0.20/linux/drivers/scsi/g_NCR5380.h	Mon Apr 29 17:14:19 1996
+++ linux/drivers/scsi/g_NCR5380.h	Sun Sep 15 13:21:20 1996
@@ -32,6 +32,8 @@
 #ifndef GENERIC_NCR5380_H
 #define GENERIC_NCR5380_H
 
+#include <linux/config.h>
+
 #define GENERIC_NCR5380_PUBLIC_RELEASE 1
 
 #ifdef NCR53C400
diff -u --recursive --new-file v2.0.20/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.0.20/linux/drivers/scsi/scsi.c	Mon Aug  5 10:13:52 1996
+++ linux/drivers/scsi/scsi.c	Mon Sep 16 13:05:18 1996
@@ -2116,7 +2116,19 @@
 		
 		host->last_reset = jiffies;
 		temp = host->hostt->reset(SCpnt, reset_flags);
-		host->last_reset = jiffies;
+		/*
+		  This test allows the driver to introduce an additional bus
+		  settle time delay by setting last_reset up to 20 seconds in
+		  the future.  In the normal case where the driver does not
+		  modify last_reset, it must be assumed that the actual bus
+		  reset occurred immediately prior to the return to this code,
+		  and so last_reset must be updated to the current time, so
+		  that the delay in internal_cmnd will guarantee at least a
+		  MIN_RESET_DELAY bus settle time.
+		*/
+		if ((host->last_reset < jiffies) || 
+		    (host->last_reset > (jiffies + 20 * HZ)))
+		  host->last_reset = jiffies;
 	    }
 	    else
 	    {
@@ -2125,7 +2137,9 @@
 		host->last_reset = jiffies;
 	        SCpnt->flags |= (WAS_RESET | IS_RESETTING);
 		temp = host->hostt->reset(SCpnt, reset_flags);
-		host->last_reset = jiffies;
+		if ((host->last_reset < jiffies) || 
+		    (host->last_reset > (jiffies + 20 * HZ)))
+		  host->last_reset = jiffies;
 		if (!host->block) host->host_busy--;
 	    }
 	    
diff -u --recursive --new-file v2.0.20/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.0.20/linux/drivers/scsi/sd.c	Sat Aug 10 10:03:15 1996
+++ linux/drivers/scsi/sd.c	Wed Sep 18 11:13:52 1996
@@ -428,7 +428,7 @@
 		   SCpnt->host->host_no, (int) SCpnt->channel, 
 		   (int) SCpnt->target, (int) SCpnt->lun);
 	    print_command(SCpnt->cmnd);
-	    print_sense("sr", SCpnt);
+	    print_sense("sd", SCpnt);
 	    SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
 	    requeue_sd_request(SCpnt);
 	    return;
diff -u --recursive --new-file v2.0.20/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.0.20/linux/drivers/scsi/sr.c	Wed Sep 11 17:57:14 1996
+++ linux/drivers/scsi/sr.c	Mon Sep 16 13:05:18 1996
@@ -859,8 +859,8 @@
 		    if (count+1 != SCpnt->use_sg) panic("Bad sr request list");
 		    break;
 		};
-		if (((long) sgpnt[count].address) + sgpnt[count].length > ISA_DMA_THRESHOLD &&
-		  SCpnt->host->unchecked_isa_dma) {
+		if (((long) sgpnt[count].address) + sgpnt[count].length - 1 >
+		    ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) {
 		    sgpnt[count].alt_address = sgpnt[count].address;
 		    /* We try to avoid exhausting the DMA pool, since it is easier
 		     * to control usage here.  In other places we might have a more
diff -u --recursive --new-file v2.0.20/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.0.20/linux/drivers/scsi/wd7000.c	Sun Sep  1 09:15:33 1996
+++ linux/drivers/scsi/wd7000.c	Mon Sep 16 13:05:18 1996
@@ -100,21 +100,33 @@
  *                                                           J.B. Jan 1994.
  *
  *
- *  Revision: 08/24/1996. by Miroslav Zagorac <zaga@fly.cc.fer.hr>
+ *  Revisions by Miroslav Zagorac <zaga@fly.cc.fer.hr>
+ *
+ *  08/24/1996.
  *
  *  Enhancement for wd7000_detect function has been made, so you don't have
- *  to enter BIOS ROM adress and IO port in initialisation data (see struct
- *  Config). We cannot detect IRQ and DMA for now, so we have to enter them
- *  as arguments while wd_7000 is detected. If someone has IRQ and DMA set
- *  to some other value, he can enter them in configuration without any
- *  problem. Also I wrote a function wd7000_setup, so now you can enter
- *  WD-7000 definition as kernel arguments, as in lilo.conf:
+ *  to enter BIOS ROM adress in initialisation data (see struct Config).
+ *  We cannot detect IRQ, DMA and I/O base address for now, so we have to
+ *  enter them as arguments while wd_7000 is detected. If someone has IRQ,
+ *  DMA or I/O base address set to some other value, he can enter them in
+ *  configuration without any problem. Also I wrote a function wd7000_setup,
+ *  so now you can enter WD-7000 definition as kernel arguments,
+ *  as in lilo.conf:
  *
- *     append="wd7000=IRQ,DMA"
+ *     append="wd7000=IRQ,DMA,IO"
  *
  *  PS: If card BIOS ROM is disabled, function wd7000_detect now will recognize
  *      adapter, unlike the old one. Anyway, BIOS ROM from WD7000 adapter is
- *      worthless for Linux. :)
+ *      useless for Linux. B^)
+ *
+ *
+ *  09/06/1996.
+ *
+ *  Autodetecting of I/O base address from wd7000_detect function is removed,
+ *  some little bugs removed, etc...
+ *
+ *  Thanks to Roger Scott for driver debugging.
+ *
  */
 
 #ifdef MODULE
@@ -232,18 +244,19 @@
  *  Standard Adapter Configurations - used by wd7000_detect
  */
 typedef struct {
-  int irq;			/* IRQ level */
-  int dma;			/* DMA channel */
+  int      irq;			/* IRQ level        */
+  int      dma;			/* DMA channel      */
+  unsigned iobase;		/* I/O base address */
 } Config;
 
 /*
  * Add here your configuration...
  */
 static const Config configs[] = {
-  { 15,  6 },			/* defaults for single adapter */
-  { 11,  5 },			/* defaults for second adapter */
-  {  9,  6 },			/* My configuretion (Zaga)     */
-  { -1, -1 }                    /* Empty slot                  */
+  { 15,  6, 0x350 },		/* defaults for single adapter */
+  { 11,  5, 0x320 },		/* defaults for second adapter */
+  {  7,  6, 0x350 },		/* My configuration (Zaga)     */
+  { -1, -1, 0x0   }		/* Empty slot                  */
 };
 #define NUM_CONFIGS (sizeof(configs)/sizeof(Config))
 
@@ -530,6 +543,7 @@
  */
 static short wd7000_setupIRQ[NUM_CONFIGS];
 static short wd7000_setupDMA[NUM_CONFIGS];
+static short wd7000_setupIO[NUM_CONFIGS];
 static short wd7000_card_num = 0;
 
 /*
@@ -541,14 +555,15 @@
  * Note: You can now set these options from the kernel's "command line".
  * The syntax is:
  *
- *     wd7000=IRQ,DMA
+ *     wd7000=IRQ,DMA,IO
  * eg:
- *     wd7000=15,6
+ *     wd7000=7,6,0x350
  *
  * will configure the driver for a WD-7000 controller
- * using IRQ 15 with a DMA channel 6.
+ * using IRQ 15 with a DMA channel 6, at IO base address 0x350.
  */
-void wd7000_setup (char *str, int *ints) {
+void wd7000_setup (char *str, int *ints)
+{
     short i, j;
 
     if (wd7000_card_num >= NUM_CONFIGS) {
@@ -558,16 +573,17 @@
         return;
     }
 
-    if (ints[0] != 2)
+    if (ints[0] != 3)
 	printk ("wd7000_setup: Error in command line!  "
-	        "Usage: wd7000=IRQ,DMA\n");
+	        "Usage: wd7000=IRQ,DMA,IO\n");
     else {
 	for (i = 0; i < NUM_IRQS; i++)
 	    if (ints[1] == wd7000_irq[i])
 		break;
 
 	if (i == NUM_IRQS) {
-	    printk ("wd7000_setup: invalid IRQ.\n");
+	    printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
+		    "invalid IRQ.\n", ints[1], ints[2], ints[3]);
 	    return;
 	}
 	else
@@ -577,29 +593,53 @@
 	    if (ints[2] == wd7000_dma[i])
 		break;
 
-	if (i == NUM_IRQS) {
-	    printk ("wd7000_setup: invalid DMA channel.\n");
+	if (i == NUM_DMAS) {
+	    printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
+		    "invalid DMA channel.\n", ints[1], ints[2], ints[3]);
 	    return;
 	}
 	else
 	    wd7000_setupDMA[wd7000_card_num] = ints[2];
 
+	for (i = 0; i < NUM_IOPORTS; i++)
+	    if (ints[3] == wd7000_iobase[i])
+		break;
+
+	if (i == NUM_IOPORTS) {
+	    printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
+		    "invalid I/O base address.\n", ints[1], ints[2], ints[3]);
+	    return;
+	}
+	else
+	    wd7000_setupIO[wd7000_card_num] = ints[3];
+
 	if (wd7000_card_num)
 	    for (i = 0; i < (wd7000_card_num - 1); i++)
 	        for (j = i + 1; j < wd7000_card_num; j++)
 	            if (wd7000_setupIRQ[i] == wd7000_setupIRQ[j]) {
-	                printk ("wd7000_setup: duplicated IRQ!\n");
+	                printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
+			        "duplicated IRQ!\n",
+				ints[1], ints[2], ints[3]);
 		        return;
 	            }
 	            else if (wd7000_setupDMA[i] == wd7000_setupDMA[j]) {
-	                printk ("wd7000_setup: duplicated DMA channel!\n");
+	                printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
+			        "duplicated DMA channel!\n",
+				ints[1], ints[2], ints[3]);
+		        return;
+	            }
+	            else if (wd7000_setupIO[i] == wd7000_setupIO[j]) {
+	                printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
+			        "duplicated I/O base address!\n",
+				ints[1], ints[2], ints[3]);
 		        return;
 	            }
 
 #ifdef DEBUG
-	printk ("wd7000_setup: IRQ=%d, DMA=%d\n",
+	printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x\n",
 	        wd7000_setupIRQ[wd7000_card_num],
-		wd7000_setupDMA[wd7000_card_num]);
+		wd7000_setupDMA[wd7000_card_num],
+		wd7000_setupIO[wd7000_card_num]);
 #endif
 
 	wd7000_card_num++;
@@ -675,16 +715,20 @@
 
 #define WAITnexttimeout 200  /* 2 seconds */
 
-#define WAIT(port, mask, allof, noneof)					\
- { register volatile unsigned WAITbits; 				\
-   register unsigned long WAITtimeout = jiffies + WAITnexttimeout;	\
-   while (1) {								\
-     WAITbits = inb(port) & (mask);					\
-     if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
-       break;                                                         	\
-     if (jiffies > WAITtimeout) goto fail;				\
-   }									\
- }
+static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned noneof)
+{
+    register unsigned WAITbits;
+    register unsigned long WAITtimeout = jiffies + WAITnexttimeout;
+
+    while (jiffies <= WAITtimeout) {
+     	WAITbits = inb (port) & mask;
+
+	if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
+	    return (0);
+    }
+
+    return (1);
+}
 
 
 static inline void delay( unsigned how_long )
@@ -697,17 +741,19 @@
 
 static inline int command_out(Adapter *host, unchar *cmd, int len)
 {
-    WAIT(host->iobase+ASC_STAT,ASC_STATMASK,CMD_RDY,0);
-    while (len--)  {
-	do  {
-	    outb(*cmd, host->iobase+ASC_COMMAND);
-	    WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
-	}  while (inb(host->iobase+ASC_STAT) & CMD_REJ);
-	cmd++;
+    if (! WAIT (host->iobase+ASC_STAT,ASC_STATMASK,CMD_RDY,0)) {
+	while (len--)  {
+	    do  {
+		outb(*cmd, host->iobase+ASC_COMMAND);
+		WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
+	    }  while (inb(host->iobase+ASC_STAT) & CMD_REJ);
+
+	    cmd++;
+	}
+
+	return 1;
     }
-    return 1;
 
-fail:
     printk("wd7000 command_out: WAIT failed(%d)\n", len+1);
     return 0;
 }
@@ -921,7 +967,7 @@
 static void wd7000_scsi_done(Scsi_Cmnd * SCpnt)
 {
 #ifdef DEBUG
-    printk("wd7000_scsi_done: 0x%06x\n",(long) SCpnt);
+    printk ("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt);
 #endif
     SCpnt->SCp.phase = 0;
 }
@@ -1121,16 +1167,20 @@
     int diag;
 
     /*
-       Reset the adapter - only.  The SCSI bus was initialized at power-up,
-       and we need to do this just so we control the mailboxes, etc.
-    */
+     *  Reset the adapter - only.  The SCSI bus was initialized at power-up,
+     *  and we need to do this just so we control the mailboxes, etc.
+     */
     outb(ASC_RES, host->iobase+ASC_CONTROL);
     delay(1);  /* reset pulse: this is 10ms, only need 25us */
     outb(0,host->iobase+ASC_CONTROL);
     host->control = 0;   /* this must always shadow ASC_CONTROL */
-    WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
 
-    if ((diag = inb(host->iobase+ASC_INTR_STAT)) != 1)  {
+    if (WAIT (host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+        printk ("wd7000_init: WAIT timed out.\n"); 
+        return 0;					/* 0 = not ok */
+    }
+
+    if ((diag = inb(host->iobase+ASC_INTR_STAT)) != 1) {
 	printk("wd7000_init: ");
 
 	switch (diag)  {
@@ -1167,7 +1217,11 @@
 	printk("wd7000_init: adapter initialization failed.\n"); 
 	return 0;
     }
-    WAIT(host->iobase+ASC_STAT, ASC_STATMASK, ASC_INIT, 0);
+
+    if (WAIT (host->iobase+ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
+        printk ("wd7000_init: WAIT timed out.\n"); 
+        return 0;
+    }
 
     if (request_irq(host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
 	printk("wd7000_init: can't get IRQ %d.\n", host->irq);
@@ -1188,10 +1242,6 @@
     }
 
     return 1;
-
-  fail:
-    printk("wd7000_init: WAIT timed out.\n"); 
-    return 0;					/* 0 = not ok */
 }
 
 
@@ -1226,8 +1276,9 @@
  */
 int wd7000_detect (Scsi_Host_Template *tpnt)
 {
-    short present = 0, biosaddr_ptr, iobase_ptr, cfg_ptr, sig_ptr, i;
+    short present = 0, biosaddr_ptr, cfg_ptr, sig_ptr, i, pass;
     short biosptr[NUM_CONFIGS];
+    unsigned iobase;
     Adapter *host = NULL;
     struct Scsi_Host *sh;
 
@@ -1240,14 +1291,14 @@
      */
     init_scbs ();
 
-    for (cfg_ptr = 0; cfg_ptr < NUM_CONFIGS; cfg_ptr++) {
+    for (pass = 0, cfg_ptr = 0; pass < NUM_CONFIGS; pass++) {
         for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
 	    for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {
-	        for (i = 0; i < cfg_ptr; i++)
+	        for (i = 0; i < pass; i++)
 	            if (biosptr[i] == biosaddr_ptr)
 		        break;
 
-		if ((i == cfg_ptr) &&
+		if ((i == pass) &&
 		    !memcmp ((void *) (wd7000_biosaddr[biosaddr_ptr] +
 		             signatures[sig_ptr].ofs), signatures[sig_ptr].sig,
 		             signatures[sig_ptr].len))
@@ -1257,7 +1308,7 @@
 bios_matched:
 
 #ifdef DEBUG
-	printk ("wd7000_detect: pass %d\n", cfg_ptr + 1);
+	printk ("wd7000_detect: pass %d\n", pass + 1);
 
         if (biosaddr_ptr == NUM_ADDRS)
 	    printk ("WD-7000 SST BIOS not detected...\n");
@@ -1266,91 +1317,122 @@
 	            wd7000_biosaddr[biosaddr_ptr]);
 #endif
 
-	for (iobase_ptr = 0; iobase_ptr < NUM_IOPORTS; iobase_ptr++)
-	    if (! check_region (wd7000_iobase[iobase_ptr], 4)) {
-	        /*
-		 * ASC reset...
-		 */
- 	        outb (ASC_RES, wd7000_iobase[iobase_ptr] + ASC_CONTROL);
-	        delay (1);
-	        outb (0, wd7000_iobase[iobase_ptr] + ASC_CONTROL);
-	        WAIT (wd7000_iobase[iobase_ptr] + ASC_STAT, ASC_STATMASK,
-		      CMD_RDY, 0);
-
-		if (inb (wd7000_iobase[iobase_ptr] + ASC_INTR_STAT) == 1) {
-		   /*
-		    *  We register here, to get a pointer to the extra space,
-		    *  which we'll use as the Adapter structure (host) for
-		    *  this adapter.  It is located just after the registered
-		    *  Scsi_Host structure (sh), and is located by the empty
-		    *  array hostdata.
-		    */
-	    	    sh = scsi_register (tpnt, sizeof (Adapter));
-	    	    host = (Adapter *) sh->hostdata;
+	if (wd7000_card_num) 
+	    iobase = wd7000_setupIO[wd7000_card_num - 1];
+	else {
+	    if (configs[cfg_ptr++].irq < 0)
+		continue;
+
+	    iobase = configs[cfg_ptr - 1].iobase;
+	}
 
 #ifdef DEBUG
-	    	    printk ("wd7000_detect: adapter allocated at 0x%x\n",
-	    		    (int) host);
+ 	printk ("wd7000_detect: check IO 0x%x region...\n", iobase);
 #endif
 
-	    	    memset (host, 0, sizeof (Adapter));
-
-		    if (wd7000_card_num) {
-	    	        host->irq = wd7000_setupIRQ[--wd7000_card_num];
-	    	        host->dma = wd7000_setupDMA[wd7000_card_num];
-		    }
-		    else {
-	    	        host->irq = configs[cfg_ptr].irq;
-	    	        host->dma = configs[cfg_ptr].dma;
-		    }
-
-	    	    host->sh = sh;
-	    	    host->iobase = wd7000_iobase[iobase_ptr];
-	    	    irq2host[host->irq] = host;
+	if (! check_region (iobase, 4)) {
 
 #ifdef DEBUG
-		    printk ("wd7000_detect: Trying init WD-7000 card at IO "
-			    "0x%x, IRQ %d, DMA %d...\n",
-			    host->iobase, host->irq, host->dma);
+ 	    printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
 #endif
 
-	    	    if (! wd7000_init (host)) {  /* Initialization failed */
-	    		scsi_unregister (sh);
+ 	    /*
+  	     * ASC reset...
+ 	     */
+ 	    outb (ASC_RES, iobase + ASC_CONTROL);
+ 	    delay (1);
+ 	    outb (0, iobase + ASC_CONTROL);
+
+ 	    if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0))
+#ifdef DEBUG
+ 	    {
+  		printk ("failed!\n");
+  		continue;
+ 	    }
+ 	    else
+  		printk ("ok!\n");
+#else
+	    continue;
+#endif
 
-	    		continue;
-	    	    }
+	    if (inb (iobase + ASC_INTR_STAT) == 1) {
+		/*
+		 *  We register here, to get a pointer to the extra space,
+		 *  which we'll use as the Adapter structure (host) for
+		 *  this adapter.  It is located just after the registered
+		 *  Scsi_Host structure (sh), and is located by the empty
+		 *  array hostdata.
+		 */
+		sh = scsi_register (tpnt, sizeof (Adapter));
+		host = (Adapter *) sh->hostdata;
 
-		    /*
-		     *  OK from here - we'll use this adapter/configuration.
-		     */
-		    wd7000_revision (host);   /* important for scatter/gather */
+#ifdef DEBUG
+		printk ("wd7000_detect: adapter allocated at 0x%x\n",
+			(int) host);
+#endif
 
-                    /*
-		     * Register our ports.
-		     */
-    		    request_region (host->iobase, 4, "wd7000");
+		memset (host, 0, sizeof (Adapter));
 
-    		    /*
-    		     *  For boards before rev 6.0, scatter/gather
-		     *  isn't supported.
-    		     */
-    		    if (host->rev1 < 6)
-   		       sh->sg_tablesize = SG_NONE;
+		if (wd7000_card_num) {
+		    host->irq = wd7000_setupIRQ[--wd7000_card_num];
+		    host->dma = wd7000_setupDMA[wd7000_card_num];
+		}
+		else {
+		    host->irq = configs[cfg_ptr - 1].irq;
+		    host->dma = configs[cfg_ptr - 1].dma;
+		}
 
-    		    present++;		/* count it */
+	    	host->sh = sh;
+    		host->iobase = iobase;
+		irq2host[host->irq] = host;
 
-		    if (biosaddr_ptr != NUM_ADDRS)
-                        biosptr[cfg_ptr] = biosaddr_ptr;
+#ifdef DEBUG
+		printk ("wd7000_detect: Trying init WD-7000 card at IO "
+			"0x%x, IRQ %d, DMA %d...\n",
+			host->iobase, host->irq, host->dma);
+#endif
 
-                    printk ("Western Digital WD-7000 (rev %d.%d) ",
-			    host->rev1, host->rev2);
-                    printk ("using IO 0x%xh, IRQ %d, DMA %d.\n", 
-	                    host->iobase, host->irq, host->dma);
+		if (! wd7000_init (host)) {  /* Initialization failed */
+		    scsi_unregister (sh);
 
-	    	    break;
+		    continue;
 		}
-fail:
+
+		/*
+		 *  OK from here - we'll use this adapter/configuration.
+		 */
+		wd7000_revision (host);   /* important for scatter/gather */
+
+		/*
+		 * Register our ports.
+		 */
+		request_region (host->iobase, 4, "wd7000");
+
+		/*
+		 *  For boards before rev 6.0, scatter/gather
+		 *  isn't supported.
+		 */
+		if (host->rev1 < 6)
+		    sh->sg_tablesize = SG_NONE;
+
+		present++;		/* count it */
+
+		if (biosaddr_ptr != NUM_ADDRS)
+		    biosptr[pass] = biosaddr_ptr;
+
+		printk ("Western Digital WD-7000 (rev %d.%d) ",
+			host->rev1, host->rev2);
+		printk ("using IO 0x%x, IRQ %d, DMA %d.\n", 
+			host->iobase, host->irq, host->dma);
 	    }
+	}
+
+#ifdef DEBUG
+	else
+ 	    printk ("wd7000_detect: IO 0x%x region already allocated!\n",
+		    iobase);
+#endif
+
     }
 
     if (! present)
diff -u --recursive --new-file v2.0.20/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v2.0.20/linux/drivers/sound/Readme.cards	Sat Jul  6 11:31:43 1996
+++ linux/drivers/sound/Readme.cards	Mon Sep 16 13:05:18 1996
@@ -1036,5 +1036,5 @@
   European/Finnish mirror: http://personal.eunet.fi/pp/voxware
 
 www home page of commercial
-UNIX Sound System drivers: http://www.4front-tech.com/uss.html
+Open Sound System drivers: http://www.4front-tech.com/uss.html
 
diff -u --recursive --new-file v2.0.20/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.0.20/linux/drivers/sound/dev_table.h	Sun Jul  7 11:18:51 1996
+++ linux/drivers/sound/dev_table.h	Sun Sep 15 13:21:20 1996
@@ -15,6 +15,7 @@
 #ifndef _DEV_TABLE_H_
 #define _DEV_TABLE_H_
 
+#include <linux/config.h>
 
 /*
  * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h)
diff -u --recursive --new-file v2.0.20/linux/fs/binfmt_java.c linux/fs/binfmt_java.c
--- v2.0.20/linux/fs/binfmt_java.c	Mon May 13 07:17:23 1996
+++ linux/fs/binfmt_java.c	Sat Sep 14 11:08:07 1996
@@ -10,7 +10,6 @@
 #include <linux/stat.h>
 #include <linux/malloc.h>
 #include <linux/binfmts.h>
-#include <paths.h>
 
 #define _PATH_JAVA	"/usr/bin/java"
 #define _PATH_APPLET	"/usr/bin/appletviewer"
@@ -93,7 +92,7 @@
 
 	/*
 	 * OK, we've set the interpreter name
-	 * Splice in (1) the interpreter's name for argv[0] (_PATH_BSHELL)
+	 * Splice in (1) the interpreter's name for argv[0] (_PATH_SH)
 	 *           (2) the name of the appletviewer wrapper for argv[1] (_PATH_APPLET)
 	 *           (3) filename of html file (replace argv[0])
 	 *
diff -u --recursive --new-file v2.0.20/linux/fs/buffer.c linux/fs/buffer.c
--- v2.0.20/linux/fs/buffer.c	Sun Sep  8 19:50:21 1996
+++ linux/fs/buffer.c	Fri Sep 20 12:52:39 1996
@@ -69,6 +69,7 @@
 int nr_free[NR_SIZES] = {0,};
 int buffermem = 0;
 int nr_buffer_heads = 0;
+int refilled = 0;       /* Set NZ when a buffer freelist is refilled */
 extern int *blksize_size[];
 
 /* Here is the parameter block for the bdflush process. If you add or
@@ -493,7 +494,7 @@
 		bh->b_count++;
 		wait_on_buffer(bh);
 		if (bh->b_dev == dev && bh->b_blocknr == block
-		                             && bh->b_size == size)
+					     && bh->b_size == size)
 			return bh;
 		bh->b_count--;
 	}
@@ -512,7 +513,7 @@
 
 	switch (size) {
 		default: panic("Invalid blocksize passed to set_blocksize");
-	        case 512: case 1024: case 2048: case 4096: case 8192: ;
+		case 512: case 1024: case 2048: case 4096: case 8192: ;
 	}
 
 	if (blksize_size[MAJOR(dev)][MINOR(dev)] == 0 && size == BLOCK_SIZE) {
@@ -568,6 +569,7 @@
 	if (nr_free[isize] > 100)
 		return;
 
+	++refilled;
 	/* If there are too many dirty buffers, we wake up the update process
 	   now so as to ensure that there are still clean buffers available
 	   for user processes to use (and dirty) */
@@ -723,7 +725,7 @@
 	
 	if (nr_free_pages > min_free_pages + 5) {
 		if (grow_buffers(GFP_BUFFER, size)) {
-	                needed -= PAGE_SIZE;
+			needed -= PAGE_SIZE;
 			goto repeat0;
 		};
 	}
@@ -810,6 +812,7 @@
 void refile_buffer(struct buffer_head * buf)
 {
 	int dispose;
+	int isize;
 
 	if(buf->b_dev == B_FREE) {
 		printk("Attempt to refile free buffer\n");
@@ -835,10 +838,21 @@
 		remove_from_queues(buf);
 		buf->b_list = dispose;
 		insert_into_queues(buf);
-		if(dispose == BUF_DIRTY && nr_buffers_type[BUF_DIRTY] > 
+		if (dispose == BUF_DIRTY) {
+		/* This buffer is dirty, maybe we need to start flushing. */
+		/* If too high a percentage of the buffers are dirty... */
+		if (nr_buffers_type[BUF_DIRTY] > 
 		   (nr_buffers - nr_buffers_type[BUF_SHARED]) *
 		   bdf_prm.b_un.nfract/100)
 			 wakeup_bdflush(0);
+		/* If this is a loop device, and
+		 * more than half of the buffers of this size are dirty... */ 
+		/* (Prevents no-free-buffers deadlock with loop device.) */
+		isize = BUFSIZE_INDEX(buf->b_size);
+		if (MAJOR(buf->b_dev) == LOOP_MAJOR &&
+		    nr_buffers_st[isize][BUF_DIRTY]*2>nr_buffers_size[isize])
+			wakeup_bdflush(1);
+		}
 	}
 }
 
@@ -924,7 +938,7 @@
 	index = BUFSIZE_INDEX(bh->b_size);
 
 	if (buffer_uptodate(bh))
-	        return(bh);   
+		return(bh);   
 	else ll_rw_block(READ, 1, &bh);
 
 	blocks = (filesize - pos) >> (9+index);
@@ -952,7 +966,7 @@
 	if (j>1)  
 		ll_rw_block(READA, (j-1), bhlist+1); 
 	for(i=1; i<j; i++)
-	        brelse(bhlist[i]);
+		brelse(bhlist[i]);
 
 	/* Wait for this buffer, and then continue on */
 	bh = bhlist[0];
@@ -1371,7 +1385,7 @@
 
 	tmp = bh;
 	while (1) {
-	        nr_free[isize]++;
+		nr_free[isize]++;
 		if (insert_point) {
 			tmp->b_next_free = insert_point->b_next_free;
 			tmp->b_prev_free = insert_point;
@@ -1383,6 +1397,7 @@
 		}
 		insert_point = tmp;
 		++nr_buffers;
+		++nr_buffers_size[isize];
 		if (tmp->b_this_page)
 			tmp = tmp->b_this_page;
 		else
@@ -1412,7 +1427,7 @@
 {
 	unsigned long page;
 	struct buffer_head * tmp, * p;
-        int isize = BUFSIZE_INDEX(bh->b_size);
+	int isize = BUFSIZE_INDEX(bh->b_size);
 
 	*bhp = bh;
 	page = (unsigned long) bh->b_data;
@@ -1607,8 +1622,8 @@
 				continue;
 			}
 			/* At priority 6, only consider really old
-                           (age==0) buffers for reclaiming.  At
-                           priority 0, consider any buffers. */
+			   (age==0) buffers for reclaiming.  At
+			   priority 0, consider any buffers. */
 			if ((age_of((unsigned long) bh->b_data) >>
 			     (6-priority)) > 0)
 				continue;				
@@ -1733,7 +1748,7 @@
 		     unsigned int starting_block, int size)
 {
 	struct buffer_head *bh;
-        int isize = BUFSIZE_INDEX(size);
+	int isize = BUFSIZE_INDEX(size);
 	int i;
 
 	/* We want to give ourselves a really good shot at generating
@@ -1759,7 +1774,7 @@
 static unsigned long try_to_generate_cluster(kdev_t dev, int block, int size)
 {
 	struct buffer_head * bh, * tmp, * arr[MAX_BUF_PER_PAGE];
-        int isize = BUFSIZE_INDEX(size);
+	int isize = BUFSIZE_INDEX(size);
 	unsigned long offset;
 	unsigned long page;
 	int nblock;
@@ -1886,9 +1901,12 @@
  */
 struct wait_queue * bdflush_wait = NULL;
 struct wait_queue * bdflush_done = NULL;
+struct task_struct *bdflush_tsk = 0;
 
 static void wakeup_bdflush(int wait)
 {
+	if (current == bdflush_tsk)
+		return;
 	wake_up(&bdflush_wait);
 	if (wait) {
 		run_task_queue(&tq_disk);
@@ -2018,6 +2036,14 @@
  * the syscall above, but now we launch it ourselves internally with
  * kernel_thread(...)  directly after the first thread in init/main.c */
 
+/* To prevent deadlocks for a loop device:
+ * 1) Do non-blocking writes to loop (avoids deadlock with running
+ *	out of request blocks).
+ * 2) But do a blocking write if the only dirty buffers are loop buffers
+ *	(otherwise we go into an infinite busy-loop).
+ * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
+ *	with running out of free buffers for loop's "real" device).
+*/
 int bdflush(void * unused) 
 {
 	int i;
@@ -2025,6 +2051,8 @@
 	int nlist;
 	int ncount;
 	struct buffer_head * bh, *next;
+	int major;
+	int wrta_cmd = WRITEA;	/* non-blocking write for LOOP */
 
 	/*
 	 *	We have a bare-bones task_struct, and really should fill
@@ -2035,6 +2063,7 @@
 	current->session = 1;
 	current->pgrp = 1;
 	sprintf(current->comm, "kflushd");
+	bdflush_tsk = current;
 
 	/*
 	 *	As a kernel thread we want to tamper with system buffers
@@ -2060,6 +2089,7 @@
 #endif
 		 {
 			 ndirty = 0;
+			 refilled = 0;
 		 repeat:
 			 bh = lru_list[nlist];
 			 if(bh) 
@@ -2082,11 +2112,21 @@
 					  
 					  if (buffer_locked(bh) || !buffer_dirty(bh))
 						   continue;
+					  major = MAJOR(bh->b_dev);
 					  /* Should we write back buffers that are shared or not??
 					     currently dirty buffers are not shared, so it does not matter */
+					  if (refilled && major == LOOP_MAJOR)
+						   continue;
 					  bh->b_count++;
 					  ndirty++;
 					  bh->b_flushtime = 0;
+					  if (major == LOOP_MAJOR) {
+						  ll_rw_block(wrta_cmd,1, &bh);
+						  wrta_cmd = WRITEA;
+						  if (buffer_dirty(bh))
+							  --ndirty;
+					  }
+					  else
 					  ll_rw_block(WRITE, 1, &bh);
 #ifdef DEBUG
 					  if(nlist != BUF_DIRTY) ncount++;
@@ -2098,6 +2138,14 @@
 		if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount);
 		printk("sleeping again.\n");
 #endif
+		/* If we didn't write anything, but there are still
+		 * dirty buffers, then make the next write to a
+		 * loop device to be a blocking write.
+		 * This lets us block--which we _must_ do! */
+		if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0) {
+			wrta_cmd = WRITE;
+			continue;
+		}
 		run_task_queue(&tq_disk);
 		wake_up(&bdflush_done);
 		
diff -u --recursive --new-file v2.0.20/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.0.20/linux/fs/ext2/namei.c	Wed Jul 10 13:11:15 1996
+++ linux/fs/ext2/namei.c	Fri Sep 20 13:17:18 1996
@@ -519,7 +519,7 @@
 	inode->i_nlink = 2;
 	mark_buffer_dirty(dir_block, 1);
 	brelse (dir_block);
-	inode->i_mode = S_IFDIR | (mode & S_IRWXUGO & ~current->fs->umask);
+	inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
 	inode->i_dirt = 1;
diff -u --recursive --new-file v2.0.20/linux/fs/locks.c linux/fs/locks.c
--- v2.0.20/linux/fs/locks.c	Sun Sep  1 09:15:33 1996
+++ linux/fs/locks.c	Wed Sep 18 11:40:58 1996
@@ -128,21 +128,20 @@
 static char *lock_get_status(struct file_lock *fl, char *p, int id, char *pfx);
 
 static struct file_lock *file_lock_table = NULL;
+static struct file_lock *unused_file_locks = NULL;
 
-/* Free lock not inserted in any queue */
+/*
+ * Free lock not inserted in any queue
+ *
+ * Careful! We can't just "kfree()" it: there may be other processes
+ * that have yet to remove themselves from the wait queues. Thus the
+ * internal memory management.
+ */
 static inline void locks_free_lock(struct file_lock *fl)
 {
-	/*
-	 * CAREFUL! We can't free it until everybody waiting for
-	 * this block have removed themselves from the wait queue
-	 */
-	if (fl->fl_wait) {
-		struct wait_queue *head = WAIT_QUEUE_HEAD(&fl->fl_wait);
-		while (fl->fl_wait != head)
-			schedule();
-	}
-	kfree(fl);
-	return;
+	struct file_lock *next = unused_file_locks;
+	unused_file_locks = fl;
+	fl->fl_next = next;
 }
 
 /* Add lock fl to the blocked list pointed to by block.
@@ -914,26 +913,30 @@
 
 static struct file_lock *locks_alloc_lock(struct file_lock *fl)
 {
-	struct file_lock *tmp;
+	struct file_lock *retval;
 
-	/* Okay, let's make a new file_lock structure... */
-	if ((tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock),
-					       GFP_ATOMIC)) == NULL)
-		return (tmp);
-
-	tmp->fl_nextlink = NULL;
-	tmp->fl_prevlink = NULL;
-	tmp->fl_next = NULL;
-	tmp->fl_block = NULL;
-	tmp->fl_flags = fl->fl_flags;
-	tmp->fl_owner = fl->fl_owner;
-	tmp->fl_file = fl->fl_file;
-	tmp->fl_wait = NULL;
-	tmp->fl_type = fl->fl_type;
-	tmp->fl_start = fl->fl_start;
-	tmp->fl_end = fl->fl_end;
-
-	return (tmp);
+	retval = unused_file_locks;
+	if (retval) {
+		unused_file_locks = retval->fl_next;
+		goto init_file_lock;
+	}
+	retval = (struct file_lock *)
+		kmalloc(sizeof(struct file_lock), GFP_ATOMIC);
+	if (retval) {
+		retval->fl_wait = NULL;
+init_file_lock:
+		retval->fl_next = NULL;
+		retval->fl_nextlink = NULL;
+		retval->fl_prevlink = NULL;
+		retval->fl_block = NULL;
+		retval->fl_owner = fl->fl_owner;
+		retval->fl_file = fl->fl_file;
+		retval->fl_flags = fl->fl_flags;
+		retval->fl_type = fl->fl_type;
+		retval->fl_start = fl->fl_start;
+		retval->fl_end = fl->fl_end;		
+	}
+	return retval;
 }
 
 /* Insert file lock fl into an inode's lock list at the position indicated
diff -u --recursive --new-file v2.0.20/linux/fs/namei.c linux/fs/namei.c
--- v2.0.20/linux/fs/namei.c	Wed Sep 11 17:57:15 1996
+++ linux/fs/namei.c	Fri Sep 20 13:17:18 1996
@@ -585,7 +585,7 @@
 	if (dir->i_sb && dir->i_sb->dq_op)
 		dir->i_sb->dq_op->initialize(dir, -1);
 	down(&dir->i_sem);
-	error = dir->i_op->mkdir(dir, basename, namelen, mode & 0777 & ~current->fs->umask);
+	error = dir->i_op->mkdir(dir, basename, namelen, mode & 01777 & ~current->fs->umask);
 	up(&dir->i_sem);
 	iput(dir);
 	return error;
diff -u --recursive --new-file v2.0.20/linux/fs/super.c linux/fs/super.c
--- v2.0.20/linux/fs/super.c	Wed Sep 11 17:57:16 1996
+++ linux/fs/super.c	Fri Sep 20 13:17:18 1996
@@ -948,7 +948,7 @@
 				current->fs->root = inode;
 				ROOT_DEV = sb->s_dev;
 				printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
-				vfsmnt = add_vfsmnt(ROOT_DEV, "rootfs", "/");
+				vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
 				if (!vfsmnt)
 					panic("VFS: add_vfsmnt failed for NFS root.\n");
 				vfsmnt->mnt_sb = sb;
@@ -1010,7 +1010,7 @@
 			printk ("VFS: Mounted root (%s filesystem)%s.\n",
 				fs_type->name,
 				(sb->s_flags & MS_RDONLY) ? " readonly" : "");
-			vfsmnt = add_vfsmnt(ROOT_DEV, "rootfs", "/");
+			vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
 			if (!vfsmnt)
 				panic("VFS: add_vfsmnt failed for root fs");
 			vfsmnt->mnt_sb = sb;
@@ -1075,7 +1075,7 @@
 	}
 	iput(old_root); /* sb->s_covered */
 	remove_vfsmnt(old_root_dev);
-	vfsmnt = add_vfsmnt(old_root_dev,"old_rootfs",put_old);
+	vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old);
 	if (!vfsmnt) printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");
 	else {
 		vfsmnt->mnt_sb = old_root->i_sb;
diff -u --recursive --new-file v2.0.20/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- v2.0.20/linux/include/asm-i386/semaphore.h	Sun Sep 15 10:34:18 1996
+++ linux/include/asm-i386/semaphore.h	Sat Sep 14 11:18:46 1996
@@ -34,7 +34,7 @@
 	__asm__ __volatile__(
 		"# atomic down operation\n"
 		"1:\n\t"
-		"leal 1b,%%eax\n\t"
+		"movl $1b,%%eax\n\t"
 #ifdef __SMP__
 		"lock ; "
 #endif
@@ -55,7 +55,7 @@
 {
 	__asm__ __volatile__(
 		"# atomic up operation\n\t"
-		"leal 1f,%%eax\n\t"
+		"movl $1f,%%eax\n\t"
 #ifdef __SMP__
 		"lock ; "
 #endif
diff -u --recursive --new-file v2.0.20/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.0.20/linux/include/linux/cdrom.h	Thu May  9 10:35:12 1996
+++ linux/include/linux/cdrom.h	Wed Sep 18 11:13:53 1996
@@ -280,6 +280,8 @@
 
 /*
  * For controlling a changer.  (Used by ATAPI driver.)
+ * This ioctl is depreciated in favor of CDROM_SELECT_DISC from
+ * ucdrom.h.  It will probably be deleted during the 2.1 kernel series.
  */
 #define CDROMLOADFROMSLOT	0x531a	/* LOAD disk from slot*/
 
diff -u --recursive --new-file v2.0.20/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.0.20/linux/include/linux/fs.h	Wed Sep 11 17:57:18 1996
+++ linux/include/linux/fs.h	Fri Sep 20 16:23:18 1996
@@ -50,8 +50,8 @@
 
 #define READ 0
 #define WRITE 1
-#define READA 2		/* read-ahead - don't pause */
-#define WRITEA 3	/* "write-ahead" - silly, but somewhat useful */
+#define READA 2		/* read-ahead  - don't block if no resources */
+#define WRITEA 3	/* write-ahead - don't block if no resources */
 
 #ifndef NULL
 #define NULL ((void *) 0)
diff -u --recursive --new-file v2.0.20/linux/include/net/ip_masq.h linux/include/net/ip_masq.h
--- v2.0.20/linux/include/net/ip_masq.h	Thu Jul 25 20:32:32 1996
+++ linux/include/net/ip_masq.h	Fri Sep 20 15:26:37 1996
@@ -14,7 +14,7 @@
  *	I used an extra 4K port-space
  */
  
-#define PORT_MASQ_BEGIN	60000
+#define PORT_MASQ_BEGIN	61000
 #define PORT_MASQ_END	(PORT_MASQ_BEGIN+4096)
 
 #define MASQUERADE_EXPIRE_TCP     15*60*HZ
diff -u --recursive --new-file v2.0.20/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.0.20/linux/scripts/Menuconfig	Wed Jul 10 07:48:35 1996
+++ linux/scripts/Menuconfig	Mon Sep 16 13:07:00 1996
@@ -546,7 +546,7 @@
 			printf("}\n") >>menu
 			return
 		} 
-		else if ($0 ~ /^#|$MAKE|mainmenu_name/) {
+		else if ($0 ~ /^#|\$MAKE|mainmenu_name/) {
 			printf("") >>menu
 		}
 		else if ($1 == "source") {
diff -u --recursive --new-file v2.0.20/linux/scripts/mkdep.c linux/scripts/mkdep.c
--- v2.0.20/linux/scripts/mkdep.c	Thu Jan  1 02:00:00 1970
+++ linux/scripts/mkdep.c	Fri Sep 20 16:25:03 1996
@@ -0,0 +1,274 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+
+char *filename, *command, __depname[256] = "\n\t@touch ";
+int needsconfig, hasconfig, hasdep;
+
+#define depname (__depname+9)
+
+struct path_struct {
+	int len;
+	char buffer[256-sizeof(int)];
+} path_array[2] = {
+	{ 23, "/usr/src/linux/include/" },
+	{  0, "" }
+};
+
+static void handle_include(int type, char *name, int len)
+{
+	int plen;
+	struct path_struct *path = path_array+type;
+
+	if (len == 14 && !memcmp(name, "linux/config.h", len))
+		hasconfig = 1;
+
+	plen = path->len;
+	memcpy(path->buffer+plen, name, len);
+	len += plen;
+	path->buffer[len] = '\0';
+	if (access(path->buffer, F_OK))
+		return;
+
+	if (!hasdep) {
+		hasdep = 1;
+		printf("%s:", depname);
+	}
+	printf(" \\\n   %s", path->buffer);
+}
+
+static void handle_config(void)
+{
+	needsconfig = 1;
+	if (!hasconfig)
+		fprintf(stderr,
+			"%s needs config but has not included config file\n",
+			filename);
+}
+
+#if defined(__alpha__) || defined(__i386__)
+#define LE_MACHINE
+#endif
+
+#ifdef LE_MACHINE
+#define first_byte(x) current = (unsigned char) x; x >>= 8;
+#else
+#define first_byte(x) current = x >> 8*(sizeof(unsigned long)-1); x <<= 8;
+#endif
+
+#define GETNEXT { \
+if (!__buf) { \
+	__buf = *(unsigned long *) next; \
+	if (!__buf) \
+		break; \
+} first_byte(__buf); next++; }
+#define CASE(c,label) if (current == c) goto label
+#define NOTCASE(c,label) if (current != c) goto label
+
+static void state_machine(char *next)
+{
+	for(;;) {
+	unsigned long __buf = 0;
+	unsigned char current;
+
+normal:
+	GETNEXT
+__normal:
+	CASE('/',slash);
+	CASE('"',string);
+	CASE('\'',char_const);
+	CASE('#',preproc);
+	goto normal;
+
+slash:
+	GETNEXT
+	CASE('*',comment);
+	goto __normal;
+
+string:
+	GETNEXT
+	CASE('"',normal);
+	NOTCASE('\\',string);
+	GETNEXT
+	goto string;
+
+char_const:
+	GETNEXT
+	CASE('\'',normal);
+	NOTCASE('\\',char_const);
+	GETNEXT
+	goto char_const;
+
+comment:
+	GETNEXT
+__comment:
+	NOTCASE('*',comment);
+	GETNEXT
+	CASE('/',normal);
+	goto __comment;
+
+preproc:
+	GETNEXT
+	CASE('\n',normal);
+	CASE(' ',preproc);
+	CASE('\t',preproc);
+	CASE('i',i_preproc);
+	GETNEXT
+
+skippreproc:
+	CASE('\n',normal);
+	CASE('\\',skippreprocslash);
+	GETNEXT
+	goto skippreproc;
+
+skippreprocslash:
+	GETNEXT;
+	GETNEXT;
+	goto skippreproc;
+
+i_preproc:
+	GETNEXT
+	CASE('f',if_line);
+	NOTCASE('n',skippreproc);
+	GETNEXT
+	NOTCASE('c',skippreproc);
+	GETNEXT
+	NOTCASE('l',skippreproc);
+	GETNEXT
+	NOTCASE('u',skippreproc);
+	GETNEXT
+	NOTCASE('d',skippreproc);
+	GETNEXT
+	NOTCASE('e',skippreproc);
+
+/* "# include" found */
+include_line:
+	GETNEXT
+	CASE('\n',normal);
+	CASE('<', std_include_file);
+	NOTCASE('"', include_line);
+
+/* "local" include file */
+{
+	char *incname = next;
+local_include_name:
+	GETNEXT
+	CASE('\n',normal);
+	NOTCASE('"', local_include_name);
+	handle_include(1, incname, next-incname-1);
+	goto skippreproc;
+}
+
+/* <std> include file */
+std_include_file:
+{
+	char *incname = next;
+std_include_name:
+	GETNEXT
+	CASE('\n',normal);
+	NOTCASE('>', std_include_name);
+	handle_include(0, incname, next-incname-1);
+	goto skippreproc;
+}
+
+if_line:
+	if (needsconfig)
+		goto skippreproc;
+if_start:
+	if (!memcmp("CONFIG_", next, 7)) {
+		handle_config();
+		goto skippreproc;
+	}
+	GETNEXT
+	CASE('\n', normal);
+	CASE('_', if_middle);
+	if (current >= 'a' && current <= 'z')
+		goto if_middle;
+	if (current < 'A' || current > 'Z')
+		goto if_start;
+if_middle:
+	GETNEXT
+	CASE('\n', normal);
+	CASE('_', if_middle);
+	if (current >= 'a' && current <= 'z')
+		goto if_middle;
+	if (current < 'A' || current > 'Z')
+		goto if_start;
+	goto if_middle;
+	}
+}
+
+static void do_depend(void)
+{
+	char *map;
+	int mapsize;
+	int pagesizem1 = getpagesize()-1;
+	int fd = open(filename, O_RDONLY);
+	struct stat st;
+
+	if (fd < 0) {
+		perror("mkdep: open");
+		return;
+	}
+	fstat(fd, &st);
+	mapsize = st.st_size + 2*sizeof(unsigned long);
+	mapsize = (mapsize+pagesizem1) & ~pagesizem1;
+	map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (-1 == (long)map) {
+		perror("mkdep: mmap");
+		close(fd);
+		return;
+	}
+	close(fd);
+	state_machine(map);
+	munmap(map, mapsize);
+	if (hasdep)
+		puts(command);
+}
+
+int main(int argc, char **argv)
+{
+	int len;
+	char * hpath;
+
+	hpath = getenv("HPATH");
+	if (!hpath)
+		hpath = "/usr/src/linux/include";
+	len = strlen(hpath);
+	memcpy(path_array[0].buffer, hpath, len);
+	if (len && hpath[len-1] != '/') {
+		path_array[0].buffer[len] = '/';
+		len++;
+	}
+	path_array[0].buffer[len] = '\0';
+	path_array[0].len = len;
+
+	while (--argc > 0) {
+		int len;
+		char *name = *++argv;
+
+		filename = name;
+		len = strlen(name);
+		memcpy(depname, name, len+1);
+		command = __depname;
+		if (len > 2 && name[len-2] == '.') {
+			switch (name[len-1]) {
+				case 'c':
+				case 'S':
+					depname[len-1] = 'o';
+					command = "";
+			}
+		}
+		needsconfig = hasconfig = hasdep = 0;
+		do_depend();
+		if (hasconfig && !needsconfig)
+			fprintf(stderr, "%s doesn't need config\n", filename);
+	}
+	return 0;
+}
