diff -u --recursive --new-file v1.1.38/linux/Makefile linux/Makefile
--- v1.1.38/linux/Makefile	Wed Aug  3 09:32:20 1994
+++ linux/Makefile	Thu Aug  4 08:47:27 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 38
+SUBLEVEL = 39
 
 all:	Version zImage
 
diff -u --recursive --new-file v1.1.38/linux/drivers/block/README.hd linux/drivers/block/README.hd
--- v1.1.38/linux/drivers/block/README.hd	Tue Aug  2 11:27:40 1994
+++ linux/drivers/block/README.hd	Thu Aug  4 08:35:02 1994
@@ -1,159 +1,8 @@
-IDE Performance Enhancements	Version 2.1
-============================	===========
+This hard disk driver (hd.c) includes support for IDE Multiple Mode
+and IRQ-unmasking during I/O (both disabled by default), as well as
+support for drives where the BIOS reports "more than 16 heads".
 
-What's new in version 2.1:
-	-- Support added for E-IDE BIOSs, for systems with IDE drives
-	that "have more than 16 logical heads" (according the BIOS).
-	-- the HDIO_SETUNMASKINTR and HDIO_SETMULTCOUNT now permit
-	only the superuser to change settings, and no longer permit
-	minor device numbers to be used.
+The hdparm.c program for controlling various features is now packaged
+separately.  Look for it on your favorite linux FTP site.
 
-This version of hd.c includes support for two optional features:
-
-(1) The disk I/O routines can now run with interrupts unmasked
-	most of the time, making them much friendlier to high
-	speed serial ports and other system activity.
-
-(2) Support is included for IDE "Multiple Sector Mode", the use
-	of which can reduce disk I/O kernel overhead by 10-30%
-	on many systems, with a corresponding 10-20% increase in
-	data throughput.
-
-By default, both features are DISABLED, for compatibility with
-	systems on which they may cause troubles.
-
-The IRQ unmasking has been known to CORRUPT FILESYSTEMS in the
-past on systems with strange hard drives.  Backup before trying!
-
-It works on most systems, but use at your own risk!!
-
-Drives which support "Multiple Sector Mode" are identified by the
-kernel at boot time, and a message is displayed indicating the
-largest possible setting for "MaxMult" (max sector count for
-"Multiple Sector Mode").
-
-For more detailed boot-time information about your drive, change
-the definition of VERBOSE_DRIVE_INFO from 0 to 1 near the top
-of hd.c and rebuild/reinstall the kernel.
-
-Some drives (mostly older CONNER drives) do not implement multiple mode
-correctly, and data corruption may occur.. but if you wait long enough
-the error recovery logic *should* be able to recover eventually.
-
-I recommend using settings of 8, 16, or 32.  Many drives also support
-non-powers of two, but other drives do not -- try strange values at
-your own risk!
-
-To try this out more safely, mount the drive's partitions read-only
-before using hdparm (see below) for the first time.  If it doesn't
-work, email me (mlord@bnr.ca) with the drive name as displayed at
-boot time, so I can warn others and possibly add a hook to the code.
-
-To enable the features, a small program is included below:  hdparm.c
-This one is *different* from previous versions -- be sure to recompile it!
-
-Compile this using   cc -O -o /usr/bin/hdparm hdparm.c
-and then use it to enable/disable the new features, as follows:
-
-To turn on 16-sector multiple mode, with interrupt unmasking:
-
-	hdparm /dev/hda 16 1
-
-To view the current settings:
-
-	hdparm /dev/hda
-
-If you have more than one drive, a separate command would need to		be issued for the second drive as well, using the same or different
-settings as desired:
-
-	hdparm /dev/hdb 16 1
-
-To turn off both features on the first drive, use:
-
-	hdparm /dev/hda 0 0
-
-To benchmark the performance difference, try:
-
-	hdparm /dev/hda 0 0
-	sync
-	time dd if=/dev/hda of=/dev/null bs=1024k count=30
-	time dd if=/dev/hda of=/dev/null bs=1024k count=30
-	time dd if=/dev/hda of=/dev/null bs=1024k count=30
-	hdparm /dev/hda 16 1
-	sync
-	time dd if=/dev/hda of=/dev/null bs=1024k count=30
-	time dd if=/dev/hda of=/dev/null bs=1024k count=30
-	time dd if=/dev/hda of=/dev/null bs=1024k count=30
-
-This gives before and after views.  Compare the total elapsed times,
-as well as the percent of CPU used in each case.  Run several trials
-to ensure/verify consistent results.  Some drives are actually *slower*
-with multiple mode enabled, but those are very rare indeed.  Most systems
-experience a 10-30% increase in throughput, with a corresponding 5-50%
-decrease in kernel/system CPU usage.
-
-If you are using linux kernel 1.1.4 or higher (with the "cluster" code),
-then you may not notice a big difference with the above tests.  However,
-I have noticed that the iozone benchmark program does seem to work fairly
-reliably under kernels with the "cluster" code, so you could try that
-instead (under older kernels, iozone seems to give wildly varying results
-from trial to trial, at least on my system).
-
-To have your favorite settings installed automatically at boot time,
-place the hdparm command(s) into the /etc/rc.d/rc.local file.
-Alternatively, one could modify the DEFAULTs near the top of hd.c
-and rebuild and install the new kernel.
-
-Enjoy,
-mlord@bnr.ca
-
-**** CUT HERE for hdparm.c ****
-
-/* make using:    cc -O -o /usr/bin/hdparm hdparm.c */
-
-#include <linux/hdreg.h>
-#include <sys/ioctl.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/* extern int hd_ioctl(struct inode * inode, struct file * file,
- *                     unsigned int cmd, unsigned long arg);
- */
-
-
-void main (int argc, char *argv[])
-{
-	int fd, mrc, irc;
-	static long mcount, irqmode;
-
-	if (argc != 4 && argc != 2) {
-		fprintf(stderr,"Usage:  %s  <device>"
-			       " [<MultModeCount:0-64> <unmask:0/1>]\n", *argv);
-		exit (1);
-	}
-
-	fd = open (*++argv, O_RDONLY);
-	if (fd < 0) {
-		printf ("open failed - '%s' - %d\n", *argv, fd);
-		exit(1);
-	}
-        if (argc == 4) {
-		mcount = atoi(*++argv);
-		mrc = ioctl (fd, HDIO_SETMULTCOUNT, &mcount);
-		/* note that the new mcount does not take effect
-		   until the next disk I/O operation, so if we were
-		   to query it before then, the old value will show.
-		   Also, the drive may reject the new value, which will
-		   result in multiple mode being turned OFF completely! */
-		irqmode = atoi(*++argv);
-		irc = ioctl (fd, HDIO_SETUNMASKINTR, &irqmode);
-        }
-        else {
-		mrc = ioctl (fd, HDIO_GETMULTCOUNT, &mcount);
-		irc = ioctl (fd, HDIO_GETUNMASKINTR, &irqmode);
-        }
-	printf("MultModeCount=%d, rc=%d\n", mcount, mrc);
-	printf("unmask=%d, rc=%d\n", irqmode, irc);
-}
+-mlord@bnr.ca
diff -u --recursive --new-file v1.1.38/linux/drivers/block/blk.h linux/drivers/block/blk.h
--- v1.1.38/linux/drivers/block/blk.h	Tue Aug  2 11:27:40 1994
+++ linux/drivers/block/blk.h	Thu Aug  4 08:35:02 1994
@@ -95,10 +95,10 @@
 extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end);
 
 #define RO_IOCTLS(dev,where) \
-  case BLKROSET: if (!suser()) return -EPERM; \
+  case BLKROSET: if (!suser()) return -EACCES; \
 		 set_device_ro((dev),get_fs_long((long *) (where))); return 0; \
   case BLKROGET: { int __err = verify_area(VERIFY_WRITE, (void *) (where), sizeof(long)); \
-		   if (!__err) put_fs_long(is_read_only(dev),(long *) (where)); return __err; }
+		   if (!__err) put_fs_long(0!=is_read_only(dev),(long *) (where)); return __err; }
 		 
 #ifdef MAJOR_NR
 
diff -u --recursive --new-file v1.1.38/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v1.1.38/linux/drivers/block/hd.c	Tue Aug  2 11:27:40 1994
+++ linux/drivers/block/hd.c	Thu Aug  4 08:35:03 1994
@@ -17,13 +17,12 @@
  *
  *  IDE IRQ-unmask & drive-id & multiple-mode code added by Mark Lord.
  *
- *  Support for E-IDE BIOS drive geometry translation added by Mark Lord.
- *   -- hd.c no longer chokes on E-IDE drives with "more than 16 heads".
+ *  Support for BIOS drive geometry translation added by Mark Lord.
+ *   -- hd.c no longer chokes on drives with "more than 16 heads".
  */
 
 #define DEFAULT_MULT_COUNT  0	/* set to 0 to disable multiple mode at boot */
 #define DEFAULT_UNMASK_INTR 0	/* set to 0 to *NOT* unmask irq's more often */
-#define VERBOSE_DRIVE_INFO  0	/* set to 1 for more drive info at boot time */
 
 #include <asm/irq.h>
 #include <linux/errno.h>
@@ -35,6 +34,7 @@
 #include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/config.h>
+#include <linux/malloc.h>
 
 #define REALLY_SLOW_IO
 #include <asm/system.h>
@@ -64,7 +64,8 @@
 static void recal_intr(void);
 static void bad_rw_intr(void);
 
-static char recalibrate[ MAX_HD ] = { 0, };
+static char recalibrate[MAX_HD] = { 0, };
+static char special_op[MAX_HD] = { 0, };
 static int access_count[MAX_HD] = {0, };
 static char busy[MAX_HD] = {0, };
 static struct wait_queue * busy_wait = NULL;
@@ -82,6 +83,8 @@
 struct hd_i_struct {
 	unsigned int head,sect,cyl,wpcom,lzone,ctl;
 	};
+static struct hd_driveid *hd_ident_info[MAX_HD];
+	
 #ifdef HD_TYPE
 static struct hd_i_struct hd_info[] = { HD_TYPE };
 struct hd_i_struct bios_info[] = { HD_TYPE };
@@ -195,11 +198,13 @@
 {
 	unsigned short port;
 
+#ifdef DEBUG
 	if (drive>1 || head>15) {
 		printk("bad drive mapping, trying to access drive=%d, cyl=%d, head=%d, sect=%d\n",
 			drive, cyl, head, sect);
 		panic("harddisk driver problem");
 	}
+#endif
 #if (HD_DELAY > 0)
 	while (read_timer() - last_req < HD_DELAY)
 		/* nothing */;
@@ -207,7 +212,7 @@
 	if (reset)
 		return;
 	if (!controller_ready(drive, head)) {
-		reset = 1;
+		special_op[drive] += reset = 1;
 		return;
 	}
 	SET_INTR(intr_addr);
@@ -230,7 +235,7 @@
 static unsigned int mult_count  [MAX_HD] = {0,}; /* currently enabled MultMode count */
 static struct request WCURRENT;
 
-static void rawstring (char *prefix, char *s, int n)
+static void rawstring (char *prefix, unsigned char *s, int n)
 {
 	if (prefix)
 		printk(prefix);
@@ -243,78 +248,20 @@
 	}
 }
 
-#if VERBOSE_DRIVE_INFO
-
-char *cfg_str[] =
-{	"", " HardSect", " SoftSect", " NotMFM", " HdSw>15uSec", " SpinMotCtl",
-	" Fixed", " Removeable", " DTR<=5Mbs", " DTR>5Mbs", " DTR>10Mbs",
-	" RotSpdTol>.5%", " dStbOff", " TrkOff", " FmtGapReq", "",
-};
-
-char *ioready[]		= {"no", "?", "yes", "on/off"};
-char *SlowMedFast[]	= {"slow", "medium", "fast"};
-char *BuffType[]	= {"?", "1Sect", "DualPort", "DualPortCache"};
-
-#define YN(b)	(((b)==0)?"no":"yes")
-
-static void dmpstr (char *prefix, unsigned int i, char *s[], unsigned int maxi)
-{
-	printk(prefix);
-	printk( (i > maxi) ? "?" : s[i] );
-}
-
-static void dump_identity (unsigned int dev, unsigned short ib[])
-{
-	int i;
-	char dashes[] = "\n+-------------------------------------------------------------------+\n";
-	printk (dashes);
-	printk ("hd%c:  Drive Identification Info:\n", dev+'a');
-	rawstring (" Model=",(char *)&ib[27],40);
-	rawstring (", FwRev=",(char *)&ib[23],8);
-	rawstring (", SerialNo=",(char *)&ib[10],20);
-	printk ("\n Config={");
-	for (i=0; i<=15; i++) if (ib[0] & (1<<i)) printk (cfg_str[i]);
-	printk (" }\n");
-	printk (" Default CHS=%d/%d/%d, TrkSize=%d, SectSize=%d, ECCbytes=%d\n",
-		ib[1],ib[3],ib[6],ib[4],ib[5], ib[22]);
-	dmpstr (" BuffType=",ib[20],BuffType,3);
-	ib[47] &= 0xFF;
-	printk (", BuffSize=%dKB, MaxMultSect=%d\n", ib[21]/2, ib[47]);
-	printk (" Features: DblWordIO=%s, IORDY=%s, LBA=%s, DMA=%s",
-		YN(ib[48]&1),ioready[(ib[49]&0xC00)>>10],YN(ib[49]&0x200),YN(ib[49]&0x100));
-	dmpstr (", tPIO=",ib[51]>>8,SlowMedFast,2);
-	if (ib[49]&0x100 && (ib[53]&1))
-		dmpstr (", tDMA=",ib[52]>>8,SlowMedFast,2);
-	printk ("\n (%s): Current CHS=%d/%d/%d, TotSect=%d",
-		(((ib[53]&1)==0)?"maybe":"valid"),
-		ib[54],ib[55],ib[56],*(int *)&ib[57]);
-	if (ib[49]&0x200)
-		printk (", MaxLBAsect=%d", *(int *)&ib[60]);
-	printk("\n CurMultSect=%d%s",ib[59]&0xFF,(ib[59]&0x100)?"":"?");
-	if (ib[49]&0x100)
-		printk (", DMA-1w=%04X, DMA-mw=%04X", ib[62], ib[63]);
-	printk ("%s\n",dashes);
-}
-#endif /* VERBOSE_DRIVE_INFO */
-
 static void identify_intr(void)
 {
 	unsigned int dev = DEVICE_NR(CURRENT->dev);
-	unsigned short ib[64], stat = inb_p(HD_STATUS);
+	unsigned short stat = inb_p(HD_STATUS);
+	struct hd_driveid id;
 
 	if (unmask_intr[dev])
 		sti();
 	if (stat & (BUSY_STAT|ERR_STAT))
-		printk ("  hd%c: multiple mode not supported\n", dev+'a');
+		printk ("  hd%c: identity unknown\n", dev+'a');
 	else {
-		insw(HD_DATA,(char *)ib,64); /* get first 128 ID bytes */
-#if VERBOSE_DRIVE_INFO
-		dump_identity(dev, ib);
-#endif
-		printk ("  hd%c: ", dev+'a');
-		rawstring(NULL, (char *)&ib[27], 40);
-		max_mult[dev] = ib[47] & 0xff;
-		if (ib[53]&1 && ib[54] && ib[55] && ib[56]) {
+		insw(HD_DATA, (char *)&id, sizeof(id)/2); /* get ID bytes */
+		max_mult[dev] = id.max_multsect;
+		if ((id.cur_valid&1) && id.cur_cyls && id.cur_heads && (id.cur_heads <= 16) && id.cur_sectors) {
 			/*
 			 * Extract the physical drive geometry for our use.
 			 * Note that we purposely do *not* update the bios_info.
@@ -322,16 +269,23 @@
 			 * still have the same logical view as the BIOS does,
 			 * which keeps the partition table from being screwed.
 			 */
-			hd_info[dev].cyl  = ib[54];
-			hd_info[dev].head = ib[55];
-			hd_info[dev].sect = ib[56];
-		}
-		printk (" (%dMB IDE w/%dKB Cache, MaxMult=%d, CHS=%d/%d/%d)\n",
-			ib[1]*ib[3]*ib[6] / 2048, ib[21]>>1, max_mult[dev],
-			hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect);
-		insw(HD_DATA,(char *)ib,64); /* flush remaining 384 ID bytes */
-		insw(HD_DATA,(char *)ib,64);
-		insw(HD_DATA,(char *)ib,64);
+			hd_info[dev].cyl  = id.cur_cyls;
+			hd_info[dev].head = id.cur_heads;
+			hd_info[dev].sect = id.cur_sectors; 
+		}
+		printk ("  hd%c: ", dev+'a');
+		rawstring(NULL, id.model, sizeof(id.model));
+		printk (", %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
+			id.cyls*id.heads*id.sectors/2048, id.buf_size/2,
+			hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect, id.max_multsect);
+		/* save drive info for later query via HDIO_GETIDENTITY */
+		if (NULL != (hd_ident_info[dev] = kmalloc(sizeof(id),GFP_ATOMIC)))
+			*hd_ident_info[dev] = id;
+		
+		/* flush remaining 384 (reserved/undefined) ID bytes: */
+		insw(HD_DATA,(char *)&id,sizeof(id)/2);
+		insw(HD_DATA,(char *)&id,sizeof(id)/2);
+		insw(HD_DATA,(char *)&id,sizeof(id)/2);
 	}
 	hd_request();
 	return;
@@ -443,11 +397,11 @@
 	dev = MINOR(CURRENT->dev) >> 6;
 	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
 		end_request(0);
-		recalibrate[dev] = 1;
+		special_op[dev] += recalibrate[dev] = 1;
 	} else if (CURRENT->errors % RESET_FREQ == 0)
-		reset = 1;
+		special_op[dev] += reset = 1;
 	else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
-		recalibrate[dev] = 1;
+		special_op[dev] += recalibrate[dev] = 1;
 	/* Otherwise just retry */
 }
 
@@ -644,7 +598,7 @@
 {
 	DEVICE_INTR = NULL;
 	sti();
-	reset = 1;
+	special_op [DEVICE_NR(CURRENT->dev)] += reset = 1;
 	if (!CURRENT)
 		return;
 	printk(KERN_DEBUG "HD timeout\n");
@@ -703,42 +657,45 @@
 #endif
 	if (!unmask_intr[dev])
 		cli();
-	if (reset) {
-		int i;
-
-		for (i=0; i < NR_HD; i++)
-			recalibrate[i] = 1;
-		cli(); /* better play it safe, as resets are the last resort */
-		reset_hd();
-		return;
-	}
-	if (recalibrate[dev]) {
-		recalibrate[dev] = 0;
-		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
-		if (reset)
-			goto repeat;
-		return;
-	}	
-	if (!identified[dev]) {
-		identified[dev]  = 1;
-		unmask_intr[dev] = DEFAULT_UNMASK_INTR;
-		mult_req[dev]    = DEFAULT_MULT_COUNT;
-		hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
-		if (reset)
-			goto repeat;
-		return;
-	}
-	if (mult_req[dev] != mult_count[dev]) {
-		hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
-		if (reset)
+	if (special_op[dev]) {	/* we use "special_op" to reduce overhead on r/w */
+		if (reset) {
+			int i;
+	
+			for (i=0; i < NR_HD; i++)
+				special_op[i] = recalibrate[i] = 1;
+			cli(); /* better play it safe, as resets are the last resort */
+			reset_hd();
+			return;
+		}
+		if (recalibrate[dev]) {
+			recalibrate[dev] = 0;
+			hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
+			if (reset)
+				goto repeat;
+			return;
+		}	
+		if (!identified[dev]) {
+			identified[dev]  = 1;
+			unmask_intr[dev] = DEFAULT_UNMASK_INTR;
+			mult_req[dev]    = DEFAULT_MULT_COUNT;
+			hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
+			if (reset)
+				goto repeat;
+			return;
+		}
+		if (mult_req[dev] != mult_count[dev]) {
+			hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
+			if (reset)
+				goto repeat;
+			return;
+		}
+		if (hd_info[dev].head > 16) {
+			printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
+			end_request(0);
 			goto repeat;
-		return;
-	}
-	if (hd_info[dev].head > 16) {
-		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
-		end_request(0);
-		goto repeat;
-	}
+		}
+		--special_op[dev];
+	} /* special_op[dev] */
 	if (CURRENT->cmd == READ) {
 		unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;
 		hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);
@@ -792,7 +749,7 @@
 	struct hd_geometry *loc = (struct hd_geometry *) arg;
 	int dev, err;
 
-	if (!inode)
+	if ((!inode) || (!inode->i_rdev))
 		return -EINVAL;
 	dev = MINOR(inode->i_rdev) >> 6;
 	if (dev >= NR_HD)
@@ -814,21 +771,25 @@
 			return 0;
 		case BLKRASET:
 			if(!suser())  return -EACCES;
-			if(!inode->i_rdev) return -EINVAL;
 			if(arg > 0xff) return -EINVAL;
 			read_ahead[MAJOR(inode->i_rdev)] = arg;
 			return 0;
+		case BLKRAGET:
+			if (!arg)  return -EINVAL;
+			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+			if (err)
+				return err;
+			put_fs_long(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
+			return 0;
          	case BLKGETSIZE:   /* Return device size */
 			if (!arg)  return -EINVAL;
 			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
 			if (err)
 				return err;
-			put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects,
-				(long *) arg);
+			put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
 			return 0;
 		case BLKFLSBUF:
 			if(!suser())  return -EACCES;
-			if(!inode->i_rdev) return -EINVAL;
 			fsync_dev(inode->i_rdev);
 			invalidate_buffers(inode->i_rdev);
 			return 0;
@@ -838,8 +799,8 @@
 
 		case HDIO_SETUNMASKINTR:
 			if (!suser()) return -EACCES;
-			if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
 			if (!arg)  return -EINVAL;
+			if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
 			err = verify_area(VERIFY_READ, (long *) arg, sizeof(long));
 			if (err)
 				return err;
@@ -876,15 +837,25 @@
 			cli();	/* a prior request might still be in progress */
 			if (arg > max_mult[dev])
 				err = -EINVAL;	/* out of range for device */
-			else if (mult_req[dev] != mult_count[dev])
+			else if (mult_req[dev] != mult_count[dev]) {
+				++special_op[dev];
 				err = -EBUSY;	/* busy, try again */
-			else {
+			} else {
 				mult_req[dev] = arg;
+				++special_op[dev];
 				err = 0;
 			}
 			restore_flags(flags);
 			return err;
 		}
+		case HDIO_GETIDENTITY:
+			if (!arg)  return -EINVAL;
+			if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
+			if (hd_ident_info[dev] == NULL)  return -ENOMSG;
+			err = verify_area(VERIFY_WRITE, (char *) arg, sizeof(struct hd_driveid));
+			if (err)
+				return err;
+			memcpy_tofs((char *)arg, (char *) hd_ident_info[dev], sizeof(struct hd_driveid));
 
 		RO_IOCTLS(inode->i_rdev,arg);
 		default:
@@ -1031,6 +1002,8 @@
 		}
 		hd[i<<6].nr_sects = bios_info[i].head *
 				bios_info[i].sect * bios_info[i].cyl;
+		hd_ident_info[i] = NULL;
+		special_op[i] = 1;
 	}
 	if (NR_HD) {
 		if (irqaction(HD_IRQ,&hd_sigaction)) {
diff -u --recursive --new-file v1.1.38/linux/drivers/block/ramdisk.c linux/drivers/block/ramdisk.c
--- v1.1.38/linux/drivers/block/ramdisk.c	Fri Jul  8 13:26:32 1994
+++ linux/drivers/block/ramdisk.c	Thu Aug  4 08:31:04 1994
@@ -186,7 +186,7 @@
 
 /* ugly, ugly */
 	if (floppy_grab_irq_and_dma()) {
-		printk("Unable to gram floppy IRQ/DMA for loading ramdisk image\n");
+		printk("Unable to grab floppy IRQ/DMA for loading ramdisk image\n");
 		return;
 	}
 	do_load();
diff -u --recursive --new-file v1.1.38/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v1.1.38/linux/drivers/net/plip.c	Sat Jul 23 17:38:37 1994
+++ linux/drivers/net/plip.c	Thu Aug  4 08:18:56 1994
@@ -774,6 +774,7 @@
 		    break;
 		if (--cx == 0) /* time out */
 		    return 1;
+		udelay(PLIP_DELAY_UNIT);
 	    }
 	    outb(0x10 | (data >> 4), PAR_DATA(dev));
 	    *ns_p = PLIP_NST_2;
@@ -788,6 +789,7 @@
 		    break;
 		if (--cx == 0) /* time out */
 		    return 1;
+		udelay(PLIP_DELAY_UNIT);
 	    }
 	    return 0;
 
diff -u --recursive --new-file v1.1.38/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.1.38/linux/drivers/scsi/Makefile	Wed Aug  3 09:32:27 1994
+++ linux/drivers/scsi/Makefile	Tue Aug  2 18:02:16 1994
@@ -87,10 +87,10 @@
 SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c
 endif
 
-#ifdef CONFIG_SCSI_NCR53C7xx
+ifdef CONFIG_SCSI_NCR53C7xx
 SCSI_OBJS := $(SCSI_OBJS) 53c7,8xx.o 
 SCSI_SRCS := $(SCSI_SRCS) 53c7,8xx.c
-#endif
+endif
 
 ifdef CONFIG_SCSI_PAS16
 SCSI_OBJS := $(SCSI_OBJS) pas16.o
diff -u --recursive --new-file v1.1.38/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.1.38/linux/drivers/scsi/st.c	Tue Aug  2 11:27:43 1994
+++ linux/drivers/scsi/st.c	Tue Aug  2 18:02:15 1994
@@ -1712,7 +1712,7 @@
   if(SDp->type != TYPE_TAPE) return 0;
 
   printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n", 
-	 ++st_template.dev_noticed,
+	 st_template.dev_noticed++,
 	 SDp->host->host_no , SDp->id, SDp->lun); 
   
   return 1;
diff -u --recursive --new-file v1.1.38/linux/fs/super.c linux/fs/super.c
--- v1.1.38/linux/fs/super.c	Wed Aug  3 09:32:32 1994
+++ linux/fs/super.c	Thu Aug  4 08:22:30 1994
@@ -650,7 +650,7 @@
 		wait_for_keypress();
 		/* ugly, ugly */
 		if (floppy_grab_irq_and_dma())
-			printk("Unable to gram floppy IRQ/DMA for mounting root floppy\n");
+			printk("Unable to grab floppy IRQ/DMA for mounting root floppy\n");
 	}
 	for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
 		if (!fs_type->requires_dev)
diff -u --recursive --new-file v1.1.38/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.1.38/linux/include/linux/fs.h	Wed Aug  3 09:32:32 1994
+++ linux/include/linux/fs.h	Thu Aug  4 08:35:03 1994
@@ -105,6 +105,7 @@
 #define BLKGETSIZE 4704 /* return device size */
 #define BLKFLSBUF 4705 /* flush buffer cache */
 #define BLKRASET 4706 /* Set read ahead for block device */
+#define BLKRAGET 4707 /* get current read ahead setting */
 
 /* These are a few other constants  only used by scsi  devices */
 
diff -u --recursive --new-file v1.1.38/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v1.1.38/linux/include/linux/hdreg.h	Thu Jul 21 08:18:19 1994
+++ linux/include/linux/hdreg.h	Thu Aug  4 08:35:03 1994
@@ -72,4 +72,49 @@
 #define HDIO_GETMULTCOUNT	0x304
 #define HDIO_SETMULTCOUNT	0x305
 #define HDIO_SETFEATURE  	0x306
+#define HDIO_GETIDENTITY 	0x307
 #endif
+
+/* structure returned by HDIO_GETIDENTITY, as per ASC X3T9.2 rev 4a */
+struct hd_driveid {
+	unsigned short	config;		/* lots of obsolete bit flags */
+	unsigned short	cyls;		/* "physical" cyls */
+	unsigned short	reserved0;	/* reserved */
+	unsigned short	heads;		/* "physical" heads */
+	unsigned short	track_bytes;	/* unformatted bytes per track */
+	unsigned short	sector_bytes;	/* unformatted bytes per sector */
+	unsigned short	sectors;	/* "physical" sectors per track */
+	unsigned short	vendor0;	/* vendor unique */
+	unsigned short	vendor1;	/* vendor unique */
+	unsigned short	vendor2;	/* vendor unique */
+	unsigned char	serial_no[20];	/* big_endian; 0 = not_specified */
+	unsigned short	buf_type;
+	unsigned short	buf_size;	/* 512 byte increments; 0 = not_specified */
+	unsigned short	ecc_bytes;	/* for r/w long cmds; 0 = not_specified */
+	unsigned char	fw_rev[8];	/* big_endian; 0 = not_specified */
+	unsigned char	model[40];	/* big_endian; 0 = not_specified */
+	unsigned char	max_multsect;	/* 0=not_implemented */
+	unsigned char	vendor3;	/* vendor unique */
+	unsigned short	dword_io;	/* 0=not_implemented; 1=implemented */
+	unsigned char	vendor4;	/* vendor unique */
+	unsigned char	capability;	/* bit0:DMA, bit1:LBA */
+	unsigned short	reserved1;	/* reserved */
+	unsigned char	vendor5;	/* vendor unique */
+	unsigned char	tPIO;		/* 0=slow, 1=medium, 2=fast */
+	unsigned char	vendor6;	/* vendor unique */
+	unsigned char	tDMA;		/* 0=slow, 1=medium, 2=fast */
+	unsigned short	cur_valid;	/* when (bit0==1) use logical geom */
+	unsigned short	cur_cyls;	/* logical cylinders */
+	unsigned short	cur_heads;	/* logical heads */
+	unsigned short	cur_sectors;	/* logical sectors per track */
+	unsigned short	cur_capacity0;	/* logical total sectors on drive */
+	unsigned short	cur_capacity1;	/*  (2 words, misaligned int)     */
+	unsigned char	multsect;	/* current multiple sector count */
+	unsigned char	multsect_valid;	/* when (bit0==1) multsect is ok */
+	unsigned int	lba_capacity;	/* total number of sectors */
+	unsigned short	dma_1word;	/* single-word dma info */
+	unsigned short	dma_mword;	/* multiple-word dma info */
+	/* unsigned short reserved2[64];*/	/* reserved */
+	/* unsigned short vendor7  [32];*/	/* vendor unique */
+	/* unsigned short reserved3[96];*/	/* reserved */
+};
diff -u --recursive --new-file v1.1.38/linux/include/linux/scsicam.h linux/include/linux/scsicam.h
--- v1.1.38/linux/include/linux/scsicam.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/scsicam.h	Wed Aug  3 09:17:44 1994
@@ -0,0 +1,16 @@
+/*
+ * scsicam.h - SCSI CAM support functions, use for HDIO_GETGEO, etc.
+ *
+ * Copyright 1993, 1994 Drew Eckhardt
+ *      Visionary Computing 
+ *      (Unix and Linux consulting and custom programming)
+ *      drew@Colorado.EDU
+ *	+1 (303) 786-7975
+ *
+ * For more information, please consult the SCSI-CAM draft.
+ */
+
+#ifndef SCSICAM_H
+#define SCSICAM_H
+extern int scsicam_bios_param (Disk *disk, int dev, int *ip);
+#endif /* def SCSICAM_H */
diff -u --recursive --new-file v1.1.38/linux/init/main.c linux/init/main.c
--- v1.1.38/linux/init/main.c	Wed Aug  3 09:32:33 1994
+++ linux/init/main.c	Wed Aug  3 09:40:01 1994
@@ -98,6 +98,7 @@
 #ifdef CONFIG_SBPCD
 extern void sbpcd_setup(char *str, int *ints);
 #endif CONFIG_SBPCD
+void ramdisk_setup(char *str, int *ints);
 
 #ifdef CONFIG_SYSVIPC
 extern void ipc_init(void);
@@ -175,6 +176,7 @@
 	void (*setup_func)(char *, int *);
 } bootsetups[] = {
 	{ "reserve=", reserve_setup },
+	{ "ramdisk=", ramdisk_setup },
 #ifdef CONFIG_INET
 	{ "ether=", eth_setup },
 #endif
@@ -220,6 +222,12 @@
 #endif CONFIG_SBPCD
 	{ 0, 0 }
 };
+
+void ramdisk_setup(char *str, int *ints)
+{
+   if (ints[0] > 0 && ints[1] >= 0)
+      ramdisk_size = ints[1];
+}
 
 int checksetup(char *line)
 {
diff -u --recursive --new-file v1.1.38/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v1.1.38/linux/kernel/ptrace.c	Sat Jul 23 17:38:38 1994
+++ linux/kernel/ptrace.c	Wed Aug  3 09:44:46 1994
@@ -291,8 +291,11 @@
 	if (request == PTRACE_ATTACH) {
 		if (child == current)
 			return -EPERM;
-		if ((!child->dumpable || (current->uid != child->euid) ||
-	 	    (current->gid != child->egid)) && !suser())
+		if ((!child->dumpable ||
+		    (current->uid != child->euid) ||
+		    (current->uid != child->uid) ||
+	 	    (current->gid != child->egid) ||
+	 	    (current->gid != child->gid)) && !suser())
 			return -EPERM;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
diff -u --recursive --new-file v1.1.38/linux/net/inet/skbuff.c linux/net/inet/skbuff.c
--- v1.1.38/linux/net/inet/skbuff.c	Tue Jun 21 14:16:29 1994
+++ linux/net/inet/skbuff.c	Thu Aug  4 08:17:41 1994
@@ -525,6 +525,7 @@
 	n->tries=0;
 	n->lock=0;
 	n->users=0;
+	n->pkt_type=skb->pkt_type;
 	return n;
 }
 	
diff -u --recursive --new-file v1.1.38/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.38/linux/net/inet/tcp.c	Wed Aug  3 09:32:36 1994
+++ linux/net/inet/tcp.c	Thu Aug  4 08:22:04 1994
@@ -299,7 +299,7 @@
 	 * until we time out, or the user gives up.
 	 */
 
-	if (icmp_err_convert[err & 0xff].fatal) 
+	if (icmp_err_convert[err & 0xff].fatal || sk->state == TCP_SYN_SENT) 
 	{
 		if (sk->state == TCP_SYN_SENT) 
 		{
