diff -u --recursive --new-file v2.1.61/linux/CREDITS linux/CREDITS
--- v2.1.61/linux/CREDITS	Sat Nov  1 11:04:27 1997
+++ linux/CREDITS	Sun Nov  2 13:13:44 1997
@@ -1094,10 +1094,10 @@
 S: Germany
 
 N: David Mosberger-Tang
-E: davidm@azstarnet.com
+E: David.Mosberger@acm.org
 D: Linux/Alpha
-S: 2552 E. Copper Street
-S: Tucson, Arizona 85716-2406
+S: 35706 Runckel Lane
+S: Fremont, CA 94536
 S: USA
 
 N: Ian A. Murdock
diff -u --recursive --new-file v2.1.61/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.61/linux/Documentation/Configure.help	Sat Oct 25 02:44:14 1997
+++ linux/Documentation/Configure.help	Sat Nov  1 12:23:52 1997
@@ -1667,10 +1667,10 @@
 Enable vendor-specific extensions (for SCSI CDROM)
 CONFIG_BLK_DEV_SR_VENDOR
   This enables the usage of vendor specific SCSI commands. This is
-  required for some stuff which is newer than the SCSI-II standard:
-  MultiSession CD support and some ioctls for reading Mode 2 Form 2
-  sectors. You'll probably want to say Y here, unless you have a
-  _really old_ CD-ROM drive.
+  required to support multisession CD's on with old NEC/TOSHIBA
+  cdrom drives (and HP Writers). If you have such a drive and get
+  the first session only, try to turn this on. Most drives should
+  work fine without this.
 
 SCSI generic support
 CONFIG_CHR_DEV_SG
diff -u --recursive --new-file v2.1.61/linux/Makefile linux/Makefile
--- v2.1.61/linux/Makefile	Sat Nov  1 11:04:27 1997
+++ linux/Makefile	Mon Nov  3 09:30:30 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 61
+SUBLEVEL = 62
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.61/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.1.61/linux/arch/alpha/kernel/time.c	Wed Apr 16 14:14:59 1997
+++ linux/arch/alpha/kernel/time.c	Sat Nov  1 09:53:00 1997
@@ -12,6 +12,10 @@
  *      precision CMOS clock update
  * 1997-01-09    Adrian Sun
  *      use interval timer if CONFIG_RTC=y
+ * 1997-10-29    John Bowman (bowman@math.ualberta.ca)
+ *      fixed tick loss calculation in timer_interrupt
+ *      (round system clock to nearest tick instead of truncating)
+ *      fixed algorithm in time_init for getting time from CMOS clock
  */
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -23,6 +27,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/hwrpb.h>
+#include <asm/delay.h>
 
 #include <linux/mc146818rtc.h>
 #include <linux/timex.h>
@@ -45,10 +50,11 @@
  */
 #define FIX_SHIFT	48
 
+static unsigned long round_ticks;
+
 /* lump static variables together for more efficient access: */
 static struct {
 	__u32		last_time;		/* cycle counter last time it got invoked */
-	__u32		max_cycles_per_tick;	/* more makes us think we lost an interrupt */
 	unsigned long	scaled_ticks_per_cycle;	/* ticks/cycle * 2^48 */
 	long		last_rtc_update;	/* last time the cmos clock got updated */
 } state;
@@ -70,19 +76,15 @@
 void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
 {
 	__u32 delta, now;
+	int i, nticks;
 
 	now = rpcc();
 	delta = now - state.last_time;
 	state.last_time = now;
-	if (delta > state.max_cycles_per_tick) {
-		int i, missed_ticks;
-
-		missed_ticks = ((delta * state.scaled_ticks_per_cycle) >> FIX_SHIFT) - 1;
-		for (i = 0; i < missed_ticks; ++i) {
-			do_timer(regs);
-		}
+	nticks = ((delta * state.scaled_ticks_per_cycle+round_ticks) >> FIX_SHIFT);
+	for (i = 0; i < nticks; ++i) {
+		do_timer(regs);
 	}
-	do_timer(regs);
 
 	/*
 	 * If we have an externally synchronized Linux clock, then update
@@ -136,7 +138,6 @@
 #endif
         void (*irq_handler)(int, void *, struct pt_regs *);
 	unsigned int year, mon, day, hour, min, sec;
-	int i;
 
 	/* The Linux interpretation of the CMOS clock register contents:
 	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
@@ -144,20 +145,23 @@
 	 * Let's hope other operating systems interpret the RTC the same way.
 	 */
 	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-			break;
-	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-			break;
-	do { /* Isn't this overkill ? UIP above should guarantee consistency */
-		sec = CMOS_READ(RTC_SECONDS);
-		min = CMOS_READ(RTC_MINUTES);
-		hour = CMOS_READ(RTC_HOURS);
-		day = CMOS_READ(RTC_DAY_OF_MONTH);
-		mon = CMOS_READ(RTC_MONTH);
-		year = CMOS_READ(RTC_YEAR);
-	} while (sec != CMOS_READ(RTC_SECONDS));
+	/* Wait for rise.... (may take up to 1 second) */
+	
+	while(!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
+	
+    /* Wait for fall.... */
+	
+	while(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+	
+    __delay(1000000);
+	  
+	sec = CMOS_READ(RTC_SECONDS);
+	min = CMOS_READ(RTC_MINUTES);
+	hour = CMOS_READ(RTC_HOURS);
+	day = CMOS_READ(RTC_DAY_OF_MONTH);
+	mon = CMOS_READ(RTC_MONTH);
+	year = CMOS_READ(RTC_YEAR);
+
 	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 	  {
 	    BCD_TO_BIN(sec);
@@ -186,7 +190,7 @@
 	}
 	state.last_time = rpcc();
 	state.scaled_ticks_per_cycle = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq;
-	state.max_cycles_per_tick = (2 * hwrpb->cycle_freq) / HZ;
+	round_ticks=(unsigned long) 1 << (FIX_SHIFT-1);
 	state.last_rtc_update = 0;
 
 #ifdef CONFIG_RTC 
diff -u --recursive --new-file v2.1.61/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.1.61/linux/drivers/block/ide-probe.c	Mon Oct 20 10:36:52 1997
+++ linux/drivers/block/ide-probe.c	Mon Nov  3 09:31:00 1997
@@ -123,11 +123,12 @@
 #endif /* CONFIG_BLK_DEV_PROMISE */
 		switch (type) {
 			case ide_floppy:
-				if (strstr (id->model, "oppy") || strstr (id->model, "poyp")) {
+				if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
+					printk("cdrom or floppy?, assuming ");
+				if (drive->media != ide_cdrom) {
 					printk ("FLOPPY");
 					break;
 				}
-				printk ("cdrom or floppy?, assuming ");
 				type = ide_cdrom;	/* Early cdrom models used zero */
 			case ide_cdrom:
 				printk ("CDROM");
diff -u --recursive --new-file v2.1.61/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.61/linux/drivers/char/lp.c	Wed Sep 24 20:05:46 1997
+++ linux/drivers/char/lp.c	Fri Oct 31 11:23:36 1997
@@ -272,9 +272,9 @@
 	return total_bytes_written;
 }
 
-static long lp_write(struct inode * inode, struct file * file,
-	const char * buf, unsigned long count)
+static ssize_t lp_write(struct file * file, const char * buf, size_t count, loff_t *ppos)
 {
+	struct inode *inode = file->f_dentry->d_inode;
 	unsigned int minor = MINOR(inode->i_rdev);
 	int retv;
 
@@ -315,9 +315,9 @@
 }
 
 /* Status readback confirming to ieee1284 */
-static long lp_read(struct inode * inode, struct file * file, 
-		   char * buf, unsigned long count)
+static ssize_t lp_read(struct file * file, char * buf, size_t count, loff_t *ppos)
 {
+	struct inode *inode = file->f_dentry->d_inode;
 	unsigned char z=0, Byte=0, status;
 	char *temp;
 	int retval;
diff -u --recursive --new-file v2.1.61/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c
--- v2.1.61/linux/drivers/isdn/avmb1/capi.c	Wed Sep 24 20:05:47 1997
+++ linux/drivers/isdn/avmb1/capi.c	Mon Nov  3 10:14:54 1997
@@ -45,12 +45,11 @@
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/skbuff.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
-#include <asm/poll.h>
-#endif
 #include <linux/capi.h>
 #include <linux/kernelcapi.h>
 
+#include <asm/poll.h>
+
 #include "compat.h"
 #include "capiutil.h"
 #include "capicmd.h"
@@ -96,29 +95,16 @@
 
 /* -------- file_operations ----------------------------------------- */
 
-#if LINUX_VERSION_CODE < 0x020100
-static int capi_lseek(struct inode *inode, struct file *file,
-		      off_t offset, int origin)
+static loff_t capi_llseek(struct file *file, loff_t offset, int origin)
 {
 	return -ESPIPE;
 }
-#else
-static long long capi_llseek(struct inode *inode, struct file *file,
-			     long long offset, int origin)
-{
-	return -ESPIPE;
-}
-#endif
 
-#if LINUX_VERSION_CODE < 0x020100
-static int capi_read(struct inode *inode, struct file *file,
-		     char *buf, int count)
-#else
-static long capi_read(struct inode *inode, struct file *file,
-		      char *buf, unsigned long count)
-#endif
+static ssize_t capi_read(struct file *file,
+		      char *buf, size_t count,
+		      loff_t *off)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
 	struct capidev *cdev;
 	struct sk_buff *skb;
 	int retval;
@@ -164,15 +150,11 @@
 	return copied;
 }
 
-#if LINUX_VERSION_CODE < 0x020100
-static int capi_write(struct inode *inode, struct file *file,
-		      const char *buf, int count)
-#else
-static long capi_write(struct inode *inode, struct file *file,
-		       const char *buf, unsigned long count)
-#endif
+static ssize_t capi_write(struct file *file,
+		       const char *buf, size_t count,
+		       loff_t *off)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
 	struct capidev *cdev;
 	struct sk_buff *skb;
 	int retval;
@@ -215,40 +197,6 @@
 	return count;
 }
 
-#if (LINUX_VERSION_CODE < 0x020117)
-static int capi_select(struct inode *inode, struct file *file,
-		       int sel_type, select_table * wait)
-{
-	unsigned int minor = MINOR(inode->i_rdev);
-	struct capidev *cdev;
-
-	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
-		return -ENODEV;
-
-	cdev = &capidevs[minor];
-
-	switch (sel_type) {
-	case SEL_IN:
-		if (!skb_queue_empty(&cdev->recv_queue))
-			return 1;
-		/* fall througth */
-	case SEL_EX:
-		/* error conditions ? */
-
-		select_wait(&cdev->recv_wait, wait);
-		return 0;
-	case SEL_OUT:
-		/* 
-		   if (!queue_full())
-		   return 1;
-		   select_wait(&cdev->send_wait, wait);
-		   return 0;
-		 */
-		return 1;
-	}
-	return 1;
-}
-#else
 static unsigned int
 capi_poll(struct file *file, poll_table * wait)
 {
@@ -266,7 +214,6 @@
 		mask |= POLLIN | POLLRDNORM;
 	return mask;
 }
-#endif
 
 static int capi_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, unsigned long arg)
@@ -480,19 +427,11 @@
 
 static struct file_operations capi_fops =
 {
-#if LINUX_VERSION_CODE < 0x020100
-	capi_lseek,
-#else
 	capi_llseek,
-#endif
 	capi_read,
 	capi_write,
 	NULL,			/* capi_readdir */
-#if (LINUX_VERSION_CODE < 0x020117)
-	capi_select,
-#else
 	capi_poll,
-#endif
 	capi_ioctl,
 	NULL,			/* capi_mmap */
 	capi_open,
diff -u --recursive --new-file v2.1.61/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c
--- v2.1.61/linux/drivers/isdn/hisax/avm_a1.c	Thu May 29 21:53:05 1997
+++ linux/drivers/isdn/hisax/avm_a1.c	Mon Nov  3 09:54:38 1997
@@ -558,7 +558,7 @@
 	u_char val, sval, stat = 0;
 	char tmp[32];
 
-	sp = (struct IsdnCardState *) irq2dev_map[intno];
+	sp = (struct IsdnCardState *) dev_id;
 
 	if (!sp) {
 		printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
@@ -798,8 +798,7 @@
 			printk(KERN_WARNING
 			       "AVM A1: IRQ(%d) getting no interrupts during init\n",
 			       sp->irq);
-			irq2dev_map[sp->irq] = NULL;
-			free_irq(sp->irq, NULL);
+			free_irq(sp->irq, sp);
 			return (0);
 		}
 	}
diff -u --recursive --new-file v2.1.61/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c
--- v2.1.61/linux/drivers/isdn/hisax/elsa.c	Thu May 29 21:53:05 1997
+++ linux/drivers/isdn/hisax/elsa.c	Mon Nov  3 09:54:38 1997
@@ -887,7 +887,7 @@
 	struct IsdnCardState *sp;
 	u_char val;
 
-	sp = (struct IsdnCardState *) irq2dev_map[intno];
+	sp = (struct IsdnCardState *) dev_id;
 
 	if (!sp) {
 		printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
@@ -1219,8 +1219,7 @@
 			       "Elsa: IRQ(%d) getting no interrupts during init %d\n",
 			       sp->irq, 4 - cnt);
 			if (cnt == 1) {
-				irq2dev_map[sp->irq] = NULL;
-				free_irq(sp->irq, NULL);
+				free_irq(sp->irq, sp);
 				return (0);
 			} else {
 				reset_elsa(sp);
diff -u --recursive --new-file v2.1.61/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- v2.1.61/linux/drivers/isdn/hisax/isdnl1.c	Thu May 29 21:53:06 1997
+++ linux/drivers/isdn/hisax/isdnl1.c	Mon Nov  3 09:54:38 1997
@@ -766,13 +766,12 @@
 	save_flags(flags);
 	cli();
 	if (request_irq(card->sp->irq, routine,
-			I4L_IRQ_FLAG, "HiSax", NULL)) {
+			I4L_IRQ_FLAG, "HiSax", card->sp)) {
 		printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
 		       card->sp->irq);
 		restore_flags(flags);
 		return (0);
 	}
-	irq2dev_map[card->sp->irq] = (void *) card->sp;
 	restore_flags(flags);
 	return (1);
 }
@@ -782,8 +781,7 @@
 {
 	struct IsdnCard *card = cards + cardnr;
 
-	irq2dev_map[card->sp->irq] = NULL;
-	free_irq(card->sp->irq, NULL);
+	free_irq(card->sp->irq, card->sp);
 }
 
 void
diff -u --recursive --new-file v2.1.61/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c
--- v2.1.61/linux/drivers/isdn/hisax/ix1_micro.c	Thu May 29 21:53:06 1997
+++ linux/drivers/isdn/hisax/ix1_micro.c	Mon Nov  3 09:54:38 1997
@@ -644,7 +644,7 @@
 	struct IsdnCardState *sp;
 	u_char val, stat = 0;
 
-	sp = (struct IsdnCardState *) irq2dev_map[intno];
+	sp = (struct IsdnCardState *) dev_id;
 
 	if (!sp) {
 		printk(KERN_WARNING "Teles: Spurious interrupt!\n");
@@ -867,8 +867,7 @@
 			printk(KERN_WARNING
 			       "ix1-Micro: IRQ(%d) getting no interrupts during init\n",
 			       sp->irq);
-			irq2dev_map[sp->irq] = NULL;
-			free_irq(sp->irq, NULL);
+			free_irq(sp->irq, sp);
 			return (0);
 		}
 	}
diff -u --recursive --new-file v2.1.61/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c
--- v2.1.61/linux/drivers/isdn/hisax/teles0.c	Thu May 29 21:53:06 1997
+++ linux/drivers/isdn/hisax/teles0.c	Mon Nov  3 09:54:38 1997
@@ -605,7 +605,7 @@
 	struct IsdnCardState *sp;
 	u_char val, stat = 0;
 
-	sp = (struct IsdnCardState *) irq2dev_map[intno];
+	sp = (struct IsdnCardState *) dev_id;
 
 	if (!sp) {
 		printk(KERN_WARNING "Teles0: Spurious interrupt!\n");
@@ -828,8 +828,7 @@
 			printk(KERN_WARNING
 			       "Teles0: IRQ(%d) getting no interrupts during init\n",
 			       sp->irq);
-			irq2dev_map[sp->irq] = NULL;
-			free_irq(sp->irq, NULL);
+			free_irq(sp->irq, sp);
 			return (0);
 		}
 	}
diff -u --recursive --new-file v2.1.61/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c
--- v2.1.61/linux/drivers/isdn/hisax/teles3.c	Thu May 29 21:53:06 1997
+++ linux/drivers/isdn/hisax/teles3.c	Mon Nov  3 09:54:38 1997
@@ -585,7 +585,7 @@
 	u_char val, stat = 0;
 	int count = 0;
 
-	sp = (struct IsdnCardState *) irq2dev_map[intno];
+	sp = (struct IsdnCardState *) dev_id;
 
 	if (!sp) {
 		printk(KERN_WARNING "Teles: Spurious interrupt!\n");
@@ -829,8 +829,7 @@
 			printk(KERN_WARNING
 			       "Teles3: IRQ(%d) getting no interrupts during init\n",
 			       sp->irq);
-			irq2dev_map[sp->irq] = NULL;
-			free_irq(sp->irq, NULL);
+			free_irq(sp->irq, sp);
 			return (0);
 		}
 	}
diff -u --recursive --new-file v2.1.61/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.1.61/linux/drivers/isdn/isdn_common.c	Tue Sep 23 16:48:47 1997
+++ linux/drivers/isdn/isdn_common.c	Mon Nov  3 09:58:23 1997
@@ -849,9 +849,9 @@
 }
 
 static RWTYPE
-isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
+isdn_read(struct file *file, char *buf, RWARG count, loff_t *off)
 {
-	uint minor = MINOR(inode->i_rdev);
+	uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
 	int len = 0;
 	ulong flags;
 	int drvidx;
@@ -869,7 +869,7 @@
 		if ((len = strlen(p)) <= count) {
 			if (copy_to_user(buf, p, len))
 				return -EFAULT;
-			file->f_pos += len;
+			*off += len;
 			return len;
 		}
 		return 0;
@@ -886,7 +886,7 @@
 		save_flags(flags);
 		cli();
 		len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1);
-		file->f_pos += len;
+		*off += len;
 		restore_flags(flags);
 		return len;
 	}
@@ -912,7 +912,7 @@
 		else
 			dev->drv[drvidx]->stavail = 0;
 		restore_flags(flags);
-		file->f_pos += len;
+		*off += len;
 		return len;
 	}
 #ifdef CONFIG_ISDN_PPP
@@ -928,9 +928,9 @@
 }
 
 static RWTYPE
-isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
+isdn_write(struct file *file, const char *buf, RWARG count, loff_t * off)
 {
-	uint minor = MINOR(inode->i_rdev);
+	uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
 	int drvidx;
 	int chidx;
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v2.1.61/linux/drivers/net/3c501.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/3c501.c	Mon Nov  3 09:29:30 1997
@@ -758,7 +758,7 @@
 	 *	Free and disable the IRQ.
 	 */
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 	outb(AX_RESET, AX_CMD);		/* Reset the chip */
 
 	MOD_DEC_USE_COUNT;
diff -u --recursive --new-file v2.1.61/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v2.1.61/linux/drivers/net/3c503.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/3c503.c	Mon Nov  3 09:29:30 1997
@@ -369,7 +369,7 @@
 static int
 el2_close(struct device *dev)
 {
-    free_irq(dev->irq, NULL);
+    free_irq(dev->irq, dev);
     dev->irq = ei_status.saved_irq;
     outb(EGACFR_IRQOFF, E33G_GACFR);	/* disable interrupts. */
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.1.61/linux/drivers/net/3c505.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/3c505.c	Mon Nov  3 09:29:30 1997
@@ -1216,7 +1216,7 @@
 	/*
 	 * release the IRQ
 	 */
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	free_dma(dev->dma);
 	free_pages((unsigned long) adapter->dma_buffer, __get_order(DMA_BUFFER_SIZE));
diff -u --recursive --new-file v2.1.61/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.1.61/linux/drivers/net/3c507.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/3c507.c	Mon Nov  3 09:29:30 1997
@@ -890,7 +890,7 @@
 	dev_3c507.priv = NULL;
 
 	/* If we don't do this, we can't re-insmod it later. */
-	free_irq(dev_3c507.irq, NULL);
+	free_irq(dev_3c507.irq, &dev_3c507);
 	release_region(dev_3c507.base_addr, EL16_IO_EXTENT);
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.61/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.1.61/linux/drivers/net/3c509.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/3c509.c	Mon Nov  3 09:29:30 1997
@@ -866,7 +866,7 @@
 		if (dev->priv != NULL) {
 			kfree_s(dev->priv,sizeof(struct el3_private));
 			dev->priv = NULL;
-			free_irq(dev->irq, NULL);
+			free_irq(dev->irq, dev);
 			release_region(dev->base_addr, EL3_IO_EXTENT);
 			unregister_netdev(dev);
 		}
diff -u --recursive --new-file v2.1.61/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c
--- v2.1.61/linux/drivers/net/ac3200.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/ac3200.c	Mon Nov  3 09:29:30 1997
@@ -173,7 +173,7 @@
 	/* Allocate dev->priv and fill in 8390 specific dev fields. */
 	if (ethdev_init(dev)) {
 		printk (" unable to allocate memory for dev->priv.\n");
-		free_irq(dev->irq, NULL);
+		free_irq(dev->irq, dev);
 		return -ENOMEM;
 	}
 
@@ -303,7 +303,7 @@
 #ifdef notyet
 	/* We should someday disable shared memory and interrupts. */
 	outb(0x00, ioaddr + 6);	/* Disable interrupts. */
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 #endif
 
 	ei_close(dev);
@@ -369,7 +369,7 @@
 			kfree(dev->priv);
 			dev->priv = NULL;
 			/* Someday free_irq may be in ac_close_card() */
-			free_irq(dev->irq, NULL);
+			free_irq(dev->irq, dev);
 			release_region(dev->base_addr, AC_IO_EXTENT);
 			unregister_netdev(dev);
 		}
diff -u --recursive --new-file v2.1.61/linux/drivers/net/apricot.c linux/drivers/net/apricot.c
--- v2.1.61/linux/drivers/net/apricot.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/apricot.c	Mon Nov  3 09:29:30 1997
@@ -547,7 +547,7 @@
 
     if (i < 4)
     {
-        free_irq(dev->irq, NULL);
+        free_irq(dev->irq, dev);
         return -EAGAIN;
     }
 
@@ -930,7 +930,7 @@
 		   dev->name, lp->scb.status, lp->scb.command);
 	    break;
     	}
-    free_irq(dev->irq, NULL);
+    free_irq(dev->irq, dev);
     remove_rx_bufs(dev);
     MOD_DEC_USE_COUNT;
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/arc-rimi.c linux/drivers/net/arc-rimi.c
--- v2.1.61/linux/drivers/net/arc-rimi.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/arc-rimi.c	Mon Nov  3 09:29:30 1997
@@ -220,7 +220,7 @@
   dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
   if (dev->priv == NULL)
     {
-      free_irq(airq,NULL);
+      free_irq(airq,dev);
       return -ENOMEM;
     }
   memset(dev->priv,0,sizeof(struct arcnet_local));
@@ -790,7 +790,7 @@
 
   if (dev->irq)
     {
-      free_irq(dev->irq,NULL);
+      free_irq(dev->irq,dev);
     }
 
   unregister_netdev(dev);
diff -u --recursive --new-file v2.1.61/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v2.1.61/linux/drivers/net/at1700.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/at1700.c	Mon Nov  3 09:29:30 1997
@@ -654,7 +654,7 @@
 	dev_at1700.priv = NULL;
 
 	/* If we don't do this, we can't re-insmod it later. */
-	free_irq(dev_at1700.irq, NULL);
+	free_irq(dev_at1700.irq, &dev_at1700);
 	release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.61/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.1.61/linux/drivers/net/atp.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/atp.c	Mon Nov  3 09:29:30 1997
@@ -727,7 +727,7 @@
 
 	/* Free the IRQ line. */
 	outb(0x00, ioaddr + PAR_CONTROL);
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	/* Leave the hardware in a reset state. */
     write_reg_high(ioaddr, CMR1, CMR1h_RESET);
diff -u --recursive --new-file v2.1.61/linux/drivers/net/auto_irq.c linux/drivers/net/auto_irq.c
--- v2.1.61/linux/drivers/net/auto_irq.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/auto_irq.c	Fri Oct 31 11:23:47 1997
@@ -46,8 +46,11 @@
 	irqs = probe_irq_on();
 }
 
+#define BUSY_LOOP_UNTIL(j) while ((long)(jiffies-(j)) < 0) ;
 int autoirq_report(int waittime)
 {
+	unsigned long delay = jiffies + waittime;
+	BUSY_LOOP_UNTIL(delay)
 	return probe_irq_off(irqs);
 }
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/com20020.c linux/drivers/net/com20020.c
--- v2.1.61/linux/drivers/net/com20020.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/com20020.c	Mon Nov  3 09:29:30 1997
@@ -354,7 +354,7 @@
   dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
   if (dev->priv == NULL)
     {
-      free_irq(airq,NULL);
+      free_irq(airq,dev);
       release_region(ioaddr,ARCNET_TOTAL_SIZE);
       return -ENOMEM;
     }
@@ -1024,7 +1024,7 @@
 
   if (dev->irq)
     {
-      free_irq(dev->irq,NULL);
+      free_irq(dev->irq,dev);
     }
 
   if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
diff -u --recursive --new-file v2.1.61/linux/drivers/net/com90io.c linux/drivers/net/com90io.c
--- v2.1.61/linux/drivers/net/com90io.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/com90io.c	Mon Nov  3 09:29:30 1997
@@ -314,7 +314,7 @@
   dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
   if (dev->priv == NULL)
     {
-      free_irq(airq,NULL);
+      free_irq(airq,dev);
       release_region(ioaddr,ARCNET_TOTAL_SIZE);
       return -ENOMEM;
     }
@@ -903,7 +903,7 @@
 
   if (dev->irq)
     {
-      free_irq(dev->irq,NULL);
+      free_irq(dev->irq,dev);
     }
 
   if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
diff -u --recursive --new-file v2.1.61/linux/drivers/net/com90xx.c linux/drivers/net/com90xx.c
--- v2.1.61/linux/drivers/net/com90xx.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/com90xx.c	Mon Nov  3 09:29:30 1997
@@ -584,7 +584,7 @@
   dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
   if (dev->priv == NULL)
     {
-      free_irq(airq,NULL);
+      free_irq(airq,dev);
       release_region(ioaddr,ARCNET_TOTAL_SIZE);
       return -ENOMEM;
     }
@@ -1201,7 +1201,7 @@
 
   if (dev->irq)
     {
-      free_irq(dev->irq,NULL);
+      free_irq(dev->irq,dev);
     }
 
   if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
diff -u --recursive --new-file v2.1.61/linux/drivers/net/cops.c linux/drivers/net/cops.c
--- v2.1.61/linux/drivers/net/cops.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/cops.c	Mon Nov  3 09:29:30 1997
@@ -1005,7 +1005,7 @@
 {
         /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 
-        free_irq(dev_cops.irq, NULL);
+        free_irq(dev_cops.irq, &dev_cops);
         release_region(dev_cops.base_addr, COPS_IO_EXTENT);
 	unregister_netdev(&dev_cops);
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.1.61/linux/drivers/net/cs89x0.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/cs89x0.c	Mon Nov  3 09:29:30 1997
@@ -655,7 +655,7 @@
                 printk("%s: EEPROM is configured for unavailable media\n", dev->name);
         release_irq:
                 writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
-                free_irq(dev->irq, NULL);
+                free_irq(dev->irq, dev);
 		return -EAGAIN;
 	}
 
@@ -918,7 +918,7 @@
 
 	dev->start = 0;
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	/* Update the statistics here. */
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v2.1.61/linux/drivers/net/de600.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/de600.c	Mon Nov  3 09:29:30 1997
@@ -366,7 +366,7 @@
 	select_prn();
 
 	if (dev->start) {
-		free_irq(DE600_IRQ, NULL);
+		free_irq(DE600_IRQ, dev);
 		dev->start = 0;
 		MOD_DEC_USE_COUNT;
 	}
diff -u --recursive --new-file v2.1.61/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v2.1.61/linux/drivers/net/de620.c	Sat Oct 25 02:44:15 1997
+++ linux/drivers/net/de620.c	Mon Nov  3 09:29:30 1997
@@ -463,7 +463,7 @@
 	/* disable recv */
 	de620_set_register(dev, W_TCR, RXOFF);
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	dev->start = 0;
 	MOD_DEC_USE_COUNT;
diff -u --recursive --new-file v2.1.61/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.1.61/linux/drivers/net/depca.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/depca.c	Mon Nov  3 09:29:30 1997
@@ -1057,7 +1057,7 @@
   /*
   ** Free the associated irq
   */
-  free_irq(dev->irq, NULL);
+  free_irq(dev->irq, dev);
 
   MOD_DEC_USE_COUNT;
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/e2100.c linux/drivers/net/e2100.c
--- v2.1.61/linux/drivers/net/e2100.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/e2100.c	Mon Nov  3 09:29:30 1997
@@ -352,7 +352,7 @@
 	if (ei_debug > 1)
 		printk("%s: Shutting down ethercard.\n", dev->name);
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 	dev->irq = ei_status.saved_irq;
 
 	/* Shut off the interrupt line and secondary interface. */
diff -u --recursive --new-file v2.1.61/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.1.61/linux/drivers/net/eepro.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/eepro.c	Mon Nov  3 09:29:30 1997
@@ -819,7 +819,7 @@
 	outb(RESET_CMD, ioaddr);
 
 	/* release the interrupt */
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	/* Update the statistics here. What statistics? */
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.1.61/linux/drivers/net/eexpress.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/eexpress.c	Mon Nov  3 09:29:30 1997
@@ -388,7 +388,7 @@
 	lp->started = 0;
 	scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
 	outb(0,ioaddr+SIGNAL_CA);
-	free_irq(irq,NULL);
+	free_irq(irq,dev);
 	outb(i586_RST,ioaddr+EEPROM_Ctrl);
 	release_region(ioaddr,16);
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/es3210.c linux/drivers/net/es3210.c
--- v2.1.61/linux/drivers/net/es3210.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/es3210.c	Mon Nov  3 09:29:30 1997
@@ -225,7 +225,7 @@
 
 		if (mem_enabled != 0x80) {
 			printk(" shared mem disabled - giving up\n");
-			free_irq(dev->irq, NULL);
+			free_irq(dev->irq, dev);
 			return -ENXIO;
 		}
 		dev->mem_start = 0xC0000 + mem_bits*0x4000;
@@ -243,7 +243,7 @@
 	/* Allocate dev->priv and fill in 8390 specific dev fields. */
 	if (ethdev_init(dev)) {
 		printk (" unable to allocate memory for dev->priv.\n");
-		free_irq(dev->irq, NULL);
+		free_irq(dev->irq, dev);
 		return -ENOMEM;
 	}
 
@@ -432,7 +432,7 @@
 		if (dev->priv != NULL) {
 			kfree(dev->priv);
 			dev->priv = NULL;
-			free_irq(dev->irq, NULL);
+			free_irq(dev->irq, dev);
 			release_region(dev->base_addr, ES_IO_EXTENT);
 			unregister_netdev(dev);
 		}
diff -u --recursive --new-file v2.1.61/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.1.61/linux/drivers/net/eth16i.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/eth16i.c	Mon Nov  3 09:29:30 1997
@@ -1225,7 +1225,7 @@
 void cleanup_module(void)
 {
 	unregister_netdev( &dev_eth16i );
-	free_irq( dev_eth16i.irq, NULL );
+	free_irq( dev_eth16i.irq, &dev_eth16i );
 	release_region( dev_eth16i.base_addr, ETH16I_IO_EXTENT );
 }
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.1.61/linux/drivers/net/ewrk3.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/ewrk3.c	Mon Nov  3 09:29:30 1997
@@ -1148,7 +1148,7 @@
   while (inb(EWRK3_RQ));
 
   if (!lp->hard_strapped) {
-    free_irq(dev->irq, NULL);
+    free_irq(dev->irq, dev);
   }
 
   MOD_DEC_USE_COUNT;
diff -u --recursive --new-file v2.1.61/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v2.1.61/linux/drivers/net/fmv18x.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/fmv18x.c	Mon Nov  3 09:29:30 1997
@@ -641,7 +641,7 @@
 	dev_fmv18x.priv = NULL;
 
 	/* If we don't do this, we can't re-insmod it later. */
-	free_irq(dev_fmv18x.irq, NULL);
+	free_irq(dev_fmv18x.irq, &dev_fmv18x);
 	release_region(dev_fmv18x.base_addr, FMV18X_IO_EXTENT);
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.61/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c
--- v2.1.61/linux/drivers/net/hp-plus.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/hp-plus.c	Mon Nov  3 09:29:30 1997
@@ -288,7 +288,7 @@
 	int ioaddr = dev->base_addr - NIC_OFFSET;
 	int option_reg = inw(ioaddr + HPP_OPTION);
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 	ei_close(dev);
 	outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
 		 ioaddr + HPP_OPTION);
diff -u --recursive --new-file v2.1.61/linux/drivers/net/hp.c linux/drivers/net/hp.c
--- v2.1.61/linux/drivers/net/hp.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/hp.c	Mon Nov  3 09:29:30 1997
@@ -180,7 +180,7 @@
 	/* Allocate dev->priv and fill in 8390 specific dev fields. */
 	if (ethdev_init(dev)) {
 		printk (" unable to get memory for dev->priv.\n");
-		free_irq(dev->irq, NULL);
+		free_irq(dev->irq, dev);
 		return -ENOMEM;
 	}
 
@@ -435,7 +435,7 @@
 			int ioaddr = dev->base_addr - NIC_OFFSET;
 			kfree(dev->priv);
 			dev->priv = NULL;
-			free_irq(dev->irq, NULL);
+			free_irq(dev->irq, dev);
 			release_region(ioaddr, HP_IO_EXTENT);
 			unregister_netdev(dev);
 		}
diff -u --recursive --new-file v2.1.61/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.1.61/linux/drivers/net/ibmtr.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/ibmtr.c	Mon Nov  3 09:29:30 1997
@@ -1577,7 +1577,7 @@
         for (i = 0; i < IBMTR_MAX_ADAPTERS; i++)
 	        if (dev_ibmtr[i]) {
 			 unregister_trdev(dev_ibmtr[i]);
-			 free_irq(dev_ibmtr[i]->irq, NULL);
+			 free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]);
 			 release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT);
 			 kfree_s(dev_ibmtr[i]->priv, sizeof(struct tok_info));
 			 kfree_s(dev_ibmtr[i], sizeof(struct device));
diff -u --recursive --new-file v2.1.61/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.1.61/linux/drivers/net/lance.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/lance.c	Mon Nov  3 09:29:30 1997
@@ -1129,7 +1129,7 @@
 	if (dev->dma != 4)
 		disable_dma(dev->dma);
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.61/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c
--- v2.1.61/linux/drivers/net/ltpc.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/ltpc.c	Mon Nov  3 09:29:30 1997
@@ -1023,9 +1023,9 @@
 
 	cli();
  
-	if (!probe3) free_irq(3,NULL);
-	if (!probe4) free_irq(4,NULL);
-	if (!probe9) free_irq(9,NULL);
+	if (!probe3) free_irq(3,dev);
+	if (!probe4) free_irq(4,dev);
+	if (!probe9) free_irq(9,dev);
 
 	sti();
  
@@ -1248,7 +1248,7 @@
 	if(debug&DEBUG_VERBOSE) printk("freeing irq\n");
 
 	if(dev_ltpc.irq) {
-		free_irq(dev_ltpc.irq,NULL);
+		free_irq(dev_ltpc.irq,&dev_ltpc);
 		dev_ltpc.irq = 0;
 	}
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v2.1.61/linux/drivers/net/ne.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/ne.c	Mon Nov  3 09:29:30 1997
@@ -440,7 +440,7 @@
     /* Allocate dev->priv and fill in 8390 specific dev fields. */
     if (ethdev_init(dev)) {
 	printk (" unable to get memory for dev->priv.\n");
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 	return -ENOMEM;
     }
 
@@ -785,7 +785,7 @@
 		if (dev->priv != NULL) {
 			kfree(dev->priv);
 			dev->priv = NULL;
-			free_irq(dev->irq, NULL);
+			free_irq(dev->irq, dev);
 			release_region(dev->base_addr, NE_IO_EXTENT);
 			unregister_netdev(dev);
 		}
diff -u --recursive --new-file v2.1.61/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.1.61/linux/drivers/net/net_init.c	Mon Jun 16 16:35:55 1997
+++ linux/drivers/net/net_init.c	Mon Nov  3 10:20:52 1997
@@ -59,7 +59,7 @@
 */
 
 /* The list of used and available "eth" slots (for "eth0", "eth1", etc.) */
-#define MAX_ETH_CARDS 16 /* same as the number if irq's in irq2dev[] */
+#define MAX_ETH_CARDS 16
 static struct device *ethdev_index[MAX_ETH_CARDS];
 
 
@@ -439,7 +439,7 @@
 
 #ifdef CONFIG_TR
 /* The list of used and available "tr" slots */
-#define MAX_TR_CARDS 16 /* same as the number of irq's in irq2dev[] */
+#define MAX_TR_CARDS 16
 static struct device *trdev_index[MAX_TR_CARDS];
 
 struct device *init_trdev(struct device *dev, int sizeof_priv)
diff -u --recursive --new-file v2.1.61/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.1.61/linux/drivers/net/ni52.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/ni52.c	Mon Nov  3 09:29:30 1997
@@ -240,7 +240,7 @@
  */
 static int ni52_close(struct device *dev)
 {
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	ni_reset586(); /* the hard way to stop the receiver */
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.1.61/linux/drivers/net/ni65.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/ni65.c	Mon Nov  3 09:29:30 1997
@@ -285,7 +285,7 @@
 	}
 	else
 	{
-		free_irq(dev->irq,NULL);
+		free_irq(dev->irq,dev);
 		dev->start = 0;
 		return -EAGAIN;
 	}
@@ -312,7 +312,7 @@
 		}
 	}
 #endif
-	free_irq(dev->irq,NULL);
+	free_irq(dev->irq,dev);
 	dev->tbusy = 1;
 	dev->start = 0;
 	MOD_DEC_USE_COUNT;
diff -u --recursive --new-file v2.1.61/linux/drivers/net/pi2.c linux/drivers/net/pi2.c
--- v2.1.61/linux/drivers/net/pi2.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/pi2.c	Mon Nov  3 09:29:30 1997
@@ -1439,7 +1439,7 @@
     if (dev->base_addr & 2) {	/* if A channel */
 	if (first_time) {
 	    if (request_dma(dev->dma,"pi2")) {
-		free_irq(dev->irq, NULL);
+		free_irq(dev->irq, dev);
 		return -EAGAIN;
 	    }
 	}
@@ -1669,7 +1669,7 @@
 
 void cleanup_module(void)
 {
-    free_irq(pi0a.irq, NULL);	/* IRQs and IO Ports are shared */
+    free_irq(pi0a.irq, &pi0a);	/* IRQs and IO Ports are shared */
     release_region(pi0a.base_addr & 0x3f0, PI_TOTAL_SIZE);
 
     kfree(pi0a.priv);
diff -u --recursive --new-file v2.1.61/linux/drivers/net/pt.c linux/drivers/net/pt.c
--- v2.1.61/linux/drivers/net/pt.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/pt.c	Mon Nov  3 09:29:30 1997
@@ -896,7 +896,7 @@
         {
             if (request_dma(dev->dma, "pt"))
             {
-                free_irq(dev->irq, NULL);
+                free_irq(dev->irq, dev);
                 return -EAGAIN;
             }
         }
@@ -1769,7 +1769,7 @@
 
 void cleanup_module(void)
 {
-	free_irq(pt0a.irq, NULL);	/* IRQs and IO Ports are shared */
+	free_irq(pt0a.irq, &pt0a);	/* IRQs and IO Ports are shared */
 	release_region(pt0a.base_addr & 0x3f0, PT_TOTAL_SIZE);
 
 	kfree(pt0a.priv);
diff -u --recursive --new-file v2.1.61/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v2.1.61/linux/drivers/net/sdla.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/sdla.c	Mon Nov  3 09:29:30 1997
@@ -1694,6 +1694,6 @@
 	if (sdla0.priv)
 		kfree(sdla0.priv);
 	if (sdla0.irq)
-		free_irq(sdla0.irq, NULL);
+		free_irq(sdla0.irq, &sdla0);
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.61/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.1.61/linux/drivers/net/seeq8005.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/seeq8005.c	Mon Nov  3 09:29:30 1997
@@ -573,7 +573,7 @@
 	/* Flush the Tx and disable Rx here. */
 	outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	/* Update the statistics here. */
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c
--- v2.1.61/linux/drivers/net/sgiseeq.c	Thu Jun 26 12:33:39 1997
+++ linux/drivers/net/sgiseeq.c	Mon Nov  3 09:29:31 1997
@@ -468,7 +468,7 @@
 	/* Shutdown the Seeq. */
 	reset_hpc3_and_seeq(sp->hregs, sregs);
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.61/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.1.61/linux/drivers/net/sk_g16.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/sk_g16.c	Mon Nov  3 09:29:31 1997
@@ -1630,7 +1630,7 @@
 
     SK_write_reg(CSR0, CSR0_STOP); /* STOP the LANCE */
 
-    free_irq(dev->irq, NULL);      /* Free IRQ */
+    free_irq(dev->irq, dev);      /* Free IRQ */
 
     return 0; /* always succeed */
     
diff -u --recursive --new-file v2.1.61/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c
--- v2.1.61/linux/drivers/net/skeleton.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/skeleton.c	Mon Nov  3 09:29:31 1997
@@ -322,7 +322,7 @@
 	 * and clean up on failure.
 	 */
 	if (request_dma(dev->dma, cardname)) {
-		free_irq(dev->irq, NULL);
+		free_irq(dev->irq, dev);
 		return -EAGAIN;
 	}
 
@@ -497,7 +497,7 @@
 	/* If not IRQ or DMA jumpered, free up the line. */
 	outw(0x00, ioaddr+0);	/* Release the physical interrupt line. */
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 	free_dma(dev->dma);
 
 	/* Update the statistics here. */
@@ -604,7 +604,7 @@
 	 * allocate them in net_probe1().
 	 */
 	/*
-	   free_irq(this_device.irq, NULL);
+	   free_irq(this_device.irq, dev);
 	   free_dma(this_device.dma);
 	*/
 	release_region(this_device.base_addr, NETCARD_IO_EXTENT);
diff -u --recursive --new-file v2.1.61/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c
--- v2.1.61/linux/drivers/net/smc-mca.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/smc-mca.c	Mon Nov  3 09:29:31 1997
@@ -289,7 +289,7 @@
 		printk("%s: Shutting down ethercard.\n", dev->name);
 
 	outb(0x00, ioaddr + 6);     /* Disable interrupts. */
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	NS8390_init(dev, 0);
 	/* We should someday disable shared memory and change to 8-bit mode
diff -u --recursive --new-file v2.1.61/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v2.1.61/linux/drivers/net/smc-ultra.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/smc-ultra.c	Mon Nov  3 09:29:31 1997
@@ -405,7 +405,7 @@
 		printk("%s: Shutting down ethercard.\n", dev->name);
 
 	outb(0x00, ioaddr + 6);		/* Disable interrupts. */
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	NS8390_init(dev, 0);
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.1.61/linux/drivers/net/smc9194.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/smc9194.c	Mon Nov  3 09:29:31 1997
@@ -1763,7 +1763,7 @@
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	unregister_netdev(&devSMC9194);
 
-	free_irq(devSMC9194.irq, NULL );
+	free_irq(devSMC9194.irq, &devSMC9194);
 	release_region(devSMC9194.base_addr, SMC_IO_EXTENT);
 
 	if (devSMC9194.priv)
diff -u --recursive --new-file v2.1.61/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.1.61/linux/drivers/net/wavelan.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/wavelan.c	Mon Nov  3 09:29:31 1997
@@ -3922,7 +3922,7 @@
     }
   else
     {
-      free_irq(dev->irq, NULL);
+      free_irq(dev->irq, dev);
 #ifdef DEBUG_CONFIG_ERRORS
       printk(KERN_INFO "%s: wavelan_open(): impossible to start the card\n",
 	     dev->name);
@@ -3970,7 +3970,7 @@
    */
   wv_82586_stop(dev);
 
-  free_irq(dev->irq, NULL);
+  free_irq(dev->irq, dev);
 
   MOD_DEC_USE_COUNT;
 
diff -u --recursive --new-file v2.1.61/linux/drivers/net/wd.c linux/drivers/net/wd.c
--- v2.1.61/linux/drivers/net/wd.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/wd.c	Mon Nov  3 09:29:31 1997
@@ -262,7 +262,7 @@
 	/* Allocate dev->priv and fill in 8390 specific dev fields. */
 	if (ethdev_init(dev)) {
 		printk (" unable to get memory for dev->priv.\n");
-		free_irq(dev->irq, NULL);
+		free_irq(dev->irq, dev);
 		return -ENOMEM;
 	}
 
@@ -499,7 +499,7 @@
 			int ioaddr = dev->base_addr - WD_NIC_OFFSET;
 			kfree(dev->priv);
 			dev->priv = NULL;
-			free_irq(dev->irq, NULL);
+			free_irq(dev->irq, dev);
 			release_region(ioaddr, WD_IO_EXTENT);
 			unregister_netdev(dev);
 		}
diff -u --recursive --new-file v2.1.61/linux/drivers/net/znet.c linux/drivers/net/znet.c
--- v2.1.61/linux/drivers/net/znet.c	Sat Oct 25 02:44:16 1997
+++ linux/drivers/net/znet.c	Mon Nov  3 09:29:31 1997
@@ -601,7 +601,7 @@
 	disable_dma(zn.rx_dma);
 	disable_dma(zn.tx_dma);
 
-	free_irq(dev->irq, NULL);
+	free_irq(dev->irq, dev);
 
 	if (znet_debug > 1)
 		printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
diff -u --recursive --new-file v2.1.61/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.61/linux/drivers/scsi/Makefile	Mon Aug 18 18:19:46 1997
+++ linux/drivers/scsi/Makefile	Sat Nov  1 12:23:52 1997
@@ -67,12 +67,8 @@
   endif
 endif
 
-ifeq ($(CONFIG_BLK_DEV_SR_VENDOR),y)
-SR_VENDOR = sr_vendor.o
-endif
-
 ifeq ($(CONFIG_BLK_DEV_SR),y)
-L_OBJS += sr.o sr_ioctl.o $(SR_VENDOR)
+L_OBJS += sr.o sr_ioctl.o sr_vendor.o
 else
   ifeq ($(CONFIG_BLK_DEV_SR),m)
   M_OBJS += sr_mod.o
@@ -461,8 +457,8 @@
 		scsicam.o scsi_proc.o
 	$(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
 
-sr_mod.o: sr.o sr_ioctl.o $(SR_VENDOR)
-	$(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o $(SR_VENDOR)
+sr_mod.o: sr.o sr_ioctl.o sr_vendor.o
+	$(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o sr_vendor.o
 
 sd_mod.o: sd.o sd_ioctl.o
 	$(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o
diff -u --recursive --new-file v2.1.61/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.1.61/linux/drivers/scsi/ppa.c	Mon Aug  4 16:25:38 1997
+++ linux/drivers/scsi/ppa.c	Sat Nov  1 12:40:30 1997
@@ -225,7 +225,7 @@
 	return;
 }
 
-static int ppa_release(struct Scsi_Host *host)
+int ppa_release(struct Scsi_Host *host)
 {
 	int host_no = host->unique_id;
 
diff -u --recursive --new-file v2.1.61/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h
--- v2.1.61/linux/drivers/scsi/ppa.h	Mon Aug  4 16:25:38 1997
+++ linux/drivers/scsi/ppa.h	Mon Nov  3 10:27:43 1997
@@ -52,7 +52,7 @@
 int ppa_reset(Scsi_Cmnd *, unsigned int);
 int ppa_proc_info(char *, char **, off_t, int, int, int);
 int ppa_biosparam(Disk *, kdev_t, int*);
-static int ppa_release(struct Scsi_Host *);
+int ppa_release(struct Scsi_Host *);
 
 #ifndef	MODULE
 #ifdef	PPA_CODE
diff -u --recursive --new-file v2.1.61/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.61/linux/drivers/scsi/scsi.c	Thu Jul 17 10:06:05 1997
+++ linux/drivers/scsi/scsi.c	Sat Nov  1 12:23:53 1997
@@ -3293,6 +3293,7 @@
      * This does any final handling that is required.
      */
     if(tpnt->finish && tpnt->nr_dev)  (*tpnt->finish)();
+    resize_dma_pool();
     MOD_INC_USE_COUNT;
     return 0;
 }
diff -u --recursive --new-file v2.1.61/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.1.61/linux/drivers/scsi/sr.c	Mon Aug 18 18:19:46 1997
+++ linux/drivers/scsi/sr.c	Sat Nov  1 12:23:53 1997
@@ -45,6 +45,8 @@
 #include <scsi/scsi_ioctl.h>   /* For the door lock/unlock commands */
 #include "constants.h"
 
+MODULE_PARM(xa_test,"i"); /* see sr_ioctl.c */
+
 #define MAX_RETRIES 3
 #define SR_TIMEOUT (30 * HZ)
 
@@ -67,12 +69,15 @@
 
 static int sr_open(struct cdrom_device_info*, int);
 void get_sectorsize(int);
+void get_capabilities(int);
 
 void requeue_sr_request (Scsi_Cmnd * SCpnt);
 static int sr_media_change(struct cdrom_device_info*, int);
 
 static void sr_release(struct cdrom_device_info *cdi)
 {
+	if (scsi_CDs[MINOR(cdi->dev)].sector_size > 2048)
+		sr_set_blocklength(MINOR(cdi->dev),2048);
 	sync_dev(cdi->dev);
 	scsi_CDs[MINOR(cdi->dev)].device->access_count--;
 	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
@@ -89,14 +94,14 @@
         sr_media_change,              /* media changed */
         sr_tray_move,                 /* tray move */
         sr_lock_door,                 /* lock door */
-        NULL,                         /* select speed */
+        sr_select_speed,              /* select speed */
         NULL,                         /* select disc */
         sr_get_last_session,          /* get last session */
         sr_get_mcn,                   /* get universal product code */
         sr_reset,                     /* hard reset */
         sr_audio_ioctl,               /* audio ioctl */
         sr_dev_ioctl,                 /* device-specific ioctl */
-        CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK |
+        CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK | CDC_SELECT_SPEED |
         CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO,
         0
 };
@@ -139,10 +144,9 @@
         /* If the disk changed, the capacity will now be different,
          * so we force a re-read of this information */
         if (retval) {
-#ifdef CONFIG_BLK_DEV_SR_VENDOR
+		/* check multisession offset etc */
                 sr_cd_check(cdi);
-#endif
-
+		
                  /* 
                   * If the disk changed, the capacity will now be different,
                   * so we force a re-read of this information 
@@ -311,7 +315,8 @@
 		}
 
 		if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
-			printk("CD-ROM error: ");
+			printk("sr%d: CD-ROM error: ",
+                               DEVICE_NR(SCpnt->request.rq_dev));
 			print_sense("sr", SCpnt);
 			printk("command was: ");
 			print_command(SCpnt->cmnd);
@@ -329,7 +334,8 @@
 		}
 
 		if (SCpnt->sense_buffer[2] == NOT_READY) {
-			printk(KERN_INFO "CD-ROM not ready.  Make sure you have a disc in the drive.\n");
+			printk(KERN_INFO "sr%d: CD-ROM not ready.  Make sure you have a disc in the drive.\n",
+                               DEVICE_NR(SCpnt->request.rq_dev));
 			SCpnt = end_scsi_request(SCpnt, 0, this_count);
 			requeue_sr_request(SCpnt); /* Do next request */
 			return;
@@ -358,7 +364,7 @@
 		    requeue_sr_request(SCpnt);
 		    return;
 		}
-    }
+        }
 
 	/* We only get this far if we have an error we have not recognized */
 	if(result) {
@@ -443,6 +449,17 @@
  	    SDev->was_reset = 0;
 	}
 
+	/* we do lazy blocksize switching (when reading XA sectors,
+	 * see CDROMREADMODE2 ioctl) */
+	if (scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].sector_size > 2048) {
+	    if (!in_interrupt())
+		sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev),2048);
+#if 1
+            else
+                printk("sr: can't switch blocksize: in interrupt\n");
+#endif
+	}
+
 	if (flag++ == 0)
 	    SCpnt = allocate_device(&CURRENT,
 				    scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
@@ -649,7 +666,7 @@
 		     * ensure that all scsi operations are able to do at least a non-scatter/gather
 		     * operation */
 		    if(sgpnt[count].address == NULL){ /* Out of dma memory */
-			printk("Warning: Running low on SCSI DMA buffers");
+			printk("Warning: Running low on SCSI DMA buffers\n");
 			/* Try switching back to a non scatter-gather operation. */
 			while(--count >= 0){
 			    if(sgpnt[count].alt_address)
@@ -805,17 +822,7 @@
     SDp->scsi_request_fn = do_sr_request;
     scsi_CDs[i].device = SDp;
 
-    scsi_CDs[i].cdi.ops        = &sr_dops;
-    scsi_CDs[i].cdi.handle     = &scsi_CDs[i];
-    scsi_CDs[i].cdi.dev        = MKDEV(MAJOR_NR,i);
-    scsi_CDs[i].cdi.mask       = 0;
-    scsi_CDs[i].cdi.speed      = 1;
-    scsi_CDs[i].cdi.capacity   = 1;
-    register_cdrom(&scsi_CDs[i].cdi, "sr");
-
-#ifdef CONFIG_BLK_DEV_SR_VENDOR
     sr_vendor_init(i);
-#endif
 
     sr_template.nr_dev++;
     if(sr_template.nr_dev > sr_template.dev_max)
@@ -902,7 +909,7 @@
 		case 512:
 			break;
 		default:
-			printk ("scd%d : unsupported sector size %d.\n",
+			printk ("sr%d: unsupported sector size %d.\n",
 				i, scsi_CDs[i].sector_size);
 			scsi_CDs[i].capacity = 0;
 			scsi_CDs[i].needs_sector_size = 1;
@@ -919,6 +926,58 @@
     scsi_free(buffer, 512);
 }
 
+void get_capabilities(int i){
+    unsigned char cmd[6];
+    unsigned char *buffer;
+    int           rc,n;
+
+    static char *loadmech[] = {
+        "caddy",
+        "tray",
+        "pop-up",
+        "",
+        "changer",
+        "changer",
+        "",
+        ""
+    };          
+
+    buffer = (unsigned char *) scsi_malloc(512);
+    cmd[0] = MODE_SENSE;
+    cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+    cmd[2] = 0x2a;
+    cmd[4] = 128;
+    cmd[3] = cmd[5] = 0;
+    rc = sr_do_ioctl(i, cmd, buffer, 128, 1);
+    
+    if (-EINVAL == rc) {
+        /* failed, drive has'nt this mode page */
+        scsi_CDs[i].cdi.speed      = 1;
+        scsi_CDs[i].cdi.capacity   = 1;
+        /* disable speed select, drive probably can't do this either */
+        scsi_CDs[i].cdi.mask      |= CDC_SELECT_SPEED;
+    } else {
+        n = buffer[3]+4;
+        scsi_CDs[i].cdi.speed    = ((buffer[n+8] << 8) + buffer[n+9])/176;
+        scsi_CDs[i].cdi.capacity = 1;
+      	scsi_CDs[i].readcd_known = 1;
+        scsi_CDs[i].readcd_cdda  = buffer[n+5] & 0x01;
+        /* print some capability bits */
+        printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n",i,
+               ((buffer[n+14] << 8) + buffer[n+15])/176,
+               scsi_CDs[i].cdi.speed,
+               buffer[n+3]&0x01 ? "writer " : "",   /* CD Writer */
+               buffer[n+2]&0x02 ? "cd/rw " : "",    /* can read rewriteable */
+               buffer[n+4]&0x20 ? "xa/form2 " : "", /* can read xa/from2 */
+               buffer[n+5]&0x01 ? "cdda " : "",     /* can read audio data */
+               loadmech[buffer[n+6]>>5]);
+	if ((buffer[n+6] >> 5) == 0)
+		/* caddy drives can't close tray... */
+        	scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY;
+    }
+    scsi_free(buffer, 512);
+}
+
 static int sr_registered = 0;
 
 static int sr_init()
@@ -984,7 +1043,16 @@
 	scsi_CDs[i].use = 1;
 	scsi_CDs[i].ten = 1;
 	scsi_CDs[i].remap = 1;
+      	scsi_CDs[i].readcd_known = 0;
+      	scsi_CDs[i].readcd_cdda  = 0;
 	sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
+
+	scsi_CDs[i].cdi.ops        = &sr_dops;
+	scsi_CDs[i].cdi.handle     = &scsi_CDs[i];
+	scsi_CDs[i].cdi.dev        = MKDEV(MAJOR_NR,i);
+	scsi_CDs[i].cdi.mask       = 0;
+	get_capabilities(i);
+	register_cdrom(&scsi_CDs[i].cdi, "sr");
     }
 
 
diff -u --recursive --new-file v2.1.61/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- v2.1.61/linux/drivers/scsi/sr.h	Mon Apr 14 16:28:16 1997
+++ linux/drivers/scsi/sr.h	Mon Nov  3 09:49:42 1997
@@ -17,8 +17,6 @@
 #ifndef _SR_H
 #define _SR_H
 
-#include <linux/config.h>
-
 #include "scsi.h"
 
 typedef struct
@@ -34,13 +32,15 @@
 	unsigned 	ten:1;			/* support ten byte commands		*/
 	unsigned 	remap:1;		/* support remapping			*/
 	unsigned 	use:1;			/* is this device still supportable	*/
-	unsigned        xa_flag:1;              /* CD has XA sectors */
+        unsigned	xa_flag:1;              /* CD has XA sectors ? */
+	unsigned 	readcd_known:1;		/* drive supports READ_CD (0xbe) */
+	unsigned 	readcd_cdda:1;		/* reading audio data using READ_CD */
 	struct cdrom_device_info cdi;
 	} Scsi_CD;
 	
 extern Scsi_CD * scsi_CDs;
 
-int sr_do_ioctl(int, unsigned char*, void*, unsigned);
+int sr_do_ioctl(int, unsigned char*, void*, unsigned, int);
 
 int sr_lock_door(struct cdrom_device_info*, int);
 int sr_tray_move(struct cdrom_device_info*, int);
@@ -49,15 +49,16 @@
 int sr_get_last_session(struct cdrom_device_info*, struct cdrom_multisession*);
 int sr_get_mcn(struct cdrom_device_info*, struct cdrom_mcn*);
 int sr_reset(struct cdrom_device_info*);
+int sr_select_speed(struct cdrom_device_info *cdi, int speed);
 int sr_audio_ioctl(struct cdrom_device_info*, unsigned int, void*);
 int sr_dev_ioctl(struct cdrom_device_info*, unsigned int, unsigned long);
 
-/* vendor-specific */
-#ifdef CONFIG_BLK_DEV_SR_VENDOR
-void sr_vendor_init(int minor);
-int sr_cd_check(struct cdrom_device_info*);
 int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest);
+int sr_is_xa(int minor);
 
-#endif
+/* sr_vendor.c */
+void sr_vendor_init(int minor);
+int sr_cd_check(struct cdrom_device_info*);
+int sr_set_blocklength(int minor, int blocklength);
 
 #endif
diff -u --recursive --new-file v2.1.61/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.1.61/linux/drivers/scsi/sr_ioctl.c	Mon Jul  7 08:24:28 1997
+++ linux/drivers/scsi/sr_ioctl.c	Mon Nov  3 09:49:55 1997
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -16,6 +15,17 @@
 #include <linux/ucdrom.h>
 #include "sr.h"
 
+#if 0
+# define DEBUG
+#endif
+
+/* for now we borrow the "operation not supported" from the network folks */
+#define EDRIVE_CANT_DO_THIS  EOPNOTSUPP
+
+/* The sr_is_xa() seems to trigger firmware bugs with some drives :-(
+ * It is off by default and can be turned on with this module parameter */
+static int xa_test = 0;
+
 extern void get_sectorsize(int);
 
 #define IOCTL_RETRIES 3
@@ -39,12 +49,14 @@
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
 
-int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength)
+int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength, int quiet)
 {
     Scsi_Cmnd * SCpnt;
-    int result;
+    int result, err = 0, retries = 0;
 
     SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
+
+retry:
     {
 	struct semaphore sem = MUTEX_LOCKED;
 	SCpnt->request.sem = &sem;
@@ -61,28 +73,79 @@
 	switch(SCpnt->sense_buffer[2] & 0xf) {
 	case UNIT_ATTENTION:
 	    scsi_CDs[target].device->changed = 1;
-	    printk("Disc change detected.\n");
+	    printk(KERN_INFO "sr%d: disc change detected.\n", target);
+	    if (retries++ < 10)
+		goto retry;
+	    err = -ENOMEDIUM;
 	    break;
 	case NOT_READY: /* This happens if there is no disc in drive */
-	    printk(KERN_INFO "CDROM not ready.  Make sure there is a disc in the drive.\n");
+            if (SCpnt->sense_buffer[12] == 0x04 &&
+                SCpnt->sense_buffer[13] == 0x01) {
+                /* sense: Logical unit is in process of becoming ready */
+                if (!quiet)
+                    printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
+		if (retries++ < 10) {
+		    /* sleep 2 sec and try again */
+                    current->state = TASK_INTERRUPTIBLE;
+                    current->timeout = jiffies + 200;
+                    schedule ();
+                    goto retry;
+		} else {
+		    /* 20 secs are enouth? */
+		    err = -ENOMEDIUM;
+		    break;
+		}
+            }
+            printk(KERN_INFO "sr%d: CDROM not ready.  Make sure there is a disc in the drive.\n",target);
+#ifdef DEBUG
+            print_sense("sr", SCpnt);
+#endif
+            err = -ENOMEDIUM;
 	    break;
 	case ILLEGAL_REQUEST:
-	    printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n");
+            if (!quiet)
+                printk("sr%d: CDROM (ioctl) reports ILLEGAL REQUEST.\n",
+                       target);
+            if (SCpnt->sense_buffer[12] == 0x20 &&
+                SCpnt->sense_buffer[13] == 0x00) {
+                /* sense: Invalid command operation code */
+                err = -EDRIVE_CANT_DO_THIS;
+            } else {
+                err = -EINVAL;
+            }
+#ifdef DEBUG
+	    print_command(sr_cmd);
+            print_sense("sr", SCpnt);
+#endif
 	    break;
 	default:
+	    printk("sr%d: CDROM (ioctl) error, command: ", target);
+	    print_command(sr_cmd);
 	    print_sense("sr", SCpnt);
+            err = -EIO;
 	};
     
     result = SCpnt->result;
     SCpnt->request.rq_status = RQ_INACTIVE; /* Deallocate */
+    /* Wake up a process waiting for device */
     wake_up(&SCpnt->device->device_wait);
-    /* Wake up a process waiting for device*/
-    return result;
+    
+    return err;
 }
 
 /* ---------------------------------------------------------------------- */
 /* interface to cdrom.c                                                   */
 
+static int test_unit_ready(int minor)
+{
+	u_char  sr_cmd[10];
+
+        sr_cmd[0] = TEST_UNIT_READY;
+        sr_cmd[1] = ((scsi_CDs[minor].device -> lun) << 5);
+        sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
+        return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1);
+}
+
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
 {
         u_char  sr_cmd[10];
@@ -92,7 +155,7 @@
         sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
         sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */;
 	
-        return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255);
+        return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0);
 }
 
 int sr_lock_door(struct cdrom_device_info *cdi, int lock)
@@ -109,51 +172,39 @@
                 return -EINVAL;
         }
 
-        if (!scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
-                        SCSI_IOCTL_TEST_UNIT_READY,0))
-                return CDS_DISC_OK;
-
-#if 1
-	/* Tell tray is open if the drive is not ready.  Seems there is
-	 * no way to check whenever the tray is really open, but this way
-	 * we get auto-close-on-open work. And it seems to have no ill
-         * effects with caddy drives... */
+        if (0 == test_unit_ready(MINOR(cdi->dev)))
+            return CDS_DISC_OK;
+
         return CDS_TRAY_OPEN;
-#else
-        return CDS_NO_DISC;
-#endif
 }
 
 int sr_disk_status(struct cdrom_device_info *cdi)
 {
 	struct cdrom_tochdr    toc_h;
 	struct cdrom_tocentry  toc_e;
-        int                    i;
+        int                    i,rc,have_datatracks = 0;
 
-        if (scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,SCSI_IOCTL_TEST_UNIT_READY,0))
-                return CDS_NO_DISC;
-
-        /* if the xa-bit is on, we tell it is XA... */
-        if (scsi_CDs[MINOR(cdi->dev)].xa_flag)
-                return CDS_XA_2_1;
+        /* look for data tracks */
+        if (0 != (rc = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)))
+                return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
         
-        /* ...else we look for data tracks */
-        if (sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h))
-                return CDS_NO_INFO;
         for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
                 toc_e.cdte_track  = i;
                 toc_e.cdte_format = CDROM_LBA;
                 if (sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &toc_e))
                         return CDS_NO_INFO;
-                if (toc_e.cdte_ctrl & CDROM_DATA_TRACK)
-                        return CDS_DATA_1;
-#if 0
-                if (i == toc_h.cdth_trk0 && toc_e.cdte_addr.lba > 100)
-                        /* guess: looks like a "hidden track" CD */
-                        return CDS_DATA_1;
-#endif
+                if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) {
+                        have_datatracks = 1;
+                        break;
+                }
         }
-        return CDS_AUDIO;
+        if (!have_datatracks)
+            return CDS_AUDIO;
+
+        if (scsi_CDs[MINOR(cdi->dev)].xa_flag)
+            return CDS_XA_2_1;
+        else
+            return CDS_DATA_1;
 }
 
 int sr_get_last_session(struct cdrom_device_info *cdi,
@@ -161,7 +212,7 @@
 {
         ms_info->addr.lba=scsi_CDs[MINOR(cdi->dev)].ms_offset;
         ms_info->xa_flag=scsi_CDs[MINOR(cdi->dev)].xa_flag ||
-            scsi_CDs[MINOR(cdi->dev)].ms_offset > 0;
+            (scsi_CDs[MINOR(cdi->dev)].ms_offset > 0);
 
 	return 0;
 }
@@ -185,7 +236,7 @@
 	buffer = (unsigned char*) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24);
+	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
 	
 	memcpy (mcn->medium_catalog_number, buffer + 9, 13);
         mcn->medium_catalog_number[13] = 0;
@@ -201,6 +252,26 @@
 	return 0;        
 }
 
+int sr_select_speed(struct cdrom_device_info *cdi, int speed)
+{
+        u_char  sr_cmd[12];
+
+        if (speed == 0)
+            speed = 0xffff; /* set to max */
+        else
+            speed *= 177;   /* Nx to kbyte/s */
+        
+	memset(sr_cmd,0,12);
+	sr_cmd[0] = 0xbb; /* SET CD SPEED */
+	sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5;
+	sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */
+	sr_cmd[3] =  speed       & 0xff; /* LSB */
+
+        if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0))
+            return -EIO;
+	return 0;
+}
+
 /* ----------------------------------------------------------------------- */
 /* this is called by the generic cdrom driver. arg is a _kernel_ pointer,  */
 /* becauce the generic cdrom driver does the user access stuff for us.     */
@@ -224,7 +295,7 @@
 	sr_cmd[8] = 0;
 	sr_cmd[9] = 0;
 	
-	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
 	
     case CDROMRESUME:
@@ -236,7 +307,7 @@
 	sr_cmd[8] = 1;
 	sr_cmd[9] = 0;
 	
-	result = sr_do_ioctl(target, sr_cmd, NULL, 255);	
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
 	
     case CDROMPLAYMSF:
@@ -254,7 +325,7 @@
 	sr_cmd[8] = msf->cdmsf_frame1;
 	sr_cmd[9] = 0;
 	
-	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
     }
 
@@ -273,7 +344,7 @@
 	sr_cmd[8] = blk->len;
 	sr_cmd[9] = 0;
 	
-	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
     }
 		
@@ -292,7 +363,7 @@
 	sr_cmd[8] = ti->cdti_ind1;
 	sr_cmd[9] = 0;
 	
-	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
     }
 	
@@ -312,7 +383,7 @@
 	buffer = (unsigned char *) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	result = sr_do_ioctl(target, sr_cmd, buffer, 12);
+	result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0);
 	
 	tochdr->cdth_trk0 = buffer[2];
 	tochdr->cdth_trk1 = buffer[3];
@@ -338,7 +409,7 @@
 	buffer = (unsigned char *) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	result = sr_do_ioctl (target, sr_cmd, buffer, 12);
+	result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0);
 	
         tocentry->cdte_ctrl = buffer[5] & 0xf;	
         tocentry->cdte_adr = buffer[5] >> 4;
@@ -361,7 +432,7 @@
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
 	sr_cmd[4] = 0;
 	
-	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
 	
     case CDROMSTART:
@@ -370,7 +441,7 @@
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
 	sr_cmd[4] = 1;
 	
-	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
         break;
 	
     case CDROMVOLCTRL:
@@ -390,7 +461,7 @@
 	buffer = (unsigned char *) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28))) {
+	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
 	    printk ("Hosed while obtaining audio mode page\n");
 	    scsi_free(buffer, 512);
             break;
@@ -410,7 +481,7 @@
             break;
 	};
 
-	if ((result = sr_do_ioctl (target, sr_cmd, mask, 28))) {
+	if ((result = sr_do_ioctl (target, sr_cmd, mask, 28, 0))) {
 	    printk ("Hosed while obtaining mask for audio mode page\n");
 	    scsi_free(buffer, 512);
 	    scsi_free(mask, 512);
@@ -431,7 +502,7 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
-	result = sr_do_ioctl (target, sr_cmd, buffer, 28);
+	result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0);
 	scsi_free(buffer, 512);
 	scsi_free(mask, 512);
         break;
@@ -454,7 +525,7 @@
 	buffer = (unsigned char *) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28))) {
+	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
 	    printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n");
 	    scsi_free(buffer, 512);
             break;
@@ -487,7 +558,7 @@
 	buffer = (unsigned char*) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	result = sr_do_ioctl(target, sr_cmd, buffer, 16);
+	result = sr_do_ioctl(target, sr_cmd, buffer, 16, 0);
 	
 	subchnl->cdsc_audiostatus = buffer[1];
 	subchnl->cdsc_format = CDROM_MSF;
@@ -516,7 +587,120 @@
     
     return result;
 }
-	
+
+/* -----------------------------------------------------------------------
+ * a function to read all sorts of funny cdrom sectors using the READ_CD
+ * scsi-3 mmc command
+ *
+ * lba:     linear block address
+ * format:  0 = data (anything)
+ *          1 = audio
+ *          2 = data (mode 1)
+ *          3 = data (mode 2)
+ *          4 = data (mode 2 form1)
+ *          5 = data (mode 2 form2)
+ * blksize: 2048 | 2336 | 2340 | 2352
+ */
+
+int
+sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
+{
+    unsigned char  cmd[12];
+
+#ifdef DEBUG
+    printk("sr%d: sr_read_cd lba=%d format=%d blksize=%d\n",
+           minor,lba,format,blksize);
+#endif
+
+    memset(cmd,0,12);
+    cmd[0] = 0xbe /* READ_CD */;
+    cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2);
+    cmd[2] = (unsigned char)(lba >> 24) & 0xff;
+    cmd[3] = (unsigned char)(lba >> 16) & 0xff;
+    cmd[4] = (unsigned char)(lba >>  8) & 0xff;
+    cmd[5] = (unsigned char) lba        & 0xff;
+    cmd[8] = 1;
+    switch (blksize) {
+    case 2336: cmd[9] = 0x58; break;
+    case 2340: cmd[9] = 0x78; break;
+    case 2352: cmd[9] = 0xf8; break;
+    default:   cmd[9] = 0x10; break;
+    }
+    return sr_do_ioctl(minor, cmd, dest, blksize, 0);
+}
+
+/*
+ * read sectors with blocksizes other than 2048
+ */
+
+int
+sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
+{
+    unsigned char   cmd[12];    /* the scsi-command */
+    int             rc;
+
+    /* we try the READ CD command first... */
+    if (scsi_CDs[minor].readcd_known) {
+        rc = sr_read_cd(minor, dest, lba, 0, blksize);
+        if (-EDRIVE_CANT_DO_THIS != rc)
+            return rc;
+        scsi_CDs[minor].readcd_known = 0;
+        printk("CDROM does'nt support READ CD (0xbe) command\n");
+        /* fall & retry the other way */
+    }
+
+    /* ... if this fails, we switch the blocksize using MODE SELECT */
+    if (blksize != scsi_CDs[minor].sector_size)
+        if (0 != (rc = sr_set_blocklength(minor, blksize)))
+            return rc;
+
+#ifdef DEBUG
+    printk("sr%d: sr_read_sector lba=%d blksize=%d\n",minor,lba,blksize);
+#endif
+    
+    memset(cmd,0,12);
+    cmd[0] = READ_10;
+    cmd[1] = (scsi_CDs[minor].device->lun << 5);
+    cmd[2] = (unsigned char)(lba >> 24) & 0xff;
+    cmd[3] = (unsigned char)(lba >> 16) & 0xff;
+    cmd[4] = (unsigned char)(lba >>  8) & 0xff;
+    cmd[5] = (unsigned char) lba        & 0xff;
+    cmd[8] = 1;
+    rc = sr_do_ioctl(minor, cmd, dest, blksize, 0);
+    
+    return rc;
+}
+
+/*
+ * read a sector in raw mode to check the sector format
+ * ret: 1 == mode2 (XA), 0 == mode1, <0 == error 
+ */
+
+int
+sr_is_xa(int minor)
+{
+    unsigned char *raw_sector;
+    int is_xa;
+    
+    if (!xa_test)
+        return 0;
+    
+    raw_sector = (unsigned char *) scsi_malloc(2048+512);
+    if (!raw_sector) return -ENOMEM;
+    if (0 == sr_read_sector(minor,scsi_CDs[minor].ms_offset+16,
+                            CD_FRAMESIZE_RAW1,raw_sector)) {
+        is_xa = (raw_sector[3] == 0x02) ? 1 : 0;
+    } else {
+        /* read a raw sector failed for some reason. */
+        is_xa = -1;
+    }
+    scsi_free(raw_sector, 2048+512);
+#ifdef DEBUG
+    printk("sr%d: sr_is_xa: %d\n",minor,is_xa);
+#endif
+    return is_xa;
+}
+
 int sr_dev_ioctl(struct cdrom_device_info *cdi,
                  unsigned int cmd, unsigned long arg)
 {
@@ -525,33 +709,31 @@
     target = MINOR(cdi->dev);
     
     switch (cmd) {
-    /* these are compatible with the ide-cd driver */
-    case CDROMREADRAW:
     case CDROMREADMODE1:
     case CDROMREADMODE2:
-
-#if CONFIG_BLK_DEV_SR_VENDOR 
+    case CDROMREADRAW:
     {
 	unsigned char      *raw;
         struct cdrom_msf   msf;
-        int                blocksize, lba, rc;
+        int                lba, rc;
+	int                blocksize = 2048;
 
-        if (cmd == CDROMREADMODE1)
-                blocksize = CD_FRAMESIZE;       /* 2048 */
-        else if (cmd == CDROMREADMODE2)
-                blocksize = CD_FRAMESIZE_RAW0;  /* 2336 */
-        else
-		/* some SCSI drives do not allow this one */
-                blocksize = CD_FRAMESIZE_RAW;   /* 2352 */
+        switch (cmd) {
+        case CDROMREADMODE2: blocksize = CD_FRAMESIZE_RAW0; break; /* 2336 */
+        case CDROMREADRAW:   blocksize = CD_FRAMESIZE_RAW;  break; /* 2352 */
+        }
 
 	if (copy_from_user(&msf,(void*)arg,sizeof(msf)))
 		return -EFAULT;
 	if (!(raw = scsi_malloc(2048+512)))
-        	return -ENOMEM;
+                return -ENOMEM;
 
 	lba = (((msf.cdmsf_min0 * CD_SECS) + msf.cdmsf_sec0)
 			* CD_FRAMES + msf.cdmsf_frame0) - CD_BLOCK_OFFSET;
-	rc = sr_read_sector(target, lba, blocksize, raw);
+        if (lba < 0 || lba >= scsi_CDs[target].capacity)
+            return -EINVAL;
+
+        rc = sr_read_sector(target, lba, blocksize, raw);
 	if (!rc)
 		if (copy_to_user((void*)arg, raw, blocksize))
 			rc = -EFAULT;
@@ -559,11 +741,44 @@
 	scsi_free(raw,2048+512);
 	return rc;
     }
-#else
-	return -EINVAL;
-#endif
+    case CDROMREADAUDIO:
+    {
+	unsigned char      *raw;
+        int                lba, rc=0;
+        struct cdrom_read_audio ra;
 
-	
+        if (!scsi_CDs[target].readcd_known || !scsi_CDs[target].readcd_cdda)
+            return -EINVAL;  /* -EDRIVE_DOES_NOT_SUPPORT_THIS ? */
+        
+	if (copy_from_user(&ra,(void*)arg,sizeof(ra)))
+            return -EFAULT;
+        
+        if (ra.addr_format == CDROM_LBA)
+            lba = ra.addr.lba;
+        else
+            lba = (((ra.addr.msf.minute * CD_SECS) + ra.addr.msf.second)
+                   * CD_FRAMES + ra.addr.msf.frame) - CD_BLOCK_OFFSET;
+
+        if (lba < 0 || lba >= scsi_CDs[target].capacity)
+            return -EINVAL;
+	if (!(raw = scsi_malloc(2048+512)))
+            return -ENOMEM;
+
+        while (ra.nframes > 0) {
+            rc = sr_read_cd(target, raw, lba, 1, CD_FRAMESIZE_RAW);
+            if (!rc)
+		if (copy_to_user(ra.buf, raw, CD_FRAMESIZE_RAW))
+                    rc = -EFAULT;
+            if (rc)
+                break;
+
+            ra.buf     += CD_FRAMESIZE_RAW;
+            ra.nframes -= 1;
+            lba++;
+        }
+	scsi_free(raw,2048+512);
+        return rc;
+    }
     case BLKRAGET:
 	if (!arg)
 		return -EINVAL;
diff -u --recursive --new-file v2.1.61/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- v2.1.61/linux/drivers/scsi/sr_vendor.c	Tue Sep 23 16:48:48 1997
+++ linux/drivers/scsi/sr_vendor.c	Mon Nov  3 09:50:20 1997
@@ -6,6 +6,12 @@
  * the like) are to new to be included into the SCSI-II standard (to
  * be exact: there is'nt anything in my draft copy).
  *
+ * Aug 1997: Ha! Got a SCSI-3 cdrom spec across my fingers. SCSI-3 does
+ *           multisession using the READ TOC command (like SONY).
+ *
+ *           Rearranged stuff here: SCSI-3 is included allways, support
+ *           for NEC/TOSHIBA/HP commands is optional.
+ *
  *   Gerd Knorr <kraxel@cs.tu-berlin.de> 
  *
  * --------------------------------------------------------------------------
@@ -20,14 +26,15 @@
  *   - SONY:	Detection and support of multisession CD's.
  *              added by Thomas Quinot <thomas@cuivre.freenix.fr>
  *
- *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS:
- *		Known to work with SONY code.
+ *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS: known to
+ *              work with SONY (SCSI3 now)  code.
  *
  *   - HP:	Much like SONY, but a little different... (Thomas)
  *              HP-Writers only ??? Maybe other CD-Writers work with this too ?
  *		HP 6020 writers now supported.
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 
@@ -40,27 +47,33 @@
 #include <linux/ucdrom.h>
 #include "sr.h"
 
+#if 0
+# define DEBUG
+#endif
+
 /* here are some constants to sort the vendors into groups */
 
-#define VENDOR_CAN_NOT_HANDLE  1   /* don't know how to handle */
+#define VENDOR_SCSI3           1   /* default: scsi-3 mmc */
+
 #define VENDOR_NEC             2
 #define VENDOR_TOSHIBA         3
-#define VENDOR_SONY_LIKE       4   /* much drives are Sony compatible */
-#define VENDOR_HP_4020         5   /* HP 4xxx writers, others too ?? */
-#define VENDOR_HP_6020         6   /* HP 6020 writers */
+#define VENDOR_HP_4020         4   /* HP 4xxx writers, others too ?? */
+#define VENDOR_HP_6020         5   /* HP 6020 writers */
 
 #define VENDOR_ID (scsi_CDs[minor].vendor)
 
-#if 0
-#define DEBUG
-#endif
-
 void
 sr_vendor_init(int minor)
 {
+#ifndef CONFIG_BLK_DEV_SR_VENDOR
+	VENDOR_ID = VENDOR_SCSI3;
+#else
 	char *vendor = scsi_CDs[minor].device->vendor;
 	char *model  = scsi_CDs[minor].device->model;
-		
+
+	/* default */
+	VENDOR_ID = VENDOR_SCSI3;
+
 	if ((!strncmp(vendor,"HP",2) || !strncmp(vendor,"PHILIPS",7)) &&
 	    scsi_CDs[minor].device->type == TYPE_WORM) {
 		if (!strncmp(model,"CD-Writer 6020",14))
@@ -80,29 +93,33 @@
 	} else if (!strncmp (vendor, "TOSHIBA", 7)) {
 		VENDOR_ID = VENDOR_TOSHIBA;
 		
-	} else {
-		/* most drives can handled like Sony ones, so we take
-		 * it as default */
-		VENDOR_ID = VENDOR_SONY_LIKE;
-#ifdef DEBUG
-		printk(KERN_DEBUG
-		       "sr: using \"Sony group\" multisession code\n");
-#endif
 	}
+#endif
 }
 
 
 /* small handy function for switching block length using MODE SELECT,
  * used by sr_read_sector() */
 
-static int
-set_density_and_blocklength(int minor, unsigned char *buffer,
-			    int density, int blocklength)
+int
+sr_set_blocklength(int minor, int blocklength)
 {
+	unsigned char           *buffer;    /* the buffer for the ioctl */
 	unsigned char		cmd[12];    /* the scsi-command */
 	struct ccs_modesel_head	*modesel;
-	int			rc;
+	int			rc,density = 0;
+
+#ifdef CONFIG_BLK_DEV_SR_VENDOR
+	if (VENDOR_ID == VENDOR_TOSHIBA)
+		density = (blocklength > 2048) ? 0x81 : 0x83;
+#endif
+
+	buffer = (unsigned char *) scsi_malloc(512);
+	if (!buffer) return -ENOMEM;
 
+#ifdef DEBUG
+	printk("sr%d: MODE SELECT 0x%x/%d\n",minor,density,blocklength);
+#endif
 	memset(cmd,0,12);
 	cmd[0] = MODE_SELECT;
 	cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4);
@@ -113,53 +130,17 @@
 	modesel->density           = density;
 	modesel->block_length_med  = (blocklength >> 8 ) & 0xff;
 	modesel->block_length_lo   =  blocklength        & 0xff;
-	rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel));
+	if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0)))
+		scsi_CDs[minor].sector_size = blocklength;
 #ifdef DEBUG
-	if (rc)
-		printk("sr: switching blocklength to %d bytes failed\n",
-		       blocklength);
+	else
+		printk("sr%d: switching blocklength to %d bytes failed\n",
+		       minor,blocklength);
 #endif
-	return rc;
-}
-
-
-/* read a sector with other than 2048 bytes length 
- * dest is assumed to be allocated with scsi_malloc
- *
- * XXX maybe we have to do some locking here.
- */
-
-int
-sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
-{
-	unsigned char   *buffer;    /* the buffer for the ioctl */
-	unsigned char   cmd[12];    /* the scsi-command */
-	int             rc, density;
-
-	density = (VENDOR_ID == VENDOR_TOSHIBA) ? 0x83 : 0;
-
-	buffer = (unsigned char *) scsi_malloc(512);
-	if (!buffer) return -ENOMEM;
-
-	rc = set_density_and_blocklength(minor, buffer, density, blksize);
-	if (!rc) {
-		memset(cmd,0,12);
-		cmd[0] = READ_10;
-		cmd[1] = (scsi_CDs[minor].device->lun << 5);
-		cmd[2] = (unsigned char)(lba >> 24) & 0xff;
-		cmd[3] = (unsigned char)(lba >> 16) & 0xff;
-		cmd[4] = (unsigned char)(lba >>  8) & 0xff;
-		cmd[5] = (unsigned char) lba        & 0xff;
-		cmd[8] = 1;
-		rc = sr_do_ioctl(minor, cmd, dest, blksize);
-		set_density_and_blocklength(minor, buffer, density, 2048);
-	}
-	
 	scsi_free(buffer, 512);
 	return rc;
 }
 
-
 /* This function gets called after a media change. Checks if the CD is
    multisession, asks for offset etc. */
 
@@ -169,7 +150,6 @@
 {
 	unsigned long   sector,min,sec,frame;
 	unsigned char   *buffer;     /* the buffer for the ioctl */
-	unsigned char   *raw_sector; 
 	unsigned char   cmd[12];     /* the scsi-command */
 	int             rc,is_xa,no_multi,minor;
 
@@ -187,16 +167,41 @@
     
 	switch(VENDOR_ID) {
 	
+	case VENDOR_SCSI3:
+		memset(cmd,0,12);
+		cmd[0] = READ_TOC;
+		cmd[1] = (scsi_CDs[minor].device->lun << 5);
+		cmd[8] = 12;
+		cmd[9] = 0x40;
+		rc = sr_do_ioctl(minor, cmd, buffer, 12, 0);	
+		if (rc != 0)
+			break;
+		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
+			printk(KERN_INFO "sr%d: Hmm, seems the drive "
+			       "doesn't support multisession CD's\n",minor);
+			no_multi = 1;
+			break;
+		}
+		sector = buffer[11] + (buffer[10] << 8) +
+			(buffer[9] << 16) + (buffer[8] << 24);
+		if (buffer[6] <= 1) {
+			/* ignore sector offsets from first track */
+			sector = 0;
+		}
+		break;
+		
+#ifdef CONFIG_BLK_DEV_SR_VENDOR
 	case VENDOR_NEC:
 		memset(cmd,0,12);
 		cmd[0] = 0xde;
 		cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
 		cmd[2] = 0xb0;
-		rc = sr_do_ioctl(minor, cmd, buffer, 0x16);
+		rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 0);
 		if (rc != 0)
 			break;
 		if (buffer[14] != 0 && buffer[14] != 0xb0) {
-			printk(KERN_INFO "sr (nec): Hmm, seems the cdrom doesn't support multisession CD's\n");
+			printk(KERN_INFO "sr%d: Hmm, seems the cdrom "
+			       "doesn't support multisession CD's\n",minor);
 			no_multi = 1;
 			break;
 		}
@@ -205,20 +210,19 @@
 		frame  = BCD_TO_BIN(buffer[17]);
 		sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
 		break;
-		
+
 	case VENDOR_TOSHIBA:
 		/* we request some disc information (is it a XA-CD ?,
 		 * where starts the last session ?) */
 		memset(cmd,0,12);
 		cmd[0] = 0xc7;
 		cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
-		rc = sr_do_ioctl(minor, cmd, buffer, 4);
-		if (rc == 0x28000002 &&
-		    !scsi_ioctl(scsi_CDs[minor].device,
-				SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
-			printk(KERN_INFO "sr (toshiba): Hmm, seems the drive doesn't support multisession CD's\n");
-		    no_multi = 1;
-		    break;
+		rc = sr_do_ioctl(minor, cmd, buffer, 4, 0);
+		if (rc == -EINVAL) {
+			printk(KERN_INFO "sr%d: Hmm, seems the drive "
+			       "doesn't support multisession CD's\n",minor);
+			no_multi = 1;
+			break;
 		}
 		if (rc != 0)
 			break;
@@ -239,102 +243,57 @@
 			0x04 : 0x0c;
 		cmd[9] = 0x40;
 		rc = sr_do_ioctl(minor, cmd, buffer,
-		    (VENDOR_ID == VENDOR_HP_4020) ? 0x04 : 0x0c);
+		    (VENDOR_ID == VENDOR_HP_4020) ? 0x04 : 0x0c, 0);
 		if (rc != 0) {
 			break;
 		}
 		if ((rc = buffer[2]) == 0) {
 			printk (KERN_WARNING
-				"sr (hp): No finished session\n");
+				"sr%d: No finished session\n",minor);
 			break;
 		}
 
-		if (VENDOR_ID == VENDOR_HP_4020) {
-		    cmd[0] = READ_TOC; /* Read TOC */
-		    cmd[1] = (scsi_CDs[minor].device->lun << 5);
-		    cmd[6] = rc & 0x7f;  /* number of last session */
-		    cmd[8] = 0x0c;
-		    cmd[9] = 0x40;
-		    rc = sr_do_ioctl(minor, cmd, buffer, 12);	
-		    if (rc != 0) {
-			    break;
-		    }
+ 		if (VENDOR_ID == VENDOR_HP_4020) {
+ 		    cmd[0] = READ_TOC; /* Read TOC */
+ 		    cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ 		    cmd[6] = rc & 0x7f;  /* number of last session */
+ 		    cmd[8] = 0x0c;
+ 		    cmd[9] = 0x40;
+ 		    rc = sr_do_ioctl(minor, cmd, buffer, 12, 0);	
+ 		    if (rc != 0) {
+ 			    break;
+ 		    }
 		}
 
 		sector = buffer[11] + (buffer[10] << 8) +
 			(buffer[9] << 16) + (buffer[8] << 24);
 		break;
-
-	case VENDOR_SONY_LIKE:
-		memset(cmd,0,12);
-		cmd[0] = READ_TOC;
-		cmd[1] = (scsi_CDs[minor].device->lun << 5);
-		cmd[8] = 12;
-		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 12);	
-		if (rc != 0) {
-			break;
-		}
-		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
-			printk(KERN_INFO "sr (sony): Hmm, seems the drive doesn't support multisession CD's\n");
-			no_multi = 1;
-			break;
-		}
-		sector = buffer[11] + (buffer[10] << 8) +
-			(buffer[9] << 16) + (buffer[8] << 24);
-		if (buffer[6] <= 1) {
-			/* ignore sector offsets from first track */
-			sector = 0;
-		}
-		break;
-		
-	case VENDOR_CAN_NOT_HANDLE:
-		sector = 0;
-		no_multi = 1;
-		break;
+#endif /* CONFIG_BLK_DEV_SR_VENDOR */
 
 	default:
 		/* should not happen */
 		printk(KERN_WARNING
-		       "sr: unknown vendor code (%i), not initialized ?\n",
-		       VENDOR_ID);
+		       "sr%d: unknown vendor code (%i), not initialized ?\n",
+		       minor,VENDOR_ID);
 		sector = 0;
 		no_multi = 1;
 		break;
 	}
-   
-	scsi_CDs[minor].xa_flag = 0;
-	if (CDS_AUDIO != sr_disk_status(cdi)) { 
-	    /* read a sector in raw mode to check the sector format */
-	    raw_sector = (unsigned char *) scsi_malloc(2048+512);
-	    if (!buffer) return -ENOMEM;
-	    if (0 == sr_read_sector(minor,sector+16,CD_FRAMESIZE_RAW1,
-				    raw_sector)){
-		is_xa = (raw_sector[3] == 0x02);
-		if (sector > 0 && !is_xa)
-			printk(KERN_INFO "sr: broken CD found: It is "
-			       "multisession, but has'nt XA sectors\n");
-	    } else {
-		/* read a raw sector failed for some reason. */
-		is_xa = (sector > 0);
-	    }
-	    scsi_free(raw_sector, 2048+512);
-	}
-#ifdef DEBUG
-	else printk("sr: audio CD found\n");
-#endif
-
 	scsi_CDs[minor].ms_offset = sector;
-	scsi_CDs[minor].xa_flag = is_xa;
+	scsi_CDs[minor].xa_flag = 0;
+	if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(minor))
+		scsi_CDs[minor].xa_flag = 1;
+	
+	if (2048 != scsi_CDs[minor].sector_size)
+		sr_set_blocklength(minor,2048);
 	if (no_multi)
 		cdi->mask |= CDC_MULTI_SESSION;
 
 #ifdef DEBUG
-	printk(KERN_DEBUG
-	       "sr: multisession offset=%lu, XA=%s\n",
-	       sector,is_xa ? "yes" : "no");
+	if (sector)
+		printk(KERN_DEBUG "sr%d: multisession offset=%lu\n",
+		       minor,sector);
 #endif
-
 	scsi_free(buffer, 512);
 	return rc;
 }
diff -u --recursive --new-file v2.1.61/linux/fs/dquot.c linux/fs/dquot.c
--- v2.1.61/linux/fs/dquot.c	Thu Sep 11 09:02:23 1997
+++ linux/fs/dquot.c	Sat Nov  1 10:59:56 1997
@@ -223,25 +223,17 @@
 	short type = dquot->dq_type;
 	struct file *filp = dquot->dq_mnt->mnt_quotas[type];
 	unsigned long fs;
+	loff_t offset;
 
 	if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL))
 		return;
 	lock_dquot(dquot);
 	down(&dquot->dq_mnt->mnt_sem);
-	if (filp->f_op->llseek) {
-		if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
-		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
-			up(&dquot->dq_mnt->mnt_sem);
-			unlock_dquot(dquot);
-			return;
-		}
-	} else
-		filp->f_pos = dqoff(dquot->dq_id);
+	offset = dqoff(dquot->dq_id);
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 
-	if (filp->f_op->write(filp->f_dentry->d_inode, filp,
-	   (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
+	if (filp->f_op->write(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset) == sizeof(struct dqblk))
 		dquot->dq_flags &= ~DQ_MOD;
 
 	up(&dquot->dq_mnt->mnt_sem);
@@ -255,23 +247,16 @@
 	short type = dquot->dq_type;
 	struct file *filp = dquot->dq_mnt->mnt_quotas[type];
 	unsigned long fs;
+	loff_t offset;
 
 	if (filp == (struct file *)NULL)
 		return;
 	lock_dquot(dquot);
 	down(&dquot->dq_mnt->mnt_sem);
-	if (filp->f_op->llseek) {
-		if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
-		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
-			up(&dquot->dq_mnt->mnt_sem);
-			unlock_dquot(dquot);
-			return;
-		}
-	} else
-		filp->f_pos = dqoff(dquot->dq_id);
+	offset = dqoff(dquot->dq_id);
 	fs = get_fs();
 	set_fs(KERNEL_DS);
-	filp->f_op->read(filp->f_dentry->d_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
+	filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset);
 	up(&dquot->dq_mnt->mnt_sem);
 	set_fs(fs);
 	if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
diff -u --recursive --new-file v2.1.61/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.61/linux/fs/nfs/dir.c	Sat Nov  1 11:04:27 1997
+++ linux/fs/nfs/dir.c	Sun Nov  2 11:00:08 1997
@@ -29,6 +29,8 @@
 
 #include <asm/segment.h>	/* for fs functions */
 
+#define NFS_MAX_AGE 10*HZ	/* max age for dentry validation */
+
 /* needed by smbfs as well ... move to dcache? */
 extern void nfs_renew_times(struct dentry *);
 extern void nfs_invalidate_dircache_sb(struct super_block *);
@@ -51,6 +53,8 @@
 	__u32 *			entry;		/* three __u32's per entry */
 };
 
+static int nfs_safe_remove(struct dentry *);
+
 static int nfs_dir_open(struct inode * inode, struct file * file);
 static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
 static int nfs_readdir(struct file *, void *, filldir_t);
@@ -62,7 +66,8 @@
 static int nfs_symlink(struct inode *, struct dentry *, const char *);
 static int nfs_link(struct inode *, struct inode *, struct dentry *);
 static int nfs_mknod(struct inode *, struct dentry *, int, int);
-static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+static int nfs_rename(struct inode *, struct dentry *,
+		      struct inode *, struct dentry *);
 
 static struct file_operations nfs_dir_operations = {
 	NULL,			/* lseek - default */
@@ -387,7 +392,7 @@
 			goto bad;
 		}
 		if (S_ISDIR(dentry->d_inode->i_mode))
-			max = 10*HZ;
+			max = NFS_MAX_AGE;
 	}
 
 	return (time < max) || IS_ROOT(dentry);
@@ -395,13 +400,44 @@
 	return 0;
 }
 
-static void nfs_silly_delete(struct dentry *);
+/*
+ * This is called from dput() when d_count is going to 0.
+ * We use it to clean up silly-renamed files, and to check
+ * for dentries that have already expired.
+ */
+static void nfs_dentry_delete(struct dentry *dentry)
+{
+	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+		int error;
+		
+		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+#ifdef NFS_DEBUG
+printk("nfs_dentry_delete: unlinking %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+		/* Unhash it first */
+		d_drop(dentry);
+		error = nfs_safe_remove(dentry);
+		if (error)
+			printk("NFS: can't silly-delete %s/%s, error=%d\n",
+				dentry->d_parent->d_name.name,
+				dentry->d_name.name, error);
+	}
+	/*
+	 * Check whether to expire the dentry ...
+	 */
+	else {
+		unsigned long age = jiffies - dentry->d_time;
+		if (age > NFS_MAX_AGE)
+			d_drop(dentry);
+	}
+}
 
 static struct dentry_operations nfs_dentry_operations = {
 	nfs_lookup_revalidate,	/* d_validate(struct dentry *) */
 	0,			/* d_hash */
 	0,			/* d_compare */
-	nfs_silly_delete,	/* d_delete(struct dentry *) */
+	nfs_dentry_delete	/* d_delete(struct dentry *) */
 };
 
 /*
@@ -564,8 +600,12 @@
 }
 
 /*
- *  Update inode->i_nlink immediately after a successful operation.
- *  (See comments for nfs_unlink.)
+ * To avoid retaining a stale inode reference, we check the dentry
+ * use count prior to the operation, and return EBUSY if it has
+ * multiple users.
+ *
+ * Update inode->i_nlink immediately after a successful operation.
+ * (See comments for nfs_unlink.)
  */
 static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
@@ -579,17 +619,27 @@
 		return -ENOENT;
 	}
 
+	error = -ENAMETOOLONG;
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
-		return -ENAMETOOLONG;
+		goto out;
 
+	error = -EBUSY;
+	if (dentry->d_count > 1) {
+		/* Attempt to shrink child dentries ... */
+		shrink_dcache_sb(dentry->d_sb); /* Arghhh */
+		if (dentry->d_count > 1)
+			goto out;
+	}
+	/* Drop the dentry to force a new lookup */
+	d_drop(dentry);
 	error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
 	if (!error) {
 		if (dentry->d_inode->i_nlink)
 			dentry->d_inode->i_nlink --;
 		nfs_invalidate_dircache(dir);
 		nfs_renew_times(dentry);
-		d_delete(dentry);
 	}
+out:
 	return error;
 }
 
@@ -606,24 +656,22 @@
  *
  *  Concerning my choice of the temp name: it is just nice to have
  *  i_ino part of the temp name, as this offers another check whether
- *  somebody attempts to remove the "silly renamed" dentry
- *  itself. Which is something that I consider evil. Your opinion may
- *  vary.
+ *  somebody attempts to remove the "silly renamed" dentry itself.
+ *  Which is something that I consider evil. Your opinion may vary.
  *  BUT:
  *  Now that I compute the hash value right, it should be possible to simply
  *  check for the DCACHE_NFSFS_RENAMED flag in dentry->d_flag instead of
  *  doing the string compare.
  *  WHICH MEANS:
  *  This offers the opportunity to shorten the temp name. Currently, I use
- *  the hex representation of i_ino + the hex value of jiffies. This
- *  sums up to as much as 36 characters for a 64 bit machine, and needs
- *  20 chars on a 32 bit machine. Have a look at jiffiesize etc.
+ *  the hex representation of i_ino + an event counter. This sums up to
+ *  as much as 36 characters for a 64 bit machine, and needs 20 chars on 
+ *  a 32 bit machine.
  *  QUINTESSENCE
  *  The use of i_ino is simply cosmetic. All we need is a unique temp
- *  file name for the .nfs files. The hex representation of "jiffies"
- *  seemed to be adequate. And as we retry in case such a file already
- *  exists we are guaranteed to succed (after some jiffies have passed
- *  by :)
+ *  file name for the .nfs files. The event counter seemed to be adequate.
+ *  And as we retry in case such a file already exists, we are guaranteed
+ *  to succeed.
  */
 
 static
@@ -631,15 +679,11 @@
 {
 	struct qstr    sqstr;
 	struct dentry *sdentry;
-	unsigned long hash;
-	int i, error;
+	int error;
 
 	sqstr.name = silly;
 	sqstr.len  = slen;
-	hash = init_name_hash();
-	for (i= 0; i < slen; i++)
-		hash = partial_name_hash(silly[i], hash);
-	sqstr.hash = end_name_hash(hash);
+	sqstr.hash = full_name_hash(silly, slen);
 	sdentry = d_lookup(parent, &sqstr);
 	if (!sdentry) {
 		sdentry = d_alloc(parent, &sqstr);
@@ -661,11 +705,16 @@
 	const int      countersize = sizeof(sillycounter)*2;
 	const int      slen       = strlen(".nfs") + i_inosize + countersize;
 	char           silly[slen+1];
-	int            error;
 	struct dentry *sdentry;
+	int            error = -EIO;
 
+	/*
+	 * Note that a silly-renamed file can be deleted once it's
+	 * no longer in use -- it's just an ordinary file now.
+	 */
 	if (dentry->d_count == 1) {
-		return -EIO;  /* No need to silly rename. */
+		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+		goto out;  /* No need to silly rename. */
 	}
 
 #ifdef NFS_PARANOIA
@@ -673,12 +722,12 @@
 printk("NFS: silly-renaming %s/%s, negative dentry??\n",
 dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
-	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
-		return -EBUSY; /* don't allow to unlink silly inode -- nope,
-				* think a bit: silly DENTRY, NOT inode --
-				* itself
-				*/
-	}
+	/*
+	 * We don't allow a dentry to be silly-renamed twice.
+	 */
+	error = -EBUSY;
+	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
+		goto out;
 
 	sprintf(silly, ".nfs%*.*lx",
 		i_inosize, i_inosize, dentry->d_inode->i_ino);
@@ -695,9 +744,12 @@
 			 dentry->d_name.name, silly);
 		
 		sdentry = nfs_silly_lookup(dentry->d_parent, silly, slen);
-		if (IS_ERR(sdentry)) {
-			return -EIO; /* FIXME ? */
-		}		
+		/*
+		 * N.B. Better to return EBUSY here ... it could be
+		 * dangerous to delete the file while it's in use.
+		 */
+		if (IS_ERR(sdentry))
+			goto out;
 	} while(sdentry->d_inode != NULL); /* need negative lookup */
 
 	error = nfs_proc_rename(NFS_SERVER(dir),
@@ -711,58 +763,67 @@
  		/* If we return 0 we don't unlink */
 	}
 	dput(sdentry);
+out:
 	return error;
 }
 
-static void nfs_silly_delete(struct dentry *dentry)
+/*
+ * Remove a file after making sure there are no pending writes,
+ * and after checking that the file has only one user. 
+ *
+ * Updating inode->i_nlink here rather than waiting for the next
+ * nfs_refresh_inode() is not merely cosmetic; once an object has
+ * been deleted, we want to get rid of the inode locally.  The NFS
+ * server may reuse the fileid for a new inode, and we don't want
+ * that to be confused with this inode.
+ */
+static int nfs_safe_remove(struct dentry *dentry)
 {
-	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
-		struct inode *dir = dentry->d_parent->d_inode;
-		int error;
+	struct inode *dir = dentry->d_parent->d_inode;
+	struct inode *inode = dentry->d_inode;
+	int error;
 		
-		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
-
-		/* Unhash it first */
-		d_drop(dentry);
-		dfprintk(VFS, "trying to unlink %s\n", dentry->d_name.name);
-		error = nfs_proc_remove(NFS_SERVER(dir),
-					NFS_FH(dir), dentry->d_name.name);
-		if (error < 0)
-			printk("NFS: can't silly-delete %s/%s, error=%d\n",
-				dentry->d_parent->d_name.name,
-				dentry->d_name.name, error);
-		if (dentry->d_inode) {
-			if (dentry->d_inode->i_nlink)
-				dentry->d_inode->i_nlink --;
-		} else {
+	error = -EBUSY;
+	if (inode) {
+		if (NFS_WRITEBACK(inode)) {
+			nfs_flush_dirty_pages(inode, 0, 0, 0);
+			if (NFS_WRITEBACK(inode)) {
 #ifdef NFS_PARANOIA
-			printk("nfs_silly_delete: negative dentry %s/%s\n",
-				dentry->d_parent->d_name.name,
-				dentry->d_name.name);
+printk("nfs_safe_remove: %s/%s writes pending, d_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
 #endif
+				goto out;
+			}
 		}
-		nfs_invalidate_dircache(dir);
+	} else {
+#ifdef NFS_PARANOIA
+printk("nfs_safe_remove: %s/%s already negative??\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
 	}
-	/*
-	 * Check whether to expire the dentry ...
-	 */
-	else {
-		unsigned long age = jiffies - dentry->d_time;
-		if (age > 10*HZ)
-			d_drop(dentry);
+
+	if (dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+printk("nfs_safe_remove: %s/%s busy, d_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+#endif
+		goto out;
 	}
+	error = nfs_proc_remove(NFS_SERVER(dir),
+					NFS_FH(dir), dentry->d_name.name);
+	if (!error) {
+		nfs_invalidate_dircache(dir);
+		if (inode && inode->i_nlink)
+			inode->i_nlink --;
+	}
+out:
+	return error;
 }
 
 /*  We do silly rename. In case sillyrename() returns -EBUSY, the inode
  *  belongs to an active ".nfs..." file and we return -EBUSY.
  *
  *  If sillyrename() returns 0, we do nothing, otherwise we unlink.
- * 
- *  Updating inode->i_nlink here rather than waiting for the next
- *  nfs_refresh_inode() is not merely cosmetic; once an object has
- *  been deleted, we want to get rid of the inode locally.  The NFS
- *  server may reuse the fileid for a new inode, and we don't want
- *  that to be confused with this inode.
  */
 static int nfs_unlink(struct inode *dir, struct dentry *dentry)
 {
@@ -781,23 +842,9 @@
 		goto out;
 
 	error = nfs_sillyrename(dir, dentry);
-
 	if (error && error != -EBUSY) {
-#ifdef NFS_PARANOIA
-if (dentry->d_count > 1)
-printk("nfs_unlink: dentry %s/%s, d_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-if (dentry->d_inode && dentry->d_inode->i_count > 1)
-printk("nfs_unlink: dentry %s/%s, inode i_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_inode->i_count);
-#endif
-		/* N.B. should check for d_count > 1 and fail */
-		error = nfs_proc_remove(NFS_SERVER(dir),
-					NFS_FH(dir), dentry->d_name.name);
+		error = nfs_safe_remove(dentry);
 		if (!error) {
-			if (dentry->d_inode->i_nlink)
-				dentry->d_inode->i_nlink --;
-			nfs_invalidate_dircache(dir);
 			nfs_renew_times(dentry);
 			d_delete(dentry);
 		}
@@ -868,31 +915,13 @@
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
 		goto out;
 
-	/*
-	 * The NFS server may want to use a new fileid for the link,
-	 * so we can't reuse the existing inode for the new dentry.
-	 * To force a new lookup after the link operation, we can just
-	 * drop the new dentry, as long as it's not busy. (See above.)
-	 */
-	error = -EBUSY;
-	if (dentry->d_count > 1) {
-#ifdef NFS_PARANOIA
-printk("nfs_link: dentry %s/%s busy, count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-#endif
-		goto out;
-	}
-	d_drop(dentry);
-
 	error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode), NFS_FH(dir),
 				dentry->d_name.name);
 	if (!error) {
 		nfs_invalidate_dircache(dir);
-#if 0
 		inode->i_count ++;
 		inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
 		d_instantiate(dentry, inode);
-#endif
 	}
 out:
 	return error;
@@ -916,23 +945,16 @@
  * using the inode layer
  *
  * Unfortunately, things are a little more complicated than indicated
- * above. The NFS server may decide to use a new fileid for the renamed
- * file, so we can't link the new name to the old inode. Otherwise, the
- * server might reuse the fileid after the old file has been removed, 
- * which would leave the new dentry holding an invalid fileid (possibly
- * leading to file corruption). To handle this consider these cases:
- *   (1) within-directory:
- *       -- no problem, just use nfs_proc_rename
- *   (2) cross-directory, only one user for old and new dentry:
- *       -- drop both dentries to force new lookups, then use rename
- *   (3) cross-directory, multiple users for old, one user for new:
- *       -- drop new dentry, silly-rename old dentry and make a link
- *   (4) cross-directory, multiple users for new dentry:
- *       -- sorry, we're busy.
+ * above. For a cross-directory move, we want to make sure we can get
+ * rid of the old inode after the operation.  This means there must be
+ * no pending writes (if it's a file), and the use count must be 1.
+ * If these conditions are met, we can drop the dentries before doing
+ * the rename.
  */
 static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		      struct inode *new_dir, struct dentry *new_dentry)
 {
+	struct inode *inode = old_dentry->d_inode;
 	int update = 1, error;
 
 #ifdef NFS_DEBUG_VERBOSE
@@ -955,60 +977,71 @@
 	    new_dentry->d_name.len > NFS_MAXNAMLEN)
 		goto out;
 	/*
-	 * Examine the cases as noted above.
+	 * Check for within-directory rename ... no complications.
 	 */
 	if (new_dir == old_dir)
-		goto simple_case;
+		goto do_rename;
+	/*
+	 * Cross-directory move ... check whether it's a file.
+	 */
 	error = -EBUSY;
-	if (new_dentry->d_count > 1) {
+	if (S_ISREG(inode->i_mode)) {
+		if (NFS_WRITEBACK(inode)) {
 #ifdef NFS_PARANOIA
-printk("nfs_rename: new dentry %s/%s busy, count=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_dentry->d_count);
+printk("nfs_rename: %s/%s has pending writes\n",
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
 #endif
-		goto out;
+			nfs_flush_dirty_pages(inode, 0, 0, 0);
+			if (NFS_WRITEBACK(inode)) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: %s/%s has pending writes after flush\n",
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
+#endif
+				goto out;
+			}
+		}
 	}
-	d_drop(new_dentry);
-	if (old_dentry->d_count > 1)
-		goto complex_case;
-	d_drop(old_dentry);
-	update = 0;
-	
-	/* no need for silly rename, proceed as usual */
-simple_case:
-	error = nfs_proc_rename(NFS_SERVER(old_dir),
-				NFS_FH(old_dir), old_dentry->d_name.name,
-				NFS_FH(new_dir), new_dentry->d_name.name);
-	if (error)
-		goto out;
-	nfs_invalidate_dircache(new_dir);
-	nfs_invalidate_dircache(old_dir);
-
-	/* Update the dcache if needed */
-	if (update)
-		d_move(old_dentry, new_dentry);
-	goto out;
+	/*
+	 * Moving a directory ... prune child dentries if needed.
+	 */
+	else if (old_dentry->d_count > 1)
+		shrink_dcache_sb(old_dentry->d_sb); /* Arghhh */
 
 	/*
-	 * We don't need to update the dcache in this case ... the
-	 * new dentry has been dropped, and the old one silly-renamed.
+	 * Now check the use counts ... we can't safely do the
+	 * rename unless we can drop the dentries first.
 	 */
-complex_case:
-	error = nfs_sillyrename(old_dir, old_dentry);
-	if (error)
+	if (old_dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: old dentry %s/%s busy, d_count=%d\n",
+old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count);
+#endif
 		goto out;
-	nfs_invalidate_dircache(old_dir);
+	}
 
-	error = nfs_link(old_dentry->d_inode, new_dir, new_dentry);
-	if (error)
-		goto out;
-	nfs_invalidate_dircache(new_dir);
+	if (new_dentry->d_count > 1) {
 #ifdef NFS_PARANOIA
-printk("nfs_rename: dentry %s/%s linked to %s/%s, old count=%d\n",
-new_dentry->d_parent->d_name.name,new_dentry->d_name.name,
-old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count);
+printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
+new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
 #endif
+		goto out;
+	}
 
+	d_drop(old_dentry);
+	d_drop(new_dentry);
+	update = 0;
+
+do_rename:
+	error = nfs_proc_rename(NFS_SERVER(old_dir),
+				NFS_FH(old_dir), old_dentry->d_name.name,
+				NFS_FH(new_dir), new_dentry->d_name.name);
+	if (!error) {
+		nfs_invalidate_dircache(new_dir);
+		nfs_invalidate_dircache(old_dir);
+		/* Update the dcache if needed */
+		if (update)
+			d_move(old_dentry, new_dentry);
+	}
 out:
 	return error;
 }
diff -u --recursive --new-file v2.1.61/linux/include/linux/isdnif.h linux/include/linux/isdnif.h
--- v2.1.61/linux/include/linux/isdnif.h	Thu May 29 21:53:11 1997
+++ linux/include/linux/isdnif.h	Mon Nov  3 10:08:48 1997
@@ -390,9 +390,9 @@
 #include <asm/uaccess.h>
 #define GET_USER get_user
 #define PUT_USER put_user
-#define RWTYPE long
+#define RWTYPE ssize_t
 #define LSTYPE long long
-#define RWARG unsigned long
+#define RWARG size_t
 #define LSARG long long
 #endif
 
diff -u --recursive --new-file v2.1.61/linux/include/linux/quota.h linux/include/linux/quota.h
--- v2.1.61/linux/include/linux/quota.h	Thu Jun 12 15:28:32 1997
+++ linux/include/linux/quota.h	Sat Nov  1 11:01:24 1997
@@ -132,7 +132,7 @@
 #define	dq_btime	dq_dqb.dqb_btime
 #define	dq_itime	dq_dqb.dqb_itime
 
-#define dqoff(UID)      ((off_t)((UID) * sizeof (struct dqblk)))
+#define dqoff(UID)      ((loff_t)((UID) * sizeof (struct dqblk)))
 
 struct dqstats {
    __u32 lookups;
diff -u --recursive --new-file v2.1.61/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.61/linux/kernel/ksyms.c	Sat Oct 25 02:44:18 1997
+++ linux/kernel/ksyms.c	Mon Nov  3 09:27:45 1997
@@ -167,6 +167,7 @@
 EXPORT_SYMBOL(invalidate_buffers);
 EXPORT_SYMBOL(invalidate_inodes);
 EXPORT_SYMBOL(invalidate_inode_pages);
+EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(inode_setattr);
@@ -197,6 +198,7 @@
 EXPORT_SYMBOL(dput);
 EXPORT_SYMBOL(get_cached_page);
 EXPORT_SYMBOL(put_cached_page);
+EXPORT_SYMBOL(shrink_dcache_sb);
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
