diff -u --recursive --new-file v1.3.20/linux/CREDITS linux/CREDITS
--- v1.3.20/linux/CREDITS	Tue Aug 15 20:38:59 1995
+++ linux/CREDITS	Mon Aug 28 10:10:15 1995
@@ -962,12 +962,14 @@
 N: Matt Welsh
 E: mdw@sunsite.unc.edu
 D: Linux Documentation Project coordinator
-D: Author, Linux Installation and Getting Started
-D: HOWTO coordinator and writer
-D: Maintainer of sunsite.unc.edu Linux doc archives
-D: Moderator, comp.os.linux.announce
-S: 205 Gray Street NE
-S: Wilson, North Carolina 27893
+D: Author, _Running_Linux_ and I&GS guide
+D: Linuxdoc-SGML formatting system
+D: Keithley DAS1200 device driver
+D: Maintainer of sunsite WWW and FTP, moderator c.o.l.answers
+S: Cornell University Computer Science Department
+S: Robotics and Vision Laboratory
+S: 4130 Upson Hall
+S: Ithaca NY 14850
 S: USA
 
 N: Marco van Wieringen
diff -u --recursive --new-file v1.3.20/linux/Makefile linux/Makefile
--- v1.3.20/linux/Makefile	Fri Aug 18 08:44:57 1995
+++ linux/Makefile	Fri Aug 18 08:44:39 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 20
+SUBLEVEL = 21
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.20/linux/Rules.make linux/Rules.make
--- v1.3.20/linux/Rules.make	Tue Aug 15 20:38:59 1995
+++ linux/Rules.make	Thu Aug 17 09:49:00 1995
@@ -45,7 +45,8 @@
 # Rule to compile a set of .o files into one .o file
 #
 ifdef O_TARGET
-$(O_TARGET): $(O_OBJS)
+$(O_TARGET): $(O_OBJS) $(TOPDIR)/include/linux/config.h
+	rm -f $@
 ifdef O_OBJS
 	$(LD) $(EXTRA_LDFLAGS) -r -o $@ $(O_OBJS)
 else
@@ -57,7 +58,7 @@
 # Rule to compile a set of .o files into one .a file
 #
 ifdef L_TARGET
-$(L_TARGET): $(L_OBJS)
+$(L_TARGET): $(L_OBJS) $(TOPDIR)/include/linux/config.h
 	rm -f $@
 	$(AR) $(EXTRA_ARFLAGS) rcs $@ $(L_OBJS)
 endif
diff -u --recursive --new-file v1.3.20/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.3.20/linux/arch/i386/config.in	Tue Aug 15 20:38:59 1995
+++ linux/arch/i386/config.in	Mon Aug 28 09:19:32 1995
@@ -26,7 +26,10 @@
 bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
 bool 'PCI bios support' CONFIG_PCI y
 if [ "$CONFIG_PCI" = "y" ]; then
- bool '   PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE y
+  bool '   PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE y
+  if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
+    bool '   PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON y
+  fi
 fi
 bool 'System V IPC' CONFIG_SYSVIPC y
 bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y
diff -u --recursive --new-file v1.3.20/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v1.3.20/linux/arch/i386/kernel/entry.S	Thu Jun 29 19:02:39 1995
+++ linux/arch/i386/kernel/entry.S	Fri Aug 18 08:44:06 1995
@@ -517,4 +517,5 @@
 	.long SYMBOL_NAME(sys_getdents)
 	.long SYMBOL_NAME(sys_select)
 	.long SYMBOL_NAME(sys_flock)
-	.space (NR_syscalls-143)*4
+	.long SYMBOL_NAME(sys_msync)
+	.space (NR_syscalls-144)*4
diff -u --recursive --new-file v1.3.20/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v1.3.20/linux/arch/i386/kernel/setup.c	Sun Aug 13 14:45:27 1995
+++ linux/arch/i386/kernel/setup.c	Thu Aug 17 07:33:26 1995
@@ -103,14 +103,24 @@
 	init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
 
 	for (;;) {
+		/*
+		 * "mem=nopentium" disables the 4MB page tables.
+		 * "mem=XXX[kKmM]" overrides the BIOS-reported
+		 * memory size
+		 */
 		if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
-			memory_end = simple_strtoul(from+4, &from, 0);
-			if ( *from == 'K' || *from == 'k' ) {
-				memory_end = memory_end << 10;
-				from++;
-			} else if ( *from == 'M' || *from == 'm' ) {
-				memory_end = memory_end << 20;
-				from++;
+			if (!memcmp(from+4, "nopentium", 9)) {
+				from += 9+4;
+				x86_capability &= ~8;
+			} else {
+				memory_end = simple_strtoul(from+4, &from, 0);
+				if ( *from == 'K' || *from == 'k' ) {
+					memory_end = memory_end << 10;
+					from++;
+				} else if ( *from == 'M' || *from == 'm' ) {
+					memory_end = memory_end << 20;
+					from++;
+				}
 			}
 		}
 		c = *(from++);
diff -u --recursive --new-file v1.3.20/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v1.3.20/linux/drivers/block/Makefile	Tue Aug 15 20:39:00 1995
+++ linux/drivers/block/Makefile	Mon Aug 28 09:19:32 1995
@@ -106,6 +106,10 @@
 L_OBJS += ide.o
 endif
 
+ifdef CONFIG_BLK_DEV_TRITON
+L_OBJS += triton.o
+endif
+
 ifdef CONFIG_BLK_DEV_IDECD
 L_OBJS += ide-cd.o
 endif
diff -u --recursive --new-file v1.3.20/linux/drivers/block/README.ide linux/drivers/block/README.ide
--- v1.3.20/linux/drivers/block/README.ide	Tue Aug 15 20:39:01 1995
+++ linux/drivers/block/README.ide	Mon Aug 28 09:19:32 1995
@@ -3,7 +3,12 @@
 Supported by:  mlord@bnr.ca           -- disks, interfaces, probing
                snyder@fnald0.fnal.gov -- cdroms, ATAPI, audio
 
-(see description later on below for handling BIG IDE drives with >1024 cyls).
+   +-----------------------------------------------------------------+
+   |  The hdparm utility for controlling various IDE features is     |
+   |  packaged separately.  Look for it on popular linux FTP sites.  |
+   +-----------------------------------------------------------------+
+
+See description later on below for handling BIG IDE drives with >1024 cyls.
 
 Major features of ide.c & ide-cd.c:
 
@@ -35,16 +40,29 @@
 NEW!		- should work for for EZ-Drive disks as well (not verified)
 		- works with Linux fdisk, LILO, loadlin, bootln, etc..
 NEW!	- ide-cd.c now compiles separate from ide.c
+NEW!	- Bus-Master DMA support for Intel PCI Triton chipset IDE interfaces
+		- for details, see comments at top of triton.c
 
-For a list of work underway, see the comments near the top of ide.c and ide-cd.c
+For work in progress, see the comments in ide.c, ide-cd.c, and triton.c.
 
 ***
-
-IMPORTANT NOTICE:  "CMD" EIDE Interfaces will not (by default) work *reliably*
-when drives are attached to the second interface.  To "fix" this, supply the
-special kernel "command line" parameter to LILO:    ide1=serialize
-Failure to do so can cause severe data corruption!
-
+***  IMPORTANT NOTICES:
+***  ==================
+***
+***  "CMD" EIDE Interfaces will not (by default) work *reliably* when drives
+***  are attached to the second interface.  This is due to a flaw in the
+***  hardware.  To "fix" this, supply the special kernel "command line"
+***  parameter to LILO or LOADLIN:    ide1=serialize
+***
+***  "CMD 640B" EIDE Interfaces will not work *reliably* when "hdparm -u1"
+***  (interrupt unmasking) is used.  This is due to a flaw in the hardware,
+***  and is only a problem when "hdparm -u1" is used after booting.
+***
+***  "RZ1000" EIDE Interfaces will also not work *reliably* when "hdparm -u1"
+***  (interrupt unmasking) is used.  This is due to a flaw in the hardware,
+***  and is only a problem when "hdparm -u1" is used after booting.
+***
+***  Failure to abide by these restrictions can cause severe data corruption!
 ***
 
 To access devices on the 2nd/3rd/4th interfaces, device entries must first be
@@ -76,7 +94,7 @@
 
 Drives are normally found by auto-probing and/or examining the CMOS/BIOS data.
 For really weird situations, the apparent (fdisk) geometry can also be specified
-on the kernel "command line" using LILO.  The format of such lines is:   
+on the kernel "command line" using LILO.  The format of such lines is:
 
 	hdx=cyls,heads,sects,wpcom,irq
 or	hdx=cdrom
@@ -139,9 +157,6 @@
 under control of ide.c.   To have ide.c also "take over" the primary
 IDE port in this situation, use the "command line" parameter:  ide0=0x1f0
 
-The hdparm.c program for controlling various IDE features is now packaged
-separately.  Look for it on popular linux FTP sites.
-
 mlord@bnr.ca
 snyder@fnald0.fnal.gov
 ================================================================================
@@ -151,7 +166,7 @@
 
   "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
   "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
- 
+
   "hdx=noprobe"		: drive may be present, but do not probe for it
   "hdx=nowerr"		: ignore the WRERR_STAT bit on this drive
   "hdx=cdrom"		: drive is present, and is a cdrom drive
@@ -300,7 +315,7 @@
 	0. Boot from the "boot floppy" created during the installation
         1. Mount your DOS partition as /dos (and stick it in /etc/fstab)
         2. Move your kernel (/vmlinuz) to /dos/vmlinuz with:  mv /vmlinuz /dos
-        3. Edit /etc/lilo.conf to change /vmlinuz to /dos/vmlinuz 
+        3. Edit /etc/lilo.conf to change /vmlinuz to /dos/vmlinuz
         4. Move /boot to /dos/boot with:  cp -a /boot /dos ; rm -r /boot
         5. Create a symlink for LILO to use with:  ln -s /dos/boot /boot
         6. Re-run LILO with:  lilo
diff -u --recursive --new-file v1.3.20/linux/drivers/block/README.optcd linux/drivers/block/README.optcd
--- v1.3.20/linux/drivers/block/README.optcd	Fri Jul  7 08:54:44 1995
+++ linux/drivers/block/README.optcd	Mon Aug 28 09:58:20 1995
@@ -1,9 +1,14 @@
 This is the README file for the Optics Storage 8000 AT CDROM device driver.
 
-The driver contains code to enable an ISP16 interface if it finds one, so if
-you have that, you're lucky.
+The driver contains code to enable an ISP16 interface if it finds one.  It
+didn't originally (although this README erroneously said so), because I think
+this kind of code should go into its own module. But having to use a hack all
+the time in order to use a part of the standard kernel started to annoy me, so
+I copied the ISP16 code by Eric van der Maarel (maarel@marin.nl) from Vadim
+Model's Sanyo sjcd driver. I'll remove it again from this driver when we have
+some common way to talk to ISP16 interfaces.
 
-My configuration code for the ISP-16 card can get found at
+My original configuration code for the ISP-16 card can get found at
       dutette.et.tudelft.nl:/pub/linux/
 and at Eberhard's mirror
       ftp.gwdg.de:/pub/linux/cdrom/drivers/optics/
@@ -32,7 +37,10 @@
 with the matching address value of your interface card.
 
 I have tried the module with several 1.2.x kernel versions, and it seems to
-work, as far as I tested. If you use it, I'd appreciate success/failure
-reports.
+work, as far as I tested. It also seems to work for several 1.3.x versions.
+If you use it, I'd appreciate success/failure reports. If you find a bug,
+try recompiling the driver with some strategically chosen #undef DEBUG_...'s
+changed into #defines (you'll find them in .../include/linux/optcd.h) and
+include the messages generated in your bug report. Good luck.
 
 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
diff -u --recursive --new-file v1.3.20/linux/drivers/block/blk.h linux/drivers/block/blk.h
--- v1.3.20/linux/drivers/block/blk.h	Tue Aug 15 20:39:01 1995
+++ linux/drivers/block/blk.h	Mon Aug 28 13:12:41 1995
@@ -336,7 +336,7 @@
 
 #if ! SCSI_MAJOR(MAJOR_NR)
 
-#ifdef _IDE_CD_C	/* ide-cd.c uses copy from ide.c */
+#if defined(_IDE_CD_C) || defined(_TRITON_C) /* shares copy with ide.c */
 void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
 #else
 
diff -u --recursive --new-file v1.3.20/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v1.3.20/linux/drivers/block/ide-cd.c	Tue Aug 15 20:39:01 1995
+++ linux/drivers/block/ide-cd.c	Mon Aug 28 08:55:17 1995
@@ -110,8 +110,6 @@
 #define PACKET_COMMAND 4315
 #define REQUEST_SENSE_COMMAND 4316
 
-#define WIN_PACKETCMD 0xa0  /* Send a packet command. */
-
 /* Some ATAPI command opcodes (just like SCSI).
    (Some other cdrom-specific codes are in cdrom.h.) */
 #define TEST_UNIT_READY         0x00
diff -u --recursive --new-file v1.3.20/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.20/linux/drivers/block/ide.c	Tue Aug 15 20:39:01 1995
+++ linux/drivers/block/ide.c	Mon Aug 28 09:19:32 1995
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 5.03  Aug 13, 1995
+ *  linux/drivers/block/ide.c	Version 5.10  Aug 26, 1995
  *
  *  Copyright (C) 1994, 1995  Linus Torvalds & authors (see below)
  */
@@ -115,12 +115,20 @@
  *  Version 5.03	tune-ups, comments, remove "busy wait" from drive resets
  *			removed PROBE_FOR_IRQS option -- no longer needed
  *			OOOPS!  fixed "bad access" bug for 2nd drive on an i/f
+ *  Version 5.04	changed "ira %d" to "irq %d" in DEBUG message
+ *			added more comments, cleaned up unexpected_intr()
+ *			OOOPS!  fixed null pointer problem in ide reset code
+ *			added autodetect for Triton chipset -- no effect yet
+ *  Version 5.05	OOOPS!  fixed bug in revalidate_disk()
+ *			OOOPS!  fixed bug in ide_do_request()
+ *			added ATAPI reset sequence for cdroms
+ *  Version 5.10	added Bus-Mastered DMA support for Triton Chipset
+ *			some (mostly) cosmetic changes
  *
  *  Driver compile-time options are in ide.h
  *
  *  To do, in likely order of completion:
  *	- add in several updates from my email collection (soon folks!)
- *	- add full support for Intel Triton chipset, including bus-mastered DMA
  *	- improved CMD support:  handing this off to someone else
  *	- find someone to work on IDE *tape drive* support
  */
@@ -142,6 +150,10 @@
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 
+#ifdef CONFIG_PCI
+#include <linux/bios32.h>
+#endif /* CONFIG_PCI */
+
 #include "ide.h"
 
 static ide_hwif_t	ide_hwifs[MAX_HWIFS];		/* hwif info */
@@ -196,50 +208,46 @@
  * ide_drive_t structs as needed, rather than always consuming memory
  * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
  */
+#define MAGIC_COOKIE 0x12345678
 static void init_ide_data (void)
 {
+	byte *p;
 	unsigned int h, unit;
-	static unsigned long magic_cookie = 0x12345678;
+	static unsigned long magic_cookie = MAGIC_COOKIE;
 
-	if (magic_cookie != 0x12345678)
+	if (magic_cookie != MAGIC_COOKIE)
 		return;		/* already initialized */
 	magic_cookie = 0;
 
 	for (h = 0; h < 16; ++h)
 		 irq_to_hwgroup[h] = NULL;
 
+	/* bulk initialize hwif & drive info with zeros */
+	p = ((byte *) ide_hwifs) + sizeof(ide_hwifs);
+	do {
+		*--p = 0;
+	} while (p > (byte *) ide_hwifs);
+
 	for (h = 0; h < MAX_HWIFS; ++h) {
 		ide_hwif_t *hwif = &ide_hwifs[h];
 
+		/* fill in any non-zero initial values */
 		hwif->noprobe	= (h > 1);
-		hwif->hwgroup	= NULL;
 		hwif->io_base	= default_io_base[h];
 		hwif->ctl_port	= hwif->io_base ? hwif->io_base + 0x206 : 0x000;
 #ifdef CONFIG_BLK_DEV_HD
 		if (hwif->io_base == HD_DATA)
 			hwif->noprobe = 1; /* may be overriden by ide_setup() */
 #endif /* CONFIG_BLK_DEV_HD */
-		hwif->gd	= NULL;
-		hwif->irq	= 0;  /* default_irqs[h] used when probe fails */
 		hwif->major	= ide_hwif_to_major[h];
 		hwif->name[0]	= 'i';
 		hwif->name[1]	= 'd';
 		hwif->name[2]	= 'e';
 		hwif->name[3]	= '0' + h;
-		hwif->name[4]	= '\0';
-		hwif->present	= 0;
-		hwif->next	= NULL;
-		hwif->reset_timeout = 0;
 
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			ide_drive_t *drive = &hwif->drives[unit];
 
-			/* bulk initialize drive info with zeros */
-			byte *p = ((byte *) drive) + sizeof(ide_drive_t);
-			do {
-				*--p = 0;
-			} while (p > (byte *) drive);
-
 			/* fill in any non-zero initial values */
 			drive->select.all		= (unit<<4)|0xa0;
 			drive->hwif			= hwif;
@@ -257,7 +265,13 @@
 
 #ifdef __i386__
 #define VLB_SYNC 1
-
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data.  We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
 static inline void do_vlb_sync (unsigned short port) {
 	unsigned int _v;
 	__asm__ __volatile__	(
@@ -404,16 +418,30 @@
 }
 
 /*
- * ide_alloc(): memory allocation for using during driver initialization.
- */
-static unsigned long init_mem_start = 0uL;	/* used by init routines */
-
-static inline void *ide_alloc (unsigned long bytecount)
-{
-	unsigned long p = init_mem_start;
-	if (!p) panic("ide: ide_alloc() not valid now\n");
-	init_mem_start += (bytecount + 3uL) & ~3uL;
-	return (void *) p;
+ * ide_alloc(): memory allocation for use *only* during driver initialization.
+ * If "within_area" is non-zero, the memory will be allocated such that
+ * it lies entirely within a "within_area" sized area (eg. 4096).  This is
+ * needed for DMA stuff.  "within_area" must be a power of two (not validated).
+ * All allocations are longword aligned.
+ */
+static unsigned long ide_mem_start = 0uL;	/* used by ide_alloc() */
+
+void *ide_alloc (unsigned long bytecount, unsigned long within_area)
+{
+	const unsigned long longsize_m1 = (sizeof(long) - 1);
+	void *p;
+
+	if (!ide_mem_start)
+		panic("ide: ide_alloc() not valid now\n");
+	ide_mem_start = (ide_mem_start + longsize_m1) & ~longsize_m1;
+	if (within_area) {
+		unsigned long fraction = within_area - (ide_mem_start & (within_area - 1));
+		if (fraction < bytecount)
+			ide_mem_start += fraction; /* realign to a new page */
+	}
+	p = (void *) ide_mem_start;
+	ide_mem_start += (bytecount + longsize_m1) & ~longsize_m1;
+	return p;
 }
 
 /*
@@ -434,10 +462,10 @@
 			break;
 	}
 	minors    = units * (1<<PARTN_BITS);
-	gd        = ide_alloc(sizeof(struct gendisk));
-	gd->sizes = ide_alloc(minors * sizeof(int));
-	gd->part  = ide_alloc(minors * sizeof(struct hd_struct));
-	bs        = ide_alloc(minors*sizeof(int));
+	gd        = ide_alloc (sizeof(struct gendisk), 0);
+	gd->sizes = ide_alloc (minors * sizeof(int), 0);
+	gd->part  = ide_alloc (minors * sizeof(struct hd_struct), 0);
+	bs        = ide_alloc (minors*sizeof(int), 0);
 
 	/* cdroms and msdos f/s are examples of non-1024 blocksizes */
 	blksize_size[hwif->major] = bs;
@@ -470,7 +498,12 @@
  */
 static void reset_ihandler (ide_drive_t *drive)
 {
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
 	unexpected_intr (HWIF(drive)->irq, HWGROUP(drive));
+	restore_flags(flags);
 }
 
 /*
@@ -481,15 +514,49 @@
 {
 	ide_hwgroup_t *hwgroup = hwif->hwgroup;
 
-	hwif->reset_timeout = jiffies + WAIT_WORSTCASE;	/* max waiting time */
+	hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE; /* max waiting time */
 	hwgroup->handler = &reset_ihandler;		/* dummy irq handler */
 	hwgroup->timer.expires = jiffies + (HZ/20);	/* polling interval */
 	add_timer(&(hwgroup->timer));
 }
 
+#ifdef CONFIG_BLK_DEV_IDECD
+/*
+ * atapi_reset_handler() gets invoked to poll the interface for completion every 50ms
+ * during an atapi drive reset operation. If the drive has not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ *
+ * Returns 1 if waiting for another 50ms, returns 0 otherwise.
+ */
+static int atapi_reset_handler (ide_hwgroup_t *hwgroup)
+{
+	ide_hwif_t *hwif = hwgroup->hwif;
+	ide_drive_t *drive = hwgroup->drive;
+	byte stat;
+
+	OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+	udelay (10);
+
+	if (!OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
+		if (jiffies < hwgroup->reset_timeout) {
+			start_reset_timer (hwif);
+			return 1;
+		}
+		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
+		return ide_do_reset (drive);	/* do it the old fashioned way */
+	}
+	hwgroup->doing_atapi_reset = 0;
+	hwgroup->handler = NULL;	/* allow new requests to be processed */
+	hwgroup->reset_timeout = 0;	/* signal end of ide reset operation */
+	printk("%s: ATAPI reset complete\n", drive->name);
+	return 0;
+}
+#endif /* CONFIG_BLK_DEV_IDECD */
+
 /*
  * reset_handler() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not not responded,
+ * during an ide reset operation. If the drives have not yet responded,
  * and we have not yet hit our maximum waiting time, then the timer is restarted
  * for another 50ms.
  *
@@ -501,8 +568,13 @@
 	ide_drive_t *drive = hwgroup->drive;
 	byte tmp;
 
+#ifdef CONFIG_BLK_DEV_IDECD
+	if (hwgroup->doing_atapi_reset)
+		return atapi_reset_handler(hwgroup);
+#endif /* CONFIG_BLK_DEV_IDECD */
+
 	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
-		if (jiffies < hwif->reset_timeout) {
+		if (jiffies < hwgroup->reset_timeout) {
 			start_reset_timer (hwif);
 			return 1;
 		}
@@ -532,7 +604,7 @@
 		}
 	}
 	hwgroup->handler = NULL;	/* allow new requests to be processed */
-	hwif->reset_timeout = 0;	/* signal end of ide reset operation */
+	hwgroup->reset_timeout = 0;	/* signal end of ide reset operation */
 	return 0;
 }
 
@@ -542,9 +614,8 @@
  * the same interface, so it can really be thought of as resetting the
  * interface rather than resetting the drive.
  *
- * ATAPI devices have their own reset mechanism (not handled here),
- * which allows them to be individually reset without clobbering other
- * devices on the same interface.  ide-cd.c will handle those separately.
+ * ATAPI devices have their own reset mechanism which allows them to be
+ * individually reset without clobbering other devices on the same interface.
  *
  * Unfortunately, the IDE interface does not generate an interrupt to let
  * us know when the reset operation has finished, so we must poll for this.
@@ -552,15 +623,35 @@
  * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
  * we set a timer to poll at 50ms intervals.
  */
-static int ide_do_reset (ide_drive_t *drive)
+int ide_do_reset (ide_drive_t *drive)
 {
 	unsigned int unit;
 	unsigned long flags;
 	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
 	save_flags(flags);
 	cli();		/* Why ? */
 
+#ifdef CONFIG_BLK_DEV_IDECD
+	/* For an ATAPI device, first try an ATAPI SRST. */
+	if (drive->media == cdrom) {
+		if (!hwgroup->doing_atapi_reset) {
+			hwgroup->doing_atapi_reset = 1;
+			if (!drive->keep_settings)
+				drive->unmask = 0;
+			OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+			OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
+			udelay (10);
+			hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
+			start_reset_timer (hwif); /* begin periodic polling */
+			restore_flags (flags);
+			return 1;
+		}
+	}
+	hwgroup->doing_atapi_reset = 0;
+#endif /* CONFIG_BLK_DEV_IDECD */
+
 	/*
 	 * First, reset any device state data we were maintaining
 	 * for any of the drives on this interface.
@@ -589,10 +680,10 @@
 	 * This single interrupt gives us a "fast poll" for drives that
 	 * recover from reset very quickly, saving us the first 50ms wait time.
 	 */
-	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set nIEN and SRST */
+	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
 	udelay(5);			/* more than enough time */
 	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
-	hwif->reset_timeout = jiffies + WAIT_WORSTCASE;
+	hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
 	start_reset_timer (hwif);	/* begin periodic polling */
 #endif	/* OK_TO_RESET_CONTROLLER */
 
@@ -640,7 +731,7 @@
 			printk("Busy ");
 		else {
 			if (stat & READY_STAT)	printk("DriveReady ");
-			if (stat & WRERR_STAT)	printk("WriteFault ");
+			if (stat & WRERR_STAT)	printk("DeviceFault ");
 			if (stat & SEEK_STAT)	printk("SeekComplete ");
 			if (stat & DRQ_STAT)	printk("DataRequest ");
 			if (stat & ECC_STAT)	printk("CorrectedError ");
@@ -746,6 +837,12 @@
 	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
 		rq->errors |= ERROR_RESET;	/* Mmmm.. timing problem */
 
+	if (rq->errors > 3 && drive->using_dma) {	/* DMA troubles? */
+		drive->using_dma = 0;
+		printk("%s: DMA disabled\n", drive->name);
+		--rq->errors;
+		return 0;
+	}
 	if (rq->errors >= ERROR_MAX)
 		ide_end_request(0, HWGROUP(drive));
 	else {
@@ -916,7 +1013,7 @@
  * Issue a simple drive command
  * The drive must be selected beforehand.
  */
-static inline void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
+static void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
 {
 	ide_set_handler (drive, handler);
 	OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
@@ -924,6 +1021,9 @@
 	OUT_BYTE(cmd,IDE_COMMAND_REG);
 }
 
+/*
+ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ */
 static void set_multmode_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
@@ -939,6 +1039,9 @@
 	IDE_DO_REQUEST;
 }
 
+/*
+ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ */
 static void set_geometry_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
@@ -950,6 +1053,9 @@
 	IDE_DO_REQUEST;
 }
 
+/*
+ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ */
 static void recal_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
@@ -961,6 +1067,10 @@
 	IDE_DO_REQUEST;
 }
 
+#ifdef IDE_DRIVE_CMD
+/*
+ * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+ */
 static void drive_cmd_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
@@ -972,8 +1082,14 @@
 		return;
 	IDE_DO_REQUEST;
 }
+#endif	/* IDE_DRIVE_CMD */
 
-static void do_special (ide_drive_t *drive)
+/*
+ * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
+ * commands to a drive.  It used to do much more, but has been scaled back
+ * in recent updates, and could be completely eliminated with a bit more effort.
+ */
+static inline void do_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
 #ifdef DEBUG
@@ -1044,6 +1160,11 @@
 	return 1;
 }
 
+/*
+ * do_rw_disk() issues WIN_{MULT}READ and WIN_{MULT}WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.  It also takes
+ * care of issuing special DRIVE_CMDs.
+ */
 static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
@@ -1075,11 +1196,15 @@
 #endif
 	}
 	if (rq->cmd == READ) {
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+			return;
 		ide_set_handler(drive, &read_intr);
 		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
 		return;
 	}
 	if (rq->cmd == WRITE) {
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
+			return;
 		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
 		if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
 			printk("%s: no DRQ after issuing %s\n", drive->name,
@@ -1108,6 +1233,10 @@
 			ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
 			return;
 		} else {
+			/*
+			 * NULL is actually a valid way of waiting for
+			 * all current requests to be flushed from the queue.
+			 */
 #ifdef DEBUG
 			printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
@@ -1120,6 +1249,9 @@
 	ide_end_request(0, HWGROUP(drive));
 }
 
+/*
+ * do_request() initiates handling of a new I/O request
+ */
 static inline void do_request (ide_hwif_t *hwif, struct request *rq)
 {
 	unsigned int minor, unit;
@@ -1137,18 +1269,21 @@
 		goto kill_rq;
 	}
 	drive = &hwif->drives[unit];
+#ifdef DEBUG
 	if (rq->bh && !rq->bh->b_lock) {
 		printk("%s: block not locked\n", drive->name);
 		goto kill_rq;
 	}
+#endif
 	block    = rq->sector;
 	blockend = block + rq->nr_sectors;
 	if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
-		printk("%s: bad access: block=%ld, count=%ld\n",
-			drive->name, block, rq->nr_sectors);
+		printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
+		 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
 		goto kill_rq;
 	}
 	block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
+	((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
 #if (DISK_RECOVERY_TIME > 0)
 	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
 #endif
@@ -1158,7 +1293,6 @@
 		return;
 
 	}
-	((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
 	if (!drive->special.all) {
 #ifdef CONFIG_BLK_DEV_IDECD
 		switch (drive->media) {
@@ -1202,7 +1336,6 @@
 void ide_do_request (ide_hwgroup_t *hwgroup)
 {
 	cli();	/* paranoia */
-
 	if (hwgroup->handler != NULL) {
 		printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name);
 		return;
@@ -1218,14 +1351,25 @@
 					goto got_rq;
 			} while ((hwif = hwif->next) != hwgroup->hwif);
 			return;		/* no work left for this hwgroup */
+		got_rq:
+			blk_dev[hwif->major].current_request = rq->next;
 		}
-	got_rq:
-		blk_dev[hwif->major].current_request = rq->next;
 		do_request(hwgroup->hwif = hwif, hwgroup->rq = rq);
 		cli();
 	} while (hwgroup->handler == NULL);
 }
 
+/*
+ * do_hwgroup_request() invokes ide_do_request() after first masking
+ * all possible interrupts for the current hwgroup.  This prevents race
+ * conditions in the event that an unexpected interrupt occurs while
+ * we are in the driver.
+ *
+ * Note that when an interrupt is used to reenter the driver, the first level
+ * handler will already have masked the irq that triggered, but any other ones
+ * for the hwgroup will still be unmasked.  The driver tries to be careful
+ * about such things.
+ */
 static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
 {
 	if (hwgroup->handler == NULL) {
@@ -1270,7 +1414,7 @@
 	save_flags(flags);
 	cli();
 
-	if (hwgroup->hwif->reset_timeout != 0) { /* ide reset in progress? */
+	if (hwgroup->reset_timeout != 0) { /* ide reset in progress? */
 		if (!reset_handler(hwgroup))
 			do_hwgroup_request (hwgroup);
 	} else if (hwgroup->handler == NULL) {	 /* not waiting for anything? */
@@ -1278,6 +1422,8 @@
 		printk("%s: marginal timeout\n", drive->name);
 	} else {				 /* drive not responding */
 		hwgroup->handler = NULL;
+		if (hwgroup->hwif->dmaproc) 
+			(void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
 		if (!ide_error(drive, "irq timeout", GET_STAT()))
 			do_hwgroup_request (hwgroup);
 	}
@@ -1293,24 +1439,32 @@
  * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
  * drive enters "idle", "standby", or "sleep" mode, so if the status looks
  * "good", we just ignore the interrupt completely.
+ *
+ * This routine assumes cli() is in effect when called.
+ *
+ * If an unexpected interrupt happens on irq15 while we are handling irq14
+ * and if the two interfaces are "serialized" (CMD640B), then it looks like
+ * we could screw up by interfering with a new request being set up for irq15.
+ *
+ * In reality, this is a non-issue.  The new command is not sent unless the
+ * drive is ready to accept one, in which case we know the drive is not
+ * trying to interrupt us.  And ide_set_handler() is always invoked before
+ * completing the issuance of any new drive command, so we will not be 
+ * accidently invoked as a result of any valid command completion interrupt.
+ *
  */
 static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
 {
 	byte stat;
 	unsigned int unit;
 	ide_hwif_t *hwif = hwgroup->hwif;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
 	/*
 	 * check for ide reset in progress
 	 */
-	if (hwif->reset_timeout != 0) {
+	if (hwgroup->reset_timeout != 0) {
 		if (!reset_handler(hwgroup))
 			do_hwgroup_request (hwgroup);
-		restore_flags(flags);
 		return;
 	}
 
@@ -1330,7 +1484,6 @@
 			}
 		}
 	} while ((hwif = hwif->next) != hwgroup->hwif);
-	restore_flags(flags);
 }
 
 /*
@@ -1340,13 +1493,8 @@
 {
 	ide_hwgroup_t  *hwgroup = irq_to_hwgroup[irq];
 	ide_handler_t  *handler;
-	if (irq != hwgroup->hwif->irq) {
-#ifdef DEBUG
-		printk("ide_intr: expected ira %d, got irq %d instead\n",
-			hwgroup->hwif->irq, irq);
-#endif
-		unexpected_intr(irq, hwgroup);
-	} else if ((handler = hwgroup->handler) != NULL) {
+
+	if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) {
 		ide_drive_t *drive = hwgroup->drive;
 		hwgroup->handler = NULL;
 		del_timer(&(hwgroup->timer));
@@ -1354,12 +1502,15 @@
 			sti();
 		handler(drive);
 	} else {
-		sti();
 		unexpected_intr(irq, hwgroup);
 	}
 	cli();
 }
 
+/*
+ * get_info_ptr() returns the (ide_drive_t *) for a given device number.
+ * It returns NULL if the given device number does not match any present drives.
+ */
 static ide_drive_t *get_info_ptr (int i_rdev)
 {
 	int		major = MAJOR(i_rdev);
@@ -1381,18 +1532,6 @@
 }
 
 #ifdef IDE_DRIVE_CMD
-static int write_fs_long (unsigned long useraddr, long value)
-{
-	int err;
-
-	if (NULL == (long *)useraddr)
-		return -EINVAL;
-	if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
-		return err;
-	put_user((unsigned)value, (long *) useraddr);
-	return 0;
-}
-
 /*
  * This function issues a specific IDE drive command onto the
  * tail of the request queue, and waits for it to be completed.
@@ -1513,7 +1652,7 @@
 	if ((drive = get_info_ptr(i_rdev)) == NULL)
 		return -ENODEV;
 
-	major = MAJOR(i_rdev);
+	major = MAJOR(i_rdev) << 8;
 	minor = drive->select.b.unit << PARTN_BITS;
 	save_flags(flags);
 	cli();
@@ -1540,6 +1679,18 @@
 	return 0;
 }
 
+static int write_fs_long (unsigned long useraddr, long value)
+{
+	int err;
+
+	if (NULL == (long *)useraddr)
+		return -EINVAL;
+	if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
+		return err;
+	put_user((unsigned)value, (long *) useraddr);
+	return 0;
+}
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -1590,6 +1741,9 @@
                 case HDIO_GET_UNMASKINTR:
 			return write_fs_long(arg, drive->unmask);
 
+                case HDIO_GET_DMA:
+			return write_fs_long(arg, drive->using_dma);
+
                 case HDIO_GET_CHIPSET:
 			return write_fs_long(arg, drive->chipset);
 
@@ -1602,13 +1756,18 @@
 			if (drive->id == NULL)
 				return -ENOMSG;
 			err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*drive->id));
-			if (err) return err;
-			memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
-			return 0;
+			if (!err)
+				memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
+			return err;
 
 			case HDIO_GET_NOWERR:
 			return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT);
 
+		case HDIO_SET_DMA:
+			if (drive->media != disk)
+				return -EPERM;
+			if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+				return -EPERM;
 		case HDIO_SET_KEEPSETTINGS:
 		case HDIO_SET_UNMASKINTR:
 		case HDIO_SET_NOWERR:
@@ -1622,6 +1781,9 @@
 			save_flags(flags);
 			cli();
 			switch (cmd) {
+				case HDIO_SET_DMA:
+					drive->using_dma = arg;
+					break;
 				case HDIO_SET_KEEPSETTINGS:
 					drive->keep_settings = arg;
 					break;
@@ -1645,7 +1807,8 @@
 			return 0;
 
 		case HDIO_SET_MULTCOUNT:
-			if (!suser()) return -EACCES;
+			if (!suser())
+				return -EACCES;
 			if (inode->i_rdev & PARTN_MASK)
 				return -EINVAL;
 			if ((drive->id != NULL) && (arg > drive->id->max_multsect))
@@ -1738,13 +1901,13 @@
 		*p++ = '\0';
 }
 
-static void do_identify (ide_drive_t *drive, byte cmd)
+static inline void do_identify (ide_drive_t *drive, byte cmd)
 {
 	int bswap;
 	struct hd_driveid *id;
 	unsigned long capacity, check;
 
-	id = drive->id = ide_alloc(SECTOR_WORDS*4);
+	id = drive->id = ide_alloc (SECTOR_WORDS*4, 0);
 	ide_input_data(drive, id, SECTOR_WORDS);	/* read 512 bytes of id info */
 	sti();
 
@@ -1764,11 +1927,11 @@
 	 */
 	bswap = 1;
 	if (cmd == WIN_PIDENTIFY) {
-		if ((id->model[0] == 'N' && id->model[1] == 'E')
-		 || (id->model[0] == 'F' && id->model[1] == 'X')
-		 || (id->model[0] == 'P' && id->model[1] == 'i'))
-			bswap = 0;	/* NEC, Pioneer and *some* Mitsumi units */
-	}				/* Vertos drives may still be weird */
+		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
+		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
+		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
+			bswap = 0;	/* Vertos drives may still be weird */
+	}
 	fixstring (id->model,     sizeof(id->model),     bswap);
 	fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
 	fixstring (id->serial_no, sizeof(id->serial_no), bswap);
@@ -1862,7 +2025,10 @@
 			drive->mult_req = id->max_multsect;
 		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
 			drive->special.b.set_multmode = 1;
-		printk(", MaxMult=%d", id->max_multsect);
+	}
+	if (HWIF(drive)->dmaproc != NULL) {	/* hwif supports DMA? */
+		if (!(HWIF(drive)->dmaproc(ide_dma_check, drive)))
+			printk(", DMA");
 	}
 	printk("\n");
 }
@@ -1998,7 +2164,7 @@
  * Returns:	0  no device was found
  *		1  device was found (note: drive->present might still be 0)
  */
-static byte probe_for_drive (ide_drive_t *drive)
+static inline byte probe_for_drive (ide_drive_t *drive)
 {
 	if (drive->noprobe)			/* skip probing? */
 		return drive->present;
@@ -2306,6 +2472,7 @@
  * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value 
  * means we have an AT controller hard disk for that drive.
  */
+
 static void probe_cmos_for_drives (ide_hwif_t *hwif)
 {
 #ifdef __i386__
@@ -2320,11 +2487,9 @@
 		ide_drive_t *drive = &hwif->drives[unit];
 		if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present) {
 			drive->cyl   = drive->bios_cyl  = *(unsigned short *)BIOS;
-			drive->head  = drive->bios_head = * (BIOS+2);
-			drive->sect  = drive->bios_sect = * (BIOS+14);
-			drive->wpcom = (*(unsigned short *)(BIOS+5))>>2;
+			drive->head  = drive->bios_head = *(BIOS+2);
+			drive->sect  = drive->bios_sect = *(BIOS+14);
 			drive->ctl   = *(BIOS+8);
-			drive->wpcom = 0;
 			drive->media = disk;
 			drive->present = 1;
 		}
@@ -2362,12 +2527,16 @@
 	 * Got the irq,  now set everything else up
 	 */
 	if ((hwgroup = irq_to_hwgroup[hwif->irq]) == NULL) {
-		hwgroup = ide_alloc(sizeof(ide_hwgroup_t));
+		hwgroup = ide_alloc (sizeof(ide_hwgroup_t), 0);
 		irq_to_hwgroup[hwif->irq] = hwgroup;
 		hwgroup->hwif 	 = hwif->next = hwif;
 		hwgroup->rq      = NULL;
 		hwgroup->handler = NULL;
 		hwgroup->drive   = NULL;
+		hwgroup->reset_timeout = 0;
+#ifdef CONFIG_BLK_DEV_IDECD
+		hwgroup->doing_atapi_reset = 0;
+#endif /* CONFIG_BLK_DEV_IDECD */
 		init_timer(&hwgroup->timer);
 		hwgroup->timer.function = &timer_expiry;
 		hwgroup->timer.data = (unsigned long) hwgroup;
@@ -2456,6 +2625,7 @@
 }
 #endif /* SUPPORT_DTC2278 */
 
+
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
@@ -2463,7 +2633,7 @@
 {
 	int h;
 
-	init_mem_start = (mem_start + 3uL) & ~3uL;	/* for ide_alloc() */
+	ide_mem_start = mem_start;	/* for ide_alloc () */
 	init_ide_data ();
 	/*
 	 * First, we determine what hardware is present
@@ -2472,6 +2642,20 @@
 	if (probe_dtc2278)
 		try_to_init_dtc2278();
 #endif /* SUPPORT_DTC2278 */
+#ifdef CONFIG_PCI
+	/*
+	 * Look for pci disk interfaces.
+	 */
+	if (pcibios_present()) {
+#ifdef CONFIG_BLK_DEV_TRITON
+		ide_init_triton (ide_hwifs);
+#endif /* CONFIG_BLK_DEV_TRITON */
+	}
+#endif /* CONFIG_PCI */
+
+	/*
+	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
+	 */
 	for (h = 0; h < MAX_HWIFS; ++h) {
 		ide_hwif_t *hwif = &ide_hwifs[h];
 		if (!hwif->noprobe) {
@@ -2491,6 +2675,7 @@
 			if (hwif->irq == HD_IRQ && hwif->io_base != HD_DATA) {
 				printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
 				hwif->present = 0;
+B
 			}
 #endif /* CONFIG_BLK_DEV_HD */
 		}
@@ -2535,7 +2720,7 @@
 			hwif->present = 1;	/* success */
 		}
 	}
-	mem_start = init_mem_start;
-	init_mem_start = 0uL;	/* prevent further use of ide_alloc() */
+	mem_start = ide_mem_start;
+	ide_mem_start = 0uL;	/* prevent further use of ide_alloc() */
 	return mem_start;
 }
diff -u --recursive --new-file v1.3.20/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v1.3.20/linux/drivers/block/ide.h	Tue Aug 15 20:39:01 1995
+++ linux/drivers/block/ide.h	Mon Aug 28 13:13:08 1995
@@ -21,7 +21,7 @@
 #undef REALLY_SLOW_IO			/* most systems can safely undef this */
 #include <asm/io.h>
 
-#define	REALLY_FAST_IO			/* define if ide ports are perfect */
+#undef 	REALLY_FAST_IO			/* define if ide ports are perfect */
 #define INITIAL_MULT_COUNT	0	/* off=0; on=2,4,8,16,32, etc.. */
 
 #ifndef DISK_RECOVERY_TIME		/* off=0; on=access_delay_time */
@@ -121,14 +121,6 @@
 
 #ifdef CONFIG_BLK_DEV_IDECD
 
-struct packet_command {
-  char *buffer;
-  int buflen;
-  int stat;
-  unsigned char c[12];
-};
-
-
 struct atapi_request_sense {
   unsigned char error_code : 7;
   unsigned char valid      : 1;
@@ -146,6 +138,14 @@
   byte sense_key_specific[3];
 };
 
+struct packet_command {
+  char *buffer;
+  int buflen;
+  int stat;
+  struct atapi_request_sense *sense_data;
+  unsigned char c[12];
+};
+
 /* Space to hold the disk TOC. */
 
 #define MAX_TRACKS 99
@@ -165,6 +165,9 @@
 };
 
 struct atapi_toc {
+  int    last_session_lba;
+  int    xa_flag;
+  unsigned capacity;
   struct atapi_toc_header hdr;
   struct atapi_toc_entry  ent[MAX_TRACKS+1];  /* One extra for the leadout. */
 };
@@ -230,14 +233,13 @@
 	unsigned vlb_32bit	: 1;	/* use 32bit in/out for data */
 	unsigned vlb_sync	: 1;	/* needed for some 32bit chip sets */
 	unsigned removeable	: 1;	/* 1 if need to do check_media_change */
-	unsigned dma_capable	: 1;	/* for Intel Triton chipset, others.. */
+	unsigned using_dma	: 1;	/* disk is using dma for read/write */
+	unsigned unmask		: 1;	/* flag: okay to unmask other irqs */
+	media_t		media;		/* disk, cdrom, tape */
 	select_t	select;		/* basic drive/head select reg value */
-	byte		unmask;		/* flag: okay to unmask other irqs */
 	void		*hwif;		/* actually (ide_hwif_t *) */
 	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
 	byte		ready_stat;	/* min status value for drive ready */
-	byte		wpcom;		/* ignored by all IDE drives */
-	media_t		media;		/* disk, cdrom, tape */
 	byte		mult_count;	/* current multiple sector setting */
 	byte 		mult_req;	/* requested multiple sector setting */
 	byte		chipset;	/* interface chipset access method */
@@ -259,22 +261,38 @@
 #endif /* CONFIG_BLK_DEV_IDECD */
 	} ide_drive_t;
 
+/*
+ * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA.  All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case the caller
+ * should either try again later, or revert to PIO for the current request.
+ */
+typedef enum {ide_dma_read = 0, ide_dma_write = 1, ide_dma_abort = 2, ide_dma_check = 3} ide_dma_action_t;
+typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
+
 typedef struct hwif_s {
 	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
 	void		*hwgroup;	/* actually (ide_hwgroup_t *) */
 	unsigned short	io_base;	/* base io port addr */
 	unsigned short	ctl_port;	/* usually io_base+0x206 */
-	ide_drive_t		drives[MAX_DRIVES];	/* drive info */
+	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
 	struct gendisk	*gd;		/* gendisk structure */
+	ide_dmaproc_t	*dmaproc;	/* dma read/write/abort routine */
+	unsigned long	*dmatable;	/* dma physical region descriptor table */
+	unsigned short	dma_base;	/* base addr for dma ports (triton) */
 	byte		irq;		/* our irq number */
 	byte		major;		/* our major number */
 	byte		drivecount;	/* how many drives attached */
 	char 		name[5];	/* name of interface, eg. "ide0" */
 	unsigned	noprobe : 1;	/* don't probe for this interface */
 	unsigned	present : 1;	/* this interface exists */
-	unsigned long	reset_timeout;	/* timeout value during ide resets */
 #if (DISK_RECOVERY_TIME > 0)
-	unsigned long	last_timer;	/* time when previous rq was done */
+	unsigned long	last_time;	/* time when previous rq was done */
 #endif
 #ifdef CONFIG_BLK_DEV_IDECD
 	struct request request_sense_request;	/* from ide-cd.c */
@@ -283,7 +301,7 @@
 	} ide_hwif_t;
 
 /*
- *  our internal interrupt handler type
+ *  internal ide interrupt handler type
  */
 typedef void (ide_handler_t)(ide_drive_t *);
 
@@ -294,6 +312,10 @@
 	struct request		*rq;	/* current request */
 	struct timer_list	timer;	/* failsafe timer */
 	struct request		wrq;	/* local copy of current write rq */
+	unsigned long	reset_timeout;	/* timeout value during ide resets */
+#ifdef CONFIG_BLK_DEV_IDECD
+	int			doing_atapi_reset;
+#endif /* CONFIG_BLK_DEV_IDECD */
 	} ide_hwgroup_t;
 
 /*
@@ -363,6 +385,23 @@
  */
 int ide_xlate_1024(dev_t, int, const char *);
 
+/*
+ * Start a reset operation for an IDE interface.
+ * Returns 0 if the reset operation is still in progress,
+ *  in which case the drive MUST return, to await completion.
+ * Returns 1 if the reset is complete (success or failure).
+ */
+int ide_do_reset (ide_drive_t *);
+
+/*
+ * ide_alloc(): memory allocation for use *only* during driver initialization.
+ * If "within_area" is non-zero, the memory will be allocated such that
+ * it lies entirely within a "within_area" sized area (eg. 4096).  This is
+ * needed for DMA stuff.  "within_area" must be a power of two (not validated).
+ * All allocations are longword aligned.
+ */
+void *ide_alloc (unsigned long bytecount, unsigned long within_area);
+
 #ifdef CONFIG_BLK_DEV_IDECD
 /*
  * These are routines in ide-cd.c invoked from ide.c
@@ -374,3 +413,8 @@
 void ide_cdrom_release (struct inode *, struct file *, ide_drive_t *);
 void ide_cdrom_setup (ide_drive_t *);
 #endif /* CONFIG_BLK_DEV_IDECD */
+
+#ifdef CONFIG_BLK_DEV_TRITON
+void ide_init_triton (ide_hwif_t *);
+#endif /* CONFIG_BLK_DEV_TRITON */
+
diff -u --recursive --new-file v1.3.20/linux/drivers/block/optcd.c linux/drivers/block/optcd.c
--- v1.3.20/linux/drivers/block/optcd.c	Fri Jul  7 08:54:45 1995
+++ linux/drivers/block/optcd.c	Mon Aug 28 09:58:20 1995
@@ -1,10 +1,12 @@
-/*	$Id: optcd.c,v 1.7 1995/06/28 20:20:13 root Exp $
+/*	$Id: optcd.c,v 1.3 1995/08/24 19:54:27 root Exp root $
 	linux/drivers/block/optcd.c - Optics Storage 8000 AT CDROM driver
 
 	Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
 
 	Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks
-	by Eberhard Moenkeberg.
+	by Eberhard Moenkeberg (emoenke@gwdg.de). ISP16 detection and
+	configuration by Eric van der Maarel (maarel@marin.nl), with some data
+	communicated by Vadim V. Model (vadim@rbrf.msk.su).
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
@@ -38,6 +40,12 @@
 				should go into its own driver. The driver now
 				has its own major nr.
 				Disk change detection now seems to work, too.
+				This version became part of the standard
+				kernel as of version 1.3.7
+	24-9-95		v0.4	Re-inserted ISP-16 interface code which I
+				copied from sjcd.c, with a few changes.
+				Updated README.optcd. Submitted for
+				inclusion in 1.3.21
 */
 
 #include <linux/major.h>
@@ -69,6 +77,59 @@
 #define optcd_port optcd	/* Needed for the modutils. */
 # include <linux/optcd.h>
 
+
+/* Some (Media)Magic */
+/* define types of drive the interface on an ISP16 card may be looking at */
+#define ISP16_DRIVE_X 0x00
+#define ISP16_SONY  0x02
+#define ISP16_PANASONIC0 0x02
+#define ISP16_SANYO0 0x02
+#define ISP16_MITSUMI  0x04
+#define ISP16_PANASONIC1 0x06
+#define ISP16_SANYO1 0x06
+#define ISP16_DRIVE_NOT_USED 0x08  /* not used */
+#define ISP16_DRIVE_SET_MASK 0xF1  /* don't change 0-bit or 4-7-bits*/
+/* ...for port */
+#define ISP16_DRIVE_SET_PORT 0xF8D
+/* set io parameters */
+#define ISP16_BASE_340  0x00
+#define ISP16_BASE_330  0x40
+#define ISP16_BASE_360  0x80
+#define ISP16_BASE_320  0xC0
+#define ISP16_IRQ_X  0x00
+#define ISP16_IRQ_5  0x04  /* shouldn't be used due to soundcard conflicts */
+#define ISP16_IRQ_7  0x08  /* shouldn't be used due to soundcard conflicts */
+#define ISP16_IRQ_3  0x0C
+#define ISP16_IRQ_9  0x10
+#define ISP16_IRQ_10  0x14
+#define ISP16_IRQ_11  0x18
+#define ISP16_DMA_X  0x03
+#define ISP16_DMA_3  0x00
+#define ISP16_DMA_5  0x00
+#define ISP16_DMA_6  0x01
+#define ISP16_DMA_7  0x02
+#define ISP16_IO_SET_MASK  0x20  /* don't change 5-bit */
+/* ...for port */
+#define ISP16_IO_SET_PORT  0xF8E
+/* enable the drive */
+#define ISP16_NO_IDE__ENABLE_CDROM_PORT  0xF90  /* ISP16 without IDE interface */
+#define ISP16_IDE__ENABLE_CDROM_PORT  0xF91  /* ISP16 with IDE interface */
+#define ISP16_ENABLE_CDROM  0x80  /* seven bit */
+
+/* the magic stuff */
+#define ISP16_CTRL_PORT  0xF8F
+#define ISP16_NO_IDE__CTRL  0xE2  /* ISP16 without IDE interface */
+#define ISP16_IDE__CTRL  0xE3  /* ISP16 with IDE interface */
+
+static short isp16_detect(void);
+static short isp16_no_ide__detect(void);
+static short isp16_with_ide__detect(void);
+static short isp16_config( int base, u_char drive_type, int irq, int dma );
+static short isp16_type; /* dependent on type of interface card */
+static u_char isp16_ctrl;
+static u_short isp16_enable_cdrom_port;
+
+
 static short optcd_port = OPTCD_PORTBASE;
 
 /* Read current status/data availability flags */
@@ -1363,6 +1424,29 @@
 			optcd_port);
 		RETURN_EIO;
 	}
+
+	if (!check_region(ISP16_DRIVE_SET_PORT, 5)) {
+	/* If someone else has'nt already reserved these ports,
+	   probe for an ISP16 interface card, and enable SONY mode
+	   with no interrupts and no DMA. (As far as I know, all optics
+	   drives come with a SONY interface.) */
+  if ( (isp16_type=isp16_detect()) < 0 )
+    printk( "No ISP16 cdrom interface found.\n" );
+  else {
+    u_char expected_drive;
+
+    printk( "ISP16 cdrom interface (%s optional IDE) detected.\n",
+      (isp16_type==2)?"with":"without" );
+
+    expected_drive = (isp16_type?ISP16_SANYO1:ISP16_SANYO0);
+
+    if ( isp16_config( optcd_port, ISP16_SONY, 0, 0 ) < 0 ) {
+      printk( "ISP16 cdrom interface has not been properly configured.\n" );
+      return(mem_start);
+    }
+  }
+	}
+
 	if (!optResetDrive()) {
 		printk("optcd: drive at 0x%x not ready\n", optcd_port);
 		RETURN_EIO;
@@ -1406,3 +1490,191 @@
 	printk("optcd: module released.\n");
 }
 #endif MODULE
+
+
+/*
+ * -- ISP16 detection and configuration
+ *
+ *    Copyright (c) 1995, Eric van der Maarel <maarel@marin.nl>
+ *
+ *    Version 0.5
+ *
+ *    Detect cdrom interface on ISP16 soundcard.
+ *    Configure cdrom interface.
+ *
+ *    Algorithm for the card with no IDE support option taken
+ *    from the CDSETUP.SYS driver for MSDOS,
+ *    by OPTi Computers, version 2.03.
+ *    Algorithm for the IDE supporting ISP16 as communicated
+ *    to me by Vadim Model and Leo Spiekman.
+ *
+ *    Use, modifification or redistribution of this software is
+ *    allowed under the terms of the GPL.
+ *
+ */
+
+
+#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p))
+#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
+
+static short
+isp16_detect(void)
+{
+
+  if ( !( isp16_with_ide__detect() < 0 ) )
+    return(2);
+  else
+    return( isp16_no_ide__detect() );
+}
+
+static short
+isp16_no_ide__detect(void)
+{
+  u_char ctrl;
+  u_char enable_cdrom;
+  u_char io;
+  short i = -1;
+
+  isp16_ctrl = ISP16_NO_IDE__CTRL;
+  isp16_enable_cdrom_port = ISP16_NO_IDE__ENABLE_CDROM_PORT;
+
+  /* read' and write' are a special read and write, respectively */
+
+  /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */
+  ctrl = ISP16_IN( ISP16_CTRL_PORT ) & 0xFC;
+  ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+
+  /* read' 3,4 and 5-bit from the cdrom enable port */
+  enable_cdrom = ISP16_IN( ISP16_NO_IDE__ENABLE_CDROM_PORT ) & 0x38;
+
+  if ( !(enable_cdrom & 0x20) ) {  /* 5-bit not set */
+    /* read' last 2 bits of ISP16_IO_SET_PORT */
+    io = ISP16_IN( ISP16_IO_SET_PORT ) & 0x03;
+    if ( ((io&0x01)<<1) == (io&0x02) ) {  /* bits are the same */
+      if ( io == 0 ) {  /* ...the same and 0 */
+        i = 0;
+        enable_cdrom |= 0x20;
+      }
+      else {  /* ...the same and 1 */  /* my card, first time 'round */
+        i = 1;
+        enable_cdrom |= 0x28;
+      }
+      ISP16_OUT( ISP16_NO_IDE__ENABLE_CDROM_PORT, enable_cdrom );
+    }
+    else {  /* bits are not the same */
+      ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+      return(i); /* -> not detected: possibly incorrect conclusion */
+    }
+  }
+  else if ( enable_cdrom == 0x20 )
+    i = 0;
+  else if ( enable_cdrom == 0x28 )  /* my card, already initialised */
+    i = 1;
+
+  ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+
+  return(i);
+}
+
+static short
+isp16_with_ide__detect(void)
+{
+  u_char ctrl;
+  u_char tmp;
+
+  isp16_ctrl = ISP16_IDE__CTRL;
+  isp16_enable_cdrom_port = ISP16_IDE__ENABLE_CDROM_PORT;
+
+  /* read' and write' are a special read and write, respectively */
+
+  /* read' ISP16_CTRL_PORT and save */
+  ctrl = ISP16_IN( ISP16_CTRL_PORT );
+
+  /* write' zero to the ctrl port and get response */
+  ISP16_OUT( ISP16_CTRL_PORT, 0 );
+  tmp = ISP16_IN( ISP16_CTRL_PORT );
+
+  if ( tmp != 2 )  /* isp16 with ide option not detected */
+    return(-1);
+
+  /* restore ctrl port value */
+  ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+  
+  return(2);
+}
+
+static short
+isp16_config( int base, u_char drive_type, int irq, int dma )
+{
+  u_char base_code;
+  u_char irq_code;
+  u_char dma_code;
+  u_char i;
+
+  if ( (drive_type == ISP16_MITSUMI) && (dma != 0) )
+    printk( "Mitsumi cdrom drive has no dma support.\n" );
+
+  switch (base) {
+  case 0x340: base_code = ISP16_BASE_340; break;
+  case 0x330: base_code = ISP16_BASE_330; break;
+  case 0x360: base_code = ISP16_BASE_360; break;
+  case 0x320: base_code = ISP16_BASE_320; break;
+  default:
+    printk( "Base address 0x%03X not supported by cdrom interface on ISP16.\n", base );
+    return(-1);
+  }
+  switch (irq) {
+  case 0: irq_code = ISP16_IRQ_X; break; /* disable irq */
+  case 5: irq_code = ISP16_IRQ_5;
+          printk( "Irq 5 shouldn't be used by cdrom interface on ISP16,"
+            " due to possible conflicts with the soundcard.\n");
+          break;
+  case 7: irq_code = ISP16_IRQ_7;
+          printk( "Irq 7 shouldn't be used by cdrom interface on ISP16,"
+            " due to possible conflicts with the soundcard.\n");
+          break;
+  case 3: irq_code = ISP16_IRQ_3; break;
+  case 9: irq_code = ISP16_IRQ_9; break;
+  case 10: irq_code = ISP16_IRQ_10; break;
+  case 11: irq_code = ISP16_IRQ_11; break;
+  default:
+    printk( "Irq %d not supported by cdrom interface on ISP16.\n", irq );
+    return(-1);
+  }
+  switch (dma) {
+  case 0: dma_code = ISP16_DMA_X; break;  /* disable dma */
+  case 1: printk( "Dma 1 cannot be used by cdrom interface on ISP16,"
+            " due to conflict with the soundcard.\n");
+          return(-1); break;
+  case 3: dma_code = ISP16_DMA_3; break;
+  case 5: dma_code = ISP16_DMA_5; break;
+  case 6: dma_code = ISP16_DMA_6; break;
+  case 7: dma_code = ISP16_DMA_7; break;
+  default:
+    printk( "Dma %d not supported by cdrom interface on ISP16.\n", dma );
+    return(-1);
+  }
+
+  if ( drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 &&
+    drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 &&
+    drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI &&
+    drive_type != ISP16_DRIVE_X ) {
+    printk( "Drive type (code 0x%02X) not supported by cdrom"
+     " interface on ISP16.\n", drive_type );
+    return(-1);
+  }
+
+  /* set type of interface */
+  i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK;  /* clear some bits */
+  ISP16_OUT( ISP16_DRIVE_SET_PORT, i|drive_type );
+
+  /* enable cdrom on interface with ide support */
+  if ( isp16_type > 1 )
+    ISP16_OUT( isp16_enable_cdrom_port, ISP16_ENABLE_CDROM );
+
+  /* set base address, irq and dma */
+  i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK;  /* keep some bits */
+  ISP16_OUT( ISP16_IO_SET_PORT, i|base_code|irq_code|dma_code );
+
+  return(0);
+}
diff -u --recursive --new-file v1.3.20/linux/drivers/block/triton.c linux/drivers/block/triton.c
--- v1.3.20/linux/drivers/block/triton.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/block/triton.c	Mon Aug 28 09:19:32 1995
@@ -0,0 +1,352 @@
+/*
+ *  linux/drivers/block/triton.c	Version 1.00  Aug 26, 1995
+ *
+ *  Copyright (c) 1995  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This module provides support for the Bus Master IDE DMA function
+ * of the Intel PCI Triton chipset (82371FB).
+ *
+ * DMA is currently supported only for hard disk drives (not cdroms).
+ *
+ * Support for cdroms will likely be added at a later date,
+ * after broader experience has been obtained with hard disks.
+ *
+ * Up to four drives may be enabled for DMA, and the Triton chipset will
+ * (hopefully) arbitrate the PCI bus among them.  Note that the 82371FB chip
+ * provides a single "line buffer" for the BM IDE function, so performance of
+ * multiple (two) drives doing DMA simultaneously will suffer somewhat,
+ * as they contest for that resource bottleneck.  This is handled transparently
+ * inside the 82371FB chip.
+ *
+ * By default, DMA support is prepared for use, but is currently enabled only
+ * for drives which support multi-word DMA mode2 (mword2), or which are
+ * recognized as "good" (see table below).  Drives with only mode0 or mode1
+ * (single or multi) DMA should also work with this chipset/driver (eg. MC2112A)
+ * but are not enabled by default.  Use "hdparm -i" to view supported modes
+ * for a given drive.
+ *
+ * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling
+ * DMA support, but must be (re-)compiled against this kernel version or later.
+ *
+ * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
+ * If problems arise, ide.c will disable DMA operation after a few retries.
+ * This error recovery mechanism works and has been extremely well exercised.
+ *
+ * IDE drives, depending on their vintage, may support several different modes
+ * of DMA operation.  The boot-time modes are indicated with a "*" in
+ * the "hdparm -i" listing, and can be changed with *knowledgeable* use of
+ * the "hdparm -X" feature.  There is seldom a need to do this, as drives
+ * normally power-up with their "best" PIO/DMA modes enabled.
+ *
+ * Testing was done with an ASUS P55TP4XE/100 system and the following drives:
+ *
+ *   Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4.
+ *	- DMA mode2 works fine (7.4MB/sec), despite the tiny on-drive buffer.
+ *	- This drive also does PIO mode4, slightly slower than DMA mode2.
+ *
+ *   Micropolis MC2112A (1Gig w/512kB buffer), drive pre-dates EIDE, ATA2.
+ *	- DMA works fine (2.2MB/sec), probably due to the large on-drive buffer.
+ *	- This older drive can also be tweaked for fastPIO (3,7MB/sec) by using
+ *	  maximum clock settings (5,4) and setting all flags except prefetch.
+ *
+ *   Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3.
+ *	- DMA does not work reliably.  The drive appears to be somewhat tardy
+ *	  in deasserting DMARQ at the end of a sector.  This is evident in
+ *	  the observation that WRITEs work most of the time, depending on
+ *	  cache-buffer occupancy, but multi-sector reads seldom work.
+ *
+ * Drives like the AC31000H could likely be made to work if all DMA were done
+ * one sector at a time, but that would likely negate any advantage over PIO.
+ *
+ * If you have any drive models add, email your results to:  mlord@bnr.ca
+ * Keep an eye on your /var/adm/messages for "DMA disabled" messages.
+ */
+#define _TRITON_C
+#include <linux/config.h>
+#ifndef CONFIG_BLK_DEV_TRITON
+#define CONFIG_BLK_DEV_TRITON y
+#endif
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/io.h>
+
+#include "ide.h"
+
+/*
+ * good_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which do not support mword2 DMA but which are
+ * known to work fine with this interface under Linux.
+ */
+const char *good_dma_drives[] = {"Micropolis 2112A"};
+
+/*
+ * Our Physical Region Descriptor (PRD) table should be large enough
+ * to handle the biggest I/O request we are likely to see.  Since requests
+ * can have no more than 256 sectors, and since the typical blocksize is
+ * two sectors, we can get by with a limit of 128 entries here for the
+ * usual worst case.  Most requests seem to include some contiguous blocks,
+ * further reducing the number of table entries required.
+ *
+ * Note that the driver reverts to PIO mode for individual requests that exceed
+ * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
+ * 100% of all crazy scenarios here is not necessary.
+ */
+#define PRD_ENTRIES	128	/* max memory area count per DMA */
+
+/*
+ * dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static void dma_intr (ide_drive_t *drive)
+{
+	byte stat, dma_stat;
+	int i;
+	struct request *rq = HWGROUP(drive)->rq;
+	unsigned short dma_base = HWIF(drive)->dma_base;
+
+	dma_stat = inb(dma_base+2);	/* get DMA status */
+	outb(inb(dma_base)&~1, dma_base);	/* stop DMA operation */
+	stat = GET_STAT();
+	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+		if ((dma_stat & 7) == 4) {	/* verify good DMA status */
+			rq = HWGROUP(drive)->rq;
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				ide_end_request(1, HWGROUP(drive));
+			}
+			IDE_DO_REQUEST;
+			return;
+		}
+		printk("%s: bad DMA status: 0x%02x\n", drive->name, dma_stat);
+	}
+	sti();
+	if (!ide_error(drive, "dma_intr", stat))
+		IDE_DO_REQUEST;
+}
+
+/*
+ * build_dmatable() prepares a dma request.
+ * Returns 0 if all went okay, returns 1 otherwise.
+ */
+static int build_dmatable (ide_drive_t *drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	struct buffer_head *bh = rq->bh;
+	unsigned long size, addr, *table = HWIF(drive)->dmatable;
+	unsigned int count = 0;
+
+	do {
+		/*
+		 * Determine addr and size of next buffer area.  We assume that
+		 * individual virtual buffers are always composed linearly in
+		 * physical memory.  For example, we assume that any 8kB buffer
+		 * is always composed of two adjacent physical 4kB pages rather
+		 * than two possibly non-adjacent physical 4kB pages.
+		 */
+		if (bh == NULL) {  /* paging requests have (rq->bh == NULL) */
+			addr = virt_to_bus (rq->buffer);
+			size = rq->nr_sectors << 9;
+		} else {
+			/* group sequential buffers into one large buffer */
+			addr = virt_to_bus (bh->b_data);
+			size = bh->b_size;
+			while ((bh = bh->b_reqnext) != NULL) {
+				if ((addr + size) != virt_to_bus (bh->b_data))
+					break;
+				size += bh->b_size;
+			}
+		}
+
+		/*
+		 * Fill in the dma table, without crossing any 64kB boundaries.
+		 * We assume 16-bit alignment of all blocks.
+		 */
+		while (size) {
+			if (++count >= PRD_ENTRIES) {
+				printk("%s: DMA table too small\n", drive->name);
+				return 1; /* revert to PIO for this request */
+			} else {
+				unsigned long bcount = 0x10000 - (addr & 0xffff);
+				if (bcount > size)
+					bcount = size;
+				*table++ = addr;
+				*table++ = bcount;
+				addr += bcount;
+				size -= bcount;
+			}
+		}
+	} while (bh != NULL);
+	if (count) {
+		*--table |= 0x80000000;	/* set End-Of-Table (EOT) bit */
+		return 0;
+	}
+	printk("%s: empty DMA table?\n", drive->name);
+	return 1;	/* let the PIO routines handle this weirdness */
+}
+
+/*
+ * triton_dmaproc() initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA.  All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case
+ * the caller should revert to PIO for the current request.
+ */
+static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	const char **list;
+	unsigned long dma_base = HWIF(drive)->dma_base;
+
+	if (func == ide_dma_abort) {
+		outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
+		return 0;
+	}
+	if (func == ide_dma_check) {
+		struct hd_driveid *id = drive->id;
+		if (id && (id->capability & 1)) {
+			/* Enable DMA on any drive that supports mword2 DMA */
+			if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
+				drive->using_dma = 1;
+				return 0;		/* DMA enabled */
+			}
+			/* Consult the list of known "good" drives */
+			list = good_dma_drives;
+			while (*list) {
+				if (!strcmp(*list++,id->model)) {
+					drive->using_dma = 1;
+					return 0;	/* DMA enabled */
+				}
+			}
+		}
+		return 1;	/* DMA not enabled */
+	}
+	if (build_dmatable (drive))
+		return 1;
+	outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */
+	outb((!func) << 3, dma_base);			/* specify r/w */
+	outb(0x26, dma_base+2);				/* clear status bits */
+	ide_set_handler (drive, &dma_intr);		/* issue cmd to drive */
+	OUT_BYTE(func ? WIN_WRITEDMA : WIN_READDMA, IDE_COMMAND_REG);
+	outb(inb(dma_base)|1, dma_base);			/* begin DMA */
+	return 0;
+}
+
+/*
+ * print_triton_drive_flags() displays the currently programmed options
+ * in the Triton chipset for a given drive.
+ *
+ *	If fastDMA  is "no", then slow ISA timings are used for DMA data xfers.
+ *	If fastPIO  is "no", then slow ISA timings are used for PIO data xfers.
+ *	If IORDY    is "no", then IORDY is assumed to always be asserted.
+ *	If PreFetch is "no", then data pre-fetch/post are not used.
+ *
+ * When "fastPIO" and/or "fastDMA" are "yes", then faster PCI timings and
+ * back-to-back 16-bit data transfers are enabled, using the sample_CLKs
+ * and recovery_CLKs (PCI clock cycles) timing parameters for that interface.
+ */
+static void print_triton_drive_flags (unsigned int unit, byte flags)
+{
+	printk("         %s ", unit ? "slave :" : "master:");
+	printk( "fastDMA=%s",	(flags&9)	? "on " : "off");
+	printk(" PreFetch=%s",	(flags&4)	? "on " : "off");
+	printk(" IORDY=%s",	(flags&2)	? "on " : "off");
+	printk(" fastPIO=%s\n",	((flags&9)==1)	? "on " : "off");
+}
+
+/*
+ * ide_init_triton() uses the PCI BIOS to scan for a Triton i82371FB chip,
+ * and prepares the IDE driver for DMA operation if one is found.
+ * This routine is called from ide.c during driver initialization.
+ */
+void ide_init_triton (ide_hwif_t  hwifs[])
+{
+	int rc = 0, h;
+	unsigned short bmiba, pcicmd;
+	unsigned int timings;
+	unsigned char bus, fn;
+
+	if (pcibios_find_device (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371, 0, &bus, &fn))
+		goto quit;
+	++fn;	/* IDE is second function on this chip */
+
+	/*
+	 * See if IDE and BM-DMA features are enabled:
+	 */
+	if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd)))
+		goto quit;
+	if ((pcicmd & 5) != 5) {
+		if ((pcicmd & 1) == 0)
+			printk("ide: Triton IDE ports are not enabled\n");
+		else
+			printk("ide: Triton BM-DMA feature is not enabled\n");
+		goto quit;
+	}
+#if 0
+	(void) pcibios_write_config_word(bus, fn, 0x42, 0x8037); /* for my MC2112A */
+#endif
+	/*
+	 * See if ide port(s) are enabled
+	 */
+	if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings)))
+		goto quit;
+	if (!(timings & 0x80008000)) {
+		printk("ide: Triton IDE ports are not enabled\n");
+		goto quit;
+	}
+	printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn);
+
+	/*
+	 * Get the bmiba base address
+	 */
+	if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba)))
+		goto quit;
+	bmiba &= 0xfff0;	/* extract port base address */
+
+	/*
+	 * Save the dma_base port addr for each interface
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_hwif_t *hwif = &hwifs[h];
+		unsigned short base, time;
+		if (hwif->io_base == 0x1f0 && (timings & 0x8000)) {
+			time = timings & 0xffff;
+			base = bmiba;
+		} else if (hwif->io_base == 0x170 && (timings & 0x80000000)) {
+			time = timings >> 16;
+			base = bmiba + 8;
+		} else
+			continue;
+		printk("    %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+5);
+		if (check_region(base, 6)) {
+			printk(" -- ERROR, PORTS ALREADY IN USE");
+		} else {
+			unsigned long *table;
+			request_region(base, 8, hwif->name);
+			hwif->dma_base  = base;
+			table = ide_alloc(2 * PRD_ENTRIES * sizeof(long), 4096);
+			hwif->dmatable = table;
+			outl((unsigned long) table, base + 4);
+			hwif->dmaproc  = &triton_dmaproc;
+		}
+		printk("\n    %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
+		 hwif->name, time, ((~time>>12)&3)+2, ((~time>>8)&3)+1);
+		print_triton_drive_flags (0, time & 0xf);
+		print_triton_drive_flags (1, (time >> 4) & 0xf);
+	}
+
+quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
+}
+
diff -u --recursive --new-file v1.3.20/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v1.3.20/linux/drivers/char/lp.c	Sun Aug 13 14:45:28 1995
+++ linux/drivers/char/lp.c	Mon Aug 28 09:01:27 1995
@@ -33,7 +33,7 @@
 
 /* the BIOS manuals say there can be up to 4 lpt devices
  * but I have not seen a board where the 4th address is listed
- * if you have different hardware change the table below 
+ * if you have different hardware change the table below
  * please let me know if you have different equipment
  * if you have more than 3 printers, remember to increase LP_NO
  */
@@ -41,7 +41,7 @@
 	{ 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
 	{ 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
 	{ 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },
-}; 
+};
 #define LP_NO 3
 
 /* Test if printer is ready (and optionally has no error conditions) */
@@ -51,9 +51,9 @@
   ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : 1)
 #define _LP_CAREFUL_READY(status) \
    (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
-      (LP_PBUSY|LP_PSELECD|LP_PERRORP) 
+      (LP_PBUSY|LP_PSELECD|LP_PERRORP)
 
-/* 
+/*
  * All my debugging code assumes that you debug with only one printer at
  * a time. RWWH
  * Debug info moved into stats area, so this is no longer true (Rob Janssen)
@@ -72,7 +72,7 @@
 static inline int lp_char_polled(char lpchar, int minor)
 {
 	int status, wait = 0;
-	unsigned long count  = 0; 
+	unsigned long count  = 0;
 	struct lp_stats *stats;
 
 	do {
@@ -92,10 +92,10 @@
 	/* must wait before taking strobe high, and after taking strobe
 	   low, according spec.  Some printers need it, others don't. */
 	while(wait != LP_WAIT(minor)) wait++;
-        /* control port takes strobe high */
+	/* control port takes strobe high */
 	outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
 	while(wait) wait--;
-        /* take strobe low */
+	/* take strobe low */
 	outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
 	/* update waittime statistics */
 	if (count > stats->maxwait) {
@@ -116,7 +116,7 @@
 static inline int lp_char_interrupt(char lpchar, int minor)
 {
 	int wait;
-	unsigned long count = 0; 
+	unsigned long count = 0;
 	unsigned char status;
 	struct lp_stats *stats;
 
@@ -269,7 +269,7 @@
 				current->timeout = jiffies + LP_TIMEOUT_POLLED;
 				schedule();
 			} else
-	                /* not offline or out of paper. on fire? */
+			/* not offline or out of paper. on fire? */
 			if (!(status & LP_PERRORP)) {
 				printk(KERN_ERR "lp%d reported invalid error status (on fire, eh?)\n", minor);
 				if(LP_F(minor) & LP_ABORT)
@@ -340,7 +340,7 @@
 	   have commandeered O_NONBLOCK, even though it is being used in
 	   a non-standard manner.  This is strictly a Linux hack, and
 	   should most likely only ever be used by the tunelp application. */
-        if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {
+	if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {
 		int status = LP_S(minor);
 		if (status & LP_POUTPA) {
 			printk(KERN_INFO "lp%d out of paper\n", minor);
@@ -545,7 +545,7 @@
 		printk("lp: unable to get major %d\n", LP_MAJOR);
 #ifdef MODULE
 		return -EIO;
-#else		
+#else
 		return kmem_start;
 #endif
 	}
@@ -577,7 +577,7 @@
 
 #ifdef MODULE
 	return 0;
-#else	
+#else
 	return kmem_start;
 #endif
 }
@@ -586,14 +586,19 @@
 #ifdef MODULE
 void cleanup_module(void)
 {
-        int offset;
-	if(MOD_IN_USE)
-               printk("lp: busy - remove delayed\n");
-        else {
-               unregister_chrdev(LP_MAJOR,"lp");
-	       for (offset = 0; offset < LP_NO; offset++) 
-			if (LP_F(offset) & LP_EXIST) 
-		 		release_region(LP_B(offset),3);
+	int offset;
+
+	if(MOD_IN_USE) {
+	       printk("lp: busy - remove delayed\n");
+	       return;
+	}
+	unregister_chrdev(LP_MAJOR,"lp");
+	for (offset = 0; offset < LP_NO; offset++) {
+		int base, size;
+		base = LP_B(offset);
+		size = (base == 0x3bc)? 3 : 8;
+		if (LP_F(offset) & LP_EXIST)
+			release_region(LP_B(offset),size);
 	}
 }
 
diff -u --recursive --new-file v1.3.20/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.3.20/linux/drivers/char/serial.c	Tue Aug 15 20:39:02 1995
+++ linux/drivers/char/serial.c	Fri Aug 18 11:08:52 1995
@@ -31,7 +31,6 @@
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
-#include <linux/major.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
 
diff -u --recursive --new-file v1.3.20/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.20/linux/drivers/net/Makefile	Fri Aug 18 08:44:57 1995
+++ linux/drivers/net/Makefile	Fri Aug 18 09:41:31 1995
@@ -298,7 +298,8 @@
 depca.o: depca.c CONFIG
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
 
-Space.o: ../../include/linux/autoconf.h
+Space.o: Space.c ../../include/linux/autoconf.h CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(OPTS) -c $<
 
 net_init.o: ../../include/linux/autoconf.h
 
diff -u --recursive --new-file v1.3.20/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v1.3.20/linux/drivers/net/net_init.c	Tue Aug 15 20:39:03 1995
+++ linux/drivers/net/net_init.c	Mon Aug 28 10:43:29 1995
@@ -341,13 +341,13 @@
 			restore_flags(flags);
 			return;
 		}
-		for (i = 0; i < MAX_ETH_CARDS; ++i) 
+	}
+	for (i = 0; i < MAX_ETH_CARDS; ++i) 
+	{
+		if (ethdev_index[i] == dev) 
 		{
-			if (ethdev_index[i] == dev) 
-			{
-				ethdev_index[i] = NULL;
-				break;
-			}
+			ethdev_index[i] = NULL;
+			break;
 		}
 	}
 	restore_flags(flags);
diff -u --recursive --new-file v1.3.20/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.3.20/linux/drivers/net/ppp.c	Wed Aug  2 13:21:05 1995
+++ linux/drivers/net/ppp.c	Fri Aug 18 08:35:08 1995
@@ -1775,7 +1775,7 @@
 
   /* If doing demand dial then divert the first frame to pppd. */
   if (ppp->flags & SC_IP_DOWN) {
-    if (ppp->flags & SC_IP_FLUSH == 0) {
+    if ((ppp->flags & SC_IP_FLUSH) == 0) {
       if (ppp_us_queue (ppp, proto, p, len))
 	ppp->flags |= SC_IP_FLUSH;
     }
diff -u --recursive --new-file v1.3.20/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v1.3.20/linux/drivers/pci/pci.c	Tue Aug 15 20:39:04 1995
+++ linux/drivers/pci/pci.c	Fri Aug 18 08:43:14 1995
@@ -73,7 +73,7 @@
 	BRIDGE( INTEL,		INTEL_82434,	"82434LX Mercury/Neptune", 0x00),
 	DEVICE( INTEL,		INTEL_82430,	"82430ZX Aries"),
 	DEVICE( INTEL,		INTEL_82437,	"82437 Triton"),
-	DEVICE( INTEL,		INTEL_82371,	"82471 Triton"),
+	DEVICE( INTEL,		INTEL_82371,	"82371 Triton"),
 	DEVICE( INTEL,		INTEL_82438,	"82438"),
 	DEVICE( INTEL,		INTEL_7116,	"SAA7116"),
 	DEVICE( INTEL,		INTEL_82865,	"82865"),
@@ -261,7 +261,7 @@
 	      case PCI_CLASS_NOT_DEFINED_VGA:		return "VGA compatible device";
 
 	      case PCI_CLASS_STORAGE_SCSI:		return "SCSI storage controller";
-	      case PCI_CLASS_STORAGE_IDE:		return "IDE controller";
+	      case PCI_CLASS_STORAGE_IDE:		return "IDE interface";
 	      case PCI_CLASS_STORAGE_FLOPPY:		return "Floppy disk controller";
 	      case PCI_CLASS_STORAGE_IPI:		return "IPI bus controller";
 	      case PCI_CLASS_STORAGE_RAID:		return "RAID bus controller";
diff -u --recursive --new-file v1.3.20/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.3.20/linux/drivers/scsi/Makefile	Fri Aug 18 08:44:57 1995
+++ linux/drivers/scsi/Makefile	Thu Aug 17 07:19:18 1995
@@ -191,7 +191,7 @@
 	$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c 
 
 aic7xxx_asm:	aic7xxx_asm.c
-	$(CC) $(CFLAGS) -o $@ aic7xxx_asm.c
+	$(HOSTCC) -o $@ aic7xxx_asm.c
 
 aic7xxx.c: aic7xxx_seq.h
 aic7xxx_seq.h:	aic7xxx_asm aic7xxx.seq
diff -u --recursive --new-file v1.3.20/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.20/linux/drivers/scsi/scsi.c	Tue Aug  8 12:31:38 1995
+++ linux/drivers/scsi/scsi.c	Mon Aug 28 10:13:21 1995
@@ -107,9 +107,9 @@
  * It is only initialized to !=0 if the scsi code is present 
  */ 
 extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, 
-                                      off_t offset, int length, int inout); 
+				      off_t offset, int length, int inout); 
 extern int dispatch_scsi_info(int ino, char *buffer, char **start, 
-                              off_t offset, int length, int inout); 
+			      off_t offset, int length, int inout); 
 
 
 /*
@@ -202,19 +202,19 @@
 {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
 {"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
 {"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},   /* causes failed REQUEST SENSE on lun 1 
-                                                 * for aha152x controller, which causes 
-                                                 * SCSI code to reset bus.*/
+						 * for aha152x controller, which causes 
+						 * SCSI code to reset bus.*/
 {"SEAGATE", "ST296","921", BLIST_NOLUN},        /* Responds to all lun */
 {"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN},
 {"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},
 {"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},
 {"TANDBERG","TDC 3600","U07", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
 {"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1 
-                                                 * for seagate controller, which causes 
-                                                 * SCSI code to reset bus.*/
+						 * for seagate controller, which causes 
+						 * SCSI code to reset bus.*/
 {"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1 
-                                                 * for seagate controller, which causes 
-                                                 * SCSI code to reset bus.*/
+						 * for seagate controller, which causes 
+						 * SCSI code to reset bus.*/
 {"QUANTUM","LPS525S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
 {"QUANTUM","PD1225S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
 {"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN},   /* Locks up if polled for lun != 0 */
@@ -407,12 +407,12 @@
 		
 		/*
 		 * We need the for so our continue, etc. work fine.
-                 * We put this in a variable so that we can override
-                 * it during the scan if we detect a device *KNOWN*
-                 * to have multiple logical units.
+		 * We put this in a variable so that we can override
+		 * it during the scan if we detect a device *KNOWN*
+		 * to have multiple logical units.
 		 */
-                max_dev_lun = (max_scsi_luns < shpnt->max_lun ? 
-                               max_scsi_luns : shpnt->max_lun);
+		max_dev_lun = (max_scsi_luns < shpnt->max_lun ? 
+			       max_scsi_luns : shpnt->max_lun);
 
 		for (lun = 0; lun < max_dev_lun; ++lun)
 		{
@@ -555,8 +555,8 @@
 				SDpnt->manufacturer = SCSI_MAN_NEC;
 			} else if (!strncmp(scsi_result+8,"TOSHIBA",7))
 			    SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
-                        else if (!strncmp(scsi_result+8,"SONY",4))
-                            SDpnt->manufacturer = SCSI_MAN_SONY;
+			else if (!strncmp(scsi_result+8,"SONY",4))
+			    SDpnt->manufacturer = SCSI_MAN_SONY;
 			else
 			    SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
 			
@@ -569,7 +569,7 @@
 			SDpnt->changed = 0;
 			SDpnt->access_count = 0;
 			SDpnt->busy = 0;
-                        SDpnt->has_cmdblocks = 0;
+			SDpnt->has_cmdblocks = 0;
 			/*
 			 * Currently, all sequential devices are assumed to be
 			 * tapes, all random devices disk, with the appropriate
@@ -599,7 +599,7 @@
 #endif
 			}
 			
-                        SDpnt->single_lun = 0;
+			SDpnt->single_lun = 0;
 			SDpnt->soft_reset =
 			    (scsi_result[7] & 1) && ((scsi_result[3] &7) == 2);
 			SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
@@ -640,10 +640,10 @@
 
 			    SDpnt->disconnect = 0;
 
-                            /*
-                             * Get any flags for this device.
-                             */
-                            bflags = get_device_flags(scsi_result);
+			    /*
+			     * Get any flags for this device.
+			     */
+			    bflags = get_device_flags(scsi_result);
 
 			    
 			    /*
@@ -654,16 +654,16 @@
 			     * change it here if it turns out that it isn't
 			     * a TEXEL drive.
 			     */
-                            if( (bflags & BLIST_BORKEN) == 0 )
-                            {
+			    if( (bflags & BLIST_BORKEN) == 0 )
+			    {
 				SDpnt->borken = 0;
-                            }
+			    }
 			    
 			    
 			    /* These devices need this "key" to unlock the
 			     * devices so we can use it 
 			     */
-                            if( (bflags & BLIST_KEY) != 0 ) {
+			    if( (bflags & BLIST_KEY) != 0 ) {
 				printk("Unlocked floptical drive.\n");
 				SDpnt->lockable = 0;
 				scsi_cmd[0] = MODE_SENSE;
@@ -706,28 +706,28 @@
 			     */
 			    if(bflags & BLIST_NOLUN) break;
 
-                            /*
-                             * If we want to only allow I/O to one of the luns
-                             * attached to this device at a time, then we set this
-                             * flag.
-                             */
-                            if(bflags & BLIST_SINGLELUN)
-                            {
-                                SDpnt->single_lun = 1;
-                            }
-
-                            /*
-                             * If this device is known to support multiple units, override
-                             * the other settings, and scan all of them.
-                             */
-                            if(bflags & BLIST_FORCELUN)
-                            {
-                                /*
-                                 * We probably want to make this a variable, but this
-                                 * will do for now.
-                                 */
-                                max_dev_lun = 8;
-                            }
+			    /*
+			     * If we want to only allow I/O to one of the luns
+			     * attached to this device at a time, then we set this
+			     * flag.
+			     */
+			    if(bflags & BLIST_SINGLELUN)
+			    {
+				SDpnt->single_lun = 1;
+			    }
+
+			    /*
+			     * If this device is known to support multiple units, override
+			     * the other settings, and scan all of them.
+			     */
+			    if(bflags & BLIST_FORCELUN)
+			    {
+				/*
+				 * We probably want to make this a variable, but this
+				 * will do for now.
+				 */
+				max_dev_lun = 8;
+			    }
  
 
 			    /* Old drives like the MAXTOR XT-3280 say vers=0 */
@@ -741,10 +741,10 @@
 			}
 		    }       /* if result == DID_OK ends */
 
-                    /*
-                     * This might screw us up with multi-lun devices, but the user can
-                     * scan for them too.
-                     */
+		    /*
+		     * This might screw us up with multi-lun devices, but the user can
+		     * scan for them too.
+		     */
 		    if(hardcoded == 1)
 			goto leave;
 		} /* for lun ends */
@@ -850,35 +850,35 @@
       
     SCpnt = device->host->host_queue;
     if (!device->single_lun) {
-        while(SCpnt){
-            if(SCpnt->target == device->id &&
-               SCpnt->lun == device->lun) {
-                if(SCpnt->request.dev < 0) break;
-            }
-            SCpnt = SCpnt->next;
-        }
+	while(SCpnt){
+	    if(SCpnt->target == device->id &&
+	       SCpnt->lun == device->lun) {
+		if(SCpnt->request.dev < 0) break;
+	    }
+	    SCpnt = SCpnt->next;
+	}
     } else {
-        while(SCpnt){
-            if(SCpnt->target == device->id) {
-                if (SCpnt->lun == device->lun) {
-                    if(found == NULL 
-                       && SCpnt->request.dev < 0) 
-                    {
-                        found=SCpnt;
-                    }
-                } 
-                if(SCpnt->request.dev >= 0) {
-                    /*
-                     * I think that we should really limit things to one
-                     * outstanding command per device - this is what tends to trip
-                     * up buggy firmware.
-                     */
-                    return NULL;
-                }
-            }
-            SCpnt = SCpnt->next;
-        }
-        SCpnt = found;
+	while(SCpnt){
+	    if(SCpnt->target == device->id) {
+		if (SCpnt->lun == device->lun) {
+		    if(found == NULL 
+		       && SCpnt->request.dev < 0) 
+		    {
+			found=SCpnt;
+		    }
+		} 
+		if(SCpnt->request.dev >= 0) {
+		    /*
+		     * I think that we should really limit things to one
+		     * outstanding command per device - this is what tends to trip
+		     * up buggy firmware.
+		     */
+		    return NULL;
+		}
+	    }
+	    SCpnt = SCpnt->next;
+	}
+	SCpnt = found;
     }
     
     if (!SCpnt) return NULL;
@@ -975,41 +975,41 @@
     if (intr_count && SCSI_BLOCK(host)) return NULL;
     
     while (1==1){
-        SCpnt = device->host->host_queue;
-        if (!device->single_lun) {
-            while(SCpnt){
-                if(SCpnt->target == device->id &&
-                   SCpnt->lun == device->lun) {
-                   SCwait = SCpnt;
-                    if(SCpnt->request.dev < 0) break;
-                }
-                SCpnt = SCpnt->next;
-            }
-        } else {
-            while(SCpnt){
-                if(SCpnt->target == device->id) {
-                    if (SCpnt->lun == device->lun) {
-                        SCwait = SCpnt;
-                        if(found == NULL 
-                           && SCpnt->request.dev < 0) 
-                        {
-                            found=SCpnt;
-                        }
-                    } 
-                    if(SCpnt->request.dev >= 0) {
-                        /*
-                         * I think that we should really limit things to one
-                         * outstanding command per device - this is what tends to trip
-                         * up buggy firmware.
-                         */
-                        found = NULL;
-                        break;
-                    }
-                }
-                SCpnt = SCpnt->next;
-            }
-            SCpnt = found;
-        }
+	SCpnt = device->host->host_queue;
+	if (!device->single_lun) {
+	    while(SCpnt){
+		if(SCpnt->target == device->id &&
+		   SCpnt->lun == device->lun) {
+		   SCwait = SCpnt;
+		    if(SCpnt->request.dev < 0) break;
+		}
+		SCpnt = SCpnt->next;
+	    }
+	} else {
+	    while(SCpnt){
+		if(SCpnt->target == device->id) {
+		    if (SCpnt->lun == device->lun) {
+			SCwait = SCpnt;
+			if(found == NULL 
+			   && SCpnt->request.dev < 0) 
+			{
+			    found=SCpnt;
+			}
+		    } 
+		    if(SCpnt->request.dev >= 0) {
+			/*
+			 * I think that we should really limit things to one
+			 * outstanding command per device - this is what tends to trip
+			 * up buggy firmware.
+			 */
+			found = NULL;
+			break;
+		    }
+		}
+		SCpnt = SCpnt->next;
+	    }
+	    SCpnt = found;
+	}
 
 	save_flags(flags);
 	cli();
@@ -2198,7 +2198,8 @@
 		scsi_init_memory_start += size;
 	    }
 	}
-    memset((void *) retval, 0, size);
+    if (retval)
+	memset((void *) retval, 0, size);
     return (void *) retval;
 }
 
@@ -2341,19 +2342,22 @@
     
     dma_sectors = (dma_sectors + 15) & 0xfff0;
     dma_free_sectors = dma_sectors;  /* This must be a multiple of 16 */
+
+    if (dma_sectors)
+    {
+	dma_malloc_freelist = (unsigned char *)
+	    scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
+	memset(dma_malloc_freelist, 0, dma_sectors >> 3);
+
+	dma_malloc_pages = (unsigned char **)
+	    scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
+	memset(dma_malloc_pages, 0, dma_sectors >> 1);
+
+	for(i=0; i< dma_sectors >> 3; i++)
+	    dma_malloc_pages[i] = (unsigned char *)
+		scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
     
-    dma_malloc_freelist = (unsigned char *)
-	scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
-    memset(dma_malloc_freelist, 0, dma_sectors >> 3);
-    
-    dma_malloc_pages = (unsigned char **)
-	scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
-    memset(dma_malloc_pages, 0, dma_sectors >> 1);
-    
-    for(i=0; i< dma_sectors >> 3; i++)
-	dma_malloc_pages[i] = (unsigned char *)
-	    scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-    
+    }
     /* OK, now we finish the initialization by doing spin-up, read
      * capacity, etc, etc 
      */
@@ -2440,40 +2444,40 @@
     HBA_ptr = scsi_hostlist;
 
     if(inout == 0) { 
-        size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
-        len += size; 
-        pos = begin + len;
-        while (HBA_ptr) {
+	size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+	len += size; 
+	pos = begin + len;
+	while (HBA_ptr) {
 #if 0
-            size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, HBA_ptr->hostt->procname);
-            len += size; 
-            pos = begin + len;
-#endif
-            scd = scsi_devices;
-            while (scd) {
-                if (scd->host == HBA_ptr) {
-                    proc_print_scsidevice(scd, buffer, &size, len);
-                    len += size; 
-                    pos = begin + len;
-                    
-                    if (pos < offset) {
-                        len = 0;
-                        begin = pos;
-                    }
-                    if (pos > offset + length)
-                        goto stop_output;
-                }
-                scd = scd->next;
-            }
+	    size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, HBA_ptr->hostt->procname);
+	    len += size; 
+	    pos = begin + len;
+#endif
+	    scd = scsi_devices;
+	    while (scd) {
+		if (scd->host == HBA_ptr) {
+		    proc_print_scsidevice(scd, buffer, &size, len);
+		    len += size; 
+		    pos = begin + len;
+		    
+		    if (pos < offset) {
+			len = 0;
+			begin = pos;
+		    }
+		    if (pos > offset + length)
+			goto stop_output;
+		}
+		scd = scd->next;
+	    }
 	    HBA_ptr = HBA_ptr->next;
-        }
-        
+	}
+	
     stop_output:
-        *start=buffer+(offset-begin);   /* Start of wanted data */
-        len-=(offset-begin);	    /* Start slop */
-        if(len>length)
-            len = length;		    /* Ending slop */
-        return (len);     
+	*start=buffer+(offset-begin);   /* Start of wanted data */
+	len-=(offset-begin);	    /* Start slop */
+	if(len>length)
+	    len = length;		    /* Ending slop */
+	return (len);     
     }
 
     if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
@@ -2623,15 +2627,18 @@
 	 */
 	if( new_dma_sectors < dma_sectors )
 	    new_dma_sectors = dma_sectors;
-	
-	new_dma_malloc_freelist = (unsigned char *)
-	    scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
-	memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
-	
-	new_dma_malloc_pages = (unsigned char **)
-	    scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
-	memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
-	
+
+	if (new_dma_sectors)
+	{
+	    new_dma_malloc_freelist = (unsigned char *)
+		scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
+	    memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
+
+	    new_dma_malloc_pages = (unsigned char **)
+		scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
+	    memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
+	}
+
 	/*
 	 * If we need more buffers, expand the list.
 	 */
@@ -2646,13 +2653,19 @@
 	 */
 	save_flags(flags);
 	cli();
-	memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
-	scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+	if (dma_malloc_freelist)
+	{
+	    memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
+	    scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+	}
 	dma_malloc_freelist = new_dma_malloc_freelist;
 	
-	memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
-	scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
-	
+	if (dma_malloc_pages)
+	{
+	    memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
+	    scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
+	}
+
 	dma_free_sectors += new_dma_sectors - dma_sectors;
 	dma_malloc_pages = new_dma_malloc_pages;
 	dma_sectors = new_dma_sectors;
@@ -2739,7 +2752,7 @@
 		scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
 		sdpnt->host->host_queue = SCpnt;
 		if (SCpnt) SCpnt->prev = NULL;
-                sdpnt->has_cmdblocks = 0;
+		sdpnt->has_cmdblocks = 0;
 	    }
     
     /* Next free up the Scsi_Device structures for this host */
@@ -2904,7 +2917,7 @@
 		    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
 		}
 	    }
-            SDpnt->has_cmdblocks = 0;
+	    SDpnt->has_cmdblocks = 0;
 	}
     }
     /*
diff -u --recursive --new-file v1.3.20/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c
--- v1.3.20/linux/drivers/scsi/sd_ioctl.c	Fri Jul  7 08:54:51 1995
+++ linux/drivers/scsi/sd_ioctl.c	Mon Aug 28 11:25:15 1995
@@ -30,7 +30,7 @@
     struct hd_geometry *loc = (struct hd_geometry *) arg;
     
     switch (cmd) {
-    case HDIO_REQ:   /* Return BIOS disk parameters */
+    case HDIO_GETGEO:   /* Return BIOS disk parameters */
 	if (!loc)  return -EINVAL;
 	error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
 	if (error)
diff -u --recursive --new-file v1.3.20/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v1.3.20/linux/drivers/sound/ad1848.c	Sun Aug 13 14:45:33 1995
+++ linux/drivers/sound/ad1848.c	Fri Aug 18 08:35:24 1995
@@ -252,7 +252,7 @@
   prev = INB (io_Index_Addr (devc));
   OUTB (0x00, io_Index_Addr (devc));	/* Clear the MCE bit */
 
-  if (prev & 0x40 == 0)		/* Not in MCE mode */
+  if ((prev & 0x40) == 0)		/* Not in MCE mode */
     {
       RESTORE_INTR (flags);
       return;
diff -u --recursive --new-file v1.3.20/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c
--- v1.3.20/linux/drivers/sound/sound_switch.c	Sun Aug 13 14:45:34 1995
+++ linux/drivers/sound/sound_switch.c	Fri Aug 18 08:35:59 1995
@@ -479,7 +479,7 @@
 {
   DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
 
-  if ((cmd >> 8) & 0xff == 'M' && num_mixers > 0)	/* Mixer ioctl */
+  if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0)	/* Mixer ioctl */
     if ((dev & 0x0f) != SND_DEV_CTL)
       {
 	int             dtype = dev & 0x0f;
diff -u --recursive --new-file v1.3.20/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v1.3.20/linux/fs/binfmt_elf.c	Tue Aug  8 12:31:39 1995
+++ linux/fs/binfmt_elf.c	Mon Aug 28 10:16:45 1995
@@ -172,7 +172,7 @@
 static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
 			     struct inode * interpreter_inode, unsigned int *interp_load_addr)
 {
-        struct file * file;
+	struct file * file;
 	struct elf_phdr *elf_phdata  =  NULL;
 	struct elf_phdr *eppnt;
 	unsigned int len;
@@ -258,7 +258,7 @@
 
 	SYS(close)(elf_exec_fileno);
 	if(error < 0 && error > -1024) {
-	        kfree(elf_phdata);
+		kfree(elf_phdata);
 		return 0xffffffff;
 	}
 
@@ -386,7 +386,7 @@
 	retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
 			   elf_ex.e_phentsize * elf_ex.e_phnum, 1);
 	if (retval < 0) {
-	        kfree (elf_phdata);
+		kfree (elf_phdata);
 		MOD_DEC_USE_COUNT;
 		return retval;
 	}
@@ -399,7 +399,7 @@
 	elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
 
 	if (elf_exec_fileno < 0) {
-	        kfree (elf_phdata);
+		kfree (elf_phdata);
 		MOD_DEC_USE_COUNT;
 		return elf_exec_fileno;
 	}
@@ -458,7 +458,7 @@
 	
 	/* Some simple consistency checks for the interpreter */
 	if(elf_interpreter){
-	        interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
+		interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
 		if(retval < 0) {
 			kfree(elf_interpreter);
 			kfree(elf_phdata);
@@ -500,10 +500,10 @@
 		  }
 		}
 		if (!bprm->p) {
-		        if(elf_interpreter) {
+			if(elf_interpreter) {
 			      kfree(elf_interpreter);
 			}
-		        kfree (elf_phdata);
+			kfree (elf_phdata);
 			MOD_DEC_USE_COUNT;
 			return -E2BIG;
 		}
@@ -662,6 +662,15 @@
 				MAP_FIXED | MAP_PRIVATE, 0);
 	}
 
+	/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
+	   starts %edx contains a pointer to a function which might be
+	   registered using `atexit'.  This provides a mean for the
+	   dynamic linker to call DT_FINI functions for shared libraries
+	   that have been loaded before the code runs.
+
+	   A value of 0 tells we have no such handler.  */
+	regs->edx = 0;
+
 	start_thread(regs, elf_entry, bprm->p);
 	if (current->flags & PF_PTRACED)
 		send_sig(SIGTRAP, current, 0);
@@ -674,7 +683,7 @@
 
 static int
 load_elf_library(int fd){
-        struct file * file;
+	struct file * file;
 	struct elfhdr elf_ex;
 	struct elf_phdr *elf_phdata  =  NULL;
 	struct  inode * inode;
@@ -751,7 +760,7 @@
 	
 	SYS(close)(fd);
 	if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
-	        kfree(elf_phdata);
+		kfree(elf_phdata);
 		MOD_DEC_USE_COUNT;
 		return error;
 	}
diff -u --recursive --new-file v1.3.20/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.20/linux/fs/buffer.c	Fri Aug 18 08:44:58 1995
+++ linux/fs/buffer.c	Fri Aug 18 08:44:06 1995
@@ -1171,6 +1171,7 @@
 	return address;
 }
 
+#if 0
 /*
  * bwrite_page writes a page out to the buffer cache and/or the physical device.
  * It's used for mmap writes (the same way bread_page() is used for mmap reads).
@@ -1192,9 +1193,10 @@
 			mark_buffer_dirty(bh[i], 0);
 			brelse(bh[i]);
 		} else
-			memset((void *) address, 0, size);
+			memset((void *) address, 0, size); /* ???!?!! */
 	}	
 }
+#endif
 
 /*
  * Try to increase the number of buffers available: the size argument
diff -u --recursive --new-file v1.3.20/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v1.3.20/linux/fs/msdos/namei.c	Wed Aug  2 13:21:15 1995
+++ linux/fs/msdos/namei.c	Mon Aug 28 08:42:13 1995
@@ -105,8 +105,9 @@
 	char msdos_name[MSDOS_NAME];
 	int res;
 
-	if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
-	    msdos_name,1)) < 0) return res;
+	res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, msdos_name,1);
+	if (res < 0)
+		return -ENOENT;
 	return msdos_scan(dir,msdos_name,bh,de,ino);
 }
 
diff -u --recursive --new-file v1.3.20/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v1.3.20/linux/fs/nfs/inode.c	Tue Jul 18 16:28:58 1995
+++ linux/fs/nfs/inode.c	Mon Aug 28 10:08:24 1995
@@ -143,6 +143,7 @@
 	if (data->addr.sin_addr.s_addr == INADDR_ANY) {  /* No address passed */
 	  if (((struct sockaddr_in *)(&server->toaddr))->sin_addr.s_addr == INADDR_ANY) {
 	    printk("NFS: Error passed unconnected socket and no address\n") ;
+	    MOD_DEC_USE_COUNT;
 	    return NULL ;
 	  } else {
 	    /* Need access to socket internals  JSP */
diff -u --recursive --new-file v1.3.20/linux/fs/proc/net.c linux/fs/proc/net.c
--- v1.3.20/linux/fs/proc/net.c	Tue Aug 15 20:39:04 1995
+++ linux/fs/proc/net.c	Mon Aug 28 12:53:10 1995
@@ -36,49 +36,6 @@
 #include <linux/config.h>
 #include <linux/mm.h>
 
-static struct file_operations proc_netdir_operations = {
-	NULL,			/* lseek - default */
-	NULL,			/* read - bad */
-	NULL,			/* write - bad */
-	proc_readdir,		/* readdir */
-	NULL,			/* select - default */
-	NULL,			/* ioctl - default */
-	NULL,			/* mmap */
-	NULL,			/* no special open code */
-	NULL,			/* no special release code */
-	NULL			/* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-static struct inode_operations proc_netdir_inode_operations = {
-	&proc_netdir_operations,	/* default net directory file-ops */
-	NULL,			/* create */
-	proc_lookup,		/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	NULL,			/* bmap */
-	NULL,			/* truncate */
-	NULL			/* permission */
-};
-
-struct proc_dir_entry proc_net = {
-	PROC_NET, 3, "net",
-	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
-	0, &proc_netdir_inode_operations,
-	NULL, NULL,
-	NULL,
-	NULL, NULL	
-};
-
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
 
 static int proc_readnet(struct inode * inode, struct file * file,
diff -u --recursive --new-file v1.3.20/linux/fs/proc/root.c linux/fs/proc/root.c
--- v1.3.20/linux/fs/proc/root.c	Tue Aug 15 20:39:04 1995
+++ linux/fs/proc/root.c	Mon Aug 28 12:53:52 1995
@@ -22,6 +22,53 @@
 static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
 static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
 
+/*
+ * These are the generic /proc directory operations. They
+ * use the in-memory "struct proc_dir_entry" tree to parse
+ * the /proc directory.
+ *
+ * NOTE! The /proc/scsi directory currently does not correctly
+ * build up the proc_dir_entry tree, and will show up empty.
+ */
+static struct file_operations proc_dir_operations = {
+	NULL,			/* lseek - default */
+	NULL,			/* read - bad */
+	NULL,			/* write - bad */
+	proc_readdir,		/* readdir */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	NULL,			/* no special release code */
+	NULL			/* can't fsync */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+static struct inode_operations proc_dir_inode_operations = {
+	&proc_dir_operations,	/* default net directory file-ops */
+	NULL,			/* create */
+	proc_lookup,		/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+/*
+ * The root /proc directory is special, as it has the
+ * <pid> directories. Thus we don't use the generic
+ * directory handling functions for that..
+ */
 static struct file_operations proc_root_operations = {
 	NULL,			/* lseek - default */
 	NULL,			/* read - bad */
@@ -36,7 +83,7 @@
 };
 
 /*
- * proc directories can do almost nothing..
+ * proc root can do almost nothing..
  */
 static struct inode_operations proc_root_inode_operations = {
 	&proc_root_operations,	/* default base directory file-ops */
@@ -61,8 +108,26 @@
  */
 struct proc_dir_entry proc_root = {
 	PROC_ROOT_INO, 5, "/proc",
-	S_IFDIR | S_IRUGO | S_IXUGO, 3, 0, 0,
+	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
 	0, &proc_root_inode_operations,
+	NULL, NULL,
+	NULL,
+	&proc_root, NULL
+};
+
+struct proc_dir_entry proc_net = {
+	PROC_NET, 3, "net",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+	0, &proc_dir_inode_operations,
+	NULL, NULL,
+	NULL,
+	NULL, NULL	
+};
+
+struct proc_dir_entry proc_scsi = {
+	PROC_SCSI, 4, "scsi",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+	0, &proc_dir_inode_operations,
 	NULL, NULL,
 	NULL,
 	&proc_root, NULL
diff -u --recursive --new-file v1.3.20/linux/fs/proc/scsi.c linux/fs/proc/scsi.c
--- v1.3.20/linux/fs/proc/scsi.c	Tue Aug 15 20:39:04 1995
+++ linux/fs/proc/scsi.c	Mon Aug 28 12:54:33 1995
@@ -34,8 +34,6 @@
 			 char * buf, int count);
 static int proc_writescsi(struct inode * inode, struct file * file,
 			 const char * buf, int count);
-static int proc_readscsidir(struct inode *, struct file *, 
-			    void *, filldir_t filldir);
 static int proc_lookupscsi(struct inode *,const char *,int,struct inode **);
 static int proc_scsilseek(struct inode *, struct file *, off_t, int);
 
@@ -50,7 +48,7 @@
     proc_scsilseek,	/* lseek   */
     proc_readscsi,	/* read	   */
     proc_writescsi,	/* write   */
-    proc_readscsidir,	/* readdir */
+    NULL,		/* readdir */
     NULL,		/* select  */
     NULL,		/* ioctl   */
     NULL,		/* mmap	   */
@@ -80,15 +78,6 @@
     NULL	    /* permission  */
 };
 
-struct proc_dir_entry proc_scsi = {
-	PROC_SCSI, 4, "scsi",
-	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
-	0, &proc_scsi_inode_operations,
-	NULL, NULL,
-	NULL,
-	&proc_root, NULL
-};
-
 struct proc_dir_entry scsi_dir[PROC_SCSI_FILE - PROC_SCSI_SCSI + 3]; 
 struct proc_dir_entry scsi_hba_dir[(PROC_SCSI_LAST - PROC_SCSI_FILE) * 4]; 
 
@@ -175,36 +164,6 @@
     }
     iput(dir);
     return(-ENOENT);
-}
-
-static int proc_readscsidir(struct inode * inode, struct file * filp,
-			    void * dirent, filldir_t filldir)
-{
-    struct proc_dir_entry * de;
-    uint index, num;
- 
-    num = 0;
-
-    if (!inode || !S_ISDIR(inode->i_mode))
-	return(-EBADF);
-
-    index = count_dir_entries(inode->i_ino, &num);
-
-    while (((unsigned) filp->f_pos + index) < index + num) {
-	if (dispatch_scsi_info_ptr) {
-	    if (inode->i_ino <= PROC_SCSI_SCSI)
-		de = scsi_dir + filp->f_pos;
-	    else
-		de = scsi_hba_dir + filp->f_pos + index;
-        }
-	else {
-	    de = scsi_dir2 + filp->f_pos;
-        }
-	if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino)<0)
-	    break;
-	filp->f_pos++;
-    }
-    return(0);
 }
 
 int get_not_present_info(char *buffer, char **start, off_t offset, int length)
diff -u --recursive --new-file v1.3.20/linux/fs/smbfs/README linux/fs/smbfs/README
--- v1.3.20/linux/fs/smbfs/README	Fri Jul  7 08:54:52 1995
+++ linux/fs/smbfs/README	Mon Aug 28 09:48:36 1995
@@ -1,7 +1,7 @@
 smbfs is a filesystem which understands the SMB protocol. This is the
 protocol Windows for Workgroups, Windows NT or Lan Manager use to talk
-to each other. It was inspired by samba, the program by Andrew
-Tridgell that turns any unix site into a file server for DOS or
+to each other. smbfs was inspired by samba, the program written by
+Andrew Tridgell that turns any unix host into a file server for DOS or
 Windows clients.  See ftp://nimbus.anu.edu.au/pub/tridge/samba/ for
 this interesting program suite and lots of more information on SMB and
 NetBIOS over TCP/IP. There you also find explanation for conceps like
diff -u --recursive --new-file v1.3.20/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v1.3.20/linux/fs/smbfs/dir.c	Tue Jul 11 10:02:58 1995
+++ linux/fs/smbfs/dir.c	Mon Aug 28 09:48:36 1995
@@ -159,10 +159,11 @@
 static struct smb_dirent* c_entry = NULL;
 
 static int
-smb_readdir1(struct inode *inode, const struct file *filp,
-	     struct smb_dirent *ret,ino_t *ino)
+smb_readdir(struct inode *inode, struct file *filp,
+            void *dirent, filldir_t filldir)
 {
 	int result, i = 0;
+        int index = 0;
 	struct smb_dirent *entry = NULL;
         struct smb_server *server = SMB_SERVER(inode);
 
@@ -198,6 +199,7 @@
 			if (filp->f_pos == c_entry[i].f_pos) {
                                 entry = &c_entry[i];
                                 c_last_returned_index = i;
+                                index = i;
                                 break;
 			}
 		}
@@ -222,6 +224,7 @@
 			c_size = result;
 			entry = c_entry;
                         c_last_returned_index = 0;
+                        index = 0;
                         for (i = 0; i < c_size; i++) {
 
                                 switch (server->case_handling) 
@@ -236,22 +239,26 @@
                         }
 		}
 	}
-	
-	if (entry) {
+
+        if (entry == NULL) {
+                /* Nothing found, even from a smb call */
+                return 0;
+        }
+
+        while (index < c_size) {
 
                 /* We found it.  For getwd(), we have to return the
                    correct inode in d_ino if the inode is currently in
                    use. Otherwise the inode number does not
-                   matter. */ 
+                   matter. (You can argue a lot about this..) */ 
 
-                int  path_len;
+                int path_len;
+                int len;
                 struct smb_inode_info *ino_info;
                 char complete_path[SMB_MAXPATHLEN];
 
-                
-
-		i = strlen(entry->path);
-                if ((result = get_pname_static(inode, entry->path, i,
+		len = strlen(entry->path);
+                if ((result = get_pname_static(inode, entry->path, len,
                                                complete_path,
                                                &path_len)) < 0)
                         return result;
@@ -268,30 +275,20 @@
 		DDPRINTK("smb_readdir: entry->path = %s\n", entry->path);
 		DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos);
 
-		*ino = (ino_t)ino_info; /* use the pointer as the
-					  inode - dangerous if we have
-					  64 bit pointers! FIXME */
-
-		*ret = *entry;
-		return 1;
-	}
-
-	return 0;
-}
-
-static int 
-smb_readdir(struct inode *inode, struct file *filp,
-            void *dirent, filldir_t filldir)
-{
-	struct smb_dirent d;
-	ino_t ino;
+                if (filldir(dirent, entry->path, len,
+                            entry->f_pos, (ino_t)ino_info) < 0) {
+                        break;
+                }
 
-	while (smb_readdir1(inode,filp,&d,&ino) == 1) {		
-		if (filldir(dirent,d.path,strlen(d.path)+1,
-			    filp->f_pos,ino) < 0) {
-			return 0;
-		}
-		filp->f_pos++;
+                if (   (inode->i_ino != c_ino)
+                    || (entry->f_pos != filp->f_pos)) {
+                        /* Someone has destroyed the cache while we slept
+                           in filldir */
+                        break;
+                }
+                filp->f_pos += 1;
+                index += 1;
+                entry += 1;
 	}
 	return 0;
 }
@@ -716,13 +713,9 @@
         found_in_cache = 0;
         
         if (dir->i_ino == c_ino) {
-                int first = c_last_returned_index - 1;
+                int first = c_last_returned_index;
                 int i;
 
-                if (first < 0) {
-                        first = c_size - 1;
-                }
-
                 i = first;
                 do {
                         DDPRINTK("smb_lookup: trying index: %d, name: %s\n",
@@ -735,7 +728,8 @@
                                 break;
                         }
                         i = (i + 1) % c_size;
-
+                        DDPRINTK("smb_lookup: index %d, name %s failed\n",
+                                 i, c_entry[i].path);
                 } while (i != first);
         }
 
@@ -920,10 +914,19 @@
 	res = smb_proc_mv(SMB_SERVER(old_dir), old_path, old_len,
                           new_path, new_len);
 
+	if (res == -EEXIST) {
+		int res1;
+		res1 = smb_proc_unlink(SMB_SERVER(old_dir), new_path, new_len);
+		if (res1 == 0) {
+			res = smb_proc_mv(SMB_SERVER(old_dir), old_path,
+					  old_len, new_path, new_len);
+		}
+	}
+
         if (res == 0) {
                 smb_invalid_dir_cache(old_dir->i_ino);
                 smb_invalid_dir_cache(new_dir->i_ino);
-        }
+        }		
 	
  finished:
 	iput(old_dir); 
diff -u --recursive --new-file v1.3.20/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v1.3.20/linux/fs/smbfs/file.c	Wed Aug  2 13:21:15 1995
+++ linux/fs/smbfs/file.c	Mon Aug 28 09:48:36 1995
@@ -102,10 +102,25 @@
 	/* First read in as much as possible for each bufsize. */
         while (already_read < count) {
 
-                to_read = min(bufsize, count - already_read);
+                result = 0;
+                to_read = 0;
+                
+                if ((SMB_SERVER(inode)->blkmode & 1) != 0) {
+                        to_read = min(65535, count - already_read);
+                        DPRINTK("smb_file_read: Raw %d bytes\n", to_read);
+                        result = smb_proc_read_raw(SMB_SERVER(inode),
+                                                   SMB_FINFO(inode),
+                                                   pos, to_read, buf);
+                        DPRINTK("smb_file_read: returned %d\n", result);
+                }
+
+                if (result <= 0) {
+                        to_read = min(bufsize, count - already_read);
+                        result = smb_proc_read(SMB_SERVER(inode),
+                                               SMB_FINFO(inode),
+                                               pos, to_read, buf, 1);
+                }
 
-		result = smb_proc_read(SMB_SERVER(inode), SMB_FINFO(inode),
-                                       pos, to_read, buf, 1);
 		if (result < 0)
 			return result;
 		pos += result;
@@ -162,12 +177,30 @@
 
         already_written = 0;
 
+        DPRINTK("smb_write_file: blkmode = %d, blkmode & 2 = %d\n",
+                SMB_SERVER(inode)->blkmode,
+                SMB_SERVER(inode)->blkmode & 2);
+        
         while (already_written < count) {
 
-                to_write = min(bufsize, count - already_written);
+                result = 0;
+                to_write = 0;
 
-		result = smb_proc_write(SMB_SERVER(inode), SMB_FINFO(inode), 
-					pos, to_write, buf);
+                if ((SMB_SERVER(inode)->blkmode & 2) != 0) {
+                        to_write = min(65535, count - already_written);
+                        DPRINTK("smb_file_write: Raw %d bytes\n", to_write);
+                        result = smb_proc_write_raw(SMB_SERVER(inode),
+                                                    SMB_FINFO(inode), 
+                                                    pos, to_write, buf);
+                        DPRINTK("smb_file_write: returned %d\n", result);
+                }
+
+                if (result <= 0) {
+                        to_write = min(bufsize, count - already_written);
+                        result = smb_proc_write(SMB_SERVER(inode),
+                                                SMB_FINFO(inode), 
+                                                pos, to_write, buf);
+                }
 
 		if (result < 0)
 			return result;
diff -u --recursive --new-file v1.3.20/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v1.3.20/linux/fs/smbfs/inode.c	Tue Aug  8 12:31:41 1995
+++ linux/fs/smbfs/inode.c	Mon Aug 28 09:48:36 1995
@@ -345,13 +345,18 @@
 	if ((error = inode_change_ok(inode, attr)) < 0)
 		return error;
 
-        if (!S_ISREG(inode->i_mode))
-                return -EPERM;
+	if (((attr->ia_valid & ATTR_UID) && 
+	     (attr->ia_uid != SMB_SERVER(inode)->m.uid)))
+		return -EPERM;
 
-        if ((attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) != 0) {
+	if (((attr->ia_valid & ATTR_GID) && 
+	     (attr->ia_uid != SMB_SERVER(inode)->m.gid)))
                 return -EPERM;
-        }
-        
+
+	if (((attr->ia_valid & ATTR_MODE) &&
+	     (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
+		return -EPERM;
+
         if ((attr->ia_valid & ATTR_SIZE) != 0) {
 
                 if ((error = smb_make_open(inode, O_WRONLY)) < 0)
diff -u --recursive --new-file v1.3.20/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v1.3.20/linux/fs/smbfs/proc.c	Tue Aug  8 12:31:41 1995
+++ linux/fs/smbfs/proc.c	Mon Aug 28 09:48:36 1995
@@ -69,18 +69,7 @@
 	return &p[2];
 }
 
-static byte *
-smb_decode_dword(byte *p, dword *data)
-{
-#if (ARCH == i386)
-	*data = *((dword *)p);
-#else
-	*data = (dword)p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
-#endif
-	return &p[4];
-}
-
-static byte *
+byte *
 smb_encode_smb_length(byte *p, dword len)
 {
 	p[0] = p[1] = 0;
@@ -320,6 +309,9 @@
 			case ERRlock:       return EDEADLOCK;
 			case ERRfilexists:  return EEXIST;
 			case 87:            return 0; /* Unknown error!! */
+			/* This next error seems to occur on an mv when
+			 * the destination exists */
+			case 183:	    return EEXIST;
 			default:            return EIO;
 		}
 	else if (errcls == ERRSRV) 
@@ -655,6 +647,33 @@
         return data_len;
 }
 
+/* count must be <= 65535. No error number is returned.  A result of 0
+   indicates an error, which has to be investigated by a normal read
+   call. */
+int
+smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo, 
+                  off_t offset, long count, char *data)
+{
+        char *buf = server->packet;
+        int result;
+
+        if ((count <= 0) || (count > 65535)) {
+                return -EINVAL;
+        }
+
+	smb_setup_header_exclusive(server, SMBreadbraw, 8, 0);
+
+        WSET(buf, smb_vwv0, finfo->fileid);
+        DSET(buf, smb_vwv1, offset);
+        WSET(buf, smb_vwv3, count);
+        WSET(buf, smb_vwv4, 0);
+        DSET(buf, smb_vwv5, 0);
+
+        result = smb_request_read_raw(server, data, count);
+        smb_unlock_server(server);
+        return result;
+}
+
 int
 smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
                off_t offset, int count, const char *data)
@@ -682,6 +701,61 @@
 	return res;
 }
 
+/* count must be <= 65535 */
+int
+smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, 
+                   off_t offset, long count, const char *data)
+{
+        char *buf = server->packet;
+        int result;
+
+        if ((count <= 0) || (count > 65535)) {
+                return -EINVAL;
+        }
+
+	smb_setup_header_exclusive(server, SMBwritebraw, 11, 0);
+
+        WSET(buf, smb_vwv0, finfo->fileid);
+        WSET(buf, smb_vwv1, count);
+        WSET(buf, smb_vwv2, 0); /* reserved */
+        DSET(buf, smb_vwv3, offset);
+        DSET(buf, smb_vwv5, 0); /* timeout */
+        WSET(buf, smb_vwv7, 1); /* send final result response */
+        DSET(buf, smb_vwv8, 0); /* reserved */
+        WSET(buf, smb_vwv10, 0); /* no data in this buf */
+        WSET(buf, smb_vwv11, 0); /* no data in this buf */
+
+        result = smb_request_ok(server, SMBwritebraw, 1, 0);
+
+        DPRINTK("smb_proc_write_raw: first request returned %d\n", result);
+        
+        if (result < 0) {
+                smb_unlock_server(server);
+                return result;
+        }
+        
+        result = smb_request_write_raw(server, data, count);
+
+        DPRINTK("smb_proc_write_raw: raw request returned %d\n", result);
+        
+        if (result > 0) {
+                /* We have to do the checks of smb_request_ok here as well */
+                if (smb_valid_packet(server->packet) != 0) {
+                        DPRINTK("not a valid packet!\n");
+                        result = -EIO;
+                } else if (server->rcls != 0) {
+                        result = -smb_errno(server->rcls, server->err);
+                } else if (smb_verify(server->packet, SMBwritec,1,0) != 0) {
+                        DPRINTK("smb_verify failed\n");
+                        result = -EIO;
+                }
+        }
+
+        smb_unlock_server(server);
+        return result;
+}
+
+
 /* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */
 
 static int
@@ -1642,12 +1716,14 @@
                         server->m.password);
                 DPRINTK("smb_proc_connect: usernam = %s\n",
                         server->m.username);
+                DPRINTK("smb_proc_connect: blkmode = %d\n",
+                        WVAL(server->packet, smb_vwv5));
 
-                p = smb_decode_word(p, &(server->maxxmt));
-                p = smb_decode_word(p, &(server->maxmux));
-                p = smb_decode_word(p, &(server->maxvcs));
-                p = smb_decode_word(p, &(server->blkmode));
-                p = smb_decode_dword(p, &(server->sesskey));
+                server->maxxmt = WVAL(server->packet, smb_vwv2);
+                server->maxmux = WVAL(server->packet, smb_vwv3);
+                server->maxvcs = WVAL(server->packet, smb_vwv4);
+                server->blkmode= WVAL(server->packet, smb_vwv5);
+                server->sesskey= DVAL(server->packet, smb_vwv6);
 
                 smb_setup_header(server, SMBsesssetupX, 10,
                                  2 + userlen + passlen);
@@ -1673,6 +1749,15 @@
                         goto fail;
                 }
                 smb_decode_word(server->packet+32, &(server->server_uid));
+        }
+        else
+
+        {
+                server->maxxmt = 0;
+                server->maxmux = 0;
+                server->maxvcs = 0;
+                server->blkmode = 0;
+                server->sesskey = 0;
         }
 
 	/* Fine! We have a connection, send a tcon message. */
diff -u --recursive --new-file v1.3.20/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v1.3.20/linux/fs/smbfs/sock.c	Tue Jul 11 10:02:58 1995
+++ linux/fs/smbfs/sock.c	Mon Aug 28 09:48:36 1995
@@ -175,27 +175,36 @@
 }
 
 /*
- * smb_receive
- * fs points to the correct segment, server != NULL, sock!=NULL
+ * smb_receive_raw
+ * fs points to the correct segment, sock != NULL, target != NULL
+ * The smb header is only stored if want_header != 0.
  */
 static int
-smb_receive(struct smb_server *server, struct socket *sock)
+smb_receive_raw(struct socket *sock, unsigned char *target,
+                int max_raw_length, int want_header)
 {
         int len, result;
+        int already_read;
         unsigned char peek_buf[4];
+        unsigned short fs;      /* We fool the kernel to believe
+                                   we call from user space. */
+
 
  re_recv:
 
+	fs = get_fs();
+	set_fs(get_ds());
         result = sock->ops->recvfrom(sock, (void *)peek_buf, 4, 0,
-                                     MSG_PEEK, NULL, NULL);
+                                     0, NULL, NULL);
+        set_fs(fs);
 
         if (result < 0) {
-                DPRINTK("smb_receive: recv error = %d\n", -result);
+                DPRINTK("smb_receive_raw: recv error = %d\n", -result);
                 return result;
         }
 
-        if (result == 0) {
-                DPRINTK("smb_receive: got 0 bytes\n");
+        if (result < 4) {
+                DPRINTK("smb_receive_raw: got less than 4 bytes\n");
                 return -EIO;
         }
 
@@ -206,51 +215,72 @@
                 break;
 
         case 0x85:
-                DPRINTK("smb_receive: Got SESSION KEEP ALIVE\n");
-                sock->ops->recvfrom(sock, (void *)peek_buf, 4, 1,
-                                    0, NULL, NULL);
+                DPRINTK("smb_receive_raw: Got SESSION KEEP ALIVE\n");
                 goto re_recv;
                 
         default:
-                printk("smb_receive: Invalid packet\n");
+                printk("smb_receive_raw: Invalid packet\n");
                 return -EIO;
         }
 
-        /* Length not including first four bytes. */
-	len = smb_len(peek_buf) + 4; 
-        if (len > server->max_xmit) { 
-                printk("smb_receive: Received length (%d) > max_xmit (%d)!\n", 
-		       len, server->max_xmit);
+        /* The length in the RFC NB header is the raw data length */
+	len = smb_len(peek_buf); 
+        if (len > max_raw_length) { 
+                printk("smb_receive_raw: Received length (%d) > max_xmit (%d)!\n", 
+		       len, max_raw_length);
                 return -EIO;
 	}
-        else
-        {
-                int already_read = 0;
 
-                while (already_read < len) {
+        if (want_header != 0) {
+                memcpy_tofs(target, peek_buf, 4);
+                target += 4;
+        }
+
+        already_read = 0;
+
+        while (already_read < len) {
                 
-                        result = sock->ops->
-                                recvfrom(sock,
-                                         (void *)(server->packet+already_read),
-                                         len - already_read, 0, 0,
-                                         NULL, NULL);
+                result = sock->ops->
+                        recvfrom(sock,
+                                 (void *)(target+already_read),
+                                 len - already_read, 0, 0,
+                                 NULL, NULL);
    
-                        if (result < 0) {
-                                printk("SMB: notice message: error = %d\n",
-                                       -result);
-                                return result;
-                        }
-
-                        already_read += result;
+                if (result < 0) {
+                        printk("smb_receive_raw: recvfrom error = %d\n",
+                               -result);
+                        return result;
                 }
-                result = already_read;
+
+                already_read += result;
+        }
+        return already_read;
+}
+
+/*
+ * smb_receive
+ * fs points to the correct segment, server != NULL, sock!=NULL
+ */
+static int
+smb_receive(struct smb_server *server, struct socket *sock)
+{
+        int result;
+
+        result = smb_receive_raw(sock, server->packet,
+                                 server->max_xmit - 4, /* max_xmit in server
+                                                          includes NB header */
+                                 1); /* We want the header */
+
+        if (result < 0) {
+                printk("smb_receive: receive error: %d\n", result);
+                return result;
         }
 
         server->rcls = *((unsigned char *)(server->packet+9));
         server->err  = *((unsigned short *)(server->packet+11));
 
         if (server->rcls != 0) {
-                DPRINTK("smb_response: rcls=%d, err=%d\n",
+                DPRINTK("smb_receive: rcls=%d, err=%d\n",
                         server->rcls, server->err);
         }
 
@@ -447,12 +477,6 @@
         if (server->state != CONN_VALID)
                 return -EIO;
         	
-#if 0
-	while (server->lock)
-		sleep_on(&server->wait);
-	server->lock = 1;
-#endif
-
         if ((result = smb_dont_catch_keepalive(server)) != 0) {
                 server->state = CONN_INVALID;
                 smb_invalidate_all_inodes(server);
@@ -486,11 +510,6 @@
                 result = result2;
         }
 
-#if 0
-	server->lock = 0;
-	wake_up(&server->wait);
-#endif
-
         if (result < 0) {
                 server->state = CONN_INVALID;
                 smb_invalidate_all_inodes(server);
@@ -526,12 +545,6 @@
         if (server->state != CONN_VALID)
                 return -EIO;
         	
-#if 0
-	while (server->lock)
-		sleep_on(&server->wait);
-	server->lock = 1;
-#endif
-
         if ((result = smb_dont_catch_keepalive(server)) != 0) {
                 server->state = CONN_INVALID;
                 smb_invalidate_all_inodes(server);
@@ -540,13 +553,13 @@
 
         len = smb_len(buffer) + 4;
 
-        DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
-
 	old_mask = current->blocked;
 	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
 	fs = get_fs();
 	set_fs(get_ds());
 
+        DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
+
         result = sock->ops->send(sock, (void *)buffer, len, 0, 0);
         if (result < 0) {
                 printk("smb_trans2_request: send error = %d\n", result);
@@ -567,17 +580,162 @@
                 result = result2;
         }
 
-#if 0
-	server->lock = 0;
-	wake_up(&server->wait);
-#endif
-
         if (result < 0) {
                 server->state = CONN_INVALID;
                 smb_invalidate_all_inodes(server);
         }
         
         DDPRINTK("smb_trans2_request: result = %d\n", result);
+
+	return result;
+}
+
+/* target must be in user space */
+int
+smb_request_read_raw(struct smb_server *server,
+                     unsigned char *target, int max_len)
+{
+	unsigned long old_mask;
+	int len, result, result2;
+	unsigned short fs;      /* We fool the kernel to believe
+                                   we call from user space. */
+
+	struct socket *sock = server_sock(server);
+	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
+
+	if ((sock == NULL) || (buffer == NULL)) {
+		printk("smb_request_read_raw: Bad server!\n");
+		return -EBADF;
+	}
+
+        if (server->state != CONN_VALID)
+                return -EIO;
+        	
+        if ((result = smb_dont_catch_keepalive(server)) != 0) {
+                server->state = CONN_INVALID;
+                smb_invalidate_all_inodes(server);
+                return result;
+        }
+
+        len = smb_len(buffer) + 4;
+
+	old_mask = current->blocked;
+	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
+	fs = get_fs();
+	set_fs(get_ds());
+
+        DPRINTK("smb_request_read_raw: len = %d cmd = 0x%X\n",
+                len, buffer[8]);
+        DPRINTK("smb_request_read_raw: target=%X, max_len=%d\n",
+                (unsigned int)target, max_len);
+        DPRINTK("smb_request_read_raw: buffer=%X, sock=%X\n",
+                (unsigned int)buffer, (unsigned int)sock);
+
+        result = sock->ops->send(sock, (void *)buffer, len, 0, 0);
+
+        DPRINTK("smb_request_read_raw: send returned %d\n", result);
+
+	set_fs(fs);             /* We recv into user space */
+
+        if (result < 0) {
+                printk("smb_request_read_raw: send error = %d\n", result);
+        }
+        else {
+                result = smb_receive_raw(sock, target, max_len, 0);
+        }
+
+        /* read/write errors are handled by errno */
+        current->signal &= ~_S(SIGPIPE);
+	current->blocked = old_mask;
+
+        if ((result2 = smb_catch_keepalive(server)) < 0) {
+                result = result2;
+        }
+
+        if (result < 0) {
+                server->state = CONN_INVALID;
+                smb_invalidate_all_inodes(server);
+        }
+        
+        DPRINTK("smb_request_read_raw: result = %d\n", result);
+
+	return result;
+}
+
+/* Source must be in user space. smb_request_write_raw assumes that
+ * the request SMBwriteBraw has been completed successfully, so that
+ * we can send the raw data now.  */
+int
+smb_request_write_raw(struct smb_server *server,
+                      unsigned const char *source, int length)
+{
+	unsigned long old_mask;
+	int result, result2;
+	unsigned short fs;      /* We fool the kernel to believe
+                                   we call from user space. */
+        byte nb_header[4];
+
+	struct socket *sock = server_sock(server);
+	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
+
+	if ((sock == NULL) || (buffer == NULL)) {
+                printk("smb_request_write_raw: Bad server!\n");
+		return -EBADF;
+	}
+
+        if (server->state != CONN_VALID)
+                return -EIO;
+        	
+        if ((result = smb_dont_catch_keepalive(server)) != 0) {
+                server->state = CONN_INVALID;
+                smb_invalidate_all_inodes(server);
+                return result;
+        }
+
+	old_mask = current->blocked;
+	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
+	fs = get_fs();
+	set_fs(get_ds());
+
+        smb_encode_smb_length(nb_header, length);
+
+        result = sock->ops->send(sock, (void *)nb_header, 4, 0, 0);
+
+        if (result == 4) {
+                set_fs(fs);     /* source is in user-land */
+                result = sock->ops->send(sock, (void *)source, length, 0, 0);
+                set_fs(get_ds());
+        } else {
+                result = -EIO;
+        }
+
+        DPRINTK("smb_request_write_raw: send returned %d\n", result);
+
+        if (result == length) {
+                result = smb_receive(server, sock);
+        } else {
+                result = -EIO;
+        }
+
+        /* read/write errors are handled by errno */
+        current->signal &= ~_S(SIGPIPE);
+	current->blocked = old_mask;
+	set_fs(fs);
+
+        if ((result2 = smb_catch_keepalive(server)) < 0) {
+                result = result2;
+        }
+
+        if (result < 0) {
+                server->state = CONN_INVALID;
+                smb_invalidate_all_inodes(server);
+        }
+
+        if (result > 0) {
+                result = length;
+        }
+        
+        DPRINTK("smb_request_write_raw: result = %d\n", result);
 
 	return result;
 }
diff -u --recursive --new-file v1.3.20/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v1.3.20/linux/include/asm-i386/string.h	Tue Aug  8 12:31:41 1995
+++ linux/include/asm-i386/string.h	Fri Aug 18 09:37:40 1995
@@ -496,6 +496,25 @@
 return (s);	
 }
 
+/* Added by Gertjan van Wingerde to make minix and sysv module work */
+#define __HAVE_ARCH_STRNLEN
+extern inline size_t strnlen(const char * s, size_t count)
+{
+register int __res;
+__asm__ __volatile__(
+	"movl %1,%0\n\t"
+	"jmp 2f\n"
+	"1:\tcmpb $0,(%0)\n\t"
+	"je 3f\n\t"
+	"incl %0\n"
+	"2:\tdecl %2\n\t"
+	"cmpl $-1,%2\n\t"
+	"jne 1b\n"
+	"3:\tsubl %1,%0"
+	:"=a" (__res):"c" (s),"d" (count));
+return __res;
+}
+/* end of additional stuff */
 
 /*
  * This looks horribly ugly, but the compiler can optimize it totally,
diff -u --recursive --new-file v1.3.20/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v1.3.20/linux/include/asm-i386/unistd.h	Tue Jul 18 16:28:58 1995
+++ linux/include/asm-i386/unistd.h	Fri Aug 18 08:44:06 1995
@@ -149,6 +149,7 @@
 #define __NR_getdents		141
 #define __NR__newselect		142
 #define __NR_flock		143
+#define __NR_msync		144
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
 #define _syscall0(type,name) \
diff -u --recursive --new-file v1.3.20/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v1.3.20/linux/include/linux/hdreg.h	Tue Aug 15 20:39:04 1995
+++ linux/include/linux/hdreg.h	Mon Aug 28 13:11:59 1995
@@ -56,12 +56,18 @@
 #define WIN_DOORLOCK		0xde	/* lock door on removeable drives */
 #define WIN_DOORUNLOCK		0xdf	/* unlock door on removeable drives */
 
-#define WIN_PIDENTIFY		0xA1	/* identify ATA-PI device	*/
-#define WIN_MULTREAD		0xC4	/* read multiple sectors	*/
-#define WIN_MULTWRITE		0xC5	/* write multiple sectors	*/
-#define WIN_SETMULT		0xC6	/* enable read multiple		*/
+#define WIN_MULTREAD		0xC4	/* read sectors using multiple mode */
+#define WIN_MULTWRITE		0xC5	/* write sectors using multiple mode */
+#define WIN_SETMULT		0xC6	/* enable/disable multiple mode */
 #define WIN_IDENTIFY		0xEC	/* ask drive to identify itself	*/
-#define WIN_SETFEATURES		0xEF	/* set special drive features   */
+#define WIN_SETFEATURES		0xEF	/* set special drive features */
+#define WIN_READDMA		0xc8	/* read sectors using DMA transfers */
+#define WIN_WRITEDMA		0xca	/* write sectors using DMA transfers */
+
+/* Additional drive command codes used by ATAPI devices. */
+#define WIN_PIDENTIFY		0xA1	/* identify ATAPI device	*/
+#define WIN_SRST		0x08	/* ATAPI soft reset command */
+#define WIN_PACKETCMD		0xa0	/* Send a packet command. */
 
 /* Bits for HD_ERROR */
 #define MARK_ERR	0x01	/* Bad address mark */
@@ -80,13 +86,13 @@
 
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x30n/0x31n */
 #define HDIO_GETGEO		0x301	/* get device geometry */
-#define HDIO_REQ		HDIO_GETGEO	/* obsolete, use HDIO_GETGEO */
 #define HDIO_GET_UNMASKINTR	0x302	/* get current unmask setting */
 #define HDIO_GET_MULTCOUNT	0x304	/* get current IDE blockmode setting */
 #define HDIO_GET_IDENTITY 	0x307	/* get IDE identification info */
 #define HDIO_GET_KEEPSETTINGS 	0x308	/* get keep-settings-on-reset flag */
 #define HDIO_GET_CHIPSET	0x309	/* get current interface type setting */
-#define HDIO_GET_NOWERR	0x30a	/* get ignore-write-error flag */
+#define HDIO_GET_NOWERR		0x30a	/* get ignore-write-error flag */
+#define HDIO_GET_DMA		0x30b	/* get use-dma flag */
 #define HDIO_DRIVE_CMD		0x31f	/* execute a special drive command */
 
 /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x32n/0x33n */
@@ -94,7 +100,8 @@
 #define HDIO_SET_UNMASKINTR	0x322	/* permit other irqs during I/O */
 #define HDIO_SET_KEEPSETTINGS	0x323	/* keep ioctl settings on reset */
 #define HDIO_SET_CHIPSET	0x324	/* optimise driver for interface type */
-#define HDIO_SET_NOWERR	0x325	/* set ignore-write-error flag */
+#define HDIO_SET_NOWERR		0x325	/* set ignore-write-error flag */
+#define HDIO_SET_DMA		0x326	/* set use-dma flag */
 
 /* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
 struct hd_driveid {
diff -u --recursive --new-file v1.3.20/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v1.3.20/linux/include/linux/if_arp.h	Sun Feb  5 14:27:28 1995
+++ linux/include/linux/if_arp.h	Mon Aug 28 10:43:28 1995
@@ -28,7 +28,7 @@
 #define	ARPHRD_AX25	3		/* AX.25 Level 2		*/
 #define	ARPHRD_PRONET	4		/* PROnet token ring		*/
 #define	ARPHRD_CHAOS	5		/* Chaosnet			*/
-#define	ARPHRD_IEEE802	6		/* IEEE 802.2 Ethernet- huh?	*/
+#define	ARPHRD_IEEE802	6		/* IEEE 802.2 Ethernet/TR/TB	*/
 #define	ARPHRD_ARCNET	7		/* ARCnet			*/
 #define	ARPHRD_APPLETLK	8		/* APPLEtalk			*/
 /* Dummy types for non ARP hardware */
@@ -40,6 +40,7 @@
 #define ARPHRD_ADAPT	264
 #define ARPHRD_PPP	512
 #define ARPHRD_TUNNEL	768		/* IPIP tunnel			*/
+#define ARPHRD_TUNNEL6	769		/* IPIP6 tunnel			*/
 
 /* ARP protocol opcodes. */
 #define	ARPOP_REQUEST	1		/* ARP request			*/
diff -u --recursive --new-file v1.3.20/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v1.3.20/linux/include/linux/if_ether.h	Tue Aug 15 20:39:04 1995
+++ linux/include/linux/if_ether.h	Mon Aug 28 10:43:28 1995
@@ -49,6 +49,7 @@
 #define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
 #define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
 #define ETH_P_IPX	0x8137		/* IPX over DIX			*/
+#define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
 #define ETH_P_802_3	0x0001		/* Dummy type for 802.3 frames  */
 #define ETH_P_AX25	0x0002		/* Dummy protocol id for AX.25  */
 #define ETH_P_ALL	0x0003		/* Every packet (be careful!!!) */
diff -u --recursive --new-file v1.3.20/linux/include/linux/in.h linux/include/linux/in.h
--- v1.3.20/linux/include/linux/in.h	Tue Aug 15 20:39:05 1995
+++ linux/include/linux/in.h	Mon Aug 28 10:43:28 1995
@@ -127,4 +127,23 @@
 
 #endif
 
+/*
+ *	IPv6 definitions as we start to include them. This is just
+ *	a beginning dont get excited 8)
+ */
+ 
+struct in_addr6
+{
+	unsigned char s6_addr[16];
+};
+
+struct sockaddr_in6
+{
+	unsigned short sin6_family;
+	unsigned short sin6_port;
+	unsigned long sin6_flowinfo;
+	struct in_addr6 sin6_addr;
+};
+
+
 #endif	/* _LINUX_IN_H */
diff -u --recursive --new-file v1.3.20/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.3.20/linux/include/linux/mm.h	Tue Aug  8 12:31:42 1995
+++ linux/include/linux/mm.h	Mon Aug 28 11:19:42 1995
@@ -95,13 +95,13 @@
 	void (*close)(struct vm_area_struct * area);
 	void (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
 	void (*protect)(struct vm_area_struct *area, unsigned long, size_t, unsigned int newprot);
-	void (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags);
+	int (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags);
 	void (*advise)(struct vm_area_struct *area, unsigned long, size_t, unsigned int advise);
 	unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address,
 		unsigned long page, int write_access);
 	unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
 		unsigned long page);
-	void (*swapout)(struct vm_area_struct *,  unsigned long, pte_t *);
+	int (*swapout)(struct vm_area_struct *,  unsigned long, pte_t *);
 	pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
 };
 
diff -u --recursive --new-file v1.3.20/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v1.3.20/linux/include/linux/skbuff.h	Tue Aug 15 20:39:05 1995
+++ linux/include/linux/skbuff.h	Mon Aug 28 13:12:37 1995
@@ -363,6 +363,7 @@
 extern struct sk_buff *		skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
 extern int			datagram_select(struct sock *sk, int sel_type, select_table *wait);
 extern void			skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
+extern void			skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size);
 extern void			skb_free_datagram(struct sk_buff *skb);
 
 #endif	/* __KERNEL__ */
diff -u --recursive --new-file v1.3.20/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v1.3.20/linux/include/linux/smb_fs.h	Wed Aug  2 13:21:16 1995
+++ linux/include/linux/smb_fs.h	Mon Aug 28 13:19:05 1995
@@ -124,13 +124,18 @@
 
 /* linux/fs/smbfs/proc.c */
 dword smb_len(unsigned char *packet);
+byte *smb_encode_smb_length(byte *p, dword len);
 int smb_proc_open(struct smb_server *server, const char *pathname,
                   int len, struct smb_dirent *entry);
 int smb_proc_close(struct smb_server *server, struct smb_dirent *finfo);
 int smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, 
 		  off_t offset, long count, char *data, int fs);
+int smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo, 
+                      off_t offset, long count, char *data);
 int smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
 		   off_t offset, int count, const char *data);
+int smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, 
+                       off_t offset, long count, const char *data);
 int smb_proc_create(struct smb_server *server, const char *path,
                     int len, struct smb_dirent *entry);
 int smb_proc_mknew(struct smb_server *server, const char *path, int len,
@@ -161,6 +166,10 @@
 int smb_release(struct smb_server *server);
 int smb_connect(struct smb_server *server);
 int smb_request(struct smb_server *server);
+int smb_request_read_raw(struct smb_server *server,
+                         unsigned char *target, int max_len);
+int smb_request_write_raw(struct smb_server *server,
+                          unsigned const char *source, int length);
 int smb_catch_keepalive(struct smb_server *server);
 int smb_dont_catch_keepalive(struct smb_server *server);
 int smb_trans2_request(struct smb_server *server,
diff -u --recursive --new-file v1.3.20/linux/include/linux/socket.h linux/include/linux/socket.h
--- v1.3.20/linux/include/linux/socket.h	Wed Aug  9 14:55:43 1995
+++ linux/include/linux/socket.h	Mon Aug 28 10:43:28 1995
@@ -48,6 +48,7 @@
 #define AF_BRIDGE	7	/* Multiprotocol bridge 	*/
 #define AF_AAL5		8	/* Reserved for Werner's ATM 	*/
 #define AF_X25		9	/* Reserved for X.25 project 	*/
+#define AF_INET6	10	/* IP version 6			*/
 #define AF_MAX		12	/* For now.. */
 
 /* Protocol families, same as address families. */
@@ -61,6 +62,7 @@
 #define PF_BRIDGE	AF_BRIDGE
 #define PF_AAL5		AF_AAL5
 #define PF_X25		AF_X25
+#define PF_INET6	AF_INET6
 
 #define PF_MAX		AF_MAX
 
diff -u --recursive --new-file v1.3.20/linux/include/net/netrom.h linux/include/net/netrom.h
--- v1.3.20/linux/include/net/netrom.h	Fri Aug 18 08:44:58 1995
+++ linux/include/net/netrom.h	Mon Aug 28 10:43:29 1995
@@ -90,7 +90,7 @@
 extern struct nr_parms_struct nr_default;
 extern int  nr_rx_frame(struct sk_buff *, struct device *);
 extern void nr_destroy_socket(struct sock *);
-extern int  nr_get_info(char *, char **, off_t, int, int);
+/*extern int  nr_get_info(char *, char **, off_t, int, int);*/
 
 /* nr_dev.c */
 extern int  nr_rx_ip(struct sk_buff *, struct device *);
diff -u --recursive --new-file v1.3.20/linux/kernel/Makefile linux/kernel/Makefile
--- v1.3.20/linux/kernel/Makefile	Fri Aug 18 08:44:58 1995
+++ linux/kernel/Makefile	Mon Aug 28 10:13:47 1995
@@ -20,6 +20,8 @@
 
 ifdef CONFIG_MODVERSIONS
 $(O_TARGET): $(SYMTAB_OBJS:.o=.ver)
+dep: $(SYMTAB_OBJS:.o=.ver)
+fastdep: $(SYMTAB_OBJS:.o=.ver)
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.20/linux/mm/filemap.c linux/mm/filemap.c
--- v1.3.20/linux/mm/filemap.c	Mon Jul 31 15:59:03 1995
+++ linux/mm/filemap.c	Mon Aug 28 14:25:17 1995
@@ -1,7 +1,7 @@
 /*
- *	linux/mm/filemmap.c
+ *	linux/mm/filemap.c
  *
- * Copyright (C) 1994 Linus Torvalds
+ * Copyright (C) 1994, 1995  Linus Torvalds
  */
 
 /*
@@ -18,6 +18,8 @@
 #include <linux/mman.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -26,9 +28,15 @@
 /*
  * Shared mappings implemented 30.11.1994. It's not fully working yet,
  * though.
+ *
+ * Shared mappings now work. 15.8.1995  Bruno.
  */
 
-static inline void multi_bmap(struct inode * inode, unsigned int block, unsigned int * nr, int shift)
+/*
+ * Simple routines for both non-shared and shared mappings.
+ */
+
+static inline void multi_bmap(struct inode * inode, unsigned long block, unsigned int * nr, int shift)
 {
 	int i = PAGE_SIZE >> shift;
 	block >>= shift;
@@ -51,23 +59,19 @@
 	return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, no_share);
 }
 
+
 /*
- * NOTE! mmap sync doesn't really work yet. This is mainly a stub for it,
- * which only works if the buffers and the page were already sharing the
- * same physical page (that's actually pretty common, especially if the
- * file has been mmap'ed before being read the normal way).
- *
- * Todo:
- * - non-shared pages also need to be synced with the buffers.
- * - the "swapout()" function needs to swap out the page to
- *   the shared file instead of using the swap device.
+ * Tries to write a shared mapped page to its backing store. May return -EIO
+ * if the disk is full.
  */
-static void filemap_sync_page(struct vm_area_struct * vma,
+static int filemap_write_page(struct vm_area_struct * vma,
 	unsigned long offset,
 	unsigned long page)
 {
+	int old_fs;
+	unsigned long size, result;
+	struct file file;
 	struct inode * inode;
-	int nr[PAGE_SIZE/512];
 	struct buffer_head * bh;
 
 	bh = buffer_pages[MAP_NR(page)];
@@ -78,14 +82,39 @@
 			mark_buffer_dirty(tmp, 0);
 			tmp = tmp->b_this_page;
 		} while (tmp != bh);
-		return;
+		return 0;
 	}
+
 	inode = vma->vm_inode;
-	offset += vma->vm_offset;
-	multi_bmap(inode, offset, nr, inode->i_sb->s_blocksize_bits);
-	bwrite_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize);
+	file.f_op = inode->i_op->default_file_ops;
+	if (!file.f_op->write)
+		return -EIO;
+	size = offset + PAGE_SIZE;
+	/* refuse to extend file size.. */
+	if (S_ISREG(inode->i_mode)) {
+		if (size > inode->i_size)
+			size = inode->i_size;
+		/* Ho humm.. We should have tested for this earlier */
+		if (size < offset)
+			return -EIO;
+	}
+	size -= offset;
+	file.f_mode = 3;
+	file.f_flags = 0;
+	file.f_count = 1;
+	file.f_inode = inode;
+	file.f_pos = offset;
+	file.f_reada = 0;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	result = file.f_op->write(inode, &file, (const char *) page, size);
+	set_fs(old_fs);
+	if (result != size)
+		return -EIO;
+	return 0;
 }
 
+
 /*
  * Swapping to a shared file: while we're busy writing out the page
  * (and the page still exists in memory), we save the page information
@@ -94,20 +123,22 @@
  *
  * Once we've written it all out, we mark the page entry "empty", which
  * will result in a normal page-in (instead of a swap-in) from the now
- * up-to-date shared file mapping.
+ * up-to-date disk file.
  */
-void filemap_swapout(struct vm_area_struct * vma,
+int filemap_swapout(struct vm_area_struct * vma,
 	unsigned long offset,
 	pte_t *page_table)
 {
+	int error;
 	unsigned long page = pte_page(*page_table);
 	unsigned long entry = SWP_ENTRY(SHM_SWP_TYPE, MAP_NR(page));
 
 	pte_val(*page_table) = entry;
 	invalidate();
-	filemap_sync_page(vma, offset, page);
+	error = filemap_write_page(vma, offset, page);
 	if (pte_val(*page_table) == entry)
 		pte_clear(page_table);
+	return error;
 }
 
 /*
@@ -124,41 +155,58 @@
 
 	mem_map[page]++;
 	page = (page << PAGE_SHIFT) + PAGE_OFFSET;
-	return pte_mkdirty(mk_pte(page,vma->vm_page_prot));
+	return mk_pte(page,vma->vm_page_prot);
 }
 
-static inline void filemap_sync_pte(pte_t * pte, struct vm_area_struct *vma,
+
+static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
 	unsigned long address, unsigned int flags)
 {
-	pte_t page = *pte;
-
-	if (!pte_present(page))
-		return;
-	if (!pte_dirty(page))
-		return;
-	if (flags & MS_INVALIDATE) {
-		pte_clear(pte);
+	pte_t pte = *ptep;
+	unsigned long page;
+	int error;
+
+	if (!(flags & MS_INVALIDATE)) {
+		if (!pte_present(pte))
+			return 0;
+		if (!pte_dirty(pte))
+			return 0;
+		*ptep = pte_mkclean(pte);
+		page = pte_page(pte);
+		mem_map[MAP_NR(page)]++;
 	} else {
-		mem_map[MAP_NR(pte_page(page))]++;
-		*pte = pte_mkclean(page);
+		if (pte_none(pte))
+			return 0;
+		pte_clear(ptep);
+		if (!pte_present(pte)) {
+			swap_free(pte_val(pte));
+			return 0;
+		}
+		page = pte_page(pte);
+		if (!pte_dirty(pte) || flags == MS_INVALIDATE) {
+			free_page(page);
+			return 0;
+		}
 	}
-	filemap_sync_page(vma, address - vma->vm_start, pte_page(page));
-	free_page(pte_page(page));
+	error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page);
+	free_page(page);
+	return error;
 }
 
-static inline void filemap_sync_pte_range(pmd_t * pmd,
+static inline int filemap_sync_pte_range(pmd_t * pmd,
 	unsigned long address, unsigned long size, 
 	struct vm_area_struct *vma, unsigned long offset, unsigned int flags)
 {
 	pte_t * pte;
 	unsigned long end;
+	int error;
 
 	if (pmd_none(*pmd))
-		return;
+		return 0;
 	if (pmd_bad(*pmd)) {
 		printk("filemap_sync_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
 		pmd_clear(pmd);
-		return;
+		return 0;
 	}
 	pte = pte_offset(pmd, address);
 	offset += address & PMD_MASK;
@@ -166,26 +214,29 @@
 	end = address + size;
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
+	error = 0;
 	do {
-		filemap_sync_pte(pte, vma, address + offset, flags);
+		error |= filemap_sync_pte(pte, vma, address + offset, flags);
 		address += PAGE_SIZE;
 		pte++;
 	} while (address < end);
+	return error;
 }
 
-static inline void filemap_sync_pmd_range(pgd_t * pgd,
+static inline int filemap_sync_pmd_range(pgd_t * pgd,
 	unsigned long address, unsigned long size, 
 	struct vm_area_struct *vma, unsigned int flags)
 {
 	pmd_t * pmd;
 	unsigned long offset, end;
+	int error;
 
 	if (pgd_none(*pgd))
-		return;
+		return 0;
 	if (pgd_bad(*pgd)) {
 		printk("filemap_sync_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
 		pgd_clear(pgd);
-		return;
+		return 0;
 	}
 	pmd = pmd_offset(pgd, address);
 	offset = address & PMD_MASK;
@@ -193,31 +244,34 @@
 	end = address + size;
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
+	error = 0;
 	do {
-		filemap_sync_pte_range(pmd, address, end - address, vma, offset, flags);
+		error |= filemap_sync_pte_range(pmd, address, end - address, vma, offset, flags);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	} while (address < end);
+	return error;
 }
 
-static void filemap_sync(struct vm_area_struct * vma, unsigned long address,
+static int filemap_sync(struct vm_area_struct * vma, unsigned long address,
 	size_t size, unsigned int flags)
 {
 	pgd_t * dir;
 	unsigned long end = address + size;
+	int error = 0;
 
 	dir = pgd_offset(current, address);
 	while (address < end) {
-		filemap_sync_pmd_range(dir, address, end - address, vma, flags);
+		error |= filemap_sync_pmd_range(dir, address, end - address, vma, flags);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
 	invalidate();
-	return;
+	return error;
 }
 
 /*
- * This handles area unmaps..
+ * This handles partial area unmaps..
  */
 static void filemap_unmap(struct vm_area_struct *vma, unsigned long start, size_t len)
 {
@@ -251,9 +305,9 @@
 };
 
 /*
- * Private mappings just need to be able to load in the map
+ * Private mappings just need to be able to load in the map.
  *
- * (this is actually used for shared mappings as well, if we
+ * (This is actually used for shared mappings as well, if we
  * know they can't ever get write permissions..)
  */
 static struct vm_operations_struct file_private_mmap = {
@@ -274,17 +328,21 @@
 {
 	struct vm_operations_struct * ops;
 
-	if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
-		return -EINVAL;
+	if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) {
+		ops = &file_shared_mmap;
+		/* share_page() can only guarantee proper page sharing if
+		 * the offsets are all page aligned. */
+		if (vma->vm_offset & (PAGE_SIZE - 1))
+			return -EINVAL;
+	} else {
+		ops = &file_private_mmap;
+		if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
+			return -EINVAL;
+	}
 	if (!inode->i_sb || !S_ISREG(inode->i_mode))
 		return -EACCES;
 	if (!inode->i_op || !inode->i_op->bmap)
 		return -ENOEXEC;
-	ops = &file_private_mmap;
-	if (vma->vm_flags & VM_SHARED) {
-		if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
-			ops = &file_shared_mmap;
-	}
 	if (!IS_RDONLY(inode)) {
 		inode->i_atime = CURRENT_TIME;
 		inode->i_dirt = 1;
@@ -293,4 +351,75 @@
 	inode->i_count++;
 	vma->vm_ops = ops;
 	return 0;
+}
+
+
+/*
+ * The msync() system call.
+ */
+
+static int msync_interval(struct vm_area_struct * vma,
+	unsigned long start, unsigned long end, int flags)
+{
+	if (!vma->vm_inode)
+		return 0;
+	if (vma->vm_ops->sync) {
+		int error;
+		error = vma->vm_ops->sync(vma, start, end-start, flags);
+		if (error)
+			return error;
+		if (flags & MS_SYNC)
+			return file_fsync(vma->vm_inode, NULL);
+		return 0;
+	}
+	return 0;
+}
+
+asmlinkage int sys_msync(unsigned long start, size_t len, int flags)
+{
+	unsigned long end;
+	struct vm_area_struct * vma;
+	int unmapped_error, error;
+
+	if (start & ~PAGE_MASK)
+		return -EINVAL;
+	len = (len + ~PAGE_MASK) & PAGE_MASK;
+	end = start + len;
+	if (end < start)
+		return -EINVAL;
+	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
+		return -EINVAL;
+	if (end == start)
+		return 0;
+	/*
+	 * If the interval [start,end) covers some unmapped address ranges,
+	 * just ignore them, but return -EFAULT at the end.
+	 */
+	vma = find_vma(current, start);
+	unmapped_error = 0;
+	for (;;) {
+		/* Still start < end. */
+		if (!vma)
+			return -EFAULT;
+		/* Here start < vma->vm_end. */
+		if (start < vma->vm_start) {
+			unmapped_error = -EFAULT;
+			start = vma->vm_start;
+		}
+		/* Here vma->vm_start <= start < vma->vm_end. */
+		if (end <= vma->vm_end) {
+			if (start < end) {
+				error = msync_interval(vma, start, end, flags);
+				if (error)
+					return error;
+			}
+			return unmapped_error;
+		}
+		/* Here vma->vm_start <= start < vma->vm_end < end. */
+		error = msync_interval(vma, start, vma->vm_end, flags);
+		if (error)
+			return error;
+		start = vma->vm_end;
+		vma = vma->vm_next;
+	}
 }
diff -u --recursive --new-file v1.3.20/linux/mm/swap.c linux/mm/swap.c
--- v1.3.20/linux/mm/swap.c	Tue Jul 18 16:28:59 1995
+++ linux/mm/swap.c	Fri Aug 18 09:11:02 1995
@@ -55,6 +55,13 @@
 
 extern int shm_swap (int, unsigned long);
 
+/*
+ * To save us from swapping out pages which have just been swapped in and
+ * have not been modified since then, we keep in swap_cache[page>>PAGE_SHIFT]
+ * the swap entry which was last used to fill the page, or zero if the
+ * page does not currently correspond to a page in swap. PAGE_DIRTY makes
+ * this info useless.
+ */
 unsigned long *swap_cache;
 
 #ifdef SWAP_CACHE_INFO
@@ -366,12 +373,14 @@
 		return 0;
 	}	
 	if (pte_dirty(pte)) {
-		if (mem_map[MAP_NR(page)] != 1)
-			return 0;
 		if (vma->vm_ops && vma->vm_ops->swapout) {
+			pid_t pid = vma->vm_task->pid;
 			vma->vm_task->mm->rss--;
-			vma->vm_ops->swapout(vma, address-vma->vm_start, page_table);
+			if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table))
+				kill_proc(pid, SIGBUS, 1);
 		} else {
+			if (mem_map[MAP_NR(page)] != 1)
+				return 0;
 			if (!(entry = get_swap_page()))
 				return 0;
 			vma->vm_task->mm->rss--;
diff -u --recursive --new-file v1.3.20/linux/net/Changes linux/net/Changes
--- v1.3.20/linux/net/Changes	Sun Aug 13 14:45:35 1995
+++ linux/net/Changes	Mon Aug 28 10:43:36 1995
@@ -140,9 +140,9 @@
 
 ------->>>>>    1.3.14  <<<<<----------
 
-o	IPX works					[IN]
-o	NetROM works					[IN]
-o	AX.25 works					[IN]
+o	IPX works					[TESTED]
+o	NetROM works					[TESTED]
+o	AX.25 works					[TESTED]
 o	Most modules need recompiling even though they
 	load OK 					[BLAME LINUS]
 o	Appletalk works nicely				[CHECKED]
@@ -150,14 +150,14 @@
 
 ------->>>>>   1.3.15  <<<<<---------
 o	Mike Shaver has started RFC1122 verification	[IN PROGRESS]
-o	Minor bug fixes					[IN]
+o	Minor bug fixes					[TESTED]
 
 ------->>>> 1.3.16 <<<--------
 
 o	Missing patches for device change in TCP	[TESTED]
 o	Device locking					[TESTED]
-o	Infinite slip devices				[IN]
-o	New AF_UNIX sockets				[IN]
+o	Infinite slip devices				[IN - BUG]
+o	New AF_UNIX sockets				[TESTED]
 o	Sendmsg/recvmsg (for some stuff only)		[IN]
 o	Device unload loopholes fixed			[TESTED]
 o	Extra firewall abilities			[IN]
@@ -165,11 +165,17 @@
 
 ------->>>> 1.3.18 <<<<---------
 
-o	AF_UNIX debugging				[IN]
-o	TCP explode on SWS bug fix			[IN]
-o	John Naylor's ARP hwtype fix			[IN]
-o	Datagram select matches BSD semantics		[IN]
-
+o	AF_UNIX debugging				[TESTED]
+o	TCP explode on SWS bug fix			[TESTED]
+o	John Naylor's ARP hwtype fix			[TESTED]
+o	Datagram select matches BSD semantics		[TESTED]
+
+-------->>>>> 1.3.21 <<<<<---------
+
+o	AF_UNIX fixes and 4K limiter			[IN]
+o	Sendmsg/recvmsg for AX.25/Appletalk		[IN]
+o	Datagram generic iovec support			[IN]
+o	Misc minor bug fixes				[IN]
 
 o	Finish merging the bridge code
 o	SIOCSLEEPRT patch
@@ -177,7 +183,7 @@
 o	Fast checksum/copy on outgoing TCP
 o	Fast dev_grab_next() transmit reload function
 	and dev_push_failed() ??
-o	Faster ip_forward last hit cache		[PENDING]
+o	Faster ip_forward last hit cache		[PENDING(GuruA0)]
 o	Forwarding queue control (+ fairness algorithms ??)
 o	IP forward flow control.
 o	Infinite PPP devices.
@@ -186,6 +192,10 @@
 o	Finish 802.2 Class I code to be compliant to the oddities of 802.2
 o	Full variable length AX.25 support		[JSN doing]
 o	Tidy BPQ support
+o	Strange eth0-eth3 bug 
+o	Finish IPIP bug fixes
+o	Why doesnt the PROTO_UNREACH get sent ?
+
 
 0.2
 ---
@@ -282,9 +292,10 @@
 17.	PPP multilink. Another nasty job.
 
 18.	Implement swIPe under Linux.
-[In progress]
+[Reportedly in progress]
 
 19.	IPv4 IP-AH and IP-ESP.
+[Taken]
 
 BTW: Don't let the magic words 'kernel programming' worry you. Its like DOS
 - you make a mistake you have to reboot. You do at least get dumps and a
diff -u --recursive --new-file v1.3.20/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v1.3.20/linux/net/appletalk/ddp.c	Fri Aug 18 08:44:58 1995
+++ linux/net/appletalk/ddp.c	Mon Aug 28 10:43:29 1995
@@ -13,6 +13,7 @@
  *		Michael Callahan	:	Made routing work
  *		Wesley Craig		:	Fix probing to listen to a
  *						passed node id.
+ *		Alan Cox		:	Added send/recvmsg support
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -1466,11 +1467,10 @@
 	return(0);
 }
 
-static int atalk_sendto(struct socket *sock, const void *ubuf, int len, int noblock,
-	unsigned flags, struct sockaddr *sat, int addr_len)
+static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
 {
 	atalk_socket *sk=(atalk_socket *)sock->data;
-	struct sockaddr_at *usat=(struct sockaddr_at *)sat;
+	struct sockaddr_at *usat=(struct sockaddr_at *)msg->msg_name;
 	struct sockaddr_at local_satalk, gsat;
 	struct sk_buff *skb;
 	struct device *dev;
@@ -1495,7 +1495,7 @@
 				return -EBUSY;
 		}
 
-		if(addr_len <sizeof(*usat))
+		if(msg->msg_namelen <sizeof(*usat))
 			return(-EINVAL);
 		if(usat->sat_family != AF_APPLETALK)
 			return -EINVAL;
@@ -1581,7 +1581,7 @@
 	if(sk->debug)
 		printk("SK %p: Copy user data (%d bytes).\n", sk, len);
 		
-	memcpy_fromfs(skb_put(skb,len),ubuf,len);
+	memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len);
 
 	if(sk->no_check==1)
 		ddp->deh_sum=0;
@@ -1643,16 +1643,32 @@
 	return len;
 }
 
+
+static int atalk_sendto(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags,
+		struct sockaddr *sa, int addr_len)
+{
+	struct iovec iov;
+	struct msghdr msg;
+	iov.iov_base=(void *)ubuf;
+	iov.iov_len=size;
+	msg.msg_name=(void *)sa;
+	msg.msg_namelen=addr_len;
+	msg.msg_accrights=NULL;
+	msg.msg_iov=&iov;
+	msg.msg_iovlen=1;
+	return atalk_sendmsg(sock,&msg,size,noblock,flags);	
+}
+
+
 static int atalk_send(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags)
 {
 	return atalk_sendto(sock,ubuf,size,noblock,flags,NULL,0);
 }
 
-static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
-		   unsigned flags, struct sockaddr *sip, int *addr_len)
+static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
 {
 	atalk_socket *sk=(atalk_socket *)sock->data;
-	struct sockaddr_at *sat=(struct sockaddr_at *)sip;
+	struct sockaddr_at *sat=(struct sockaddr_at *)msg->msg_name;
 	struct ddpehdr	*ddp = NULL;
 	int copied = 0;
 	struct sk_buff *skb;
@@ -1678,14 +1694,14 @@
 		copied=ddp->deh_len;
 		if(copied > size)
 			copied=size;
-		skb_copy_datagram(skb,0,ubuf,copied);
+		skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied);
 	}
 	else
 	{
 		copied=ddp->deh_len - sizeof(*ddp);
 		if (copied > size)
 			copied = size;
-		skb_copy_datagram(skb,sizeof(*ddp),ubuf,copied);
+		skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied);
 	}
 	if(sat)
 	{
@@ -1705,6 +1721,23 @@
 }
 
 
+static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags,
+		struct sockaddr *sa, int *addr_len)
+{
+	struct iovec iov;
+	struct msghdr msg;
+	iov.iov_base=ubuf;
+	iov.iov_len=size;
+	msg.msg_name=(void *)sa;
+	msg.msg_namelen=0;
+	if (addr_len)
+		msg.msg_namelen = *addr_len;
+	msg.msg_accrights=NULL;
+	msg.msg_iov=&iov;
+	msg.msg_iovlen=1;
+	return atalk_recvmsg(sock,&msg,size,noblock,flags,addr_len);	
+}
+
 static int atalk_recv(struct socket *sock, void *ubuf, int size , int noblock,
 	unsigned flags)
 {
@@ -1848,6 +1881,8 @@
 	atalk_setsockopt,
 	atalk_getsockopt,
 	atalk_fcntl,
+	atalk_sendmsg,
+	atalk_recvmsg
 };
 
 static struct notifier_block ddp_notifier={
@@ -1886,6 +1921,6 @@
 		atalk_if_get_info
 	});
 
-	printk("Appletalk BETA 0.11 for Linux NET3.030\n");
+	printk("Appletalk BETA 0.12 for Linux NET3.030\n");
 }
 #endif
diff -u --recursive --new-file v1.3.20/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v1.3.20/linux/net/ax25/af_ax25.c	Fri Aug 18 08:44:59 1995
+++ linux/net/ax25/af_ax25.c	Mon Aug 28 10:43:30 1995
@@ -1630,12 +1630,11 @@
 	return ax25_rcv(skb, dev, &port_call, ptype);
 }
 
-static int ax25_sendto(struct socket *sock, const void *ubuf, int len, int noblock,
-	unsigned flags, struct sockaddr *usip, int addr_len)
+static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, int noblock, int flags)
 {
 	struct sock *sk = (struct sock *)sock->data;
-	struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)usip;
-	unsigned char *uaddr = (unsigned char *)usip;
+	struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
+	unsigned char *uaddr = (unsigned char *)msg->msg_name;
 	int err;
 	struct sockaddr_ax25 sax;
 	struct sk_buff *skb;
@@ -1644,14 +1643,17 @@
 	ax25_digi *dp;
 	ax25_digi dtmp;
 	int lv;
+	int addr_len=msg->msg_namelen;
 	
 	if (sk->err) {
+		cli();
 		err     = sk->err;
 		sk->err = 0;
+		sti();
 		return -err;
 	}
 
-	if (flags)
+	if (flags|| msg->msg_accrights)
 		return -EINVAL;
 
 	if (sk->zapped)
@@ -1731,7 +1733,7 @@
 		printk("AX.25: Appending user data\n");
 
 	/* User data follows immediately after the AX.25 data */
-	memcpy_fromfs(skb_put(skb, len), ubuf, len);
+	memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
 
 	/* Add the PID, usually AX25_TEXT */
 	asmptr  = skb_push(skb, 1);
@@ -1780,6 +1782,22 @@
 		
 }
 
+static int ax25_sendto(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags,
+		struct sockaddr *sa, int addr_len)
+{
+	struct iovec iov;
+	struct msghdr msg;
+	iov.iov_base=(void *)ubuf;
+	iov.iov_len=size;
+	msg.msg_name=(void *)sa;
+	msg.msg_namelen=addr_len;
+	msg.msg_accrights=NULL;
+	msg.msg_iov=&iov;
+	msg.msg_iovlen=1;
+	return ax25_sendmsg(sock,&msg,size,noblock,flags);	
+}
+
+
 static int ax25_send(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags)
 {
 	return ax25_sendto(sock, ubuf, size, noblock, flags, NULL, 0);
@@ -1787,22 +1805,23 @@
 
 static int ax25_write(struct socket *sock, const char *ubuf, int size, int noblock)
 {
-	return ax25_send(sock, ubuf, size, noblock, 0);
+	return ax25_sendto(sock, ubuf, size, noblock, 0, NULL, 0);
 }
 
-static int ax25_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
-		   unsigned flags, struct sockaddr *sip, int *addr_len)
+static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
 {
 	struct sock *sk = (struct sock *)sock->data;
-	struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)sip;
-	char *addrptr = (char *)sip;
+	struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
+	char *addrptr = (char *)msg->msg_name;
 	int copied, length;
 	struct sk_buff *skb;
 	int er;
 
 	if (sk->err) {
+		cli();
 		er      = -sk->err;
 		sk->err = 0;
+		sti();
 		return er;
 	}
 	
@@ -1830,7 +1849,7 @@
 	}
 
 	copied = (size < length) ? size : length;
-	skb_copy_datagram(skb, 0, ubuf, copied);
+	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	
 	if (sax) {
 		struct sockaddr_ax25 addr;
@@ -1859,6 +1878,23 @@
 	return copied;
 }		
 
+static int ax25_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags,
+		struct sockaddr *sa, int *addr_len)
+{
+	struct iovec iov;
+	struct msghdr msg;
+	iov.iov_base=ubuf;
+	iov.iov_len=size;
+	msg.msg_name=(void *)sa;
+	msg.msg_namelen=0;
+	if (addr_len)
+		msg.msg_namelen = *addr_len;
+	msg.msg_accrights=NULL;
+	msg.msg_iov=&iov;
+	msg.msg_iovlen=1;
+	return ax25_recvmsg(sock,&msg,size,noblock,flags,addr_len);	
+}
+
 static int ax25_recv(struct socket *sock, void *ubuf, int size , int noblock,
 	unsigned flags)
 {
@@ -2076,6 +2112,8 @@
 	ax25_setsockopt,
 	ax25_getsockopt,
 	ax25_fcntl,
+	ax25_sendmsg,
+	ax25_recvmsg
 };
 
 /* Called by socket.c on kernel start up */
diff -u --recursive --new-file v1.3.20/linux/net/core/Makefile linux/net/core/Makefile
--- v1.3.20/linux/net/core/Makefile	Fri Aug 18 08:44:59 1995
+++ linux/net/core/Makefile	Thu Aug 17 09:34:44 1995
@@ -9,10 +9,10 @@
 
 O_TARGET := core.o
 
-O_OBJS	:=
+O_OBJS	:= sock.o skbuff.o iovec.o datagram.o
 
 ifdef CONFIG_NET
-O_OBJS	+= sock.o dev.o dev_mcast.o iovec.o skbuff.o datagram.o
+O_OBJS	+= dev.o dev_mcast.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.20/linux/net/core/datagram.c linux/net/core/datagram.c
--- v1.3.20/linux/net/core/datagram.c	Sun Aug 13 14:45:35 1995
+++ linux/net/core/datagram.c	Mon Aug 28 10:43:29 1995
@@ -17,6 +17,7 @@
  *		Florian  La Roche:	Changed for my new skbuff handling.
  *		Darryl Miles	:	Fixed non-blocking SOCK_SEQPACKET.
  *		Linus Torvalds	:	BSD semantic fixes.
+ *		Alan Cox	:	Datagram iovec handling
  *
  *	Note:
  *		A lot of this will change when the protocol/socket separation
@@ -164,9 +165,23 @@
 	restore_flags(flags);
 }
 
+/*
+ *	Copy a datagram to a linear buffer.
+ */
+
 void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
 {
 	memcpy_tofs(to,skb->h.raw+offset,size);
+}
+
+
+/*
+ *	Copy a datagram to an iovec.
+ */
+ 
+void skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, int size)
+{
+	memcpy_toiovec(to,skb->h.raw+offset,size);
 }
 
 /*
diff -u --recursive --new-file v1.3.20/linux/net/core/iovec.c linux/net/core/iovec.c
--- v1.3.20/linux/net/core/iovec.c	Tue Aug  8 12:31:43 1995
+++ linux/net/core/iovec.c	Mon Aug 28 10:39:06 1995
@@ -64,9 +64,10 @@
 {
 	while(len>0)
 	{
-		memcpy_tofs(iov->iov_base, kdata,iov->iov_len);
-		kdata+=iov->iov_len;
-		len-=iov->iov_len;
+		int copy = min(iov->iov_len,len);
+		memcpy_tofs(iov->iov_base,kdata,copy);
+		kdata+=copy;
+		len-=copy;
 		iov++;
 	}
 }
diff -u --recursive --new-file v1.3.20/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v1.3.20/linux/net/ipv4/af_inet.c	Tue Aug 15 20:39:11 1995
+++ linux/net/ipv4/af_inet.c	Mon Aug 28 10:43:29 1995
@@ -95,7 +95,7 @@
 extern int tcp_get_info(char *, char **, off_t, int, int);
 extern int udp_get_info(char *, char **, off_t, int, int);
 
-int (*rarp_ioctl_hook)(int,void*) = NULL;
+int (*rarp_ioctl_hook)(unsigned int,void*) = NULL;
 
 /*
  *	See if a socket number is in use.
diff -u --recursive --new-file v1.3.20/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v1.3.20/linux/net/ipv4/arp.c	Fri Aug 18 08:44:59 1995
+++ linux/net/ipv4/arp.c	Mon Aug 28 09:36:25 1995
@@ -691,7 +691,7 @@
  *	Check for bad requests for 127.x.x.x and requests for multicast
  *	addresses.  If this is one such, delete it.
  */
-	if (IN_LOOPBACK(tip) || IN_MULTICAST(tip))
+	if (LOOPBACK(tip) || MULTICAST(tip))
 	{
 		kfree_skb(skb, FREE_READ);
 		return 0;
diff -u --recursive --new-file v1.3.20/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v1.3.20/linux/net/ipv4/icmp.c	Wed Aug  2 13:21:17 1995
+++ linux/net/ipv4/icmp.c	Mon Aug 28 10:43:29 1995
@@ -102,7 +102,7 @@
      (OK... we don't use it)
    MUST discard received REPLYs if not using this system (OK)
    MUST NOT send replies unless specifically made agent for this sort
-     of thing. (NOT YET)
+     of thing. (OK)
 */
 
 #include <linux/types.h>
diff -u --recursive --new-file v1.3.20/linux/net/ipv4/ip.c linux/net/ipv4/ip.c
--- v1.3.20/linux/net/ipv4/ip.c	Fri Aug 18 08:44:59 1995
+++ linux/net/ipv4/ip.c	Mon Aug 28 10:43:29 1995
@@ -205,6 +205,26 @@
 	return mac;
 }
 
+static int ip_send_room(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, unsigned long saddr)
+{
+	int mac = 0;
+
+	skb->dev = dev;
+	skb->arp = 1;
+	if (dev->hard_header)
+	{
+		skb_reserve(skb,MAX_HEADER);
+		mac = dev->hard_header(skb, dev, ETH_P_IP, NULL, NULL, len);
+		if (mac < 0)
+		{
+			mac = -mac;
+			skb->arp = 0;
+			skb->raddr = daddr;	/* next routing address */
+		}
+	}
+	return mac;
+}
+
 int ip_id_count = 0;
 
 /*
@@ -287,7 +307,10 @@
 	 *	Now build the MAC header.
 	 */
 
-	tmp = ip_send(skb, raddr, len, *dev, saddr);
+	if(type==IPPROTO_TCP)
+		tmp = ip_send_room(skb, raddr, len, *dev, saddr);
+	else
+		tmp = ip_send(skb, raddr, len, *dev, saddr);
 
 	/*
 	 *	Book keeping
@@ -1300,6 +1323,15 @@
 	int err;
 #endif	
 
+#ifdef CONFIG_NET_IPV6
+	/* 
+	 *	Intercept IPv6 frames. We dump ST-II and invalid types just below..
+	 */
+	 
+	if(iph->version == 6)
+		return ipv6_rcv(skb,dev,pt);
+#endif		
+
 	ip_statistics.IpInReceives++;
 
 	/*
@@ -1571,13 +1603,13 @@
 		{
 			struct sock *sknext=NULL;
 			struct sk_buff *skb1;
-			raw_sk=get_sock_raw(raw_sk, hash,  iph->saddr, iph->daddr);
+			raw_sk=get_sock_raw(raw_sk, iph->protocol,  iph->saddr, iph->daddr);
 			if(raw_sk)	/* Any raw sockets */
 			{
 				do
 				{
 					/* Find the next */
-					sknext=get_sock_raw(raw_sk->next, hash, iph->saddr, iph->daddr);
+					sknext=get_sock_raw(raw_sk->next, iph->protocol, iph->saddr, iph->daddr);
 					if(sknext)
 						skb1=skb_clone(skb, GFP_ATOMIC);
 					else
diff -u --recursive --new-file v1.3.20/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v1.3.20/linux/net/ipv4/ip_fw.c	Fri Aug 18 08:44:59 1995
+++ linux/net/ipv4/ip_fw.c	Mon Aug 28 10:43:29 1995
@@ -1502,7 +1502,7 @@
 #ifdef CONFIG_IP_MASQUERADE
 
 static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
-			      int length)
+			      int length, int unused)
 {
 	off_t pos=0, begin=0;
 	struct ip_masq *ms;
diff -u --recursive --new-file v1.3.20/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v1.3.20/linux/net/ipv4/tcp.c	Wed Aug  9 14:55:45 1995
+++ linux/net/ipv4/tcp.c	Mon Aug 28 10:43:29 1995
@@ -886,7 +886,7 @@
 	 * until we time out, or the user gives up.
 	 */
 
-	if (icmp_err_convert[err & 0xff].fatal || sk->state == TCP_SYN_SENT) 
+	if (err < 13 && (icmp_err_convert[err & 0xff].fatal || sk->state == TCP_SYN_SENT))
 	{
 		if (sk->state == TCP_SYN_SENT) 
 		{
diff -u --recursive --new-file v1.3.20/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v1.3.20/linux/net/ipv4/udp.c	Wed Aug  2 13:21:18 1995
+++ linux/net/ipv4/udp.c	Mon Aug 28 10:43:29 1995
@@ -189,7 +189,7 @@
 	/* 4.1.3.3. */
 	/* After the comment above, that should be no surprise. */
 
-	if (icmp_err_convert[err & 0xff].fatal)
+	if (err < 13 && icmp_err_convert[err & 0xff].fatal)
 	{
 		sk->err = icmp_err_convert[err & 0xff].errno;
 		sk->error_report(sk);
diff -u --recursive --new-file v1.3.20/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v1.3.20/linux/net/netrom/af_netrom.c	Fri Aug 18 08:45:00 1995
+++ linux/net/netrom/af_netrom.c	Mon Aug 28 10:43:29 1995
@@ -36,6 +36,7 @@
 #include <linux/string.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
+#include <linux/stat.h>
 #include <net/ax25.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
@@ -53,7 +54,7 @@
 #include <linux/proc_fs.h>
 #include <net/ip.h>
 #include <net/arp.h>
-
+#include <linux/if_arp.h>
 #include <linux/proc_fs.h>
 
 /************************************************************************\
@@ -1411,16 +1412,19 @@
 	proc_net_register(&(struct proc_dir_entry) {
 		PROC_NET_NR, 2, "nr",
 		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations, 
 		nr_get_info
 	});
 	proc_net_register(&(struct proc_dir_entry) {
 		PROC_NET_NR_NEIGH, 8, "nr_neigh",
 		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations, 
 		nr_neigh_get_info
 	});
 	proc_net_register(&(struct proc_dir_entry) {
 		PROC_NET_NR_NODES, 8, "nr_nodes",
 		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations, 
 		nr_nodes_get_info
 	});
 }
diff -u --recursive --new-file v1.3.20/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v1.3.20/linux/net/netrom/nr_dev.c	Fri Aug 18 08:45:00 1995
+++ linux/net/netrom/nr_dev.c	Mon Aug 28 10:43:29 1995
@@ -41,6 +41,7 @@
 
 #include <net/ip.h>
 #include <net/arp.h>
+#include <linux/if_arp.h>
 
 #include <net/ax25.h>
 #include <net/netrom.h>
diff -u --recursive --new-file v1.3.20/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v1.3.20/linux/net/unix/af_unix.c	Fri Aug 18 08:45:00 1995
+++ linux/net/unix/af_unix.c	Mon Aug 28 10:43:29 1995
@@ -5,8 +5,8 @@
  *
  *		Currently this contains all but the file descriptor passing code.
  *		Before that goes in the odd bugs in the iovec handlers need 
- *		fixing, and this bit testing. BSD fd passing is a trivial part
- *		of the exercise.
+ *		fixing, and this bit testing. BSD fd passing is not a trivial part
+ *		of the exercise it turns out. Anyone like writing garbage collectors.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -15,8 +15,9 @@
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
- *		Niibe Yutaka	:	async I/O support
+ *		Niibe Yutaka	:	async I/O support.
  *		Carsten Paeth	:	PF_UNIX check, address fixes.
+ *		Alan Cox	:	Limit size of allocated blocks.
  */
 
 #include <linux/config.h>
@@ -681,7 +682,7 @@
 	if(sun==NULL)
 	{
 		if(sk->protinfo.af_unix.other==NULL)
-			return -EINVAL;
+			return -ENOTCONN;
 	}
 
 	/*
@@ -694,6 +695,13 @@
 		if(sock->type==SOCK_DGRAM)
 			return -EMSGSIZE;
 		len=(sk->sndbuf-sizeof(struct sk_buff))/2;
+		/*
+		 *	Keep to page sized kmalloc()'s as various people
+		 *	have suggested. Big mallocs stress the vm too
+		 *	much.
+		 */
+		if(len > 4000 && sock->type!=SOCK_DGRAM)
+			len = 4000;
 	}
 	 
 	size=/*protocol_size(&proto_unix)+*/len;
@@ -1044,7 +1052,7 @@
 
 void unix_proto_init(struct net_proto *pro)
 {
-	printk("NET3: Unix domain sockets 0.07 BETA for Linux NET3.030.\n");
+	printk("NET3: Unix domain sockets 0.09 BETA for Linux NET3.030.\n");
 	sock_register(unix_proto_ops.family, &unix_proto_ops);
 	proc_net_register(&(struct proc_dir_entry) {
 		PROC_NET_UNIX,  4, "unix",
diff -u --recursive --new-file v1.3.20/linux/scripts/depend.awk linux/scripts/depend.awk
--- v1.3.20/linux/scripts/depend.awk	Tue Aug 15 20:39:12 1995
+++ linux/scripts/depend.awk	Mon Aug 28 10:40:44 1995
@@ -14,9 +14,8 @@
 			return "Yes"
 		} else {return ""}
 	}
-	ERRNO=""
-	getline dummy < f
-	if(!length(ERRNO)) {
+	ERRNO = getline dummy < f
+	if(ERRNO >= 0) {
 		close(f)
 		return FILEHASH[f]="Yes"
 	} else {
diff -u --recursive --new-file v1.3.20/linux/versions.mk linux/versions.mk
--- v1.3.20/linux/versions.mk	Thu Jun  1 11:53:40 1995
+++ linux/versions.mk	Fri Aug 18 10:10:27 1995
@@ -26,6 +26,6 @@
 	do echo "#include <linux/modules/$${f}>"; done) \
 	> $(TOPINCL)/modversions.h
 
-dep: $(TOPINCL)/modversions.h
+fastdep: $(TOPINCL)/modversions.h
 
 endif
