diff -u --recursive --new-file v2.3.27/linux/CREDITS linux/CREDITS
--- v2.3.27/linux/CREDITS	Thu Nov 11 20:11:30 1999
+++ linux/CREDITS	Fri Nov 12 04:36:13 1999
@@ -1046,6 +1046,17 @@
 S: 8103 Rein
 S: Austria
 
+N: Jan Kara
+E: jack@atrey.karlin.mff.cuni.cz
+E: jack@suse.cz
+D: Quota fixes for 2.2 kernel
+D: Quota fixes for 2.3 kernel
+D: Few other fixes in filesystem area (buffer cache, isofs, loopback)
+W: http://atrey.karlin.mff.cuni.cz/~jack/
+S: Krosenska' 543
+S: 181 00 Praha 8
+S: Czech Republic
+
 N: Jan "Yenya" Kasprzak
 E: kas@fi.muni.cz
 D: Author of the COSA/SRP sync serial board driver.
diff -u --recursive --new-file v2.3.27/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.27/linux/Documentation/Configure.help	Thu Nov 11 20:11:30 1999
+++ linux/Documentation/Configure.help	Fri Nov 12 10:12:11 1999
@@ -685,17 +685,8 @@
 
   Please read the comments at the top of drivers/block/hpt366.c
 
-HPT366 (EXPERIMENTAL)
-CONFIG_BLK_DEV_HPT366_SHARED
-  This requires CONFIG_BLK_DEV_HPT366.
-  It appears that there are different versions or releases of this hardware
-  by ABit.  Since some cases the second channel of the onboard chipset works
-  and others fail, it is default disabled.  This is required to be set if you
-  want to attempt the setup of the second channel.
-
-  JUMBO WARNING, do not boot a kernel with this enabled if it is your only
-  one.  You may not be able to get back into your machine without physically
-  detaching the attached devices.
+HPT366 Fast Interrupt support (EXPERIMENTAL)
+HPT366_FAST_IRQ_PREDICTION
 
   If unsure, say N.
 
diff -u --recursive --new-file v2.3.27/linux/Makefile linux/Makefile
--- v2.3.27/linux/Makefile	Thu Nov 11 20:11:31 1999
+++ linux/Makefile	Thu Nov 11 20:10:44 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 27
+SUBLEVEL = 28
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.3.27/linux/arch/arm/kernel/ioport.c linux/arch/arm/kernel/ioport.c
--- v2.3.27/linux/arch/arm/kernel/ioport.c	Fri Oct 22 13:21:44 1999
+++ linux/arch/arm/kernel/ioport.c	Fri Nov 12 04:29:47 1999
@@ -4,6 +4,7 @@
  * IO permission support for ARM.
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.27/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile
--- v2.3.27/linux/arch/i386/boot/Makefile	Fri Oct 22 13:21:45 1999
+++ linux/arch/i386/boot/Makefile	Thu Nov 11 19:11:18 1999
@@ -51,11 +51,11 @@
 bootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-bbootsect: bbootsect.o
-	$(LD) -Ttext 0x0 -s -oformat binary $< -o $@
+bbootsect: bbootsect.o bsetup.o
+	$(LD) -Ttext 0x0 -R bsetup.o -s -oformat binary $< -o $@
 
 bbootsect.o: bbootsect.s
-	$(AS) --defsym bootsect_kludge=0x220 -o $@ $<
+	$(AS) -o $@ $<
 
 bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
diff -u --recursive --new-file v2.3.27/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.3.27/linux/arch/i386/boot/setup.S	Fri Oct 22 13:21:45 1999
+++ linux/arch/i386/boot/setup.S	Thu Nov 11 19:11:18 1999
@@ -783,7 +783,7 @@
 
 empty_8042:
 	pushl	%ecx
-	movl	$0xFFFFFF, %ecx
+	movl	$0x00FFFFFF, %ecx
 
 empty_8042_loop:
 	decl	%ecx
diff -u --recursive --new-file v2.3.27/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- v2.3.27/linux/arch/i386/boot/video.S	Fri Oct 22 13:21:45 1999
+++ linux/arch/i386/boot/video.S	Thu Nov 11 19:11:18 1999
@@ -1008,7 +1008,7 @@
 vesa1:
 # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
 # XXX:	lodsw	%gs:(%si), %ax			# Get next mode in the list
-	.byte 0x66, 0x65, 0xAD
+	.byte	0x65, 0xAD			# %gs seg prefix + lodsw
 	cmpw	$0xffff, %ax			# End of the table?
 	jz	vesar
 	
diff -u --recursive --new-file v2.3.27/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.3.27/linux/arch/i386/kernel/smp.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/kernel/smp.c	Fri Nov 12 04:29:47 1999
@@ -8,7 +8,6 @@
  *	later.
  */
 
-#include <linux/config.h>
 #include <linux/init.h>
 
 #include <linux/mm.h>
diff -u --recursive --new-file v2.3.27/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c
--- v2.3.27/linux/arch/i386/lib/usercopy.c	Mon Oct 11 15:38:14 1999
+++ linux/arch/i386/lib/usercopy.c	Fri Nov 12 04:29:47 1999
@@ -5,6 +5,7 @@
  * Copyright 1997 Andi Kleen <ak@muc.de>
  * Copyright 1997 Linus Torvalds
  */
+#include <linux/config.h>
 #include <asm/uaccess.h>
 #include <asm/mmx.h>
 
diff -u --recursive --new-file v2.3.27/linux/arch/m68k/kernel/sun3-head.S linux/arch/m68k/kernel/sun3-head.S
--- v2.3.27/linux/arch/m68k/kernel/sun3-head.S	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/kernel/sun3-head.S	Fri Nov 12 04:29:47 1999
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/linkage.h>
 
 #include <asm/page.h>
diff -u --recursive --new-file v2.3.27/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c
--- v2.3.27/linux/arch/m68k/mac/macints.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/mac/macints.c	Fri Nov 12 04:29:47 1999
@@ -115,7 +115,6 @@
  *     the SCC ourselves and only call the handler for the appopriate channel.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/arch/m68k/mac/psc.c linux/arch/m68k/mac/psc.c
--- v2.3.27/linux/arch/m68k/mac/psc.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/mac/psc.c	Fri Nov 12 04:29:47 1999
@@ -13,7 +13,6 @@
  * they aren't actually interrupt lines but data lines (to the DSP?)
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.3.27/linux/arch/m68k/math-emu/fp_entry.S linux/arch/m68k/math-emu/fp_entry.S
--- v2.3.27/linux/arch/m68k/math-emu/fp_entry.S	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/math-emu/fp_entry.S	Fri Nov 12 04:29:47 1999
@@ -35,6 +35,7 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/entry.h>
 
diff -u --recursive --new-file v2.3.27/linux/arch/m68k/math-emu/fp_util.S linux/arch/m68k/math-emu/fp_util.S
--- v2.3.27/linux/arch/m68k/math-emu/fp_util.S	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/math-emu/fp_util.S	Fri Nov 12 04:29:47 1999
@@ -35,6 +35,7 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <linux/config.h>
 #include "fp_emu.h"
 
 /*
diff -u --recursive --new-file v2.3.27/linux/arch/m68k/sun3/prom/console.c linux/arch/m68k/sun3/prom/console.c
--- v2.3.27/linux/arch/m68k/sun3/prom/console.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/sun3/prom/console.c	Fri Nov 12 04:29:47 1999
@@ -5,7 +5,6 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/arch/m68k/sun3/prom/misc.c linux/arch/m68k/sun3/prom/misc.c
--- v2.3.27/linux/arch/m68k/sun3/prom/misc.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/sun3/prom/misc.c	Fri Nov 12 04:29:47 1999
@@ -5,7 +5,6 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/arch/m68k/sun3/sun3ints.c linux/arch/m68k/sun3/sun3ints.c
--- v2.3.27/linux/arch/m68k/sun3/sun3ints.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/sun3/sun3ints.c	Fri Nov 12 04:29:47 1999
@@ -6,7 +6,6 @@
  * for more details.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/arch/ppc/8xx_io/commproc.c linux/arch/ppc/8xx_io/commproc.c
--- v2.3.27/linux/arch/ppc/8xx_io/commproc.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/8xx_io/commproc.c	Fri Nov 12 04:29:47 1999
@@ -21,7 +21,6 @@
  * applications that require more DP ram, we can expand the boundaries
  * but then we have to be careful of any downloaded microcode.
  */
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.27/linux/arch/ppc/8xx_io/commproc.h linux/arch/ppc/8xx_io/commproc.h
--- v2.3.27/linux/arch/ppc/8xx_io/commproc.h	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/8xx_io/commproc.h	Fri Nov 12 04:29:47 1999
@@ -18,6 +18,7 @@
 #ifndef __CPM_8XX__
 #define __CPM_8XX__
 
+#include <linux/config.h>
 #include <asm/8xx_immap.h>
 
 /* CPM Command register.
diff -u --recursive --new-file v2.3.27/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c
--- v2.3.27/linux/arch/ppc/8xx_io/enet.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/8xx_io/enet.c	Fri Nov 12 04:29:47 1999
@@ -22,6 +22,7 @@
  * small packets.
  *
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.3.27/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c
--- v2.3.27/linux/arch/ppc/8xx_io/fec.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/8xx_io/fec.c	Fri Nov 12 04:29:47 1999
@@ -16,6 +16,7 @@
  * small packets.
  *
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.3.27/linux/arch/ppc/amiga/ints.c linux/arch/ppc/amiga/ints.c
--- v2.3.27/linux/arch/ppc/amiga/ints.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/amiga/ints.c	Fri Nov 12 04:29:47 1999
@@ -5,7 +5,6 @@
  *  Needed to drive the m68k emulating IRQ hardware on the PowerUp boards.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
diff -u --recursive --new-file v2.3.27/linux/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c
--- v2.3.27/linux/arch/ppc/kernel/pmac_support.c	Sun Nov  7 16:37:34 1999
+++ linux/arch/ppc/kernel/pmac_support.c	Fri Nov 12 04:29:47 1999
@@ -1,6 +1,7 @@
 /*
  * Miscellaneous procedures for dealing with the PowerMac hardware.
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/reboot.h>
diff -u --recursive --new-file v2.3.27/linux/arch/ppc/kernel/ppc8xx_pic.c linux/arch/ppc/kernel/ppc8xx_pic.c
--- v2.3.27/linux/arch/ppc/kernel/ppc8xx_pic.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/ppc8xx_pic.c	Fri Nov 12 04:29:47 1999
@@ -1,4 +1,4 @@
-
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/arch/ppc/kernel/ppc8xx_pic.h linux/arch/ppc/kernel/ppc8xx_pic.h
--- v2.3.27/linux/arch/ppc/kernel/ppc8xx_pic.h	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/ppc8xx_pic.h	Fri Nov 12 04:29:47 1999
@@ -1,7 +1,7 @@
-
 #ifndef _PPC_KERNEL_PPC8xx_H
 #define _PPC_KERNEL_PPC8xx_H
 
+#include <linux/config.h>
 #include "local_irq.h"
 
 extern struct hw_interrupt_type ppc8xx_pic;
diff -u --recursive --new-file v2.3.27/linux/arch/ppc/kernel/qspan_pci.c linux/arch/ppc/kernel/qspan_pci.c
--- v2.3.27/linux/arch/ppc/kernel/qspan_pci.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/qspan_pci.c	Fri Nov 12 04:29:47 1999
@@ -15,6 +15,7 @@
  * we have switched the chip select.
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
diff -u --recursive --new-file v2.3.27/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c
--- v2.3.27/linux/arch/sh/kernel/irq_onchip.c	Sun Nov  7 16:37:34 1999
+++ linux/arch/sh/kernel/irq_onchip.c	Fri Nov 12 04:29:47 1999
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
diff -u --recursive --new-file v2.3.27/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- v2.3.27/linux/arch/sparc64/kernel/trampoline.S	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc64/kernel/trampoline.S	Fri Nov 12 04:29:47 1999
@@ -4,8 +4,6 @@
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <linux/config.h>
-
 #include <asm/head.h>
 #include <asm/asi.h>
 #include <asm/lsu.h>
diff -u --recursive --new-file v2.3.27/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.3.27/linux/arch/sparc64/mm/ultra.S	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc64/mm/ultra.S	Fri Nov 12 04:29:47 1999
@@ -4,8 +4,6 @@
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <linux/config.h>
-
 #include <asm/asi.h>
 #include <asm/pgtable.h>
 #include <asm/spitfire.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.27/linux/drivers/block/Config.in	Sun Nov  7 16:37:34 1999
+++ linux/drivers/block/Config.in	Fri Nov 12 10:12:11 1999
@@ -53,6 +53,9 @@
 	    fi
 	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
 	    bool '    AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
+	       if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then
+		 bool '      AEC6210 Tuning support' CONFIG_BLK_DEV_AEC6210_TUNING
+	       fi
 	    if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
 	       if [ "$CONFIG_X86" = "y" ]; then
 		  bool '    ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
@@ -65,7 +68,10 @@
 	       if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
 		  bool '      HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA
 	       fi
-  	       bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366
+	       bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366
+	       if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then
+		  bool '      HPT366 Fast Interrupt support (EXPERIMENTAL)' HPT366_FAST_IRQ_PREDICTION
+	       fi
 	    fi
 	    if [ "$CONFIG_X86" = "y" ]; then
 	       bool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
@@ -219,6 +225,7 @@
 fi
 
 if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+     "$CONFIG_BLK_DEV_AEC6210" = "y" -o \
      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
      "$CONFIG_BLK_DEV_CMD640" = "y" -o \
      "$CONFIG_BLK_DEV_CY82C693" = "y" -o \
diff -u --recursive --new-file v2.3.27/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.3.27/linux/drivers/block/Makefile	Fri Oct 22 13:21:47 1999
+++ linux/drivers/block/Makefile	Fri Nov 12 10:12:11 1999
@@ -243,11 +243,11 @@
 ###Collect
 
 ifeq ($(CONFIG_BLK_DEV_IDE),y)
-  LX_OBJS += ide.o
+  LX_OBJS += ide.o ide-features.o
   L_OBJS += ide-probe.o $(IDE_OBJS)
 else
   ifeq ($(CONFIG_BLK_DEV_IDE),m)
-  MIX_OBJS += ide.o $(IDE_OBJS)
+  MIX_OBJS += ide.o ide-features.o $(IDE_OBJS)
   M_OBJS += ide-mod.o ide-probe-mod.o
   endif
 endif
@@ -374,8 +374,8 @@
 
 include $(TOPDIR)/Rules.make
 
-ide-mod.o: ide.o $(IDE_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ ide.o $(IDE_OBJS)
+ide-mod.o: ide.o ide-features.o $(IDE_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ ide.o ide-features.o $(IDE_OBJS)
 
 ide-probe-mod.o: ide-probe.o ide-geometry.o
 	$(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o
diff -u --recursive --new-file v2.3.27/linux/drivers/block/aec6210.c linux/drivers/block/aec6210.c
--- v2.3.27/linux/drivers/block/aec6210.c	Fri Oct 22 13:21:47 1999
+++ linux/drivers/block/aec6210.c	Fri Nov 12 10:12:11 1999
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/aec6210.c	Version 0.02	Sept. 3, 1999
+ * linux/drivers/block/aec6210.c	Version 0.03	Nov. 12, 1999
  *
  * Copyright (C) 1998-99	Andre Hedrick (andre@suse.com)
  * May be copied or modified under the terms of the GNU General Public License
@@ -51,10 +51,225 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
+#include "ide_modes.h"
+
+#define ACARD_DEBUG_DRIVE_INFO 1
+
+#ifdef CONFIG_BLK_DEV_AEC6210_TUNING
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	unsigned short	chipset_settings;
+	byte		ultra_settings;
+};
+
+struct chipset_bus_clock_list_entry aec6210_base [] = {
+	{	XFER_UDMA_2,	0x0401,	0x02	},
+	{	XFER_UDMA_1,	0x0401,	0x01	},
+	{	XFER_UDMA_0,	0x0401,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x0401,	0x00	},
+	{	XFER_MW_DMA_1,	0x0402,	0x00	},
+	{	XFER_MW_DMA_0,	0x070a,	0x00	},
+
+	{	XFER_PIO_4,	0x0401,	0x00	},
+	{	XFER_PIO_3,	0x0403,	0x00	},
+	{	XFER_PIO_2,	0x0708,	0x00	},
+	{	XFER_PIO_1,	0x070a,	0x00	},
+	{	XFER_PIO_0,	0x0700,	0x00	},
+	{	0,		0x0000,	0x00	}
+};
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
 /*
  * TO DO: active tuning and correction of cards without a bios.
  */
 
+static unsigned short pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->chipset_settings;
+		}
+	return 0x0000;
+}
+
+static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->ultra_settings;
+		}
+	return 0x00;
+}
+
+static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	int			err;
+	byte			drive_pci;
+	unsigned short		drive_conf = 0x0000;
+	byte			ultra = 0x00, ultra_conf = 0x00;
+	byte			tmp1 = 0x00, tmp2 = 0x00;
+
+	int drive_number	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+
+	switch(drive_number) {
+		case 0:		drive_pci = 0x40; break;
+		case 1:		drive_pci = 0x42; break;
+		case 2:		drive_pci = 0x44; break;
+		case 3:		drive_pci = 0x46; break;
+		default:	return -1;
+	}
+
+	pci_read_config_word(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
+	drive_conf = pci_bus_clock_list(speed, aec6210_base);
+	pci_write_config_word(HWIF(drive)->pci_dev, drive_pci, drive_conf);
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, &ultra);
+	tmp1 = ((0x00 << (2*drive_number)) | (ultra & ~(3 << (2*drive_number))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, aec6210_base);
+	tmp2 = ((ultra_conf << (2*drive_number)) | (tmp1 & ~(3 << (2*drive_number))));
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x54, tmp2);
+
+	err = ide_config_drive_speed(drive, speed);
+
+#if ACARD_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d 0x04%x 0x02%x 0x02%x 0x02%x 0x02%x\n",
+		drive->name, ide_xfer_verbose(speed), drive_number,
+		drive_conf, ultra, tmp1, ultra_conf, tmp2);
+#endif /* ACARD_DEBUG_DRIVE_INFO */
+
+	return(err);
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
+{
+	struct hd_driveid *id = drive->id;
+	byte speed = -1;
+
+	if (drive->media != ide_disk)
+		return ((int) ide_dma_off_quietly);
+
+	if (((id->dma_ultra & 0x0010) ||
+	     (id->dma_ultra & 0x0008) ||
+	     (id->dma_ultra & 0x0004)) && (ultra)) {
+		speed = XFER_UDMA_2;
+	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
+		speed = XFER_UDMA_1;
+	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
+		speed = XFER_UDMA_0;
+	} else if (id->dma_mword & 0x0004) {
+		speed = XFER_MW_DMA_2;
+	} else if (id->dma_mword & 0x0002) {
+		speed = XFER_MW_DMA_1;
+	} else if (id->dma_mword & 0x0001) {
+		speed = XFER_MW_DMA_0;
+	} else if (id->dma_1word & 0x0004) {
+		speed = XFER_SW_DMA_2;
+	} else if (id->dma_1word & 0x0002) {
+		speed = XFER_SW_DMA_1;
+	} else if (id->dma_1word & 0x0001) {
+		speed = XFER_SW_DMA_0;
+	} else {
+		return ((int) ide_dma_off_quietly);
+	}
+	(void) aec6210_tune_chipset(drive, speed);
+
+	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+}
+
+static void aec6210_tune_drive (ide_drive_t *drive, byte pio)
+{
+	byte speed;
+
+	switch(pio) {
+		case 5:
+			speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+		case 4:
+			speed = XFER_PIO_4; break;
+		case 3:
+			speed = XFER_PIO_3; break;
+		case 2:
+			speed = XFER_PIO_2; break;
+		case 1:
+			speed = XFER_PIO_1; break;
+		default:
+			speed = XFER_PIO_0; break;
+	}
+	(void) aec6210_tune_chipset(drive, speed);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
+
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
+		}
+		dma_func = ide_dma_off_quietly;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x001F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive, 1);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive, 0);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive, 0);
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		aec6210_tune_drive(drive, 5);
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * aec6210_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+int aec6210_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */
+
 unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name)
 {
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
@@ -62,4 +277,45 @@
 		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
 	return dev->irq;
+}
+
+void __init ide_init_aec6210 (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_BLK_DEV_AEC6210_TUNING
+	hwif->tuneproc = &aec6210_tune_drive;
+
+	if (hwif->dma_base) {
+		hwif->dmaproc = &aec6210_dmaproc;
+		hwif->drives[0].autotune = 0;
+		hwif->drives[1].autotune = 0;
+	} else {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+	}
+#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */
+}
+
+void __init ide_dmacapable_aec6210 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	byte dma_new	= 0;
+	byte dma_old	= inb(dmabase+2);
+	byte reg54h	= 0;
+	byte masterdma	= hwif->channel ? 0x30 : 0x03;
+	byte slavedma	= hwif->channel ? 0xc0 : 0x0c;
+	unsigned long flags;
+
+	__save_flags(flags);	/* local CPU only */
+	__cli();		/* local CPU only */
+
+	dma_new = dma_old;
+
+	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
+
+	if (reg54h & masterdma)	dma_new |= 0x20;
+	if (reg54h & slavedma)	dma_new |= 0x40;
+	if (dma_new != dma_old)	outb(dma_new, dmabase+2);
+
+	__restore_flags(flags);	/* local CPU only */
+
+	ide_setup_dma(hwif, dmabase, 8);
 }
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ali14xx.c linux/drivers/block/ali14xx.c
--- v2.3.27/linux/drivers/block/ali14xx.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/ali14xx.c	Fri Nov 12 10:12:11 1999
@@ -204,11 +204,11 @@
 {
 	/* auto-detect IDE controller port */
 	if (!findPort()) {
-		printk("ali14xx: not found\n");
+		printk("\nali14xx: not found");
 		return;
 	}
 
-	printk("ali14xx: base= 0x%03x, regOn = 0x%02x\n", basePort, regOn);
+	printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn);
 	ide_hwifs[0].chipset = ide_ali14xx;
 	ide_hwifs[1].chipset = ide_ali14xx;
 	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
@@ -219,7 +219,7 @@
 
 	/* initialize controller registers */
 	if (!initRegisters()) {
-		printk("ali14xx: Chip initialization failed\n");
+		printk("\nali14xx: Chip initialization failed");
 		return;
 	}
 }
diff -u --recursive --new-file v2.3.27/linux/drivers/block/alim15x3.c linux/drivers/block/alim15x3.c
--- v2.3.27/linux/drivers/block/alim15x3.c	Fri Oct 22 13:21:47 1999
+++ linux/drivers/block/alim15x3.c	Fri Nov 12 10:12:11 1999
@@ -693,6 +693,31 @@
 		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
 	}
 
+	if (m5229_revision == 0x20) {
+		/*
+		 * check M1533 revision (offset 0x08)
+		 */
+		pci_read_config_byte(isa_dev, 0x08, &tmpbyte);
+		if (tmpbyte == 0x0A) {
+			unsigned long flags;
+			pci_read_config_byte(dev, 0x4e, &tmpbyte);
+			save_flags(flags);
+			cli();
+			/*
+			 * set bit 6
+			 */
+			pci_write_config_byte(dev, 0x4e, tmpbyte | 0x40);
+			restore_flags(flags);
+
+			/*
+			 * this special version is similar to revision 0xC2
+			 * but does not support UDMA66
+			 * (cable_80_pin[0] = 0; cable_80_pin[1] = 0;)
+			 */
+			m5229_revision = 0xC2;
+		}
+	}
+
 	return 0;
 }
 
@@ -742,7 +767,7 @@
 	}
 
 	hwif->tuneproc = &ali15x3_tune_drive;
-	if ((hwif->dma_base) && (m5229_revision >= 0xC1)) {
+	if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
 		/*
 		 * M1543C or newer for DMAing
 		 */
diff -u --recursive --new-file v2.3.27/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c
--- v2.3.27/linux/drivers/block/cmd640.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/cmd640.c	Fri Nov 12 10:12:11 1999
@@ -686,6 +686,7 @@
 		d.cycle_time,
 		d.overridden ? " (overriding vendor mode)" : "");
 	display_clocks(index);
+	return;
 }
 
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
diff -u --recursive --new-file v2.3.27/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.3.27/linux/drivers/block/cpqarray.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/block/cpqarray.c	Fri Nov 12 04:29:47 1999
@@ -22,6 +22,7 @@
  *    driver, you'll probably need the Compaq Array Controller Interface
  *    Specificiation (Document number ECG086/1198)
  */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/block/hpt366.c linux/drivers/block/hpt366.c
--- v2.3.27/linux/drivers/block/hpt366.c	Fri Oct 22 13:21:47 1999
+++ linux/drivers/block/hpt366.c	Fri Nov 12 10:12:11 1999
@@ -218,7 +218,8 @@
 {
 	struct hd_driveid *id	= drive->id;
 	byte speed		= 0x00;
-	unsigned int reg40 = 0;
+	byte reg51h		= 0;
+	unsigned int reg40	= 0;
 	int  rval;
 
 	if ((id->dma_ultra & 0x0010) &&
@@ -258,15 +259,22 @@
 		return ((int) ide_dma_off_quietly);
 	}
 
-	/* Disable the "fast interrupt" prediction.
+	pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, &reg51h);
+
+#ifdef HPT366_FAST_IRQ_PREDICTION
+	/*
+	 * Some drives prefer/allow for the method of handling interrupts.
+	 */
+	if (!(reg51h & 0x80))
+		pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h|0x80);
+#else /* ! HPT366_FAST_IRQ_PREDICTION */
+	/*
+	 * Disable the "fast interrupt" prediction.
 	 * Instead, always wait for the real interrupt from the drive!
 	 */
-	{
-		byte reg51h = 0;
-		pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, &reg51h);
-		if (reg51h & 0x80)
-			pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80);
-	}
+	if (reg51h & 0x80)
+		pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80);
+#endif /* HPT366_FAST_IRQ_PREDICTION */
 
 	/*
 	 * Preserve existing PIO settings:
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.3.27/linux/drivers/block/ide-cd.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/block/ide-cd.c	Fri Nov 12 10:12:11 1999
@@ -276,7 +276,6 @@
  
 #define IDECD_VERSION "4.56"
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -539,7 +538,7 @@
 
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
-static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
+static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive, int good_stat,
 				int *stat_ret)
 {
 	struct request *rq = HWGROUP(drive)->rq;
@@ -570,7 +569,7 @@
 
 			pc->stat = 1;
 			cdrom_end_request (1, drive);
-			ide_error (drive, "request sense failure", stat);
+			*startstop = ide_error (drive, "request sense failure", stat);
 			return 1;
 
 		} else if (cmd == PACKET_COMMAND) {
@@ -640,7 +639,7 @@
 			} else if ((err & ~ABRT_ERR) != 0) {
 				/* Go to the default handler
 				   for other errors. */
-				ide_error (drive, "cdrom_decode_status", stat);
+				*startstop = ide_error (drive, "cdrom_decode_status", stat);
 				return 1;
 			} else if ((++rq->errors > ERROR_MAX)) {
 				/* We've racked up too many retries.  Abort. */
@@ -656,6 +655,7 @@
 	}
 
 	/* Retry, or handle the next request. */
+	*startstop = ide_stopped;
 	return 1;
 }
 
@@ -682,13 +682,15 @@
    called when the interrupt from the drive arrives.  Otherwise, HANDLER
    will be called immediately after the drive is prepared for the transfer. */
 
-static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen,
+static ide_startstop_t cdrom_start_packet_command (ide_drive_t *drive, int xferlen,
 				       ide_handler_t *handler)
 {
+	ide_startstop_t startstop;
 	struct cdrom_info *info = drive->driver_data;
 
 	/* Wait for the controller to be idle. */
-	if (ide_wait_stat(drive, 0, BUSY_STAT, WAIT_READY)) return 1;
+	if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
+		return startstop;
 
 	if (info->dma)
 		info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
@@ -709,12 +711,11 @@
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
 		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		(*handler) (drive);
+		return (*handler) (drive);
 	}
-
-	return 0;
 }
 
 /* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN.
@@ -722,7 +723,7 @@
    by cdrom_start_packet_command.
    HANDLER is the interrupt handler to call when the command completes
    or there's data ready. */
-static int cdrom_transfer_packet_command (ide_drive_t *drive,
+static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
                                           unsigned char *cmd_buf, int cmd_len,
 					  ide_handler_t *handler)
 {
@@ -730,14 +731,16 @@
 		/* Here we should have been called after receiving an interrupt
 		   from the device.  DRQ should how be set. */
 		int stat_dum;
+		ide_startstop_t startstop;
 
 		/* Check for errors. */
-		if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum))
-			return 1;
+		if (cdrom_decode_status (&startstop, drive, DRQ_STAT, &stat_dum))
+			return startstop;
 	} else {
+		ide_startstop_t startstop;
 		/* Otherwise, we must wait for DRQ to get set. */
-		if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
-			return 1;
+		if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
+			return startstop;
 	}
 
 	/* Arm the interrupt handler. */
@@ -746,7 +749,7 @@
 	/* Send the command to the device. */
 	atapi_output_bytes (drive, cmd_buf, cmd_len);
 
-	return 0;
+	return ide_started;
 }
 
 
@@ -843,12 +846,13 @@
 /*
  * Interrupt routine.  Called when a read request has completed.
  */
-static void cdrom_read_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
 {
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
 	struct cdrom_info *info = drive->driver_data;
 	int i, dma = info->dma, dma_error = 0;
+	ide_startstop_t startstop;
 
 	struct request *rq = HWGROUP(drive)->rq;
 
@@ -859,19 +863,18 @@
 			HWIF(drive)->dmaproc(ide_dma_off, drive);
 	}
 
-	if (cdrom_decode_status (drive, 0, &stat))
-		return;
+	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+		return startstop;
  
 	if (dma) {
-		if (dma_error) {
-			ide_error (drive, "dma error", stat);
-			return;
-		}
-		for (i = rq->nr_sectors; i > 0;) {
-			i -= rq->current_nr_sectors;
-			ide_end_request(1, HWGROUP(drive));
-		}
-		return;
+		if (!dma_error) {
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				ide_end_request(1, HWGROUP(drive));
+			}
+			return ide_stopped;
+		} else
+			return ide_error (drive, "dma error", stat);
 	}
 
 	/* Read the interrupt reason and the transfer length. */
@@ -888,11 +891,12 @@
 			cdrom_end_request (0, drive);
 		} else
 			cdrom_end_request (1, drive);
-		return;
+		return ide_stopped;
 	}
 
 	/* Check that the drive is expecting to do the same thing we are. */
-	if (cdrom_read_check_ireason (drive, len, ireason)) return;
+	if (cdrom_read_check_ireason (drive, len, ireason))
+		return ide_stopped;
 
 	/* Assume that the drive will always provide data in multiples
 	   of at least SECTOR_SIZE, as it gets hairy to keep track
@@ -907,7 +911,7 @@
 			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
 		}
 		cdrom_end_request (0, drive);
-		return;
+		return ide_stopped;
 	}
 
 	/* The number of sectors we need to read from the drive. */
@@ -967,6 +971,7 @@
 	/* Done moving data!
 	   Wait for another interrupt. */
 	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
+	return ide_started;
 }
 
 /*
@@ -1031,7 +1036,7 @@
  * However, for drq_interrupt devices, it is called from an interrupt
  * when the drive is ready to accept the command.
  */
-static void cdrom_start_read_continuation (ide_drive_t *drive)
+static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
 {
 	struct packet_command pc;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1058,7 +1063,7 @@
 			printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n",
 				drive->name, rq->current_nr_sectors);
 			cdrom_end_request (0, drive);
-			return;
+			return ide_stopped;
 		}
 		sector -= nskip;
 		nsect += nskip;
@@ -1083,7 +1088,7 @@
 	put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
 
 	/* Send the command to the drive and return. */
-	(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c),
+	return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c),
 					      &cdrom_read_intr);
 }
 
@@ -1092,14 +1097,15 @@
 #define IDECD_SEEK_TIMER	(5 * WAIT_MIN_SLEEP)	/* 100 ms */
 #define IDECD_SEEK_TIMEOUT     WAIT_CMD			/* 10 sec */
 
-static void cdrom_seek_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
 	int stat;
 	static int retry = 10;
+	ide_startstop_t startstop;
 
-	if (cdrom_decode_status (drive, 0, &stat))
-		return;
+	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+		return startstop;
 	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
 
 	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
@@ -1108,9 +1114,10 @@
 			drive->dsc_overlap = 0;
 		}
 	}
+	return ide_stopped;
 }
 
-static void cdrom_start_seek_continuation (ide_drive_t *drive)
+static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
 {
 	struct packet_command pc;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1125,16 +1132,16 @@
 	memset (&pc.c, 0, sizeof (pc.c));
 	pc.c[0] = GPCMD_SEEK;
 	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
-	(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr);
+	return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr);
 }
 
-static void cdrom_start_seek (ide_drive_t *drive, unsigned int block)
+static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block)
 {
 	struct cdrom_info *info = drive->driver_data;
 
 	info->dma = 0;
 	info->start_seek = jiffies;
-	cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
+	return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
 }
 
 /* Fix up a possibly partially-processed request so that we can
@@ -1153,7 +1160,7 @@
 /*
  * Start a read request from the CD-ROM.
  */
-static void cdrom_start_read (ide_drive_t *drive, unsigned int block)
+static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1173,8 +1180,9 @@
 
 	/* Satisfy whatever we can of this request from our cached sector. */
 	if (cdrom_read_from_buffer(drive))
-		return;
+		return ide_stopped;
 
+	/* Clear the local sector buffer. */
 	info->nsectors_buffered = 0;
 
 	/* use dma, if possible. */
@@ -1185,7 +1193,7 @@
 		info->dma = 0;
 
 	/* Start sending the read request to the drive. */
-	cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
+	return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
 }
 
 /****************************************************************************
@@ -1198,15 +1206,16 @@
 		struct atapi_request_sense *reqbuf);
 
 /* Interrupt routine for packet command completion. */
-static void cdrom_pc_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
 {
 	int ireason, len, stat, thislen;
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
+	ide_startstop_t startstop;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (drive, 0, &stat))
-		return;
+	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+		return startstop;
 
 	/* Read the interrupt reason and the transfer length. */
 	ireason = IN_BYTE (IDE_NSECTOR_REG);
@@ -1239,15 +1248,25 @@
 			pc->stat = 1;
 			cdrom_end_request (1, drive);
 		}
-		return;
+		return ide_stopped;
 	}
 
 	/* Figure out how much data to transfer. */
 	thislen = pc->buflen;
+	if (thislen < 0) thislen = -thislen;
 	if (thislen > len) thislen = len;
 
 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
+		/* Check that we want to write. */
+		if (pc->buflen > 0) {
+			printk ("%s: cdrom_pc_intr: Drive wants "
+				"to transfer data the wrong way!\n",
+				drive->name);
+			pc->stat = 1;
+			thislen = 0;
+		}
+
 		/* Transfer the data. */
 		atapi_output_bytes (drive, pc->buffer, thislen);
 
@@ -1266,6 +1285,14 @@
 
 	/* Same drill for reading. */
 	else if ((ireason & 3) == 2) {
+		/* Check that we want to read. */
+		if (pc->buflen < 0) {
+			printk ("%s: cdrom_pc_intr: Drive wants to "
+				"transfer data the wrong way!\n",
+				drive->name);
+			pc->stat = 1;
+			thislen = 0;
+		}
 
 		/* Transfer the data. */
 		atapi_input_bytes (drive, pc->buffer, thislen);
@@ -1290,21 +1317,22 @@
 
 	/* Now we wait for another interrupt. */
 	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
+	return ide_started;
 }
 
 
-static void cdrom_do_pc_continuation (ide_drive_t *drive)
+static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 
 	/* Send the command to the drive and return. */
-	cdrom_transfer_packet_command (drive, pc->c,
+	return cdrom_transfer_packet_command (drive, pc->c,
 				       sizeof (pc->c), &cdrom_pc_intr);
 }
 
 
-static void cdrom_do_packet_command (ide_drive_t *drive)
+static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
 {
 	int len;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1316,7 +1344,7 @@
 	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
-	cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
+	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
 }
 
 
@@ -1401,51 +1429,50 @@
 /****************************************************************************
  * cdrom driver request routine.
  */
-static
-void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t
+ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
+	ide_startstop_t action;
 	struct cdrom_info *info = drive->driver_data;
 
 	switch (rq->cmd) {
-	case READ: {
-		if (CDROM_CONFIG_FLAGS(drive)->seeking) {
-			unsigned long elpased = jiffies - info->start_seek;
-			int stat = GET_STAT();
-
-			if ((stat & SEEK_STAT) != SEEK_STAT) {
-				if (elpased < IDECD_SEEK_TIMEOUT) {
-					ide_stall_queue(drive, IDECD_SEEK_TIMER);
-					return;
+		case READ: {
+			if (CDROM_CONFIG_FLAGS(drive)->seeking) {
+				unsigned long elpased = jiffies - info->start_seek;
+				int stat = GET_STAT();
+
+				if ((stat & SEEK_STAT) != SEEK_STAT) {
+					if (elpased < IDECD_SEEK_TIMEOUT) {
+						ide_stall_queue(drive, IDECD_SEEK_TIMER);
+						return ide_stopped;
+					}
+					printk ("%s: DSC timeout\n", drive->name);
 				}
-				printk ("%s: DSC timeout\n", drive->name);
+				CDROM_CONFIG_FLAGS(drive)->seeking = 0;
 			}
-			CDROM_CONFIG_FLAGS(drive)->seeking = 0;
+			if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap)
+				action = cdrom_start_seek (drive, block);
+			else
+				action = cdrom_start_read (drive, block);
+			info->last_block = block;
+			return action;
 		}
-		if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap)
-			cdrom_start_seek (drive, block);
-		else
-			cdrom_start_read (drive, block);
-		info->last_block = block;
-		break;
-	}
 
-	case PACKET_COMMAND:
-	case REQUEST_SENSE_COMMAND: {
-		cdrom_do_packet_command(drive);
-		break;
-	}
+		case PACKET_COMMAND:
+		case REQUEST_SENSE_COMMAND: {
+			return cdrom_do_packet_command(drive);
+		}
 
-	case RESET_DRIVE_COMMAND: {
-		cdrom_end_request(1, drive);
-		ide_do_reset(drive);
-		break;
-	}
+		case RESET_DRIVE_COMMAND: {
+			cdrom_end_request(1, drive);
+			return ide_do_reset(drive);
+		}
 
-	default: {
-		printk("ide-cd: bad cmd %d\n", rq -> cmd);
-		cdrom_end_request(0, drive);
-		break;
-	}
+		default: {
+			printk("ide-cd: bad cmd %d\n", rq -> cmd);
+			cdrom_end_request(0, drive);
+			return ide_stopped;
+		}
 	}
 }
 
@@ -2367,8 +2394,13 @@
 
 	if (drive->using_dma) {
 		if ((drive->id->field_valid & 4) &&
-		    (drive->id->dma_ultra & (drive->id->dma_ultra >> 8) & 7)) {
-			printk(", UDMA");	/* UDMA BIOS-enabled! */
+		    (drive->id->word93 & 0x2000) &&
+		    (HWIF(drive)->udma_four) &&
+		    (drive->id->dma_ultra & (drive->id->dma_ultra >> 11) & 3)) {
+			printk(", UDMA(66)");	/* UDMA BIOS-enabled! */
+		} else if ((drive->id->field_valid & 4) &&
+			   (drive->id->dma_ultra & (drive->id->dma_ultra >> 8) & 7)) {
+			printk(", UDMA(33)");	/* UDMA BIOS-enabled! */
 		} else if (drive->id->field_valid & 4) {
 			printk(", (U)DMA");	/* Can be BIOS-enabled! */
 		} else {
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.3.27/linux/drivers/block/ide-disk.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/block/ide-disk.c	Fri Nov 12 10:12:11 1999
@@ -133,7 +133,7 @@
 /*
  * read_intr() is the handler for disk read/multread interrupts
  */
-static void read_intr (ide_drive_t *drive)
+static ide_startstop_t read_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
@@ -141,8 +141,7 @@
 	struct request *rq;
 
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		ide_error(drive, "read_intr", stat);
-		return;
+		return ide_error(drive, "read_intr", stat);
 	}
 	msect = drive->mult_count;
 	
@@ -154,12 +153,6 @@
 		msect -= nsect;
 	} else
 		nsect = 1;
-	/*
-	 * PIO input can take longish times, so we drop the spinlock.
-	 * On SMP, bad things might happen if syscall level code adds
-	 * a new request while we do this PIO, so we just freeze all
-	 * request queue handling while doing the PIO. FIXME
-	 */
 	idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
 #ifdef DEBUG
 	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
@@ -176,21 +169,24 @@
 		if (msect)
 			goto read_next;
 		ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
+                return ide_started;
 	}
+        return ide_stopped;
 }
 
 /*
  * write_intr() is the handler for disk write interrupts
  */
-static void write_intr (ide_drive_t *drive)
+static ide_startstop_t write_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = hwgroup->rq;
-	int error = 0;
 
-	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+	if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
+        } else {
 #ifdef DEBUG
 		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
 			drive->name, rq->sector, (unsigned long) rq->buffer,
@@ -207,26 +203,30 @@
 			if (i > 0) {
 				idedisk_output_data (drive, rq->buffer, SECTOR_WORDS);
 				ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
+                                return ide_started;
 			}
-			goto out;
+                        return ide_stopped;
 		}
-	} else
-		error = 1;
-out:
-	if (error)
-		ide_error(drive, "write_intr", stat);
+                printk("%s: write_intr error2: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
+        }
+	return ide_error(drive, "write_intr", stat);
 }
 
 /*
  * ide_multwrite() transfers a block of up to mcount sectors of data
  * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 if successful;  returns 1 if request had to be aborted due to corrupted buffer list.
  */
-void ide_multwrite (ide_drive_t *drive, unsigned int mcount)
+int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
 {
-	struct request *rq = &HWGROUP(drive)->wrq;
+ 	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
+ 	struct request	*rq = &hwgroup->wrq;
+
+  	do {
+ 		unsigned long flags;
+  		unsigned int nsect = rq->current_nr_sectors;
 
-	do {
-		unsigned int nsect = rq->current_nr_sectors;
 		if (nsect > mcount)
 			nsect = mcount;
 		mcount -= nsect;
@@ -237,6 +237,7 @@
 			drive->name, rq->sector, (unsigned long) rq->buffer,
 			nsect, rq->nr_sectors - nsect);
 #endif
+		spin_lock_irqsave(&io_request_lock, flags);	/* Is this really necessary? */
 #ifdef CONFIG_BLK_DEV_PDC4030
 		rq->sector += nsect;
 #endif
@@ -247,32 +248,36 @@
 				rq->current_nr_sectors = rq->bh->b_size>>9;
 				rq->buffer             = rq->bh->b_data;
 			} else {
-				panic("%s: buffer list corrupted\n", drive->name);
-				break;
+				spin_unlock_irqrestore(&io_request_lock, flags);
+				printk("%s: buffer list corrupted\n", drive->name);
+				ide_end_request(0, hwgroup);
+				return 1;
 			}
 		} else {
 			rq->buffer += nsect << 9;
 		}
+                spin_unlock_irqrestore(&io_request_lock, flags);
 	} while (mcount);
+        return 0;
 }
 
 /*
  * multwrite_intr() is the handler for disk multwrite interrupts
  */
-static void multwrite_intr (ide_drive_t *drive)
+static ide_startstop_t multwrite_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = &hwgroup->wrq;
-	int error = 0;
 
 	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
 		if (stat & DRQ_STAT) {
 			if (rq->nr_sectors) {
-				ide_multwrite(drive, drive->mult_count);
+				if (ide_multwrite(drive, drive->mult_count))
+					return ide_stopped;
 				ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
-				goto out;
+				return ide_started;
 			}
 		} else {
 			if (!rq->nr_sectors) {	/* all done? */
@@ -281,20 +286,17 @@
 					i -= rq->current_nr_sectors;
 					ide_end_request(1, hwgroup);
 				}
-				goto out;
+				return ide_stopped;
 			}
 		}
-	} else
-		error = 1;
-out:
-	if (error)
-		ide_error(drive, "multwrite_intr", stat);
+	}
+	return ide_error(drive, "multwrite_intr", stat);
 }
 
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
-static void set_multmode_intr (ide_drive_t *drive)
+static ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
 
@@ -309,28 +311,31 @@
 		drive->special.b.recalibrate = 1;
 		(void) ide_dump_status(drive, "set_multmode", stat);
 	}
+	return ide_stopped;
 }
 
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
-static void set_geometry_intr (ide_drive_t *drive)
+static ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
 
 	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		ide_error(drive, "set_geometry_intr", stat);
+		return ide_error(drive, "set_geometry_intr", stat);
+	return ide_stopped;
 }
 
 /*
  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
-static void recal_intr (ide_drive_t *drive)
+static ide_startstop_t recal_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
 
 	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		ide_error(drive, "recal_intr", stat);
+		return ide_error(drive, "recal_intr", stat);
+	return ide_stopped;
 }
 
 /*
@@ -338,7 +343,7 @@
  * using LBA if supported, or CHS otherwise, to address sectors.
  * It also takes care of issuing special DRIVE_CMDs.
  */
-static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
@@ -375,45 +380,61 @@
 	}
 #ifdef CONFIG_BLK_DEV_PDC4030
 	if (IS_PDC4030_DRIVE) {
-		extern void do_pdc4030_io(ide_drive_t *, struct request *);
-		do_pdc4030_io (drive, rq);
-		return;
+		extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
+		return do_pdc4030_io (drive, rq);
 	}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 	if (rq->cmd == READ) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
-			return;
+			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
 		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
-		return;
+		return ide_started;
 	}
 	if (rq->cmd == WRITE) {
+		ide_startstop_t startstop;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
-			return;
+			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
-		if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
 			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
 				drive->mult_count ? "MULTWRITE" : "WRITE");
-			return;
+			return startstop;
 		}
 		if (!drive->unmask)
 			__cli();	/* local CPU only */
 		if (drive->mult_count) {
-			HWGROUP(drive)->wrq = *rq; /* scratchpad */
+			ide_hwgroup_t *hwgroup = HWGROUP(drive);
+			/*
+			 * Ugh.. this part looks ugly because we MUST set up
+			 * the interrupt handler before outputting the first block
+			 * of data to be written.  If we hit an error (corrupted buffer list)
+			 * in ide_multwrite(), then we need to remove the handler/timer
+			 * before returning.  Fortunately, this NEVER happens (right?).
+			 */
+			hwgroup->wrq = *rq; /* scratchpad */
 			ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
-			ide_multwrite(drive, drive->mult_count);
+			if (ide_multwrite(drive, drive->mult_count)) {
+				unsigned long flags;
+				spin_lock_irqsave(&io_request_lock, flags);
+				hwgroup->handler = NULL;
+				del_timer(&hwgroup->timer);
+				spin_unlock_irqrestore(&io_request_lock, flags);
+				return ide_stopped;
+			}
 		} else {
 			ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
 			idedisk_output_data(drive, rq->buffer, SECTOR_WORDS);
 		}
-		return;
+		return ide_started;
 	}
 	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
 	ide_end_request(0, HWGROUP(drive));
+	return ide_stopped;
 }
 
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
@@ -472,7 +493,7 @@
 	return (drive->capacity - drive->sect0);
 }
 
-static void idedisk_special (ide_drive_t *drive)
+static ide_startstop_t idedisk_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
 
@@ -498,7 +519,9 @@
 		int special = s->all;
 		s->all = 0;
 		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);
+		return ide_stopped;
 	}
+	return IS_PDC4030_DRIVE ? ide_stopped : ide_started;
 }
 
 static void idedisk_pre_reset (ide_drive_t *drive)
@@ -620,7 +643,7 @@
 		return -EBUSY;
 	drive->nowerr = arg;
 	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
-	spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c
--- v2.3.27/linux/drivers/block/ide-dma.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/block/ide-dma.c	Fri Nov 12 10:12:11 1999
@@ -186,7 +186,7 @@
 /*
  * dma_intr() is the handler for disk read/write DMA interrupts
  */
-void ide_dma_intr (ide_drive_t *drive)
+ide_startstop_t ide_dma_intr (ide_drive_t *drive)
 {
 	int i;
 	byte stat, dma_stat;
@@ -201,12 +201,11 @@
 				i -= rq->current_nr_sectors;
 				ide_end_request(1, HWGROUP(drive));
 			}
-			return;
+			return ide_stopped;
 		}
 		printk("%s: dma_intr: bad DMA status\n", drive->name);
 	}
-	ide__sti();	/* local CPU only */
-	ide_error(drive, "dma_intr", stat);
+	return ide_error(drive, "dma_intr", stat);
 }
 
 /*
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-features.c linux/drivers/block/ide-features.c
--- v2.3.27/linux/drivers/block/ide-features.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/ide-features.c	Fri Nov 12 10:12:11 1999
@@ -0,0 +1,275 @@
+/*
+ * linux/drivers/block/ide-features.c
+ *
+ *  Copyright (C) 1999  Linus Torvalds & authors (see below)
+ *  
+ *  Andre Hedrick <andre@suse.com>
+ *
+ *  Extracts if ide.c to address the evolving transfer rate code for
+ *  the SETFEATURES_XFER callouts.  Below are original authors of some or
+ *  various parts of any given function below.
+ *
+ *  Mark Lord     <mlord@pobox.com>
+ *  Gadi Oxman    <gadio@netvision.net.il>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+/*
+ *
+ */
+char *ide_xfer_verbose (byte xfer_rate)
+{
+	switch(xfer_rate) {
+		case XFER_UDMA_4:	return("UDMA 4");
+		case XFER_UDMA_3:	return("UDMA 3");
+		case XFER_UDMA_2:	return("UDMA 2");
+		case XFER_UDMA_1:	return("UDMA 1");
+		case XFER_UDMA_0:	return("UDMA 0");
+		case XFER_MW_DMA_2:	return("MW DMA 2");
+		case XFER_MW_DMA_1:	return("MW DMA 1");
+		case XFER_MW_DMA_0:	return("MW DMA 0");
+		case XFER_SW_DMA_2:	return("SW DMA 2");
+		case XFER_SW_DMA_1:	return("SW DMA 1");
+		case XFER_SW_DMA_0:	return("SW DMA 0");
+		case XFER_PIO_4:	return("PIO 4");
+		case XFER_PIO_3:	return("PIO 3");
+		case XFER_PIO_2:	return("PIO 2");
+		case XFER_PIO_1:	return("PIO 1");
+		case XFER_PIO_0:	return("PIO 0");
+		case XFER_PIO_SLOW:	return("PIO SLOW");
+		default:		return("XFER ERROR");
+	}
+}
+
+/*
+ *
+ */
+char *ide_media_verbose (ide_drive_t *drive)
+{
+	switch (drive->media) {
+		case ide_disk:		return("disk  ");
+		case ide_cdrom:		return("cdrom ");
+		case ide_tape:		return("tape  ");
+		case ide_floppy:	return("floppy");
+		default:		return("??????");
+	}
+}
+
+int ide_driveid_update (ide_drive_t *drive)
+{
+	/*
+	 * Re-read drive->id for possible DMA mode
+	 * change (copied from ide-probe.c)
+	 */
+	struct hd_driveid *id;
+	unsigned long timeout, irqs, flags;
+
+	probe_irq_off(probe_irq_on());
+	irqs = probe_irq_on();
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+	ide_delay_50ms();
+	OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
+	timeout = jiffies + WAIT_WORSTCASE;
+	do {
+		if (0 < (signed long)(jiffies - timeout)) {
+			if (irqs)
+				(void) probe_irq_off(irqs);
+			return 0;	/* drive timed-out */
+		}
+		ide_delay_50ms();	/* give drive a breather */
+	} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
+	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
+	if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT))
+		return 0;
+	__save_flags(flags);	/* local CPU only */
+	__cli();		/* local CPU only; some systems need this */
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	ide_input_data(drive, id, SECTOR_WORDS);
+	(void) GET_STAT();	/* clear drive IRQ */
+	ide__sti();		/* local CPU only */
+	__restore_flags(flags);	/* local CPU only */
+	ide_fix_driveid(id);
+	if (id && id->cyls) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+#ifdef DEBUG
+		printk("%s: dma_ultra=%04X, dma_mword=%04X, dma_1word=%04X\n",
+			drive->name, id->dma_ultra, id->dma_mword, id->dma_1word);
+#endif
+		kfree(id);
+	}
+	return 1;
+}
+
+/*
+ * Similar to ide_wait_stat(), except it never calls ide_error internally.
+ * This is a kludge to handle the new ide_config_drive_speed() function,
+ * and should not otherwise be used anywhere.  Eventually, the tuneproc's
+ * should be updated to return ide_startstop_t, in which case we can get
+ * rid of this abomination again.  :)   -ml
+ */
+int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
+{
+	byte stat;
+	int i;
+	unsigned long flags;
+
+	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
+	if ((stat = GET_STAT()) & BUSY_STAT) {
+		__save_flags(flags);	/* local CPU only */
+		ide__sti();	/* local CPU only */
+		timeout += jiffies;
+		while ((stat = GET_STAT()) & BUSY_STAT) {
+			if (0 < (signed long)(jiffies - timeout)) {
+				__restore_flags(flags);	/* local CPU only */
+				(void)ide_dump_status(drive, "ide_wait_noerr", stat);
+				return 1;
+			}
+		}
+		__restore_flags(flags); /* local CPU only */
+	}
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = GET_STAT()), good, bad))
+			return 0;
+	}
+	(void)ide_dump_status(drive, "ide_wait_noerr", stat);
+	return 1;
+}
+
+
+/*
+ * Verify that we are doing an approved SETFEATURES_XFER with respect
+ * to the hardware being able to support request.  Since some hardware
+ * can improperly report capabilties, we check to see if the host adapter
+ * in combination with the device (usually a disk) properly detect
+ * and acknowledge each end of the ribbon.
+ */
+int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature)
+{
+	if ((cmd == WIN_SETFEATURES) &&
+	    (nsect > XFER_UDMA_2) &&
+	    (feature == SETFEATURES_XFER)) {
+		if (!HWIF(drive)->udma_four) {
+			printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name);
+			return 1;
+		}
+		if ((drive->id->word93 & 0x2000) == 0) {
+			printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
+ * 1 : Safe to update drive->id DMA registers.
+ * 0 : OOPs not allowed.
+ */
+int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature)
+{
+	struct hd_driveid *id = drive->id;
+
+	if ((cmd == WIN_SETFEATURES) &&
+	    (nsect >= XFER_SW_DMA_0) &&
+	    (feature == SETFEATURES_XFER) &&
+	    (id->dma_ultra || id->dma_mword || id->dma_1word))
+		return 1;
+	return 0;
+}
+
+int ide_config_drive_speed (ide_drive_t *drive, byte speed)
+{
+	unsigned long flags;
+	int err;
+	byte stat;
+
+	__save_flags(flags);	/* local CPU only */
+	__cli();		/* local CPU only */
+
+	/*
+	 * Don't use ide_wait_cmd here - it will
+	 * attempt to set_geometry and recalibrate,
+	 * but for some reason these don't work at
+	 * this point (lost interrupt).
+	 */
+	SELECT_DRIVE(HWIF(drive), drive);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
+	OUT_BYTE(speed, IDE_NSECTOR_REG);
+	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+
+	err = ide_wait_noerr(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
+
+#if 0
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+#endif
+
+	__restore_flags(flags);	/* local CPU only */
+
+	stat = GET_STAT();
+	if (stat != DRIVE_READY)
+		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
+
+	drive->id->dma_ultra &= ~0xFF00;
+	drive->id->dma_mword &= ~0x0F00;
+	drive->id->dma_1word &= ~0x0F00;
+
+	switch(speed) {
+		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+		default: break;
+	}
+	return(err);
+}
+
+EXPORT_SYMBOL(ide_driveid_update);
+EXPORT_SYMBOL(ide_wait_noerr);
+EXPORT_SYMBOL(ide_ata66_check);
+EXPORT_SYMBOL(set_transfer);
+EXPORT_SYMBOL(ide_config_drive_speed);
+
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.3.27/linux/drivers/block/ide-floppy.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/block/ide-floppy.c	Fri Nov 12 10:12:11 1999
@@ -830,7 +830,7 @@
  *	idefloppy_pc_intr is the usual interrupt handler which will be called
  *	during a packet command.
  */
-static void idefloppy_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_status_reg_t status;
@@ -875,24 +875,22 @@
 			rq->errors++;
 			if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
 				printk (KERN_ERR "ide-floppy: I/O error in request sense command\n");
-				ide_do_reset (drive);
-				return;
+				return ide_do_reset (drive);
 			}
 			idefloppy_retry_pc (drive);				/* Retry operation */
-			return;
+			return ide_stopped; /* queued, but not started */
 		}
 		pc->error = 0;
 		if (floppy->failed_pc == pc)
 			floppy->failed_pc=NULL;
 		pc->callback(drive);			/* Command finished - Call the callback function */
-		return;
+		return ide_stopped;
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
 		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
@@ -901,14 +899,12 @@
 
 	if (ireason.b.cod) {
 		printk (KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
 		printk (KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read");
 		printk (KERN_ERR "but the floppy wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
@@ -917,7 +913,7 @@
 				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
 				idefloppy_discard_data (drive,bcount.all);
 				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
-				return;
+				return ide_started;
 			}
 #if IDEFLOPPY_DEBUG_LOG
 			printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n");
@@ -939,31 +935,33 @@
 	pc->current_position+=bcount.all;
 
 	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+	return ide_started;
 }
 
-static void idefloppy_transfer_pc (ide_drive_t *drive)
+static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 {
+	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_ireason_reg_t ireason;
 
-	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
-		return;
+		return startstop;
 	}
 	ireason.all=IN_BYTE (IDE_IREASON_REG);
 	if (!ireason.b.cod || ireason.b.io) {
 		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
 	atapi_output_bytes (drive, floppy->pc->c, 12);		/* Send the actual packet */
+	return ide_started;
 }
 
 /*
  *	Issue a packet command
  */
-static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
+static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_bcount_reg_t bcount;
@@ -991,7 +989,7 @@
 		}
 		floppy->failed_pc=NULL;
 		pc->callback(drive);
-		return;
+		return ide_stopped;
 	}
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "Retry number - %d\n",pc->retries);
@@ -1027,9 +1025,10 @@
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
 		ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		idefloppy_transfer_pc (drive);
+		return idefloppy_transfer_pc (drive);
 	}
 }
 
@@ -1135,7 +1134,7 @@
 /*
  *	idefloppy_do_request is our request handling function.	
  */
-static void idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_pc_t *pc;
@@ -1152,7 +1151,7 @@
 		else
 			printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
 		idefloppy_end_request (0, HWGROUP(drive));
-		return;
+		return ide_stopped;
 	}
 	switch (rq->cmd) {
 		case READ:
@@ -1160,7 +1159,7 @@
 			if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
 				printk ("%s: unsupported r/w request size\n", drive->name);
 				idefloppy_end_request (0, HWGROUP(drive));
-				return;
+				return ide_stopped;
 			}
 			pc = idefloppy_next_pc_storage (drive);
 			idefloppy_create_rw_cmd (floppy, pc, rq, block);
@@ -1171,10 +1170,10 @@
 		default:
 			printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd);
 			idefloppy_end_request (0,HWGROUP (drive));
-			return;
+			return ide_stopped;
 	}
 	pc->rq = rq;
-	idefloppy_issue_pc (drive, pc);
+	return idefloppy_issue_pc (drive, pc);
 }
 
 /*
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-geometry.c linux/drivers/block/ide-geometry.c
--- v2.3.27/linux/drivers/block/ide-geometry.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/block/ide-geometry.c	Fri Nov 12 10:12:11 1999
@@ -1,6 +1,7 @@
 /*
  * linux/drivers/block/ide-geometry.c
  */
+#include <linux/config.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
@@ -65,9 +66,7 @@
 			drive->head  = drive->bios_head = *(BIOS+2);
 			drive->sect  = drive->bios_sect = *(BIOS+14);
 			drive->ctl   = *(BIOS+8);
-#if 0
 			drive->present = 1;
-#endif
 		}
 		BIOS += 16;
 	}
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.3.27/linux/drivers/block/ide-pci.c	Fri Oct 22 13:21:47 1999
+++ linux/drivers/block/ide-pci.c	Fri Nov 12 10:12:11 1999
@@ -49,6 +49,7 @@
 #define DEVID_HT6565	((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
 #define DEVID_AEC6210	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP850UF})
 #define DEVID_W82C105	((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
+#define DEVID_UM8673F	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8673F})
 #define DEVID_UM8886A	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
 #define DEVID_UM8886BF	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
 #define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
@@ -61,66 +62,17 @@
 
 #define	IDE_IGNORE	((void *)-1)
 
-#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(ide_hwif_t *);
-#define INIT_TRM290	&ide_init_trm290
-#else
-#define INIT_TRM290	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(ide_hwif_t *);
-#define INIT_OPTI621	&ide_init_opti621
-#else
-#define INIT_OPTI621	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_NS87415
-extern void ide_init_ns87415(ide_hwif_t *);
-#define INIT_NS87415	&ide_init_ns87415
-#else
-#define INIT_NS87415	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_CMD646
-extern void ide_init_cmd646(ide_hwif_t *);
-#define INIT_CMD646	&ide_init_cmd646
-#else
-#ifdef __sparc_v9__
-#define INIT_CMD646	IDE_IGNORE
-#else
-#define INIT_CMD646	NULL
-#endif
-#endif
-
-#ifdef CONFIG_BLK_DEV_SL82C105
-extern void ide_init_sl82c105(ide_hwif_t *);
-#define INIT_W82C105	&ide_init_sl82c105
-#else
-#define INIT_W82C105	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_init_rz1000(ide_hwif_t *);
-#define INIT_RZ1000	&ide_init_rz1000
-#else
-#define INIT_RZ1000	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
-extern unsigned int ata66_via82cxxx(ide_hwif_t *);
-extern void ide_init_via82cxxx(ide_hwif_t *);
-extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
-#define PCI_VIA82CXXX	&pci_init_via82cxxx
-#define ATA66_VIA82CXXX	&ata66_via82cxxx
-#define INIT_VIA82CXXX	&ide_init_via82cxxx
-#define DMA_VIA82CXXX	&ide_dmacapable_via82cxxx
+#ifdef CONFIG_BLK_DEV_AEC6210
+extern unsigned int pci_init_aec6210(struct pci_dev *, const char *);
+extern void ide_init_aec6210(ide_hwif_t *);
+extern void ide_dmacapable_aec6210(ide_hwif_t *, unsigned long);
+#define PCI_AEC6210	&pci_init_aec6210
+#define INIT_AEC6210	&ide_init_aec6210
+#define DMA_AEC6210	&ide_dmacapable_aec6210
 #else
-#define PCI_VIA82CXXX	NULL
-#define ATA66_VIA82CXXX	NULL
-#define INIT_VIA82CXXX	NULL
-#define DMA_VIA82CXXX	NULL
+#define PCI_AEC6210	NULL
+#define INIT_AEC6210	NULL
+#define DMA_AEC6210	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_ALI15X3
@@ -139,6 +91,17 @@
 #define DMA_ALI15X3	NULL
 #endif
 
+#ifdef CONFIG_BLK_DEV_CMD646
+extern void ide_init_cmd646(ide_hwif_t *);
+#define INIT_CMD646	&ide_init_cmd646
+#else
+#ifdef __sparc_v9__
+#define INIT_CMD646	IDE_IGNORE
+#else
+#define INIT_CMD646	NULL
+#endif
+#endif
+
 #ifdef CONFIG_BLK_DEV_CY82C693
 extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
 extern void ide_init_cy82c693(ide_hwif_t *);
@@ -149,32 +112,7 @@
 #define INIT_CY82C693	NULL
 #endif
 
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
-extern unsigned int ata66_pdc202xx(ide_hwif_t *);
-extern void ide_init_pdc202xx(ide_hwif_t *);
-#define PCI_PDC202XX	&pci_init_pdc202xx
-#define ATA66_PDC202XX	&ata66_pdc202xx
-#define INIT_PDC202XX	&ide_init_pdc202xx
-#else
-#define PCI_PDC202XX	NULL
-#define ATA66_PDC202XX	NULL
-#define INIT_PDC202XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_PIIX
-extern void ide_init_piix(ide_hwif_t *);
-#define INIT_PIIX	&ide_init_piix
-#else
-#define INIT_PIIX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_AEC6210
-extern unsigned int pci_init_aec6210(struct pci_dev *, const char *);
-#define PCI_AEC6210	&pci_init_aec6210
-#else
-#define PCI_AEC6210	NULL
-#endif
+#define INIT_CX5530	NULL
 
 #ifdef CONFIG_BLK_DEV_HPT34X
 extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
@@ -204,6 +142,52 @@
 #define DMA_HPT366	NULL
 #endif
 
+#ifdef CONFIG_BLK_DEV_NS87415
+extern void ide_init_ns87415(ide_hwif_t *);
+#define INIT_NS87415	&ide_init_ns87415
+#else
+#define INIT_NS87415	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_OPTI621
+extern void ide_init_opti621(ide_hwif_t *);
+#define INIT_OPTI621	&ide_init_opti621
+#else
+#define INIT_OPTI621	NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_PDC202XX
+extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
+extern unsigned int ata66_pdc202xx(ide_hwif_t *);
+extern void ide_init_pdc202xx(ide_hwif_t *);
+#define PCI_PDC202XX	&pci_init_pdc202xx
+#define ATA66_PDC202XX	&ata66_pdc202xx
+#define INIT_PDC202XX	&ide_init_pdc202xx
+#else
+#define PCI_PDC202XX	NULL
+#define ATA66_PDC202XX	NULL
+#define INIT_PDC202XX	NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_PIIX
+extern unsigned int pci_init_piix(struct pci_dev *, const char *);
+extern void ide_init_piix(ide_hwif_t *);
+#define PCI_PIIX	&pci_init_piix
+#define INIT_PIIX	&ide_init_piix
+#else
+#define PCI_PIIX	NULL
+#define INIT_PIIX	NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_RZ1000
+extern void ide_init_rz1000(ide_hwif_t *);
+#define INIT_RZ1000	&ide_init_rz1000
+#else
+#define INIT_RZ1000	IDE_IGNORE
+#endif
+
+#define INIT_SAMURAI	NULL
+
 #ifdef CONFIG_BLK_DEV_SIS5513
 extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
 extern unsigned int ata66_sis5513(ide_hwif_t *);
@@ -217,8 +201,35 @@
 #define INIT_SIS5513	NULL
 #endif
 
-#define INIT_SAMURAI	NULL
-#define INIT_CX5530	NULL
+#ifdef CONFIG_BLK_DEV_SL82C105
+extern void ide_init_sl82c105(ide_hwif_t *);
+#define INIT_W82C105	&ide_init_sl82c105
+#else
+#define INIT_W82C105	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_TRM290
+extern void ide_init_trm290(ide_hwif_t *);
+#define INIT_TRM290	&ide_init_trm290
+#else
+#define INIT_TRM290	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
+extern unsigned int ata66_via82cxxx(ide_hwif_t *);
+extern void ide_init_via82cxxx(ide_hwif_t *);
+extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
+#define PCI_VIA82CXXX	&pci_init_via82cxxx
+#define ATA66_VIA82CXXX	&ata66_via82cxxx
+#define INIT_VIA82CXXX	&ide_init_via82cxxx
+#define DMA_VIA82CXXX	&ide_dmacapable_via82cxxx
+#else
+#define PCI_VIA82CXXX	NULL
+#define ATA66_VIA82CXXX	NULL
+#define INIT_VIA82CXXX	NULL
+#define DMA_VIA82CXXX	NULL
+#endif
 
 typedef struct ide_pci_enablebit_s {
 	byte	reg;	/* byte pci reg holding the enable-bit */
@@ -241,8 +252,8 @@
 static ide_pci_device_t ide_pci_chipsets[] __initdata = {
 	{DEVID_PIIXa,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
 	{DEVID_PIIXb,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX3,	"PIIX3",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4,	"PIIX4",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_PIIX3,	"PIIX3",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_PIIX4,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
 	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
 	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
@@ -260,12 +271,13 @@
 	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	PCI_AEC6210,	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	OFF_BOARD,	0 },
+	{DEVID_AEC6210,	"AEC6210",	PCI_AEC6210,	NULL,		INIT_AEC6210,	DMA_AEC6210,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	OFF_BOARD,	0 },
 	{DEVID_W82C105,	"W82C105",	NULL,		NULL,		INIT_W82C105,	NULL,		{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
+	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
-	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	256 },
+	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240 },
 	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -549,7 +561,8 @@
 			}
 		}
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF)) {
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) {
 			hwif->irq = hwif->channel ? 15 : 14;
 			goto bypass_umc_dma;
 		}
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.3.27/linux/drivers/block/ide-probe.c	Fri Oct 22 13:21:47 1999
+++ linux/drivers/block/ide-probe.c	Fri Nov 12 10:12:11 1999
@@ -402,7 +402,7 @@
 	if (hwif->noprobe)
 		return;
 	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) {
-		extern void probe_cmos_for_drives(ide_hwif_t *hwif);
+		extern void probe_cmos_for_drives(ide_hwif_t *);
 
 		probe_cmos_for_drives (hwif);
 	}
@@ -575,10 +575,6 @@
 		hwgroup->handler  = NULL;
 		hwgroup->drive    = NULL;
 		hwgroup->busy     = 0;
-		hwgroup->spinlock = (spinlock_t)SPIN_LOCK_UNLOCKED;
-#if (DEBUG_SPINLOCK > 0)
-		printk("hwgroup(%s) spinlock is %p\n", hwif->name,  &hwgroup->spinlock);	/* FIXME */
-#endif
 		init_timer(&hwgroup->timer);
 		hwgroup->timer.function = &ide_timer_expiry;
 		hwgroup->timer.data = (unsigned long) hwgroup;
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c
--- v2.3.27/linux/drivers/block/ide-proc.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/block/ide-proc.c	Fri Nov 12 10:12:11 1999
@@ -78,6 +78,11 @@
 int (*ali_display_info)(char *, char **, off_t, int, int) = NULL;
 #endif /* CONFIG_BLK_DEV_ALI15X3 */
 
+#ifdef CONFIG_BLK_DEV_PIIX
+extern byte piix_proc;
+int (*piix_display_info)(char *, char **, off_t, int, int) = NULL;
+#endif /* CONFIG_BLK_DEV_PIIX */
+
 #ifdef CONFIG_BLK_DEV_SIS5513
 extern byte sis_proc;
 int (*sis_display_info)(char *, char **, off_t, int, int) = NULL;
@@ -372,6 +377,8 @@
 		case ide_pdc4030:	name = "pdc4030";	break;
 		case ide_rz1000:	name = "rz1000";	break;
 		case ide_trm290:	name = "trm290";	break;
+		case ide_cmd646:	name = "cmd646";	break;
+		case ide_cy82c693:	name = "cy82c693";	break;
 		case ide_4drives:	name = "4drives";	break;
 		default:		name = "(unknown)";	break;
 	}
@@ -752,7 +759,6 @@
 	for (h = 0; h < MAX_HWIFS; h++) {
 		ide_hwif_t *hwif = &ide_hwifs[h];
 		int exist = (hwif->proc != NULL);
-
 #if 0
 		if (!hwif->present)
 			continue;
@@ -781,6 +787,10 @@
 	if ((ali_display_info) && (ali_proc))
 		create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
 #endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_PIIX
+	if ((piix_display_info) && (piix_proc))
+		create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info);
+#endif /* CONFIG_BLK_DEV_PIIX */
 #ifdef CONFIG_BLK_DEV_SIS5513
 	if ((sis_display_info) && (sis_proc))
 		create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info);
@@ -801,6 +811,10 @@
 	if ((ali_display_info) && (ali_proc))
 		remove_proc_entry("ide/ali",0);
 #endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_PIIX
+	if ((piix_display_info) && (piix_proc))
+		remove_proc_entry("ide/piix",0);
+#endif /* CONFIG_BLK_DEV_PIIX */
 #ifdef CONFIG_BLK_DEV_SIS5513
 	if ((sis_display_info) && (sis_proc))
 		remove_proc_entry("ide/sis", 0);
@@ -809,6 +823,7 @@
 	if ((via_display_info) && (via_proc))
 		remove_proc_entry("ide/via",0);
 #endif /* CONFIG_BLK_DEV_VIA82CXXX */
+
 	remove_proc_entry("ide/drivers", 0);
 	destroy_proc_ide_interfaces();
 	remove_proc_entry("ide", 0);
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.3.27/linux/drivers/block/ide-tape.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/block/ide-tape.c	Fri Nov 12 10:12:11 1999
@@ -526,7 +526,7 @@
 	int b_count;
 	byte *buffer;				/* Data buffer */
 	byte *current_position;			/* Pointer into the above buffer */
-	void (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
+	ide_startstop_t (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
 	byte pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned int flags;			/* Status/Action bit flags */
 } idetape_pc_t;
@@ -1660,7 +1660,7 @@
 	}
 }
 
-static void idetape_request_sense_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -1674,6 +1674,7 @@
 		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
 		idetape_end_request (0,HWGROUP (drive));
 	}
+	return ide_stopped;
 }
 
 /*
@@ -1705,7 +1706,7 @@
  *	last packet command. We queue a request sense packet command in
  *	the head of the request list.
  */
-static void idetape_retry_pc (ide_drive_t *drive)
+static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
@@ -1718,6 +1719,7 @@
 	idetape_create_request_sense_cmd (pc);
 	set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
 	idetape_queue_pc_head (drive, pc, rq);
+	return ide_stopped;
 }
 
 /*
@@ -1728,7 +1730,7 @@
  *	algorithm described before idetape_issue_packet_command.
  *
  */
-static void idetape_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_status_reg_t status;
@@ -1784,11 +1786,9 @@
 #endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
 				printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
-				ide_do_reset (drive);
-				return;
+				return ide_do_reset (drive);
 			}
-			idetape_retry_pc (drive);				/* Retry operation */
-			return;
+			return idetape_retry_pc (drive);		/* Retry operation */
 		}
 		pc->error = 0;
 		if (test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {	/* Media access command */
@@ -1796,20 +1796,18 @@
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
 			idetape_postpone_request (drive);		/* Allow ide.c to handle other requests */
-			return;
+			return ide_stopped;
 		}
 		if (tape->failed_pc == pc)
 			tape->failed_pc=NULL;
-		pc->callback(drive);			/* Command finished - Call the callback function */
-		return;
+		return pc->callback(drive);			/* Command finished - Call the callback function */
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
 		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
 		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
@@ -1818,14 +1816,12 @@
 
 	if (ireason.b.cod) {
 		printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
 		printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
 		printk (KERN_ERR "but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
@@ -1834,7 +1830,7 @@
 				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
 				idetape_discard_data (drive,bcount.all);
 				ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL);
-				return;
+				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
 			printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
@@ -1856,6 +1852,7 @@
 	pc->current_position+=bcount.all;
 
 	ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL);		/* And set the interrupt handler again */
+	return ide_started;
 }
 
 /*
@@ -1901,16 +1898,17 @@
  *
  */
 
-static void idetape_transfer_pc(ide_drive_t *drive)
+static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
 	idetape_ireason_reg_t ireason;
 	int retries = 100;
+	ide_startstop_t startstop;
 
-	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
-		return;
+		return startstop;
 	}
 	ireason.all=IN_BYTE (IDE_IREASON_REG);
 	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
@@ -1925,14 +1923,14 @@
 	}
 	if (!ireason.b.cod || ireason.b.io) {
 		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
 	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
+	return ide_started;
 }
 
-static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
+static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_bcount_reg_t bcount;
@@ -1961,8 +1959,7 @@
 			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
 		}
 		tape->failed_pc=NULL;
-		pc->callback(drive);
-		return;
+		return pc->callback(drive);
 	}
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "Retry number - %d\n",pc->retries);
@@ -1997,13 +1994,14 @@
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
 		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return ide_started;
 	} else {
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		idetape_transfer_pc(drive);
+		return idetape_transfer_pc(drive);
 	}
 }
 
-static void idetape_media_access_finished (ide_drive_t *drive)
+static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
@@ -2013,8 +2011,7 @@
 	if (status.b.dsc) {
 		if (status.b.check) {					/* Error detected */
 			printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
-			idetape_retry_pc (drive);			/* Retry operation */
-			return;
+			return idetape_retry_pc (drive);		/* Retry operation */
 		}
 		pc->error = 0;
 		if (tape->failed_pc == pc)
@@ -2023,13 +2020,13 @@
 		pc->error = IDETAPE_ERROR_GENERAL;
 		tape->failed_pc = NULL;
 	}
-	pc->callback (drive);
+	return pc->callback (drive);
 }
 
 /*
  *	General packet command callback function.
  */
-static void idetape_pc_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	
@@ -2038,9 +2035,10 @@
 #endif /* IDETAPE_DEBUG_LOG */
 
 	idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive));
+	return ide_stopped;
 }
 
-static void idetape_rw_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -2057,6 +2055,7 @@
 		idetape_end_request (1, HWGROUP (drive));
 	else
 		idetape_end_request (tape->pc->error, HWGROUP (drive));
+	return ide_stopped;
 }
 
 static void idetape_create_locate_cmd (idetape_pc_t *pc, unsigned int block, byte partition)
@@ -2175,7 +2174,7 @@
 		set_bit (PC_DMA_RECOMMENDED, &pc->flags);
 }
 
-static void idetape_read_position_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_read_position_result_t *result;
@@ -2205,6 +2204,7 @@
 		}
 	} else
 		idetape_end_request (0,HWGROUP (drive));
+	return ide_stopped;
 }
 
 static void idetape_create_read_position_cmd (idetape_pc_t *pc)
@@ -2218,7 +2218,7 @@
 /*
  *	idetape_do_request is our request handling function.	
  */
-static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
@@ -2234,24 +2234,23 @@
 		/*
 		 *	We do not support buffer cache originated requests.
 		 */
-		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue\n", drive->name);
+		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
 		ide_end_request (0,HWGROUP (drive));			/* Let the common code handle it */
-		return;
+		return ide_stopped;
 	}
 
 	/*
 	 *	Retry a failed packet command
 	 */
 	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		idetape_issue_packet_command (drive, tape->failed_pc);
-		return;
+		return idetape_issue_packet_command (drive, tape->failed_pc);
 	}
 #if IDETAPE_DEBUG_BUGS
 	if (postponed_rq != NULL)
 		if (rq != postponed_rq) {
 			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
 			idetape_end_request (0,HWGROUP (drive));
-			return;
+			return ide_stopped;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 
@@ -2271,15 +2270,16 @@
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
 			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
-			if (rq->cmd == IDETAPE_PC_RQ2)
+			if (rq->cmd == IDETAPE_PC_RQ2) {
 				idetape_media_access_finished (drive);
-			else
-				ide_do_reset (drive);
-			return;
+				return ide_stopped;
+			} else {
+				return ide_do_reset (drive);
+			}
 		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
 		idetape_postpone_request (drive);
-		return;
+		return ide_stopped;
 	}
 	switch (rq->cmd) {
 		case IDETAPE_READ_RQ:
@@ -2294,20 +2294,20 @@
 			rq->cmd = IDETAPE_WRITE_RQ;
 			rq->errors = IDETAPE_ERROR_EOD;
 			idetape_end_request (1, HWGROUP(drive));
-			return;
+			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc=(idetape_pc_t *) rq->buffer;
 			rq->cmd = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
 			idetape_media_access_finished (drive);
-			return;
+			return ide_stopped;
 		default:
 			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
 			idetape_end_request (0,HWGROUP (drive));
-			return;
+			return ide_stopped;
 	}
-	idetape_issue_packet_command (drive, pc);
+	return idetape_issue_packet_command (drive, pc);
 }
 
 /*
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.3.27/linux/drivers/block/ide.c	Thu Nov 11 20:11:32 1999
+++ linux/drivers/block/ide.c	Fri Nov 12 10:12:11 1999
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c		Version 6.20	July 10, 1999
+ *  linux/drivers/block/ide.c		Version 6.21	November 9, 1999
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -106,15 +106,18 @@
  *			  ATA-66 compliant, but have yet to determine a method
  *			  of verification of the 80c cable presence.
  *			  Specifically Promise's PDC20262 chipset.
+ * Version 6.21		Fixing/Fixed SMP spinlock issue with insight from an old
+ *			  hat that clarified original low level driver design.
  *
  *  Some additional driver compile-time options are in ./include/linux/ide.h
  *
  *  To do, in likely order of completion:
  *	- modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
-*/
+ *
+ */
 
-#define	REVISION	"Revision: 6.20"
-#define	VERSION		"Id: ide.c 6.20 1999/07/10"
+#define	REVISION	"Revision: 6.21"
+#define	VERSION		"Id: ide.c 6.21 1999/11/10"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -186,7 +189,7 @@
  * For really screwy hardware (hey, at least it *can* be used with Linux)
  * we can enforce a minimum delay time between successive operations.
  */
-static unsigned long read_timer(void)
+static unsigned long read_timer (void)
 {
 	unsigned long t, flags;
 	int i;
@@ -472,7 +475,7 @@
 #if 0
 	udelay(1);	/* need to guarantee 400ns since last command was issued */
 #endif
-	if (GET_STAT() & BUSY_STAT)
+	if (GET_STAT() & BUSY_STAT)	/* Note: this may clear a pending IRQ!! */
 		return 0;	/* drive busy:  definitely not interrupting */
 	return 1;		/* drive ready: *might* be interrupting */
 }
@@ -480,7 +483,7 @@
 /*
  * This is our end_request replacement function.
  */
-void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup)
+void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
 {
 	struct request *rq;
 	unsigned long flags;
@@ -511,18 +514,16 @@
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
-#ifdef DEBUG
+	spin_lock_irqsave(&io_request_lock, flags);
 	if (hwgroup->handler != NULL) {
 		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
 			drive->name, hwgroup->handler, handler);
 	}
-#endif
 	hwgroup->handler	= handler;
 	hwgroup->expiry		= expiry;
 	hwgroup->timer.expires	= jiffies + timeout;
-	add_timer(&(hwgroup->timer));
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+	add_timer(&hwgroup->timer);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /*
@@ -557,7 +558,7 @@
 	}
 }
 
-static void do_reset1 (ide_drive_t *, int);		/* needed below */
+static ide_startstop_t do_reset1 (ide_drive_t *, int);		/* needed below */
 
 /*
  * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
@@ -565,7 +566,7 @@
  * and we have not yet hit our maximum waiting time, then the timer is restarted
  * for another 50ms.
  */
-static void atapi_reset_pollfunc (ide_drive_t *drive)
+static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	byte stat;
@@ -578,14 +579,14 @@
 	} else {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
 			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-			return;	/* continue polling */
+			return ide_started;	/* continue polling */
 		}
 		hwgroup->poll_timeout = 0;	/* end of polling */
 		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
-		do_reset1 (drive, 1);	/* do it the old fashioned way */
-		return;
+		return do_reset1 (drive, 1);	/* do it the old fashioned way */
 	}
 	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
 }
 
 /*
@@ -594,7 +595,7 @@
  * and we have not yet hit our maximum waiting time, then the timer is restarted
  * for another 50ms.
  */
-static void reset_pollfunc (ide_drive_t *drive)
+static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	ide_hwif_t *hwif = HWIF(drive);
@@ -603,7 +604,7 @@
 	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
 			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
-			return;	/* continue polling */
+			return ide_started;	/* continue polling */
 		}
 		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
 	} else  {
@@ -635,6 +636,7 @@
 		}
 	}
 	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
 }
 
 static void pre_reset (ide_drive_t *drive)
@@ -664,7 +666,7 @@
  * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
  * we set a timer to poll at 50ms intervals.
  */
-static void do_reset1 (ide_drive_t *drive, int  do_not_try_atapi)
+static ide_startstop_t do_reset1 (ide_drive_t *drive, int  do_not_try_atapi)
 {
 	unsigned int unit;
 	unsigned long flags;
@@ -683,7 +685,7 @@
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
 		__restore_flags (flags);	/* local CPU only */
-		return;
+		return ide_started;
 	}
 
 	/*
@@ -696,7 +698,7 @@
 #if OK_TO_RESET_CONTROLLER
 	if (!IDE_CONTROL_REG) {
 		__restore_flags(flags);
-		return;
+		return ide_stopped;
 	}
 	/*
 	 * Note that we also set nIEN while resetting the device,
@@ -724,14 +726,15 @@
 #endif	/* OK_TO_RESET_CONTROLLER */
 
 	__restore_flags (flags);	/* local CPU only */
+	return ide_started;
 }
 
 /*
  * ide_do_reset() is the entry point to the drive/interface reset code.
  */
-void ide_do_reset (ide_drive_t *drive)
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
 {
-	do_reset1 (drive, 0);
+	return do_reset1 (drive, 0);
 }
 
 /*
@@ -757,11 +760,8 @@
 	HWGROUP(drive)->rq = NULL;
 	rq->rq_status = RQ_INACTIVE;
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	save_flags(flags);	/* all CPUs; overkill? */
-	cli();			/* all CPUs; overkill? */
 	if (rq->sem != NULL)
 		up(rq->sem);	/* inform originator that rq has been serviced */
-	restore_flags(flags);	/* all CPUs; overkill? */
 }
 
 /*
@@ -854,19 +854,19 @@
 /*
  * ide_error() takes action based on the error returned by the drive.
  */
-void ide_error (ide_drive_t *drive, const char *msg, byte stat)
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
 {
 	struct request *rq;
 	byte err;
 
 	err = ide_dump_status(drive, msg, stat);
 	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
-		return;
+		return ide_stopped;
 	/* retry only "normal" I/O: */
 	if (rq->cmd == IDE_DRIVE_CMD) {
 		rq->errors = 1;
 		ide_end_drive_cmd(drive, stat, err);
-		return;
+		return ide_stopped;
 	}
 	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
@@ -875,7 +875,7 @@
 			/* err has different meaning on cdrom and tape */
 			if (err == ABRT_ERR) {
 				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return;	/* some newer drives don't support WIN_SPECIFY */
+					return ide_stopped; /* some newer drives don't support WIN_SPECIFY */
 			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR))
 				; /* UDMA crc error -- just retry the operation */
 			else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
@@ -897,19 +897,20 @@
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
-			ide_do_reset(drive);
-			return;
-		} else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
 			drive->special.b.recalibrate = 1;
 		++rq->errors;
 	}
+	return ide_stopped;
 }
 
 /*
  * Issue a simple drive command
  * The drive must be selected beforehand.
  */
-void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
+void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
 {
 	ide_set_handler (drive, handler, WAIT_CMD, NULL);
 	if (IDE_CONTROL_REG)
@@ -921,7 +922,7 @@
 /*
  * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
  */
-static void drive_cmd_intr (ide_drive_t *drive)
+static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	byte *args = (byte *) rq->buffer;
@@ -938,17 +939,17 @@
 			udelay(100);
 	}
 
-	if (OK_STAT(stat, READY_STAT, BAD_STAT))
-		ide_end_drive_cmd (drive, stat, GET_ERR());
-	else
-		ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+		return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
+	ide_end_drive_cmd (drive, stat, GET_ERR());
+	return ide_stopped;
 }
 
 /*
  * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
  * commands to a drive.  It used to do much more, but has been scaled back.
  */
-static inline void do_special (ide_drive_t *drive)
+static ide_startstop_t do_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
 
@@ -961,11 +962,12 @@
 		if (tuneproc != NULL)
 			tuneproc(drive, drive->tune_req);
 	} else if (drive->driver != NULL) {
-		DRIVER(drive)->special(drive);
+		return DRIVER(drive)->special(drive);
 	} else if (s->all) {
 		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
 		s->all = 0;
 	}
+	return ide_stopped;
 }
 
 /*
@@ -979,12 +981,11 @@
  * setting a timer to wake up at half second intervals thereafter,
  * until timeout is achieved, before timing out.
  */
-int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
-{
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
 	byte stat;
 	int i;
 	unsigned long flags;
-
+ 
 	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
 	if ((stat = GET_STAT()) & BUSY_STAT) {
 		__save_flags(flags);	/* local CPU only */
@@ -993,7 +994,7 @@
 		while ((stat = GET_STAT()) & BUSY_STAT) {
 			if (0 < (signed long)(jiffies - timeout)) {
 				__restore_flags(flags);	/* local CPU only */
-				ide_error(drive, "status timeout", stat);
+				*startstop = ide_error(drive, "status timeout", stat);
 				return 1;
 			}
 		}
@@ -1011,7 +1012,7 @@
 		if (OK_STAT((stat = GET_STAT()), good, bad))
 			return 0;
 	}
-	ide_error(drive, "status error", stat);
+	*startstop = ide_error(drive, "status error", stat);
 	return 1;
 }
 
@@ -1019,7 +1020,7 @@
  * execute_drive_cmd() issues a special drive command,
  * usually initiated by ioctl() from the external hdparm program.
  */
-static void execute_drive_cmd (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
 {
 	byte *args = rq->buffer;
 	if (args) {
@@ -1033,11 +1034,11 @@
 			OUT_BYTE(args[2],IDE_FEATURE_REG);
 			OUT_BYTE(args[1],IDE_SECTOR_REG);
 			ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
-			return;
+			return ide_started;
 		}
 		OUT_BYTE(args[2],IDE_FEATURE_REG);
 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
-		return;
+		return ide_started;
 	} else {
 		/*
 		 * NULL is actually a valid way of waiting for
@@ -1047,21 +1048,21 @@
 		printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
 		ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
-		return;
+		return ide_stopped;
 	}
 }
 
 /*
  * start_request() initiates handling of a new I/O request
  */
-static inline void start_request (ide_drive_t *drive)
+static ide_startstop_t start_request (ide_drive_t *drive)
 {
+	ide_startstop_t startstop;
 	unsigned long block, blockend;
 	struct request *rq = drive->queue;
 	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	ide__sti();	/* local CPU only */
 #ifdef DEBUG
 	printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
 #endif
@@ -1094,29 +1095,27 @@
 #endif
 
 	SELECT_DRIVE(hwif, drive);
-	if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
 		printk("%s: drive not ready for command\n", drive->name);
-		return;
+		return startstop;
 	}
 	if (!drive->special.all) {
 		if (rq->cmd == IDE_DRIVE_CMD) {
-			execute_drive_cmd(drive, rq);
-			return;
+			return execute_drive_cmd(drive, rq);
 		}
 		if (drive->driver != NULL) {
-			DRIVER(drive)->do_request(drive, rq, block);
-			return;
+			return (DRIVER(drive)->do_request(drive, rq, block));
 		}
 		printk("%s: media type %d not supported\n", drive->name, drive->media);
 		goto kill_rq;
 	}
-	do_special(drive);
-	return;
+	return do_special(drive);
 kill_rq:
 	if (drive->driver != NULL)
 		DRIVER(drive)->end_request(0, HWGROUP(drive));
 	else
 		ide_end_request(0, HWGROUP(drive));
+	return ide_stopped;
 }
 
 /*
@@ -1177,22 +1176,54 @@
 }
 
 /*
- * Caller must have already acquired spinlock using *spinflags 
+ * Issue a new request to a drive from hwgroup
+ * Caller must have already done spin_lock_irqsave(&io_request_lock, ..);
+ *
+ * A hwgroup is a serialized group of IDE interfaces.  Usually there is
+ * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
+ * may have both interfaces in a single hwgroup to "serialize" access.
+ * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
+ * together into one hwgroup for serialized access.
+ *
+ * Note also that several hwgroups can end up sharing a single IRQ,
+ * possibly along with many other devices.  This is especially common in
+ * PCI-based systems with off-board IDE controller cards.
+ *
+ * The IDE driver uses the single global io_request_lock spinlock to protect
+ * access to the request queues, and to protect the hwgroup->busy flag.
+ *
+ * The first thread into the driver for a particular hwgroup sets the
+ * hwgroup->busy flag to indicate that this hwgroup is now active,
+ * and then initiates processing of the top request from the request queue.
+ *
+ * Other threads attempting entry notice the busy setting, and will simply
+ * queue their new requests and exit immediately.  Note that hwgroup->busy
+ * remains set even when the driver is merely awaiting the next interrupt.
+ * Thus, the meaning is "this hwgroup is busy processing a request".
+ *
+ * When processing of a request completes, the completing thread or IRQ-handler
+ * will start the next request from the queue.  If no more work remains,
+ * the driver will clear the hwgroup->busy flag and exit.
+ *
+ * The io_request_lock (spinlock) is used to protect all access to the
+ * hwgroup->busy flag, but is otherwise not needed for most processing in
+ * the driver.  This makes the driver much more friendlier to shared IRQs
+ * than previous designs, while remaining 100% (?) SMP safe and capable.
  */
-static void ide_do_request (ide_hwgroup_t *hwgroup, unsigned long *hwgroup_flags, int masked_irq)
+static void ide_do_request (ide_hwgroup_t *hwgroup)
 {
 	struct blk_dev_struct *bdev;
 	ide_drive_t	*drive;
 	ide_hwif_t	*hwif;
-	unsigned long	io_flags;
+	ide_startstop_t	startstop;
 
-	hwgroup->busy = 1;
-	while (hwgroup->handler == NULL) {
-		spin_lock_irqsave(&io_request_lock, io_flags);
+	ide_get_lock(&ide_lock, ide_intr, hwgroup);	/* for atari only: POSSIBLY BROKEN HERE(?) */
+
+	while (!hwgroup->busy) {
+		hwgroup->busy = 1;
 		drive = choose_drive(hwgroup);
 		if (drive == NULL) {
 			unsigned long sleep = 0;
-
 			hwgroup->rq = NULL;
 			drive = hwgroup->drive;
 			do {
@@ -1202,27 +1233,34 @@
 				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
 					sleep = drive->sleep;
 			} while ((drive = drive->next) != hwgroup->drive);
-			spin_unlock_irqrestore(&io_request_lock, io_flags);
 			if (sleep) {
+				/*
+				 * Take a short snooze, and then wake up this hwgroup again.
+				 * This gives other hwgroups on the same a chance to
+				 * play fairly with us, just in case there are big differences
+				 * in relative throughputs.. don't want to hog the cpu too much.
+				 */
 				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
 					sleep = jiffies + WAIT_MIN_SLEEP;
 #if 1
 				if (hwgroup->timer.next || hwgroup->timer.prev)
 					printk("ide_set_handler: timer already active\n");
 #endif
+				hwgroup->sleeping = 1;	/* so that ide_timer_expiry knows what to do */
 				mod_timer(&hwgroup->timer, sleep);
+				/* we purposely leave hwgroup->busy==1 while sleeping */
 			} else {
 				/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */
 				ide_release_lock(&ide_lock);	/* for atari only */
+				hwgroup->busy = 0;
 			}
-			hwgroup->busy = 0;
-			return;
+			return;		/* no more work for this hwgroup (for now) */
 		}
 		hwif = HWIF(drive);
-		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif &&
-		    hwif->io_ports[IDE_CONTROL_OFFSET])
+		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
 			/* set nIEN for previous hwif */
 			OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]);
+		}
 		hwgroup->hwif = hwif;
 		hwgroup->drive = drive;
 		drive->sleep = 0;
@@ -1232,39 +1270,13 @@
 		if (bdev->current_request == &bdev->plug)	/* FIXME: paranoia */
 			printk("%s: Huh? nuking plugged queue\n", drive->name);
 		bdev->current_request = hwgroup->rq = drive->queue;
-		spin_unlock_irqrestore(&io_request_lock, io_flags);
-
-#if 0
-		if (hwif->irq != masked_irq)
-			disable_irq_nosync(hwif->irq);
-		spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
-		start_request(drive);
-		spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
-		if (hwif->irq != masked_irq)
-			enable_irq(hwif->irq);
-#else
-
-		if (masked_irq && hwif->irq != masked_irq) {
-			printk("%s: (disable_irq) %smasked_irq %d\n",
-				drive->name,
-				masked_irq  ? "" : "un_", hwif->irq);
-
-#if 0
-			disable_irq(hwif->irq);
-#else
-			disable_irq_nosync(hwif->irq);
-#endif
-		}
-		spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
-		start_request(drive);
-		spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
-		if (masked_irq && hwif->irq != masked_irq) {
-			printk("%s: (enable_irq) %smasked_irq %d\n",
-				drive->name,
-				masked_irq ? "" : "un_", hwif->irq);
-			enable_irq(hwif->irq);
-		}
-#endif
+		spin_unlock(&io_request_lock);
+		if (!hwif->serialized)	/* play it safe with buggy hardware */
+			ide__sti();
+		startstop = start_request(drive);
+		spin_lock_irq(&io_request_lock);
+		if (startstop == ide_stopped)
+			hwgroup->busy = 0;
 	}
 }
 
@@ -1278,179 +1290,158 @@
 	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
 }
 
-/*
- * do_hwgroup_request() invokes ide_do_request() after claiming hwgroup->busy.
- */
-static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
-	if (hwgroup->busy) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		return;
-	}
-	del_timer(&hwgroup->timer);
-	ide_get_lock(&ide_lock, ide_intr, hwgroup);	/* for atari only */
-	ide_do_request(hwgroup, &flags, 0);
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-}
-
-/*
- * ll_rw_blk.c invokes our do_idex_request() function
- * with the io_request_spinlock already grabbed.
- * Since we need to do our own spinlock's internally,
- * on paths that don't necessarily originate through the
- * do_idex_request() path, we have to undo the spinlock on entry,
- * and restore it again on exit.
- * Fortunately, this is mostly a nop for non-SMP kernels.
- */
-static inline void unlock_do_hwgroup_request (ide_hwgroup_t *hwgroup)
-{
-	spin_unlock(&io_request_lock);
-	do_hwgroup_request (hwgroup);
-	spin_lock_irq(&io_request_lock);
-}
-
 void do_ide0_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[0].hwgroup);
+	ide_do_request (ide_hwifs[0].hwgroup);
 }
 
 #if MAX_HWIFS > 1
 void do_ide1_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[1].hwgroup);
+	ide_do_request (ide_hwifs[1].hwgroup);
 }
 #endif /* MAX_HWIFS > 1 */
 
 #if MAX_HWIFS > 2
 void do_ide2_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[2].hwgroup);
+	ide_do_request (ide_hwifs[2].hwgroup);
 }
 #endif /* MAX_HWIFS > 2 */
 
 #if MAX_HWIFS > 3
 void do_ide3_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[3].hwgroup);
+	ide_do_request (ide_hwifs[3].hwgroup);
 }
 #endif /* MAX_HWIFS > 3 */
 
 #if MAX_HWIFS > 4
 void do_ide4_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[4].hwgroup);
+	ide_do_request (ide_hwifs[4].hwgroup);
 }
 #endif /* MAX_HWIFS > 4 */
 
 #if MAX_HWIFS > 5
 void do_ide5_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[5].hwgroup);
+	ide_do_request (ide_hwifs[5].hwgroup);
 }
 #endif /* MAX_HWIFS > 5 */
 
 #if MAX_HWIFS > 6
 void do_ide6_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[6].hwgroup);
+	ide_do_request (ide_hwifs[6].hwgroup);
 }
 #endif /* MAX_HWIFS > 6 */
 
 #if MAX_HWIFS > 7
 void do_ide7_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[7].hwgroup);
+	ide_do_request (ide_hwifs[7].hwgroup);
 }
 #endif /* MAX_HWIFS > 7 */
 
 #if MAX_HWIFS > 8
 void do_ide8_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[8].hwgroup);
+	ide_do_request (ide_hwifs[8].hwgroup);
 }
 #endif /* MAX_HWIFS > 8 */
 
 #if MAX_HWIFS > 9
 void do_ide9_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[9].hwgroup);
+	ide_do_request (ide_hwifs[9].hwgroup);
 }
 #endif /* MAX_HWIFS > 9 */
 
-static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq)
-{
-	unsigned long	flags;
-	ide_drive_t	*drive;
-
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
-	if (hwgroup->handler != NULL) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		return;
-	}
-	drive = hwgroup->drive;
-	set_recovery_timer(HWIF(drive));
-	drive->service_time = jiffies - drive->service_start;
-	ide_do_request(hwgroup, &flags, masked_irq);
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-}
-
+/*
+ * ide_timer_expiry() is our timeout function for all drive operations.
+ * But note that it can also be invoked as a result of a "sleep" operation
+ * triggered by the mod_timer() call in ide_do_request.
+ */
 void ide_timer_expiry (unsigned long data)
 {
-	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
-	ide_drive_t   *drive;
-	ide_handler_t *handler;
-	ide_expiry_t  *expiry;
-	unsigned long flags;
-	unsigned long wait;
+	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
+	ide_handler_t	*handler;
+	ide_expiry_t	*expiry;
+ 	unsigned long	flags;
+	unsigned long	wait;
 
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
-	drive = hwgroup->drive;
-	if ((handler = hwgroup->handler) == NULL) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		do_hwgroup_request(hwgroup);
-		return;
-	}
-
-	hwgroup->busy = 1;	/* should already be "1" */
+	spin_lock_irqsave(&io_request_lock, flags);
+	del_timer(&hwgroup->timer);
 
-	if ((expiry = hwgroup->expiry) != NULL) {
-		/* continue */
-		if ((wait = expiry(drive)) != 0) {
-			/* reset timer */
-			hwgroup->timer.expires	= jiffies + wait;
-			add_timer(&(hwgroup->timer));
-			spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-			return;
+	if ((handler = hwgroup->handler) == NULL) {
+		/*
+		 * Either a marginal timeout occured
+		 * (got the interrupt just as timer expired),
+		 * or we were "sleeping" to give other devices a chance.
+		 * Either way, we don't really want to complain about anything.
+		 */
+		if (hwgroup->sleeping) {
+			hwgroup->sleeping = 0;
+			hwgroup->busy = 0;
 		}
-	}
-
-	hwgroup->handler = NULL;
-
-	if (hwgroup->poll_timeout != 0) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		handler(drive);
-	} else if (drive_is_ready(drive)) {
-		printk("%s: lost interrupt\n", drive->name);
-		(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		handler(drive);
 	} else {
-		if (drive->waiting_for_dma) {
-			(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
-			printk("%s: timeout waiting for DMA\n", drive->name);
-	/*
-	 *  need something here for HPT34X.......AMH
-	 *  irq timeout: status=0x58 { DriveReady SeekComplete DataRequest }
-	 */
-			(void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive);
+		ide_drive_t *drive = hwgroup->drive;
+		hwgroup->handler = NULL;
+		if (!drive) {
+			printk("ide_timer_expiry: hwgroup->drive was NULL\n");
+		} else {
+			ide_hwif_t *hwif;
+			ide_startstop_t startstop;
+			if (!hwgroup->busy) {
+				hwgroup->busy = 1;	/* paranoia */
+				printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+			}
+			if ((expiry = hwgroup->expiry) != NULL) {
+				/* continue */
+				if ((wait = expiry(drive)) != 0) {
+					/* reset timer */
+					hwgroup->timer.expires  = jiffies + wait;
+					add_timer(&hwgroup->timer);
+					spin_unlock_irqrestore(&io_request_lock, flags);
+					return;
+				}
+			}
+			/*
+			 * We need to simulate a real interrupt when invoking
+			 * the handler() function, which means we need to globally
+			 * mask the specific IRQ:
+			 */
+			spin_unlock(&io_request_lock);
+			hwif  = HWIF(drive);
+			disable_irq(hwif->irq);
+			__cli();	/* local CPU only, as if we were handling an interrupt */
+			if (hwgroup->poll_timeout != 0) {
+				startstop = handler(drive);
+			} else if (drive_is_ready(drive)) {
+				if (drive->waiting_for_dma)
+					(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
+				(void)ide_ack_intr(hwif);
+				printk("%s: lost interrupt\n", drive->name);
+				startstop = handler(drive);
+			} else {
+				if (drive->waiting_for_dma) {
+					(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
+					printk("%s: timeout waiting for DMA\n", drive->name);
+					(void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive);
+				}
+				startstop = ide_error(drive, "irq timeout", GET_STAT());
+			}
+			set_recovery_timer(hwif);
+			drive->service_time = jiffies - drive->service_start;
+			enable_irq(hwif->irq);
+			spin_lock_irq(&io_request_lock);
+			if (startstop == ide_stopped)
+				hwgroup->busy = 0;
 		}
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		ide_error(drive, "irq timeout", GET_STAT());
 	}
-	start_next_request(hwgroup, 0);
+	ide_do_request(hwgroup);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /*
@@ -1500,6 +1491,7 @@
 		}
 	} while ((hwif = hwif->next) != hwgroup->hwif);
 }
+
 /*
  * entry point for all interrupts, caller does __cli() for us
  */
@@ -1510,13 +1502,13 @@
 	ide_hwif_t *hwif;
 	ide_drive_t *drive;
 	ide_handler_t *handler;
+	ide_startstop_t startstop;
 
-	__cli();	/* local CPU only */
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwif = hwgroup->hwif;
 
 	if (!ide_ack_intr(hwif)) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return;
 	}
 
@@ -1542,29 +1534,70 @@
 			 * so we can safely try to do something about it:
 			 */
 			unexpected_intr(irq, hwgroup);
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		} else {
+			/*
+			 * Whack the status register, just in case we have a leftover pending IRQ.
+			 *
+			 * Unless we are some version of a Promise Ultra66 :: PDC20262.
+			 * We will hang like a rock....
+			 */
+			byte skip_status = ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
+					    (hwif->pci_dev->device == PCI_DEVICE_ID_TTI_HPT366)) ? 1 : 0;
+			if (!skip_status)
+				(void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 		}
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return;
 	}
 	drive = hwgroup->drive;
-	if (!drive || !drive_is_ready(drive)) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+	if (!drive) {
+		/*
+		 * This should NEVER happen, and there isn't much we could do about it here.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return;
 	}
+	if (!drive_is_ready(drive)) {
+		/*
+		 * This happens regularly when we share a PCI IRQ with another device.
+		 * Unfortunately, it can also happen with some buggy drives that trigger
+		 * the IRQ before their status register is up to date.  Hopefully we have
+		 * enough advance overhead that the latter isn't a problem.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if (!hwgroup->busy) {
+		hwgroup->busy = 1;	/* paranoia */
+		printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
+	}
 	hwgroup->handler = NULL;
-	del_timer(&(hwgroup->timer));
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+	del_timer(&hwgroup->timer);
+	spin_unlock(&io_request_lock);
 	if (drive->unmask)
 		ide__sti();	/* local CPU only */
-	handler(drive);		/* service this interrupt, may set handler for next interrupt */
+	startstop = handler(drive);		/* service this interrupt, may set handler for next interrupt */
+	spin_lock_irq(&io_request_lock);
 	/*
 	 * Note that handler() may have set things up for another
 	 * interrupt to occur soon, but it cannot happen until
 	 * we exit from this routine, because it will be the
-	 * same irq as is currently being serviced here,
-	 * and Linux won't allow another (on any CPU) until we return.
+	 * same irq as is currently being serviced here, and Linux
+	 * won't allow another of the same (on any CPU) until we return.
 	 */
-	start_next_request(hwgroup, hwif->irq);
+	set_recovery_timer(HWIF(drive));
+	drive->service_time = jiffies - drive->service_start;
+	if (startstop == ide_stopped) {
+		if (hwgroup->handler == NULL) {	/* paranoia */
+			hwgroup->busy = 0;
+			ide_do_request(hwgroup);
+		} else {
+			printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
+		}
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /*
@@ -1649,7 +1682,6 @@
 	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
 	if (action == ide_wait)
 		rq->sem = &sem;
-
 	spin_lock_irqsave(&io_request_lock, flags);
 	cur_rq = drive->queue;
 	if (cur_rq == NULL || action == ide_preempt) {
@@ -1665,13 +1697,14 @@
 		rq->next = cur_rq->next;
 		cur_rq->next = rq;
 	}
+	ide_do_request(hwgroup);
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	do_hwgroup_request(hwgroup);
 	if (action == ide_wait) {
-		down(&sem);	/* wait for it to be serviced */
-		rq->sem = NULL;
+		down(&sem);			/* wait for it to be serviced */
+		return rq->errors ? -EIO : 0;	/* return -EIO if errors */
 	}
-	return rq->errors ? -EIO : 0;	/* return -EIO if errors */
+	return 0;
+
 }
 
 /*
@@ -1682,7 +1715,7 @@
  * usage == 1 (we need an open channel to use an ioctl :-), so this
  * is our limit.
  */
-int ide_revalidate_disk(kdev_t i_rdev)
+int ide_revalidate_disk (kdev_t i_rdev)
 {
 	ide_drive_t *drive;
 	ide_hwgroup_t *hwgroup;
@@ -1694,14 +1727,14 @@
 	major = MAJOR(i_rdev);
 	minor = drive->select.b.unit << PARTN_BITS;
 	hwgroup = HWGROUP(drive);
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
+	spin_lock_irqsave(&io_request_lock, flags);
 	if (drive->busy || (drive->usage > 1)) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return -EBUSY;
 	};
 	drive->busy = 1;
 	MOD_INC_USE_COUNT;
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	for (p = 0; p < (1<<PARTN_BITS); ++p) {
 		if (drive->part[p].nr_sects > 0) {
@@ -1767,7 +1800,7 @@
 #endif /* CONFIG_KMOD */
 }
 
-static int ide_open(struct inode * inode, struct file * filp)
+static int ide_open (struct inode * inode, struct file * filp)
 {
 	ide_drive_t *drive;
 	int rc;
@@ -1807,7 +1840,7 @@
  * Releasing a block device means we sync() it, so that it can safely
  * be forgotten about...
  */
-static int ide_release(struct inode * inode, struct file * file)
+static int ide_release (struct inode * inode, struct file * file)
 {
 	ide_drive_t *drive;
 
@@ -1821,7 +1854,7 @@
 	return 0;
 }
 
-int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
+int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
 {
 	if (!drive->present || drive->busy || drive->usage)
 		goto abort;
@@ -1979,6 +2012,7 @@
 	init_hwif_data (index);	/* restore hwif data to pristine status */
 	hwif->hwgroup = old_hwif.hwgroup;
 	hwif->tuneproc = old_hwif.tuneproc;
+	hwif->resetproc = old_hwif.resetproc;
 	hwif->dmaproc = old_hwif.dmaproc;
 	hwif->dma_base = old_hwif.dma_base;
 	hwif->dma_extra = old_hwif.dma_extra;
@@ -2089,7 +2123,7 @@
 	return ide_register_hw(&hw, NULL);
 }
 
-void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
 
@@ -2115,7 +2149,7 @@
 		kfree(setting);
 }
 
-void ide_remove_setting(ide_drive_t *drive, char *name)
+void ide_remove_setting (ide_drive_t *drive, char *name)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting;
 
@@ -2128,7 +2162,7 @@
 	kfree(setting);
 }
 
-static ide_settings_t *ide_find_setting_by_ioctl(ide_drive_t *drive, int cmd)
+static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
 {
 	ide_settings_t *setting = drive->settings;
 
@@ -2140,7 +2174,7 @@
 	return setting;
 }
 
-ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
+ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
 {
 	ide_settings_t *setting = drive->settings;
 
@@ -2152,7 +2186,7 @@
 	return setting;
 }
 
-static void auto_remove_settings(ide_drive_t *drive)
+static void auto_remove_settings (ide_drive_t *drive)
 {
 	ide_settings_t *setting;
 repeat:
@@ -2166,13 +2200,13 @@
 	}
 }
 
-int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
+int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
 {
 	int		val = -EINVAL;
 	unsigned long	flags;
 
 	if ((setting->rw & SETTING_READ)) {
-		spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+		spin_lock_irqsave(&io_request_lock, flags);
 		switch(setting->data_type) {
 			case TYPE_BYTE:
 				val = *((u8 *) setting->data);
@@ -2185,7 +2219,7 @@
 				val = *((u32 *) setting->data);
 				break;
 		}
-		spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+		spin_unlock_irqrestore(&io_request_lock, flags);
 	}
 	return val;
 }
@@ -2195,20 +2229,29 @@
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	unsigned long timeout = jiffies + (3 * HZ);
 
-	spin_lock_irqsave(&hwgroup->spinlock, *flags);
+	spin_lock_irqsave(&io_request_lock, *flags);
 	while (hwgroup->busy) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, *flags);
-		__sti();	/* local CPU only; needed for jiffies */
+		unsigned long lflags;
+		spin_unlock_irqrestore(&io_request_lock, *flags);
+		__save_flags(lflags);	/* local CPU only */
+		__sti();		/* local CPU only; needed for jiffies */
 		if (0 < (signed long)(jiffies - timeout)) {
+			__restore_flags(lflags);	/* local CPU only */
 			printk("%s: channel busy\n", drive->name);
 			return -EBUSY;
 		}
-		spin_lock_irqsave(&hwgroup->spinlock, *flags);
+		__restore_flags(lflags);	/* local CPU only */
+		spin_lock_irqsave(&io_request_lock, *flags);
 	}
 	return 0;
 }
 
-int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
+/*
+ * FIXME:  This should be changed to enqueue a special request
+ * to the driver to change settings, and then wait on a sema for completion.
+ * The current scheme of polling is kludgey, though safe enough.
+ */
+int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
 {
 	unsigned long flags;
 	int i;
@@ -2240,7 +2283,7 @@
 				*p = val;
 			break;
 	}
-	spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	return 0;
 }
 
@@ -2254,7 +2297,7 @@
 	return 0;
 }
 
-static int set_using_dma(ide_drive_t *drive, int arg)
+static int set_using_dma (ide_drive_t *drive, int arg)
 {
 	if (!drive->driver || !DRIVER(drive)->supports_dma)
 		return -EPERM;
@@ -2265,7 +2308,7 @@
 	return 0;
 }
 
-static int set_pio_mode(ide_drive_t *drive, int arg)
+static int set_pio_mode (ide_drive_t *drive, int arg)
 {
 	struct request rq;
 
@@ -2280,7 +2323,7 @@
 	return 0;
 }
 
-void ide_add_generic_settings(ide_drive_t *drive)
+void ide_add_generic_settings (ide_drive_t *drive)
 {
 /*
  *			drive	setting name		read/write access				read ioctl		write ioctl		data type	min	max				mul_factor	div_factor	data pointer			set function
@@ -2325,136 +2368,6 @@
 	while (0 < (signed long)(timeout - jiffies));
 }
 
-int ide_config_drive_speed (ide_drive_t *drive, byte speed)
-{
-	struct hd_driveid *id = drive->id;
-	unsigned long flags;
-	int err;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	/*
-	 * Don't use ide_wait_cmd here - it will
-	 * attempt to set_geometry and recalibrate,
-	 * but for some reason these don't work at
-	 * this point (lost interrupt).
-	 */
-	SELECT_DRIVE(HWIF(drive), drive);
-	if (IDE_CONTROL_REG)
-	    OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(speed, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-
-	err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
-
-#if 0
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-#endif
-
-	__restore_flags(flags);	/* local CPU only */
-
-        switch(speed) {
-		case XFER_UDMA_4:
-			if (!((id->dma_ultra >> 8) & 16)) {
-				drive->id->dma_ultra &= ~0xFF00;
-				drive->id->dma_ultra |= 0x1010;
-			}
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-			break;
-		case XFER_UDMA_3:
-			if (!((id->dma_ultra >> 8) & 8)) {
-				drive->id->dma_ultra &= ~0xFF00;
-				drive->id->dma_ultra |= 0x0808;
-			}
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-			break;
-		case XFER_UDMA_2:
-			if (!((id->dma_ultra >> 8) & 4)) {
-				drive->id->dma_ultra &= ~0xFF00;
-				drive->id->dma_ultra |= 0x0404;
-			}
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-			break;
-		case XFER_UDMA_1:
-			if (!((id->dma_ultra >> 8) & 2)) {
-				drive->id->dma_ultra &= ~0xFF00;
-				drive->id->dma_ultra |= 0x0202;
-			}
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-			break;
-		case XFER_UDMA_0:
-			if (!((id->dma_ultra >> 8) & 1)) {
-				drive->id->dma_ultra &= ~0xFF00;
-				drive->id->dma_ultra |= 0x0101;
-			}
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-			break;
-		case XFER_MW_DMA_2:
-			drive->id->dma_ultra &= ~0xFF00;
-			if (!((id->dma_mword >> 8) & 4)) {
-				drive->id->dma_mword &= ~0x0F00;
-				drive->id->dma_mword |= 0x0404;
-			}
-			drive->id->dma_1word &= ~0x0F00;
-			break;
-		case XFER_MW_DMA_1:
-			drive->id->dma_ultra &= ~0xFF00;
-			if (!((id->dma_mword >> 8) & 2)) {
-				drive->id->dma_mword &= ~0x0F00;
-				drive->id->dma_mword |= 0x0202;
-			}
-			drive->id->dma_1word &= ~0x0F00;
-			break;
-		case XFER_MW_DMA_0:
-			drive->id->dma_ultra &= ~0xFF00;
-			if (!((id->dma_mword >> 8) & 1)) {
-				drive->id->dma_mword &= ~0x0F00;
-				drive->id->dma_mword |= 0x0101;
-			}
-			drive->id->dma_1word &= ~0x0F00;
-			break;
-		case XFER_SW_DMA_2:
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_mword &= ~0x0F00;
-			if (!((id->dma_1word >> 8) & 4)) {
-				drive->id->dma_1word &= ~0x0F00;
-				drive->id->dma_1word |= 0x0404;
-			}
-			break;
-		case XFER_SW_DMA_1:
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_mword &= ~0x0F00;
-			if (!((id->dma_1word >> 8) & 2)) {
-				drive->id->dma_1word &= ~0x0F00;
-				drive->id->dma_1word |= 0x0202;
-			}
-			break;
-		case XFER_SW_DMA_0:
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_mword &= ~0x0F00;
-			if (!((id->dma_1word >> 8) & 1)) {
-				drive->id->dma_1word &= ~0x0F00;
-				drive->id->dma_1word |= 0x0101;
-			}
-			break;
-		default:
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-			break;
-	}
-
-	return(err);
-}
-
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2509,8 +2422,7 @@
 				return -EINVAL;
 			if (drive->id == NULL)
 				return -ENOMSG;
-			if (copy_to_user((char *)arg, (char *)drive->id,
-					 (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
+			if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
 				return -EFAULT;
 			return 0;
 
@@ -2537,28 +2449,16 @@
 					return -ENOMEM;
 				memcpy(argbuf, args, 4);
 			}
-			if ((((byte *)arg)[0] == WIN_SETFEATURES) &&
-			    (((byte *)arg)[1] > 66) &&
-			    (((byte *)arg)[2] == 3)) {
-				if (!HWIF(drive)->udma_four) {
-					printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name);
-					goto abort;
-				}
-				if ((drive->id->word93 & 0x2000) == 0) {
-					printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name);
-					goto abort;
-				}
-			}
+			if (ide_ata66_check(drive, args[0], args[1], args[2]))
+				goto abort;
+
 			err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
-			if (!err &&
-			    (((byte *)arg)[0] == WIN_SETFEATURES) &&
-			    (((byte *)arg)[1] >= 16) &&
-			    (((byte *)arg)[2] == 3) &&
-			    (drive->id->dma_ultra ||
-			     drive->id->dma_mword ||
-			     drive->id->dma_1word)) {
 
-				/* 
+			if (!err && set_transfer(drive, args[0], args[1], args[2])) {
+
+#if 1
+				ide_driveid_update(drive);
+#else				/* 
 				 * Re-read drive->id for possible DMA mode 
 				 * change (copied from ide-probe.c)
 				 */
@@ -2602,6 +2502,7 @@
 #endif
 				kfree(id);
 				}
+#endif
 			}
 		abort:
 			if (copy_to_user((void *)arg, argbuf, argsize))
@@ -2694,32 +2595,6 @@
 }
 
 /*
- *
- */
-char *ide_xfer_verbose (byte xfer_rate) {
-	switch(xfer_rate) {
-		case XFER_UDMA_4:	return("UDMA 4");
-		case XFER_UDMA_3:	return("UDMA 3");
-		case XFER_UDMA_2:	return("UDMA 2");
-		case XFER_UDMA_1:	return("UDMA 1");
-		case XFER_UDMA_0:	return("UDMA 0");
-		case XFER_MW_DMA_2:	return("MW DMA 2");
-		case XFER_MW_DMA_1:	return("MW DMA 1");
-		case XFER_MW_DMA_0:	return("MW DMA 0");
-		case XFER_SW_DMA_2:	return("SW DMA 2");
-		case XFER_SW_DMA_1:	return("SW DMA 1");
-		case XFER_SW_DMA_0:	return("SW DMA 0");
-		case XFER_PIO_4:	return("PIO 4");
-		case XFER_PIO_3:	return("PIO 3");
-		case XFER_PIO_2:	return("PIO 2");
-		case XFER_PIO_1:	return("PIO 1");
-		case XFER_PIO_0:	return("PIO 0");
-		case XFER_PIO_SLOW:	return("PIO SLOW");
-		default:		return("XFER ERROR");
-	}
-}
-
-/*
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
  */
@@ -2796,7 +2671,7 @@
  * "hdx=nowerr"		: ignore the WRERR_STAT bit on this drive
  * "hdx=cdrom"		: drive is present, and is a cdrom drive
  * "hdx=cyl,head,sect"	: disk drive is present, with specified geometry
- * "hdx=noremap"        : do not remap 0->1 even though EZD was detected
+ * "hdx=noremap"	: do not remap 0->1 even though EZD was detected
  * "hdx=autotune"	: driver will attempt to tune interface speed
  *				to the fastest PIO mode supported,
  *				if possible for this drive only.
@@ -3198,6 +3073,14 @@
 }
 
 /*
+ * __setup("ide", ide_setup);
+ * #ifdef CONFIG_BLK_DEV_VIA82CXXX
+ * __setup("splitfifo", ide_setup);
+ * #endif
+ * __setup("hd", ide_setup);
+ */
+
+/*
  * probe_for_hwifs() finds/initializes "known" IDE interfaces
  */
 static void __init probe_for_hwifs (void)
@@ -3332,9 +3215,10 @@
 	return ide_unregister_subdriver(drive);
 }
 
-static void default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	ide_end_request(0, HWGROUP(drive));
+	return ide_stopped;
 }
  
 static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
@@ -3372,12 +3256,13 @@
 	return 0x7fffffff;	/* cdrom or tape */
 }
 
-static void default_special (ide_drive_t *drive)
+static ide_startstop_t default_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
 
 	s->all = 0;
 	drive->mult_req = 0;
+	return ide_stopped;
 }
 
 static void setup_driver_defaults (ide_drive_t *drive)
@@ -3577,7 +3462,6 @@
 EXPORT_SYMBOL(ide_cmd);
 EXPORT_SYMBOL(ide_wait_cmd);
 EXPORT_SYMBOL(ide_delay_50ms);
-EXPORT_SYMBOL(ide_config_drive_speed);
 EXPORT_SYMBOL(ide_stall_queue);
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(ide_add_proc_entries);
diff -u --recursive --new-file v2.3.27/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c
--- v2.3.27/linux/drivers/block/pdc202xx.c	Fri Oct 22 13:21:47 1999
+++ linux/drivers/block/pdc202xx.c	Fri Nov 12 10:12:11 1999
@@ -78,6 +78,7 @@
  *  Released under terms of General Public License
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -220,7 +221,7 @@
 
 	int			err;
 	unsigned int		drive_conf;
-	byte			drive_pci;
+	byte			drive_pci, speed_ok = 0;
 	byte			test1, test2, speed = -1;
 	byte			AP, BP, CP, DP, TB, TC;
 	unsigned short		EP;
@@ -278,16 +279,20 @@
 	switch(drive_number) {
 		case 0:	drive_pci = 0x60;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) {
+				speed_ok = 1;
 				goto chipset_is_set;
+			}
 			pci_read_config_byte(dev, (drive_pci), &test1);
 			if (!(test1 & SYNC_ERRDY_EN))
 				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
 			break;
 		case 1:	drive_pci = 0x64;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) {
+				speed_ok = 1;
 				goto chipset_is_set;
+			}
 			pci_read_config_byte(dev, 0x60, &test1);
 			pci_read_config_byte(dev, (drive_pci), &test2);
 			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
@@ -295,16 +300,20 @@
 			break;
 		case 2:	drive_pci = 0x68;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) {
+				speed_ok = 1;
 				goto chipset_is_set;
+			}
 			pci_read_config_byte(dev, (drive_pci), &test1);
 			if (!(test1 & SYNC_ERRDY_EN))
 				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
 			break;
 		case 3:	drive_pci = 0x6c;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) {
+				speed_ok = 1;
 				goto chipset_is_set;
+			}
 			pci_read_config_byte(dev, 0x68, &test1);
 			pci_read_config_byte(dev, (drive_pci), &test2);
 			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
@@ -402,7 +411,8 @@
 	decode_registers(REG_D, DP);
 #endif /* PDC202XX_DECODE_REGISTER_INFO */
 
-	err = ide_config_drive_speed(drive, speed);
+	if (!speed_ok)
+		err = ide_config_drive_speed(drive, speed);
 
 #if PDC202XX_DEBUG_DRIVE_INFO
 	printk("%s: %s drive%d 0x%08x ",
diff -u --recursive --new-file v2.3.27/linux/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c
--- v2.3.27/linux/drivers/block/pdc4030.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/block/pdc4030.c	Fri Nov 12 10:12:11 1999
@@ -158,6 +158,7 @@
 	ide_hwif_t *hwif2;
 	struct dc_ident ident;
 	int i;
+	ide_startstop_t startstop;
 	
 	if (!hwif) return 0;
 
@@ -174,7 +175,7 @@
 	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
 		return 0;
 	}
-	if (ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
+	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
 		printk(KERN_INFO
 			"%s: Failed Promise read config!\n",hwif->name);
 		return 0;
@@ -301,7 +302,7 @@
 /*
  * promise_read_intr() is the handler for disk read/multread interrupts
  */
-static void promise_read_intr (ide_drive_t *drive)
+static ide_startstop_t promise_read_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int total_remaining;
@@ -309,8 +310,7 @@
 	struct request *rq;
 
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		ide_error(drive, "promise_read_intr", stat);
-		return;
+		return ide_error(drive, "promise_read_intr", stat);
 	}
 
 read_again:
@@ -367,12 +367,13 @@
 			printk(KERN_DEBUG "%s: promise_read: waiting for"
 			       "interrupt\n", drive->name);
 #endif 
-			return;
+			return ide_started;
 		}
 		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
 		       "!DRQ !BUSY\n", drive->name);
-		ide_error(drive, "promise read intr", stat);
+		return ide_error(drive, "promise read intr", stat);
 	}
+	return ide_stopped;
 }
 
 /*
@@ -383,7 +384,7 @@
  *
  * Once not busy, the end request is called.
  */
-static void promise_complete_pollfunc(ide_drive_t *drive)
+static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = hwgroup->rq;
@@ -392,13 +393,12 @@
 	if (GET_STAT() & BUSY_STAT) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
 			ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-			return; /* continue polling... */
+			return ide_started; /* continue polling... */
 		}
 		hwgroup->poll_timeout = 0;
 		printk(KERN_ERR "%s: completion timeout - still busy!\n",
 		       drive->name);
-		ide_error(drive, "busy timeout", GET_STAT());
-		return;
+		return ide_error(drive, "busy timeout", GET_STAT());
 	}
 
 	hwgroup->poll_timeout = 0;
@@ -409,24 +409,24 @@
 		i -= rq->current_nr_sectors;
 		ide_end_request(1, hwgroup);
 	}
+	return ide_stopped;
 }
 
 /*
  * promise_write_pollfunc() is the handler for disk write completion polling.
  */
-static void promise_write_pollfunc (ide_drive_t *drive)
+static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
 	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
 			ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
-			return; /* continue polling... */
+			return ide_started; /* continue polling... */
 		}
 		hwgroup->poll_timeout = 0;
 		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
-		ide_error (drive, "write timeout", GET_STAT());
-		return;
+		return ide_error (drive, "write timeout", GET_STAT());
 	}
 
 	/*
@@ -439,7 +439,7 @@
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
 		drive->name, GET_STAT());
 #endif
-	return;
+	return ide_started;
 }
 
 /*
@@ -449,7 +449,7 @@
  * before the final 4 sectors are transfered. There is no interrupt generated
  * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
  */
-static void promise_write (ide_drive_t *drive)
+static ide_startstop_t promise_write (ide_drive_t *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = &hwgroup->wrq;
@@ -465,21 +465,25 @@
 	 * the polling strategy as defined above.
 	 */
 	if (rq->nr_sectors > 4) {
-		ide_multwrite(drive, rq->nr_sectors - 4);
+		if (ide_multwrite(drive, rq->nr_sectors - 4))
+			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+		return ide_started;
 	} else {
 	/*
 	 * There are 4 or fewer sectors to transfer, do them all in one go
 	 * and wait for NOT BUSY.
 	 */
-		ide_multwrite(drive, rq->nr_sectors);
+		if (ide_multwrite(drive, rq->nr_sectors))
+			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
 			"status = %02x\n", drive->name, GET_STAT());
 #endif
+		return ide_started;
 	}
 }
 
@@ -488,7 +492,7 @@
  * already set up. It issues a READ or WRITE command to the Promise
  * controller, assuming LBA has been used to set up the block number.
  */
-void do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
 {
 	unsigned long timeout;
 	byte stat;
@@ -510,8 +514,7 @@
 			stat=GET_STAT();
 			if (stat & DRQ_STAT) {
 				udelay(1);
-				promise_read_intr(drive);
-				return;
+				return promise_read_intr(drive);
 			}
 			if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
 #ifdef DEBUG_READ
@@ -519,29 +522,31 @@
 				                  "interrupt\n", drive->name);
 #endif
 				ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
-				return;
+				return ide_started;
 			}
 			udelay(1);
 		} while (time_before(jiffies, timeout));
 
 		printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
 			drive->name);
-
+		return ide_stopped;
 	} else if (rq->cmd == WRITE) {
+		ide_startstop_t startstop;
 		OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
-		if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
 			printk(KERN_ERR "%s: no DRQ after issuing "
 			       "PROMISE_WRITE\n", drive->name);
-			return;
+			return startstop;
 	    	}
 		if (!drive->unmask)
 			__cli();	/* local CPU only */
 		HWGROUP(drive)->wrq = *rq; /* scratchpad */
-		promise_write(drive);
+		return promise_write(drive);
 
 	} else {
 		printk("KERN_WARNING %s: bad command: %d\n",
 		       drive->name, rq->cmd);
 		ide_end_request(0, HWGROUP(drive));
+		return ide_stopped;
 	}
 }
diff -u --recursive --new-file v2.3.27/linux/drivers/block/piix.c linux/drivers/block/piix.c
--- v2.3.27/linux/drivers/block/piix.c	Fri Oct 22 13:21:47 1999
+++ linux/drivers/block/piix.c	Fri Nov 12 10:12:11 1999
@@ -68,6 +68,42 @@
 
 #define PIIX_DEBUG_DRIVE_INFO		0
 
+#define DISPLAY_PIIX_TIMINGS
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int piix_get_info(char *, char **, off_t, int, int);
+extern int (*piix_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int piix_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+	/* int rc; */
+	int piix_who = (bmide_dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 4 : 3;
+	char *p = buffer;
+	p += sprintf(p, "\n                                Intel PIIX%d Chipset.\n", piix_who);
+	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n\n");
+	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "\n");
+	p += sprintf(p, "\n");
+
+/*
+ *	FIXME.... Add configuration junk data....blah blah......
+ */
+
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ *  Used to set Fifo configuration via kernel command line:
+ */
+
+byte piix_proc = 0;
+
 extern char *ide_xfer_verbose (byte xfer_rate);
 
 #ifdef CONFIG_BLK_DEV_PIIX_TUNING
@@ -248,6 +284,18 @@
 }
 #endif /* CONFIG_BLK_DEV_PIIX_TUNING */
 
+unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!piix_proc) {
+		piix_proc = 1;
+		bmide_dev = dev;
+		piix_display_info = &piix_get_info;
+	}
+#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
 void __init ide_init_piix (ide_hwif_t *hwif)
 {
 	hwif->tuneproc = &piix_tune_drive;
@@ -262,5 +310,4 @@
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
 	}
-
 }
diff -u --recursive --new-file v2.3.27/linux/drivers/block/sis5513.c linux/drivers/block/sis5513.c
--- v2.3.27/linux/drivers/block/sis5513.c	Fri Oct 22 13:21:47 1999
+++ linux/drivers/block/sis5513.c	Fri Nov 12 10:12:11 1999
@@ -8,6 +8,7 @@
  * Tested and designed on the SiS620/5513 chipset.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -27,13 +28,35 @@
 
 #include "ide_modes.h"
 
+#define DISPLAY_SIS_TIMINGS
 #define SIS5513_DEBUG_DRIVE_INFO	0
 
-#define DISPLAY_SIS_TIMINGS
+static struct pci_dev *host_dev = NULL;
+
+#define arraysize(x)			(sizeof(x)/sizeof(*(x)))
 
-static struct pci_dev *host_dev;
+#define SIS5513_FLAG_ATA_00		0x00000000
+#define SIS5513_FLAG_ATA_16		0x00000001
+#define SIS5513_FLAG_ATA_33		0x00000002
+#define SIS5513_FLAG_ATA_66		0x00000004
+#define SIS5513_FLAG_LATENCY		0x00000010
+
+static const struct {
+	const char *name;
+	unsigned short host_id;
+	unsigned int flags;
+} SiSHostChipInfo[] = {
+	{ "SiS530",	PCI_DEVICE_ID_SI_530,	SIS5513_FLAG_ATA_66, },
+	{ "SiS540",	PCI_DEVICE_ID_SI_540,	SIS5513_FLAG_ATA_66, },
+	{ "SiS620",	PCI_DEVICE_ID_SI_620,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS630",	PCI_DEVICE_ID_SI_630,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	SIS5513_FLAG_ATA_33, },
+	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	SIS5513_FLAG_ATA_33, },
+	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	SIS5513_FLAG_ATA_16, },
+};
 
 #if 0
+
 static struct _pio_mode_mapping {
 	byte data_active;
 	byte recovery;
@@ -122,9 +145,6 @@
 	int rc;
 	char *p = buffer;
 	byte reg,reg1;
-#if 0
-	byte cyc, rec, act;
-#endif
 	u16 reg2, reg3;
 
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
@@ -213,16 +233,16 @@
 	byte			drive_pci, test1, test2, mask;
 	int			err;
 
-	byte speed		= 0x00;
-	byte unmask		= 0xE0;
-	byte four_two		= 0x00;
+	byte speed		= 0x00, unmask = 0xE0, four_two = 0x00;
 	int drive_number	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
 	byte udma_66		= ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0;
 
 	if (host_dev) {
 		switch(host_dev->device) {
 			case PCI_DEVICE_ID_SI_530:
+			case PCI_DEVICE_ID_SI_540:
 			case PCI_DEVICE_ID_SI_620:
+			case PCI_DEVICE_ID_SI_630:
 				unmask   = 0xF0;
 				four_two = 0x01;
 			default:
@@ -246,13 +266,15 @@
 		pci_read_config_byte(dev, drive_pci|0x01, &test2);
 	}
 
-	if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) {
+	if ((id->dma_ultra & 0x0010) && (ultra) &&
+	    (udma_66) && (four_two)) {
 		if (!(test2 & 0x90)) {
 			pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
 			pci_write_config_byte(dev, drive_pci|0x01, test2|0x90);
 		}
 		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) {
+	} else if ((id->dma_ultra & 0x0008) && (ultra) &&
+		   (udma_66) && (four_two)) {
 		if (!(test2 & 0xA0)) {
 			pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
 			pci_write_config_byte(dev, drive_pci|0x01, test2|0xA0);
@@ -438,29 +460,23 @@
 unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
 {
 	struct pci_dev *host;
+	int i = 0;
 	byte latency = 0;
 
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
 
-	for (host = pci_devices; host; host=host->next) {
-		if (host->vendor == PCI_VENDOR_ID_SI &&
-		    host->device == PCI_DEVICE_ID_SI_620) {
+	for (i = 0; i < arraysize (SiSHostChipInfo) && !host_dev; i++) {
+		host = pci_find_device (PCI_VENDOR_ID_SI,
+					SiSHostChipInfo[i].host_id,
+					NULL);
+		if (!host)
+			continue;
+
+		host_dev = host;
+		printk(SiSHostChipInfo[i].name);
+		if (SiSHostChipInfo[i].flags & SIS5513_FLAG_LATENCY) {
 			if (latency != 0x10)
 				pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
-			host_dev = host;
-			break;
-		} else if (host->vendor == PCI_VENDOR_ID_SI &&
-			   host->device == PCI_DEVICE_ID_SI_530) {
-			host_dev = host;
-			break;
-		} else if (host->vendor == PCI_VENDOR_ID_SI &&
-			   host->device == PCI_DEVICE_ID_SI_5600) {
-			host_dev = host;
-			break;
-		} else if (host->vendor == PCI_VENDOR_ID_SI &&
-			   host->device == PCI_DEVICE_ID_SI_5597) {
-			host_dev = host;
-			break;
 		}
 	}
 
@@ -468,9 +484,10 @@
 		byte reg52h = 0;
 
 		pci_read_config_byte(dev, 0x52, &reg52h);
-		if (!(reg52h & 0x04))
+		if (!(reg52h & 0x04)) {
 			/* set IDE controller to operate in Compabitility mode obly */
 			pci_write_config_byte(dev, 0x52, reg52h|0x04);
+		}
 #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
 		sis_proc = 1;
 		bmide_dev = dev;
@@ -489,7 +506,9 @@
 	if (host_dev) {
 		switch(host_dev->device) {
 			case PCI_DEVICE_ID_SI_530:
+			case PCI_DEVICE_ID_SI_540:
 			case PCI_DEVICE_ID_SI_620:
+			case PCI_DEVICE_ID_SI_630:
 				ata66 = (reg48h & mask) ? 0 : 1;
 			default:
 				break;
@@ -509,7 +528,9 @@
 	if (host_dev) {
 		switch(host_dev->device) {
 			case PCI_DEVICE_ID_SI_530:
+			case PCI_DEVICE_ID_SI_540:
 			case PCI_DEVICE_ID_SI_620:
+			case PCI_DEVICE_ID_SI_630:
 			case PCI_DEVICE_ID_SI_5600:
 			case PCI_DEVICE_ID_SI_5597:
 				hwif->autodma = 1;
diff -u --recursive --new-file v2.3.27/linux/drivers/char/drm/bufs.c linux/drivers/char/drm/bufs.c
--- v2.3.27/linux/drivers/char/drm/bufs.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/char/drm/bufs.c	Fri Nov 12 04:29:47 1999
@@ -30,6 +30,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/config.h>
 #include "drmP.h"
 #include "linux/un.h"
 
diff -u --recursive --new-file v2.3.27/linux/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h
--- v2.3.27/linux/drivers/char/drm/drmP.h	Fri Sep 10 23:57:29 1999
+++ linux/drivers/char/drm/drmP.h	Fri Nov 12 04:29:47 1999
@@ -33,6 +33,7 @@
 #define _DRM_P_H_
 
 #ifdef __KERNEL__
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/char/drm/gamma_drv.c linux/drivers/char/drm/gamma_drv.c
--- v2.3.27/linux/drivers/char/drm/gamma_drv.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/char/drm/gamma_drv.c	Fri Nov 12 04:29:47 1999
@@ -30,6 +30,7 @@
  */
 
 #define EXPORT_SYMTAB
+#include <linux/config.h>
 #include "drmP.h"
 #include "gamma_drv.h"
 EXPORT_SYMBOL(gamma_init);
diff -u --recursive --new-file v2.3.27/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.3.27/linux/drivers/i2o/i2o_pci.c	Thu Nov 11 20:11:35 1999
+++ linux/drivers/i2o/i2o_pci.c	Fri Nov 12 04:29:47 1999
@@ -16,6 +16,7 @@
  *		Support polled I2O PCI controllers. 
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/isdn/eicon/eicon_isa.h linux/drivers/isdn/eicon/eicon_isa.h
--- v2.3.27/linux/drivers/isdn/eicon/eicon_isa.h	Thu Nov 11 20:11:37 1999
+++ linux/drivers/isdn/eicon/eicon_isa.h	Fri Nov 12 04:29:47 1999
@@ -48,6 +48,7 @@
 #define eicon_isa_h
 
 #ifdef __KERNEL__
+#include <linux/config.h>
 
 /* Factory defaults for ISA-Cards */
 #define EICON_ISA_MEMBASE 0xd0000
diff -u --recursive --new-file v2.3.27/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c
--- v2.3.27/linux/drivers/macintosh/via-cuda.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/macintosh/via-cuda.c	Fri Nov 12 04:29:47 1999
@@ -9,6 +9,7 @@
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include <stdarg.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.3.27/linux/drivers/net/8390.c	Thu Nov 11 20:11:39 1999
+++ linux/drivers/net/8390.c	Fri Nov 12 04:29:47 1999
@@ -47,6 +47,7 @@
 static const char *version =
     "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h
--- v2.3.27/linux/drivers/net/acenic_firmware.h	Tue Sep  7 12:14:06 1999
+++ linux/drivers/net/acenic_firmware.h	Fri Nov 12 04:29:47 1999
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 /*
  * Declare these here even if Tigon I support is disabled to avoid
  * the compiler complaining about undefined symbols.
diff -u --recursive --new-file v2.3.27/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- v2.3.27/linux/drivers/net/dmfe.c	Thu Nov 11 20:11:40 1999
+++ linux/drivers/net/dmfe.c	Fri Nov 12 04:29:47 1999
@@ -46,7 +46,6 @@
    
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- v2.3.27/linux/drivers/net/irda/toshoboe.c	Wed Oct 27 16:34:12 1999
+++ linux/drivers/net/irda/toshoboe.c	Fri Nov 12 04:29:47 1999
@@ -84,6 +84,7 @@
 
 /* No user servicable parts below here */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- v2.3.27/linux/drivers/net/pcmcia/netwave_cs.c	Thu Nov 11 20:11:41 1999
+++ linux/drivers/net/pcmcia/netwave_cs.c	Fri Nov 12 04:29:47 1999
@@ -37,6 +37,7 @@
 /* To have statistics (just packets sent) define this */
 #undef NETWAVE_STATS
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.3.27/linux/drivers/net/pcmcia/ray_cs.c	Thu Nov 11 20:11:41 1999
+++ linux/drivers/net/pcmcia/ray_cs.c	Fri Nov 12 04:29:47 1999
@@ -22,6 +22,7 @@
  * 
 =============================================================================*/
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/net/pcmcia/tulip_cb.c linux/drivers/net/pcmcia/tulip_cb.c
--- v2.3.27/linux/drivers/net/pcmcia/tulip_cb.c	Thu Nov 11 20:11:41 1999
+++ linux/drivers/net/pcmcia/tulip_cb.c	Fri Nov 12 04:29:47 1999
@@ -102,7 +102,6 @@
 #error You must compile this driver with "-O".
 #endif
 
-#include <linux/config.h>
 #include <linux/version.h>
 #ifdef MODULE
 #ifdef MODVERSIONS
diff -u --recursive --new-file v2.3.27/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h
--- v2.3.27/linux/drivers/net/pcmcia/wavelan_cs.h	Thu Nov 11 20:11:41 1999
+++ linux/drivers/net/pcmcia/wavelan_cs.h	Fri Nov 12 04:29:47 1999
@@ -358,6 +358,7 @@
 /***************************** INCLUDES *****************************/
 
 /* Linux headers that we need */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/net/setup.c linux/drivers/net/setup.c
--- v2.3.27/linux/drivers/net/setup.c	Thu Nov 11 20:11:42 1999
+++ linux/drivers/net/setup.c	Fri Nov 12 10:12:11 1999
@@ -309,7 +309,7 @@
 		static struct net_device dummy_dev = {
 			"dummy" __PAD5, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, dummy_init, 
 		};
-		register_netdev(&sb1000_dev);
+		register_netdev(&dummy_dev);
 	}
 #endif	
 #ifdef CONFIG_EQUALIZER
@@ -325,7 +325,7 @@
 			NULL,				/* next device */
 			eql_init			/* set up the rest */
 		};
-		register_netdev(&sb1000_dev);
+		register_netdev(&eql_dev);
 	}
 #endif	
 #ifdef CONFIG_APBIF
@@ -335,7 +335,7 @@
 		{
         		"bif" __PAD3, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, bif_init 
         	};
-		register_netdev(&sb1000_dev);
+		register_netdev(&bif_dev);
         }
 #endif
 #ifdef CONFIG_NET_SB1000
diff -u --recursive --new-file v2.3.27/linux/drivers/net/starfire.c linux/drivers/net/starfire.c
--- v2.3.27/linux/drivers/net/starfire.c	Thu Nov 11 20:11:42 1999
+++ linux/drivers/net/starfire.c	Fri Nov 12 04:29:47 1999
@@ -69,7 +69,6 @@
 #endif
 
 /* Include files, designed to support most kernel versions 2.0.0 and later. */
-#include <linux/config.h>
 #ifdef MODULE
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/net/wan/cycx_drv.c linux/drivers/net/wan/cycx_drv.c
--- v2.3.27/linux/drivers/net/wan/cycx_drv.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/net/wan/cycx_drv.c	Thu Nov 11 20:10:36 1999
@@ -15,6 +15,10 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* 1999/11/11	acme		set_current_state(TASK_INTERRUPTIBLE), code cleanup
+* 1999/11/08	acme		init_cyc2x deleted, doing nothing
+* 1999/11/06	acme		back to read[bw], write[bw] and memcpy_to and
+*				fromio to use dpmbase ioremaped
 * 1999/10/26	acme		use isa_read[bw], isa_write[bw] and isa_memcpy_to
 *				and fromio
 * 1999/10/23	acme		cleanup to only supports cyclom2x: all the other
@@ -58,10 +62,10 @@
 #include <linux/cycx_drv.h>	/* API definitions */
 #include <linux/cycx_cfm.h>	/* CYCX firmware module definitions */
 #include <linux/delay.h>	/* udelay */
-#include <asm/io.h>		/* for inb(), outb(), etc. */
+#include <asm/io.h>		/* read[wl], write[wl], ioremap, iounmap */
 
 #define	MOD_VERSION	0
-#define	MOD_RELEASE	3
+#define	MOD_RELEASE	4
 
 #ifdef MODULE
 MODULE_AUTHOR("Arnaldo Carvalho de Melo");
@@ -70,30 +74,29 @@
 
 /* Function Prototypes */
 /* Module entry points. These are called by the OS and must be public. */
-int init_module (void);
-void cleanup_module (void);
+int init_module(void);
+void cleanup_module(void);
 
 /* Hardware-specific functions */
-static int load_cyc2x (cycxhw_t *hw, cfm_t *cfm, u32 len);
-static void cycx_bootcfg (cycxhw_t *hw);
+static int load_cyc2x(cycxhw_t *hw, cfm_t *cfm, u32 len);
+static void cycx_bootcfg(cycxhw_t *hw);
 
-static int init_cyc2x (cycxhw_t *hw);
-static int reset_cyc2x (u32 addr);
-static int detect_cyc2x (u32 addr);
+static int reset_cyc2x(u32 addr);
+static int detect_cyc2x(u32 addr);
 
 /* Miscellaneous functions */
-static void delay_cycx (int sec);
-static int get_option_index (u32 *optlist, u32 optval);
-static u16 checksum (u8 *buf, u32 len);
+static void delay_cycx(int sec);
+static int get_option_index(u32 *optlist, u32 optval);
+static u16 checksum(u8 *buf, u32 len);
 
 #define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET)
 
-#define cyc2x_readb(b) isa_readb(b)
-#define cyc2x_readw(b) isa_readw(b)
-#define cyc2x_writeb(b, addr) isa_writeb(b, addr)
-#define cyc2x_writew(w, addr) isa_writew(w, addr)
-#define cyc2x_memcpy_toio(addr, buf, len) isa_memcpy_toio((addr), buf, len)
-#define cyc2x_memcpy_fromio(buf, addr, len) isa_memcpy_fromio(buf, (addr), len)
+#define cyc2x_readb(b) readb(b)
+#define cyc2x_readw(b) readw(b)
+#define cyc2x_writeb(b, addr) writeb(b, addr)
+#define cyc2x_writew(w, addr) writew(w, addr)
+#define cyc2x_memcpy_toio(addr, buf, len) memcpy_toio((addr), buf, len)
+#define cyc2x_memcpy_fromio(buf, addr, len) memcpy_fromio(buf, (addr), len)
 
 /* Global Data */
 
@@ -125,7 +128,7 @@
  *		< 0	error.
  * Context:	process */
 #ifdef MODULE
-int init_module (void)
+int init_module(void)
 {
 	printk(KERN_INFO "%s v%u.%u %s\n",
 		fullname, MOD_VERSION, MOD_RELEASE, copyright);
@@ -133,7 +136,7 @@
 }
 /* Module 'remove' entry point.
  * o release all remaining system resources */
-void cleanup_module (void)
+void cleanup_module(void)
 {
 }
 #endif
@@ -148,21 +151,14 @@
  * Return:	0	ok.
  *		< 0	error */
 EXPORT_SYMBOL(cycx_setup);
-int cycx_setup (cycxhw_t *hw, void *cfm, u32 len)
+int cycx_setup(cycxhw_t *hw, void *cfm, u32 len)
 {
-	if (!detect_cyc2x(hw->dpmbase)) {
-		printk(KERN_ERR "%s: adapter Cyclom 2X not found at "
-				"address 0x%lX!\n",
-			modname, (unsigned long) hw->dpmbase);
-		return -EINVAL;
-	}
-
-	printk(KERN_INFO "%s: found Cyclom 2X card at address 0x%lx.\n",
-			 modname, (unsigned long) hw->dpmbase);
+	unsigned long dpmbase = hw->dpmbase;
+	int err;
 
 	/* Verify IRQ configuration options */
 	if (!get_option_index(cycx_2x_irq_options, hw->irq)) {
-		printk (KERN_ERR "%s: IRQ %d is illegal!\n", modname, hw->irq);
+		printk(KERN_ERR "%s: IRQ %d is illegal!\n", modname, hw->irq);
 		return -EINVAL;
 	} 
 
@@ -171,34 +167,50 @@
 		printk(KERN_ERR "%s: you must specify the dpm address!\n",
 				modname);
  		return -EINVAL;
-	}
-	else if (!get_option_index(cyc2x_dpmbase_options, hw->dpmbase)) {
+	} else if (!get_option_index(cyc2x_dpmbase_options, hw->dpmbase)) {
 		printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n",
-				modname, (unsigned long) hw->dpmbase);
+				modname, dpmbase);
 		return -EINVAL;
 	}
 
+	hw->dpmbase = (u32)ioremap(dpmbase, CYCX_WINDOWSIZE);
 	hw->dpmsize = CYCX_WINDOWSIZE;
 
-	init_cyc2x(hw);
+	if (!detect_cyc2x(hw->dpmbase)) {
+		printk(KERN_ERR "%s: adapter Cyclom 2X not found at "
+				"address 0x%lX!\n", modname, dpmbase);
+		return -EINVAL;
+	}
 
-	printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
-			 modname, (unsigned long) hw->dpmbase);
+	printk(KERN_INFO "%s: found Cyclom 2X card at address 0x%lX.\n",
+			 modname, dpmbase);
 
 	/* Load firmware. If loader fails then shut down adapter */
-	return load_cyc2x(hw, cfm, len);
+	err = load_cyc2x(hw, cfm, len);
+
+	if (err)
+		cycx_down(hw);         /* shutdown adapter */
+
+	return err;
 } 
 
+EXPORT_SYMBOL(cycx_down);
+int cycx_down(cycxhw_t *hw)
+{
+	iounmap((u32 *)hw->dpmbase);
+	return 0;
+}
+
 /* Enable interrupt generation.  */
 EXPORT_SYMBOL(cycx_inten);
-void cycx_inten (cycxhw_t *hw)
+void cycx_inten(cycxhw_t *hw)
 {
-	cyc2x_writeb (0, hw->dpmbase);
+	cyc2x_writeb(0, hw->dpmbase);
 }
 
 /* Generate an interrupt to adapter's CPU. */
 EXPORT_SYMBOL(cycx_intr);
-void cycx_intr (cycxhw_t *hw)
+void cycx_intr(cycxhw_t *hw)
 {
 	cyc2x_writew(0, hw->dpmbase + GEN_CYCX_INTR);
 }
@@ -207,7 +219,7 @@
  * o Set exec flag.
  * o Busy-wait until flag is reset. */
 EXPORT_SYMBOL(cycx_exec);
-int cycx_exec (u32 addr)
+int cycx_exec(u32 addr)
 {
 	u16 i = 0;
 	/* wait till addr content is zeroed */
@@ -223,10 +235,12 @@
 /* Read absolute adapter memory.
  * Transfer data from adapter's memory to data buffer. */
 EXPORT_SYMBOL(cycx_peek);
-int cycx_peek (cycxhw_t *hw, u32 addr, void *buf, u32 len)
+int cycx_peek(cycxhw_t *hw, u32 addr, void *buf, u32 len)
 {
-	if (len == 1)	*(u8*)buf = cyc2x_readb (hw->dpmbase + addr);
-	else 		cyc2x_memcpy_fromio(buf, hw->dpmbase + addr, len);
+	if (len == 1)
+		*(u8*)buf = cyc2x_readb(hw->dpmbase + addr);
+	else
+		cyc2x_memcpy_fromio(buf, hw->dpmbase + addr, len);
 
 	return 0;
 }
@@ -234,10 +248,12 @@
 /* Write Absolute Adapter Memory.
  * Transfer data from data buffer to adapter's memory. */
 EXPORT_SYMBOL(cycx_poke);
-int cycx_poke (cycxhw_t *hw, u32 addr, void *buf, u32 len)
+int cycx_poke(cycxhw_t *hw, u32 addr, void *buf, u32 len)
 {
-	if (len == 1) cyc2x_writeb (*(u8*)buf, hw->dpmbase + addr);
-	else	      cyc2x_memcpy_toio(hw->dpmbase + addr, buf, len);
+	if (len == 1)
+		cyc2x_writeb(*(u8*)buf, hw->dpmbase + addr);
+	else
+		cyc2x_memcpy_toio(hw->dpmbase + addr, buf, len);
 
 	return 0;
 }
@@ -249,13 +265,13 @@
    return 1 if memory exists at addr and 0 if not. */
 static int memory_exists(u32 addr)
 {
-	int timeout = 0;
+	int tries = 0;
 
-	for (; timeout < 3 ; timeout++) {
-		cyc2x_writew (TEST_PATTERN, addr + 0x10);
+	for (; tries < 3 ; tries++) {
+		cyc2x_writew(TEST_PATTERN, addr + 0x10);
 
-		if (cyc2x_readw (addr + 0x10) == TEST_PATTERN)
-			if (cyc2x_readw (addr + 0x10) == TEST_PATTERN) return 1;
+		if (cyc2x_readw(addr + 0x10) == TEST_PATTERN)
+			if (cyc2x_readw(addr + 0x10) == TEST_PATTERN) return 1;
 
 		delay_cycx(1);
 	}
@@ -267,10 +283,10 @@
 static void reset_load(u32 addr, u8 *buffer, u32 cnt)
 {
 	u32 pt_code = addr + RESET_OFFSET;
-	u16 i, j;
+	u16 i; /*, j; */
 
-	for ( i = 0 ; i < cnt ; i++) {
-		for (j = 0 ; j < 50 ; j++); /* Delay - FIXME busy waiting... */
+	for (i = 0 ; i < cnt ; i++) {
+/*		for (j = 0 ; j < 50 ; j++); Delay - FIXME busy waiting... */
 		cyc2x_writeb(*buffer++, pt_code++);
 	}
 }
@@ -286,7 +302,7 @@
 }
 
 /* Set up entry point and kick start Cyclom-X CPU. */
-static void cycx_start (u32 addr)
+static void cycx_start(u32 addr)
 {
 	/* put in 0x30 offset the jump instruction to the code entry point */
 	cyc2x_writeb(0xea, addr + 0x30);
@@ -326,19 +342,21 @@
 	cyc2x_writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
 	cyc2x_writew(GEN_DEFPAR, pt_boot_cmd);
 
-	if (wait_cyc(addr) < 0) return 2;
+	if (wait_cyc(addr) < 0)
+		return -1;
 
 	cyc2x_writew(0, pt_boot_cmd + sizeof(u16));
 	cyc2x_writew(0x4000, pt_boot_cmd + 2 * sizeof(u16));
 	cyc2x_writew(GEN_SET_SEG, pt_boot_cmd);
 
-	if (wait_cyc(addr) < 0) return 2;
+	if (wait_cyc(addr) < 0)
+		return -1;
 
 	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
 		if (buffer_load(addr, code + i,
 				MIN(CFM_LOAD_BUFSZ, (len - i))) < 0) {
 			printk(KERN_ERR "%s: Error !!\n", modname);
-			return 4;
+			return -1;
 		}
 
 	return 0;
@@ -355,18 +373,20 @@
 	cyc2x_writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
 	cyc2x_writew(GEN_DEFPAR, pt_boot_cmd);
 
-	if (wait_cyc(addr) == -1) return 2;
+	if (wait_cyc(addr) < 0)
+		return -1;
 
 	cyc2x_writew(0x0000, pt_boot_cmd + sizeof(u16));
 	cyc2x_writew(0xc400, pt_boot_cmd + 2 * sizeof(u16));
 	cyc2x_writew(GEN_SET_SEG, pt_boot_cmd);
 
-	if (wait_cyc(addr) == -1) return 1;
+	if (wait_cyc(addr) < 0)
+		return -1;
 
 	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
 		if (buffer_load(addr, code + i,MIN(CFM_LOAD_BUFSZ,(len - i)))) {
 			printk(KERN_ERR "%s: Error !!\n", modname);
-			return 4;
+			return -1;
 		}
 
 	return 0;
@@ -375,7 +395,7 @@
 /* Load adapter from the memory image of the CYCX firmware module. 
  * o verify firmware integrity and compatibility
  * o start adapter up */
-static int load_cyc2x (cycxhw_t *hw, cfm_t *cfm, u32 len)
+static int load_cyc2x(cycxhw_t *hw, cfm_t *cfm, u32 len)
 {
 	int i, j;
 	cycx_header_t *img_hdr;
@@ -386,8 +406,8 @@
 	u16 cksum;
 
 	/* Announce */
-	printk(KERN_INFO "%s: firmware signature=\"%s\"\n",
-			 modname, cfm->signature); 
+	printk(KERN_INFO "%s: firmware signature=\"%s\"\n", modname,
+							    cfm->signature);
 
 	/* Verify firmware signature */
 	if (strcmp(cfm->signature, CFM_SIGNATURE)) {
@@ -456,23 +476,24 @@
 		delay_cycx(1);
 
 		for (j = 0 ; j < 3 ; j++)
-			if (!cyc2x_readw(pt_cycld)) goto reset_loaded;
-			else delay_cycx(1);
+			if (!cyc2x_readw(pt_cycld))
+				goto reset_loaded;
+			else
+				delay_cycx(1);
 	}
 
 	printk(KERN_ERR "%s: reset not started.\n", modname);
 	return -EINVAL;
+
 reset_loaded:
 	/* Load data.bin */
-	if(cycx_data_boot(hw->dpmbase, data_image, 
-				       img_hdr->data_size)) {
+	if (cycx_data_boot(hw->dpmbase, data_image, img_hdr->data_size)) {
 		printk(KERN_ERR "%s: cannot load data file.\n", modname);
 		return -EINVAL;
 	}
 
 	/* Load code.bin */
-	if(cycx_code_boot(hw->dpmbase, code_image, 
-				       img_hdr->code_size)) {
+	if (cycx_code_boot(hw->dpmbase, code_image, img_hdr->code_size)) {
 		printk(KERN_ERR "%s: cannot load code file.\n", modname);
 		return -EINVAL;
 	}
@@ -500,32 +521,20 @@
    - As of now, only static buffers are available to the user.
      So, the bit VD_RXDIRC must be set in 'valid'. That means that user
      wants to use the static transmission and reception buffers. */
-static void cycx_bootcfg (cycxhw_t *hw)
+static void cycx_bootcfg(cycxhw_t *hw)
 {
 	/* use fixed buffers */
 	cyc2x_writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET); 
 }
 
-/* Initialize CYCX_2X adapter. */
-static int init_cyc2x (cycxhw_t *hw)
-{
-	if (!detect_cyc2x(hw->dpmbase))
-		return -ENODEV;
-
-	return 0;
-}
-
 /* Detect Cyclom 2x adapter.
  *	Following tests are used to detect Cyclom 2x adapter:
  *       to be completed based on the tests done below
  *	Return 1 if detected o.k. or 0 if failed.
  *	Note:	This test is destructive! Adapter will be left in shutdown
  *		state after the test. */
-static int detect_cyc2x (u32 addr)
+static int detect_cyc2x(u32 addr)
 {
-	printk(KERN_INFO "%s: looking for a cyclom 2x at 0x%lX...\n",
-			 modname, (unsigned long) addr);
-
 	reset_cyc2x(addr);
 	return memory_exists(addr);
 }
@@ -533,35 +542,36 @@
 /* Miscellaneous */
 /* Get option's index into the options list.
  *	Return option's index (1 .. N) or zero if option is invalid. */
-static int get_option_index (u32 *optlist, u32 optval)
+static int get_option_index(u32 *optlist, u32 optval)
 {
 	int i = 1;
-	for (; i <= optlist[0]; ++i) if (optlist[i] == optval) return i;
+
+	for (; i <= optlist[0]; ++i)
+		if (optlist[i] == optval)
+			return i;
+
 	return 0;
 }
 
 /* Reset adapter's CPU. */
-static int reset_cyc2x (u32 addr)
+static int reset_cyc2x(u32 addr)
 {
-	cyc2x_writeb (0, addr + RST_ENABLE);  delay_cycx (2);
-	cyc2x_writeb (0, addr + RST_DISABLE); delay_cycx (2);
+	cyc2x_writeb(0, addr + RST_ENABLE);
+	delay_cycx(2);
+	cyc2x_writeb(0, addr + RST_DISABLE);
+	delay_cycx(2);
 	return memory_exists(addr);
 }
 
 /* Delay */
-static void delay_cycx (int sec)
+static void delay_cycx(int sec)
 {
-/* acme
-   Thu dez 31 21:45:16 EDT 1998
-   FIXME I'll keep this comment here just in case, as of now I don't
-   know it all the contexts where this routine is used are interruptible... */
-
-	current->state = TASK_INTERRUPTIBLE;
+	set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout(sec*HZ);
 }
 
 /* Calculate 16-bit CRC using CCITT polynomial. */
-static u16 checksum (u8 *buf, u32 len)
+static u16 checksum(u8 *buf, u32 len)
 {
 	u16 crc = 0;
 	u16 mask, flag;
@@ -571,7 +581,9 @@
 			flag = (crc & 0x8000);
 			crc <<= 1;
 			crc |= ((*buf & mask) ? 1 : 0);
-			if (flag) crc ^= 0x1021;
+
+			if (flag)
+				crc ^= 0x1021;
 		}
 
 	return crc;
diff -u --recursive --new-file v2.3.27/linux/drivers/net/wan/cycx_main.c linux/drivers/net/wan/cycx_main.c
--- v2.3.27/linux/drivers/net/wan/cycx_main.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/net/wan/cycx_main.c	Thu Nov 11 20:10:36 1999
@@ -13,6 +13,8 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* 1999/11/06	acme		cycx_down back to life (it needs to be
+*				called to iounmap the dpmbase)
 * 1999/08/09	acme		removed references to enable_tx_int
 *				use spinlocks instead of cli/sti in
 *				cyclomx_set_state
@@ -248,6 +250,7 @@
 	}
 
 	if (err) {
+		cycx_down(&card->hw);
 		free_irq(irq, card);
 		return err;
 	}
@@ -274,7 +277,8 @@
 
 	card = wandev->private;
 	wandev->state = WAN_UNCONFIGURED;
-	printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name,wandev->irq);
+	cycx_down(&card->hw);
+	printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name, wandev->irq);
 	free_irq(wandev->irq, card);
 	return 0;
 }
diff -u --recursive --new-file v2.3.27/linux/drivers/nubus/proc.c linux/drivers/nubus/proc.c
--- v2.3.27/linux/drivers/nubus/proc.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/nubus/proc.c	Fri Nov 12 04:29:47 1999
@@ -17,7 +17,6 @@
    icons) these files will provide "cooked" data.  Otherwise they will
    simply provide raw access (read-only of course) to the ROM.  */
 
-#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/pci/helper.c linux/drivers/pci/helper.c
--- v2.3.27/linux/drivers/pci/helper.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/pci/helper.c	Fri Nov 12 04:29:47 1999
@@ -8,7 +8,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 
diff -u --recursive --new-file v2.3.27/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- v2.3.27/linux/drivers/pci/pci.ids	Thu Nov 11 20:11:42 1999
+++ linux/drivers/pci/pci.ids	Fri Nov 12 10:12:11 1999
@@ -543,14 +543,16 @@
 	0406  85C501/2
 	0496  85C496
 	0530  530 Host
+	0540  540 Host
 	0597  5513C
 	0601  85C601
 	0620  620 Host
+	0630  630 Host
 	0900  SiS900 10/100 Ethernet
 	3602  83C602
 	5107  5107
 	5511  5511/5512
-	5513  5513
+	5513  5513 [IDE]
 	5517  5517
 	5571  5571
 	5591  5591/5592 Host
diff -u --recursive --new-file v2.3.27/linux/drivers/pci/syscall.c linux/drivers/pci/syscall.c
--- v2.3.27/linux/drivers/pci/syscall.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/pci/syscall.c	Fri Nov 12 04:29:47 1999
@@ -7,7 +7,6 @@
  * magic northbridge registers..
  */
 
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c
--- v2.3.27/linux/drivers/pcmcia/cistpl.c	Thu Nov 11 20:11:42 1999
+++ linux/drivers/pcmcia/cistpl.c	Fri Nov 12 04:29:47 1999
@@ -33,6 +33,7 @@
 
 #define __NO_VERSION__
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h
--- v2.3.27/linux/drivers/pcmcia/cs_internal.h	Thu Nov 11 20:11:42 1999
+++ linux/drivers/pcmcia/cs_internal.h	Fri Nov 12 11:29:06 1999
@@ -19,6 +19,8 @@
 #ifndef _LINUX_CS_INTERNAL_H
 #define _LINUX_CS_INTERNAL_H
 
+#include <linux/config.h>
+
 typedef struct erase_busy_t {
     eraseq_entry_t	*erase;
     client_handle_t	client;
diff -u --recursive --new-file v2.3.27/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- v2.3.27/linux/drivers/pcmcia/ds.c	Thu Nov 11 20:11:42 1999
+++ linux/drivers/pcmcia/ds.c	Fri Nov 12 04:29:47 1999
@@ -31,6 +31,7 @@
     
 ======================================================================*/
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c
--- v2.3.27/linux/drivers/pcmcia/rsrc_mgr.c	Thu Nov 11 20:11:42 1999
+++ linux/drivers/pcmcia/rsrc_mgr.c	Fri Nov 12 04:29:47 1999
@@ -33,6 +33,7 @@
 
 #define __NO_VERSION__
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/sbus/char/uctrl.c linux/drivers/sbus/char/uctrl.c
--- v2.3.27/linux/drivers/sbus/char/uctrl.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/sbus/char/uctrl.c	Fri Nov 12 04:29:47 1999
@@ -4,7 +4,6 @@
  * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/scsi/i60uscsi.h linux/drivers/scsi/i60uscsi.h
--- v2.3.27/linux/drivers/scsi/i60uscsi.h	Tue Sep  7 12:14:06 1999
+++ linux/drivers/scsi/i60uscsi.h	Fri Nov 12 04:29:47 1999
@@ -60,6 +60,8 @@
  *	12/19/98 bv, v1.02a Use spinlocks for 2.1.95 and up.
  **************************************************************************/
 
+#include <linux/config.h>
+
 #define ULONG   unsigned long
 #define PVOID   void *
 #define USHORT  unsigned short
diff -u --recursive --new-file v2.3.27/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.3.27/linux/drivers/scsi/ide-scsi.c	Thu Nov 11 20:11:47 1999
+++ linux/drivers/scsi/ide-scsi.c	Fri Nov 12 10:12:11 1999
@@ -307,7 +307,7 @@
 /*
  *	Our interrupt handler.
  */
-static void idescsi_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	byte status, ireason;
@@ -337,15 +337,14 @@
 		if (status & ERR_STAT)
 			rq->errors++;
 		idescsi_end_request (1, HWGROUP(drive));
-		return;
+		return ide_stopped;
 	}
 	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
 	ireason = IN_BYTE (IDE_IREASON_REG);
 
 	if (ireason & IDESCSI_IREASON_COD) {
 		printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (ireason & IDESCSI_IREASON_IO) {
 		temp = pc->actually_transferred + bcount;
@@ -365,7 +364,7 @@
 				pc->current_position += temp;
 				idescsi_discard_data (drive,bcount - temp);
 				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
-				return;
+				return ide_started;
 			}
 #if IDESCSI_DEBUG_LOG
 			printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");
@@ -389,32 +388,34 @@
 	pc->current_position+=bcount;
 
 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
+	return ide_started;
 }
 
-static void idescsi_transfer_pc (ide_drive_t *drive)
+static ide_startstop_t idescsi_transfer_pc (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	idescsi_pc_t *pc = scsi->pc;
 	byte ireason;
+	ide_startstop_t startstop;
 
-	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk (KERN_ERR "ide-scsi: Strange, packet command initiated yet DRQ isn't asserted\n");
-		return;
+		return startstop;
 	}
 	ireason = IN_BYTE (IDE_IREASON_REG);
 	if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {
 		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* Set the interrupt routine */
 	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */
+	return ide_started;
 }
 
 /*
  *	Issue a packet command
  */
-static void idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
+static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	int bcount;
@@ -443,16 +444,17 @@
 	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
 		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		idescsi_transfer_pc (drive);
+		return idescsi_transfer_pc (drive);
 	}
 }
 
 /*
  *	idescsi_do_request is our request handling function.
  */
-static void idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 #if IDESCSI_DEBUG_LOG
 	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
@@ -460,11 +462,11 @@
 #endif /* IDESCSI_DEBUG_LOG */
 
 	if (rq->cmd == IDESCSI_PC_RQ) {
-		idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer);
-		return;
+		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer);
 	}
 	printk (KERN_ERR "ide-scsi: %s: unsupported command in request queue (%x)\n", drive->name, rq->cmd);
 	idescsi_end_request (0,HWGROUP (drive));
+	return ide_stopped;
 }
 
 static int idescsi_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
diff -u --recursive --new-file v2.3.27/linux/drivers/scsi/ini9100u.h linux/drivers/scsi/ini9100u.h
--- v2.3.27/linux/drivers/scsi/ini9100u.h	Thu Nov 11 20:11:47 1999
+++ linux/drivers/scsi/ini9100u.h	Fri Nov 12 11:30:07 1999
@@ -82,10 +82,7 @@
 extern int i91u_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 extern int i91u_abort(Scsi_Cmnd *);
 extern int i91u_reset(Scsi_Cmnd *, unsigned int);
-
 extern int i91u_biosparam(Scsi_Disk *, kdev_t, int *);	/*for linux v2.0 */
-extern struct proc_dir_entry proc_scsi_ini9100u;
-#endif
 
 #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.03g"
 
diff -u --recursive --new-file v2.3.27/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c
--- v2.3.27/linux/drivers/scsi/inia100.c	Thu Nov 11 20:11:47 1999
+++ linux/drivers/scsi/inia100.c	Fri Nov 12 04:29:47 1999
@@ -80,7 +80,6 @@
 #include <linux/blk.h>
 #include <linux/spinlock.h>
 #include <linux/stat.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/scsi/qlogicfc.h linux/drivers/scsi/qlogicfc.h
--- v2.3.27/linux/drivers/scsi/qlogicfc.h	Thu Aug 26 13:05:39 1999
+++ linux/drivers/scsi/qlogicfc.h	Fri Nov 12 04:40:46 1999
@@ -86,8 +86,6 @@
 #define NULL (0)
 #endif
 
-extern struct proc_dir_entry proc_scsi_isp2x00;
-
 #define QLOGICFC {							   \
         detect:                 isp2x00_detect,                            \
         release:                isp2x00_release,                           \
diff -u --recursive --new-file v2.3.27/linux/drivers/scsi/qlogicisp.h linux/drivers/scsi/qlogicisp.h
--- v2.3.27/linux/drivers/scsi/qlogicisp.h	Sun Dec 21 17:04:49 1997
+++ linux/drivers/scsi/qlogicisp.h	Fri Nov 12 04:40:46 1999
@@ -70,8 +70,6 @@
 #define NULL (0)
 #endif
 
-extern struct proc_dir_entry proc_scsi_isp1020;
-
 #define QLOGICISP {							   \
 	detect:			isp1020_detect,				   \
 	release:		isp1020_release,			   \
diff -u --recursive --new-file v2.3.27/linux/drivers/scsi/qlogicpti.h linux/drivers/scsi/qlogicpti.h
--- v2.3.27/linux/drivers/scsi/qlogicpti.h	Mon Mar 15 16:11:31 1999
+++ linux/drivers/scsi/qlogicpti.h	Fri Nov 12 04:40:46 1999
@@ -163,8 +163,6 @@
 int qlogicpti_abort(Scsi_Cmnd *);
 int qlogicpti_reset(Scsi_Cmnd *, unsigned int);
 
-extern struct proc_dir_entry proc_scsi_qlogicpti;
-
 /* mailbox command complete status codes */
 #define MBOX_COMMAND_COMPLETE		0x4000
 #define INVALID_COMMAND			0x4001
diff -u --recursive --new-file v2.3.27/linux/drivers/scsi/sim710.c linux/drivers/scsi/sim710.c
--- v2.3.27/linux/drivers/scsi/sim710.c	Thu Nov 11 20:11:48 1999
+++ linux/drivers/scsi/sim710.c	Fri Nov 12 04:29:47 1999
@@ -60,6 +60,7 @@
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/scsi/wd33c93.h linux/drivers/scsi/wd33c93.h
--- v2.3.27/linux/drivers/scsi/wd33c93.h	Mon Oct  4 15:49:30 1999
+++ linux/drivers/scsi/wd33c93.h	Fri Nov 12 04:29:47 1999
@@ -23,6 +23,7 @@
 #ifndef WD33C93_H
 #define WD33C93_H
 
+#include <linux/config.h>
 
 #define PROC_INTERFACE     /* add code for /proc/scsi/wd33c93/xxx interface */
 #ifdef  PROC_INTERFACE
diff -u --recursive --new-file v2.3.27/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c
--- v2.3.27/linux/drivers/sound/adlib_card.c	Mon Oct  4 15:49:30 1999
+++ linux/drivers/sound/adlib_card.c	Fri Nov 12 04:29:47 1999
@@ -10,8 +10,6 @@
  * for more info.
  */
 
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include "sound_config.h"
 #include "soundmodule.h"
diff -u --recursive --new-file v2.3.27/linux/drivers/sound/lowlevel/miroaci.h linux/drivers/sound/lowlevel/miroaci.h
--- v2.3.27/linux/drivers/sound/lowlevel/miroaci.h	Mon Oct  4 15:49:30 1999
+++ linux/drivers/sound/lowlevel/miroaci.h	Fri Nov 12 04:29:47 1999
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #if defined(CONFIG_ACI_MIXER) || defined(CONFIG_ACI_MIXER_MODULE)
 extern int aci_implied_cmd(unsigned char opcode);
 extern int aci_write_cmd(unsigned char opcode, unsigned char parameter);
diff -u --recursive --new-file v2.3.27/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.3.27/linux/drivers/sound/maestro.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/sound/maestro.c	Fri Nov 12 04:29:47 1999
@@ -177,6 +177,7 @@
 
 /*****************************************************************************/
 
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 
diff -u --recursive --new-file v2.3.27/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
--- v2.3.27/linux/drivers/sound/opl3.c	Mon Oct  4 15:49:30 1999
+++ linux/drivers/sound/opl3.c	Fri Nov 12 04:29:47 1999
@@ -20,7 +20,6 @@
  *	OPL3 devices.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 
diff -u --recursive --new-file v2.3.27/linux/drivers/usb/ezusb.c linux/drivers/usb/ezusb.c
--- v2.3.27/linux/drivers/usb/ezusb.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/usb/ezusb.c	Fri Nov 12 04:29:47 1999
@@ -34,7 +34,6 @@
 
 /*****************************************************************************/
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/socket.h>
 #include <linux/list.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.27/linux/drivers/usb/printer.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/usb/printer.c	Fri Nov 12 04:26:37 1999
@@ -165,7 +165,7 @@
 	unsigned long partial;
 	int result = USB_ST_NOERROR;
 	int maxretry;
-	
+
 	do {
 		char *obuf = p->obuf;
 		unsigned long thistime;
@@ -180,7 +180,7 @@
 			if (signal_pending(current)) {
 				return bytes_written ? bytes_written : -EINTR;
 			}
-			result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
+			result = usb_bulk_msg(p->pusb_dev,
 					 usb_sndbulkpipe(p->pusb_dev, p->bulk_out_ep),
 					 obuf, thistime, &partial, HZ*20);
 			if (partial) {
@@ -233,7 +233,7 @@
 			return -ENODEV;
 		this_read = (count > sizeof(buf)) ? sizeof(buf) : count;
 
-		result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
+		result = usb_bulk_msg(p->pusb_dev,
 			  usb_rcvbulkpipe(p->pusb_dev, p->bulk_in_ep),
 			  buf, this_read, &partial, HZ*20);
 
diff -u --recursive --new-file v2.3.27/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.27/linux/drivers/usb/usb.c	Thu Nov 11 20:11:49 1999
+++ linux/drivers/usb/usb.c	Fri Nov 12 13:22:56 1999
@@ -1304,6 +1304,11 @@
 	return ret;
 }
 
+int usb_bulk_msg(struct usb_device *dev, unsigned int pipe, void *data, int len, unsigned long *rval, int timeout)
+{
+	return dev->bus->op->bulk_msg(dev, pipe, data, len, rval, timeout);
+}
+
 void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
 {
 	return dev->bus->op->request_bulk(dev, pipe, handler, data, len, dev_id);
@@ -1517,7 +1522,7 @@
 EXPORT_SYMBOL(usb_control_msg);
 EXPORT_SYMBOL(usb_request_irq);
 EXPORT_SYMBOL(usb_release_irq);
-/* EXPORT_SYMBOL(usb_bulk_msg); */
+EXPORT_SYMBOL(usb_bulk_msg);
 EXPORT_SYMBOL(usb_request_bulk);
 EXPORT_SYMBOL(usb_terminate_bulk);
 
diff -u --recursive --new-file v2.3.27/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.27/linux/drivers/usb/usb.h	Sun Nov  7 16:37:34 1999
+++ linux/drivers/usb/usb.h	Fri Nov 12 13:22:56 1999
@@ -579,6 +579,7 @@
 extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *, void **);
 extern int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe);
 
+extern int usb_bulk_msg(struct usb_device *, unsigned int, void *, int, unsigned long *, int);
 extern void *usb_request_bulk(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *);
 extern int usb_terminate_bulk(struct usb_device *, void *);
 
@@ -694,6 +695,8 @@
 #define usb_rcvisocpipe(dev,endpoint)	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
 #define usb_sndbulkpipe(dev,endpoint)	((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
 #define usb_rcvbulkpipe(dev,endpoint)	((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndintpipe(dev,endpoint)	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvintpipe(dev,endpoint)	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
 #define usb_snddefctrl(dev)		((PIPE_CONTROL << 30) | __default_pipe(dev))
 #define usb_rcvdefctrl(dev)		((PIPE_CONTROL << 30) | __default_pipe(dev) | USB_DIR_IN)
 
diff -u --recursive --new-file v2.3.27/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
--- v2.3.27/linux/drivers/usb/usb_scsi.c	Thu Nov 11 20:11:49 1999
+++ linux/drivers/usb/usb_scsi.c	Fri Nov 12 13:22:56 1999
@@ -1,14 +1,14 @@
 
-/* Driver for USB scsi like devices
- * 
+/* Driver for USB SCSI-like devices
+ *
  * (C) Michael Gee (michael@linuxspecific.com) 1999
  *
  * This driver is schizoid  - it makes a USB device appear as both a SCSI device
  * and a character device. The latter is only available if the device has an
  * interrupt endpoint, and is used specifically to receive interrupt events.
  *
- * In order to support various 'strange' devices, this module supports plug in
- * device specific filter modules, which can do their own thing when required.
+ * In order to support various 'strange' devices, this module supports plug-in
+ * device-specific filter modules, which can do their own thing when required.
  *
  * Further reference.
  *	This driver is based on the 'USB Mass Storage Class' document. This
@@ -55,6 +55,12 @@
 
 };
 
+#ifdef REWRITE_PROJECT
+#define IRQ_PERIOD		255
+#else
+#define IRQ_PERIOD		0	/* single IRQ transfer then remove it */
+#endif
+
 /*
  * Per device data
  */
@@ -68,7 +74,7 @@
 	struct usb_device 	*pusb_dev;
 	struct usb_scsi_filter  *filter;		/* filter driver */
 	void 			*fdata;			/* filter data */
-	unsigned int		flags;			/* from filter initially*/
+	unsigned int		flags;			/* from filter initially */
 	__u8			ifnum;			/* interface number */
 	__u8			ep_in;			/* in endpoint */
 	__u8			ep_out;			/* out ....... */
@@ -91,9 +97,11 @@
 	__u16			ip_data;		/* interrupt data */
 	int			ip_wanted;		/* needed */
 	int			pid;			/* control thread */
-	struct semaphore      	*notify; 		/* wait for thread to begin */
+	struct semaphore	*notify; 		/* wait for thread to begin */
 	void			*irq_handle;		/* for USB interrupt requests */
 	unsigned int		irqpipe;		/* remember pipe for release_irq */
+	int			mode_xlate;		/* if current SCSI command is MODE_6 */
+							/* but is translated to MODE_10 for UFI */
 };
 
 /*
@@ -142,8 +150,8 @@
 	length -= this_xfer;
 	do {
 	    /* US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer); */
-	    result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, pipe, buf, 
-						    this_xfer, &partial, HZ*5);
+	    result = usb_bulk_msg(us->pusb_dev, pipe, buf,
+				this_xfer, &partial, HZ*5);
 
 	    if (result != 0 || partial != this_xfer)
 		US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n",
@@ -152,7 +160,7 @@
 	    if (result == USB_ST_STALL) {
 		US_DEBUGP("clearing endpoint halt for pipe %x\n", pipe);
 		usb_clear_halt(us->pusb_dev,
-			       usb_pipeendpoint(pipe) | (pipe & USB_DIR_IN));
+			usb_pipeendpoint(pipe) | (pipe & USB_DIR_IN));
 	    }
 
 	    /* we want to retry if the device reported NAK */
@@ -313,6 +321,7 @@
 
 	    case MODE_SENSE:
 	    case MODE_SELECT:
+		us->mode_xlate = (srb->cmnd[0] == MODE_SENSE);
 		cmd[0] = srb->cmnd[0] | 0x40;
 		cmd[1] = srb->cmnd[1];
 		cmd[2] = srb->cmnd[2];
@@ -320,6 +329,7 @@
 		break;
 
 	    default:
+		us->mode_xlate = 0;
 		memcpy(cmd, srb->cmnd, srb->cmd_len);
 		break;
 	    }
@@ -385,7 +395,7 @@
 	    return DID_ABORT << 16;
 	}
 	US_DEBUGP("Got AP status %x %x\n", status[0], status[1]);
-	if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY && 
+	if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY &&
 	    ( (status[0] & ~3) || status[1]))
 	    return (DID_OK << 16) | 2;
 	else
@@ -397,9 +407,9 @@
 
 	/* add interrupt transfer, marked for removal */
 	us->ip_wanted = 1;
-	us->irqpipe = usb_rcvctrlpipe(us->pusb_dev, us->ep_int);
+	us->irqpipe = usb_rcvintpipe(us->pusb_dev, us->ep_int);
 	result = usb_request_irq(us->pusb_dev, us->irqpipe, pop_CBI_irq,
-				0, (void *)us, &us->irq_handle);
+				IRQ_PERIOD, (void *)us, &us->irq_handle);
 	if (result) {
 	    US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n",
 		result);
@@ -407,6 +417,11 @@
 	}
 
 	sleep_on(&us->ip_waitq);
+#ifdef REWRITE_PROJECT
+    	usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
+	us->irq_handle = NULL;
+#endif
+
 	if (us->ip_wanted) {
 	    US_DEBUGP("Did not get interrupt on CBI\n");
 	    us->ip_wanted = 0;
@@ -527,9 +542,9 @@
     US_DEBUGP("Bulk command S %x T %x L %d F %d CL %d\n",
 		bcb.Signature, bcb.Tag, bcb.DataTransferLength,
 		bcb.Flags, bcb.Length);
-    result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev,
-		     usb_sndbulkpipe(us->pusb_dev, us->ep_out), &bcb, 
-					    US_BULK_CB_WRAP_LEN, &partial, HZ*5);
+    result = usb_bulk_msg(us->pusb_dev,
+			usb_sndbulkpipe(us->pusb_dev, us->ep_out), &bcb,
+			US_BULK_CB_WRAP_LEN, &partial, HZ*5);
     if (result) {
 	US_DEBUGP("Bulk command result %x\n", result);
 	return DID_ABORT << 16;
@@ -550,9 +565,9 @@
 
     stall = 0;
     do {
-	result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev,
-			 usb_rcvbulkpipe(us->pusb_dev, us->ep_in), &bcs, 
-						US_BULK_CS_WRAP_LEN, &partial, HZ*5);
+	result = usb_bulk_msg(us->pusb_dev,
+			usb_rcvbulkpipe(us->pusb_dev, us->ep_in), &bcs,
+			US_BULK_CS_WRAP_LEN, &partial, HZ*5);
 	if (result == USB_ST_STALL || result == USB_ST_TIMEOUT)
 	    stall++;
 	else
@@ -635,7 +650,6 @@
     if (us->irq_handle) {
     	usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
 	us->irq_handle = NULL;
-	us->irqpipe = 0;
     }
     if (us->filter)
 	us->filter->release(us->fdata);
@@ -831,7 +845,7 @@
     //exit_fs(current);
 
     sprintf(current->comm, "usbscsi%d", us->host_number);
-    
+
     unlock_kernel();
 
     up(us->notify);
@@ -868,7 +882,7 @@
 		    /* check for variable length - do properly if so */
 
 		    if (us->filter && us->filter->command)
-		        us->srb->result = us->filter->command(us->fdata, us->srb);
+			us->srb->result = us->filter->command(us->fdata, us->srb);
 		    else if (us->srb->cmnd[0] == START_STOP &&
 			     us->pusb_dev->descriptor.idProduct == 0x0001 &&
 			     us->pusb_dev->descriptor.idVendor == 0x04e6)
@@ -884,7 +898,7 @@
 			    else
 				break;
 			    saveallocation = us->srb->cmnd[4];
-                            us->srb->cmnd[4] = 18;
+			    us->srb->cmnd[4] = 18;
 			    break;
 
 			case INQUIRY:
@@ -893,7 +907,7 @@
 			    else
 				break;
 			    saveallocation = us->srb->cmnd[4];
-                            us->srb->cmnd[4] = 36;
+			    us->srb->cmnd[4] = 36;
 			    break;
 
 			case MODE_SENSE:
@@ -902,7 +916,7 @@
 			    else
 				break;
 			    saveallocation = us->srb->cmnd[4];
-                            us->srb->cmnd[4] = 4;
+			    us->srb->cmnd[4] = 4;
 			    break;
 
 			case LOG_SENSE:
@@ -912,14 +926,14 @@
 			    else
 				break;
 			    saveallocation = (us->srb->cmnd[7] << 8) | us->srb->cmnd[8];
-                            us->srb->cmnd[7] = 0;
-                            us->srb->cmnd[8] = 8;
+			    us->srb->cmnd[7] = 0;
+			    us->srb->cmnd[8] = 8;
 			    break;
 
 			default:
 			    break;
 			} /* end switch on cmnd[0] */
-		        us->srb->result = us->pop(us->srb);
+			us->srb->result = us->pop(us->srb);
 
 			if (savelen != us->srb->request_bufflen &&
 			    us->srb->result == (DID_OK << 16)) {
@@ -961,7 +975,7 @@
 				savelen, length);
 
 			    if (us->srb->request_bufflen != length) {
-			        US_DEBUGP("redoing cmd with len=%d\n", length);
+				US_DEBUGP("redoing cmd with len=%d\n", length);
 				us->srb->request_bufflen = length;
 				us->srb->result = us->pop(us->srb);
 			    }
@@ -982,6 +996,17 @@
 				    printk("\n");
 				}
 				us->srb->cmnd[4] = saveallocation;
+				if (us->mode_xlate) {
+					/* convert MODE_SENSE_10 return data
+					 * format to MODE_SENSE_6 format */
+					unsigned char *dta = (unsigned char *)us->srb->request_buffer;
+					dta[0] = dta[1];	/* data len */
+					dta[1] = dta[2];	/* med type */
+					dta[2] = dta[3];	/* dev-spec prm */
+					dta[3] = dta[7];	/* block desc len */
+					printk (KERN_DEBUG USB_SCSI "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
+						dta[0], dta[1], dta[2], dta[3]);
+				}
 				break;
 
 			    case LOG_SENSE:
@@ -1006,7 +1031,7 @@
 				    }
 				}
 			    } else if (us->srb->cmnd[0] != INQUIRY &&
-				       us->srb->result == (DID_OK << 16)) {
+				    us->srb->result == (DID_OK << 16)) {
 				us->srb->result |= 2;	/* force check condition */
 			    }
 			}
@@ -1108,13 +1133,13 @@
 
 	/* now check if we have seen it before */
 
-	if (dev->descriptor.iSerialNumber && 
+	if (dev->descriptor.iSerialNumber &&
 	    usb_string(dev, dev->descriptor.iSerialNumber) ) {
 	    make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
-		      usb_string(dev, dev->descriptor.iSerialNumber));
+		usb_string(dev, dev->descriptor.iSerialNumber));
 	} else {
 	    make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
-		      "0");
+		"0");
 	}
 	for (ss = us_list; ss; ss = ss->next) {
 	    if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid))	{
@@ -1172,13 +1197,13 @@
 	break;
     }
 
-    /* 
-     * we are expecting a minimum of 2 endpoints - in and out (bulk)
-     * an optional interrupt is OK (necessary for CBI protocol)
-     * we will ignore any others
+    /*
+     * We are expecting a minimum of 2 endpoints - in and out (bulk).
+     * An optional interrupt is OK (necessary for CBI protocol).
+     * We will ignore any others.
      */
 
-    for (i = 0; i < interface->bNumEndpoints; i++) { 
+    for (i = 0; i < interface->bNumEndpoints; i++) {
 	    if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 			== USB_ENDPOINT_XFER_BULK) {
 		    if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN)
@@ -1276,7 +1301,6 @@
 	memcpy(htmplt, &my_host_template, sizeof(my_host_template));
 	ss->host_number = my_host_number++;
 
-
 	(struct us_data *)htmplt->proc_dir = ss;
 
 	if (dev->descriptor.idVendor == 0x04e6 &&
@@ -1291,12 +1315,19 @@
 			qstat, 2, HZ*5);
 	    US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
 	    init_waitqueue_head(&ss->ip_waitq);
-	    ss->irqpipe = usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int);
+	    ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
 	    result = usb_request_irq(ss->pusb_dev, ss->irqpipe, pop_CBI_irq,
-				0, (void *)ss, &ss->irq_handle);
+				IRQ_PERIOD, (void *)ss, &ss->irq_handle);
 	    if (result)
 	    	return NULL;
+
 	    interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6);
+#ifdef REWRITE_PROJECT
+	    /* FIXME: Don't know if this release_irq() call is at the
+		right place/time. */
+    	    usb_release_irq(ss->pusb_dev, ss->irq_handle, ss->irqpipe);
+	    ss->irq_handle = NULL;
+#endif
 
 	} else if (ss->protocol == US_PR_CBI)
 	    init_waitqueue_head(&ss->ip_waitq);
@@ -1307,7 +1338,7 @@
 	    DECLARE_MUTEX_LOCKED(sem);
 
 	    init_waitqueue_head(&ss->waitq);
-    
+
 	    ss->notify = &sem;
 	    ss->pid = kernel_thread(usbscsi_control_thread, ss,
 		    CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
@@ -1337,6 +1368,7 @@
 	prev->next = ss;
     }
 
+    printk(KERN_WARNING "DANGEROUS: USB SCSI driver data integrity not assured !!!\n");
     printk(KERN_INFO "USB SCSI device found at address %d\n", dev->devnum);
 
     return ss;
diff -u --recursive --new-file v2.3.27/linux/drivers/usb/usb_scsi.h linux/drivers/usb/usb_scsi.h
--- v2.3.27/linux/drivers/usb/usb_scsi.h	Wed Jun 30 11:24:55 1999
+++ linux/drivers/usb/usb_scsi.h	Fri Nov 12 13:22:56 1999
@@ -1,13 +1,13 @@
-/* Driver for USB scsi - include file
- * 
+/* Driver for USB SCSI - include file
+ *
  * (C) Michael Gee (michael@linuxspecific.com) 1999
  *
- * This driver is scitzoid  - it make a USB scanner appear as both a SCSI device
+ * This driver is schizoid  - it makes a USB scanner appear as both a SCSI device
  * and a character device. The latter is only available if the device has an
  * interrupt endpoint, and is used specifically to receive interrupt events.
  *
- * In order to support various 'strange' scanners, this module supports plug in
- * device specific filter modules, which can do their own thing when required.
+ * In order to support various 'strange' scanners, this module supports plug-in
+ * device-specific filter modules, which can do their own thing when required.
  *
  */
 
@@ -58,7 +58,7 @@
     __u32	Signature;		/* contains 'USBC' */
     __u32	Tag;			/* unique per command id */
     __u32	DataTransferLength;	/* size of data */
-    __u8	Flags;	       		/* direction in bit 0 */
+    __u8	Flags;			/* direction in bit 0 */
     __u8	Lun;			/* LUN normally 0 */
     __u8	Length;			/* of of the CDB */
     __u8	CDB[16];		/* max command */
@@ -101,10 +101,10 @@
 	struct usb_scsi_filter * next;	/* usb_scsi driver only */
 	char *name;			/* not really required */
 
-        unsigned int flags;                     			/* Filter flags */
-        void * (* probe) (struct usb_device *, char *, char *, char *);	/* probe device */
-	void (* release)(void *);					/* device gone */
-        int (* command)(void *, Scsi_Cmnd *);  /* all commands */
+	unsigned int flags;		/* Filter flags */
+	void * (* probe) (struct usb_device *, char *, char *, char *);	/* probe device */
+	void (* release)(void *);	/* device gone */
+	int (* command)(void *, Scsi_Cmnd *);  /* all commands */
 };
 
 #define GUID(x) __u32 x[3]
diff -u --recursive --new-file v2.3.27/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.3.27/linux/drivers/video/aty128fb.c	Fri Oct 22 13:21:51 1999
+++ linux/drivers/video/aty128fb.c	Fri Nov 12 04:29:47 1999
@@ -24,7 +24,7 @@
  * example code and hardware. Thanks Nitya.	-atong
  */
 
-
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- v2.3.27/linux/drivers/video/cyber2000fb.c	Mon Nov  1 13:56:27 1999
+++ linux/drivers/video/cyber2000fb.c	Fri Nov 12 04:29:47 1999
@@ -5,6 +5,7 @@
  *
  * Based on cyberfb.c
  */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.27/linux/drivers/video/rivafb.c linux/drivers/video/rivafb.c
--- v2.3.27/linux/drivers/video/rivafb.c	Sun Nov  7 16:37:34 1999
+++ linux/drivers/video/rivafb.c	Fri Nov 12 04:29:47 1999
@@ -20,6 +20,7 @@
 /* version number of this driver */
 #define RIVAFB_VERSION "0.6.5"
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.27/linux/fs/dquot.c linux/fs/dquot.c
--- v2.3.27/linux/fs/dquot.c	Sat Oct  9 11:47:50 1999
+++ linux/fs/dquot.c	Fri Nov 12 04:36:13 1999
@@ -21,6 +21,19 @@
  *		Revised list management to avoid races
  *		-- Bill Hawes, <whawes@star.net>, 9/98
  *
+ *		Fixed races in dquot_transfer(), dqget() and dquot_alloc_...().
+ *		As the consequence the locking was moved from dquot_decr_...(),
+ *		dquot_incr_...() to calling functions.
+ *		invalidate_dquots() now writes modified dquots.
+ *		Serialized quota_off() and quota_on() for mount point.
+ *		Fixed a few bugs in grow_dquots.
+ *		Fixed deadlock in write_dquot() - we no longer account quotas on
+ *		quota files
+ *		remove_dquot_ref() moved to inode.c - it now traverses through inodes
+ *		add_dquot_ref() restarts after blocking
+ *		Added check for bogus uid and fixed check for group in quotactl.
+ *		Jan Kara, <jack@suse.cz>, sponsored by SuSE CR, 10-11/99
+ *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
  */
 
@@ -74,7 +87,7 @@
  */
 
 static struct dquot *inuse_list = NULL;
-LIST_HEAD(free_dquots);
+static LIST_HEAD(free_dquots);
 static struct dquot *dquot_hash[NR_DQHASH];
 static int dquot_updating[NR_DQHASH];
 
@@ -82,6 +95,9 @@
 static DECLARE_WAIT_QUEUE_HEAD(dquot_wait);
 static DECLARE_WAIT_QUEUE_HEAD(update_wait);
 
+static void dqput(struct dquot *);
+static struct dquot *dqduplicate(struct dquot *);
+
 static inline char is_enabled(struct vfsmount *vfsmnt, short type)
 {
 	switch (type) {
@@ -166,7 +182,8 @@
 {
 	/* sanity check */
 	if (list_empty(&dquot->dq_free)) {
-		printk("remove_free_dquot: dquot not on free list??\n");
+		printk("remove_free_dquot: dquot not on the free list??\n");
+		return;		/* J.K. Just don't do anything */
 	}
 	list_del(&dquot->dq_free);
 	INIT_LIST_HEAD(&dquot->dq_free);
@@ -226,16 +243,25 @@
 	wake_up(&dquot->dq_wait);
 }
 
+/*
+ *	We don't have to be afraid of deadlocks as we never have quotas on quota files...
+ */
 static void write_dquot(struct dquot *dquot)
 {
 	short type = dquot->dq_type;
-	struct file *filp = dquot->dq_mnt->mnt_dquot.files[type];
+	struct file *filp;
 	mm_segment_t fs;
 	loff_t offset;
 	ssize_t ret;
+	struct semaphore *sem = &dquot->dq_mnt->mnt_dquot.dqio_sem;
 
 	lock_dquot(dquot);
-	down(&dquot->dq_mnt->mnt_dquot.semaphore);
+	if (!dquot->dq_mnt) {	/* Invalidated quota? */
+		unlock_dquot(dquot);
+		return;
+	}
+	down(sem);
+	filp = dquot->dq_mnt->mnt_dquot.files[type];
 	offset = dqoff(dquot->dq_id);
 	fs = get_fs();
 	set_fs(KERNEL_DS);
@@ -253,40 +279,42 @@
 		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
 			kdevname(dquot->dq_dev));
 
-	up(&dquot->dq_mnt->mnt_dquot.semaphore);
 	set_fs(fs);
-
+	up(sem);
 	unlock_dquot(dquot);
+
 	dqstats.writes++;
 }
 
 static void read_dquot(struct dquot *dquot)
 {
-	short type;
+	short type = dquot->dq_type;
 	struct file *filp;
 	mm_segment_t fs;
 	loff_t offset;
 
-	type = dquot->dq_type;
 	filp = dquot->dq_mnt->mnt_dquot.files[type];
-
 	if (filp == (struct file *)NULL)
 		return;
 
 	lock_dquot(dquot);
-	down(&dquot->dq_mnt->mnt_dquot.semaphore);
+	if (!dquot->dq_mnt)	/* Invalidated quota? */
+		goto out_lock;
+	/* Now we are sure filp is valid - the dquot isn't invalidated */
+	down(&dquot->dq_mnt->mnt_dquot.dqio_sem);
 	offset = dqoff(dquot->dq_id);
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset);
-	up(&dquot->dq_mnt->mnt_dquot.semaphore);
+	up(&dquot->dq_mnt->mnt_dquot.dqio_sem);
 	set_fs(fs);
 
 	if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
 	    dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0)
 		dquot->dq_flags |= DQ_FAKE;
-	unlock_dquot(dquot);
 	dqstats.reads++;
+out_lock:
+	unlock_dquot(dquot);
 }
 
 /*
@@ -306,10 +334,11 @@
 
 void invalidate_dquots(kdev_t dev, short type)
 {
-	struct dquot *dquot, *next = inuse_list;
+	struct dquot *dquot, *next;
 	int need_restart;
 
 restart:
+	next = inuse_list;	/* Here it is better. Otherwise the restart doesn't have any sense ;-) */
 	need_restart = 0;
 	while ((dquot = next) != NULL) {
 		next = dquot->dq_next;
@@ -317,6 +346,8 @@
 			continue;
 		if (dquot->dq_type != type)
 			continue;
+		if (!dquot->dq_mnt)	/* Already invalidated entry? */
+			continue;
 		if (dquot->dq_flags & DQ_LOCKED) {
 			__wait_on_dquot(dquot);
 
@@ -329,6 +360,18 @@
 				continue;
 			if (dquot->dq_type != type)
 				continue;
+			if (!dquot->dq_mnt)
+				continue;
+		}
+		/*
+		 *  Because inodes needn't to be the only holders of dquot
+		 *  the quota needn't to be written to disk. So we write it
+		 *  ourselves before discarding the data just for sure...
+		 */
+		if (dquot->dq_flags & DQ_MOD && dquot->dq_mnt)
+		{
+			write_dquot(dquot);
+			need_restart = 1;	/* We slept on IO */
 		}
 		clear_dquot(dquot);
 	}
@@ -342,10 +385,11 @@
 
 int sync_dquots(kdev_t dev, short type)
 {
-	struct dquot *dquot, *next = inuse_list;
+	struct dquot *dquot, *next, *ddquot;
 	int need_restart;
 
 restart:
+	next = inuse_list;
 	need_restart = 0;
 	while ((dquot = next) != NULL) {
 		next = dquot->dq_next;
@@ -353,12 +397,16 @@
 			continue;
                 if (type != -1 && dquot->dq_type != type)
 			continue;
+		if (!dquot->dq_mnt)	/* Invalidated? */
+			continue;
 		if (!(dquot->dq_flags & (DQ_LOCKED | DQ_MOD)))
 			continue;
 
-		wait_on_dquot(dquot);
-		if (dquot->dq_flags & DQ_MOD)
-			write_dquot(dquot);
+		if ((ddquot = dqduplicate(dquot)) == NODQUOT)
+			continue;
+		if (ddquot->dq_flags & DQ_MOD)
+			write_dquot(ddquot);
+		dqput(ddquot);
 		/* Set the flag for another pass. */
 		need_restart = 1;
 	}
@@ -373,7 +421,8 @@
 	return(0);
 }
 
-void dqput(struct dquot *dquot)
+/* NOTE: If you change this function please check whether dqput_blocks() works right... */
+static void dqput(struct dquot *dquot)
 {
 	if (!dquot)
 		return;
@@ -390,42 +439,45 @@
 	 * checking and doesn't need to be written. It's just an empty
 	 * dquot that is put back on to the freelist.
 	 */
-	if (dquot->dq_mnt != (struct vfsmount *)NULL) {
+	if (dquot->dq_mnt)
 		dqstats.drops++;
 we_slept:
-		wait_on_dquot(dquot);
-		if (dquot->dq_count > 1) {
-			dquot->dq_count--;
-			return;
-		}
-		if (dquot->dq_flags & DQ_MOD) {
-			write_dquot(dquot);
-			goto we_slept;
-		}
+	if (dquot->dq_count > 1) {
+		/* We have more than one user... We can simply decrement use count */
+		dquot->dq_count--;
+		return;
+	}
+	if (dquot->dq_flags & DQ_LOCKED) {
+		printk(KERN_ERR "VFS: Locked quota to be put on the free list.\n");
+		dquot->dq_flags &= ~DQ_LOCKED;
+	}
+	if (dquot->dq_mnt && dquot->dq_flags & DQ_MOD) {
+		write_dquot(dquot);
+		goto we_slept;
 	}
 
 	/* sanity check */
 	if (!list_empty(&dquot->dq_free)) {
-		printk("dqput: dquot already on free list??\n");
-	}
-	if (--dquot->dq_count == 0) {
- 		/* Place at end of LRU free queue */
-		put_dquot_last(dquot);
-		wake_up(&dquot_wait);
+		printk(KERN_ERR "dqput: dquot already on free list??\n");
+		dquot->dq_count--;	/* J.K. Just decrementing use count seems safer... */
+		return;
 	}
-
-	return;
+	dquot->dq_count--;
+	dquot->dq_flags &= ~DQ_MOD;	/* Modified flag has no sense on free list */
+	/* Place at end of LRU free queue */
+	put_dquot_last(dquot);
+	wake_up(&dquot_wait);
 }
 
-static void grow_dquots(void)
+static int grow_dquots(void)
 {
 	struct dquot *dquot;
-	int cnt = 32;
+	int cnt = 0;
 
-	while (cnt > 0) {
+	while (cnt < 32) {
 		dquot = kmem_cache_alloc(dquot_cachep, SLAB_KERNEL);
 		if(!dquot)
-			return;
+			return cnt;
 
 		nr_dquots++;
 		memset((caddr_t)dquot, 0, sizeof(struct dquot));
@@ -433,8 +485,9 @@
 		/* all dquots go on the inuse_list */
 		put_inuse(dquot);
 		put_dquot_head(dquot);
-		cnt--;
+		cnt++;
 	}
+	return cnt;
 }
 
 static struct dquot *find_best_candidate_weighted(void)
@@ -446,6 +499,7 @@
 
 	while ((tmp = tmp->next) != &free_dquots && --limit) {
 		dquot = list_entry(tmp, struct dquot, dq_free);
+		/* This should never happen... */
 		if (dquot->dq_flags & (DQ_LOCKED | DQ_MOD))
 			continue;
 		myscore = dquot->dq_referenced;
@@ -474,27 +528,16 @@
 struct dquot *get_empty_dquot(void)
 {
 	struct dquot *dquot;
-	int count;
+	int shrink = 1;	/* Number of times we should try to shrink dcache and icache */
 
 repeat:
 	dquot = find_best_free();
 	if (!dquot)
 		goto pressure;
 got_it:
-	if (dquot->dq_flags & (DQ_LOCKED | DQ_MOD)) {
-		wait_on_dquot(dquot);
-		if (dquot->dq_flags & DQ_MOD)
-		{
-			if(dquot->dq_mnt != (struct vfsmount *)NULL)
-				write_dquot(dquot);
-		}
-		/*
-		 * The dquot may be back in use now, so we
-		 * must recheck the free list.
-		 */
-		goto repeat;
-	}
-	/* sanity check ... */
+	/* Sanity checks */
+	if (dquot->dq_flags & DQ_LOCKED)
+		printk(KERN_ERR "VFS: Locked dquot on the free list\n");
 	if (dquot->dq_count != 0)
 		printk(KERN_ERR "VFS: free dquot count=%d\n", dquot->dq_count);
 
@@ -505,10 +548,9 @@
 	return dquot;
 
 pressure:
-	if (nr_dquots < max_dquots) {
-		grow_dquots();
-		goto repeat;
-	}
+	if (nr_dquots < max_dquots)
+		if (grow_dquots())
+			goto repeat;
 
 	dquot = find_best_candidate_weighted();
 	if (dquot)
@@ -516,10 +558,11 @@
 	/*
 	 * Try pruning the dcache to free up some dquots ...
 	 */
-	if (count) {
-		printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count);
-		prune_dcache(count);
-		prune_icache(count);
+	if (shrink) {
+		printk(KERN_DEBUG "get_empty_dquot: pruning dcache and icache\n");
+		prune_dcache(128);
+		prune_icache(128);
+		shrink--;
 		goto repeat;
 	}
 
@@ -534,7 +577,7 @@
 	struct dquot *dquot, *empty = NULL;
 	struct vfsmount *vfsmnt;
 
-        if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL || is_enabled(vfsmnt, type) == 0)
+        if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL || !is_enabled(vfsmnt, type))
                 return(NODQUOT);
 
 we_slept:
@@ -567,12 +610,67 @@
 	while (dquot_updating[hashent])
 		sleep_on(&update_wait);
 
+	if (!dquot->dq_mnt) {	/* Has somebody invalidated entry under us? */
+		/*
+		 *  Do it as if the quota was invalidated before we started
+		 */
+		dqput(dquot);
+		return NODQUOT;
+	}
 	dquot->dq_referenced++;
 	dqstats.lookups++;
 
 	return dquot;
 }
 
+static struct dquot *dqduplicate(struct dquot *dquot)
+{
+	if (dquot == NODQUOT || !dquot->dq_mnt)
+		return NODQUOT;
+	dquot->dq_count++;
+	wait_on_dquot(dquot);
+	if (!dquot->dq_mnt) {
+		dquot->dq_count--;
+		return NODQUOT;
+	}
+	dquot->dq_referenced++;
+	dqstats.lookups++;
+	return dquot;
+}
+
+/* Check whether this inode is quota file */
+static inline int is_quotafile(struct inode *inode)
+{
+	int cnt;
+	struct vfsmount *vfsmnt;
+	struct file **files;
+
+	vfsmnt = lookup_vfsmnt(inode->i_dev);
+	if (!vfsmnt)
+		return 0;
+	files = vfsmnt->mnt_dquot.files;
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if (files[cnt] && files[cnt]->f_dentry->d_inode == inode)
+			return 1;
+	return 0;
+}
+
+static int dqinit_needed(struct inode *inode, short type)
+{
+	int cnt;
+
+        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
+                return 0;
+	if (is_quotafile(inode))
+		return 0;
+	if (type != -1)
+		return inode->i_dquot[type] == NODQUOT;
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if (inode->i_dquot[cnt] == NODQUOT)
+			return 1;
+	return 0;
+}
+
 static void add_dquot_ref(kdev_t dev, short type)
 {
 	struct super_block *sb = get_super(dev);
@@ -582,6 +680,7 @@
 	if (!sb || !sb->dq_op)
 		return;	/* nothing to do */
 
+restart:
 	file_list_lock();
 	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
 		struct file *filp = list_entry(p, struct file, f_list);
@@ -590,84 +689,81 @@
 		inode = filp->f_dentry->d_inode;
 		if (!inode)
 			continue;
-		/* N.B. race problem -- filp could become unused */
-		if (filp->f_mode & FMODE_WRITE) {
+		if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
 			file_list_unlock();
 			sb->dq_op->initialize(inode, type);
 			inode->i_flags |= S_QUOTA;
-			file_list_lock();
+			/* As we may have blocked we had better restart... */
+			goto restart;
 		}
 	}
 	file_list_unlock();
 }
 
-static void reset_dquot_ptrs(kdev_t dev, short type)
+/* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */
+static inline int dqput_blocks(struct dquot *dquot)
 {
-	struct super_block *sb = get_super(dev);
-	struct list_head *p;
-	struct inode *inode;
-	struct dquot *dquot;
+	if (dquot->dq_count == 1)
+		return 1;
+	return 0;
+}
+
+/* Remove references to dquots from inode - add dquot to list for freeing if needed */
+int remove_inode_dquot_ref(struct inode *inode, short type, struct list_head *tofree_head)
+{
+	struct dquot *dquot = inode->i_dquot[type];
 	int cnt;
 
-	if (!sb || !sb->dq_op)
-		return;	/* nothing to do */
+	inode->i_dquot[type] = NODQUOT;
+	/* any other quota in use? */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (inode->i_dquot[cnt] != NODQUOT)
+			goto put_it;
+	}
+	inode->i_flags &= ~S_QUOTA;
+put_it:
+	if (dquot != NODQUOT)
+		if (dqput_blocks(dquot)) {
+			if (dquot->dq_count != 1)
+				printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", dquot->dq_count);
+			list_add(&dquot->dq_free, tofree_head);	/* As dquot must have currently users it can't be on the free list... */
+			return 1;
+		}
+		else
+			dqput(dquot);   /* We have guaranteed we won't block */
+	return 0;
+}
 
-restart:
-	/* free any quota for unused dentries */
-	shrink_dcache_sb(sb);
+/* Free list of dquots - called from inode.c */
+void put_dquot_list(struct list_head *tofree_head)
+{
+	struct list_head *act_head = tofree_head;
+	struct dquot *dquot;
 
-	file_list_lock();
-	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
-		struct file *filp = list_entry(p, struct file, f_list);
-		if (!filp->f_dentry)
-			continue;
-		inode = filp->f_dentry->d_inode;
-		if (!inode)
-			continue;
-		/*
-		 * Note: we restart after each blocking operation,
-		 * as the inuse_filps list may have changed.
-		 */
-		if (IS_QUOTAINIT(inode)) {
-			dquot = inode->i_dquot[type];
-			inode->i_dquot[type] = NODQUOT;
-			/* any other quota in use? */
-			for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-				if (inode->i_dquot[cnt] != NODQUOT)
-					goto put_it;
-			}
-			inode->i_flags &= ~S_QUOTA;
-		put_it:
-			if (dquot != NODQUOT) {
-				file_list_unlock();
-				dqput(dquot);
-				/* we may have blocked ... */
-				goto restart;
-			}
-		}
+	/* So now we have dquots on the list... Just free them */
+	while (act_head != tofree_head) {
+		dquot = list_entry(act_head, struct dquot, dq_free);
+		act_head = act_head->next;
+		list_del(&dquot->dq_free);	/* Remove dquot from the list so we won't have problems... */
+		INIT_LIST_HEAD(&dquot->dq_free);
+		dqput(dquot);
 	}
-	file_list_unlock();
 }
 
 static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
 {
-	lock_dquot(dquot);
 	dquot->dq_curinodes += number;
 	dquot->dq_flags |= DQ_MOD;
-	unlock_dquot(dquot);
 }
 
 static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number)
 {
-	lock_dquot(dquot);
 	dquot->dq_curblocks += number;
 	dquot->dq_flags |= DQ_MOD;
-	unlock_dquot(dquot);
 }
 
 static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
 {
-	lock_dquot(dquot);
 	if (dquot->dq_curinodes > number)
 		dquot->dq_curinodes -= number;
 	else
@@ -676,12 +772,10 @@
 		dquot->dq_itime = (time_t) 0;
 	dquot->dq_flags &= ~DQ_INODES;
 	dquot->dq_flags |= DQ_MOD;
-	unlock_dquot(dquot);
 }
 
 static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number)
 {
-	lock_dquot(dquot);
 	if (dquot->dq_curblocks > number)
 		dquot->dq_curblocks -= number;
 	else
@@ -690,7 +784,6 @@
 		dquot->dq_btime = (time_t) 0;
 	dquot->dq_flags &= ~DQ_BLKS;
 	dquot->dq_flags |= DQ_MOD;
-	unlock_dquot(dquot);
 }
 
 static inline char need_print_warning(short type, uid_t initiator, struct dquot *dquot)
@@ -709,7 +802,7 @@
 	return(initiator == 0 && dquot->dq_mnt->mnt_dquot.rsquash[dquot->dq_type] == 0);
 }
 
-static int check_idq(struct dquot *dquot, short type, u_long short inodes, uid_t initiator, 
+static int check_idq(struct dquot *dquot, short type, u_long inodes, uid_t initiator, 
 			struct tty_struct *tty)
 {
 	if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
@@ -874,9 +967,11 @@
 	if (dquot == NODQUOT)
 		goto out;
 
+	lock_dquot(dquot);	/* We must protect against invalidating the quota */
 	error = -EFAULT;
 	if (dqblk && !copy_to_user(dqblk, &dquot->dq_dqb, sizeof(struct dqblk)))
 		error = 0;
+	unlock_dquot(dquot);
 	dqput(dquot);
 out:
 	return error;
@@ -917,14 +1012,14 @@
  * This is a simple algorithm that calculates the size of a file in blocks.
  * This is only used on filesystems that do not have an i_blocks count.
  */
-static u_long isize_to_blocks(size_t isize, size_t blksize)
+static u_long isize_to_blocks(loff_t isize, size_t blksize_bits)
 {
 	u_long blocks;
 	u_long indirect;
 
-	if (!blksize)
-		blksize = BLOCK_SIZE;
-	blocks = (isize / blksize) + ((isize % blksize) ? 1 : 0);
+	if (!blksize_bits)
+		blksize_bits = BLOCK_SIZE_BITS;
+	blocks = (isize >> blksize_bits) + ((isize & ~((1 << blksize_bits)-1)) ? 1 : 0);
 	if (blocks > 10) {
 		indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */
 		if (blocks > (10 + 256)) {
@@ -934,7 +1029,7 @@
 		}
 		blocks += indirect;
 	}
-	return(blocks);
+	return blocks;
 }
 
 /*
@@ -951,6 +1046,9 @@
 	if (S_ISREG(inode->i_mode) ||
             S_ISDIR(inode->i_mode) ||
             S_ISLNK(inode->i_mode)) {
+		/* We don't want to have quotas on quota files - nasty deadlocks possible */
+		if (is_quotafile(inode))
+			return;
 		for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 			if (type != -1 && cnt != type)
 				continue;
@@ -968,6 +1066,8 @@
 						break;
 				}
 				dquot = dqget(inode->i_dev, id, cnt);
+				if (dquot == NODQUOT)
+					continue;
 				if (inode->i_dquot[cnt] != NODQUOT) {
 					dqput(dquot);
 					continue;
@@ -1005,23 +1105,36 @@
 int dquot_alloc_block(const struct inode *inode, unsigned long number, uid_t initiator, 
 			char warn)
 {
-	unsigned short cnt;
+	int cnt;
 	struct tty_struct *tty = current->tty;
+	struct dquot *dquot[MAXQUOTAS];
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (inode->i_dquot[cnt] == NODQUOT)
+		dquot[cnt] = dqduplicate(inode->i_dquot[cnt]);
+		if (dquot[cnt] == NODQUOT)
 			continue;
-		if (check_bdq(inode->i_dquot[cnt], cnt, number, initiator, tty, warn))
-			return(NO_QUOTA);
+		lock_dquot(dquot[cnt]);
+		if (check_bdq(dquot[cnt], cnt, number, initiator, tty, warn))
+			goto put_all;
 	}
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (inode->i_dquot[cnt] == NODQUOT)
+		if (dquot[cnt] == NODQUOT)
 			continue;
-		dquot_incr_blocks(inode->i_dquot[cnt], number);
+		dquot_incr_blocks(dquot[cnt], number);
+		unlock_dquot(dquot[cnt]);
+		dqput(dquot[cnt]);
 	}
 
-	return(QUOTA_OK);
+	return QUOTA_OK;
+put_all:
+	for (; cnt >= 0; cnt--) {
+		if (dquot[cnt] == NODQUOT)
+			continue;
+		unlock_dquot(dquot[cnt]);
+		dqput(dquot[cnt]);
+	}
+	return NO_QUOTA;
 }
 
 /*
@@ -1029,23 +1142,36 @@
  */
 int dquot_alloc_inode(const struct inode *inode, unsigned long number, uid_t initiator)
 {
-	unsigned short cnt;
+	int cnt;
 	struct tty_struct *tty = current->tty;
+	struct dquot *dquot[MAXQUOTAS];
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (inode->i_dquot[cnt] == NODQUOT)
+		dquot[cnt] = dqduplicate(inode -> i_dquot[cnt]);
+		if (dquot[cnt] == NODQUOT)
 			continue;
-		if (check_idq(inode->i_dquot[cnt], cnt, number, initiator, tty))
-			return(NO_QUOTA);
+		lock_dquot(dquot[cnt]);
+		if (check_idq(dquot[cnt], cnt, number, initiator, tty))
+			goto put_all;
 	}
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (inode->i_dquot[cnt] == NODQUOT)
+		if (dquot[cnt] == NODQUOT)
 			continue;
-		dquot_incr_inodes(inode->i_dquot[cnt], number);
+		dquot_incr_inodes(dquot[cnt], number);
+		unlock_dquot(dquot[cnt]);
+		dqput(dquot[cnt]);
 	}
 
-	return(QUOTA_OK);
+	return QUOTA_OK;
+put_all:
+	for (; cnt >= 0; cnt--) {
+		if (dquot[cnt] == NODQUOT)
+			continue;
+		unlock_dquot(dquot[cnt]);
+		dqput(dquot[cnt]);
+	}
+	return NO_QUOTA;
 }
 
 /*
@@ -1054,11 +1180,14 @@
 void dquot_free_block(const struct inode *inode, unsigned long number)
 {
 	unsigned short cnt;
+	struct dquot *dquot;
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (inode->i_dquot[cnt] == NODQUOT)
+		dquot = inode->i_dquot[cnt];
+		if (dquot == NODQUOT)
 			continue;
-		dquot_decr_blocks(inode->i_dquot[cnt], number);
+		wait_on_dquot(dquot);
+		dquot_decr_blocks(dquot, number);
 	}
 }
 
@@ -1068,11 +1197,14 @@
 void dquot_free_inode(const struct inode *inode, unsigned long number)
 {
 	unsigned short cnt;
+	struct dquot *dquot;
 
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-		if (inode->i_dquot[cnt] == NODQUOT)
+		dquot = inode->i_dquot[cnt];
+		if (dquot == NODQUOT)
 			continue;
-		dquot_decr_inodes(inode->i_dquot[cnt], number);
+		wait_on_dquot(dquot);
+		dquot_decr_inodes(dquot, number);
 	}
 }
 
@@ -1081,21 +1213,25 @@
  *
  * Note: this is a blocking operation.
  */
-int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction, uid_t initiator)
+int dquot_transfer(struct dentry *dentry, struct iattr *iattr, uid_t initiator)
 {
+	struct inode *inode = dentry -> d_inode;
 	unsigned long blocks;
 	struct dquot *transfer_from[MAXQUOTAS];
 	struct dquot *transfer_to[MAXQUOTAS];
 	struct tty_struct *tty = current->tty;
 	short cnt, disc;
+	int error = -EDQUOT;
 
+	if (!inode)
+		return -ENOENT;
 	/*
 	 * Find out if this filesystem uses i_blocks.
 	 */
-	if (inode->i_blksize == 0)
-		blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE);
+	if (!inode->i_sb || !inode->i_sb->s_blocksize)
+		blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS);
 	else
-		blocks = (inode->i_blocks / 2);
+		blocks = (inode->i_blocks >> 1);
 
 	/*
 	 * Build the transfer_from and transfer_to lists and check quotas to see
@@ -1112,27 +1248,60 @@
 			case USRQUOTA:
 				if (inode->i_uid == iattr->ia_uid)
 					continue;
-				transfer_from[cnt] = dqget(inode->i_dev, (direction) ? iattr->ia_uid : inode->i_uid, cnt);
-				transfer_to[cnt] = dqget(inode->i_dev, (direction) ? inode->i_uid : iattr->ia_uid, cnt);
+				/* We can get transfer_from from inode, can't we? */
+				transfer_from[cnt] = dqget(inode->i_dev, inode->i_uid, cnt);
+				transfer_to[cnt] = dqget(inode->i_dev, iattr->ia_uid, cnt);
 				break;
 			case GRPQUOTA:
 				if (inode->i_gid == iattr->ia_gid)
 					continue;
-				transfer_from[cnt] = dqget(inode->i_dev, (direction) ? iattr->ia_gid : inode->i_gid, cnt);
-				transfer_to[cnt] = dqget(inode->i_dev, (direction) ? inode->i_gid : iattr->ia_gid, cnt);
+				transfer_from[cnt] = dqget(inode->i_dev, inode->i_gid, cnt);
+				transfer_to[cnt] = dqget(inode->i_dev, iattr->ia_gid, cnt);
 				break;
 		}
 
-		if (check_idq(transfer_to[cnt], cnt, 1, initiator, tty) == NO_QUOTA ||
-		    check_bdq(transfer_to[cnt], cnt, blocks, initiator, tty, 0) == NO_QUOTA) {
-			for (disc = 0; disc <= cnt; disc++) {
-				dqput(transfer_from[disc]);
-				dqput(transfer_to[disc]);
+		/* Something bad (eg. quotaoff) happened while we were sleeping? */
+		if (transfer_from[cnt] == NODQUOT || transfer_to[cnt] == NODQUOT)
+		{
+			if (transfer_from[cnt] != NODQUOT) {
+				dqput(transfer_from[cnt]);
+				transfer_from[cnt] = NODQUOT;
 			}
-			return(NO_QUOTA);
+			if (transfer_to[cnt] != NODQUOT) {
+				dqput(transfer_to[cnt]);
+				transfer_to[cnt] = NODQUOT;
+			}
+			continue;
+		}
+		/*
+		 *  We have to lock the quotas to prevent races...
+		 */
+		if (transfer_from[cnt] < transfer_to[cnt])
+		{
+                	lock_dquot(transfer_from[cnt]);
+			lock_dquot(transfer_to[cnt]);
+		}
+		else
+		{
+			lock_dquot(transfer_to[cnt]);
+			lock_dquot(transfer_from[cnt]);
+		}
+
+		/*
+		 * The entries might got invalidated while locking. The second
+		 * dqget() could block and so the first structure might got
+		 * invalidated or locked...
+		 */
+		if (!transfer_to[cnt]->dq_mnt || !transfer_from[cnt]->dq_mnt ||
+		    check_idq(transfer_to[cnt], cnt, 1, initiator, tty) == NO_QUOTA ||
+		    check_bdq(transfer_to[cnt], cnt, blocks, initiator, tty, 0) == NO_QUOTA) {
+			cnt++;
+			goto put_all;
 		}
 	}
 
+	if ((error = notify_change(dentry, iattr)))
+		goto put_all; 
 	/*
 	 * Finally perform the needed transfer from transfer_from to transfer_to,
 	 * and release any pointers to dquots not needed anymore.
@@ -1144,28 +1313,39 @@
 		if (transfer_from[cnt] == NODQUOT && transfer_to[cnt] == NODQUOT)
 			continue;
 
-		if (transfer_from[cnt] != NODQUOT) {
-			dquot_decr_inodes(transfer_from[cnt], 1);
-			dquot_decr_blocks(transfer_from[cnt], blocks);
-		}
+		dquot_decr_inodes(transfer_from[cnt], 1);
+		dquot_decr_blocks(transfer_from[cnt], blocks);
 
-		if (transfer_to[cnt] != NODQUOT) {
-			dquot_incr_inodes(transfer_to[cnt], 1);
-			dquot_incr_blocks(transfer_to[cnt], blocks);
-		}
+		dquot_incr_inodes(transfer_to[cnt], 1);
+		dquot_incr_blocks(transfer_to[cnt], blocks);
 
+		unlock_dquot(transfer_from[cnt]);
+		dqput(transfer_from[cnt]);
 		if (inode->i_dquot[cnt] != NODQUOT) {
 			struct dquot *temp = inode->i_dquot[cnt];
 			inode->i_dquot[cnt] = transfer_to[cnt];
+			unlock_dquot(transfer_to[cnt]);
 			dqput(temp);
-			dqput(transfer_from[cnt]);
 		} else {
-			dqput(transfer_from[cnt]);
+			unlock_dquot(transfer_to[cnt]);
 			dqput(transfer_to[cnt]);
 		}
 	}
 
-	return(QUOTA_OK);
+	return 0;
+put_all:
+	for (disc = 0; disc < cnt; disc++) {
+		/* There should be none or both pointers set but... */
+		if (transfer_to[disc] != NODQUOT) {
+			unlock_dquot(transfer_to[disc]);
+			dqput(transfer_to[disc]);
+		}
+		if (transfer_from[disc] != NODQUOT) {
+			unlock_dquot(transfer_from[disc]);
+			dqput(transfer_from[disc]);
+		}
+	}
+	return error;
 }
 
 
@@ -1221,6 +1401,9 @@
 	}
 }
 
+/* Function in inode.c - remove pointers to dquots in icache */
+extern void remove_dquot_ref(kdev_t, short);
+
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
@@ -1229,48 +1412,57 @@
 	struct vfsmount *vfsmnt;
 	struct file *filp;
 	short cnt;
+	int enabled = 0;
+
+	/* We don't need to search for vfsmnt each time - umount has to wait for us */
+	vfsmnt = lookup_vfsmnt(dev);
+	if (!vfsmnt || !vfsmnt->mnt_sb)
+		goto out;
 
+	/* We need to serialize quota_off() for device */
+	down(&vfsmnt->mnt_dquot.dqoff_sem);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (type != -1 && cnt != type)
 			continue;
-
-		vfsmnt = lookup_vfsmnt(dev);
-		if (!vfsmnt)
-			goto out;
-                if (!vfsmnt->mnt_sb)
-			goto out;
 		if (!is_enabled(vfsmnt, cnt))
 			continue;
 		reset_enable_flags(vfsmnt, cnt);
 
 		/* Note: these are blocking operations */
-		reset_dquot_ptrs(dev, cnt);
+		remove_dquot_ref(dev, cnt);
 		invalidate_dquots(dev, cnt);
 
+		/* Wait for any pending IO - remove me as soon as invalidate is more polite */
+		down(&vfsmnt->mnt_dquot.dqio_sem);
 		filp = vfsmnt->mnt_dquot.files[cnt];
 		vfsmnt->mnt_dquot.files[cnt] = (struct file *)NULL;
 		vfsmnt->mnt_dquot.inode_expire[cnt] = 0;
 		vfsmnt->mnt_dquot.block_expire[cnt] = 0;
+		up(&vfsmnt->mnt_dquot.dqio_sem);
 		fput(filp);
-	}
+	}	
 
 	/*
 	 * Check whether any quota is still enabled,
 	 * and if not clear the dq_op pointer.
 	 */
-	vfsmnt = lookup_vfsmnt(dev);
-	if (vfsmnt && vfsmnt->mnt_sb) {
-		int enabled = 0;
-		for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-			enabled |= is_enabled(vfsmnt, cnt);
-		if (!enabled)
-			vfsmnt->mnt_sb->dq_op = NULL;
-	}
-
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		enabled |= is_enabled(vfsmnt, cnt);
+	if (!enabled)
+		vfsmnt->mnt_sb->dq_op = NULL;
+	up(&vfsmnt->mnt_dquot.dqoff_sem);
 out:
 	return(0);
 }
 
+static inline int check_quotafile_size(loff_t size)
+{
+	ulong blocks = size >> BLOCK_SIZE_BITS;
+	size_t off = size & ~(BLOCK_SIZE - 1);
+
+	return !((blocks % sizeof(struct dqblk) + off % sizeof(struct dqblk)) % sizeof(struct dqblk));
+}
+
 int quota_on(kdev_t dev, short type, char *path)
 {
 	struct file *f;
@@ -1287,47 +1479,52 @@
 
 	if (is_enabled(vfsmnt, type))
 		return -EBUSY;
-	mnt_dquot = &vfsmnt->mnt_dquot;
 
+	mnt_dquot = &vfsmnt->mnt_dquot;
+	down(&mnt_dquot->dqoff_sem);
 	tmp = getname(path);
 	error = PTR_ERR(tmp);
 	if (IS_ERR(tmp))
-		return error;
+		goto out_lock;
 
 	f = filp_open(tmp, O_RDWR, 0600);
 	putname(tmp);
-	if (IS_ERR(f))
-		return PTR_ERR(f);
 
-	/* sanity checks */
+	error = PTR_ERR(f);
+	if (IS_ERR(f))
+		goto out_lock;
 	error = -EIO;
 	if (!f->f_op->read && !f->f_op->write)
-		goto cleanup;
+		goto out_f;
 	inode = f->f_dentry->d_inode;
 	error = -EACCES;
 	if (!S_ISREG(inode->i_mode))
-		goto cleanup;
+		goto out_f;
 	error = -EINVAL;
-	if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0)
-		goto cleanup;
+	if (inode->i_size == 0 || !check_quotafile_size(inode->i_size))
+		goto out_f;
+	dquot_drop(inode);	/* We don't want quota on quota files */
 
-	/* OK, there we go */
 	set_enable_flags(vfsmnt, type);
 	mnt_dquot->files[type] = f;
 
 	dquot = dqget(dev, 0, type);
-	mnt_dquot->inode_expire[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
-	mnt_dquot->block_expire[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME;
+	mnt_dquot->inode_expire[type] = (dquot != NODQUOT) ? dquot->dq_itime : MAX_IQ_TIME;
+	mnt_dquot->block_expire[type] = (dquot != NODQUOT) ? dquot->dq_btime : MAX_DQ_TIME;
 	dqput(dquot);
 
 	vfsmnt->mnt_sb->dq_op = &dquot_operations;
 	add_dquot_ref(dev, type);
 
-	return(0);
+	up(&mnt_dquot->dqoff_sem);
+	return 0;
 
-cleanup:
-	fput(f);
-	return error;
+out_f:
+	filp_close(f, NULL);
+out_lock:
+	up(&mnt_dquot->dqoff_sem);
+
+	return error; 
 }
 
 /*
@@ -1348,6 +1545,9 @@
 
 	if ((u_int) type >= MAXQUOTAS)
 		goto out;
+	if (id & ~0xFFFF)
+		goto out;
+
 	ret = -EPERM;
 	switch (cmds) {
 		case Q_SYNC:
@@ -1355,7 +1555,7 @@
 			break;
 		case Q_GETQUOTA:
 			if (((type == USRQUOTA && current->euid != id) ||
-			     (type == GRPQUOTA && current->egid != id)) &&
+			     (type == GRPQUOTA && in_group_p(id))) &&
 			    !capable(CAP_SYS_RESOURCE))
 				goto out;
 			break;
@@ -1365,7 +1565,7 @@
 	}
 
 	ret = -EINVAL;
-	dev = 0;
+	dev = NODEV;
 	if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) {
 		mode_t mode;
 		struct dentry * dentry;
diff -u --recursive --new-file v2.3.27/linux/fs/inode.c linux/fs/inode.c
--- v2.3.27/linux/fs/inode.c	Mon Nov  1 13:56:27 1999
+++ linux/fs/inode.c	Fri Nov 12 11:06:18 1999
@@ -756,3 +756,51 @@
     inode->i_atime = CURRENT_TIME;
     mark_inode_dirty (inode);
 }   /*  End Function update_atime  */
+
+
+/*
+ *	Quota functions that want to walk the inode lists..
+ */
+#ifdef CONFIG_QUOTA
+
+/* Functions back in dquot.c */
+void put_dquot_list(struct list_head *);
+int remove_inode_dquot_ref(struct inode *, short, struct list_head *);
+
+void remove_dquot_ref(kdev_t dev, short type)
+{
+	struct super_block *sb = get_super(dev);
+	struct inode *inode;
+	struct list_head *act_head;
+	LIST_HEAD(tofree_head);
+
+	if (!sb || !sb->dq_op)
+		return;	/* nothing to do */
+
+	/* We have to be protected against other CPUs */
+	spin_lock(&inode_lock);
+ 
+	for (act_head = inode_in_use.next; act_head != &inode_in_use; act_head = act_head->next) {
+		inode = list_entry(act_head, struct inode, i_list);
+		if (inode->i_sb != sb || !IS_QUOTAINIT(inode))
+			continue;
+		remove_inode_dquot_ref(inode, type, &tofree_head);
+	}
+	for (act_head = inode_unused.next; act_head != &inode_unused; act_head = act_head->next) {
+		inode = list_entry(act_head, struct inode, i_list);
+		if (inode->i_sb != sb || !IS_QUOTAINIT(inode))
+			continue;
+		remove_inode_dquot_ref(inode, type, &tofree_head);
+	}
+	for (act_head = sb->s_dirty.next; act_head != &sb->s_dirty; act_head = act_head->next) {
+		inode = list_entry(act_head, struct inode, i_list);
+		if (!IS_QUOTAINIT(inode))
+			continue;
+  		remove_inode_dquot_ref(inode, type, &tofree_head);
+	}
+	spin_unlock(&inode_lock);
+
+	put_dquot_list(&tofree_head);
+}
+
+#endif
diff -u --recursive --new-file v2.3.27/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.3.27/linux/fs/isofs/inode.c	Sun Nov  7 16:37:34 1999
+++ linux/fs/isofs/inode.c	Fri Nov 12 13:21:09 1999
@@ -990,8 +990,8 @@
 	}
 
 	bh_result->b_dev = inode->i_dev;
-	bh_result->b_blocknr =
-		(b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
+	bh_result->b_blocknr = firstext +
+		((b_off - offset) >> ISOFS_BUFFER_BITS(inode));
 	bh_result->b_state |= (1UL << BH_Mapped);
 	err = 0;
 
@@ -1236,8 +1236,7 @@
 	  iso_date(raw_inode->date, high_sierra);
 
 	inode->u.isofs_i.i_first_extent = (isonum_733 (raw_inode->extent) +
-					   isonum_711 (raw_inode->ext_attr_length))
-	  << inode -> i_sb -> u.isofs_sb.s_log_zone_size;
+					   isonum_711 (raw_inode->ext_attr_length));
 
 /* Now test for possible Rock Ridge extensions which will override some of
    these numbers in the inode structure. */
diff -u --recursive --new-file v2.3.27/linux/fs/isofs/rock.c linux/fs/isofs/rock.c
--- v2.3.27/linux/fs/isofs/rock.c	Fri Sep 25 16:27:13 1998
+++ linux/fs/isofs/rock.c	Fri Nov 12 13:21:09 1999
@@ -358,9 +358,10 @@
 #ifdef DEBUG
 	printk("RR CL (%x)\n",inode->i_ino);
 #endif
-	inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) <<
-		inode -> i_sb -> u.isofs_sb.s_log_zone_size;
-	reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent);
+	inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location);
+	reloc = iget(inode->i_sb,
+		     (inode->u.isofs_i.i_first_extent <<
+		      inode -> i_sb -> u.isofs_sb.s_log_zone_size));
 	if (!reloc)
 		goto out;
 	inode->i_mode = reloc->i_mode;
diff -u --recursive --new-file v2.3.27/linux/fs/nfsd/stats.c linux/fs/nfsd/stats.c
--- v2.3.27/linux/fs/nfsd/stats.c	Thu Nov 11 20:11:50 1999
+++ linux/fs/nfsd/stats.c	Fri Nov 12 04:40:46 1999
@@ -17,6 +17,7 @@
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/sunrpc/svc.h>
diff -u --recursive --new-file v2.3.27/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.3.27/linux/fs/proc/array.c	Thu Nov 11 20:11:50 1999
+++ linux/fs/proc/array.c	Fri Nov 12 04:29:47 1999
@@ -62,7 +62,6 @@
 #include <linux/mman.h>
 #include <linux/proc_fs.h>
 #include <linux/ioport.h>
-#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
diff -u --recursive --new-file v2.3.27/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.3.27/linux/fs/proc/base.c	Thu Nov 11 20:11:50 1999
+++ linux/fs/proc/base.c	Fri Nov 12 11:02:34 1999
@@ -104,9 +104,12 @@
 {
 	struct mm_struct *mm = task->mm;
 	int res = 0;
-	if (mm)
-		res = access_process_vm(task, mm->env_start, buffer,
-					mm->env_end - mm->env_start, 0);
+	if (mm) {
+		int len = mm->env_end - mm->env_start;
+		if (len > PAGE_SIZE)
+			len = PAGE_SIZE;
+		res = access_process_vm(task, mm->env_start, buffer, len, 0);
+	}
 	return res;
 }
 
@@ -116,9 +119,12 @@
 {
 	struct mm_struct *mm = task->mm;
 	int res = 0;
-	if (mm)
-		res = access_process_vm(task, mm->arg_start, buffer,
-					mm->arg_end - mm->arg_start, 0);
+	if (mm) {
+		int len = mm->arg_end - mm->arg_start;
+		if (len > PAGE_SIZE)
+			len = PAGE_SIZE;
+		res = access_process_vm(task, mm->arg_start, buffer, len, 0);
+	}
 	return res;
 }
 
diff -u --recursive --new-file v2.3.27/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v2.3.27/linux/fs/proc/inode.c	Thu Nov 11 20:11:50 1999
+++ linux/fs/proc/inode.c	Fri Nov 12 04:40:46 1999
@@ -14,6 +14,7 @@
 #include <linux/locks.h>
 #include <linux/limits.h>
 #include <linux/config.h>
+#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <asm/system.h>
diff -u --recursive --new-file v2.3.27/linux/fs/proc/kcore.c linux/fs/proc/kcore.c
--- v2.3.27/linux/fs/proc/kcore.c	Thu Nov 11 20:11:50 1999
+++ linux/fs/proc/kcore.c	Fri Nov 12 10:37:24 1999
@@ -16,7 +16,6 @@
 #include <linux/elf.h>
 #include <linux/elfcore.h>
 #include <linux/vmalloc.h>
-#include <linux/proc_fs.h>
 #include <asm/uaccess.h>
 
 
@@ -189,7 +188,7 @@
  * store an ELF coredump header in the supplied buffer
  * num_vma is the number of elements in vmlist
  */
-static void elf_kcore_store_hdr(char *bufp, int num_vma, int elf_buflen)
+static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff)
 {
 	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
 	struct elf_prpsinfo prpsinfo;	/* NT_PRPSINFO */
@@ -235,18 +234,20 @@
 	nhdr->p_flags	= 0;
 	nhdr->p_align	= 0;
 
-	/* setup ELF PT_LOAD program header */
+	/* setup ELF PT_LOAD program header for the 
+	 * virtual range 0xc0000000 -> high_memory */
 	phdr = (struct elf_phdr *) bufp;
 	bufp += sizeof(struct elf_phdr);
 	offset += sizeof(struct elf_phdr);
 	phdr->p_type	= PT_LOAD;
 	phdr->p_flags	= PF_R|PF_W|PF_X;
-	phdr->p_offset	= elf_buflen;
+	phdr->p_offset	= dataoff;
 	phdr->p_vaddr	= PAGE_OFFSET;
 	phdr->p_paddr	= __pa(PAGE_OFFSET);
 	phdr->p_filesz	= phdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET);
 	phdr->p_align	= PAGE_SIZE;
 
+	/* setup ELF PT_LOAD program headers, one for every kvma range */
 	for (m=vmlist; m; m=m->next) {
 		phdr = (struct elf_phdr *) bufp;
 		bufp += sizeof(struct elf_phdr);
@@ -254,9 +255,9 @@
 
 		phdr->p_type	= PT_LOAD;
 		phdr->p_flags	= PF_R|PF_W|PF_X;
-		phdr->p_offset	= (size_t)m->addr - PAGE_OFFSET + elf_buflen;
+		phdr->p_offset	= (size_t)m->addr - PAGE_OFFSET + dataoff;
 		phdr->p_vaddr	= (size_t)m->addr;
-		phdr->p_paddr	= __pa(m);
+		phdr->p_paddr	= __pa(m->addr);
 		phdr->p_filesz	= phdr->p_memsz	= m->size;
 		phdr->p_align	= PAGE_SIZE;
 	}
@@ -310,13 +311,16 @@
 /*
  * read from the ELF header and then kernel memory
  */
-static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen,
-			      loff_t *fpos)
+static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t *fpos)
 {
 	ssize_t acc = 0;
 	size_t size, tsz;
 	char * elf_buffer;
-	int elf_buflen = 0, num_vma = 0;
+	size_t elf_buflen = 0;
+	int num_vma = 0;
+
+	if (verify_area(VERIFY_WRITE, buffer, buflen))
+		return -EFAULT;
 
 	/* XXX we need to somehow lock vmlist between here
 	 * and after elf_kcore_store_hdr() returns.
@@ -340,7 +344,7 @@
 			return -ENOMEM;
 		memset(elf_buffer, 0, elf_buflen);
 		elf_kcore_store_hdr(elf_buffer, num_vma, elf_buflen);
-		copy_to_user(buffer, elf_buffer, tsz);
+		copy_to_user(buffer, elf_buffer + *fpos, tsz);
 		kfree(elf_buffer);
 		buflen -= tsz;
 		*fpos += tsz;
@@ -349,7 +353,7 @@
 
 		/* leave now if filled buffer already */
 		if (buflen == 0)
-			return tsz;
+			return acc;
 	}
 
 	/* where page 0 not mapped, write zeros into buffer */
@@ -374,14 +378,10 @@
 #endif
 
 	/* fill the remainder of the buffer from kernel VM space */
-#if defined (__i386__) || defined (__mc68000__)
-	copy_to_user(buffer, __va(*fpos - PAGE_SIZE), buflen);
-#else
-	copy_to_user(buffer, __va(*fpos), buflen);
-#endif
+	copy_to_user(buffer, __va(*fpos - elf_buflen), buflen);
+
 	acc += buflen;
 	*fpos += buflen;
-
 	return acc;
 
 }
diff -u --recursive --new-file v2.3.27/linux/fs/super.c linux/fs/super.c
--- v2.3.27/linux/fs/super.c	Mon Nov  1 13:56:27 1999
+++ linux/fs/super.c	Fri Nov 12 04:36:13 1999
@@ -104,7 +104,8 @@
 	lptr->mnt_dev = sb->s_dev;
 	lptr->mnt_flags = sb->s_flags;
 
-	sema_init(&lptr->mnt_dquot.semaphore, 1);
+	sema_init(&lptr->mnt_dquot.dqio_sem, 1);
+	sema_init(&lptr->mnt_dquot.dqoff_sem, 1);
 	lptr->mnt_dquot.flags = 0;
 
 	/* N.B. Is it really OK to have a vfsmount without names? */
diff -u --recursive --new-file v2.3.27/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.3.27/linux/fs/sysv/inode.c	Sat Oct  9 11:47:50 1999
+++ linux/fs/sysv/inode.c	Fri Nov 12 04:29:47 1999
@@ -21,6 +21,7 @@
  *  the superblock.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/fs/udf/dir.c linux/fs/udf/dir.c
--- v2.3.27/linux/fs/udf/dir.c	Mon Nov  1 13:56:27 1999
+++ linux/fs/udf/dir.c	Fri Nov 12 04:29:47 1999
@@ -32,6 +32,7 @@
 #include "udfdecl.h"
 
 #if defined(__linux__) && defined(__KERNEL__)
+#include <linux/config.h>
 #include <linux/version.h>
 #include "udf_i.h"
 #include "udf_sb.h"
diff -u --recursive --new-file v2.3.27/linux/fs/udf/file.c linux/fs/udf/file.c
--- v2.3.27/linux/fs/udf/file.c	Mon Nov  1 13:56:27 1999
+++ linux/fs/udf/file.c	Fri Nov 12 04:29:47 1999
@@ -31,6 +31,7 @@
  */
 
 #include "udfdecl.h"
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/udf_fs.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.27/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.3.27/linux/fs/udf/super.c	Sun Nov  7 16:37:34 1999
+++ linux/fs/udf/super.c	Fri Nov 12 04:29:47 1999
@@ -48,6 +48,7 @@
 
 #include "udfdecl.h"    
 
+#include <linux/config.h>
 #include <linux/blkdev.h>
 #include <linux/malloc.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.27/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.3.27/linux/include/asm-arm/arch-ebsa285/irq.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Fri Nov 12 04:29:47 1999
@@ -11,6 +11,7 @@
  *  16-Mar-1999	RMK	Added autodetect of ISA PICs
  */
 /* no need for config.h - arch/arm/kernel/irq.c does this for us */
+#include <linux/config.h>
 #include <asm/hardware.h>
 #include <asm/dec21285.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.3.27/linux/include/asm-arm/arch-sa1100/irq.h linux/include/asm-arm/arch-sa1100/irq.h
--- v2.3.27/linux/include/asm-arm/arch-sa1100/irq.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/arch-sa1100/irq.h	Fri Nov 12 04:29:47 1999
@@ -12,6 +12,8 @@
  *   11-08-1999	PD	SA1101 support added
  *   25-09-1999	RMK	Merged into main ARM tree, cleaned up
  */
+#include <linux/config.h>
+
 static inline unsigned int fixup_irq(unsigned int irq)
 {
 #ifdef CONFIG_SA1101
diff -u --recursive --new-file v2.3.27/linux/include/asm-arm/arch-sa1100/irqs.h linux/include/asm-arm/arch-sa1100/irqs.h
--- v2.3.27/linux/include/asm-arm/arch-sa1100/irqs.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/arch-sa1100/irqs.h	Fri Nov 12 04:29:47 1999
@@ -4,6 +4,7 @@
  * Copyright (C) 1996 Russell King
  * Copyright (C) 1998 Deborah Wallach (updates for SA1100/Brutus).
  */
+#include <linux/config.h>
 
 #ifdef CONFIG_SA1101
 #define NR_IRQS                 95
diff -u --recursive --new-file v2.3.27/linux/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h
--- v2.3.27/linux/include/asm-arm/arch-sa1100/system.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/arch-sa1100/system.h	Fri Nov 12 04:29:47 1999
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 1999 Nicolas Pitre <nico@visuaide.com>
  */
+#include <linux/config.h>
+
 #ifdef CONFIG_SA1100_VICTOR
 
 #define arch_reset( x ) {					\
diff -u --recursive --new-file v2.3.27/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h
--- v2.3.27/linux/include/asm-arm/processor.h	Thu Nov 11 20:11:51 1999
+++ linux/include/asm-arm/processor.h	Fri Nov 12 04:29:47 1999
@@ -7,6 +7,7 @@
 #ifndef __ASM_ARM_PROCESSOR_H
 #define __ASM_ARM_PROCESSOR_H
 
+#include <linux/config.h>
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
diff -u --recursive --new-file v2.3.27/linux/include/asm-i386/setup.h linux/include/asm-i386/setup.h
--- v2.3.27/linux/include/asm-i386/setup.h	Mon Jul  5 19:59:55 1999
+++ linux/include/asm-i386/setup.h	Fri Nov 12 10:12:11 1999
@@ -2,3 +2,9 @@
  *	Just a place holder. We don't want to have to test x86 before
  *	we include stuff
  */
+
+#ifndef _i386_SETUP_H
+#define _i386_SETUP_H
+
+
+#endif /* _i386_SETUP_H */
diff -u --recursive --new-file v2.3.27/linux/include/asm-m68k/dvma.h linux/include/asm-m68k/dvma.h
--- v2.3.27/linux/include/asm-m68k/dvma.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/dvma.h	Fri Nov 12 04:29:47 1999
@@ -9,6 +9,8 @@
 #ifndef __M68K_DVMA_H
 #define __M68K_DVMA_H
 
+#include <linux/config.h>
+
 #ifdef CONFIG_SUN3
 /* sun3 dvma page support */
 
diff -u --recursive --new-file v2.3.27/linux/include/asm-m68k/elf.h linux/include/asm-m68k/elf.h
--- v2.3.27/linux/include/asm-m68k/elf.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/elf.h	Fri Nov 12 04:29:47 1999
@@ -5,6 +5,7 @@
  * ELF register definitions..
  */
 
+#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/user.h>
 
diff -u --recursive --new-file v2.3.27/linux/include/asm-m68k/mmu_context.h linux/include/asm-m68k/mmu_context.h
--- v2.3.27/linux/include/asm-m68k/mmu_context.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/mmu_context.h	Fri Nov 12 04:29:47 1999
@@ -1,6 +1,8 @@
 #ifndef __M68K_MMU_CONTEXT_H
 #define __M68K_MMU_CONTEXT_H
 
+#include <linux/config.h>
+
 #ifndef CONFIG_SUN3
 
 #include <asm/setup.h>
diff -u --recursive --new-file v2.3.27/linux/include/asm-m68k/openprom.h linux/include/asm-m68k/openprom.h
--- v2.3.27/linux/include/asm-m68k/openprom.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/openprom.h	Fri Nov 12 04:29:47 1999
@@ -8,6 +8,8 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
+
 /* Empirical constants... */
 #ifdef CONFIG_SUN3
 #define KADB_DEBUGGER_BEGVM     0x0fee0000    /* There is no kadb yet but...*/
diff -u --recursive --new-file v2.3.27/linux/include/asm-m68k/param.h linux/include/asm-m68k/param.h
--- v2.3.27/linux/include/asm-m68k/param.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/param.h	Fri Nov 12 04:29:47 1999
@@ -1,6 +1,8 @@
 #ifndef _M68K_PARAM_H
 #define _M68K_PARAM_H
 
+#include <linux/config.h>
+
 #ifndef HZ
 #define HZ 100
 #endif
diff -u --recursive --new-file v2.3.27/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v2.3.27/linux/include/asm-m68k/processor.h	Thu Nov 11 20:11:52 1999
+++ linux/include/asm-m68k/processor.h	Fri Nov 12 04:29:47 1999
@@ -13,6 +13,7 @@
  */
 #define current_text_addr() ({ __label__ _l; _l: &&_l;})
 
+#include <linux/config.h>
 #include <asm/segment.h>
 #include <asm/fpu.h>
 #include <asm/ptrace.h>
diff -u --recursive --new-file v2.3.27/linux/include/asm-m68k/shm.h linux/include/asm-m68k/shm.h
--- v2.3.27/linux/include/asm-m68k/shm.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/shm.h	Fri Nov 12 04:29:47 1999
@@ -1,6 +1,8 @@
 #ifndef _M68K_SHM_H
 #define _M68K_SHM_H
 
+#include <linux/config.h>
+
 /* format of page table entries that correspond to shared memory pages
    currently out in swap space (see also mm/swap.c):
    bits 0-1 (PAGE_PRESENT) is  = 0
diff -u --recursive --new-file v2.3.27/linux/include/asm-m68k/sun3ints.h linux/include/asm-m68k/sun3ints.h
--- v2.3.27/linux/include/asm-m68k/sun3ints.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/sun3ints.h	Fri Nov 12 04:29:47 1999
@@ -11,7 +11,6 @@
 #ifndef SUN3INTS_H
 #define SUN3INTS_H
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.27/linux/include/asm-ppc/irq_control.h linux/include/asm-ppc/irq_control.h
--- v2.3.27/linux/include/asm-ppc/irq_control.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-ppc/irq_control.h	Fri Nov 12 04:29:47 1999
@@ -6,8 +6,6 @@
 #ifndef _PPC_IRQ_CONTROL_H
 #define _PPC_IRQ_CONTROL_H
 
-#include <linux/config.h>
-
 #include <asm/irq.h>
 #include <asm/atomic.h>
 
diff -u --recursive --new-file v2.3.27/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.3.27/linux/include/asm-ppc/keyboard.h	Fri Oct 15 15:25:14 1999
+++ linux/include/asm-ppc/keyboard.h	Fri Nov 12 04:29:47 1999
@@ -15,7 +15,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
 #include <linux/adb.h>
 #include <asm/machdep.h>
 
diff -u --recursive --new-file v2.3.27/linux/include/asm-ppc/linux_logo.h linux/include/asm-ppc/linux_logo.h
--- v2.3.27/linux/include/asm-ppc/linux_logo.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-ppc/linux_logo.h	Fri Nov 12 04:29:47 1999
@@ -11,7 +11,6 @@
  * (i.e. linux_logo_{red,green,blue}[0] is color 0x20)
  */
  
-#include <linux/config.h>
 #include <linux/init.h>
 
 #define linux_logo_banner "Linux/PPC version " UTS_RELEASE
diff -u --recursive --new-file v2.3.27/linux/include/asm-ppc/mpc8xx.h linux/include/asm-ppc/mpc8xx.h
--- v2.3.27/linux/include/asm-ppc/mpc8xx.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-ppc/mpc8xx.h	Fri Nov 12 04:29:47 1999
@@ -8,6 +8,8 @@
 #ifndef __CONFIG_8xx_DEFS
 #define __CONFIG_8xx_DEFS
 
+#include <linux/config.h>
+
 #ifdef CONFIG_8xx
 
 #ifdef CONFIG_MBX
diff -u --recursive --new-file v2.3.27/linux/include/linux/acpi.h linux/include/linux/acpi.h
--- v2.3.27/linux/include/linux/acpi.h	Thu Nov 11 20:11:52 1999
+++ linux/include/linux/acpi.h	Fri Nov 12 11:29:52 1999
@@ -26,6 +26,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
 
diff -u --recursive --new-file v2.3.27/linux/include/linux/cycx_drv.h linux/include/linux/cycx_drv.h
--- v2.3.27/linux/include/linux/cycx_drv.h	Mon Nov  1 13:56:27 1999
+++ linux/include/linux/cycx_drv.h	Thu Nov 11 20:10:36 1999
@@ -53,6 +53,7 @@
 
 /* Function Prototypes */
 extern int cycx_setup (cycxhw_t *hw, void *sfm, u32 len);
+extern int cycx_down (cycxhw_t *hw);
 extern int cycx_peek (cycxhw_t *hw, u32 addr, void *buf, u32 len);
 extern int cycx_poke (cycxhw_t *hw, u32 addr, void *buf, u32 len);
 extern int cycx_exec (u32 addr);
diff -u --recursive --new-file v2.3.27/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.27/linux/include/linux/fs.h	Thu Nov 11 20:11:53 1999
+++ linux/include/linux/fs.h	Fri Nov 12 11:28:05 1999
@@ -682,7 +682,7 @@
 	int (*alloc_inode) (const struct inode *, unsigned long, uid_t);
 	void (*free_block) (const struct inode *, unsigned long);
 	void (*free_inode) (const struct inode *, unsigned long);
-	int (*transfer) (struct inode *, struct iattr *, char, uid_t);
+	int (*transfer) (struct dentry *, struct iattr *, uid_t);
 };
 
 struct file_system_type {
diff -u --recursive --new-file v2.3.27/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.3.27/linux/include/linux/ide.h	Sun Nov  7 16:37:34 1999
+++ linux/include/linux/ide.h	Fri Nov 12 11:28:10 1999
@@ -227,8 +227,8 @@
 		unsigned set_multmode	: 1;	/* set multmode count */
 		unsigned set_tune	: 1;	/* tune interface for drive */
 		unsigned reserved	: 4;	/* unused */
-		} b;
-	} special_t;
+	} b;
+} special_t;
 
 typedef struct ide_drive_s {
 	struct request		*queue;	/* request queue */
@@ -299,7 +299,7 @@
 	thresholds_t		smart_thresholds;
 	values_t		smart_values;
 #endif
-	} ide_drive_t;
+} ide_drive_t;
 
 /*
  * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
@@ -317,11 +317,10 @@
 		ide_dma_off,	ide_dma_off_quietly,	ide_dma_test_irq,
 		ide_dma_bad_drive,			ide_dma_good_drive,
 		ide_dma_lostirq,			ide_dma_timeout
-	} ide_dma_action_t;
+} ide_dma_action_t;
 
 typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
 
-
 /*
  * An ide_tuneproc_t() is used to set the speed of an IDE interface
  * to a particular PIO mode.  The "byte" parameter is used
@@ -350,7 +349,7 @@
 		ide_qd6580,	ide_umc8672,	ide_ht6560b,
 		ide_pdc4030,	ide_rz1000,	ide_trm290,
 		ide_cmd646,	ide_cy82c693,	ide_4drives
-	} hwif_chipset_t;
+} hwif_chipset_t;
 
 typedef struct ide_pci_devid_s {
 	unsigned short	vid;
@@ -396,12 +395,20 @@
 #if (DISK_RECOVERY_TIME > 0)
 	unsigned long	last_time;	/* time when previous rq was done */
 #endif
-	} ide_hwif_t;
+} ide_hwif_t;
+
+  /*
+ * Status returned from various ide_ functions
+ */
+typedef enum {
+	ide_stopped,	/* no drive operation was started */
+	ide_started	/* a drive operation was started, and a handler was set */
+} ide_startstop_t;
 
 /*
  *  internal ide interrupt handler type
  */
-typedef void (ide_handler_t)(ide_drive_t *);
+typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
 
 /*
  * when ide_timer_expiry fires, invoke a handler of this type
@@ -410,9 +417,9 @@
 typedef int (ide_expiry_t)(ide_drive_t *);
 
 typedef struct hwgroup_s {
-	spinlock_t		spinlock; /* protects "busy" and "handler" */
 	ide_handler_t		*handler;/* irq handler, if active */
-	int			busy;	/* BOOL: protects all fields below */
+	volatile int		busy;	/* BOOL: protects all fields below */
+	int			sleeping; /* BOOL: wake us up on timer expiry */
 	ide_drive_t		*drive;	/* current drive */
 	ide_hwif_t		*hwif;	/* ptr to current hwif in linked-list */
 	struct request		*rq;	/* current request */
@@ -420,7 +427,7 @@
 	struct request		wrq;	/* local copy of current write rq */
 	unsigned long		poll_timeout;	/* timeout value during long polls */
 	ide_expiry_t		*expiry; /* queried upon timeouts */
-	} ide_hwgroup_t;
+} ide_hwgroup_t;
 
 /*
  * configurable drive settings
@@ -504,7 +511,7 @@
 #define IDE_SUBDRIVER_VERSION	1
 
 typedef int	(ide_cleanup_proc)(ide_drive_t *);
-typedef void 	(ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
+typedef ide_startstop_t (ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
 typedef void	(ide_end_request_proc)(byte, ide_hwgroup_t *);
 typedef int 	(ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
 typedef int	(ide_open_proc)(struct inode *, struct file *, ide_drive_t *);
@@ -512,7 +519,7 @@
 typedef int	(ide_check_media_change_proc)(ide_drive_t *);
 typedef void	(ide_pre_reset_proc)(ide_drive_t *);
 typedef unsigned long (ide_capacity_proc)(ide_drive_t *);
-typedef void	(ide_special_proc)(ide_drive_t *);
+typedef ide_startstop_t (ide_special_proc)(ide_drive_t *);
 typedef void	(ide_setting_proc)(ide_drive_t *);
 
 typedef struct ide_driver_s {
@@ -533,7 +540,7 @@
 	ide_capacity_proc		*capacity;
 	ide_special_proc		*special;
 	ide_proc_entry_t		*proc;
-	} ide_driver_t;
+} ide_driver_t;
 
 #define DRIVER(drive)		((ide_driver_t *)((drive)->driver))
 
@@ -600,9 +607,9 @@
 
 /*
  * ide_error() takes action based on the error returned by the controller.
- * The calling function must return afterwards, to restart the request.
+ * The caller should return immediately after invoking this.
  */
-void ide_error (ide_drive_t *drive, const char *msg, byte stat);
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
 
 /*
  * Issue a simple drive command
@@ -622,10 +629,13 @@
  * This routine busy-waits for the drive status to be not "busy".
  * It then checks the status for all of the "good" bits and none
  * of the "bad" bits, and if all is okay it returns 0.  All other
- * cases return 1 after invoking ide_error() -- caller should return.
- *
+ * cases return 1 after doing "*startstop = ide_error()", and the
+ * caller should return the updated value of "startstop" in this case.
+ * "startstop" is unchanged when the function returns 0;
  */
-int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+
+int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
 
 /*
  * This routine is called from the partition-table code in genhd.c
@@ -647,7 +657,7 @@
  * Start a reset operation for an IDE interface.
  * The caller should return immediately after invoking this.
  */
-void ide_do_reset (ide_drive_t *);
+ide_startstop_t ide_do_reset (ide_drive_t *);
 
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
@@ -657,12 +667,12 @@
 /*
  * "action" parameter type for ide_do_drive_cmd() below.
  */
-typedef enum
-	{ide_wait,	/* insert rq at end of list, and wait for it */
-	 ide_next,	/* insert rq immediately after current request */
-	 ide_preempt,	/* insert rq in front of current request */
-	 ide_end}	/* insert rq at end of list, but don't wait for it */
- ide_action_t;
+typedef enum {
+	ide_wait,	/* insert rq at end of list, and wait for it */
+	ide_next,	/* insert rq immediately after current request */
+	ide_preempt,	/* insert rq in front of current request */
+	ide_end		/* insert rq at end of list, but don't wait for it */
+} ide_action_t;
 
 /*
  * This function issues a special IDE device request
@@ -703,7 +713,11 @@
 int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
 
 void ide_delay_50ms (void);
+
+int ide_driveid_update (ide_drive_t *drive);
+int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature);
 int ide_config_drive_speed (ide_drive_t *drive, byte speed);
+int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
@@ -717,7 +731,7 @@
  * ide_multwrite() transfers a block of up to mcount sectors of data
  * to a drive as part of a disk multwrite operation.
  */
-void ide_multwrite (ide_drive_t *drive, unsigned int mcount);
+int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
 
 /*
  * ide_stall_queue() can be used by a drive to give excess bandwidth back
@@ -812,6 +826,7 @@
 #else /* CONFIG_BLK_DEV_OFFBOARD */
 #  define OFF_BOARD		NEVER_BOARD
 #endif /* CONFIG_BLK_DEV_OFFBOARD */
+
 unsigned long ide_find_free_region (unsigned short size) __init;
 void ide_scan_pcibus (void) __init;
 #endif
@@ -819,7 +834,7 @@
 #define BAD_DMA_DRIVE		0
 #define GOOD_DMA_DRIVE		1
 int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
-void ide_dma_intr  (ide_drive_t *drive);
+ide_startstop_t ide_dma_intr (ide_drive_t *drive);
 int check_drive_lists (ide_drive_t *drive, int good_bad);
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
 int ide_release_dma (ide_hwif_t *hwif);
diff -u --recursive --new-file v2.3.27/linux/include/linux/isapnp.h linux/include/linux/isapnp.h
--- v2.3.27/linux/include/linux/isapnp.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/isapnp.h	Fri Nov 12 11:29:37 1999
@@ -23,6 +23,7 @@
 #define LINUX_ISAPNP_H
 
 #include <linux/config.h>
+#include <linux/errno.h>
 
 /*
  *  Configuration registers (TODO: change by specification)
diff -u --recursive --new-file v2.3.27/linux/include/linux/mount.h linux/include/linux/mount.h
--- v2.3.27/linux/include/linux/mount.h	Tue Jul  6 10:18:15 1999
+++ linux/include/linux/mount.h	Fri Nov 12 04:36:13 1999
@@ -17,11 +17,12 @@
 struct quota_mount_options
 {
 	unsigned int flags;			/* Flags for diskquotas on this device */
-	struct semaphore semaphore;		/* lock device while I/O in progress */
+	struct semaphore dqio_sem;		/* lock device while I/O in progress */
+	struct semaphore dqoff_sem;		/* serialize quota_off() and quota_on() on device */
 	struct file *files[MAXQUOTAS];		/* fp's to quotafiles */
 	time_t inode_expire[MAXQUOTAS];		/* expiretime for inode-quota */
 	time_t block_expire[MAXQUOTAS];		/* expiretime for block-quota */
-	char rsquash[MAXQUOTAS];		/* for quotas treat root as any other user */
+	char rsquash[MAXQUOTAS];		/* for quotas threat root as any other user */
 };
 
 struct vfsmount
diff -u --recursive --new-file v2.3.27/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.3.27/linux/include/linux/pci_ids.h	Sun Nov  7 16:37:34 1999
+++ linux/include/linux/pci_ids.h	Fri Nov 12 10:12:11 1999
@@ -286,8 +286,10 @@
 #define PCI_DEVICE_ID_SI_501		0x0406
 #define PCI_DEVICE_ID_SI_496		0x0496
 #define PCI_DEVICE_ID_SI_530		0x0530
+#define PCI_DEVICE_ID_SI_540		0x0540
 #define PCI_DEVICE_ID_SI_601		0x0601
 #define PCI_DEVICE_ID_SI_620		0x0620
+#define PCI_DEVICE_ID_SI_630		0x0630
 #define PCI_DEVICE_ID_SI_5107		0x5107
 #define PCI_DEVICE_ID_SI_5511		0x5511
 #define PCI_DEVICE_ID_SI_5513		0x5513
diff -u --recursive --new-file v2.3.27/linux/include/linux/quota.h linux/include/linux/quota.h
--- v2.3.27/linux/include/linux/quota.h	Thu May 13 14:29:31 1999
+++ linux/include/linux/quota.h	Fri Nov 12 04:36:13 1999
@@ -202,7 +202,7 @@
 # /* nodep */ include <sys/cdefs.h>
 
 __BEGIN_DECLS
-int quotactl __P ((int, const char *, int, caddr_t));
+long quotactl __P ((int, const char *, int, caddr_t));
 __END_DECLS
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.3.27/linux/include/linux/quotaops.h linux/include/linux/quotaops.h
--- v2.3.27/linux/include/linux/quotaops.h	Wed Aug 18 16:43:33 1999
+++ linux/include/linux/quotaops.h	Fri Nov 12 11:28:02 1999
@@ -31,8 +31,8 @@
 extern void dquot_free_block(const struct inode *inode, unsigned long number);
 extern void dquot_free_inode(const struct inode *inode, unsigned long number);
 
-extern int  dquot_transfer(struct inode *inode, struct iattr *iattr,
-                           char direction, uid_t initiator);
+extern int  dquot_transfer(struct dentry *dentry, struct iattr *iattr,
+                           uid_t initiator);
 
 /*
  * Operations supported for diskquotas.
@@ -99,17 +99,11 @@
 	int error = -EDQUOT;
 
 	if (dentry->d_inode->i_sb->dq_op) {
-		if (IS_QUOTAINIT(dentry->d_inode) == 0)
-			dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1);
-		if (dentry->d_inode->i_sb->dq_op->transfer(dentry->d_inode, iattr, 0, current->fsuid))
-			goto out;
-		error = notify_change(dentry, iattr);
-		if (error)
-			dentry->d_inode->i_sb->dq_op->transfer(dentry->d_inode, iattr, 1, current->fsuid);
+		dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1);
+		error = dentry->d_inode->i_sb->dq_op->transfer(dentry, iattr, current->fsuid);
 	} else {
 		error = notify_change(dentry, iattr);
 	}
-out:
 	return error;
 }
 
diff -u --recursive --new-file v2.3.27/linux/include/net/ip.h linux/include/net/ip.h
--- v2.3.27/linux/include/net/ip.h	Fri Oct 22 13:21:55 1999
+++ linux/include/net/ip.h	Fri Nov 12 11:29:18 1999
@@ -22,7 +22,7 @@
 #ifndef _IP_H
 #define _IP_H
 
-
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/ip.h>
diff -u --recursive --new-file v2.3.27/linux/include/pcmcia/bus_ops.h linux/include/pcmcia/bus_ops.h
--- v2.3.27/linux/include/pcmcia/bus_ops.h	Thu Nov 11 20:11:54 1999
+++ linux/include/pcmcia/bus_ops.h	Fri Nov 12 04:29:47 1999
@@ -30,6 +30,8 @@
 #ifndef _LINUX_BUS_OPS_H
 #define _LINUX_BUS_OPS_H
 
+#include <linux/config.h>
+
 #ifdef CONFIG_VIRTUAL_BUS
 
 typedef struct bus_operations {
diff -u --recursive --new-file v2.3.27/linux/mm/bootmem.c linux/mm/bootmem.c
--- v2.3.27/linux/mm/bootmem.c	Sun Nov  7 16:37:34 1999
+++ linux/mm/bootmem.c	Fri Nov 12 04:29:47 1999
@@ -8,7 +8,6 @@
  *  system memory and memory holes as well.
  */
 
-#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/kernel_stat.h>
 #include <linux/swap.h>
diff -u --recursive --new-file v2.3.27/linux/mm/highmem.c linux/mm/highmem.c
--- v2.3.27/linux/mm/highmem.c	Thu Nov 11 20:11:55 1999
+++ linux/mm/highmem.c	Fri Nov 12 04:29:47 1999
@@ -16,6 +16,7 @@
  * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
@@ -269,9 +270,9 @@
 	unsigned long vto;
 
 	p_to = to->b_page;
-	vto = kmap_atomic(p_to, KM_BOUNCE_WRITE);
+	vto = kmap_atomic(p_to, KM_BOUNCE_READ);
 	memcpy((char *)vto + bh_offset(to), from->b_data, to->b_size);
-	kunmap_atomic(vto, KM_BOUNCE_WRITE);
+	kunmap_atomic(vto, KM_BOUNCE_READ);
 }
 
 static inline void bounce_end_io (struct buffer_head *bh, int uptodate)
diff -u --recursive --new-file v2.3.27/linux/net/802/fc.c linux/net/802/fc.c
--- v2.3.27/linux/net/802/fc.c	Sat Oct  9 11:47:50 1999
+++ linux/net/802/fc.c	Fri Nov 12 04:29:47 1999
@@ -10,6 +10,7 @@
  *		v 1.0 03/22/99
  */
 
+#include <linux/config.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.3.27/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.3.27/linux/net/bridge/br.c	Mon Nov  1 13:56:27 1999
+++ linux/net/bridge/br.c	Fri Nov 12 04:29:47 1999
@@ -52,7 +52,6 @@
  *	
  */
  
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
diff -u --recursive --new-file v2.3.27/linux/net/irda/irproc.c linux/net/irda/irproc.c
--- v2.3.27/linux/net/irda/irproc.c	Thu Nov 11 20:11:56 1999
+++ linux/net/irda/irproc.c	Fri Nov 12 04:40:46 1999
@@ -25,6 +25,7 @@
 
 #include <linux/miscdevice.h>
 #include <linux/proc_fs.h>
+#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <net/irda/irda.h>
diff -u --recursive --new-file v2.3.27/linux/net/sunrpc/sysctl.c linux/net/sunrpc/sysctl.c
--- v2.3.27/linux/net/sunrpc/sysctl.c	Thu Nov 11 20:11:56 1999
+++ linux/net/sunrpc/sysctl.c	Fri Nov 12 04:40:46 1999
@@ -14,6 +14,7 @@
 #include <linux/ctype.h>
 #include <linux/fs.h>
 #include <linux/sysctl.h>
+#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <asm/uaccess.h>
